1    /*
2    Copyright 2000 by Ralph Hartley
3    This software is licenced under the terms of the
4    Gnu Public Licence
5    */
6    import java.awt.*;
7    import java.awt.geom.*;
8    import java.util.*;
9    
10   
11   public abstract class TickedStroke extends SavableStroke {
12     static double tol  = 0.5;
13   
14     static int PENDOWN = 1;
15     static int PENUP = 2;
16     static int LEFT = 4;
17     static int RIGHT = 8;
18   
19     public double thickness;
20     public double ticklength;
21     int flip = 1;
22   
23     double[] lengths;
24     int[] actions;
25     int partcnt;
26   
27     public TickedStroke(double thickness) {
28       super(thickness);
29     }
30   
31     Vector heads = new Vector();
32     Vector tails = new Vector();
33   
34     public void setFlip(boolean val) {
35       if (val) flip = -1;
36       else flip = 1;
37     }
38   
39     public Shape createStrokedShape(Shape p) {
40         //System.out.println("shape = "+p);
41       PathIterator path = p.getPathIterator(new AffineTransform(),tol);
42       GeneralPath res = new GeneralPath();
43   
44       //System.out.println("res = "+res+" path = "+path);
45   
46       double[] points;// = null;
47       double[] current = null;
48       int type;
49       double[] start = null;
50   
51       heads.clear();
52       tails.clear();
53   
54       double dist;
55   
56       double[] anchor;
57       double[] end;
58   
59       int curpart = 0;
60       double phase = lengths[0];
61       boolean pendown = true;
62   
63       //System.out.println("path "+path);
64       for (;!path.isDone();path.next()) {
65           //System.out.println("done= "+path.isDone());
66         points = new double[2];
67         type = path.currentSegment(points);
68         //System.out.println("Segment "+type);
69         switch (type) {
70         case PathIterator.SEG_MOVETO:
71             res.moveTo((float)points[0],(float)points[1]);
72             start = points;
73             current = points;
74             break;
75         case PathIterator.SEG_CLOSE:
76             points = start;
77         case PathIterator.SEG_LINETO:
78             dist = Math.sqrt((points[0]-current[0])*(points[0]-current[0]) +
79                             (points[1]-current[1])*(points[1]-current[1]));
80             while (phase < dist) {
81               anchor = new double[2];
82               anchor[0] = current[0] + phase*(points[0]-current[0])/dist;
83               anchor[1] = current[1] + phase*(points[1]-current[1])/dist;
84   
85               if (pendown)
86                 res.lineTo((float)anchor[0],(float)anchor[1]);
87               else if ((actions[curpart]&PENDOWN) !=0)
88                 res.moveTo((float)anchor[0],(float)anchor[1]);
89               if ((actions[curpart]&PENDOWN) !=0) pendown = true;
90               if ((actions[curpart]&PENUP) !=0) pendown = false;
91   
92               if ((actions[curpart]&(LEFT|RIGHT)) !=0) {
93                 if((actions[curpart]&LEFT) !=0) {
94                   end = new double[2];
95                   end[0] = anchor[0] - flip*ticklength*(points[1]-current[1])/dist;
96                   end[1] = anchor[1] + flip*ticklength*(points[0]-current[0])/dist;
97           	heads.add(end);
98                 } else heads.add(anchor);
99                 if((actions[curpart]&RIGHT) !=0) {
100                  end = new double[2];
101                  end[0] = anchor[0] + flip*ticklength*(points[1]-current[1])/dist;
102                  end[1] = anchor[1] - flip*ticklength*(points[0]-current[0])/dist;
103          	tails.add(end);
104                } else tails.add(anchor);
105              }
106  
107                    dist -= phase;
108              curpart = (curpart+1)%partcnt;
109              phase = lengths[curpart];
110              current = anchor;
111            }
112            //System.out.println("backbone done");
113  
114            if (dist>0) {
115                //if (type==PathIterator.SEG_CLOSE) res.closePath();
116              // else
117              if (pendown)
118                res.lineTo((float)points[0],(float)points[1]);
119              //	    else
120              //  res.moveTo((float)points[0],(float)points[1]);
121              phase -= dist;
122              current = points;
123                  }
124        }
125      }
126      
127      for (int i=0;i<heads.size();i++) {
128        res.moveTo((float)((double[])heads.elementAt(i))[0],(float)((double[])heads.elementAt(i))[1]);
129        res.lineTo((float)((double[])tails.elementAt(i))[0],(float)((double[])tails.elementAt(i))[1]);
130      }
131  
132      return(linestroke.createStrokedShape(res));
133    }
134  }
135