Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/port80/graph/impl/ArrowFactory.java


1   //
2   // Copyright(c) 2002, Chris Leung
3   //
4   
5   package com.port80.graph.impl;
6   
7   import java.awt.Color;
8   import java.awt.geom.*;
9   import java.util.*;
10  import com.port80.util.*;
11  import com.port80.util.attr.*;
12  import com.port80.util.struct.*;
13  import com.port80.graph.*;
14  
15  /** Arrow factory.
16   *
17   *  Arrow factory provides a named collection of of stock Arrow object
18   *  templates.  Each template is parameterized by the leadinWidth,
19   *  which determines the leadin shape.  Default templates have
20   *  leadinWidth=1.0f.
21   *
22   *  The template produced have default colors from the Arrow class.
23   *  Typically client have to set the appropriate attributes for the
24   *  Arrow template and render it into an BufferedImage and then
25   *  applied AffineTransform and composition to merge the rendered
26   *  image to client area.
27   *
28   *  //FIXME:
29   *  . Scale square down to 1/sqrt(2) with leadin.
30   */
31  public class ArrowFactory implements IAttrFactory {
32  
33    ////////////////////////////////////////////////////////////////////////
34  
35    private static final String NAME = "ArrowFactory";
36    private static ArrowFactory instance = null;
37  
38    public static final int ARROW_NONE = 0;
39    public static final int ARROW_NORMAL = 1;
40    public static final int ARROW_INVERT = 2;
41    public static final int ARROW_DOT = 3;
42    public static final int ARROW_ODOT = 4;
43    public static final int ARROW_INVDOT = 5;
44    public static final int ARROW_INVODOT = 6;
45  
46    private static Map table;
47    private static final float SQRT2 = (float) Math.sqrt(2.0);
48    private static final float H = 12f;
49    private static final float LW = 1f;
50    static {
51      table = new HashMap();
52      table.put("none",null);
53      table.put("hide",null);
54      stockNormal("default", 1, 1, LW, LW);
55      stockNormal("normal", 1, 1, LW, LW);
56      stockLine("line", 1, 1, LW, LW);
57      stockDoubleLine("doubleline", 1, 1, LW, LW);
58      //
59      stockTriangle("otriangle", 1, 1, LW, LW);
60      stockSpear("ospear", 1, 1, LW, LW);
61      stockDot("odot", 1, 1, LW, LW);
62      stockDiamond("odiamond", 1, 1, LW, LW);
63      stockSquare("osquare", 1, 1, LW, LW);
64      //
65      stockTriangle("triangle", 1, 1, LW, 0f);
66      stockSpear("spear", 1, 1, LW, 0f);
67      stockDot("dot", 1, 1, LW, 0f);
68      stockDiamond("diamond", 1, 1, LW, 0f);
69      stockSquare("square", 1, 1, LW, 0f);
70    }
71  
72    ////////////////////////////////////////////////////////////////////////
73  
74    public static ArrowFactory getInstance() {
75      if (instance == null)
76        instance = new ArrowFactory();
77      return instance;
78    }
79    /** String format:
80     *  stockname
81     *  | typename,height
82     *  | typename,height,linewidth
83     *  | typename,height,width,linewidth
84     *  | typename,height,width,linewidth,leadinwidth
85     */
86    public static Arrow create(String stringvalue) {
87      if(table.containsKey(stringvalue)) {
88        return (Arrow) table.get(stringvalue);
89      }
90      // Custom.
91      int index = stringvalue.indexOf(',');
92      float leadinwidth = 1f;
93      float linewidth = 0f;
94      float w = 1f;
95      float h = 1f;
96      if (index > 0) {
97        String name = stringvalue.substring(0, index);
98        index = msg.skipWS(stringvalue, ++index, stringvalue.length());
99        FloatList f = msg.parseFloats(stringvalue.substring(index));
100       if (f.size() == 1) {
101         h = f.get(0) / H;
102         w = h;
103       } else if (f.size() == 2) {
104         h = f.get(0) / H;
105         w = h;
106         linewidth=f.get(1);
107       } else if (f.size() == 3) {
108         h = f.get(0) / H;
109         w = f.get(1) / H;
110         linewidth = f.get(2);
111       } else if (f.size() == 4) {
112         h = f.get(0) / H;
113         w = f.get(1) / H;
114         linewidth = f.get(2);
115         leadinwidth = f.get(3);
116       } else {
117         index = -1;
118       }
119       if (index > 0) {
120         if (name.equals("line"))
121           return stockLine(stringvalue, w, h, leadinwidth, linewidth);
122         if (name.equals("dot"))
123           return stockDot(stringvalue, w, h, leadinwidth, linewidth);
124         if (name.equals("triangle"))
125           return stockTriangle(stringvalue, w, h, leadinwidth, linewidth);
126         if (name.equals("square"))
127           return stockSquare(stringvalue, w, h, leadinwidth, linewidth);
128         if (name.equals("diamond"))
129           return stockDiamond(stringvalue, w, h, leadinwidth, linewidth);
130         if (name.equals("spear"))
131           return stockSpear(stringvalue, w, h, leadinwidth, linewidth);
132         if (name.equals("doubleline"))
133           return stockDoubleLine(stringvalue, w, h, leadinwidth, linewidth);
134         //
135         if (name.equals("odot"))
136           return stockDot(stringvalue, w, h, leadinwidth, linewidth==0? 1f: linewidth);
137         if (name.equals("otriangle"))
138           return stockTriangle(stringvalue, w, h, leadinwidth, linewidth==0? 1f: linewidth);
139         if (name.equals("osquare"))
140           return stockSquare(stringvalue, w, h, leadinwidth, linewidth==0? 1f: linewidth);
141         if (name.equals("odiamond"))
142           return stockDiamond(stringvalue, w, h, leadinwidth, linewidth==0? 1f: linewidth);
143         if (name.equals("ospear"))
144           return stockSpear(stringvalue, w, h, leadinwidth, linewidth==0? 1f: linewidth);
145       }
146     }
147     msg.err(
148       NAME
149         + ".create(String): invalid arrow spec, : "
150         + stringvalue
151         + "\n\t Expected format: type,height | type,height,width | type,height,width,linewidth | height,width,linewidth,leadwidth");
152     return (Arrow) table.get("normal");
153   }
154   private ArrowFactory() {}
155 
156   ////////////////////////////////////////////////////////////////////////
157 
158   /** Convert String representation of an attribute value to the
159    *  appropriate object for storing in AttrTable.
160    */
161   public Object createObject(String str) {
162     return create(str);
163   }
164 
165   public boolean isValid(Object a) {
166     return (a instanceof Arrow);
167   }
168   
169   /** The String representation of an attribute value. */
170   public String toString(Object attr) {
171     Arrow a = (Arrow) attr;
172     return a.getName();
173   }
174 
175   /** The String representation of attribute type itself. */
176   public String toString() {
177     return NAME;
178   }
179 
180   /** Prompt user and present a user interface to obtain an
181    *  attribute value from user. */
182   public Object promptUser(String prompt) {
183     return null;
184   }
185 
186   // Stock arrow shapes //////////////////////////////////////////////////
187   //
188 
189   /** These stock shapes are scaled and positioned to make drawing of
190    *  arrows easier.
191    *
192    *  . Origin (0,0) is always at the tail connection point of the
193    *    arrow so rotation of the arrow should keep the tail connection
194    *    point unchanged.
195    *
196    *  . Each arrow is consist of two parts, the arrow shape and a
197    *    lead-in shape.  The bounding box for the whole arrow is alway
198    *    a unit square.
199    *
200    *  . Stroke line width and color of the arrow outline and the
201    *    leadin line are independently, so the lead-in line width can
202    *    be adjusted to match the incoming line width.  There are 2
203    *    parameters for each stock arrow template:
204    *
205    *  lineWidth,leadinWidth
206    */
207 
208   /** Line arrow with same line width for leadin and arrow head.*/
209   private static Arrow stockNormal(String name, float w, float h, float leadinwidth, float linewidth) {
210     GeneralPath p = new GeneralPath();
211     h *= H;
212     w *= H/2;
213     float hw = w / 2f;
214     float dw = linewidth / 2f;
215     p.moveTo(0, -hw);
216     p.lineTo(h - dw, 0);
217     p.lineTo(0, hw);
218     p.moveTo(h - dw, 0);
219     p.lineTo(0, 0);
220     Arrow ret = new Arrow(name, p, null, linewidth);
221     table.put(name, ret);
222     return ret;
223   }
224 
225   /** A triangle inside a unit square.
226    */
227   private static Arrow stockTriangle(String name, float w, float h, float leadinwidth, float linewidth) {
228     GeneralPath p = new GeneralPath();
229     h *= H;
230     w *= H/2;
231     float dw = linewidth / 2f;
232     float hw = w / 2f;
233     p.moveTo(0,0);
234     p.moveTo(dw, -hw);
235     p.lineTo(h - dw, 0);
236     p.lineTo(dw, hw);
237     p.closePath();
238     Arrow ret = new Arrow(name, p, null, linewidth);
239     table.put(name, ret);
240     return ret;
241   }
242 
243   /** A unit square. */
244   private static Arrow stockSquare(String name, float w, float h, float leadinwidth, float linewidth) {
245     GeneralPath p = new GeneralPath();
246     h *= H / SQRT2;
247     w *= H / SQRT2;
248     float hw = w / 2f;
249     float dw = linewidth / 2f;
250     p.moveTo(0,0);
251     p.moveTo(dw, -hw + dw);
252     p.lineTo(h - dw, -hw + dw);
253     p.lineTo(h - dw, hw - dw);
254     p.lineTo(dw, hw - dw);
255     p.lineTo(dw, -hw + dw);
256     Arrow ret = new Arrow(name, p, null, linewidth);
257     table.put(name, ret);
258     return ret;
259   }
260 
261   /** A diamond shape. */
262   private static Arrow stockDiamond(String name, float w, float h, float leadinwidth, float linewidth) {
263     GeneralPath p = new GeneralPath();
264     h *= H;
265     w *= H;
266     float hw = w / 2f;
267     float hh = h / 2f;
268     float dw = linewidth / 2f;
269     p.moveTo(0,0);
270     p.moveTo(dw, 0);
271     p.lineTo(hw, -hh + dw);
272     p.lineTo(h - dw, 0);
273     p.lineTo(hw, hh - dw);
274     p.closePath();
275     /*
276     GeneralPath pin=new GeneralPath(); 
277     hw=leadinwidth/2f;
278     pin.moveTo(-hw,0f);
279     pin.lineTo(hw,0f);
280     pin.lineTo(hw,hw);
281     pin.lineTo(0f,0f);
282     pin.lineTo(-hw,hw);
283     pin.closePath();
284     */
285     Arrow ret = new Arrow(name, p, null, linewidth);
286     table.put(name, ret);
287     return ret;
288   }
289 
290   /** A circle. */
291   private static Arrow stockDot(String name, float w, float h, float leadinwidth, float linewidth) {
292     // Approximate a cirle by cubic curves.
293     h *= H;
294     w *= H;
295     float dw = linewidth / 2f;
296     float hw = w / 2f;
297     Ellipse2D p = new Ellipse2D.Float(dw, -hw + dw, w - linewidth, h - linewidth);
298     /*
299       GeneralPath p=new GeneralPath();
300       float hw=w/2;
301       float hh=h/2;
302       float l=linewidth;
303       float dw=linewidth/2;
304       //FIXME: Offsets are not quite right.
305       p.moveTo(hw-dw,hh);
306       p.curveTo(hw-dw,hh+0.27614236f*(h-l),  0.2761424f*(w-l),h-dw,  0f,h-dw);
307       p.curveTo(-0.2761424f*(w-l),h-dw,  -hw+dw,hh+0.27614236f*(h-dw),  -hw+dw,hh);
308       p.curveTo(-hw+dw,dw+0.22385763f*(h-l),  -0.2761424f*(w-l),dw,  0.0f,dw);
309       p.curveTo(0.2761424f*(w-l),dw,  hw-dw,dw+0.22385763f*(h-l),  hw-dw,hh);
310       p.closePath();
311     */
312     Arrow ret = new Arrow(name, p,
313       //FIXME: leadin is arc.
314   null, linewidth);
315     table.put(name, ret);
316     return ret;
317   }
318 
319   /** An spear shape stock. */
320   private static Arrow stockSpear(String name, float w, float h, float leadinwidth, float linewidth) {
321     GeneralPath p = new GeneralPath();
322     h *= H;
323     w *= H/2;
324     float hw = w / 2f;
325     float dw = linewidth / 2;
326     p.moveTo(0,0);
327     p.moveTo(0, -hw);
328     p.lineTo(h - dw, 0);
329     p.lineTo(0, hw);
330     p.lineTo(h / 4f, 0);
331     p.closePath();
332     GeneralPath pin = new GeneralPath();
333     hw = leadinwidth / 2f;
334     pin.moveTo(0, -hw);
335     pin.lineTo(h / 4f - (hw / 2f), -hw);
336     pin.lineTo(h / 4f, 0);
337     pin.lineTo(h / 4f - (hw / 2f), hw);
338     pin.lineTo(0, hw);
339     pin.closePath();
340     Arrow ret = new Arrow(name, p, pin, linewidth);
341     table.put(name, ret);
342     return ret;
343   }
344 
345   /** Arrow by line only. */
346   private static Arrow stockLine(String name, float w, float h, float leadinwidth, float linewidth) {
347     if (linewidth <= 0) 
348       linewidth = 1f;
349     GeneralPath p = new GeneralPath();
350     h *= H;
351     w *= H/2;
352     float hh = h / 2f;
353     float hw = w / 2f;
354     float dw = linewidth / 2f;
355     p.moveTo(0,0);
356     p.moveTo(hh - dw, -hw);
357     p.lineTo(h - dw, 0);
358     p.lineTo(hh - dw, hw);
359     GeneralPath pin = new GeneralPath();
360     hw = leadinwidth / 2f;
361     pin.moveTo(0, -hw);
362     pin.lineTo(h - dw - hw, -hw);
363     pin.lineTo(h - dw, 0);
364     pin.lineTo(h - dw - hw, hw);
365     pin.lineTo(0, hw);
366     pin.closePath();
367     Arrow ret = new Arrow(name, p, pin, linewidth);
368     table.put(name, ret);
369     return ret;
370   }
371 
372   /** Double arrow by line only. */
373   private static Arrow stockDoubleLine(String name, float w, float h, float leadinwidth, float linewidth) {
374     if (linewidth <= 0) 
375       linewidth = 1f;
376     GeneralPath p = new GeneralPath();
377     h *= H;
378     w *= H/2;
379     float hw = w / 2f;
380     float hh = h / 2f;
381     float dw = linewidth / 2f;
382     p.moveTo(0,0);
383     p.moveTo(hh - dw, -hw);
384     p.lineTo(h - dw, 0);
385     p.lineTo(hh - dw, hw);
386     p.moveTo(0, hw);
387     p.lineTo(hh - dw, 0);
388     p.lineTo(0, -hw);
389     GeneralPath pin = new GeneralPath();
390     hw = leadinwidth / 2f;
391     pin.moveTo(0, -hw);
392     pin.lineTo(hh - dw - hw, -hw);
393     pin.lineTo(hh - dw, 0);
394     pin.lineTo(hh - dw - hw, hw);
395     pin.lineTo(0, hw);
396     pin.closePath();
397     Arrow ret = new Arrow(name, p, pin, linewidth);
398     table.put(name, ret);
399     return ret;
400   }
401 
402   ////////////////////////////////////////////////////////////////////////
403 }