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

Last change on this file since 5693 was 4256, checked in by bastiK, 13 years ago

see #6560 - basic svg support, includes kitfox svgsalamander, r 98, patched

File size: 8.6 KB
Line 
1/*
2 * Stop.java
3 *
4 *
5 * The Salamander Project - 2D and 3D graphics libraries in Java
6 * Copyright (C) 2004 Mark McKay
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
23 * projects can be found at http://www.kitfox.com
24 *
25 * Created on January 26, 2004, 1:56 AM
26 */
27
28package com.kitfox.svg;
29
30import com.kitfox.svg.xml.StyleAttribute;
31import java.awt.Graphics2D;
32import java.awt.Rectangle;
33import java.awt.Shape;
34import java.awt.geom.AffineTransform;
35import java.awt.geom.Area;
36import java.awt.geom.NoninvertibleTransformException;
37import java.awt.geom.Point2D;
38import java.awt.geom.Rectangle2D;
39import java.util.Iterator;
40import java.util.List;
41
42
43/**
44 * @author Mark McKay
45 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
46 */
47public class Group extends ShapeElement
48{
49
50 //Cache bounding box for faster clip testing
51 Rectangle2D boundingBox;
52 Shape cachedShape;
53
54 //Cache clip bounds
55 final Rectangle clipBounds = new Rectangle();
56
57 /** Creates a new instance of Stop */
58 public Group() {
59 }
60
61 /*
62 public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent)
63 {
64 //Load style string
65 super.loaderStartElement(helper, attrs, parent);
66
67 //String transform = attrs.getValue("transform");
68 }
69 */
70
71 /**
72 * Called after the start element but before the end element to indicate
73 * each child tag that has been processed
74 */
75 public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
76 {
77 super.loaderAddChild(helper, child);
78
79// members.add(child);
80 }
81
82 protected boolean outsideClip(Graphics2D g) throws SVGException
83 {
84 g.getClipBounds(clipBounds);
85 Rectangle2D rect = getBoundingBox();
86
87//if (rect == null)
88//{
89// rect = getBoundingBox();
90//}
91
92// if (rect.intersects(clipBounds))
93 if (rect.intersects(clipBounds))
94 {
95 return false;
96 }
97
98 return true;
99 }
100
101 void pick(Point2D point, boolean boundingBox, List retVec) throws SVGException
102 {
103 Point2D xPoint = new Point2D.Double(point.getX(), point.getY());
104 if (xform != null)
105 {
106 try
107 {
108 xform.inverseTransform(point, xPoint);
109 }
110 catch (NoninvertibleTransformException ex)
111 {
112 throw new SVGException(ex);
113 }
114 }
115
116
117 for (Iterator it = children.iterator(); it.hasNext();)
118 {
119 SVGElement ele = (SVGElement)it.next();
120 if (ele instanceof RenderableElement)
121 {
122 RenderableElement rendEle = (RenderableElement)ele;
123
124 rendEle.pick(xPoint, boundingBox, retVec);
125 }
126 }
127 }
128
129 void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List retVec) throws SVGException
130 {
131 if (xform != null)
132 {
133 ltw = new AffineTransform(ltw);
134 ltw.concatenate(xform);
135 }
136
137
138 for (Iterator it = children.iterator(); it.hasNext();)
139 {
140 SVGElement ele = (SVGElement)it.next();
141 if (ele instanceof RenderableElement)
142 {
143 RenderableElement rendEle = (RenderableElement)ele;
144
145 rendEle.pick(pickArea, ltw, boundingBox, retVec);
146 }
147 }
148 }
149
150 public void render(Graphics2D g) throws SVGException
151 {
152 //Don't process if not visible
153 StyleAttribute styleAttrib = new StyleAttribute();
154 if (getStyle(styleAttrib.setName("visibility")))
155 {
156 if (!styleAttrib.getStringValue().equals("visible")) return;
157 }
158
159 //Do not process offscreen groups
160 boolean ignoreClip = diagram.ignoringClipHeuristic();
161 if (!ignoreClip && outsideClip(g)) return;
162
163 beginLayer(g);
164
165 Iterator it = children.iterator();
166
167 try
168 {
169 g.getClipBounds(clipBounds);
170 }
171 catch (Exception e)
172 {
173 //For some reason, getClipBounds can throw a null pointer exception for
174 // some types of Graphics2D
175 ignoreClip = true;
176 }
177
178 while (it.hasNext())
179 {
180 SVGElement ele = (SVGElement)it.next();
181 if (ele instanceof RenderableElement)
182 {
183 RenderableElement rendEle = (RenderableElement)ele;
184
185// if (shapeEle == null) continue;
186
187 if (!(ele instanceof Group))
188 {
189 //Skip if clipping area is outside our bounds
190 if (!ignoreClip && !rendEle.getBoundingBox().intersects(clipBounds))
191 {
192 continue;
193 }
194 }
195
196 rendEle.render(g);
197 }
198 }
199
200 finishLayer(g);
201 }
202
203
204 /**
205 * Retrieves the cached bounding box of this group
206 */
207 public Shape getShape()
208 {
209 if (cachedShape == null) calcShape();
210 return cachedShape;
211 }
212
213 public void calcShape()
214 {
215 Area retShape = new Area();
216
217 for (Iterator it = children.iterator(); it.hasNext();)
218 {
219 SVGElement ele = (SVGElement)it.next();
220
221 if (ele instanceof ShapeElement)
222 {
223 ShapeElement shpEle = (ShapeElement)ele;
224 Shape shape = shpEle.getShape();
225 if (shape != null)
226 {
227 retShape.add(new Area(shape));
228 }
229 }
230 }
231
232 cachedShape = shapeToParent(retShape);
233 }
234
235 /**
236 * Retrieves the cached bounding box of this group
237 */
238 public Rectangle2D getBoundingBox() throws SVGException
239 {
240 if (boundingBox == null) calcBoundingBox();
241// calcBoundingBox();
242 return boundingBox;
243 }
244
245 /**
246 * Recalculates the bounding box by taking the union of the bounding boxes
247 * of all children. Caches the result.
248 */
249 public void calcBoundingBox() throws SVGException
250 {
251// Rectangle2D retRect = new Rectangle2D.Float();
252 Rectangle2D retRect = null;
253
254 for (Iterator it = children.iterator(); it.hasNext();)
255 {
256 SVGElement ele = (SVGElement)it.next();
257
258 if (ele instanceof RenderableElement)
259 {
260 RenderableElement rendEle = (RenderableElement)ele;
261 Rectangle2D bounds = rendEle.getBoundingBox();
262 if (bounds != null)
263 {
264 if (retRect == null) retRect = bounds;
265 else retRect = retRect.createUnion(bounds);
266 }
267 }
268 }
269
270// if (xform != null)
271// {
272// retRect = xform.createTransformedShape(retRect).getBounds2D();
273// }
274
275 //If no contents, use degenerate rectangle
276 if (retRect == null) retRect = new Rectangle2D.Float();
277
278 boundingBox = boundsToParent(retRect);
279 }
280
281 public boolean updateTime(double curTime) throws SVGException
282 {
283 boolean changeState = super.updateTime(curTime);
284 Iterator it = children.iterator();
285
286 //Distribute message to all members of this group
287 while (it.hasNext())
288 {
289 SVGElement ele = (SVGElement)it.next();
290 boolean updateVal = ele.updateTime(curTime);
291
292 changeState = changeState || updateVal;
293
294 //Update our shape if shape aware children change
295 if (ele instanceof ShapeElement) cachedShape = null;
296 if (ele instanceof RenderableElement) boundingBox = null;
297 }
298
299 return changeState;
300 }
301}
Note: See TracBrowser for help on using the repository browser.