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