summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/kitfox/svg/animation
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/kitfox/svg/animation')
-rw-r--r--src/main/java/com/kitfox/svg/animation/AnimTimeParser.jjt316
-rw-r--r--src/main/java/com/kitfox/svg/animation/Animate.java354
-rw-r--r--src/main/java/com/kitfox/svg/animation/AnimateBase.java92
-rw-r--r--src/main/java/com/kitfox/svg/animation/AnimateColor.java81
-rw-r--r--src/main/java/com/kitfox/svg/animation/AnimateColorIface.java38
-rw-r--r--src/main/java/com/kitfox/svg/animation/AnimateMotion.java234
-rw-r--r--src/main/java/com/kitfox/svg/animation/AnimateTransform.java225
-rw-r--r--src/main/java/com/kitfox/svg/animation/AnimateXform.java52
-rw-r--r--src/main/java/com/kitfox/svg/animation/AnimationElement.java336
-rw-r--r--src/main/java/com/kitfox/svg/animation/AnimationTimeEval.java65
-rw-r--r--src/main/java/com/kitfox/svg/animation/Bezier.java201
-rw-r--r--src/main/java/com/kitfox/svg/animation/SetSmil.java55
-rw-r--r--src/main/java/com/kitfox/svg/animation/TimeBase.java99
-rw-r--r--src/main/java/com/kitfox/svg/animation/TimeCompound.java96
-rw-r--r--src/main/java/com/kitfox/svg/animation/TimeDiscrete.java51
-rw-r--r--src/main/java/com/kitfox/svg/animation/TimeIndefinite.java48
-rw-r--r--src/main/java/com/kitfox/svg/animation/TimeLookup.java75
-rw-r--r--src/main/java/com/kitfox/svg/animation/TimeSum.java60
-rw-r--r--src/main/java/com/kitfox/svg/animation/TrackBase.java104
-rw-r--r--src/main/java/com/kitfox/svg/animation/TrackColor.java95
-rw-r--r--src/main/java/com/kitfox/svg/animation/TrackDouble.java119
-rw-r--r--src/main/java/com/kitfox/svg/animation/TrackManager.java153
-rw-r--r--src/main/java/com/kitfox/svg/animation/TrackMotion.java128
-rw-r--r--src/main/java/com/kitfox/svg/animation/TrackPath.java100
-rw-r--r--src/main/java/com/kitfox/svg/animation/TrackTransform.java112
25 files changed, 3289 insertions, 0 deletions
diff --git a/src/main/java/com/kitfox/svg/animation/AnimTimeParser.jjt b/src/main/java/com/kitfox/svg/animation/AnimTimeParser.jjt
new file mode 100644
index 0000000..3a63b4c
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/AnimTimeParser.jjt
@@ -0,0 +1,316 @@
+/**
+ */
+
+
+options {
+ MULTI=true;
+ STATIC=false;
+}
+
+PARSER_BEGIN(AnimTimeParser)
+
+package com.kitfox.svg.animation.parser;
+
+import java.util.*;
+import java.io.*;
+import com.kitfox.svg.animation.*;
+
+public class AnimTimeParser
+{
+ /**
+ * Test the parser
+ */
+ public static void main(String args[]) throws ParseException
+ {
+// AnimTimeParser parser = new AnimTimeParser(System.in);
+ StringReader reader;
+
+ reader = new StringReader("1:30 + 5ms");
+ AnimTimeParser parser = new AnimTimeParser(reader);
+ TimeBase tc;
+
+ tc = parser.Expr();
+ System.err.println("AnimTimeParser eval to " + tc.evalTime());
+
+ reader = new StringReader("19");
+ parser.ReInit(reader);
+ tc = parser.Expr();
+ System.err.println("AnimTimeParser eval to " + tc.evalTime());
+ }
+
+}
+
+PARSER_END(AnimTimeParser)
+
+
+
+
+/**
+ * Tokens
+ */
+
+SKIP : /* WHITE SPACE */
+{
+ " "
+| "\t"
+| "\n"
+| "\r"
+| "\f"
+}
+
+TOKEN :
+{
+ < #LETTER: [ "a"-"z", "A"-"Z" ] >
+|
+ < #DIGIT: [ "0"-"9"] >
+|
+ < INTEGER: (<DIGIT>)+ >
+|
+ < FLOAT: (["+", "-"])? (((<DIGIT>)* "." (<DIGIT>)+) | ((<DIGIT>)+)) (["E", "e"] (["+", "-"])? (<DIGIT>)+)? >
+|
+ < INDEFINITE: "indefinite" >
+|
+ < MOUSE_OVER: "mouseover" >
+|
+ < WHEN_NOT_ACTIVE: "whenNotActive" >
+|
+ < UNITS: "ms" | "s" | "min" | "h" >
+|
+ < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>|"_"|"-")* >
+
+}
+
+
+
+
+
+
+
+/**
+ * Expression structure
+ */
+
+
+TimeBase Expr() :
+{
+ TimeBase term;
+ Vector list = new Vector();
+}
+{
+ ( term = Sum()
+ {
+ list.add(term);
+ }
+ )?
+ ( LOOKAHEAD(2) ";" term = Sum()
+ {
+ list.add(term);
+ }
+ ) *
+ (";")?
+
+ {
+ switch (list.size())
+ {
+ case 0:
+ return new TimeIndefinite();
+ case 1:
+ return (TimeBase)list.get(0);
+ default:
+ return new TimeCompound(list);
+ }
+ }
+}
+
+TimeBase Sum() :
+{
+ Token t = null;
+ TimeBase t1;
+ TimeBase t2 = null;
+}
+{
+ t1=Term() ( (t="+" | t="-") t2 = Term() )?
+ {
+ if (t2 == null) return t1;
+
+ if (t.image.equals("-"))
+ {
+ return new TimeSum(t1, t2, false);
+ }
+ else
+ {
+ return new TimeSum(t1, t2, true);
+ }
+ }
+}
+
+
+/*
+{
+ TimeBase base;
+ Vector timeList = new Vector();
+ Token t;
+}
+{
+ base=Term()
+ {
+ timeList.add(base);
+ }
+ ( (t="+" | t="-") base=Term()
+ {
+ if (t.image.equals"-")
+ timeList.sub(base);
+ else
+ timeList.add(base);
+ }
+ )*
+ {
+ switch (timeList.size())
+ {
+ case 0:
+ return new TimeIndefinite();
+ case 1:
+ return (TimeBase)timeList.get(0);
+ default:
+ return new TimeCompound(timeList);
+ }
+ }
+
+}
+*/
+
+TimeBase Term() :
+{
+ TimeBase base;
+}
+{
+ base=IndefiniteTime()
+ { return base; }
+ | base=LiteralTime()
+ { return base; }
+ | base=LookupTime()
+ { return base; }
+ | base=EventTime()
+ { return base; }
+}
+
+TimeIndefinite IndefiniteTime() :
+{}
+{
+ <INDEFINITE>
+ {
+ return new TimeIndefinite();
+ }
+}
+
+TimeDiscrete EventTime() :
+{}
+{
+ (<MOUSE_OVER> | <WHEN_NOT_ACTIVE>)
+ {
+ //For now, map all events to the zero time
+ return new TimeDiscrete(0);
+ }
+}
+
+TimeDiscrete LiteralTime() :
+{
+ double t1, t2, t3 = Double.NaN, value;
+ Token t;
+}
+{
+ t1=Number()
+ {
+ value = t1;
+ }
+ (
+
+ (":" t2=Number() (":" t3=Number())?
+ {
+ //Return clock time format (convert to seconds)
+ if (Double.isNaN(t3))
+ {
+ value = t1 * 60 + t2;
+ }
+ else
+ {
+ value = t1 * 3600 + t2 * 60 + t3;
+ }
+ }
+ )
+
+ |
+
+ (t=<UNITS>
+ {
+ //Return units format (convert to seconds)
+ if (t.image.equals("ms")) value = t1 / 1000;
+ if (t.image.equals("min")) value = t1 * 60;
+ if (t.image.equals("h")) value = t1 * 3600;
+ }
+ )
+ )?
+ {
+ return new TimeDiscrete(value);
+ }
+}
+
+
+TimeLookup LookupTime() :
+{
+ double paramNum = 0.0;
+ Token node, event;
+}
+{
+ node=<IDENTIFIER> "." event=<IDENTIFIER> (paramNum=ParamList())?
+ {
+ return new TimeLookup(null, node.image, event.image, "" + paramNum);
+ }
+}
+
+double ParamList() :
+{
+ double num;
+}
+{
+ "(" num=Number() ")"
+ {
+ return num;
+ }
+}
+
+double Number() :
+{
+ Token t;
+}
+{
+ t=<FLOAT>
+ {
+ try { return Double.parseDouble(t.image); }
+ catch (Exception e) { e.printStackTrace(); }
+
+ return 0.0;
+ }
+ | t=<INTEGER>
+ {
+ try { return Double.parseDouble(t.image); }
+ catch (Exception e) { e.printStackTrace(); }
+
+ return 0.0;
+ }
+}
+
+int Integer() :
+{
+ Token t;
+}
+{
+ t=<INTEGER>
+ {
+ try { return Integer.parseInt(t.image); }
+ catch (Exception e) { e.printStackTrace(); }
+
+ return 0;
+ }
+}
+
diff --git a/src/main/java/com/kitfox/svg/animation/Animate.java b/src/main/java/com/kitfox/svg/animation/Animate.java
new file mode 100644
index 0000000..051c526
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/Animate.java
@@ -0,0 +1,354 @@
+/*
+ * Animate.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 2:51 AM
+ */
+
+package com.kitfox.svg.animation;
+
+import com.kitfox.svg.xml.XMLParseUtil;
+import org.xml.sax.*;
+
+import com.kitfox.svg.*;
+import com.kitfox.svg.xml.*;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+/**
+ * Animate is a really annoying morphic tag that could represent a real value,
+ * a color or a path
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class Animate extends AnimateBase implements AnimateColorIface
+{
+// StyleAttribute retAttrib = new StyleAttribute
+ public static final int DT_REAL = 0;
+ public static final int DT_COLOR = 1;
+ public static final int DT_PATH = 2;
+ int dataType = DT_REAL;
+
+ protected double fromValue = Double.NaN;
+ protected double toValue = Double.NaN;
+ protected double byValue = Double.NaN;
+ protected double[] valuesValue;
+
+ protected Color fromColor = null;
+ protected Color toColor = null;
+
+ protected GeneralPath fromPath = null;
+ protected GeneralPath toPath = null;
+
+ /** Creates a new instance of Animate */
+ public Animate()
+ {
+ }
+
+ public int getDataType()
+ {
+ return dataType;
+ }
+
+ public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
+ {
+ //Load style string
+ super.loaderStartElement(helper, attrs, parent);
+
+ String strn = attrs.getValue("from");
+ if (strn != null)
+ {
+ if (XMLParseUtil.isDouble(strn))
+ {
+ fromValue = XMLParseUtil.parseDouble(strn);
+ }
+// else if (attrs.getValue("attributeName").equals("d"))
+// {
+// fromPath = this.buildPath(strn, GeneralPath.WIND_EVEN_ODD);
+// dataType = DT_PATH;
+// }
+ else
+ {
+ fromColor = ColorTable.parseColor(strn);
+ if (fromColor == null)
+ {
+ //Try path
+ fromPath = this.buildPath(strn, GeneralPath.WIND_EVEN_ODD);
+ dataType = DT_PATH;
+ }
+ else dataType = DT_COLOR;
+ }
+ }
+
+ strn = attrs.getValue("to");
+ if (strn != null)
+ {
+ if (XMLParseUtil.isDouble(strn))
+ {
+ toValue = XMLParseUtil.parseDouble(strn);
+ }
+ else
+ {
+ toColor = ColorTable.parseColor(strn);
+ if (toColor == null)
+ {
+ //Try path
+ toPath = this.buildPath(strn, GeneralPath.WIND_EVEN_ODD);
+ dataType = DT_PATH;
+ }
+ else dataType = DT_COLOR;
+ }
+ }
+
+ strn = attrs.getValue("by");
+ try
+ {
+ if (strn != null) byValue = XMLParseUtil.parseDouble(strn);
+ } catch (Exception e) {}
+
+ strn = attrs.getValue("values");
+ try
+ {
+ if (strn != null) valuesValue = XMLParseUtil.parseDoubleList(strn);
+ } catch (Exception e) {}
+ }
+
+ /**
+ * Evaluates this animation element for the passed interpolation time. Interp
+ * must be on [0..1].
+ */
+ public double eval(double interp)
+ {
+ boolean fromExists = !Double.isNaN(fromValue);
+ boolean toExists = !Double.isNaN(toValue);
+ boolean byExists = !Double.isNaN(byValue);
+ boolean valuesExists = valuesValue != null;
+
+ if (valuesExists)
+ {
+ double sp = interp * valuesValue.length;
+ int ip = (int)sp;
+ double fp = sp - ip;
+
+ int i0 = ip;
+ int i1 = ip + 1;
+
+ if (i0 < 0) return valuesValue[0];
+ if (i1 >= valuesValue.length) return valuesValue[valuesValue.length - 1];
+ return valuesValue[i0] * (1 - fp) + valuesValue[i1] * fp;
+ }
+ else if (fromExists && toExists)
+ {
+ return toValue * interp + fromValue * (1.0 - interp);
+ }
+ else if (fromExists && byExists)
+ {
+ return fromValue + byValue * interp;
+ }
+ else if (toExists && byExists)
+ {
+ return toValue - byValue * (1.0 - interp);
+ }
+ else if (byExists)
+ {
+ return byValue * interp;
+ }
+
+ //Should not reach this line
+ throw new RuntimeException("Animate tag could not be evalutated - insufficient arguements");
+ }
+
+ public Color evalColor(double interp)
+ {
+ if (fromColor == null && toColor != null)
+ {
+ float[] toCol = new float[3];
+ toColor.getColorComponents(toCol);
+ return new Color(toCol[0] * (float)interp,
+ toCol[1] * (float)interp,
+ toCol[2] * (float)interp);
+ }
+ else if (fromColor != null && toColor != null)
+ {
+ float nInterp = 1 - (float)interp;
+
+ float[] fromCol = new float[3];
+ float[] toCol = new float[3];
+ fromColor.getColorComponents(fromCol);
+ toColor.getColorComponents(toCol);
+ return new Color(fromCol[0] * nInterp + toCol[0] * (float)interp,
+ fromCol[1] * nInterp + toCol[1] * (float)interp,
+ fromCol[2] * nInterp + toCol[2] * (float)interp);
+ }
+
+ throw new RuntimeException("Animate tag could not be evalutated - insufficient arguements");
+ }
+
+ public GeneralPath evalPath(double interp)
+ {
+ if (fromPath == null && toPath != null)
+ {
+ PathIterator itTo = toPath.getPathIterator(new AffineTransform());
+
+ GeneralPath midPath = new GeneralPath();
+ float[] coordsTo = new float[6];
+
+ for (; !itTo.isDone(); itTo.next())
+ {
+ int segTo = itTo.currentSegment(coordsTo);
+
+ switch (segTo)
+ {
+ case PathIterator.SEG_CLOSE:
+ midPath.closePath();
+ break;
+ case PathIterator.SEG_CUBICTO:
+ midPath.curveTo(
+ (float)(coordsTo[0] * interp),
+ (float)(coordsTo[1] * interp),
+ (float)(coordsTo[2] * interp),
+ (float)(coordsTo[3] * interp),
+ (float)(coordsTo[4] * interp),
+ (float)(coordsTo[5] * interp)
+ );
+ break;
+ case PathIterator.SEG_LINETO:
+ midPath.lineTo(
+ (float)(coordsTo[0] * interp),
+ (float)(coordsTo[1] * interp)
+ );
+ break;
+ case PathIterator.SEG_MOVETO:
+ midPath.moveTo(
+ (float)(coordsTo[0] * interp),
+ (float)(coordsTo[1] * interp)
+ );
+ break;
+ case PathIterator.SEG_QUADTO:
+ midPath.quadTo(
+ (float)(coordsTo[0] * interp),
+ (float)(coordsTo[1] * interp),
+ (float)(coordsTo[2] * interp),
+ (float)(coordsTo[3] * interp)
+ );
+ break;
+ }
+ }
+
+ return midPath;
+ }
+ else if (toPath != null)
+ {
+ PathIterator itFrom = fromPath.getPathIterator(new AffineTransform());
+ PathIterator itTo = toPath.getPathIterator(new AffineTransform());
+
+ GeneralPath midPath = new GeneralPath();
+ float[] coordsFrom = new float[6];
+ float[] coordsTo = new float[6];
+
+ for (; !itFrom.isDone(); itFrom.next())
+ {
+ int segFrom = itFrom.currentSegment(coordsFrom);
+ int segTo = itTo.currentSegment(coordsTo);
+
+ if (segFrom != segTo)
+ {
+ throw new RuntimeException("Path shape mismatch");
+ }
+
+ switch (segFrom)
+ {
+ case PathIterator.SEG_CLOSE:
+ midPath.closePath();
+ break;
+ case PathIterator.SEG_CUBICTO:
+ midPath.curveTo(
+ (float)(coordsFrom[0] * (1 - interp) + coordsTo[0] * interp),
+ (float)(coordsFrom[1] * (1 - interp) + coordsTo[1] * interp),
+ (float)(coordsFrom[2] * (1 - interp) + coordsTo[2] * interp),
+ (float)(coordsFrom[3] * (1 - interp) + coordsTo[3] * interp),
+ (float)(coordsFrom[4] * (1 - interp) + coordsTo[4] * interp),
+ (float)(coordsFrom[5] * (1 - interp) + coordsTo[5] * interp)
+ );
+ break;
+ case PathIterator.SEG_LINETO:
+ midPath.lineTo(
+ (float)(coordsFrom[0] * (1 - interp) + coordsTo[0] * interp),
+ (float)(coordsFrom[1] * (1 - interp) + coordsTo[1] * interp)
+ );
+ break;
+ case PathIterator.SEG_MOVETO:
+ midPath.moveTo(
+ (float)(coordsFrom[0] * (1 - interp) + coordsTo[0] * interp),
+ (float)(coordsFrom[1] * (1 - interp) + coordsTo[1] * interp)
+ );
+ break;
+ case PathIterator.SEG_QUADTO:
+ midPath.quadTo(
+ (float)(coordsFrom[0] * (1 - interp) + coordsTo[0] * interp),
+ (float)(coordsFrom[1] * (1 - interp) + coordsTo[1] * interp),
+ (float)(coordsFrom[2] * (1 - interp) + coordsTo[2] * interp),
+ (float)(coordsFrom[3] * (1 - interp) + coordsTo[3] * interp)
+ );
+ break;
+ }
+ }
+
+ return midPath;
+ }
+
+ throw new RuntimeException("Animate tag could not be evalutated - insufficient arguements");
+ }
+
+ /**
+ * If this element is being accumulated, detemine the delta to accumulate by
+ */
+ public double repeatSkipSize(int reps)
+ {
+ boolean fromExists = !Double.isNaN(fromValue);
+ boolean toExists = !Double.isNaN(toValue);
+ boolean byExists = !Double.isNaN(byValue);
+
+ if (fromExists && toExists)
+ {
+ return (toValue - fromValue) * reps;
+ }
+ else if (fromExists && byExists)
+ {
+ return (fromValue + byValue) * reps;
+ }
+ else if (toExists && byExists)
+ {
+ return toValue * reps;
+ }
+ else if (byExists)
+ {
+ return byValue * reps;
+ }
+
+ //Should not reach this line
+ return 0;
+ }
+
+}
diff --git a/src/main/java/com/kitfox/svg/animation/AnimateBase.java b/src/main/java/com/kitfox/svg/animation/AnimateBase.java
new file mode 100644
index 0000000..53a6117
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/AnimateBase.java
@@ -0,0 +1,92 @@
+/*
+ * Animate.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 2:51 AM
+ */
+
+package com.kitfox.svg.animation;
+
+import java.io.*;
+import org.xml.sax.*;
+
+import com.kitfox.svg.*;
+
+/**
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+abstract public class AnimateBase extends AnimationElement
+{
+ protected double repeatCount = Double.NaN;
+ protected TimeBase repeatDur;
+
+ /** Creates a new instance of Animate */
+ public AnimateBase()
+ {
+ }
+
+ public void evalParametric(AnimationTimeEval state, double curTime)
+ {
+ evalParametric(state, curTime, repeatCount, repeatDur == null ? Double.NaN : repeatDur.evalTime());
+ }
+
+ public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
+ {
+ //Load style string
+ super.loaderStartElement(helper, attrs, parent);
+
+ String repeatDurTime = attrs.getValue("repeatDur");
+
+ try
+ {
+ if (repeatDurTime != null)
+ {
+ helper.animTimeParser.ReInit(new StringReader(repeatDurTime));
+ this.repeatDur = helper.animTimeParser.Expr();
+ this.repeatDur.setParentElement(this);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new SAXException(e);
+ }
+
+// this.repeatDur = TimeBase.parseTime(repeatDurTime);
+
+ String strn = attrs.getValue("repeatCount");
+ if (strn == null)
+ {
+ repeatCount = 1;
+ }
+ else if ("indefinite".equals(strn))
+ {
+ repeatCount = Double.POSITIVE_INFINITY;
+ }
+ else
+ {
+ try { repeatCount = Double.parseDouble(strn); }
+ catch (Exception e) { repeatCount = Double.NaN; }
+ }
+ }
+
+}
diff --git a/src/main/java/com/kitfox/svg/animation/AnimateColor.java b/src/main/java/com/kitfox/svg/animation/AnimateColor.java
new file mode 100644
index 0000000..a63ecad
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/AnimateColor.java
@@ -0,0 +1,81 @@
+/*
+ * Animate.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 2:51 AM
+ */
+
+package com.kitfox.svg.animation;
+
+import org.xml.sax.*;
+import java.awt.*;
+
+import com.kitfox.svg.*;
+import com.kitfox.svg.xml.*;
+
+/**
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class AnimateColor extends AnimateBase implements AnimateColorIface
+{
+
+ protected Color fromValue;
+ protected Color toValue;
+
+ /** Creates a new instance of Animate */
+ public AnimateColor()
+ {
+ }
+
+ public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
+ {
+ //Load style string
+ super.loaderStartElement(helper, attrs, parent);
+
+ String strn = attrs.getValue("from");
+ fromValue = ColorTable.parseColor(strn);
+
+ strn = attrs.getValue("to");
+ toValue = ColorTable.parseColor(strn);
+ }
+
+
+ /**
+ * Evaluates this animation element for the passed interpolation time. Interp
+ * must be on [0..1].
+ */
+ public Color evalColor(double interp)
+ {
+ int r1 = fromValue.getRed();
+ int g1 = fromValue.getGreen();
+ int b1 = fromValue.getBlue();
+ int r2 = toValue.getRed();
+ int g2 = toValue.getGreen();
+ int b2 = toValue.getBlue();
+ double invInterp = 1.0 - interp;
+
+ return new Color((int)(r1 * invInterp + r2 * interp),
+ (int)(g1 * invInterp + g2 * interp),
+ (int)(b1 * invInterp + b2 * interp));
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/AnimateColorIface.java b/src/main/java/com/kitfox/svg/animation/AnimateColorIface.java
new file mode 100644
index 0000000..a9b59d1
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/AnimateColorIface.java
@@ -0,0 +1,38 @@
+/*
+ * AnimateColorIface.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on January 16, 2005, 6:24 AM
+ */
+
+package com.kitfox.svg.animation;
+
+import java.awt.*;
+
+/**
+ *
+ * @author kitfox
+ */
+public interface AnimateColorIface
+{
+ public Color evalColor(double interp);
+}
diff --git a/src/main/java/com/kitfox/svg/animation/AnimateMotion.java b/src/main/java/com/kitfox/svg/animation/AnimateMotion.java
new file mode 100644
index 0000000..c96f45e
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/AnimateMotion.java
@@ -0,0 +1,234 @@
+/*
+ * Animate.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 2:51 AM
+ */
+
+package com.kitfox.svg.animation;
+
+import org.xml.sax.*;
+import java.util.regex.*;
+import java.awt.geom.*;
+import java.awt.*;
+import java.util.*;
+
+import com.kitfox.svg.*;
+
+/**
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class AnimateMotion extends AnimateXform
+{
+ static final Matcher matchPoint = Pattern.compile("\\s*(\\d+)[^\\d]+(\\d+)\\s*").matcher("");
+
+// protected double fromValue;
+// protected double toValue;
+ GeneralPath path;
+ int rotateType = RT_ANGLE;
+ double rotate; //Static angle to rotate by
+
+ public static final int RT_ANGLE = 0; //Rotate by constant 'rotate' degrees
+ public static final int RT_AUTO = 1; //Rotate to reflect tangent of position on path
+
+ final Vector bezierSegs = new Vector();
+ double curveLength;
+
+ /** Creates a new instance of Animate */
+ public AnimateMotion()
+ {
+ }
+
+ public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
+ {
+ //Load style string
+ super.loaderStartElement(helper, attrs, parent);
+
+ //Motion element implies animating the transform element
+ if (attribName == null)
+ {
+ attribName = "transform";
+ attribType = AT_AUTO;
+ additiveType = AD_SUM;
+ }
+
+
+ //Determine path
+ String from = attrs.getValue("from");
+ String to = attrs.getValue("to");
+ if (from != null && to != null)
+ {
+ Point2D.Float ptFrom = new Point2D.Float(), ptTo = new Point2D.Float();
+
+ matchPoint.reset(from);
+ if (matchPoint.matches())
+ {
+ setPoint(ptFrom, matchPoint.group(1), matchPoint.group(2));
+ }
+
+ matchPoint.reset(to);
+ if (matchPoint.matches())
+ {
+ setPoint(ptFrom, matchPoint.group(1), matchPoint.group(2));
+ }
+
+ if (ptFrom != null && ptTo != null)
+ {
+ path = new GeneralPath();
+ path.moveTo(ptFrom.x, ptFrom.y);
+ path.lineTo(ptTo.x, ptTo.y);
+ }
+ }
+
+ String path = attrs.getValue("path");
+ if (path != null)
+ {
+ this.path = buildPath(path, GeneralPath.WIND_NON_ZERO);
+ }
+
+ //Now parse rotation style
+ String rotate = attrs.getValue("rotate");
+ if (rotate != null)
+ {
+ if (rotate.equals("auto"))
+ {
+ this.rotateType = RT_AUTO;
+ }
+ else
+ {
+ try { this.rotate = Math.toRadians(Float.parseFloat(rotate)); } catch (Exception e) {}
+ }
+ }
+
+ paramaterizePath();
+ }
+
+ protected static void setPoint(Point2D.Float pt, String x, String y)
+ {
+ try { pt.x = Float.parseFloat(x); } catch (Exception e) {};
+
+ try { pt.y = Float.parseFloat(y); } catch (Exception e) {};
+ }
+
+
+ private void paramaterizePath()
+ {
+ bezierSegs.clear();
+ curveLength = 0;
+
+ double[] coords = new double[6];
+ double sx = 0, sy = 0;
+
+ for (PathIterator pathIt = path.getPathIterator(new AffineTransform()); !pathIt.isDone(); pathIt.next())
+ {
+ Bezier bezier = null;
+
+ int segType = pathIt.currentSegment(coords);
+
+ switch (segType)
+ {
+ case PathIterator.SEG_LINETO:
+ {
+ bezier = new Bezier(sx, sy, coords, 1);
+ sx = coords[0];
+ sy = coords[1];
+ break;
+ }
+ case PathIterator.SEG_QUADTO:
+ {
+ bezier = new Bezier(sx, sy, coords, 2);
+ sx = coords[2];
+ sy = coords[3];
+ break;
+ }
+ case PathIterator.SEG_CUBICTO:
+ {
+ bezier = new Bezier(sx, sy, coords, 3);
+ sx = coords[4];
+ sy = coords[5];
+ break;
+ }
+ case PathIterator.SEG_MOVETO:
+ {
+ sx = coords[0];
+ sy = coords[1];
+ break;
+ }
+ case PathIterator.SEG_CLOSE:
+ //Do nothing
+ break;
+
+ }
+
+ if (bezier != null)
+ {
+ bezierSegs.add(bezier);
+ curveLength += bezier.getLength();
+ }
+ }
+ }
+
+ /**
+ * Evaluates this animation element for the passed interpolation time. Interp
+ * must be on [0..1].
+ */
+ public AffineTransform eval(AffineTransform xform, double interp)
+ {
+ Point2D.Double point = new Point2D.Double();
+
+ if (interp >= 1)
+ {
+ Bezier last = (Bezier)bezierSegs.get(bezierSegs.size() - 1);
+ last.getFinalPoint(point);
+ xform.setToTranslation(point.x, point.y);
+ return xform;
+ }
+
+ double curLength = curveLength * interp;
+ for (Iterator it = bezierSegs.iterator(); it.hasNext();)
+ {
+ Bezier bez = (Bezier)it.next();
+
+ double bezLength = bez.getLength();
+ if (curLength < bezLength)
+ {
+ double param = curLength / bezLength;
+ bez.eval(param, point);
+ break;
+ }
+
+ curLength -= bezLength;
+ }
+
+ xform.setToTranslation(point.x, point.y);
+
+ return xform;
+ }
+
+ public static void main(String[] argv)
+ {
+ AnimateMotion a = new AnimateMotion();
+ a.path = buildPath("M0 0 L-400, 0", GeneralPath.WIND_NON_ZERO);
+ a.paramaterizePath();
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/AnimateTransform.java b/src/main/java/com/kitfox/svg/animation/AnimateTransform.java
new file mode 100644
index 0000000..efce6fc
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/AnimateTransform.java
@@ -0,0 +1,225 @@
+/*
+ * Animate.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 2:51 AM
+ */
+
+package com.kitfox.svg.animation;
+
+import com.kitfox.svg.xml.XMLParseUtil;
+import org.xml.sax.*;
+import java.awt.geom.*;
+
+import com.kitfox.svg.*;
+import com.kitfox.svg.xml.*;
+import java.util.regex.Pattern;
+
+/**
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class AnimateTransform extends AnimateXform
+{
+// protected AffineTransform fromValue;
+// protected AffineTransform toValue;
+// protected double[] fromValue; //Transform parameters
+// protected double[] toValue;
+ protected double[][] values;
+ protected double[] keyTimes;
+
+ public static final int AT_REPLACE = 0;
+ public static final int AT_SUM = 1;
+
+ protected int additive = AT_REPLACE;
+
+ public static final int TR_TRANSLATE = 0;
+ public static final int TR_ROTATE = 1;
+ public static final int TR_SCALE = 2;
+ public static final int TR_SKEWY = 3;
+ public static final int TR_SKEWX = 4;
+ public static final int TR_INVALID = 5;
+
+ protected int xformType = TR_INVALID;
+
+ /** Creates a new instance of Animate */
+ public AnimateTransform()
+ {
+ }
+
+ public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
+ {
+ //Load style string
+ super.loaderStartElement(helper, attrs, parent);
+
+ //Type of matrix of transform. Should be one of the known names used to
+ // define matrix transforms
+ // valid types: translate, scale, rotate, skewX, skewY
+ // 'matrix' not valid for animation
+ String type = attrs.getValue("type").toLowerCase();
+ if (type.equals("translate")) xformType = TR_TRANSLATE;
+ if (type.equals("rotate")) xformType = TR_ROTATE;
+ if (type.equals("scale")) xformType = TR_SCALE;
+ if (type.equals("skewx")) xformType = TR_SKEWX;
+ if (type.equals("skewy")) xformType = TR_SKEWY;
+
+ String fromStrn = attrs.getValue("from");
+ String toStrn = attrs.getValue("to");
+ if (fromStrn != null && toStrn != null)
+ {
+ //fromValue = parseSingleTransform(type + "(" + strn + ")");
+ double[] fromValue = XMLParseUtil.parseDoubleList(fromStrn);
+ fromValue = validate(fromValue);
+
+ // toValue = parseSingleTransform(type + "(" + strn + ")");
+ double[] toValue = XMLParseUtil.parseDoubleList(toStrn);
+ toValue = validate(toValue);
+
+ values = new double[][]{fromValue, toValue};
+ keyTimes = new double[]{0, 1};
+ }
+
+ String keyTimeStrn = attrs.getValue("keyTimes");
+ String valuesStrn = attrs.getValue("values");
+ if (keyTimeStrn != null && valuesStrn != null)
+ {
+ keyTimes = XMLParseUtil.parseDoubleList(keyTimeStrn);
+
+ String[] valueList = Pattern.compile(";").split(valuesStrn);
+ values = new double[valueList.length][];
+ for (int i = 0; i < valueList.length; i++)
+ {
+ double[] list = XMLParseUtil.parseDoubleList(valueList[i]);
+ values[i] = validate(list);
+ }
+ }
+
+ //Check our additive state
+ String additive = attrs.getValue("additive");
+ if (additive != null)
+ {
+ if (additive.equals("sum")) this.additive = AT_SUM;
+ }
+ }
+
+ /**
+ * Check list size against current xform type and ensure list
+ * is expanded to a standard list size
+ */
+ private double[] validate(double[] paramList)
+ {
+ switch (xformType)
+ {
+ case TR_SCALE:
+ {
+ if (paramList == null)
+ {
+ paramList = new double[]{1, 1};
+ }
+ else if (paramList.length == 1)
+ {
+ paramList = new double[]{paramList[0], paramList[0]};
+
+// double[] tmp = paramList;
+// paramList = new double[2];
+// paramList[0] = paramList[1] = tmp[0];
+ }
+ }
+ }
+
+ return paramList;
+ }
+
+ /**
+ * Evaluates this animation element for the passed interpolation time. Interp
+ * must be on [0..1].
+ */
+ public AffineTransform eval(AffineTransform xform, double interp)
+ {
+ int idx = 0;
+ for (; idx < keyTimes.length - 1; idx++)
+ {
+ if (interp >= keyTimes[idx])
+ {
+ idx--;
+ if (idx < 0) idx = 0;
+ break;
+ }
+ }
+
+ double spanStartTime = keyTimes[idx];
+ double spanEndTime = keyTimes[idx + 1];
+// double span = spanStartTime - spanEndTime;
+
+ interp = (interp - spanStartTime) / (spanEndTime - spanStartTime);
+ double[] fromValue = values[idx];
+ double[] toValue = values[idx + 1];
+
+ switch (xformType)
+ {
+ case TR_TRANSLATE:
+ {
+ double x = (1.0 - interp) * fromValue[0] + interp * toValue[0];
+ double y = (1.0 - interp) * fromValue[1] + interp * toValue[1];
+ xform.setToTranslation(x, y);
+ break;
+ }
+ case TR_ROTATE:
+ {
+ double x1 = fromValue.length == 3 ? fromValue[1] : 0;
+ double y1 = fromValue.length == 3 ? fromValue[2] : 0;
+ double x2 = toValue.length == 3 ? toValue[1] : 0;
+ double y2 = toValue.length == 3 ? toValue[2] : 0;
+
+ double theta = (1.0 - interp) * fromValue[0] + interp * toValue[0];
+ double x = (1.0 - interp) * x1 + interp * x2;
+ double y = (1.0 - interp) * y1 + interp * y2;
+ xform.setToRotation(Math.toRadians(theta), x, y);
+ break;
+ }
+ case TR_SCALE:
+ {
+ double x = (1.0 - interp) * fromValue[0] + interp * toValue[0];
+ double y = (1.0 - interp) * fromValue[1] + interp * toValue[1];
+ xform.setToScale(x, y);
+ break;
+ }
+ case TR_SKEWX:
+ {
+ double x = (1.0 - interp) * fromValue[0] + interp * toValue[0];
+ xform.setToShear(Math.toRadians(x), 0.0);
+ break;
+ }
+ case TR_SKEWY:
+ {
+ double y = (1.0 - interp) * fromValue[0] + interp * toValue[0];
+ xform.setToShear(0.0, Math.toRadians(y));
+ break;
+ }
+ default:
+ xform.setToIdentity();
+ break;
+ }
+
+ return xform;
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/AnimateXform.java b/src/main/java/com/kitfox/svg/animation/AnimateXform.java
new file mode 100644
index 0000000..d373d13
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/AnimateXform.java
@@ -0,0 +1,52 @@
+/*
+ * AnimateXform.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on January 14, 2005, 6:46 AM
+ */
+
+package com.kitfox.svg.animation;
+
+import org.xml.sax.*;
+import java.awt.geom.*;
+
+import com.kitfox.svg.xml.*;
+import com.kitfox.svg.*;
+
+/**
+ *
+ * @author kitfox
+ */
+abstract public class AnimateXform extends AnimateBase
+{
+ public AnimateXform()
+ {
+ }
+
+ public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
+ {
+ super.loaderStartElement(helper, attrs, parent);
+ }
+
+ abstract public AffineTransform eval(AffineTransform xform, double interp);
+
+}
diff --git a/src/main/java/com/kitfox/svg/animation/AnimationElement.java b/src/main/java/com/kitfox/svg/animation/AnimationElement.java
new file mode 100644
index 0000000..e1c7cd9
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/AnimationElement.java
@@ -0,0 +1,336 @@
+/*
+ * AnimateEle.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 2:52 AM
+ */
+
+package com.kitfox.svg.animation;
+
+import java.io.*;
+import org.xml.sax.*;
+
+import com.kitfox.svg.*;
+
+/**
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public abstract class AnimationElement extends SVGElement
+{
+ protected String attribName;
+// protected String attribType;
+ protected int attribType = AT_AUTO;
+
+ public static final int AT_CSS = 0;
+ public static final int AT_XML = 1;
+ public static final int AT_AUTO = 2; //Check CSS first, then XML
+
+ protected TimeBase beginTime;
+ protected TimeBase durTime;
+ protected TimeBase endTime;
+ protected int fillType = FT_AUTO;
+
+ /** <a href="http://www.w3.org/TR/smil20/smil-timing.html#adef-fill">More about the <b>fill</b> attribute</a> */
+ public static final int FT_REMOVE = 0;
+ public static final int FT_FREEZE = 1;
+ public static final int FT_HOLD = 2;
+ public static final int FT_TRANSITION = 3;
+ public static final int FT_AUTO = 4;
+ public static final int FT_DEFAULT = 5;
+
+ /** Additive state of track */
+ public static final int AD_REPLACE = 0;
+ public static final int AD_SUM = 1;
+
+ int additiveType = AD_REPLACE;
+
+ /** Accumlative state */
+ public static final int AC_REPLACE = 0;
+ public static final int AC_SUM = 1;
+
+ int accumulateType = AC_REPLACE;
+
+ /** Creates a new instance of AnimateEle */
+ public AnimationElement()
+ {
+ }
+
+ public static String animationElementToString(int attrValue)
+ {
+ switch (attrValue)
+ {
+ case AT_CSS:
+ return "CSS";
+ case AT_XML:
+ return "XML";
+ case AT_AUTO:
+ return "AUTO";
+ default:
+ throw new RuntimeException("Unknown element type");
+ }
+ }
+
+ public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
+ {
+ //Load style string
+ super.loaderStartElement(helper, attrs, parent);
+
+ attribName = attrs.getValue("attributeName");
+ String attribType = attrs.getValue("attributeType");
+ if (attribType != null)
+ {
+ attribType = attribType.toLowerCase();
+ if (attribType.equals("css")) this.attribType = AT_CSS;
+ else if (attribType.equals("xml")) this.attribType = AT_XML;
+ }
+
+ String beginTime = attrs.getValue("begin");
+ String durTime = attrs.getValue("dur");
+ String endTime = attrs.getValue("end");
+
+ try
+ {
+ if (beginTime != null)
+ {
+ helper.animTimeParser.ReInit(new StringReader(beginTime));
+ this.beginTime = helper.animTimeParser.Expr();
+ this.beginTime.setParentElement(this);
+ }
+
+ if (durTime != null)
+ {
+ helper.animTimeParser.ReInit(new StringReader(durTime));
+ this.durTime = helper.animTimeParser.Expr();
+ this.durTime.setParentElement(this);
+ }
+
+ if (endTime != null)
+ {
+ helper.animTimeParser.ReInit(new StringReader(endTime));
+ this.endTime = helper.animTimeParser.Expr();
+ this.endTime.setParentElement(this);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new SAXException(e);
+ }
+
+// this.beginTime = TimeBase.parseTime(beginTime);
+// this.durTime = TimeBase.parseTime(durTime);
+// this.endTime = TimeBase.parseTime(endTime);
+
+ String fill = attrs.getValue("fill");
+
+ if (fill != null)
+ {
+ if (fill.equals("remove")) this.fillType = FT_REMOVE;
+ if (fill.equals("freeze")) this.fillType = FT_FREEZE;
+ if (fill.equals("hold")) this.fillType = FT_HOLD;
+ if (fill.equals("transiton")) this.fillType = FT_TRANSITION;
+ if (fill.equals("auto")) this.fillType = FT_AUTO;
+ if (fill.equals("default")) this.fillType = FT_DEFAULT;
+ }
+
+ String additiveStrn = attrs.getValue("additive");
+
+ if (additiveStrn != null)
+ {
+ if (additiveStrn.equals("replace")) this.additiveType = AD_REPLACE;
+ if (additiveStrn.equals("sum")) this.additiveType = AD_SUM;
+ }
+
+ String accumulateStrn = attrs.getValue("accumulate");
+
+ if (accumulateStrn != null)
+ {
+ if (accumulateStrn.equals("replace")) this.accumulateType = AC_REPLACE;
+ if (accumulateStrn.equals("sum")) this.accumulateType = AC_SUM;
+ }
+ }
+
+ public String getAttribName() { return attribName; }
+ public int getAttribType() { return attribType; }
+ public int getAdditiveType() { return additiveType; }
+ public int getAccumulateType() { return accumulateType; }
+
+ public void evalParametric(AnimationTimeEval state, double curTime)
+ {
+ evalParametric(state, curTime, Double.NaN, Double.NaN);
+ }
+
+ /**
+ * Compares current time to start and end times and determines what degree
+ * of time interpolation this track currently represents. Returns
+ * Float.NaN if this track cannot be evaluated at the passed time (ie,
+ * it is before or past the end of the track, or it depends upon
+ * an unknown event)
+ * @param state - A structure that will be filled with information
+ * regarding the applicability of this animatoin element at the passed
+ * time.
+ * @param curTime - Current time in seconds
+ * @param repeatCount - Optional number of repetitions of length 'dur' to
+ * do. Set to Double.NaN to not consider this in the calculation.
+ * @param repeatDur - Optional amoun tof time to repeat the animaiton.
+ * Set to Double.NaN to not consider this in the calculation.
+ */
+ protected void evalParametric(AnimationTimeEval state, double curTime, double repeatCount, double repeatDur)
+ {
+ double begin = (beginTime == null) ? 0 : beginTime.evalTime();
+ if (Double.isNaN(begin) || begin > curTime)
+ {
+ state.set(Double.NaN, 0);
+ return;
+ }
+
+ double dur = (durTime == null) ? Double.NaN : durTime.evalTime();
+ if (Double.isNaN(dur))
+ {
+ state.set(Double.NaN, 0);
+ return;
+ }
+
+ //Determine end point of this animation
+ double end = (endTime == null) ? Double.NaN : endTime.evalTime();
+ double repeat;
+// if (Double.isNaN(repeatDur))
+// {
+// repeatDur = dur;
+// }
+ if (Double.isNaN(repeatCount) && Double.isNaN(repeatDur))
+ {
+ repeat = Double.NaN;
+ }
+ else
+ {
+ repeat = Math.min(
+ Double.isNaN(repeatCount) ? Double.POSITIVE_INFINITY : dur * repeatCount,
+ Double.isNaN(repeatDur) ? Double.POSITIVE_INFINITY : repeatDur);
+ }
+ if (Double.isNaN(repeat) && Double.isNaN(end))
+ {
+ //If neither and end point nor a repeat is specified, end point is
+ // implied by duration.
+ end = begin + dur;
+ }
+
+ double finishTime;
+ if (Double.isNaN(end))
+ {
+ finishTime = begin + repeat;
+ }
+ else if (Double.isNaN(repeat))
+ {
+ finishTime = end;
+ }
+ else
+ {
+ finishTime = Math.min(end, repeat);
+ }
+
+ double evalTime = Math.min(curTime, finishTime);
+// if (curTime > finishTime) evalTime = finishTime;
+
+
+// double evalTime = curTime;
+
+// boolean pastEnd = curTime > evalTime;
+
+// if (!Double.isNaN(end) && curTime > end) { pastEnd = true; evalTime = Math.min(evalTime, end); }
+// if (!Double.isNaN(repeat) && curTime > repeat) { pastEnd = true; evalTime = Math.min(evalTime, repeat); }
+
+ double ratio = (evalTime - begin) / dur;
+ int rep = (int)ratio;
+ double interp = ratio - rep;
+
+ //Adjust for roundoff
+ if (interp < 0.00001) interp = 0;
+
+// state.set(interp, rep);
+// if (!pastEnd)
+// {
+// state.set(interp, rep, false);
+// return;
+// }
+
+ //If we are still within the clip, return value
+ if (curTime == evalTime)
+ {
+ state.set(interp, rep);
+ return;
+ }
+
+ //We are past end of clip. Determine to clamp or ignore.
+ switch (fillType)
+ {
+ default:
+ case FT_REMOVE:
+ case FT_AUTO:
+ case FT_DEFAULT:
+ state.set(Double.NaN, rep);
+ return;
+ case FT_FREEZE:
+ case FT_HOLD:
+ case FT_TRANSITION:
+ state.set(interp == 0 ? 1 : interp, rep);
+ return;
+ }
+
+ }
+
+ double evalStartTime()
+ {
+ return beginTime == null ? Double.NaN : beginTime.evalTime();
+ }
+
+ double evalDurTime()
+ {
+ return durTime == null ? Double.NaN : durTime.evalTime();
+ }
+
+ /**
+ * Evaluates the ending time of this element. Returns 0 if not specified.
+ *
+ * @see hasEndTime
+ */
+ double evalEndTime()
+ {
+ return endTime == null ? Double.NaN : endTime.evalTime();
+ }
+
+ /**
+ * Checks to see if an end time has been specified for this element.
+ */
+ boolean hasEndTime() { return endTime != null; }
+
+ /**
+ * Updates all attributes in this diagram associated with a time event.
+ * Ie, all attributes with track information.
+ * @return - true if this node has changed state as a result of the time
+ * update
+ */
+ public boolean updateTime(double curTime)
+ {
+ //Animation elements to not change with time
+ return false;
+ }}
diff --git a/src/main/java/com/kitfox/svg/animation/AnimationTimeEval.java b/src/main/java/com/kitfox/svg/animation/AnimationTimeEval.java
new file mode 100644
index 0000000..ee79c8a
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/AnimationTimeEval.java
@@ -0,0 +1,65 @@
+/*
+ * AnimateTimeEval.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ *
+ * Created on September 21, 2004, 1:31 PM
+ */
+
+package com.kitfox.svg.animation;
+
+/**
+ *
+ * @author kitfox
+ */
+public class AnimationTimeEval
+{
+ /**
+ * Value on [0..1] representing the interpolation value of queried animation
+ * element, or Double.NaN if element does not provide a valid evalutaion
+ */
+ public double interp;
+
+ /**
+ * Number of completed repetitions
+ */
+ public int rep;
+
+ /**
+ * True if this evaluation is in a frozen state; ie, past the end of the
+ * track and held in the "freeze" state.
+ */
+// public boolean pastEnd;
+
+ /** Creates a new instance of AnimateTimeEval */
+ public AnimationTimeEval()
+ {
+ }
+
+// public void set(double interp, int rep, boolean pastEnd)
+ public void set(double interp, int rep)
+ {
+ this.interp = interp;
+ this.rep = rep;
+// this.pastEnd = pastEnd;
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/Bezier.java b/src/main/java/com/kitfox/svg/animation/Bezier.java
new file mode 100644
index 0000000..1fae8c1
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/Bezier.java
@@ -0,0 +1,201 @@
+/*
+ * Bezier.java
+ *
+
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on January 14, 2005, 4:08 AM
+ */
+
+package com.kitfox.svg.animation;
+
+import java.awt.geom.*;
+
+/**
+ * http://mathworld.wolfram.com/BezierCurve.html
+ * @author kitfox
+ */
+public class Bezier
+{
+ double length;
+ double[] coord;
+
+ public Bezier(double sx, double sy, double[] coords, int numCoords)
+ {
+ setCoords(sx, sy, coords, numCoords);
+ }
+
+ public void setCoords(double sx, double sy, double[] coords, int numCoords)
+ {
+ coord = new double[numCoords * 2 + 2];
+ coord[0] = sx;
+ coord[1] = sy;
+ for (int i = 0; i < numCoords; i++)
+ {
+ coord[i * 2 + 2] = coords[i * 2];
+ coord[i * 2 + 3] = coords[i * 2 + 1];
+ }
+
+ calcLength();
+ }
+
+ /**
+ * Retuns aproximation of the length of the bezier
+ */
+ public double getLength()
+ {
+ return length;
+ }
+
+ private void calcLength()
+ {
+ length = 0;
+ for (int i = 2; i < coord.length; i += 2)
+ {
+ length += lineLength(coord[i - 2], coord[i - 1], coord[i], coord[i + 1]);
+ }
+ }
+
+ private double lineLength(double x1, double y1, double x2, double y2)
+ {
+ double dx = x2 - x1, dy = y2 - y1;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ public Point2D.Double getFinalPoint(Point2D.Double point)
+ {
+ point.x = coord[coord.length - 2];
+ point.y = coord[coord.length - 1];
+ return point;
+ }
+
+ public Point2D.Double eval(double param, Point2D.Double point)
+ {
+ point.x = 0;
+ point.y = 0;
+ int numKnots = coord.length / 2;
+
+ for (int i = 0; i < numKnots; i++)
+ {
+ double scale = bernstein(numKnots - 1, i, param);
+ point.x += coord[i * 2] * scale;
+ point.y += coord[i * 2 + 1] * scale;
+ }
+
+ return point;
+ }
+
+ /**
+ * Calculates the bernstein polynomial for evaluating parametric bezier
+ * @param numKnots - one less than number of knots in this curve hull
+ * @param knotNo - knot we are evaluating Bernstein for
+ * @param param - Parametric value we are evaluating at
+ */
+ private double bernstein(int numKnots, int knotNo, double param)
+ {
+ double iParam = 1 - param;
+ //Faster evaluation for easy cases:
+ switch (numKnots)
+ {
+ case 0:
+ return 1;
+ case 1:
+ {
+ switch (knotNo)
+ {
+ case 0:
+ return iParam;
+ case 1:
+ return param;
+ }
+ break;
+ }
+ case 2:
+ {
+ switch (knotNo)
+ {
+ case 0:
+ return iParam * iParam;
+ case 1:
+ return 2 * iParam * param;
+ case 2:
+ return param * param;
+ }
+ break;
+ }
+ case 3:
+ {
+ switch (knotNo)
+ {
+ case 0:
+ return iParam * iParam * iParam;
+ case 1:
+ return 3 * iParam * iParam * param;
+ case 2:
+ return 3 * iParam * param * param;
+ case 3:
+ return param * param * param;
+ }
+ break;
+ }
+ }
+
+ //If this bezier has more than four points, calculate bernstein the hard way
+ double retVal = 1;
+ for (int i = 0; i < knotNo; i++)
+ {
+ retVal *= param;
+ }
+ for (int i = 0; i < numKnots - knotNo; i++)
+ {
+ retVal *= iParam;
+ }
+ retVal *= choose(numKnots, knotNo);
+
+ return retVal;
+ }
+
+
+
+ private int choose(int num, int denom)
+ {
+ int denom2 = num - denom;
+ if (denom < denom2)
+ {
+ int tmp = denom;
+ denom = denom2;
+ denom2 = tmp;
+ }
+
+ int prod = 1;
+ for (int i = num; i > denom; i--)
+ {
+ prod *= num;
+ }
+
+ for (int i = 2; i <= denom2; i++)
+ {
+ prod /= i;
+ }
+
+ return prod;
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/SetSmil.java b/src/main/java/com/kitfox/svg/animation/SetSmil.java
new file mode 100644
index 0000000..3ada7c9
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/SetSmil.java
@@ -0,0 +1,55 @@
+/*
+ * Set.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 2:51 AM
+ */
+
+package com.kitfox.svg.animation;
+
+import org.xml.sax.*;
+
+import com.kitfox.svg.*;
+
+/**
+ * Set is used to set a textual value; most likely for a style element.
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class SetSmil extends AnimationElement
+{
+ String toValue;
+
+ /** Creates a new instance of Set */
+ public SetSmil()
+ {
+ }
+
+ public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
+ {
+ //Load style string
+ super.loaderStartElement(helper, attrs, parent);
+
+ toValue = attrs.getValue("to");
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TimeBase.java b/src/main/java/com/kitfox/svg/animation/TimeBase.java
new file mode 100644
index 0000000..2f2f189
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TimeBase.java
@@ -0,0 +1,99 @@
+/*
+ * TimeBase.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 3:31 AM
+ */
+
+package com.kitfox.svg.animation;
+
+import java.util.regex.*;
+
+/**
+ * SVG has a complicated way of specifying time. Potentially, a time could
+ * be represened as a summation of discrete times and times of other animation
+ * events. This provides a root for the many elements we will need to define
+ * time.
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+abstract public class TimeBase
+{
+ static final Matcher matchIndefinite = Pattern.compile("\\s*indefinite\\s*").matcher("");
+ static final Matcher matchUnitTime = Pattern.compile("\\s*([-+]?((\\d*\\.\\d+)|(\\d+))([-+]?[eE]\\d+)?)\\s*(h|min|s|ms)?\\s*").matcher("");
+
+ /*
+ public static TimeBase parseTime(String text)
+ {
+ if (text == null) return null;
+
+ if (text.indexOf('+') == -1)
+ {
+ return parseTimeComponent(text);
+ }
+
+ return new TimeCompound(text);
+ }
+ */
+
+ protected static TimeBase parseTimeComponent(String text)
+ {
+ matchIndefinite.reset(text);
+ if (matchIndefinite.matches()) return new TimeIndefinite();
+
+ matchUnitTime.reset(text);
+ if (matchUnitTime.matches())
+ {
+ String val = matchUnitTime.group(1);
+ String units = matchUnitTime.group(6);
+
+ double time = 0;
+ try { time = Double.parseDouble(val); }
+ catch (Exception e) {}
+
+ if (units.equals("ms")) time *= .001;
+ else if (units.equals("min")) time *= 60;
+ else if (units.equals("h")) time *= 3600;
+
+ return new TimeDiscrete(time);
+ }
+
+ return null;
+ }
+
+ /**
+ * Calculates the (greater than or equal to 0) time in seconds this
+ * time represents. If the time cannot be determined, returns
+ * Double.NaN. If this represents an infinte amount of time, returns
+ * Double.POSITIVE_INFINITY.
+ */
+ abstract public double evalTime();
+
+ /**
+ * Some time elements need to refer to the animation element that contains
+ * them to evaluate correctly
+ */
+ public void setParentElement(AnimationElement ele)
+ {
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TimeCompound.java b/src/main/java/com/kitfox/svg/animation/TimeCompound.java
new file mode 100644
index 0000000..0545fc6
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TimeCompound.java
@@ -0,0 +1,96 @@
+/*
+ * TimeDiscrete.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 3:33 AM
+ */
+
+package com.kitfox.svg.animation;
+
+import java.util.*;
+import java.util.regex.*;
+
+/**
+ * This represents a summation of other time elements. It is used for complex
+ * timing events with offsets.
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class TimeCompound extends TimeBase
+{
+ static final Pattern patPlus = Pattern.compile("\\+");
+
+ /**
+ * This is a list of times. This element's time is calculated as the greatest
+ * member that is less than the current time.
+ */
+ final List componentTimes;
+
+ private AnimationElement parent;
+
+ /** Creates a new instance of TimeDiscrete */
+ public TimeCompound(Vector timeBases)
+ {
+ componentTimes = Collections.unmodifiableList(timeBases);
+ }
+
+ /*
+ public TimeCompound(String text)
+ {
+ String[] vals = patPlus.split(text);
+
+ Vector times = new Vector(vals.length);
+
+ for (int i = 0; i < vals.length; i++)
+ {
+ times.set(i, parseTimeComponent(vals[i]));
+ }
+
+ this(times);
+ }*/
+
+ public double evalTime()
+ {
+ double agg = 0.0;
+
+ for (Iterator it = componentTimes.iterator(); it.hasNext();)
+ {
+ TimeBase timeEle = (TimeBase)it.next();
+ double time = timeEle.evalTime();
+ agg += time;
+ }
+
+ return agg;
+ }
+
+ public void setParentElement(AnimationElement ele)
+ {
+ this.parent = ele;
+
+ for (Iterator it = componentTimes.iterator(); it.hasNext();)
+ {
+ TimeBase timeEle = (TimeBase)it.next();
+ timeEle.setParentElement(ele);
+ }
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TimeDiscrete.java b/src/main/java/com/kitfox/svg/animation/TimeDiscrete.java
new file mode 100644
index 0000000..dab7dc1
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TimeDiscrete.java
@@ -0,0 +1,51 @@
+/*
+ * TimeDiscrete.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 3:33 AM
+ */
+
+package com.kitfox.svg.animation;
+
+/**
+ * This is a time that represents a specific number of milliseconds
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class TimeDiscrete extends TimeBase
+{
+ //Milliseconds of delay
+ double secs;
+
+ /** Creates a new instance of TimeDiscrete */
+ public TimeDiscrete(double secs)
+ {
+ this.secs = secs;
+ }
+
+ public double evalTime()
+ {
+ return secs;
+ }
+
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TimeIndefinite.java b/src/main/java/com/kitfox/svg/animation/TimeIndefinite.java
new file mode 100644
index 0000000..b3859f1
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TimeIndefinite.java
@@ -0,0 +1,48 @@
+/*
+ * TimeDiscrete.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 3:33 AM
+ */
+
+package com.kitfox.svg.animation;
+
+/**
+ * This represents the indefinite (infinite) amount of time.
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class TimeIndefinite extends TimeBase
+{
+
+ /** Creates a new instance of TimeDiscrete */
+ public TimeIndefinite()
+ {
+ }
+
+ public double evalTime()
+ {
+ return Double.POSITIVE_INFINITY;
+ }
+
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TimeLookup.java b/src/main/java/com/kitfox/svg/animation/TimeLookup.java
new file mode 100644
index 0000000..e6120bd
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TimeLookup.java
@@ -0,0 +1,75 @@
+/*
+ * TimeDiscrete.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 3:33 AM
+ */
+
+package com.kitfox.svg.animation;
+
+/**
+ * This is a time that represents a specific number of milliseconds
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class TimeLookup extends TimeBase
+{
+ /**
+ * This time can only be resolved in relation to it's parent
+ */
+ private AnimationElement parent;
+
+ /**
+ * Node this lookup acts upon
+ */
+ String node;
+
+ /**
+ * Event to evalutae on this node
+ */
+ String event;
+
+ /**
+ * Optional parameter used by some events
+ */
+ String paramList;
+
+ /** Creates a new instance of TimeDiscrete */
+ public TimeLookup(AnimationElement parent, String node, String event, String paramList)
+ {
+ this.parent = parent;
+ this.node = node;
+ this.event = event;
+ this.paramList = paramList;
+ }
+
+ public double evalTime()
+ {
+ return 0.0;
+ }
+
+ public void setParentElement(AnimationElement ele)
+ {
+ parent = ele;
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TimeSum.java b/src/main/java/com/kitfox/svg/animation/TimeSum.java
new file mode 100644
index 0000000..82c98fe
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TimeSum.java
@@ -0,0 +1,60 @@
+/*
+ * TimeDiscrete.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 3:33 AM
+ */
+
+package com.kitfox.svg.animation;
+
+/**
+ * This is a time that represents a specific number of milliseconds
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class TimeSum extends TimeBase
+{
+ //Milliseconds of delay
+ TimeBase t1;
+ TimeBase t2;
+ boolean add;
+
+ /** Creates a new instance of TimeDiscrete */
+ public TimeSum(TimeBase t1, TimeBase t2, boolean add)
+ {
+ this.t1 = t1;
+ this.t2 = t2;
+ this.add = add;
+ }
+
+ public double evalTime()
+ {
+ return add ? t1.evalTime() + t2.evalTime() : t1.evalTime() - t2.evalTime();
+ }
+
+ public void setParentElement(AnimationElement ele)
+ {
+ t1.setParentElement(ele);
+ t2.setParentElement(ele);
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TrackBase.java b/src/main/java/com/kitfox/svg/animation/TrackBase.java
new file mode 100644
index 0000000..a38866f
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TrackBase.java
@@ -0,0 +1,104 @@
+/*
+ * TrackManager.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 11:34 PM
+ */
+
+package com.kitfox.svg.animation;
+
+import com.kitfox.svg.xml.StyleAttribute;
+import java.util.*;
+
+import com.kitfox.svg.xml.*;
+import com.kitfox.svg.*;
+
+/**
+ * A track holds the animation events for a single parameter of a single SVG
+ * element. It also contains the default value for the element, should the
+ * user want to see the 'unanimated' value.
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+abstract public class TrackBase
+{
+ protected final String attribName;
+ protected final int attribType; //AnimationElement.AT_*
+
+ /** Element we're animating */
+ protected final SVGElement parent;
+
+ //It doesn't make sense to sort this, since some events will depend on
+ // other events - in many cases, there will be no meaningful sorted order.
+ final Vector animEvents = new Vector();
+
+ /** Creates a new instance of TrackManager */
+// public TrackBase(SVGElement parent)
+// {
+// this(parent, "", AnimationElement.AT_AUTO);
+// }
+
+ /**
+ * Creates a track that would be valid for the name and type of element
+ * passed in. Does not actually add this elemnt to the track.
+ */
+ public TrackBase(SVGElement parent, AnimationElement ele) throws SVGElementException
+ {
+ this(parent, ele.getAttribName(), ele.getAttribType());
+ }
+
+ public TrackBase(SVGElement parent, String attribName, int attribType) throws SVGElementException
+ {
+ this.parent = parent;
+ this.attribName = attribName;
+ this.attribType = attribType;
+
+ //Make sure parent has an attribute we will write to
+ if (attribType == AnimationElement.AT_AUTO
+ && !parent.hasAttribute(attribName, AnimationElement.AT_CSS)
+ && !parent.hasAttribute(attribName, AnimationElement.AT_XML))
+ {
+ parent.addAttribute(attribName, AnimationElement.AT_CSS, "");
+ }
+ else if (!parent.hasAttribute(attribName, attribType))
+ {
+ parent.addAttribute(attribName, attribType, "");
+ }
+ }
+
+ public String getAttribName() { return attribName; }
+ public int getAttribType() { return attribType; }
+
+ public void addElement(AnimationElement ele)
+ {
+ animEvents.add(ele);
+ }
+
+ /**
+ * Returns a StyleAttribute representing the value of this track at the
+ * passed time. If this track does not apply, returns null.
+ * @return - True if successful, false if a value could not be obtained
+ */
+ abstract public boolean getValue(StyleAttribute attrib, double curTime) throws SVGException;
+
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TrackColor.java b/src/main/java/com/kitfox/svg/animation/TrackColor.java
new file mode 100644
index 0000000..97a8f3c
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TrackColor.java
@@ -0,0 +1,95 @@
+/*
+ * TrackManager.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on September 21, 2004, 11:34 PM
+ */
+
+package com.kitfox.svg.animation;
+
+import com.kitfox.svg.xml.StyleAttribute;
+import java.awt.*;
+import java.util.*;
+
+import com.kitfox.svg.*;
+import com.kitfox.svg.xml.*;
+
+/**
+ * A track holds the animation events for a single parameter of a single SVG
+ * element. It also contains the default value for the element, should the
+ * user want to see the 'unanimated' value.
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class TrackColor extends TrackBase
+{
+
+ public TrackColor(AnimationElement ele) throws SVGElementException
+ {
+ super(ele.getParent(), ele);
+ }
+
+ public boolean getValue(StyleAttribute attrib, double curTime)
+ {
+ Color col = getValue(curTime);
+ if (col == null) return false;
+
+ attrib.setStringValue("#" + Integer.toHexString(col.getRGB()));
+ return true;
+ }
+
+ public Color getValue(double curTime)
+ {
+ Color retVal = null;
+ AnimationTimeEval state = new AnimationTimeEval();
+
+ for (Iterator it = animEvents.iterator(); it.hasNext();)
+ {
+ AnimateBase ele = (AnimateBase)it.next();
+ AnimateColorIface eleColor = (AnimateColorIface)ele;
+ ele.evalParametric(state, curTime);
+
+ //Reject value if it is in the invalid state
+ if (Double.isNaN(state.interp)) continue;
+
+ if (retVal == null)
+ {
+ retVal = eleColor.evalColor(state.interp);
+ continue;
+ }
+
+ Color curCol = eleColor.evalColor(state.interp);
+ switch (ele.getAdditiveType())
+ {
+ case AnimationElement.AD_REPLACE:
+ retVal = curCol;
+ break;
+ case AnimationElement.AD_SUM:
+ retVal = new Color(curCol.getRed() + retVal.getRed(), curCol.getGreen() + retVal.getGreen(), curCol.getBlue() + retVal.getBlue());
+ break;
+ }
+ }
+
+ return retVal;
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TrackDouble.java b/src/main/java/com/kitfox/svg/animation/TrackDouble.java
new file mode 100644
index 0000000..211cb2f
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TrackDouble.java
@@ -0,0 +1,119 @@
+/*
+ * TrackManager.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 11:34 PM
+ */
+
+package com.kitfox.svg.animation;
+
+import com.kitfox.svg.xml.StyleAttribute;
+import java.util.*;
+
+import com.kitfox.svg.*;
+import com.kitfox.svg.xml.*;
+
+/**
+ * A track holds the animation events for a single parameter of a single SVG
+ * element. It also contains the default value for the element, should the
+ * user want to see the 'unanimated' value.
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class TrackDouble extends TrackBase
+{
+ public TrackDouble(AnimationElement ele) throws SVGElementException
+ {
+ super(ele.getParent(), ele);
+ }
+
+ public boolean getValue(StyleAttribute attrib, double curTime)
+ {
+ double val = getValue(curTime);
+ if (Double.isNaN(val)) return false;
+
+ attrib.setStringValue("" + val);
+ return true;
+ }
+
+ public double getValue(double curTime)
+ {
+ double retVal = Double.NaN;
+
+ StyleAttribute attr = null;
+ switch (attribType)
+ {
+ case AnimationElement.AT_CSS:
+ attr = parent.getStyleAbsolute(attribName);
+ retVal = attr.getDoubleValue();
+ break;
+ case AnimationElement.AT_XML:
+ attr = parent.getPresAbsolute(attribName);
+ retVal = attr.getDoubleValue();
+ break;
+ case AnimationElement.AT_AUTO:
+ attr = parent.getStyleAbsolute(attribName);
+ if (attr == null) attr = parent.getPresAbsolute(attribName);
+ retVal = attr.getDoubleValue();
+ break;
+ }
+
+
+
+ AnimationTimeEval state = new AnimationTimeEval();
+// boolean pastEnd = true;
+
+ for (Iterator it = animEvents.iterator(); it.hasNext();)
+ {
+ Animate ele = (Animate)it.next();
+ ele.evalParametric(state, curTime);
+
+ //Go to next element if this one does not affect processing
+ if (Double.isNaN(state.interp)) continue;
+
+ switch (ele.getAdditiveType())
+ {
+ case AnimationElement.AD_SUM:
+ retVal += ele.eval(state.interp);
+ break;
+ case AnimationElement.AD_REPLACE:
+ retVal = ele.eval(state.interp);
+ break;
+ }
+
+ //Evalutae accumulation if applicable
+ if (state.rep > 0)
+ {
+ switch (ele.getAccumulateType())
+ {
+ case AnimationElement.AC_SUM:
+ retVal += ele.repeatSkipSize(state.rep);
+ break;
+ }
+
+ }
+ }
+
+ return retVal;
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TrackManager.java b/src/main/java/com/kitfox/svg/animation/TrackManager.java
new file mode 100644
index 0000000..b8e6305
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TrackManager.java
@@ -0,0 +1,153 @@
+/*
+ * TrackManager.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on August 15, 2004, 11:34 PM
+ */
+
+package com.kitfox.svg.animation;
+
+import java.util.*;
+
+import com.kitfox.svg.*;
+import java.io.Serializable;
+
+/**
+ * Every element contains tracks, which manage the animation. There is one track
+ * for every parameter with animation, and each track in turn is composed of
+ * many events.
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class TrackManager implements Serializable
+{
+ public static final long serialVersionUID = 0;
+
+ static class TrackKey
+ {
+ String name;
+ int type;
+
+ TrackKey(AnimationElement base)
+ {
+ this(base.getAttribName(), base.getAttribType());
+ }
+
+ TrackKey(String name, int type)
+ {
+ this.name = name;
+ this.type = type;
+ }
+
+ public int hashCode() { return name.hashCode() ^ type; }
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof TrackKey)) return false;
+ TrackKey key = (TrackKey)obj;
+ return key.type == type && key.name.equals(name);
+ }
+ }
+
+ HashMap tracks = new HashMap();
+
+ /** Creates a new instance of TrackManager */
+ public TrackManager()
+ {
+ }
+
+ /**
+ * Adds a new animation element to this track
+ */
+ public void addTrackElement(AnimationElement element) throws SVGElementException
+ {
+ TrackKey key = new TrackKey(element);
+
+ TrackBase track = (TrackBase)tracks.get(key);
+
+ if (track == null)
+ {
+ //Create a track for this element
+ if (element instanceof Animate)
+ {
+ switch (((Animate)element).getDataType())
+ {
+ case Animate.DT_REAL:
+ track = new TrackDouble(element);
+ break;
+ case Animate.DT_COLOR:
+ track = new TrackColor(element);
+ break;
+ case Animate.DT_PATH:
+ track = new TrackPath(element);
+ break;
+ default:
+ throw new RuntimeException("");
+ }
+ }
+ else if (element instanceof AnimateColor)
+ {
+ track = new TrackColor(element);
+ }
+ else if (element instanceof AnimateTransform || element instanceof AnimateMotion)
+ {
+ track = new TrackTransform(element);
+ }
+
+ tracks.put(key, track);
+ }
+
+ track.addElement(element);
+ }
+
+ public TrackBase getTrack(String name, int type)
+ {
+ //Handle AUTO, which will match either CSS or XML (in that order)
+ if (type == AnimationElement.AT_AUTO)
+ {
+ TrackBase t = getTrack(name, AnimationElement.AT_CSS);
+ if (t != null) return t;
+ t = getTrack(name, AnimationElement.AT_XML);
+ if (t != null) return t;
+ return null;
+ }
+
+ //Get requested attribute
+ TrackKey key = new TrackKey(name, type);
+ TrackBase t = (TrackBase)tracks.get(key);
+ if (t != null) return t;
+
+ //If that didn't exist, see if one exists of type AUTO
+ key = new TrackKey(name, AnimationElement.AT_AUTO);
+ return (TrackBase)tracks.get(key);
+ }
+
+ public int getNumTracks()
+ {
+ return tracks.size();
+ }
+
+ public Iterator iterator()
+ {
+ return tracks.values().iterator();
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TrackMotion.java b/src/main/java/com/kitfox/svg/animation/TrackMotion.java
new file mode 100644
index 0000000..6cb8578
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TrackMotion.java
@@ -0,0 +1,128 @@
+/*
+ * TrackManager.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on September 21, 2004, 11:34 PM
+ */
+
+package com.kitfox.svg.animation;
+
+import com.kitfox.svg.xml.StyleAttribute;
+import java.awt.geom.*;
+import java.util.*;
+
+import com.kitfox.svg.*;
+import com.kitfox.svg.xml.*;
+
+/**
+ * A track holds the animation events for a single parameter of a single SVG
+ * element. It also contains the default value for the element, should the
+ * user want to see the 'unanimated' value.
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class TrackMotion extends TrackBase
+{
+ public TrackMotion(AnimationElement ele) throws SVGElementException
+ {
+ //The motion element implies a CSS attribute of transform
+// super(ele.getParent(), "transform", AnimationElement.AT_CSS);
+ super(ele.getParent(), ele);
+ }
+
+ public boolean getValue(StyleAttribute attrib, double curTime) throws SVGException
+ {
+ AffineTransform retVal = new AffineTransform();
+ retVal = getValue(retVal, curTime);
+// AffineTransform val = getValue(curTime);
+// if (val == null) return false;
+
+ double[] mat = new double[6];
+ retVal.getMatrix(mat);
+ attrib.setStringValue("matrix(" + mat[0] + " " + mat[1] + " " + mat[2] + " " + mat[3] + " " + mat[4] + " " + mat[5] + ")");
+ return true;
+ }
+
+ public AffineTransform getValue(AffineTransform retVal, double curTime) throws SVGException
+ {
+ //Init transform with default state
+ StyleAttribute attr = null;
+ switch (attribType)
+ {
+ case AnimationElement.AT_CSS:
+ attr = parent.getStyleAbsolute(attribName);
+ retVal.setTransform(SVGElement.parseSingleTransform(attr.getStringValue()));
+ break;
+ case AnimationElement.AT_XML:
+ attr = parent.getPresAbsolute(attribName);
+ retVal.setTransform(SVGElement.parseSingleTransform(attr.getStringValue()));
+ break;
+ case AnimationElement.AT_AUTO:
+ attr = parent.getStyleAbsolute(attribName);
+ if (attr == null) attr = parent.getPresAbsolute(attribName);
+ retVal.setTransform(SVGElement.parseSingleTransform(attr.getStringValue()));
+ break;
+ }
+
+
+ //Update transform with time based information
+ AnimationTimeEval state = new AnimationTimeEval();
+ AffineTransform xform = new AffineTransform();
+// boolean pastEnd = true;
+
+ for (Iterator it = animEvents.iterator(); it.hasNext();)
+ {
+ AnimateMotion ele = (AnimateMotion)it.next();
+ ele.evalParametric(state, curTime);
+
+ //Go to next element if this one does not affect processing
+ if (Double.isNaN(state.interp)) continue;
+
+ switch (ele.getAdditiveType())
+ {
+ case AnimationElement.AD_SUM:
+ retVal.concatenate(ele.eval(xform, state.interp));
+ break;
+ case AnimationElement.AD_REPLACE:
+ retVal.setTransform(ele.eval(xform, state.interp));
+ break;
+ }
+
+ //Evaluate accumulation if applicable
+/*
+ if (state.rep > 0)
+ {
+ switch (ele.getAccumulateType())
+ {
+ case AnimationElement.AC_SUM:
+ retVal += ele.repeatSkipSize(state.rep);
+ break;
+ }
+
+ }
+*/
+ }
+
+ return retVal;
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TrackPath.java b/src/main/java/com/kitfox/svg/animation/TrackPath.java
new file mode 100644
index 0000000..e2822f6
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TrackPath.java
@@ -0,0 +1,100 @@
+/*
+ * TrackManager.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on September 21, 2004, 11:34 PM
+ */
+
+package com.kitfox.svg.animation;
+
+import com.kitfox.svg.xml.StyleAttribute;
+import java.awt.*;
+import java.awt.geom.*;
+import java.util.*;
+
+import com.kitfox.svg.pathcmd.*;
+import com.kitfox.svg.*;
+import com.kitfox.svg.xml.*;
+
+/**
+ * A track holds the animation events for a single parameter of a single SVG
+ * element. It also contains the default value for the element, should the
+ * user want to see the 'unanimated' value.
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class TrackPath extends TrackBase
+{
+
+ public TrackPath(AnimationElement ele) throws SVGElementException
+ {
+ super(ele.getParent(), ele);
+ }
+
+ public boolean getValue(StyleAttribute attrib, double curTime)
+ {
+ GeneralPath path = getValue(curTime);
+ if (path == null) return false;
+
+ attrib.setStringValue(PathUtil.buildPathString(path));
+ return true;
+ }
+
+ public GeneralPath getValue(double curTime)
+ {
+ GeneralPath retVal = null;
+ AnimationTimeEval state = new AnimationTimeEval();
+
+ for (Iterator it = animEvents.iterator(); it.hasNext();)
+ {
+ AnimateBase ele = (AnimateBase)it.next();
+ Animate eleAnim = (Animate)ele;
+ ele.evalParametric(state, curTime);
+
+ //Reject value if it is in the invalid state
+ if (Double.isNaN(state.interp)) continue;
+
+ if (retVal == null)
+ {
+ retVal = eleAnim.evalPath(state.interp);
+ continue;
+ }
+
+ GeneralPath curPath = eleAnim.evalPath(state.interp);
+ switch (ele.getAdditiveType())
+ {
+ case AnimationElement.AD_REPLACE:
+ retVal = curPath;
+ break;
+ case AnimationElement.AD_SUM:
+ throw new RuntimeException("Not implemented");
+// retVal = new Color(curCol.getRed() + retVal.getRed(), curCol.getGreen() + retVal.getGreen(), curCol.getBlue() + retVal.getBlue());
+// break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+ return retVal;
+ }
+}
diff --git a/src/main/java/com/kitfox/svg/animation/TrackTransform.java b/src/main/java/com/kitfox/svg/animation/TrackTransform.java
new file mode 100644
index 0000000..d925923
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/animation/TrackTransform.java
@@ -0,0 +1,112 @@
+/*
+ * TrackManager.java
+ *
+ * The Salamander Project - 2D and 3D graphics libraries in Java
+ * Copyright (C) 2004 Mark McKay
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
+ * projects can be found at http://www.kitfox.com
+ *
+ * Created on September 21, 2004, 11:34 PM
+ */
+
+package com.kitfox.svg.animation;
+
+import com.kitfox.svg.xml.StyleAttribute;
+import java.awt.geom.*;
+import java.util.*;
+
+import com.kitfox.svg.*;
+import com.kitfox.svg.xml.*;
+
+/**
+ * A track holds the animation events for a single parameter of a single SVG
+ * element. It also contains the default value for the element, should the
+ * user want to see the 'unanimated' value.
+ *
+ * @author Mark McKay
+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
+ */
+public class TrackTransform extends TrackBase
+{
+ public TrackTransform(AnimationElement ele) throws SVGElementException
+ {
+ super(ele.getParent(), ele);
+ }
+
+ public boolean getValue(StyleAttribute attrib, double curTime) throws SVGException
+ {
+ AffineTransform retVal = new AffineTransform();
+ retVal = getValue(retVal, curTime);
+// AffineTransform val = getValue(curTime);
+// if (val == null) return false;
+
+ double[] mat = new double[6];
+ retVal.getMatrix(mat);
+ attrib.setStringValue("matrix(" + mat[0] + " " + mat[1] + " " + mat[2] + " " + mat[3] + " " + mat[4] + " " + mat[5] + ")");
+ return true;
+ }
+
+ public AffineTransform getValue(AffineTransform retVal, double curTime) throws SVGException
+ {
+ //Init transform with default state
+ StyleAttribute attr = null;
+ switch (attribType)
+ {
+ case AnimationElement.AT_CSS:
+ attr = parent.getStyleAbsolute(attribName);
+ retVal.setTransform(SVGElement.parseSingleTransform(attr.getStringValue()));
+ break;
+ case AnimationElement.AT_XML:
+ attr = parent.getPresAbsolute(attribName);
+ retVal.setTransform(SVGElement.parseSingleTransform(attr.getStringValue()));
+ break;
+ case AnimationElement.AT_AUTO:
+ attr = parent.getStyleAbsolute(attribName);
+ if (attr == null) attr = parent.getPresAbsolute(attribName);
+ retVal.setTransform(SVGElement.parseSingleTransform(attr.getStringValue()));
+ break;
+ }
+
+
+ //Update transform with time based information
+ AnimationTimeEval state = new AnimationTimeEval();
+ AffineTransform xform = new AffineTransform();
+
+ for (Iterator it = animEvents.iterator(); it.hasNext();)
+ {
+ AnimateXform ele = (AnimateXform)it.next();
+ ele.evalParametric(state, curTime);
+
+ //Go to next element if this one does not affect processing
+ if (Double.isNaN(state.interp)) continue;
+
+ switch (ele.getAdditiveType())
+ {
+ case AnimationElement.AD_SUM:
+ retVal.concatenate(ele.eval(xform, state.interp));
+ break;
+ case AnimationElement.AD_REPLACE:
+ retVal.setTransform(ele.eval(xform, state.interp));
+ break;
+ }
+
+ }
+
+ return retVal;
+ }
+}