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

Last change on this file since 10741 was 8084, checked in by bastiK, 9 years ago

add svn:eol-style=native for svgsalamander

  • Property svn:eol-style set to native
File size: 9.3 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 //Visibility can be overridden by children
153
154 if (getStyle(styleAttrib.setName("display")))
155 {
156 if (styleAttrib.getStringValue().equals("none"))
157 {
158 return;
159 }
160 }
161
162 //Do not process offscreen groups
163 boolean ignoreClip = diagram.ignoringClipHeuristic();
164// if (!ignoreClip && outsideClip(g))
165// {
166// return;
167// }
168
169 beginLayer(g);
170
171 Iterator it = children.iterator();
172
173// try
174// {
175// g.getClipBounds(clipBounds);
176// }
177// catch (Exception e)
178// {
179// //For some reason, getClipBounds can throw a null pointer exception for
180// // some types of Graphics2D
181// ignoreClip = true;
182// }
183
184 Shape clip = g.getClip();
185 while (it.hasNext())
186 {
187 SVGElement ele = (SVGElement) it.next();
188 if (ele instanceof RenderableElement)
189 {
190 RenderableElement rendEle = (RenderableElement) ele;
191
192// if (shapeEle == null) continue;
193
194 if (!(ele instanceof Group))
195 {
196 //Skip if clipping area is outside our bounds
197 if (!ignoreClip && clip != null
198 && !clip.intersects(rendEle.getBoundingBox()))
199 {
200 continue;
201 }
202 }
203
204 rendEle.render(g);
205 }
206 }
207
208 finishLayer(g);
209 }
210
211 /**
212 * Retrieves the cached bounding box of this group
213 */
214 public Shape getShape()
215 {
216 if (cachedShape == null)
217 {
218 calcShape();
219 }
220 return cachedShape;
221 }
222
223 public void calcShape()
224 {
225 Area retShape = new Area();
226
227 for (Iterator it = children.iterator(); it.hasNext();)
228 {
229 SVGElement ele = (SVGElement) it.next();
230
231 if (ele instanceof ShapeElement)
232 {
233 ShapeElement shpEle = (ShapeElement) ele;
234 Shape shape = shpEle.getShape();
235 if (shape != null)
236 {
237 retShape.add(new Area(shape));
238 }
239 }
240 }
241
242 cachedShape = shapeToParent(retShape);
243 }
244
245 /**
246 * Retrieves the cached bounding box of this group
247 */
248 public Rectangle2D getBoundingBox() throws SVGException
249 {
250 if (boundingBox == null)
251 {
252 calcBoundingBox();
253 }
254// calcBoundingBox();
255 return boundingBox;
256 }
257
258 /**
259 * Recalculates the bounding box by taking the union of the bounding boxes
260 * of all children. Caches the result.
261 */
262 public void calcBoundingBox() throws SVGException
263 {
264// Rectangle2D retRect = new Rectangle2D.Float();
265 Rectangle2D retRect = null;
266
267 for (Iterator it = children.iterator(); it.hasNext();)
268 {
269 SVGElement ele = (SVGElement) it.next();
270
271 if (ele instanceof RenderableElement)
272 {
273 RenderableElement rendEle = (RenderableElement) ele;
274 Rectangle2D bounds = rendEle.getBoundingBox();
275 if (bounds != null && (bounds.getWidth() != 0 || bounds.getHeight() != 0))
276 {
277 if (retRect == null)
278 {
279 retRect = bounds;
280 }
281 else
282 {
283 if (retRect.getWidth() != 0 || retRect.getHeight() != 0)
284 {
285 retRect = retRect.createUnion(bounds);
286 }
287 }
288 }
289 }
290 }
291
292// if (xform != null)
293// {
294// retRect = xform.createTransformedShape(retRect).getBounds2D();
295// }
296
297 //If no contents, use degenerate rectangle
298 if (retRect == null)
299 {
300 retRect = new Rectangle2D.Float();
301 }
302
303 boundingBox = boundsToParent(retRect);
304 }
305
306 public boolean updateTime(double curTime) throws SVGException
307 {
308 boolean changeState = super.updateTime(curTime);
309 Iterator it = children.iterator();
310
311 //Distribute message to all members of this group
312 while (it.hasNext())
313 {
314 SVGElement ele = (SVGElement) it.next();
315 boolean updateVal = ele.updateTime(curTime);
316
317 changeState = changeState || updateVal;
318
319 //Update our shape if shape aware children change
320 if (ele instanceof ShapeElement)
321 {
322 cachedShape = null;
323 }
324 if (ele instanceof RenderableElement)
325 {
326 boundingBox = null;
327 }
328 }
329
330 return changeState;
331 }
332}
Note: See TracBrowser for help on using the repository browser.