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

Last change on this file since 12713 was 11525, checked in by Don-vip, 7 years ago

see #14319 - update to latest version of svgSalamander (2017-01-07, patched)

  • Property svn:eol-style set to native
File size: 9.0 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 @Override
69 public String getTagName()
70 {
71 return TAG_NAME;
72 }
73
74 /**
75 * Called after the start element but before the end element to indicate
76 * each child tag that has been processed
77 */
78 @Override
79 public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
80 {
81 super.loaderAddChild(helper, child);
82 }
83
84 protected boolean outsideClip(Graphics2D g) throws SVGException
85 {
86 Shape clip = g.getClip();
87 if (clip == null)
88 {
89 return false;
90 }
91 //g.getClipBounds(clipBounds);
92 Rectangle2D rect = getBoundingBox();
93
94 if (clip.intersects(rect))
95 {
96 return false;
97 }
98
99 return true;
100 }
101
102 @Override
103 void pick(Point2D point, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
104 {
105 Point2D xPoint = new Point2D.Double(point.getX(), point.getY());
106 if (xform != null)
107 {
108 try
109 {
110 xform.inverseTransform(point, xPoint);
111 } catch (NoninvertibleTransformException ex)
112 {
113 throw new SVGException(ex);
114 }
115 }
116
117
118 for (SVGElement ele : children) {
119 if (ele instanceof RenderableElement)
120 {
121 RenderableElement rendEle = (RenderableElement) ele;
122
123 rendEle.pick(xPoint, boundingBox, retVec);
124 }
125 }
126 }
127
128 @Override
129 void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
130 {
131 if (xform != null)
132 {
133 ltw = new AffineTransform(ltw);
134 ltw.concatenate(xform);
135 }
136
137
138 for (SVGElement ele : children) {
139 if (ele instanceof RenderableElement)
140 {
141 RenderableElement rendEle = (RenderableElement) ele;
142
143 rendEle.pick(pickArea, ltw, boundingBox, retVec);
144 }
145 }
146 }
147
148 @Override
149 public void render(Graphics2D g) throws SVGException
150 {
151 //Don't process if not visible
152 StyleAttribute styleAttrib = new StyleAttribute();
153 //Visibility can be overridden by children
154
155 if (getStyle(styleAttrib.setName("display")))
156 {
157 if (styleAttrib.getStringValue().equals("none"))
158 {
159 return;
160 }
161 }
162
163 //Do not process offscreen groups
164 boolean ignoreClip = diagram.ignoringClipHeuristic();
165// if (!ignoreClip && outsideClip(g))
166// {
167// return;
168// }
169
170 beginLayer(g);
171
172 Iterator<SVGElement> it = children.iterator();
173
174// try
175// {
176// g.getClipBounds(clipBounds);
177// }
178// catch (Exception e)
179// {
180// //For some reason, getClipBounds can throw a null pointer exception for
181// // some types of Graphics2D
182// ignoreClip = true;
183// }
184
185 Shape clip = g.getClip();
186 while (it.hasNext())
187 {
188 SVGElement ele = it.next();
189 if (ele instanceof RenderableElement)
190 {
191 RenderableElement rendEle = (RenderableElement) ele;
192
193// if (shapeEle == null) continue;
194
195 if (!(ele instanceof Group))
196 {
197 //Skip if clipping area is outside our bounds
198 if (!ignoreClip && clip != null
199 && !clip.intersects(rendEle.getBoundingBox()))
200 {
201 continue;
202 }
203 }
204
205 rendEle.render(g);
206 }
207 }
208
209 finishLayer(g);
210 }
211
212 /**
213 * Retrieves the cached bounding box of this group
214 */
215 @Override
216 public Shape getShape()
217 {
218 if (cachedShape == null)
219 {
220 calcShape();
221 }
222 return cachedShape;
223 }
224
225 public void calcShape()
226 {
227 Area retShape = new Area();
228
229 for (SVGElement ele : children) {
230 if (ele instanceof ShapeElement)
231 {
232 ShapeElement shpEle = (ShapeElement) ele;
233 Shape shape = shpEle.getShape();
234 if (shape != null)
235 {
236 retShape.add(new Area(shape));
237 }
238 }
239 }
240
241 cachedShape = shapeToParent(retShape);
242 }
243
244 /**
245 * Retrieves the cached bounding box of this group
246 */
247 @Override
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 = null;
265
266 for (SVGElement ele : children) {
267 if (ele instanceof RenderableElement)
268 {
269 RenderableElement rendEle = (RenderableElement) ele;
270 Rectangle2D bounds = rendEle.getBoundingBox();
271 if (bounds != null && (bounds.getWidth() != 0 || bounds.getHeight() != 0))
272 {
273 if (retRect == null)
274 {
275 retRect = bounds;
276 }
277 else
278 {
279 if (retRect.getWidth() != 0 || retRect.getHeight() != 0)
280 {
281 retRect = retRect.createUnion(bounds);
282 }
283 }
284 }
285 }
286 }
287
288// if (xform != null)
289// {
290// retRect = xform.createTransformedShape(retRect).getBounds2D();
291// }
292
293 //If no contents, use degenerate rectangle
294 if (retRect == null)
295 {
296 retRect = new Rectangle2D.Float();
297 }
298
299 boundingBox = boundsToParent(retRect);
300 }
301
302 @Override
303 public boolean updateTime(double curTime) throws SVGException
304 {
305 boolean changeState = super.updateTime(curTime);
306 Iterator<SVGElement> it = children.iterator();
307
308 //Distribute message to all members of this group
309 while (it.hasNext())
310 {
311 SVGElement ele = it.next();
312 boolean updateVal = ele.updateTime(curTime);
313
314 changeState = changeState || updateVal;
315
316 //Update our shape if shape aware children change
317 if (ele instanceof ShapeElement)
318 {
319 cachedShape = null;
320 }
321 if (ele instanceof RenderableElement)
322 {
323 boundingBox = null;
324 }
325 }
326
327 return changeState;
328 }
329}
Note: See TracBrowser for help on using the repository browser.