com.kitfox.svg.animation.AnimationElement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of svgSalamander Show documentation
Show all versions of svgSalamander Show documentation
A tool for displaying and playing SVG content using the Java2D.
/*
* SVG Salamander
* Copyright (c) 2004, Mark McKay
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Mark McKay can be contacted at [email protected]. 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 com.kitfox.svg.SVGConst;
import com.kitfox.svg.SVGElement;
import com.kitfox.svg.SVGException;
import com.kitfox.svg.SVGLoaderHelper;
import com.kitfox.svg.animation.parser.AnimTimeParser;
import com.kitfox.svg.animation.parser.ParseException;
import com.kitfox.svg.xml.StyleAttribute;
import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* @author Mark McKay
* @author Mark McKay
*/
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
private TimeBase beginTime;
private TimeBase durTime;
private TimeBase endTime;
private int fillType = FT_AUTO;
/** More about the fill attribute */
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;
private int additiveType = AD_REPLACE;
/** Accumlative state */
public static final int AC_REPLACE = 0;
public static final int AC_SUM = 1;
private 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");
}
}
@Override
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
*/
@Override
public boolean updateTime(double curTime)
{
//Animation elements to not change with time
return false;
}
public void rebuild() throws SVGException
{
AnimTimeParser animTimeParser = new AnimTimeParser(new StringReader(""));
rebuild(animTimeParser);
}
protected void rebuild(AnimTimeParser animTimeParser) throws SVGException
{
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("begin")))
{
String newVal = sty.getStringValue();
animTimeParser.ReInit(new StringReader(newVal));
try {
this.beginTime = animTimeParser.Expr();
} catch (ParseException ex) {
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse '" + newVal + "'", ex);
}
}
if (getPres(sty.setName("dur")))
{
String newVal = sty.getStringValue();
animTimeParser.ReInit(new StringReader(newVal));
try {
this.durTime = animTimeParser.Expr();
} catch (ParseException ex) {
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse '" + newVal + "'", ex);
}
}
if (getPres(sty.setName("end")))
{
String newVal = sty.getStringValue();
animTimeParser.ReInit(new StringReader(newVal));
try {
this.endTime = animTimeParser.Expr();
} catch (ParseException ex) {
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse '" + newVal + "'", ex);
}
}
if (getPres(sty.setName("fill")))
{
String newVal = sty.getStringValue();
if (newVal.equals("remove")) this.fillType = FT_REMOVE;
if (newVal.equals("freeze")) this.fillType = FT_FREEZE;
if (newVal.equals("hold")) this.fillType = FT_HOLD;
if (newVal.equals("transiton")) this.fillType = FT_TRANSITION;
if (newVal.equals("auto")) this.fillType = FT_AUTO;
if (newVal.equals("default")) this.fillType = FT_DEFAULT;
}
if (getPres(sty.setName("additive")))
{
String newVal = sty.getStringValue();
if (newVal.equals("replace")) this.additiveType = AD_REPLACE;
if (newVal.equals("sum")) this.additiveType = AD_SUM;
}
if (getPres(sty.setName("accumulate")))
{
String newVal = sty.getStringValue();
if (newVal.equals("replace")) this.accumulateType = AC_REPLACE;
if (newVal.equals("sum")) this.accumulateType = AC_SUM;
}
}
/**
* @return the beginTime
*/
public TimeBase getBeginTime()
{
return beginTime;
}
/**
* @param beginTime the beginTime to set
*/
public void setBeginTime(TimeBase beginTime)
{
this.beginTime = beginTime;
}
/**
* @return the durTime
*/
public TimeBase getDurTime()
{
return durTime;
}
/**
* @param durTime the durTime to set
*/
public void setDurTime(TimeBase durTime)
{
this.durTime = durTime;
}
/**
* @return the endTime
*/
public TimeBase getEndTime()
{
return endTime;
}
/**
* @param endTime the endTime to set
*/
public void setEndTime(TimeBase endTime)
{
this.endTime = endTime;
}
/**
* @return the fillType
*/
public int getFillType()
{
return fillType;
}
/**
* @param fillType the fillType to set
*/
public void setFillType(int fillType)
{
this.fillType = fillType;
}
/**
* @param additiveType the additiveType to set
*/
public void setAdditiveType(int additiveType)
{
this.additiveType = additiveType;
}
/**
* @param accumulateType the accumulateType to set
*/
public void setAccumulateType(int accumulateType)
{
this.accumulateType = accumulateType;
}
}