source: josm/trunk/src/com/kitfox/svg/Group.java@ 7676

Last change on this file since 7676 was 7676, checked in by stoecker, 9 years ago

update SVG code to current SVN (fix line endings), see #10479

File size: 9.5 KB
Line 
1/*
2 * SVG Salamander
3 * Copyright (c) 2004, Mark McKay
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
9 *
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.
17 *
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
33 *
34 * Created on January 26, 2004, 1:56 AM
35 */
36package com.kitfox.svg;
37
38import com.kitfox.svg.xml.StyleAttribute;
39import java.awt.Graphics2D;
40import java.awt.Shape;
41import java.awt.geom.AffineTransform;
42import java.awt.geom.Area;
43import java.awt.geom.NoninvertibleTransformException;
44import java.awt.geom.Point2D;
45import java.awt.geom.Rectangle2D;
46import java.util.Iterator;
47import java.util.List;
48
49/**
50 * @author Mark McKay
51 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
52 */
53public class Group extends ShapeElement
54{
55 public static final String TAG_NAME = "group";
56
57 //Cache bounding box for faster clip testing
58 Rectangle2D boundingBox;
59 Shape cachedShape;
60
61 /**
62 * Creates a new instance of Stop
63 */
64 public Group()
65 {
66 }
67
68 public String getTagName()
69 {
70 return TAG_NAME;
71 }
72
73 /**
74 * Called after the start element but before the end element to indicate
75 * each child tag that has been processed
76 */
77 public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
78 {
79 super.loaderAddChild(helper, child);
80 }
81
82 protected boolean outsideClip(Graphics2D g) throws SVGException
83 {
84 Shape clip = g.getClip();
85 if (clip == null)
86 {
87 return false;
88 }
89 //g.getClipBounds(clipBounds);
90 Rectangle2D rect = getBoundingBox();
91
92 if (clip.intersects(rect))
93 {
94 return false;
95 }
96
97 return true;
98 }
99
100 void pick(Point2D point, boolean boundingBox, List retVec) throws SVGException
101 {
102 Point2D xPoint = new Point2D.Double(point.getX(), point.getY());
103 if (xform != null)
104 {
105 try
106 {
107 xform.inverseTransform(point, xPoint);
108 } catch (NoninvertibleTransformException ex)
109 {
110 throw new SVGException(ex);
111 }
112 }
113
114
115 for (Iterator it = children.iterator(); it.hasNext();)
116 {
117 SVGElement ele = (SVGElement) it.next();
118 if (ele instanceof RenderableElement)
119 {
120 RenderableElement rendEle = (RenderableElement) ele;
121
122 rendEle.pick(xPoint, boundingBox, retVec);
123 }
124 }
125 }
126
127 void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List retVec) throws SVGException
128 {
129 if (xform != null)
130 {
131 ltw = new AffineTransform(ltw);
132 ltw.concatenate(xform);
133 }
134
135
136 for (Iterator it = children.iterator(); it.hasNext();)
137 {
138 SVGElement ele = (SVGElement) it.next();
139 if (ele instanceof RenderableElement)
140 {
141 RenderableElement rendEle = (RenderableElement) ele;
142
143 rendEle.pick(pickArea, ltw, boundingBox, retVec);
144 }
145 }
146 }
147
148 public void render(Graphics2D g) throws SVGException
149 {
150 //Don't process if not visible
151 StyleAttribute styleAttrib = new StyleAttribute();
152 if (getStyle(styleAttrib.setName("visibility")))
153 {
154 if (!styleAttrib.getStringValue().equals("visible"))
155 {
156 return;
157 }
158 }
159
160 //Do not process offscreen groups
161 boolean ignoreClip = diagram.ignoringClipHeuristic();
162// if (!ignoreClip && outsideClip(g))
163// {
164// return;
165// }
166
167 beginLayer(g);
168
169 Iterator it = children.iterator();
170
171// try
172// {
173// g.getClipBounds(clipBounds);
174// }
175// catch (Exception e)
176// {
177// //For some reason, getClipBounds can throw a null pointer exception for
178// // some types of Graphics2D
179// ignoreClip = true;
180// }
181
182 Shape clip = g.getClip();
183 while (it.hasNext())
184 {
185 SVGElement ele = (SVGElement) it.next();
186 if (ele instanceof RenderableElement)
187 {
188 RenderableElement rendEle = (RenderableElement) ele;
189
190// if (shapeEle == null) continue;
191
192 if (!(ele instanceof Group))
193 {
194 //Skip if clipping area is outside our bounds
195 if (!ignoreClip && clip != null
196 && !clip.intersects(rendEle.getBoundingBox()))
197 {
198 continue;
199 }
200 }
201
202 rendEle.render(g);
203 }
204 }
205
206 finishLayer(g);
207 }
208
209 /**
210 * Retrieves the cached bounding box of this group
211 */
212 public Shape getShape()
213 {
214 if (cachedShape == null)
215 {
216 calcShape();
217 }
218 return cachedShape;
219 }
220
221 public void calcShape()
222 {
223 Area retShape = new Area();
224
225 for (Iterator it = children.iterator(); it.hasNext();)
226 {
227 SVGElement ele = (SVGElement) it.next();
228
229 if (ele instanceof ShapeElement)
230 {
231 ShapeElement shpEle = (ShapeElement) ele;
232 Shape shape = shpEle.getShape();
233 if (shape != null)
234 {
235 retShape.add(new Area(shape));
236 }
237 }
238 }
239
240 cachedShape = shapeToParent(retShape);
241 }
242
243 /**
244 * Retrieves the cached bounding box of this group
245 */
246 public Rectangle2D getBoundingBox() throws SVGException
247 {
248 if (boundingBox == null)
249 {
250 calcBoundingBox();
251 }
252// calcBoundingBox();
253 return boundingBox;
254 }
255
256 /**
257 * Recalculates the bounding box by taking the union of the bounding boxes
258 * of all children. Caches the result.
259 */
260 public void calcBoundingBox() throws SVGException
261 {
262// Rectangle2D retRect = new Rectangle2D.Float();
263 Rectangle2D retRect = null;
264
265 for (Iterator it = children.iterator(); it.hasNext();)
266 {
267 SVGElement ele = (SVGElement) it.next();
268
269 if (ele instanceof RenderableElement)
270 {
271 RenderableElement rendEle = (RenderableElement) ele;
272 Rectangle2D bounds = rendEle.getBoundingBox();
273 if (bounds != null && (bounds.getWidth() != 0 || bounds.getHeight() != 0))
274 {
275 if (retRect == null)
276 {
277 retRect = bounds;
278 }
279 else
280 {
281 if (retRect.getWidth() != 0 || retRect.getHeight() != 0)
282 {
283 retRect = retRect.createUnion(bounds);
284 }
285 }
286 }
287 }
288 }
289
290// if (xform != null)
291// {
292// retRect = xform.createTransformedShape(retRect).getBounds2D();
293// }
294
295 //If no contents, use degenerate rectangle
296 if (retRect == null)
297 {
298 retRect = new Rectangle2D.Float();
299 }
300
301 boundingBox = boundsToParent(retRect);
302 }
303
304 public boolean updateTime(double curTime) throws SVGException
305 {
306 boolean changeState = super.updateTime(curTime);
307 Iterator it = children.iterator();
308
309 //Distribute message to all members of this group
310 while (it.hasNext())
311 {
312 SVGElement ele = (SVGElement) it.next();
313 boolean updateVal = ele.updateTime(curTime);
314
315 changeState = changeState || updateVal;
316
317 //Update our shape if shape aware children change
318 if (ele instanceof ShapeElement)
319 {
320 cachedShape = null;
321 }
322 if (ele instanceof RenderableElement)
323 {
324 boundingBox = null;
325 }
326 }
327
328 return changeState;
329 }
330}
Note: See TracBrowser for help on using the repository browser.