1
2 package org.freehep.graphics2d;
3
4 import java.awt.Rectangle;
5 import java.awt.Shape;
6 import java.awt.geom.AffineTransform;
7 import java.awt.geom.PathIterator;
8 import java.awt.geom.Point2D;
9 import java.awt.geom.Rectangle2D;
10
11
12
13
14
15
16
17
18
19
20
21 public class SymbolShape implements Shape {
22
23 private static final double SQRT_2 = Math.sqrt(2.);
24
25 private static final double SQRT_3 = Math.sqrt(3.);
26
27 private class ArrayPathIterator implements PathIterator {
28
29 private int currentPoint = 0;
30
31 private double[] points;
32
33 private int[] type;
34
35 private int numberOfPoints;
36
37 private ArrayPathIterator(double[] points, int[] type) {
38 this.points = points;
39 this.type = type;
40 }
41
42 public boolean isDone() {
43 return currentPoint >= numberOfPoints;
44 }
45
46 public void next() {
47 currentPoint++;
48 }
49
50 public int currentSegment(double[] coords) {
51 coords[0] = points[2 * currentPoint];
52 coords[1] = points[2 * currentPoint + 1];
53 return type[currentPoint];
54 }
55
56 public int currentSegment(float[] coords) {
57 coords[0] = (float) points[2 * currentPoint];
58 coords[1] = (float) points[2 * currentPoint + 1];
59 return type[currentPoint];
60 }
61
62 public int getWindingRule() {
63 return PathIterator.WIND_NON_ZERO;
64 }
65
66 private void reset() {
67 currentPoint = 0;
68 }
69
70 private void done() {
71 currentPoint = numberOfPoints;
72 }
73 }
74
75 private double points[];
76
77 private int type[];
78
79 private ArrayPathIterator pathIterator;
80
81 private double x, y;
82
83 private double size;
84
85 private int symbol;
86
87 public SymbolShape() {
88 ensureNumberOfPoints(10);
89 type[0] = PathIterator.SEG_MOVETO;
90 for (int i = 1; i < type.length; i++) {
91 type[i] = PathIterator.SEG_LINETO;
92 }
93 this.pathIterator = new ArrayPathIterator(points, type);
94 }
95
96 public boolean contains(double x, double y) {
97 return getBounds2D().contains(x, y);
98 }
99
100 public boolean contains(double x, double y, double w, double h) {
101 return contains(x, y) && contains(x + w, y) && contains(x, y + h)
102 && contains(x + w, y + h);
103 }
104
105 public boolean contains(Point2D p) {
106 return contains(p.getX(), p.getY());
107 }
108
109 public boolean contains(Rectangle2D r) {
110 return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
111 }
112
113
114 public boolean intersects(double x, double y, double w, double h) {
115 return contains(x, y) || contains(x + w, y) || contains(x, y + h)
116 || contains(x + w, y + h);
117 }
118
119 public boolean intersects(Rectangle2D r) {
120 return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
121 }
122
123 public PathIterator getPathIterator(AffineTransform at, double flatness) {
124 return getPathIterator(at);
125 }
126
127 public Rectangle2D getBounds2D() {
128 return new Rectangle2D.Double(x - size / 2, y - size / 2, size, size);
129 }
130
131 public Rectangle getBounds() {
132 return getBounds2D().getBounds();
133 }
134
135 public PathIterator getPathIterator(AffineTransform t) {
136 if (t != null) {
137 t.transform(points, 0, pathIterator.points, 0, points.length / 2);
138 }
139
140
141
142
143 pathIterator.reset();
144 return pathIterator;
145 }
146
147
148
149 private void createNew(int n) {
150
151
152
153 ensureNumberOfPoints(n);
154 pathIterator.numberOfPoints = n;
155 pathIterator.done();
156 }
157
158
159
160
161
162
163
164 public void create(int symbol, double x, double y, double size) {
165 this.symbol = symbol;
166 this.x = x;
167 this.y = y;
168 this.size = size;
169 switch (symbol) {
170 case VectorGraphicsConstants.SYMBOL_VLINE:
171 createVLine(x, y, size);
172 break;
173 case VectorGraphicsConstants.SYMBOL_HLINE:
174 createHLine(x, y, size);
175 break;
176 case VectorGraphicsConstants.SYMBOL_PLUS:
177 createPlus(x, y, size);
178 break;
179 case VectorGraphicsConstants.SYMBOL_CROSS:
180 createCross(x, y, size);
181 break;
182 case VectorGraphicsConstants.SYMBOL_STAR:
183 createStar(x, y, size);
184 break;
185 case VectorGraphicsConstants.SYMBOL_BOX:
186 createBox(x, y, size);
187 break;
188 case VectorGraphicsConstants.SYMBOL_UP_TRIANGLE:
189 createUpTriangle(x, y, size);
190 break;
191 case VectorGraphicsConstants.SYMBOL_DN_TRIANGLE:
192 createDownTriangle(x, y, size);
193 break;
194 case VectorGraphicsConstants.SYMBOL_DIAMOND:
195 createDiamond(x, y, size);
196 break;
197 }
198 }
199
200 public String toString() {
201 return getClass() + ": " + symbol + " (" + x + ", " + y + ") size: "
202 + size;
203 }
204
205 private void createHLine(double x, double y, double size) {
206 createNew(2);
207
208 type[0] = PathIterator.SEG_MOVETO;
209 points[0] = x - size / 2;
210 points[1] = y;
211
212 type[1] = PathIterator.SEG_LINETO;
213 points[2] = x + size / 2;
214 points[3] = y;
215 }
216
217 private void createVLine(double x, double y, double size) {
218 createNew(2);
219
220 type[0] = PathIterator.SEG_MOVETO;
221 points[0] = x;
222 points[1] = y - size / 2;
223
224 type[1] = PathIterator.SEG_LINETO;
225 points[2] = x;
226 points[3] = y + size / 2;
227 }
228
229 private void createPlus(double x, double y, double size) {
230 createNew(4);
231 double length = size / 2.;
232
233 type[0] = PathIterator.SEG_MOVETO;
234 points[0] = x + length;
235 points[1] = y;
236
237 type[1] = PathIterator.SEG_LINETO;
238 points[2] = x - length;
239 points[3] = y;
240
241 type[2] = PathIterator.SEG_MOVETO;
242 points[4] = x;
243 points[5] = y + length;
244
245 type[3] = PathIterator.SEG_LINETO;
246 points[6] = x;
247 points[7] = y - length;
248 }
249
250 private void createCross(double x, double y, double size) {
251 createNew(4);
252 double side = size / 2. / SQRT_2;
253
254 type[0] = PathIterator.SEG_MOVETO;
255 points[0] = x - side;
256 points[1] = y - side;
257
258 type[1] = PathIterator.SEG_LINETO;
259 points[2] = x + side;
260 points[3] = y + side;
261
262 type[2] = PathIterator.SEG_MOVETO;
263 points[4] = x + side;
264 points[5] = y - side;
265
266 type[3] = PathIterator.SEG_LINETO;
267 points[6] = x - side;
268 points[7] = y + side;
269 }
270
271 private void createStar(double x, double y, double size) {
272 createNew(8);
273
274 double delta = size / 2.;
275
276 type[0] = PathIterator.SEG_MOVETO;
277 points[0] = x;
278 points[1] = y - delta;
279
280 type[1] = PathIterator.SEG_LINETO;
281 points[2] = x;
282 points[3] = y + delta;
283
284 type[2] = PathIterator.SEG_MOVETO;
285 points[4] = x - delta;
286 points[5] = y;
287
288 type[3] = PathIterator.SEG_LINETO;
289 points[6] = x + delta;
290 points[7] = y;
291
292 delta = size / 2. / SQRT_2;
293
294 type[4] = PathIterator.SEG_MOVETO;
295 points[8] = x - delta;
296 points[9] = y - delta;
297
298 type[5] = PathIterator.SEG_LINETO;
299 points[10] = x + delta;
300 points[11] = y + delta;
301
302 type[6] = PathIterator.SEG_MOVETO;
303 points[12] = x + delta;
304 points[13] = y - delta;
305
306 type[7] = PathIterator.SEG_LINETO;
307 points[14] = x - delta;
308 points[15] = y + delta;
309 }
310
311 private void createUpTriangle(double x, double y, double size) {
312 createNew(4);
313
314 type[0] = PathIterator.SEG_MOVETO;
315 points[0] = x;
316 points[1] = y - size / SQRT_3;
317
318 type[1] = PathIterator.SEG_LINETO;
319 points[2] = x - size / 2.;
320 points[3] = y + (-size / SQRT_3 + size * SQRT_3 / 2.);
321
322 type[2] = PathIterator.SEG_LINETO;
323 points[4] = x + size / 2.;
324 points[5] = y + (-size / SQRT_3 + size * SQRT_3 / 2.);
325
326 type[3] = PathIterator.SEG_CLOSE;
327 }
328
329 private void createDownTriangle(double x, double y, double size) {
330 createNew(4);
331
332 type[0] = PathIterator.SEG_MOVETO;
333 points[0] = x;
334 points[1] = y + size / SQRT_3;
335
336 type[1] = PathIterator.SEG_LINETO;
337 points[2] = x - size / 2.;
338 points[3] = y - (-size / SQRT_3 + size * SQRT_3 / 2.);
339
340 type[2] = PathIterator.SEG_LINETO;
341 points[4] = x + size / 2.;
342 points[5] = y - (-size / SQRT_3 + size * SQRT_3 / 2.);
343
344 type[3] = PathIterator.SEG_CLOSE;
345 }
346
347 private void createDiamond(double x, double y, double size) {
348 createNew(5);
349 double length = size / 2.;
350
351 type[0] = PathIterator.SEG_MOVETO;
352 points[0] = x + length;
353 points[1] = y;
354
355 type[1] = PathIterator.SEG_LINETO;
356 points[2] = x;
357 points[3] = y + length;
358
359 type[2] = PathIterator.SEG_LINETO;
360 points[4] = x - length;
361 points[5] = y;
362
363 type[3] = PathIterator.SEG_LINETO;
364 points[6] = x;
365 points[7] = y - length;
366
367 type[4] = PathIterator.SEG_CLOSE;
368 }
369
370 private void createBox(double x, double y, double size) {
371 createNew(5);
372 double side = size / SQRT_2 / 2;
373
374 type[0] = PathIterator.SEG_MOVETO;
375 points[0] = x - side;
376 points[1] = y - side;
377
378 type[1] = PathIterator.SEG_LINETO;
379 points[2] = x + side + 1;
380 points[3] = y - side;
381
382 type[2] = PathIterator.SEG_LINETO;
383 points[4] = x + side + 1;
384 points[5] = y + side + 1;
385
386 type[3] = PathIterator.SEG_LINETO;
387 points[6] = x - side;
388 points[7] = y + side + 1;
389
390 type[4] = PathIterator.SEG_CLOSE;
391 }
392
393 private void ensureNumberOfPoints(int n) {
394 if ((type == null) || (type.length < n)) {
395 this.points = new double[n * 2];
396 this.type = new int[n];
397 }
398 }
399 }