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

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

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

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 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)
274 {
275 if (retRect == null)
276 {
277 retRect = bounds;
278 } else
279 {
280 retRect = retRect.createUnion(bounds);
281 }
282 }
283 }
284 }
285
286// if (xform != null)
287// {
288// retRect = xform.createTransformedShape(retRect).getBounds2D();
289// }
290
291 //If no contents, use degenerate rectangle
292 if (retRect == null)
293 {
294 retRect = new Rectangle2D.Float();
295 }
296
297 boundingBox = boundsToParent(retRect);
298 }
299
300 public boolean updateTime(double curTime) throws SVGException
301 {
302 boolean changeState = super.updateTime(curTime);
303 Iterator it = children.iterator();
304
305 //Distribute message to all members of this group
306 while (it.hasNext())
307 {
308 SVGElement ele = (SVGElement) it.next();
309 boolean updateVal = ele.updateTime(curTime);
310
311 changeState = changeState || updateVal;
312
313 //Update our shape if shape aware children change
314 if (ele instanceof ShapeElement)
315 {
316 cachedShape = null;
317 }
318 if (ele instanceof RenderableElement)
319 {
320 boundingBox = null;
321 }
322 }
323
324 return changeState;
325 }
326}
Note: See TracBrowser for help on using the repository browser.