source: josm/trunk/src/com/kitfox/svg/SVGElement.java@ 7253

Last change on this file since 7253 was 6002, checked in by Don-vip, 13 years ago

fix #8742 - update svgsalamander to release 0.1.18+patch (fix bug SVGSALAMANDER-26) -> allow to open more SVG files

File size: 25.7 KB
RevLine 
[4256]1/*
[6002]2 * SVG Salamander
3 * Copyright (c) 2004, Mark McKay
4 * All rights reserved.
[4256]5 *
[6002]6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
[4256]9 *
[6002]10 * - Redistributions of source code must retain the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials
16 * provided with the distribution.
[4256]17 *
[6002]18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
32 * projects can be found at http://www.kitfox.com
[4256]33 *
34 * Created on January 26, 2004, 1:59 AM
35 */
36package com.kitfox.svg;
37
[6002]38import com.kitfox.svg.pathcmd.Arc;
39import com.kitfox.svg.pathcmd.BuildHistory;
40import com.kitfox.svg.pathcmd.Cubic;
41import com.kitfox.svg.pathcmd.CubicSmooth;
42import com.kitfox.svg.pathcmd.Horizontal;
43import com.kitfox.svg.pathcmd.LineTo;
44import com.kitfox.svg.pathcmd.MoveTo;
45import com.kitfox.svg.pathcmd.PathCommand;
46import com.kitfox.svg.pathcmd.Quadratic;
47import com.kitfox.svg.pathcmd.QuadraticSmooth;
48import com.kitfox.svg.pathcmd.Terminal;
49import com.kitfox.svg.pathcmd.Vertical;
50import com.kitfox.svg.xml.StyleAttribute;
51import com.kitfox.svg.xml.StyleSheet;
52import com.kitfox.svg.xml.XMLParseUtil;
53import java.awt.geom.AffineTransform;
54import java.awt.geom.GeneralPath;
[4256]55import java.io.Serializable;
[6002]56import java.net.URI;
57import java.util.ArrayList;
58import java.util.Collections;
59import java.util.HashMap;
60import java.util.HashSet;
61import java.util.Iterator;
62import java.util.LinkedList;
63import java.util.List;
64import java.util.Set;
65import java.util.regex.Matcher;
66import java.util.regex.Pattern;
67import org.xml.sax.Attributes;
68import org.xml.sax.SAXException;
[4256]69
[6002]70
[4256]71/**
72 * @author Mark McKay
73 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
74 */
75abstract public class SVGElement implements Serializable
76{
[6002]77
[4256]78 public static final long serialVersionUID = 0;
79 public static final String SVG_NS = "http://www.w3.org/2000/svg";
80 protected SVGElement parent = null;
81 protected final ArrayList children = new ArrayList();
82 protected String id = null;
83 /**
[6002]84 * CSS class. Used for applying style sheet information.
[4256]85 */
86 protected String cssClass = null;
87 /**
88 * Styles defined for this elemnt via the <b>style</b> attribute.
89 */
90 protected final HashMap inlineStyles = new HashMap();
91 /**
[6002]92 * Presentation attributes set for this element. Ie, any attribute other
[4256]93 * than the <b>style</b> attribute.
94 */
95 protected final HashMap presAttribs = new HashMap();
96 /**
97 * A list of presentation attributes to not include in the presentation
98 * attribute set.
99 */
100 protected static final Set ignorePresAttrib;
[6002]101
[4256]102 static
103 {
104 HashSet set = new HashSet();
105// set.add("id");
106// set.add("class");
107// set.add("style");
108// set.add("xml:base");
[6002]109
[4256]110 ignorePresAttrib = Collections.unmodifiableSet(set);
111 }
112 /**
[6002]113 * This element may override the URI we resolve against with an xml:base
114 * attribute. If so, a copy is placed here. Otherwise, we defer to our
115 * parent for the reolution base
[4256]116 */
117 protected URI xmlBase = null;
118 /**
119 * The diagram this element belongs to
120 */
121 protected SVGDiagram diagram;
[6002]122 boolean dirty = true;
123
[4256]124 /**
[6002]125 * Creates a new instance of SVGElement
[4256]126 */
127 public SVGElement()
128 {
129 this(null, null, null);
130 }
[6002]131
[4256]132 public SVGElement(String id, SVGElement parent)
133 {
134 this(id, null, parent);
135 }
[6002]136
[4256]137 public SVGElement(String id, String cssClass, SVGElement parent)
138 {
139 this.id = id;
140 this.cssClass = cssClass;
141 this.parent = parent;
142 }
[6002]143
144 abstract public String getTagName();
145
[4256]146 public SVGElement getParent()
147 {
148 return parent;
149 }
[6002]150
[4256]151 void setParent(SVGElement parent)
152 {
153 this.parent = parent;
154 }
[6002]155
[4256]156 /**
157 * @return an ordered list of nodes from the root of the tree to this node
158 */
159 public List getPath(List retVec)
160 {
[6002]161 if (retVec == null)
162 {
163 retVec = new ArrayList();
164 }
165
[4256]166 if (parent != null)
167 {
168 parent.getPath(retVec);
169 }
170 retVec.add(this);
[6002]171
[4256]172 return retVec;
173 }
[6002]174
[4256]175 /**
[6002]176 * @param retVec - A list to add all children to. If null, a new list is
[4256]177 * created and children of this group are added.
178 *
179 * @return The list containing the children of this group
180 */
181 public List getChildren(List retVec)
182 {
[6002]183 if (retVec == null)
184 {
185 retVec = new ArrayList();
186 }
187
[4256]188 retVec.addAll(children);
[6002]189
[4256]190 return retVec;
191 }
[6002]192
[4256]193 /**
194 * @param id - Id of svg element to return
195 * @return the child of the given id, or null if no such child exists.
196 */
197 public SVGElement getChild(String id)
198 {
199 for (Iterator it = children.iterator(); it.hasNext();)
200 {
[6002]201 SVGElement ele = (SVGElement) it.next();
[4256]202 String eleId = ele.getId();
[6002]203 if (eleId != null && eleId.equals(id))
204 {
205 return ele;
206 }
[4256]207 }
[6002]208
[4256]209 return null;
210 }
[6002]211
[4256]212 /**
[6002]213 * Searches children for given element. If found, returns index of child.
[4256]214 * Otherwise returns -1.
215 */
216 public int indexOfChild(SVGElement child)
217 {
218 return children.indexOf(child);
219 }
[6002]220
[4256]221 /**
222 * Swaps 2 elements in children.
[6002]223 *
[4256]224 * @i index of first
225 * @j index of second
226 *
227 * @return true if successful, false otherwise
228 */
229 public void swapChildren(int i, int j) throws SVGException
230 {
231 if ((children == null) || (i < 0) || (i >= children.size()) || (j < 0) || (j >= children.size()))
232 {
233 return;
234 }
[6002]235
[4256]236 Object temp = children.get(i);
237 children.set(i, children.get(j));
238 children.set(j, temp);
239 build();
240 }
[6002]241
[4256]242 /**
[6002]243 * Called during SAX load process to notify that this tag has begun the
244 * process of being loaded
245 *
[4256]246 * @param attrs - Attributes of this tag
[6002]247 * @param helper - An object passed to all SVG elements involved in this
248 * build process to aid in sharing information.
[4256]249 */
250 public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
251 {
252 //Set identification info
253 this.parent = parent;
254 this.diagram = helper.diagram;
[6002]255
[4256]256 this.id = attrs.getValue("id");
257 if (this.id != null && !this.id.equals(""))
258 {
259 diagram.setElement(this.id, this);
260 }
[6002]261
[4256]262 String className = attrs.getValue("class");
263 this.cssClass = (className == null || className.equals("")) ? null : className;
264 //docRoot = helper.docRoot;
265 //universe = helper.universe;
[6002]266
[4256]267 //Parse style string, if any
268 String style = attrs.getValue("style");
269 if (style != null)
270 {
271 HashMap map = XMLParseUtil.parseStyle(style, inlineStyles);
272 }
[6002]273
[4256]274 String base = attrs.getValue("xml:base");
275 if (base != null && !base.equals(""))
276 {
277 try
278 {
279 xmlBase = new URI(base);
[6002]280 } catch (Exception e)
[4256]281 {
282 throw new SAXException(e);
283 }
284 }
[6002]285
[4256]286 //Place all other attributes into the presentation attribute list
287 int numAttrs = attrs.getLength();
288 for (int i = 0; i < numAttrs; i++)
289 {
290 String name = attrs.getQName(i);
[6002]291 if (ignorePresAttrib.contains(name))
292 {
293 continue;
294 }
[4256]295 String value = attrs.getValue(i);
[6002]296
[4256]297 presAttribs.put(name, new StyleAttribute(name, value));
298 }
299 }
[6002]300
[4256]301 /**
302 * @return a set of Strings that corespond to CSS attributes on this element
303 */
304 public Set getInlineAttributes()
305 {
306 return inlineStyles.keySet();
307 }
[6002]308
[4256]309 /**
310 * @return a set of Strings that corespond to XML attributes on this element
311 */
312 public Set getPresentationAttributes()
313 {
314 return presAttribs.keySet();
315 }
[6002]316
[4256]317 /**
318 * Called after the start element but before the end element to indicate
319 * each child tag that has been processed
320 */
321 public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
322 {
323 children.add(child);
324 child.parent = this;
325 child.setDiagram(diagram);
326 }
[6002]327
328 protected void setDiagram(SVGDiagram diagram)
[4256]329 {
330 this.diagram = diagram;
331 diagram.setElement(id, this);
332 for (Iterator it = children.iterator(); it.hasNext();)
333 {
[6002]334 SVGElement ele = (SVGElement) it.next();
[4256]335 ele.setDiagram(diagram);
336 }
337 }
[6002]338
[4256]339 public void removeChild(SVGElement child) throws SVGElementException
340 {
341 if (!children.contains(child))
342 {
343 throw new SVGElementException(this, "Element does not contain child " + child);
344 }
[6002]345
[4256]346 children.remove(child);
347 }
[6002]348
[4256]349 /**
350 * Called during load process to add text scanned within a tag
351 */
352 public void loaderAddText(SVGLoaderHelper helper, String text)
353 {
354 }
[6002]355
[4256]356 /**
[6002]357 * Called to indicate that this tag and the tags it contains have been
358 * completely processed, and that it should finish any load processes.
[4256]359 */
360 public void loaderEndElement(SVGLoaderHelper helper) throws SVGParseException
361 {
[6002]362// try
363// {
364// build();
365// }
366// catch (SVGException se)
367// {
368// throw new SVGParseException(se);
369// }
[4256]370 }
[6002]371
[4256]372 /**
[6002]373 * Called by internal processes to rebuild the geometry of this node from
374 * it's presentation attributes, style attributes and animated tracks.
[4256]375 */
376 protected void build() throws SVGException
377 {
378 StyleAttribute sty = new StyleAttribute();
[6002]379
[4256]380 if (getPres(sty.setName("id")))
381 {
382 String newId = sty.getStringValue();
383 if (!newId.equals(id))
384 {
385 diagram.removeElement(id);
386 id = newId;
387 diagram.setElement(this.id, this);
388 }
389 }
[6002]390 if (getPres(sty.setName("class")))
391 {
392 cssClass = sty.getStringValue();
393 }
394 if (getPres(sty.setName("xml:base")))
395 {
396 xmlBase = sty.getURIValue();
397 }
398
399 //Build children
400 for (int i = 0; i < children.size(); ++i)
401 {
402 SVGElement ele = (SVGElement) children.get(i);
403 ele.build();
404 }
[4256]405 }
[6002]406
[4256]407 public URI getXMLBase()
408 {
[6002]409 return xmlBase != null ? xmlBase
410 : (parent != null ? parent.getXMLBase() : diagram.getXMLBase());
[4256]411 }
412
413 /**
[6002]414 * @return the id assigned to this node. Null if no id explicitly set.
[4256]415 */
416 public String getId()
417 {
[6002]418 return id;
[4256]419 }
420 LinkedList contexts = new LinkedList();
[6002]421
[4256]422 /**
[6002]423 * Hack to allow nodes to temporarily change their parents. The Use tag will
[4256]424 * need this so it can alter the attributes that a particular node uses.
425 */
426 protected void pushParentContext(SVGElement context)
427 {
428 contexts.addLast(context);
429 }
430
431 protected SVGElement popParentContext()
432 {
[6002]433 return (SVGElement) contexts.removeLast();
[4256]434 }
[6002]435
[4256]436 protected SVGElement getParentContext()
437 {
[6002]438 return contexts.isEmpty() ? null : (SVGElement) contexts.getLast();
[4256]439 }
[6002]440
441 public SVGRoot getRoot()
442 {
443 return parent == null ? null : parent.getRoot();
444 }
445
[4256]446 /*
447 * Returns the named style attribute. Checks for inline styles first, then
448 * internal and extranal style sheets, and finally checks for presentation
449 * attributes.
450 * @param styleName - Name of attribute to return
451 * @param recursive - If true and this object does not contain the
452 * named style attribute, checks attributes of parents abck to root until
453 * one found.
454 */
455 public boolean getStyle(StyleAttribute attrib) throws SVGException
456 {
457 return getStyle(attrib, true);
458 }
[6002]459
[4256]460 /**
[6002]461 * Copies the current style into the passed style attribute. Checks for
462 * inline styles first, then internal and extranal style sheets, and finally
463 * checks for presentation attributes. Recursively checks parents.
464 *
465 * @param attrib - Attribute to write style data to. Must have it's name set
466 * to the name of the style being queried.
467 * @param recursive - If true and this object does not contain the named
468 * style attribute, checks attributes of parents back to root until one
469 * found.
[4256]470 */
471 public boolean getStyle(StyleAttribute attrib, boolean recursive) throws SVGException
472 {
473 String styName = attrib.getName();
[6002]474
[4256]475 //Check for local inline styles
476 StyleAttribute styAttr = (StyleAttribute)inlineStyles.get(styName);
[6002]477
[4256]478 attrib.setStringValue(styAttr == null ? "" : styAttr.getStringValue());
[6002]479
[4256]480 //Return if we've found a non animated style
[6002]481 if (styAttr != null)
482 {
483 return true;
484 }
485
486
[4256]487 //Check for presentation attribute
488 StyleAttribute presAttr = (StyleAttribute)presAttribs.get(styName);
[6002]489
[4256]490 attrib.setStringValue(presAttr == null ? "" : presAttr.getStringValue());
[6002]491
[4256]492 //Return if we've found a presentation attribute instead
[6002]493 if (presAttr != null)
494 {
495 return true;
496 }
497
498 //Check for style sheet
499 SVGRoot root = getRoot();
500 if (root != null)
501 {
502 StyleSheet ss = root.getStyleSheet();
503 if (ss != null)
504 {
505 return ss.getStyle(attrib, getTagName(), cssClass);
506 }
507 }
508
[4256]509 //If we're recursive, check parents
510 if (recursive)
511 {
512 SVGElement parentContext = getParentContext();
[6002]513 if (parentContext != null)
514 {
515 return parentContext.getStyle(attrib, true);
516 }
517 if (parent != null)
518 {
519 return parent.getStyle(attrib, true);
520 }
[4256]521 }
[6002]522
[4256]523 //Unsuccessful reading style attribute
524 return false;
525 }
[6002]526
[4256]527 /**
[6002]528 * @return the raw style value of this attribute. Does not take the
529 * presentation value or animation into consideration. Used by animations to
530 * determine the base to animate from.
[4256]531 */
532 public StyleAttribute getStyleAbsolute(String styName)
533 {
534 //Check for local inline styles
[6002]535 return (StyleAttribute) inlineStyles.get(styName);
[4256]536 }
[6002]537
[4256]538 /**
539 * Copies the presentation attribute into the passed one.
[6002]540 *
[4256]541 * @return - True if attribute was read successfully
542 */
543 public boolean getPres(StyleAttribute attrib) throws SVGException
544 {
545 String presName = attrib.getName();
[6002]546
[4256]547 //Make sure we have a coresponding presentation attribute
[6002]548 StyleAttribute presAttr = (StyleAttribute) presAttribs.get(presName);
549
[4256]550 //Copy presentation value directly
551 attrib.setStringValue(presAttr == null ? "" : presAttr.getStringValue());
[6002]552
[4256]553 //Return if we found presentation attribute
[6002]554 if (presAttr != null)
555 {
556 return true;
557 }
558
[4256]559 return false;
560 }
[6002]561
[4256]562 /**
[6002]563 * @return the raw presentation value of this attribute. Ignores any
564 * modifications applied by style attributes or animation. Used by
[4256]565 * animations to determine the starting point to animate from
566 */
567 public StyleAttribute getPresAbsolute(String styName)
568 {
569 //Check for local inline styles
[6002]570 return (StyleAttribute) presAttribs.get(styName);
[4256]571 }
[6002]572
[4256]573 static protected AffineTransform parseTransform(String val) throws SVGException
574 {
575 final Matcher matchExpression = Pattern.compile("\\w+\\([^)]*\\)").matcher("");
[6002]576
[4256]577 AffineTransform retXform = new AffineTransform();
[6002]578
[4256]579 matchExpression.reset(val);
580 while (matchExpression.find())
581 {
582 retXform.concatenate(parseSingleTransform(matchExpression.group()));
583 }
[6002]584
[4256]585 return retXform;
586 }
[6002]587
[4256]588 static public AffineTransform parseSingleTransform(String val) throws SVGException
589 {
590 final Matcher matchWord = Pattern.compile("[-.\\w]+").matcher("");
[6002]591
[4256]592 AffineTransform retXform = new AffineTransform();
[6002]593
[4256]594 matchWord.reset(val);
595 if (!matchWord.find())
596 {
597 //Return identity transformation if no data present (eg, empty string)
598 return retXform;
599 }
[6002]600
[4256]601 String function = matchWord.group().toLowerCase();
[6002]602
[4256]603 LinkedList termList = new LinkedList();
604 while (matchWord.find())
605 {
606 termList.add(matchWord.group());
607 }
[6002]608
609
[4256]610 double[] terms = new double[termList.size()];
611 Iterator it = termList.iterator();
612 int count = 0;
613 while (it.hasNext())
614 {
[6002]615 terms[count++] = XMLParseUtil.parseDouble((String) it.next());
[4256]616 }
[6002]617
[4256]618 //Calculate transformation
619 if (function.equals("matrix"))
620 {
621 retXform.setTransform(terms[0], terms[1], terms[2], terms[3], terms[4], terms[5]);
[6002]622 } else if (function.equals("translate"))
[4256]623 {
[6002]624 if (terms.length == 1)
625 {
626 retXform.setToTranslation(terms[0], 0);
627 } else
628 {
629 retXform.setToTranslation(terms[0], terms[1]);
630 }
631 } else if (function.equals("scale"))
[4256]632 {
633 if (terms.length > 1)
[6002]634 {
[4256]635 retXform.setToScale(terms[0], terms[1]);
[6002]636 } else
637 {
[4256]638 retXform.setToScale(terms[0], terms[0]);
[6002]639 }
640 } else if (function.equals("rotate"))
[4256]641 {
642 if (terms.length > 2)
[6002]643 {
[4256]644 retXform.setToRotation(Math.toRadians(terms[0]), terms[1], terms[2]);
[6002]645 } else
646 {
[4256]647 retXform.setToRotation(Math.toRadians(terms[0]));
[6002]648 }
649 } else if (function.equals("skewx"))
[4256]650 {
651 retXform.setToShear(Math.toRadians(terms[0]), 0.0);
[6002]652 } else if (function.equals("skewy"))
[4256]653 {
654 retXform.setToShear(0.0, Math.toRadians(terms[0]));
[6002]655 } else
[4256]656 {
657 throw new SVGException("Unknown transform type");
658 }
[6002]659
[4256]660 return retXform;
661 }
[6002]662
[4256]663 static protected float nextFloat(LinkedList l)
664 {
[6002]665 String s = (String) l.removeFirst();
[4256]666 return Float.parseFloat(s);
667 }
[6002]668
[4256]669 static protected PathCommand[] parsePathList(String list)
670 {
671 final Matcher matchPathCmd = Pattern.compile("([MmLlHhVvAaQqTtCcSsZz])|([-+]?((\\d*\\.\\d+)|(\\d+))([eE][-+]?\\d+)?)").matcher(list);
[6002]672
[4256]673 //Tokenize
674 LinkedList tokens = new LinkedList();
675 while (matchPathCmd.find())
676 {
677 tokens.addLast(matchPathCmd.group());
678 }
[6002]679
680
[4256]681 boolean defaultRelative = false;
682 LinkedList cmdList = new LinkedList();
683 char curCmd = 'Z';
684 while (tokens.size() != 0)
685 {
[6002]686 String curToken = (String) tokens.removeFirst();
[4256]687 char initChar = curToken.charAt(0);
[6002]688 if ((initChar >= 'A' && initChar <= 'Z') || (initChar >= 'a' && initChar <= 'z'))
[4256]689 {
690 curCmd = initChar;
[6002]691 } else
[4256]692 {
693 tokens.addFirst(curToken);
694 }
[6002]695
[4256]696 PathCommand cmd = null;
[6002]697
[4256]698 switch (curCmd)
699 {
700 case 'M':
701 cmd = new MoveTo(false, nextFloat(tokens), nextFloat(tokens));
702 curCmd = 'L';
703 break;
704 case 'm':
705 cmd = new MoveTo(true, nextFloat(tokens), nextFloat(tokens));
706 curCmd = 'l';
707 break;
708 case 'L':
709 cmd = new LineTo(false, nextFloat(tokens), nextFloat(tokens));
710 break;
711 case 'l':
712 cmd = new LineTo(true, nextFloat(tokens), nextFloat(tokens));
713 break;
714 case 'H':
715 cmd = new Horizontal(false, nextFloat(tokens));
716 break;
717 case 'h':
718 cmd = new Horizontal(true, nextFloat(tokens));
719 break;
720 case 'V':
721 cmd = new Vertical(false, nextFloat(tokens));
722 break;
723 case 'v':
724 cmd = new Vertical(true, nextFloat(tokens));
725 break;
726 case 'A':
727 cmd = new Arc(false, nextFloat(tokens), nextFloat(tokens),
[6002]728 nextFloat(tokens),
729 nextFloat(tokens) == 1f, nextFloat(tokens) == 1f,
730 nextFloat(tokens), nextFloat(tokens));
[4256]731 break;
732 case 'a':
733 cmd = new Arc(true, nextFloat(tokens), nextFloat(tokens),
[6002]734 nextFloat(tokens),
735 nextFloat(tokens) == 1f, nextFloat(tokens) == 1f,
736 nextFloat(tokens), nextFloat(tokens));
[4256]737 break;
738 case 'Q':
739 cmd = new Quadratic(false, nextFloat(tokens), nextFloat(tokens),
[6002]740 nextFloat(tokens), nextFloat(tokens));
[4256]741 break;
742 case 'q':
743 cmd = new Quadratic(true, nextFloat(tokens), nextFloat(tokens),
[6002]744 nextFloat(tokens), nextFloat(tokens));
[4256]745 break;
746 case 'T':
747 cmd = new QuadraticSmooth(false, nextFloat(tokens), nextFloat(tokens));
748 break;
749 case 't':
750 cmd = new QuadraticSmooth(true, nextFloat(tokens), nextFloat(tokens));
751 break;
752 case 'C':
753 cmd = new Cubic(false, nextFloat(tokens), nextFloat(tokens),
[6002]754 nextFloat(tokens), nextFloat(tokens),
755 nextFloat(tokens), nextFloat(tokens));
[4256]756 break;
757 case 'c':
758 cmd = new Cubic(true, nextFloat(tokens), nextFloat(tokens),
[6002]759 nextFloat(tokens), nextFloat(tokens),
760 nextFloat(tokens), nextFloat(tokens));
[4256]761 break;
762 case 'S':
763 cmd = new CubicSmooth(false, nextFloat(tokens), nextFloat(tokens),
[6002]764 nextFloat(tokens), nextFloat(tokens));
[4256]765 break;
766 case 's':
767 cmd = new CubicSmooth(true, nextFloat(tokens), nextFloat(tokens),
[6002]768 nextFloat(tokens), nextFloat(tokens));
[4256]769 break;
770 case 'Z':
771 case 'z':
772 cmd = new Terminal();
773 break;
774 default:
775 throw new RuntimeException("Invalid path element");
776 }
[6002]777
[4256]778 cmdList.add(cmd);
779 defaultRelative = cmd.isRelative;
780 }
[6002]781
[4256]782 PathCommand[] retArr = new PathCommand[cmdList.size()];
783 cmdList.toArray(retArr);
784 return retArr;
785 }
[6002]786
[4256]787 static protected GeneralPath buildPath(String text, int windingRule)
788 {
789 PathCommand[] commands = parsePathList(text);
[6002]790
[4256]791 int numKnots = 2;
792 for (int i = 0; i < commands.length; i++)
793 {
794 numKnots += commands[i].getNumKnotsAdded();
795 }
[6002]796
797
[4256]798 GeneralPath path = new GeneralPath(windingRule, numKnots);
[6002]799
[4256]800 BuildHistory hist = new BuildHistory();
[6002]801
[4256]802 for (int i = 0; i < commands.length; i++)
803 {
804 PathCommand cmd = commands[i];
805 cmd.appendPath(path, hist);
806 }
[6002]807
[4256]808 return path;
809 }
[6002]810
[4256]811 /**
[6002]812 * Updates all attributes in this diagram associated with a time event. Ie,
813 * all attributes with track information.
814 *
[4256]815 * @return - true if this node has changed state as a result of the time
816 * update
817 */
818 abstract public boolean updateTime(double curTime) throws SVGException;
819
820 public int getNumChildren()
821 {
822 return children.size();
823 }
824
825 public SVGElement getChild(int i)
826 {
[6002]827 return (SVGElement) children.get(i);
[4256]828 }
[6002]829
830 public double lerp(double t0, double t1, double alpha)
831 {
832 return (1 - alpha) * t0 + alpha * t1;
833 }
[4256]834}
Note: See TracBrowser for help on using the repository browser.