1
2 package org.freehep.graphics2d;
3
4 import java.awt.BasicStroke;
5 import java.awt.Color;
6 import java.awt.Dimension;
7 import java.awt.Font;
8 import java.awt.Insets;
9 import java.awt.Paint;
10 import java.awt.Rectangle;
11 import java.awt.Shape;
12 import java.awt.Stroke;
13 import java.awt.font.TextLayout;
14 import java.awt.geom.AffineTransform;
15 import java.awt.geom.Arc2D;
16 import java.awt.geom.Area;
17 import java.awt.geom.Ellipse2D;
18 import java.awt.geom.GeneralPath;
19 import java.awt.geom.Line2D;
20 import java.awt.geom.Point2D;
21 import java.awt.geom.Rectangle2D;
22 import java.awt.geom.RoundRectangle2D;
23 import java.text.AttributedCharacterIterator;
24 import java.util.Properties;
25
26 import org.freehep.graphics2d.font.FontUtilities;
27 import org.freehep.util.UserProperties;
28
29
30
31
32
33
34
35
36
37
38
39
40 public abstract class AbstractVectorGraphics extends VectorGraphics {
41
42 private UserProperties properties;
43
44 private String creator;
45
46 private boolean isDeviceIndependent;
47
48 private SymbolShape cachedShape;
49
50 private int colorMode;
51
52 private Color backgroundColor;
53
54 private Color currentColor;
55
56 private Paint currentPaint;
57
58 private Font currentFont;
59
60 public AbstractVectorGraphics() {
61 properties = new UserProperties();
62 creator = "FreeHEP Graphics2D Driver";
63 isDeviceIndependent = false;
64 cachedShape = new SymbolShape();
65 colorMode = PrintColor.COLOR;
66
67
68 currentFont = null;
69 backgroundColor = null;
70 currentColor = null;
71 currentPaint = null;
72 }
73
74 protected AbstractVectorGraphics(AbstractVectorGraphics graphics) {
75 super();
76 properties = graphics.properties;
77 creator = graphics.creator;
78 isDeviceIndependent = graphics.isDeviceIndependent;
79 cachedShape = graphics.cachedShape;
80
81 backgroundColor = graphics.backgroundColor;
82 currentColor = graphics.currentColor;
83 currentPaint = graphics.currentPaint;
84 colorMode = graphics.colorMode;
85 currentFont = graphics.currentFont;
86 }
87
88 public void setProperties(Properties newProperties) {
89 if (newProperties == null)
90 return;
91 properties.setProperties(newProperties);
92 }
93
94 protected void initProperties(Properties defaults) {
95 properties = new UserProperties();
96 properties.setProperties(defaults);
97 }
98
99 protected Properties getProperties() {
100 return properties;
101 }
102
103 public String getProperty(String key) {
104 return properties.getProperty(key);
105 }
106
107 public Color getPropertyColor(String key) {
108 return properties.getPropertyColor(key);
109 }
110
111 public Rectangle getPropertyRectangle(String key) {
112 return properties.getPropertyRectangle(key);
113 }
114
115 public Insets getPropertyInsets(String key) {
116 return properties.getPropertyInsets(key);
117 }
118
119 public Dimension getPropertyDimension(String key) {
120 return properties.getPropertyDimension(key);
121 }
122
123 public int getPropertyInt(String key) {
124 return properties.getPropertyInt(key);
125 }
126
127 public double getPropertyDouble(String key) {
128 return properties.getPropertyDouble(key);
129 }
130
131 public boolean isProperty(String key) {
132 return properties.isProperty(key);
133 }
134
135 public String getCreator() {
136 return creator;
137 }
138
139 public void setCreator(String creator) {
140 if (creator != null) {
141 this.creator = creator;
142 }
143 }
144
145 public boolean isDeviceIndependent() {
146 return isDeviceIndependent;
147 }
148
149 public void setDeviceIndependent(boolean isDeviceIndependent) {
150 this.isDeviceIndependent = isDeviceIndependent;
151 }
152
153
154
155
156
157
158 public Font getFont() {
159 return currentFont;
160 }
161
162
163
164
165
166
167 public void setFont(Font font) {
168 if (font == null) return;
169
170
171 currentFont = font;
172 }
173
174 public void drawSymbol(int x, int y, int size, int symbol) {
175 drawSymbol((double) x, (double) y, (double) size, symbol);
176 }
177
178 public void fillSymbol(int x, int y, int size, int symbol) {
179 fillSymbol((double) x, (double) y, (double) size, symbol);
180 }
181
182 public void fillAndDrawSymbol(int x, int y, int size, int symbol,
183 Color fillColor) {
184 fillAndDrawSymbol((double) x, (double) y, (double) size, symbol,
185 fillColor);
186 }
187
188 public void drawSymbol(double x, double y, double size, int symbol) {
189 if (size <= 0)
190 return;
191 drawSymbol(this, x, y, size, symbol);
192 }
193
194 protected void drawSymbol(VectorGraphics g, double x, double y,
195 double size, int symbol) {
196 switch (symbol) {
197 case SYMBOL_VLINE:
198 case SYMBOL_STAR:
199 case SYMBOL_HLINE:
200 case SYMBOL_PLUS:
201 case SYMBOL_CROSS:
202 case SYMBOL_BOX:
203 case SYMBOL_UP_TRIANGLE:
204 case SYMBOL_DN_TRIANGLE:
205 case SYMBOL_DIAMOND:
206 cachedShape.create(symbol, x, y, size);
207 g.draw(cachedShape);
208 break;
209
210 case SYMBOL_CIRCLE: {
211 double diameter = Math.max(1, size);
212 diameter += (diameter % 2);
213 g.drawOval(x - diameter / 2, y - diameter / 2, diameter, diameter);
214 break;
215 }
216 }
217 }
218
219 public void fillSymbol(double x, double y, double size, int symbol) {
220 if (size <= 0)
221 return;
222 fillSymbol(this, x, y, size, symbol);
223 }
224
225 protected void fillSymbol(VectorGraphics g, double x, double y,
226 double size, int symbol) {
227 switch (symbol) {
228 case SYMBOL_VLINE:
229 case SYMBOL_STAR:
230 case SYMBOL_HLINE:
231 case SYMBOL_PLUS:
232 case SYMBOL_CROSS:
233 cachedShape.create(symbol, x, y, size);
234 g.draw(cachedShape);
235 break;
236
237 case SYMBOL_BOX:
238 case SYMBOL_UP_TRIANGLE:
239 case SYMBOL_DN_TRIANGLE:
240 case SYMBOL_DIAMOND:
241 cachedShape.create(symbol, x, y, size);
242 g.fill(cachedShape);
243 break;
244
245 case SYMBOL_CIRCLE: {
246 double diameter = Math.max(1, size);
247 diameter += (diameter % 2);
248 g.fillOval(x - diameter / 2, y - diameter / 2, diameter, diameter);
249 break;
250 }
251 }
252 }
253
254 public void fillAndDrawSymbol(double x, double y, double size, int symbol,
255 Color fillColor) {
256 Color color = getColor();
257 setColor(fillColor);
258 fillSymbol(x, y, size, symbol);
259 setColor(color);
260 drawSymbol(x, y, size, symbol);
261 }
262
263 public void fillAndDraw(Shape s, Color fillColor) {
264 Color color = getColor();
265 setColor(fillColor);
266 fill(s);
267 setColor(color);
268 draw(s);
269 }
270
271
272
273
274
275
276
277 private static final double bias = 0.5;
278
279 public void clearRect(int x, int y, int width, int height) {
280 clearRect((double) x + bias, (double) y + bias, (double) width, (double) height);
281 }
282
283 public void drawLine(int x1, int y1, int x2, int y2) {
284 drawLine((double) x1 + bias, (double) y1 + bias, (double) x2 + bias, (double) y2 + bias);
285 }
286
287 public void drawRect(int x, int y, int width, int height) {
288 drawRect((double) x + bias, (double) y + bias, (double) width, (double) height);
289 }
290
291 public void fillRect(int x, int y, int width, int height) {
292 fillRect((double) x, (double) y, (double) width, (double) height);
293 }
294
295 public void drawArc(int x, int y, int width, int height, int startAngle,
296 int arcAngle) {
297 drawArc((double) x + bias, (double) y + bias, (double) width, (double) height,
298 (double) startAngle, (double) arcAngle);
299 }
300
301 public void fillArc(int x, int y, int width, int height, int startAngle,
302 int arcAngle) {
303 fillArc((double) x, (double) y, (double) width, (double) height,
304 (double) startAngle, (double) arcAngle);
305 }
306
307 public void drawOval(int x, int y, int width, int height) {
308 drawOval((double) x + bias, (double) y + bias, (double) width, (double) height);
309 }
310
311 public void fillOval(int x, int y, int width, int height) {
312 fillOval((double) x, (double) y, (double) width, (double) height);
313 }
314
315 public void drawRoundRect(int x, int y, int width, int height,
316 int arcWidth, int arcHeight) {
317 drawRoundRect((double)x + bias, (double)y + bias, (double) width, (double) height, (double) arcWidth,
318 (double) arcHeight);
319 }
320
321 public void fillRoundRect(int x, int y, int width, int height,
322 int arcWidth, int arcHeight) {
323 fillRoundRect((double) x, (double) y, (double) width, (double) height,
324 (double) arcWidth, (double) arcHeight);
325 }
326
327 public void translate(int x, int y) {
328 translate((double) x, (double) y);
329 }
330
331
332
333
334 public void setLineWidth(int width) {
335 setLineWidth((double) width);
336 }
337
338 public void setLineWidth(double width) {
339 Stroke stroke = getStroke();
340 if (stroke instanceof BasicStroke) {
341 BasicStroke cs = (BasicStroke) stroke;
342 if (cs.getLineWidth() != width) {
343 stroke = new BasicStroke((float) width, cs.getEndCap(), cs
344 .getLineJoin(), cs.getMiterLimit(), cs.getDashArray(),
345 cs.getDashPhase());
346 setStroke(stroke);
347 }
348 } else {
349 stroke = new BasicStroke((float) width);
350 setStroke(stroke);
351 }
352 }
353
354 public void drawString(String str, int x, int y) {
355 drawString(str, (double) x, (double) y);
356 }
357
358 public void drawString(String s, float x, float y) {
359 drawString(s, (double) x, (double) y);
360 }
361
362 public void drawString(AttributedCharacterIterator iterator, int x, int y) {
363 drawString(iterator, (float) x, (float) y);
364 }
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382 private Point2D drawFrameAndBanner(TextLayout tl, double x, double y, int horizontal,
383 int vertical, boolean framed, Color frameColor, double frameWidth,
384 boolean banner, Color bannerColor) {
385
386
387 Rectangle2D bounds = tl.getBounds();
388
389
390 bounds.setRect(
391 bounds.getX(),
392 bounds.getY(),
393
394 Math.max(tl.getAdvance(), bounds.getWidth()),
395 bounds.getHeight());
396
397
398 AffineTransform at = AffineTransform.getTranslateInstance(x, y);
399
400
401 if (horizontal == TEXT_RIGHT) {
402 at.translate(- bounds.getWidth(), 0);
403 } else if (horizontal == TEXT_CENTER) {
404 at.translate(- bounds.getWidth() / 2, 0);
405 }
406
407
408 if (vertical == TEXT_BASELINE) {
409
410 } else if (vertical == TEXT_TOP) {
411 at.translate(0, - bounds.getY());
412 } else if (vertical == TEXT_CENTER) {
413
414
415
416
417 at.translate(0, tl.getDescent());
418 } else if (vertical == TEXT_BOTTOM) {
419 at.translate(0, - bounds.getHeight() - bounds.getY());
420 }
421
422
423 bounds = at.createTransformedShape(bounds).getBounds2D();
424
425 Point2D result = at.transform(new Point2D.Double(0, 0), new Point2D.Double());
426
427
428 double adjustment = (getFont().getSize2D() * 2) / 10;
429
430
431 bounds.setRect(
432 bounds.getX() - adjustment,
433 bounds.getY() - adjustment,
434 bounds.getWidth() + 2 * adjustment,
435 bounds.getHeight() + 2 * adjustment);
436
437 if (banner) {
438 Paint paint = getPaint();
439 setColor(bannerColor);
440 fill(bounds);
441 setPaint(paint);
442 }
443 if (framed) {
444 Paint paint = getPaint();
445 Stroke stroke = getStroke();
446 setColor(frameColor);
447 setLineWidth(frameWidth);
448 draw(bounds);
449 setPaint(paint);
450 setStroke(stroke);
451 }
452
453 return result;
454 }
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470 public void drawString(String str, double x, double y, int horizontal,
471 int vertical, boolean framed, Color frameColor, double frameWidth,
472 boolean banner, Color bannerColor) {
473
474
475
476 TextLayout tl = new TextLayout(
477 str,
478 FontUtilities.getAttributes(getFont()),
479 getFontRenderContext());
480
481
482 Point2D offset = drawFrameAndBanner(
483 tl, x, y, horizontal, vertical,
484 framed, frameColor, frameWidth, banner, bannerColor);
485
486
487 drawString(str, offset.getX(), offset.getY());
488 }
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505 public void drawString(TagString str, double x, double y, int horizontal,
506 int vertical, boolean framed, Color frameColor, double frameWidth,
507 boolean banner, Color bannerColor) {
508
509 GenericTagHandler tagHandler = new GenericTagHandler(this);
510 TextLayout tl = tagHandler.createTextLayout(str, getFont().getSize2D() / 7.5);
511
512
513 Point2D offset = drawFrameAndBanner(
514 tl, x, y, horizontal, vertical,
515 framed, frameColor, frameWidth, banner, bannerColor);
516
517
518
519 tagHandler.print(str, offset.getX(), offset.getY(), getFont().getSize2D() / 7.5);
520 }
521
522
523
524 public void drawString(String str, double x, double y, int horizontal,
525 int vertical) {
526 drawString(str, x, y, horizontal, vertical, false, null, 0, false, null);
527 }
528
529 public void drawString(TagString str, double x, double y) {
530 drawString(str, x, y, TEXT_LEFT, TEXT_BASELINE);
531 }
532
533 public void drawString(TagString str, double x, double y, int horizontal,
534 int vertical) {
535 drawString(str, x, y, horizontal, vertical, false, null, 0, false, null);
536 }
537
538
539 public int getColorMode() {
540 return colorMode;
541 }
542
543 public void setColorMode(int colorMode) {
544 this.colorMode = colorMode;
545 }
546
547
548
549
550
551
552 public Color getBackground() {
553 return backgroundColor;
554 }
555
556
557
558
559
560
561 public void setBackground(Color color) {
562 backgroundColor = color;
563 }
564
565
566
567
568
569
570 public void setColor(Color color) {
571 if (color == null) return;
572
573 currentColor = color;
574 currentPaint = color;
575 }
576
577
578
579
580
581
582 public Color getColor() {
583 return currentColor;
584 }
585
586
587
588
589
590
591 public void setPaint(Paint paint) {
592 if (paint == null) return;
593
594 if (!(paint instanceof Color))
595 currentColor = null;
596 currentPaint = paint;
597 }
598
599
600
601
602
603
604 public Paint getPaint() {
605 return currentPaint;
606 }
607
608
609
610
611
612
613 protected Color getPrintColor(Color color) {
614
615 if (colorMode == PrintColor.COLOR)
616 return color;
617
618
619 PrintColor printColor = PrintColor.createPrintColor(color);
620 return printColor.getColor(colorMode);
621 }
622
623 public void rotate(double theta, double x, double y) {
624 translate(x, y);
625 rotate(theta);
626 translate(-x, -y);
627 }
628
629 public void drawArc(double x, double y, double width, double height,
630 double startAngle, double arcAngle) {
631 draw(new Arc2D.Double(x, y, width, height, startAngle, arcAngle,
632 Arc2D.OPEN));
633 }
634
635 public void drawLine(double x1, double y1, double x2, double y2) {
636 draw(new Line2D.Double(x1, y1, x2, y2));
637 }
638
639 public void drawOval(double x, double y, double width, double height) {
640 draw(new Ellipse2D.Double(x, y, width, height));
641 }
642
643 public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
644 draw(createShape(xPoints, yPoints, nPoints, false, true));
645 }
646
647 public void drawPolyline(double[] xPoints, double[] yPoints, int nPoints) {
648 draw(createShape(xPoints, yPoints, nPoints, false));
649 }
650
651 public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
652 draw(createShape(xPoints, yPoints, nPoints, true, true));
653 }
654
655 public void drawPolygon(double[] xPoints, double[] yPoints, int nPoints) {
656 draw(createShape(xPoints, yPoints, nPoints, true));
657 }
658
659 public void drawRect(double x, double y, double width, double height) {
660 draw(new Rectangle2D.Double(x, y, width, height));
661 }
662
663 public void drawRoundRect(double x, double y, double width, double height,
664 double arcWidth, double arcHeight) {
665 draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth,
666 arcHeight));
667 }
668
669 public void fillArc(double x, double y, double width, double height,
670 double startAngle, double arcAngle) {
671 fill(new Arc2D.Double(x, y, width, height, startAngle, arcAngle,
672 Arc2D.PIE));
673 }
674
675 public void fillOval(double x, double y, double width, double height) {
676 fill(new Ellipse2D.Double(x, y, width, height));
677 }
678
679 public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
680 fill(createShape(xPoints, yPoints, nPoints, true, false));
681 }
682
683 public void fillPolygon(double[] xPoints, double[] yPoints, int nPoints) {
684 fill(createShape(xPoints, yPoints, nPoints, true));
685 }
686
687 public void fillRect(double x, double y, double width, double height) {
688 fill(new Rectangle2D.Double(x, y, width, height));
689 }
690
691 public void fillRoundRect(double x, double y, double width, double height,
692 double arcWidth, double arcHeight) {
693 fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth,
694 arcHeight));
695 }
696
697
698
699
700
701
702
703
704
705
706 protected abstract Shape createShape(double[] xPoints, double[] yPoints,
707 int nPoints, boolean close);
708
709
710
711
712
713
714
715
716
717
718 protected Shape createShape(int[] xPoints, int[] yPoints, int nPoints,
719 boolean close, boolean biased) {
720
721 float offset = biased ? (float)bias : 0.0f;
722 GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
723 if (nPoints > 0) {
724 path.moveTo(xPoints[0] + offset, yPoints[0] + offset);
725 int lastX = xPoints[0];
726 int lastY = yPoints[0];
727 if (close && (Math.abs(xPoints[nPoints - 1] - lastX) < 1)
728 && (Math.abs(yPoints[nPoints - 1] - lastY) < 1)) {
729 nPoints--;
730 }
731 for (int i = 1; i < nPoints; i++) {
732 if ((Math.abs(xPoints[i] - lastX) > 1)
733 || (Math.abs(yPoints[i] - lastY) > 1)) {
734 path.lineTo(xPoints[i] + offset, yPoints[i] + offset);
735 lastX = xPoints[i];
736 lastY = yPoints[i];
737 }
738 }
739 if (close)
740 path.closePath();
741 }
742 return path;
743 }
744
745
746
747
748
749
750
751
752
753
754
755 public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
756 if (onStroke && getStroke() != null) {
757 s = getStroke().createStrokedShape(s);
758 }
759
760 if (getTransform() != null) {
761 s = getTransform().createTransformedShape(s);
762 }
763
764 Area area = new Area(s);
765 if (getClip() != null) {
766 area.intersect(new Area(getClip()));
767 }
768
769 return area.intersects(rect);
770 }
771 }