View Javadoc

1   // Copyright 2007, FreeHEP.
2   package org.freehep.graphicsio.emf.gdi;
3   
4   import org.freehep.graphicsio.emf.EMFConstants;
5   import org.freehep.graphicsio.emf.EMFRenderer;
6   
7   import java.util.logging.Logger;
8   import java.awt.BasicStroke;
9   import java.awt.Shape;
10  import java.awt.Stroke;
11  import java.awt.geom.AffineTransform;
12  import java.awt.geom.Rectangle2D;
13  
14  /**
15   * @author Steffen Greiffenberg
16   * @version $Id$
17   */
18  public abstract class AbstractPen implements EMFConstants, GDIObject {
19  
20      /**
21       * Represents a stroke that draws inside the given shape.
22       * Used if EMFConstants.PS_INSIDEFRAME is used
23       */
24      private class InsideFrameStroke implements Stroke {
25  
26          private BasicStroke stroke;
27  
28          public InsideFrameStroke (
29              float width,
30              int cap,
31              int join,
32              float miterlimit,
33              float dash[],
34              float dash_phase) {
35  
36              stroke = new BasicStroke(width, cap, join, miterlimit, dash, dash_phase);
37          }
38  
39          public Shape createStrokedShape(Shape shape) {
40              if (shape == null) {
41                  return null;
42              }
43  
44              Rectangle2D oldBounds = shape.getBounds2D();
45              float witdh = stroke.getLineWidth();
46  
47              // calcute a transformation for inside drawing
48              // based on the stroke width
49              AffineTransform at = new AffineTransform();
50              if (oldBounds.getWidth() > 0) {
51                  at.scale(
52                      (oldBounds.getWidth() - witdh) /
53                          oldBounds.getWidth(), 1);
54              }
55  
56              if (oldBounds.getHeight() > 0) {
57                  at.scale(1,
58                      (oldBounds.getHeight() - witdh)
59                          / oldBounds.getHeight());
60              }
61  
62              // recalculate shape and its oldBounds
63              shape = at.createTransformedShape(shape);
64              Rectangle2D newBounds = shape.getBounds2D();
65  
66              // move the shape to the old origin + the line width offset
67              AffineTransform moveBackTransform = AffineTransform.getTranslateInstance(
68                  oldBounds.getX() - newBounds.getX() + witdh / 2,
69                  oldBounds.getY() - newBounds.getY() + witdh / 2);
70              shape = moveBackTransform.createTransformedShape(shape);
71  
72              // outline the shape using the simple basic stroke
73              return stroke.createStrokedShape(shape);
74          }
75      }
76  
77      /**
78       * logger for all instances
79       */
80      private static final Logger logger = Logger.getLogger("org.freehep.graphicsio.emf");
81  
82      /**
83       * returns a BasicStroke JOIN for an EMF pen style
84       * @param penStyle penstyle
85       * @return e.g. {@link java.awt.BasicStroke#JOIN_MITER}
86       */
87      protected int getJoin(int penStyle) {
88          switch (penStyle & 0xF000) {
89              case EMFConstants.PS_JOIN_ROUND:
90                  return BasicStroke.JOIN_ROUND;
91              case EMFConstants.PS_JOIN_BEVEL:
92                  return BasicStroke.JOIN_BEVEL;
93              case EMFConstants.PS_JOIN_MITER:
94                  return BasicStroke.JOIN_MITER;
95              default:
96                  logger.warning("got unsupported pen style " + penStyle);
97                  return BasicStroke.JOIN_ROUND;
98          }
99      }
100 
101     /**
102      * returns a BasicStroke JOIN for an EMF pen style
103      * @param penStyle Style to convert
104      * @return asicStroke.CAP_ROUND, BasicStroke.CAP_SQUARE, BasicStroke.CAP_BUTT
105      */
106     protected int getCap(int penStyle) {
107         switch (penStyle & 0xF00) {
108             case EMFConstants.PS_ENDCAP_ROUND:
109                 return BasicStroke.CAP_ROUND;
110             case EMFConstants.PS_ENDCAP_SQUARE:
111                 return BasicStroke.CAP_SQUARE;
112             case EMFConstants.PS_ENDCAP_FLAT:
113                 return BasicStroke.CAP_BUTT;
114             default:
115                 logger.warning("got unsupported pen style " + penStyle);
116                 return BasicStroke.CAP_ROUND;
117         }
118     }
119 
120     /**
121      * returns a Dash for an EMF pen style
122      * @param penStyle Style to convert
123      * @param style used if EMFConstants#PS_USERSTYLE is set
124      * @return float[] representing a dash
125      */
126     protected float[] getDash(int penStyle, int[] style) {
127         switch (penStyle & 0xFF) {
128             case EMFConstants.PS_SOLID:
129                 // do not use float[] { 1 }
130                 // it's _slow_
131                 return null;
132             case EMFConstants.PS_DASH:
133                 return new float[] { 5, 5 };
134             case EMFConstants.PS_DOT:
135                 return new float[] { 1, 2 };
136             case EMFConstants.PS_DASHDOT:
137                 return new float[] { 5, 2, 1, 2 };
138             case EMFConstants.PS_DASHDOTDOT:
139                 return new float[] { 5, 2, 1, 2, 1, 2 };
140             case EMFConstants.PS_INSIDEFRAME:
141                 // Represents a pen style that consists of a solid
142                 // pen that is drawn from within any given bounding rectangle
143                 return null;
144             case EMFConstants.PS_NULL:
145                 // do not use float[] { 1 }
146                 // it's _slow_
147                 return null;
148             case EMFConstants.PS_USERSTYLE:
149                 if (style != null && style.length > 0) {
150                     float[] result = new float[style.length];
151                     for (int i = 0; i < style.length; i++) {
152                         result[i] = style[i];
153                     }
154                     return result;
155                 } else {
156                     return null;
157                 }
158             default:
159                 logger.warning("got unsupported pen style " + penStyle);
160                 // do not use float[] { 1 }
161                 // it's _slow_
162                 return null;
163         }
164     }
165 
166     /**
167      * @param penStyle stored pen style
168      * @return true if PS_INSIDEFRAME is set
169      */
170     private boolean isInsideFrameStroke(int penStyle) {
171         return (penStyle & 0xFF) == EMFConstants.PS_INSIDEFRAME;
172     }
173 
174     protected Stroke createStroke(
175         EMFRenderer renderer,
176         int penStyle,
177         int[] style,
178         float width) {
179 
180         if (isInsideFrameStroke(penStyle)) {
181             return new InsideFrameStroke(
182                 width,
183                 getCap(penStyle),
184                 getJoin(penStyle),
185                 renderer.getMeterLimit(),
186                 getDash(penStyle, style),
187                 0);
188         } else {
189             return new BasicStroke(
190                 width,
191                 getCap(penStyle),
192                 getJoin(penStyle),
193                 renderer.getMeterLimit(),
194                 getDash(penStyle, style),
195                 0);
196         }
197     }
198 }