source: josm/trunk/src/com/kitfox/svg/SVGRoot.java@ 10746

Last change on this file since 10746 was 8084, checked in by bastiK, 10 years ago

add svn:eol-style=native for svgsalamander

  • Property svn:eol-style set to native
File size: 13.4 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 February 18, 2004, 5:33 PM
35 */
36
37package com.kitfox.svg;
38
39import com.kitfox.svg.xml.NumberWithUnits;
40import com.kitfox.svg.xml.StyleAttribute;
41import com.kitfox.svg.xml.StyleSheet;
42import java.awt.Graphics2D;
43import java.awt.Rectangle;
44import java.awt.Shape;
45import java.awt.geom.AffineTransform;
46import java.awt.geom.NoninvertibleTransformException;
47import java.awt.geom.Point2D;
48import java.awt.geom.Rectangle2D;
49import java.util.List;
50
51/**
52 * The root element of an SVG tree.
53 *
54 * @author Mark McKay
55 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
56 */
57public class SVGRoot extends Group
58{
59 public static final String TAG_NAME = "svg";
60
61 NumberWithUnits x;
62 NumberWithUnits y;
63 NumberWithUnits width;
64 NumberWithUnits height;
65
66 Rectangle2D.Float viewBox = null;
67
68 public static final int PA_X_NONE = 0;
69 public static final int PA_X_MIN = 1;
70 public static final int PA_X_MID = 2;
71 public static final int PA_X_MAX = 3;
72
73 public static final int PA_Y_NONE = 0;
74 public static final int PA_Y_MIN = 1;
75 public static final int PA_Y_MID = 2;
76 public static final int PA_Y_MAX = 3;
77
78 public static final int PS_MEET = 0;
79 public static final int PS_SLICE = 1;
80
81 int parSpecifier = PS_MEET;
82 int parAlignX = PA_X_MID;
83 int parAlignY = PA_Y_MID;
84
85 final AffineTransform viewXform = new AffineTransform();
86 final Rectangle2D.Float clipRect = new Rectangle2D.Float();
87
88 private StyleSheet styleSheet;
89
90 /** Creates a new instance of SVGRoot */
91 public SVGRoot()
92 {
93 }
94
95 public String getTagName()
96 {
97 return TAG_NAME;
98 }
99
100 public void build() throws SVGException
101 {
102 super.build();
103
104 StyleAttribute sty = new StyleAttribute();
105
106 if (getPres(sty.setName("x")))
107 {
108 x = sty.getNumberWithUnits();
109 }
110
111 if (getPres(sty.setName("y")))
112 {
113 y = sty.getNumberWithUnits();
114 }
115
116 if (getPres(sty.setName("width")))
117 {
118 width = sty.getNumberWithUnits();
119 }
120
121 if (getPres(sty.setName("height")))
122 {
123 height = sty.getNumberWithUnits();
124 }
125
126 if (getPres(sty.setName("viewBox")))
127 {
128 float[] coords = sty.getFloatList();
129 viewBox = new Rectangle2D.Float(coords[0], coords[1], coords[2], coords[3]);
130 }
131
132 if (getPres(sty.setName("preserveAspectRatio")))
133 {
134 String preserve = sty.getStringValue();
135
136 if (contains(preserve, "none")) { parAlignX = PA_X_NONE; parAlignY = PA_Y_NONE; }
137 else if (contains(preserve, "xMinYMin")) { parAlignX = PA_X_MIN; parAlignY = PA_Y_MIN; }
138 else if (contains(preserve, "xMidYMin")) { parAlignX = PA_X_MID; parAlignY = PA_Y_MIN; }
139 else if (contains(preserve, "xMaxYMin")) { parAlignX = PA_X_MAX; parAlignY = PA_Y_MIN; }
140 else if (contains(preserve, "xMinYMid")) { parAlignX = PA_X_MIN; parAlignY = PA_Y_MID; }
141 else if (contains(preserve, "xMidYMid")) { parAlignX = PA_X_MID; parAlignY = PA_Y_MID; }
142 else if (contains(preserve, "xMaxYMid")) { parAlignX = PA_X_MAX; parAlignY = PA_Y_MID; }
143 else if (contains(preserve, "xMinYMax")) { parAlignX = PA_X_MIN; parAlignY = PA_Y_MAX; }
144 else if (contains(preserve, "xMidYMax")) { parAlignX = PA_X_MID; parAlignY = PA_Y_MAX; }
145 else if (contains(preserve, "xMaxYMax")) { parAlignX = PA_X_MAX; parAlignY = PA_Y_MAX; }
146
147 if (contains(preserve, "meet"))
148 {
149 parSpecifier = PS_MEET;
150 }
151 else if (contains(preserve, "slice"))
152 {
153 parSpecifier = PS_SLICE;
154 }
155 }
156
157 prepareViewport();
158 }
159
160 private boolean contains(String text, String find)
161 {
162 return (text.indexOf(find) != -1);
163 }
164
165 public SVGRoot getRoot()
166 {
167 return this;
168 }
169
170 protected void prepareViewport()
171 {
172 Rectangle deviceViewport = diagram.getDeviceViewport();
173
174 Rectangle2D defaultBounds;
175 try
176 {
177 defaultBounds = getBoundingBox();
178 }
179 catch (SVGException ex)
180 {
181 defaultBounds= new Rectangle2D.Float();
182 }
183
184 //Determine destination rectangle
185 float xx, yy, ww, hh;
186 if (width != null)
187 {
188 xx = (x == null) ? 0 : StyleAttribute.convertUnitsToPixels(x.getUnits(), x.getValue());
189 if (width.getUnits() == NumberWithUnits.UT_PERCENT)
190 {
191 ww = width.getValue() * deviceViewport.width;
192 }
193 else
194 {
195 ww = StyleAttribute.convertUnitsToPixels(width.getUnits(), width.getValue());
196 }
197 }
198 else if (viewBox != null)
199 {
200 xx = (float)viewBox.x;
201 ww = (float)viewBox.width;
202 width = new NumberWithUnits(ww, NumberWithUnits.UT_PX);
203 x = new NumberWithUnits(xx, NumberWithUnits.UT_PX);
204 }
205 else
206 {
207 //Estimate size from scene bounding box
208 xx = (float)defaultBounds.getX();
209 ww = (float)defaultBounds.getWidth();
210 width = new NumberWithUnits(ww, NumberWithUnits.UT_PX);
211 x = new NumberWithUnits(xx, NumberWithUnits.UT_PX);
212 }
213
214 if (height != null)
215 {
216 yy = (y == null) ? 0 : StyleAttribute.convertUnitsToPixels(y.getUnits(), y.getValue());
217 if (height.getUnits() == NumberWithUnits.UT_PERCENT)
218 {
219 hh = height.getValue() * deviceViewport.height;
220 }
221 else
222 {
223 hh = StyleAttribute.convertUnitsToPixels(height.getUnits(), height.getValue());
224 }
225 }
226 else if (viewBox != null)
227 {
228 yy = (float)viewBox.y;
229 hh = (float)viewBox.height;
230 height = new NumberWithUnits(hh, NumberWithUnits.UT_PX);
231 y = new NumberWithUnits(yy, NumberWithUnits.UT_PX);
232 }
233 else
234 {
235 //Estimate size from scene bounding box
236 yy = (float)defaultBounds.getY();
237 hh = (float)defaultBounds.getHeight();
238 height = new NumberWithUnits(hh, NumberWithUnits.UT_PX);
239 y = new NumberWithUnits(yy, NumberWithUnits.UT_PX);
240 }
241
242 clipRect.setRect(xx, yy, ww, hh);
243
244// if (viewBox == null)
245// {
246// viewXform.setToIdentity();
247// }
248// else
249// {
250// //If viewport window is set, we are drawing to entire viewport
251// clipRect.setRect(deviceViewport);
252//
253// viewXform.setToIdentity();
254// viewXform.setToTranslation(deviceViewport.x, deviceViewport.y);
255// viewXform.scale(deviceViewport.width, deviceViewport.height);
256// viewXform.scale(1 / viewBox.width, 1 / viewBox.height);
257// viewXform.translate(-viewBox.x, -viewBox.y);
258// }
259 }
260
261 public void renderToViewport(Graphics2D g) throws SVGException
262 {
263 prepareViewport();
264
265 if (viewBox == null)
266 {
267 viewXform.setToIdentity();
268 }
269 else
270 {
271 Rectangle deviceViewport = g.getClipBounds();
272 //If viewport window is set, we are drawing to entire viewport
273 clipRect.setRect(deviceViewport);
274
275 viewXform.setToIdentity();
276 viewXform.setToTranslation(deviceViewport.x, deviceViewport.y);
277 viewXform.scale(deviceViewport.width, deviceViewport.height);
278 viewXform.scale(1 / viewBox.width, 1 / viewBox.height);
279 viewXform.translate(-viewBox.x, -viewBox.y);
280 }
281
282 AffineTransform cachedXform = g.getTransform();
283 g.transform(viewXform);
284
285 super.render(g);
286
287 g.setTransform(cachedXform);
288 }
289
290 public void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List retVec) throws SVGException
291 {
292 if (viewXform != null)
293 {
294 ltw = new AffineTransform(ltw);
295 ltw.concatenate(viewXform);
296 }
297
298 super.pick(pickArea, ltw, boundingBox, retVec);
299 }
300
301 public void pick(Point2D point, boolean boundingBox, List retVec) throws SVGException
302 {
303 Point2D xPoint = new Point2D.Double(point.getX(), point.getY());
304 if (viewXform != null)
305 {
306 try
307 {
308 viewXform.inverseTransform(point, xPoint);
309 } catch (NoninvertibleTransformException ex)
310 {
311 throw new SVGException(ex);
312 }
313 }
314
315 super.pick(xPoint, boundingBox, retVec);
316 }
317
318 public Shape getShape()
319 {
320 Shape shape = super.getShape();
321 return viewXform.createTransformedShape(shape);
322 }
323
324 public Rectangle2D getBoundingBox() throws SVGException
325 {
326 Rectangle2D bbox = super.getBoundingBox();
327 return viewXform.createTransformedShape(bbox).getBounds2D();
328 }
329
330 public float getDeviceWidth()
331 {
332 return clipRect.width;
333 }
334
335 public float getDeviceHeight()
336 {
337 return clipRect.height;
338 }
339
340 public Rectangle2D getDeviceRect(Rectangle2D rect)
341 {
342 rect.setRect(clipRect);
343 return rect;
344 }
345
346 /**
347 * Updates all attributes in this diagram associated with a time event.
348 * Ie, all attributes with track information.
349 * @return - true if this node has changed state as a result of the time
350 * update
351 */
352 public boolean updateTime(double curTime) throws SVGException
353 {
354 boolean changeState = super.updateTime(curTime);
355
356 StyleAttribute sty = new StyleAttribute();
357 boolean shapeChange = false;
358
359 if (getPres(sty.setName("x")))
360 {
361 NumberWithUnits newVal = sty.getNumberWithUnits();
362 if (!newVal.equals(x))
363 {
364 x = newVal;
365 shapeChange = true;
366 }
367 }
368
369 if (getPres(sty.setName("y")))
370 {
371 NumberWithUnits newVal = sty.getNumberWithUnits();
372 if (!newVal.equals(y))
373 {
374 y = newVal;
375 shapeChange = true;
376 }
377 }
378
379 if (getPres(sty.setName("width")))
380 {
381 NumberWithUnits newVal = sty.getNumberWithUnits();
382 if (!newVal.equals(width))
383 {
384 width = newVal;
385 shapeChange = true;
386 }
387 }
388
389 if (getPres(sty.setName("height")))
390 {
391 NumberWithUnits newVal = sty.getNumberWithUnits();
392 if (!newVal.equals(height))
393 {
394 height = newVal;
395 shapeChange = true;
396 }
397 }
398
399 if (getPres(sty.setName("viewBox")))
400 {
401 float[] coords = sty.getFloatList();
402 Rectangle2D.Float newViewBox = new Rectangle2D.Float(coords[0], coords[1], coords[2], coords[3]);
403 if (!newViewBox.equals(viewBox))
404 {
405 viewBox = newViewBox;
406 shapeChange = true;
407 }
408 }
409
410 if (shapeChange)
411 {
412 build();
413 }
414
415 return changeState || shapeChange;
416 }
417
418 /**
419 * @return the styleSheet
420 */
421 public StyleSheet getStyleSheet()
422 {
423 if (styleSheet == null)
424 {
425 for (int i = 0; i < getNumChildren(); ++i)
426 {
427 SVGElement ele = getChild(i);
428 if (ele instanceof Style)
429 {
430 return ((Style)ele).getStyleSheet();
431 }
432 }
433 }
434
435 return styleSheet;
436 }
437
438 /**
439 * @param styleSheet the styleSheet to set
440 */
441 public void setStyleSheet(StyleSheet styleSheet)
442 {
443 this.styleSheet = styleSheet;
444 }
445
446}
Note: See TracBrowser for help on using the repository browser.