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 }