source: josm/trunk/src/com/kitfox/svg/ShapeElement.java@ 4656

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

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

File size: 12.4 KB
Line 
1/*
2 * ShapeElement.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, 5:21 PM
26 */
27
28package com.kitfox.svg;
29
30import com.kitfox.svg.Marker.MarkerLayout;
31import com.kitfox.svg.Marker.MarkerPos;
32import com.kitfox.svg.xml.StyleAttribute;
33import java.awt.AlphaComposite;
34import java.awt.BasicStroke;
35import java.awt.Color;
36import java.awt.Composite;
37import java.awt.Graphics2D;
38import java.awt.Paint;
39import java.awt.Shape;
40import java.awt.geom.AffineTransform;
41import java.awt.geom.Point2D;
42import java.awt.geom.Rectangle2D;
43import java.net.URI;
44import java.util.ArrayList;
45import java.util.List;
46
47
48
49/**
50 * Parent of shape objects
51 *
52 * @author Mark McKay
53 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
54 */
55abstract public class ShapeElement extends RenderableElement
56{
57
58 /**
59 * This is necessary to get text elements to render the stroke the correct
60 * width. It is an alternative to producing new font glyph sets at different
61 * sizes.
62 */
63 protected float strokeWidthScalar = 1f;
64
65 /** Creates a new instance of ShapeElement */
66 public ShapeElement() {
67 }
68
69 abstract public void render(java.awt.Graphics2D g) throws SVGException;
70
71 /*
72 protected void setStrokeWidthScalar(float strokeWidthScalar)
73 {
74 this.strokeWidthScalar = strokeWidthScalar;
75 }
76 */
77
78 void pick(Point2D point, boolean boundingBox, List retVec) throws SVGException
79 {
80 StyleAttribute styleAttrib = new StyleAttribute();
81// if (getStyle(styleAttrib.setName("fill")) && getShape().contains(point))
82 if ((boundingBox ? getBoundingBox() : getShape()).contains(point))
83 {
84 retVec.add(getPath(null));
85 }
86 }
87
88 void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List retVec) throws SVGException
89 {
90 StyleAttribute styleAttrib = new StyleAttribute();
91// if (getStyle(styleAttrib.setName("fill")) && getShape().contains(point))
92 if (ltw.createTransformedShape((boundingBox ? getBoundingBox() : getShape())).intersects(pickArea))
93 {
94 retVec.add(getPath(null));
95 }
96 }
97
98 protected void renderShape(Graphics2D g, Shape shape) throws SVGException
99 {
100//g.setColor(Color.green);
101
102 StyleAttribute styleAttrib = new StyleAttribute();
103
104 //Don't process if not visible
105 if (getStyle(styleAttrib.setName("visibility")))
106 {
107 if (!styleAttrib.getStringValue().equals("visible")) return;
108 }
109
110 if (getStyle(styleAttrib.setName("display")))
111 {
112 if (styleAttrib.getStringValue().equals("none")) return;
113 }
114
115 //None, solid color, gradient, pattern
116 Paint fillPaint = Color.black; //Default to black. Must be explicitly set to none for no fill.
117 if (getStyle(styleAttrib.setName("fill")))
118 {
119 if (styleAttrib.getStringValue().equals("none")) fillPaint = null;
120 else
121 {
122 fillPaint = styleAttrib.getColorValue();
123 if (fillPaint == null)
124 {
125 URI uri = styleAttrib.getURIValue(getXMLBase());
126 if (uri != null)
127 {
128 Rectangle2D bounds = shape.getBounds2D();
129 AffineTransform xform = g.getTransform();
130
131 SVGElement ele = diagram.getUniverse().getElement(uri);
132 fillPaint = ((FillElement)ele).getPaint(bounds, xform);
133 }
134 }
135 }
136 }
137
138 //Default opacity
139 float opacity = 1f;
140 if (getStyle(styleAttrib.setName("opacity")))
141 {
142 opacity = styleAttrib.getRatioValue();
143 }
144
145 float fillOpacity = opacity;
146 if (getStyle(styleAttrib.setName("fill-opacity")))
147 {
148 fillOpacity *= styleAttrib.getRatioValue();
149 }
150
151
152 Paint strokePaint = null; //Default is to stroke with none
153 if (getStyle(styleAttrib.setName("stroke")))
154 {
155 if (styleAttrib.getStringValue().equals("none")) strokePaint = null;
156 else
157 {
158 strokePaint = styleAttrib.getColorValue();
159 if (strokePaint == null)
160 {
161 URI uri = styleAttrib.getURIValue(getXMLBase());
162 if (uri != null)
163 {
164 Rectangle2D bounds = shape.getBounds2D();
165 AffineTransform xform = g.getTransform();
166
167 SVGElement ele = diagram.getUniverse().getElement(uri);
168 strokePaint = ((FillElement)ele).getPaint(bounds, xform);
169 }
170 }
171 }
172 }
173
174 float[] strokeDashArray = null;
175 if (getStyle(styleAttrib.setName("stroke-dasharray")))
176 {
177 strokeDashArray = styleAttrib.getFloatList();
178 if (strokeDashArray.length == 0) strokeDashArray = null;
179 }
180
181 float strokeDashOffset = 0f;
182 if (getStyle(styleAttrib.setName("stroke-dashoffset")))
183 {
184 strokeDashOffset = styleAttrib.getFloatValueWithUnits();
185 }
186
187 int strokeLinecap = BasicStroke.CAP_BUTT;
188 if (getStyle(styleAttrib.setName("stroke-linecap")))
189 {
190 String val = styleAttrib.getStringValue();
191 if (val.equals("round"))
192 {
193 strokeLinecap = BasicStroke.CAP_ROUND;
194 }
195 else if (val.equals("square"))
196 {
197 strokeLinecap = BasicStroke.CAP_SQUARE;
198 }
199 }
200
201 int strokeLinejoin = BasicStroke.JOIN_MITER;
202 if (getStyle(styleAttrib.setName("stroke-linejoin")))
203 {
204 String val = styleAttrib.getStringValue();
205 if (val.equals("round"))
206 {
207 strokeLinejoin = BasicStroke.JOIN_ROUND;
208 }
209 else if (val.equals("bevel"))
210 {
211 strokeLinejoin = BasicStroke.JOIN_BEVEL;
212 }
213 }
214
215 float strokeMiterLimit = 4f;
216 if (getStyle(styleAttrib.setName("stroke-miterlimit")))
217 {
218 strokeMiterLimit = Math.max(styleAttrib.getFloatValueWithUnits(), 1);
219 }
220
221 float strokeOpacity = opacity;
222 if (getStyle(styleAttrib.setName("stroke-opacity")))
223 {
224 strokeOpacity *= styleAttrib.getRatioValue();
225 }
226
227 float strokeWidth = 1f;
228 if (getStyle(styleAttrib.setName("stroke-width")))
229 {
230 strokeWidth = styleAttrib.getFloatValueWithUnits();
231 }
232// if (strokeWidthScalar != 1f)
233// {
234 strokeWidth *= strokeWidthScalar;
235// }
236
237 Marker markerStart = null;
238 if (getStyle(styleAttrib.setName("marker-start")))
239 {
240 if (!styleAttrib.getStringValue().equals("none"))
241 {
242 URI uri = styleAttrib.getURIValue(getXMLBase());
243 markerStart = (Marker)diagram.getUniverse().getElement(uri);
244 }
245 }
246
247 Marker markerMid = null;
248 if (getStyle(styleAttrib.setName("marker-mid")))
249 {
250 if (!styleAttrib.getStringValue().equals("none"))
251 {
252 URI uri = styleAttrib.getURIValue(getXMLBase());
253 markerMid = (Marker)diagram.getUniverse().getElement(uri);
254 }
255 }
256
257 Marker markerEnd = null;
258 if (getStyle(styleAttrib.setName("marker-end")))
259 {
260 if (!styleAttrib.getStringValue().equals("none"))
261 {
262 URI uri = styleAttrib.getURIValue(getXMLBase());
263 markerEnd = (Marker)diagram.getUniverse().getElement(uri);
264 }
265 }
266
267
268 //Draw the shape
269 if (fillPaint != null && fillOpacity != 0f)
270 {
271 if (fillOpacity <= 0)
272 {
273 //Do nothing
274 }
275 else if (fillOpacity < 1f)
276 {
277 Composite cachedComposite = g.getComposite();
278 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, fillOpacity));
279
280 g.setPaint(fillPaint);
281 g.fill(shape);
282
283 g.setComposite(cachedComposite);
284 }
285 else
286 {
287 g.setPaint(fillPaint);
288 g.fill(shape);
289 }
290 }
291
292
293 if (strokePaint != null && strokeOpacity != 0f)
294 {
295 BasicStroke stroke;
296 if (strokeDashArray == null)
297 {
298 stroke = new BasicStroke(strokeWidth, strokeLinecap, strokeLinejoin, strokeMiterLimit);
299 }
300 else
301 {
302 stroke = new BasicStroke(strokeWidth, strokeLinecap, strokeLinejoin, strokeMiterLimit, strokeDashArray, strokeDashOffset);
303 }
304
305 Shape strokeShape = stroke.createStrokedShape(shape);
306
307 if (strokeOpacity <= 0)
308 {
309 //Do nothing
310 }
311 else if (strokeOpacity < 1f)
312 {
313 Composite cachedComposite = g.getComposite();
314 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, strokeOpacity));
315
316 g.setPaint(strokePaint);
317 g.fill(strokeShape);
318
319 g.setComposite(cachedComposite);
320 }
321 else
322 {
323 g.setPaint(strokePaint);
324 g.fill(strokeShape);
325 }
326 }
327
328 if (markerStart != null || markerMid != null || markerEnd != null)
329 {
330 MarkerLayout layout = new MarkerLayout();
331 layout.layout(shape);
332
333 ArrayList list = layout.getMarkerList();
334 for (int i = 0; i < list.size(); ++i)
335 {
336 MarkerPos pos = (MarkerPos)list.get(i);
337
338 switch (pos.type)
339 {
340 case Marker.MARKER_START:
341 if (markerStart != null)
342 {
343 markerStart.render(g, pos, strokeWidth);
344 }
345 break;
346 case Marker.MARKER_MID:
347 if (markerMid != null)
348 {
349 markerMid.render(g, pos, strokeWidth);
350 }
351 break;
352 case Marker.MARKER_END:
353 if (markerEnd != null)
354 {
355 markerEnd.render(g, pos, strokeWidth);
356 }
357 break;
358 }
359 }
360 }
361 }
362
363 abstract public Shape getShape();
364
365 protected Rectangle2D includeStrokeInBounds(Rectangle2D rect) throws SVGException
366 {
367 StyleAttribute styleAttrib = new StyleAttribute();
368 if (!getStyle(styleAttrib.setName("stroke"))) return rect;
369
370 double strokeWidth = 1;
371 if (getStyle(styleAttrib.setName("stroke-width"))) strokeWidth = styleAttrib.getDoubleValue();
372
373 rect.setRect(
374 rect.getX() - strokeWidth / 2,
375 rect.getY() - strokeWidth / 2,
376 rect.getWidth() + strokeWidth,
377 rect.getHeight() + strokeWidth);
378
379 return rect;
380 }
381
382}
Note: See TracBrowser for help on using the repository browser.