PageRenderTime 63ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 1ms

/svgsalamander-0.1.1/svg-core/src/main/java/com/kitfox/svg/animation/AnimationElement.java

#
Java | 414 lines | 267 code | 58 blank | 89 comment | 66 complexity | fd70a6cf1237c8633d2c830dd859d5a1 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0
  1. /*
  2. * AnimateEle.java
  3. *
  4. * The Salamander Project - 2D and 3D graphics libraries in Java
  5. * Copyright (C) 2004 Mark McKay
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. *
  21. * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
  22. * projects can be found at http://www.kitfox.com
  23. *
  24. * Created on August 15, 2004, 2:52 AM
  25. */
  26. package com.kitfox.svg.animation;
  27. import com.kitfox.svg.SVGElement;
  28. import com.kitfox.svg.SVGException;
  29. import com.kitfox.svg.SVGLoaderHelper;
  30. import com.kitfox.svg.animation.parser.AnimTimeParser;
  31. import com.kitfox.svg.animation.parser.ParseException;
  32. import com.kitfox.svg.xml.StyleAttribute;
  33. import java.io.StringReader;
  34. import org.xml.sax.Attributes;
  35. import org.xml.sax.SAXException;
  36. /**
  37. * @author Mark McKay
  38. * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
  39. */
  40. public abstract class AnimationElement extends SVGElement
  41. {
  42. protected String attribName;
  43. // protected String attribType;
  44. protected int attribType = AT_AUTO;
  45. public static final int AT_CSS = 0;
  46. public static final int AT_XML = 1;
  47. public static final int AT_AUTO = 2; //Check CSS first, then XML
  48. protected TimeBase beginTime;
  49. protected TimeBase durTime;
  50. protected TimeBase endTime;
  51. protected int fillType = FT_AUTO;
  52. /** <a href="http://www.w3.org/TR/smil20/smil-timing.html#adef-fill">More about the <b>fill</b> attribute</a> */
  53. public static final int FT_REMOVE = 0;
  54. public static final int FT_FREEZE = 1;
  55. public static final int FT_HOLD = 2;
  56. public static final int FT_TRANSITION = 3;
  57. public static final int FT_AUTO = 4;
  58. public static final int FT_DEFAULT = 5;
  59. /** Additive state of track */
  60. public static final int AD_REPLACE = 0;
  61. public static final int AD_SUM = 1;
  62. int additiveType = AD_REPLACE;
  63. /** Accumlative state */
  64. public static final int AC_REPLACE = 0;
  65. public static final int AC_SUM = 1;
  66. int accumulateType = AC_REPLACE;
  67. /** Creates a new instance of AnimateEle */
  68. public AnimationElement()
  69. {
  70. }
  71. public static String animationElementToString(int attrValue)
  72. {
  73. switch (attrValue)
  74. {
  75. case AT_CSS:
  76. return "CSS";
  77. case AT_XML:
  78. return "XML";
  79. case AT_AUTO:
  80. return "AUTO";
  81. default:
  82. throw new RuntimeException("Unknown element type");
  83. }
  84. }
  85. public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
  86. {
  87. //Load style string
  88. super.loaderStartElement(helper, attrs, parent);
  89. attribName = attrs.getValue("attributeName");
  90. String attribType = attrs.getValue("attributeType");
  91. if (attribType != null)
  92. {
  93. attribType = attribType.toLowerCase();
  94. if (attribType.equals("css")) this.attribType = AT_CSS;
  95. else if (attribType.equals("xml")) this.attribType = AT_XML;
  96. }
  97. String beginTime = attrs.getValue("begin");
  98. String durTime = attrs.getValue("dur");
  99. String endTime = attrs.getValue("end");
  100. try
  101. {
  102. if (beginTime != null)
  103. {
  104. helper.animTimeParser.ReInit(new StringReader(beginTime));
  105. this.beginTime = helper.animTimeParser.Expr();
  106. this.beginTime.setParentElement(this);
  107. }
  108. if (durTime != null)
  109. {
  110. helper.animTimeParser.ReInit(new StringReader(durTime));
  111. this.durTime = helper.animTimeParser.Expr();
  112. this.durTime.setParentElement(this);
  113. }
  114. if (endTime != null)
  115. {
  116. helper.animTimeParser.ReInit(new StringReader(endTime));
  117. this.endTime = helper.animTimeParser.Expr();
  118. this.endTime.setParentElement(this);
  119. }
  120. }
  121. catch (Exception e)
  122. {
  123. throw new SAXException(e);
  124. }
  125. // this.beginTime = TimeBase.parseTime(beginTime);
  126. // this.durTime = TimeBase.parseTime(durTime);
  127. // this.endTime = TimeBase.parseTime(endTime);
  128. String fill = attrs.getValue("fill");
  129. if (fill != null)
  130. {
  131. if (fill.equals("remove")) this.fillType = FT_REMOVE;
  132. if (fill.equals("freeze")) this.fillType = FT_FREEZE;
  133. if (fill.equals("hold")) this.fillType = FT_HOLD;
  134. if (fill.equals("transiton")) this.fillType = FT_TRANSITION;
  135. if (fill.equals("auto")) this.fillType = FT_AUTO;
  136. if (fill.equals("default")) this.fillType = FT_DEFAULT;
  137. }
  138. String additiveStrn = attrs.getValue("additive");
  139. if (additiveStrn != null)
  140. {
  141. if (additiveStrn.equals("replace")) this.additiveType = AD_REPLACE;
  142. if (additiveStrn.equals("sum")) this.additiveType = AD_SUM;
  143. }
  144. String accumulateStrn = attrs.getValue("accumulate");
  145. if (accumulateStrn != null)
  146. {
  147. if (accumulateStrn.equals("replace")) this.accumulateType = AC_REPLACE;
  148. if (accumulateStrn.equals("sum")) this.accumulateType = AC_SUM;
  149. }
  150. }
  151. public String getAttribName() { return attribName; }
  152. public int getAttribType() { return attribType; }
  153. public int getAdditiveType() { return additiveType; }
  154. public int getAccumulateType() { return accumulateType; }
  155. public void evalParametric(AnimationTimeEval state, double curTime)
  156. {
  157. evalParametric(state, curTime, Double.NaN, Double.NaN);
  158. }
  159. /**
  160. * Compares current time to start and end times and determines what degree
  161. * of time interpolation this track currently represents. Returns
  162. * Float.NaN if this track cannot be evaluated at the passed time (ie,
  163. * it is before or past the end of the track, or it depends upon
  164. * an unknown event)
  165. * @param state - A structure that will be filled with information
  166. * regarding the applicability of this animatoin element at the passed
  167. * time.
  168. * @param curTime - Current time in seconds
  169. * @param repeatCount - Optional number of repetitions of length 'dur' to
  170. * do. Set to Double.NaN to not consider this in the calculation.
  171. * @param repeatDur - Optional amoun tof time to repeat the animaiton.
  172. * Set to Double.NaN to not consider this in the calculation.
  173. */
  174. protected void evalParametric(AnimationTimeEval state, double curTime, double repeatCount, double repeatDur)
  175. {
  176. double begin = (beginTime == null) ? 0 : beginTime.evalTime();
  177. if (Double.isNaN(begin) || begin > curTime)
  178. {
  179. state.set(Double.NaN, 0);
  180. return;
  181. }
  182. double dur = (durTime == null) ? Double.NaN : durTime.evalTime();
  183. if (Double.isNaN(dur))
  184. {
  185. state.set(Double.NaN, 0);
  186. return;
  187. }
  188. //Determine end point of this animation
  189. double end = (endTime == null) ? Double.NaN : endTime.evalTime();
  190. double repeat;
  191. // if (Double.isNaN(repeatDur))
  192. // {
  193. // repeatDur = dur;
  194. // }
  195. if (Double.isNaN(repeatCount) && Double.isNaN(repeatDur))
  196. {
  197. repeat = Double.NaN;
  198. }
  199. else
  200. {
  201. repeat = Math.min(
  202. Double.isNaN(repeatCount) ? Double.POSITIVE_INFINITY : dur * repeatCount,
  203. Double.isNaN(repeatDur) ? Double.POSITIVE_INFINITY : repeatDur);
  204. }
  205. if (Double.isNaN(repeat) && Double.isNaN(end))
  206. {
  207. //If neither and end point nor a repeat is specified, end point is
  208. // implied by duration.
  209. end = begin + dur;
  210. }
  211. double finishTime;
  212. if (Double.isNaN(end))
  213. {
  214. finishTime = begin + repeat;
  215. }
  216. else if (Double.isNaN(repeat))
  217. {
  218. finishTime = end;
  219. }
  220. else
  221. {
  222. finishTime = Math.min(end, repeat);
  223. }
  224. double evalTime = Math.min(curTime, finishTime);
  225. // if (curTime > finishTime) evalTime = finishTime;
  226. // double evalTime = curTime;
  227. // boolean pastEnd = curTime > evalTime;
  228. // if (!Double.isNaN(end) && curTime > end) { pastEnd = true; evalTime = Math.min(evalTime, end); }
  229. // if (!Double.isNaN(repeat) && curTime > repeat) { pastEnd = true; evalTime = Math.min(evalTime, repeat); }
  230. double ratio = (evalTime - begin) / dur;
  231. int rep = (int)ratio;
  232. double interp = ratio - rep;
  233. //Adjust for roundoff
  234. if (interp < 0.00001) interp = 0;
  235. // state.set(interp, rep);
  236. // if (!pastEnd)
  237. // {
  238. // state.set(interp, rep, false);
  239. // return;
  240. // }
  241. //If we are still within the clip, return value
  242. if (curTime == evalTime)
  243. {
  244. state.set(interp, rep);
  245. return;
  246. }
  247. //We are past end of clip. Determine to clamp or ignore.
  248. switch (fillType)
  249. {
  250. default:
  251. case FT_REMOVE:
  252. case FT_AUTO:
  253. case FT_DEFAULT:
  254. state.set(Double.NaN, rep);
  255. return;
  256. case FT_FREEZE:
  257. case FT_HOLD:
  258. case FT_TRANSITION:
  259. state.set(interp == 0 ? 1 : interp, rep);
  260. return;
  261. }
  262. }
  263. double evalStartTime()
  264. {
  265. return beginTime == null ? Double.NaN : beginTime.evalTime();
  266. }
  267. double evalDurTime()
  268. {
  269. return durTime == null ? Double.NaN : durTime.evalTime();
  270. }
  271. /**
  272. * Evaluates the ending time of this element. Returns 0 if not specified.
  273. *
  274. * @see hasEndTime
  275. */
  276. double evalEndTime()
  277. {
  278. return endTime == null ? Double.NaN : endTime.evalTime();
  279. }
  280. /**
  281. * Checks to see if an end time has been specified for this element.
  282. */
  283. boolean hasEndTime() { return endTime != null; }
  284. /**
  285. * Updates all attributes in this diagram associated with a time event.
  286. * Ie, all attributes with track information.
  287. * @return - true if this node has changed state as a result of the time
  288. * update
  289. */
  290. public boolean updateTime(double curTime)
  291. {
  292. //Animation elements to not change with time
  293. return false;
  294. }
  295. public void rebuild() throws SVGException
  296. {
  297. AnimTimeParser animTimeParser = new AnimTimeParser(new StringReader(""));
  298. rebuild(animTimeParser);
  299. }
  300. protected void rebuild(AnimTimeParser animTimeParser) throws SVGException
  301. {
  302. StyleAttribute sty = new StyleAttribute();
  303. if (getPres(sty.setName("begin")))
  304. {
  305. String newVal = sty.getStringValue();
  306. animTimeParser.ReInit(new StringReader(newVal));
  307. try {
  308. this.beginTime = animTimeParser.Expr();
  309. } catch (ParseException ex) {
  310. ex.printStackTrace();
  311. }
  312. }
  313. if (getPres(sty.setName("dur")))
  314. {
  315. String newVal = sty.getStringValue();
  316. animTimeParser.ReInit(new StringReader(newVal));
  317. try {
  318. this.durTime = animTimeParser.Expr();
  319. } catch (ParseException ex) {
  320. ex.printStackTrace();
  321. }
  322. }
  323. if (getPres(sty.setName("end")))
  324. {
  325. String newVal = sty.getStringValue();
  326. animTimeParser.ReInit(new StringReader(newVal));
  327. try {
  328. this.endTime = animTimeParser.Expr();
  329. } catch (ParseException ex) {
  330. ex.printStackTrace();
  331. }
  332. }
  333. if (getPres(sty.setName("fill")))
  334. {
  335. String newVal = sty.getStringValue();
  336. if (newVal.equals("remove")) this.fillType = FT_REMOVE;
  337. if (newVal.equals("freeze")) this.fillType = FT_FREEZE;
  338. if (newVal.equals("hold")) this.fillType = FT_HOLD;
  339. if (newVal.equals("transiton")) this.fillType = FT_TRANSITION;
  340. if (newVal.equals("auto")) this.fillType = FT_AUTO;
  341. if (newVal.equals("default")) this.fillType = FT_DEFAULT;
  342. }
  343. if (getPres(sty.setName("additive")))
  344. {
  345. String newVal = sty.getStringValue();
  346. if (newVal.equals("replace")) this.additiveType = AD_REPLACE;
  347. if (newVal.equals("sum")) this.additiveType = AD_SUM;
  348. }
  349. if (getPres(sty.setName("accumulate")))
  350. {
  351. String newVal = sty.getStringValue();
  352. if (newVal.equals("replace")) this.accumulateType = AC_REPLACE;
  353. if (newVal.equals("sum")) this.accumulateType = AC_SUM;
  354. }
  355. }
  356. }