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.awt.image.*;
9    
10   public class SegBoundary extends Polygon implements Dragable {
11     private static final long serialVersionUID = -3767939017774524461L;
12     protected transient int select = 0;
13   
14     protected transient int oldx = 0;
15     protected transient int oldy = 0;
16     transient Graphics draggraphics = null;
17   
18     public SaveablePoint[] mapped = null;
19   
20     public SegBoundary() {
21       super();
22     }
23   
24     private void readObject(java.io.ObjectInputStream stream)
25         throws java.io.IOException,java.lang.ClassNotFoundException {
26       stream.defaultReadObject();
27       bounds = null;
28     }
29   
30     private double[] getUnit(int i,int offset) {
31       double[] res = new double[2];
32       res[0] = xpoints[(i+offset+npoints)%npoints]-xpoints[i%npoints];
33       res[1] = ypoints[(i+offset+npoints)%npoints]-ypoints[i%npoints];
34       double mag = Math.sqrt(res[0]*res[0]+res[1]*res[1]);
35       res[0] /= mag;
36       res[1] /= mag;
37       return(res);
38     }
39   
40     public void locate(Object what,int x,int y){
41       if (npoints<3) addPoint(x,y);
42       else {
43         int mini = -1;
44         double mindist = 10000000000.0;
45         double[] l,r;
46         double dir,olddir=1,dist=0;
47         l = getUnit(0,-1);
48         for (int i=0;i<npoints+1;i++) {
49           r = getUnit(i,1);
50           l[0] -= r[0];
51           l[1] -= r[1];
52           dir = l[0]*(x-xpoints[i%npoints]) + l[1]*(y-ypoints[i%npoints]);
53   //        System.out.println("seg "+i+" olddir = "+olddir+" dir = "+dir);
54           if (dir>0 && olddir<0) {
55             double x0 = xpoints[(i-1)%npoints];
56             double y0 = ypoints[(i-1)%npoints];
57             double x1 = xpoints[i%npoints];
58             double y1 = ypoints[i%npoints];
59             dist = (x*(y0-y1) + y*(x1-x0) +x0*y1 - y0*x1)/Math.sqrt((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1));
60             if (dist<0) dist = -dist;
61   //          System.out.println("segment "+(i-1)+" dist = "+dist);
62   
63             if (mini == -1 || dist<mindist) {
64               mini = i-1;
65               mindist = dist;
66             }
67           }
68           olddir = dir;
69           l[0] = -r[0];
70           l[1] = -r[1];
71         }
72   //      System.out.println("adding after "+mini+" of = "+npoints);
73         addPoint(xpoints[npoints-1],ypoints[npoints-1]);
74         for (int j = npoints-3; j>mini;j--) {
75           xpoints[j+1] = xpoints[j];
76           ypoints[j+1] = ypoints[j];
77         }
78         xpoints[mini+1] = x;
79         ypoints[mini+1] = y;
80   
81         bounds = null;
82       }
83   //    System.out.println("npoints = "+npoints);
84   //    for (int k = 0; k<npoints;k++) {
85   //      System.out.println(" "+k+" - ("+xpoints[k]+","+ypoints[k]+")");
86   //    }
87   //    calculateBounds(xpoints,ypoints,npoints);
88       mapped = null;
89     }
90   
91     public void fix(){
92       draggraphics =null;
93       bounds = null;
94       mapped = null;
95     }
96   
97     public void map(Mapping map) {
98       mapped = new SaveablePoint[npoints];
99       Point2D.Double pos = new Point2D.Double();
100      for (int i = 0; i<npoints;i++) {
101        mapped[i] = new SaveablePoint();
102        pos.setLocation((double)xpoints[i],(double)ypoints[i]);
103        map.ftrans(pos,mapped[i]);
104      }
105    }
106  
107  /*
108    public SegBoundary transform(AffineTransform trans,Mapping map) { 
109      SegBoundary viewborder = new SegBoundary();
110      Point2D.Double pos = new Point2D.Double();
111      Point2D.Double res = new Point2D.Double();
112      for (int i = 0; i<npoints;i++) {
113        pos.setLocation((double)xpoints[i],(double)ypoints[i]);
114        trans.transform(map.ftrans(pos,res),pos);
115        viewborder.addPoint((int)pos.getX(),(int)pos.getY());
116      }
117      return(viewborder);
118    }
119  */
120    public void delete() {
121      if (draggraphics==null) return;
122      for (int i=select;i<npoints-1;i++) {
123        xpoints[i] = xpoints[i+1];
124        ypoints[i] = ypoints[i+1];
125      }
126      npoints--;
127      bounds = null;
128      mapped = null;
129  //    calculateBounds(xpoints,ypoints,npoints);
130    }
131  
132    public void move(int x,int y){
133      if (draggraphics==null) return;
134  
135      drawPoint();
136  
137      xpoints[select] += x - oldx;
138      ypoints[select] += y - oldy;
139  
140      drawPoint();
141  
142      oldx = x;
143      oldy = y;
144      mapped = null;
145    }
146  
147    void drawPoint() {
148      if (npoints>0){
149        draggraphics.drawLine(xpoints[(select-1+npoints)%npoints],ypoints[(select-1+npoints)%npoints],
150          		    xpoints[select],ypoints[select]);
151        draggraphics.drawLine(xpoints[(select+1)%npoints],ypoints[(select+1)%npoints],
152          		    xpoints[select],ypoints[select]);
153      }
154    }
155  
156    public boolean select(int x,int y, java.awt.Graphics g){
157  
158      if (npoints==0) return(false);
159  
160      int i;
161      float mindist = ((float)x-xpoints[0])*(x-xpoints[0]) + ((float)y-ypoints[0])*(y-ypoints[0]);
162      float dist;
163      select = 0;
164      for (i=0;i<npoints;i++) {
165        dist = ((float)x-xpoints[i])*(x-xpoints[i]) + ((float)y-ypoints[i])*(y-ypoints[i]);
166        if (dist<mindist) {
167          mindist = dist;
168          select = i;
169        }
170      }
171  
172      oldx = x;
173      oldy = y;
174  
175      draggraphics = g;
176      g.setXORMode(java.awt.Color.white);
177  
178      return(true);
179    }
180  
181  /* This is just the normal definition (from the sdk) with the first
182     three lines hacked to avoid the gratuitous cloning of bounds
183     (which can be very time consuming).
184  */
185    public boolean contains(double x, double y) {
186      if (npoints <= 2) return(false);
187      if (bounds==null) getBounds();
188      if(!bounds.contains(x, y))
189        return false;
190      
191      int hits = 0;
192  
193      int lastx = xpoints[npoints - 1];
194      int lasty = ypoints[npoints - 1];
195      int curx, cury;
196  
197      // Walk the edges of the polygon
198      for (int i = 0; i < npoints; lastx = curx, lasty = cury, i++) {
199        curx = xpoints[i];
200        cury = ypoints[i];
201              
202        if (cury == lasty) {
203          continue;
204        }
205  
206        int leftx;
207        if (curx < lastx) {
208          if (x >= lastx) {
209            continue;
210          }
211          leftx = curx;
212        } else {
213          if (x >= curx) {
214            continue;
215          }
216          leftx = lastx;
217        }
218  
219        double test1, test2;
220        if (cury < lasty) {
221          if (y < cury || y >= lasty) {
222            continue;
223          }
224          if (x < leftx) {
225            hits++;
226            continue;
227          }
228          test1 = x - curx;
229          test2 = y - cury;
230        } else {
231          if (y < lasty || y >= cury) {
232            continue;
233          }
234          if (x < leftx) {
235            hits++;
236            continue;
237          }
238          test1 = x - lastx;
239          test2 = y - lasty;
240        }
241        
242        if (test1 < (test2 / (lasty - cury) * (lastx - curx))) {
243          hits++;
244        }
245      }
246  
247      return ((hits & 1) != 0);
248    }
249  }
250  
251  
252