Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / edition / UtilFunctions.java @ 6187

History | View | Annotate | Download (16.9 KB)

1 1430 fjp
/*
2
 * Created on 10-feb-2005
3
 *
4
 * gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
5 3748 caballero
 *
6 1430 fjp
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
7 3748 caballero
 *
8 1430 fjp
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License
10
 * as published by the Free Software Foundation; either version 2
11
 * of the License, or (at your option) any later version.
12 3748 caballero
 *
13 1430 fjp
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17 3748 caballero
 *
18 1430 fjp
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 3748 caballero
 *
22 1430 fjp
 * For more information, contact:
23
 *
24
 *  Generalitat Valenciana
25
 *   Conselleria d'Infraestructures i Transport
26
 *   Av. Blasco Ib??ez, 50
27
 *   46010 VALENCIA
28
 *   SPAIN
29
 *
30
 *      +34 963862235
31
 *   gvsig@gva.es
32
 *      www.gvsig.gva.es
33 3748 caballero
 *
34 1430 fjp
 *    or
35 3748 caballero
 *
36 1430 fjp
 *   IVER T.I. S.A
37
 *   Salamanca 50
38
 *   46005 Valencia
39
 *   Spain
40 3748 caballero
 *
41 1430 fjp
 *   +34 963163400
42
 *   dac@iver.es
43
 */
44
package com.iver.cit.gvsig.fmap.edition;
45
46 3904 fjp
import java.awt.geom.AffineTransform;
47 1430 fjp
import java.awt.geom.Arc2D;
48
import java.awt.geom.Point2D;
49
import java.awt.geom.Rectangle2D;
50
51 3904 fjp
import com.iver.cit.gvsig.fmap.core.IGeometry;
52 3768 caballero
import com.vividsolutions.jts.algorithm.RobustCGAlgorithms;
53
import com.vividsolutions.jts.geom.Coordinate;
54
55 1430 fjp
/**
56
 * @author FJP
57
 *
58
 * TODO To change the template for this generated type comment go to
59
 * Window - Preferences - Java - Code Generation - Code and Comments
60
 */
61
public class UtilFunctions {
62
    static public Arc2D createCircle(Point2D p1, Point2D p2, Point2D p3) //, Graphics g)
63
    {
64
        double xC, yC, w, h;
65 3748 caballero
66 1430 fjp
        // Calculamos 2 secantes, tiramos perpendiculares por sus puntos
67
        // medios y obtenemos el centro. Luego calculamos el radio.
68
        // Puntos medios de los segmentos.
69
        double xm1, ym1, xm2, ym2;
70
        xm1 = (p1.getX() + p2.getX())/ 2.0;
71
        ym1 = (p1.getY() + p2.getY())/ 2.0;
72 3748 caballero
        xm2 = (p2.getX() + p3.getX())/ 2.0;
73 1430 fjp
        ym2 = (p2.getY() + p3.getY())/ 2.0;
74 3748 caballero
75 1430 fjp
        /* g.setColor(Color.GRAY);
76
        g.draw3DRect((int)xm1, (int) ym1, 1, 1, true);
77
        g.draw3DRect((int)xm2, (int) ym2, 1, 1, true); */
78 3748 caballero
        // Pendientes de las perpendiculares y constantes
79 1430 fjp
        double mP1=0, mP2=0, A1, A2;
80
        boolean bPerp1 = false, bPerp2 = false;
81
        if (p2.getY() - p1.getY() == 0)
82
        {
83
            A1 = ym1;
84
            bPerp1 = true;
85
        }
86
        else
87
        {
88
            mP1 = (p2.getX() - p1.getX()) /(p1.getY() - p2.getY());
89
            A1 = ym1 - xm1 * mP1;
90
        }
91
        if (p2.getY() - p3.getY() == 0)
92
        {
93
            A2 = ym2;
94
            bPerp2 = true;
95
        }
96
        else
97
        {
98
            mP2 = (p3.getX() - p2.getX()) /(p2.getY() - p3.getY());
99 3748 caballero
            A2 = ym2 - xm2 * mP2;
100 1430 fjp
        }
101
        if (mP2 == mP1)
102
        {
103
            return null; // Error, 3 puntos alineados. No puede pasar un arco
104
        }
105
        else
106
        {
107
            xC = (A2 - A1)/(mP1-mP2);
108
            if (!bPerp1)
109
                yC = xC * mP1 + A1;
110 3748 caballero
            else
111 1430 fjp
                yC = xC * mP2 + A2;
112
        }
113
        double Radio = p1.distance(xC, yC);
114
        double xR = xC - Radio ;
115
        double yR = yC - Radio ;
116
        w = 2.0* Radio;
117
        h = w;
118
        Rectangle2D.Double rBounds = new Rectangle2D.Double(xR,yR, w,h);
119
        Arc2D.Double resul = new Arc2D.Double(rBounds, 0.0, 360.0, Arc2D.OPEN);
120
                /* g.setColor(Color.RED);
121
                ((Graphics2D) g).draw(resul);
122
                g.setColor(Color.BLUE);
123
                ((Graphics2D) g).draw(rBounds);
124
                g.draw3DRect((int)p1.getX(), (int) p1.getY(), 1, 1, true);
125
                g.draw3DRect((int)p2.getX(), (int) p2.getY(), 2, 2, true);
126
                g.draw3DRect((int)p3.getX(), (int) p3.getY(), 1, 1, true);
127
                g.drawString("1", (int) p1.getX(), (int) p1.getY());
128
                g.drawString("2", (int) p2.getX(), (int) p2.getY());
129
                g.drawString("3", (int) p3.getX(), (int) p3.getY());
130
                g.drawString("C", (int) xC, (int) yC);
131
                g.draw3DRect((int)xC, (int) yC, 2, 2, true); */
132 3748 caballero
133 1430 fjp
        return resul;
134
    }
135 3748 caballero
    /**
136
         * Obtiene un par de puntos que definen la recta perpendicular a p1-p2 que
137
         * pasa por el punto perp
138
         *
139
         * @param p1 punto de la recta p1-p2
140
         * @param p2 punto de la recta p1-p2
141
         * @param perp Punto por el que pasa la recta perpendicular, debe ser
142
         *                   distinto a p2
143
         *
144
         * @return Array con dos puntos que definen la recta resultante
145
         */
146
        public static Point2D[] getPerpendicular(Point2D p1, Point2D p2,
147
                Point2D perp) {
148
                if ((p2.getY() - p1.getY()) == 0) {
149
                        return new Point2D[] {
150
                                new Point2D.Double(perp.getX(), 0),
151
                                new Point2D.Double(perp.getX(), 1)
152
                        };
153
                }
154 1430 fjp
155 3748 caballero
                //Pendiente de la recta perpendicular
156
                double m = (p1.getX() - p2.getX()) / (p2.getY() - p1.getY());
157
158
                //b de la funcion de la recta perpendicular
159
                double b = perp.getY() - (m * perp.getX());
160
161
                //Obtenemos un par de puntos
162
                Point2D[] res = new Point2D[2];
163
164
                res[0] = new Point2D.Double(0, (m * 0) + b);
165
                res[1] = new Point2D.Double(1000, (m * 1000) + b);
166
167
                return res;
168
        }
169
        /**
170
         * Obtiene el punto que se encuentra a una distancia 'dist' de la recta
171
         * p1-p2 y se encuentra en la recta perpendicular que pasa por perpPoint
172
         *
173
         * @param p1 Punto de la recta p1-p2
174
         * @param p2 Punto de la recta p1-p2
175
         * @param perpPoint Punto de la recta perpendicular
176
         * @param dist Distancia del punto que se quiere obtener a la recta p1-p2
177
         *
178
         * @return DOCUMENT ME!
179
         */
180
        public static Point2D getPerpendicularPoint(Point2D p1, Point2D p2,
181
                Point2D perpPoint, double dist) {
182
                Point2D[] p = getPerpendicular(p1, p2, perpPoint);
183
                Point2D unit = getUnitVector(p[0], p[1]);
184
185
                return new Point2D.Double(perpPoint.getX() + (unit.getX() * dist),
186
                        perpPoint.getY() + (unit.getY() * dist));
187
        }
188
189
        /**
190
         * Devuelve un vector unitario en forma de punto a partir de dos puntos.
191
         *
192
         * @param p1 punto origen.
193
         * @param p2 punto destino.
194
         *
195
         * @return vector unitario.
196
         */
197
        public static Point2D getUnitVector(Point2D p1, Point2D p2) {
198
                Point2D paux = new Point2D.Double(p2.getX() - p1.getX(),
199
                                p2.getY() - p1.getY());
200
                double v = Math.sqrt(Math.pow((double) paux.getX(), (double) 2) +
201
                                Math.pow((double) paux.getY(), (double) 2));
202
                paux = new Point2D.Double(paux.getX() / v, paux.getY() / v);
203
204
                return paux;
205
        }
206
        /**
207
         * Obtiene el centro del c?rculo que pasa por los tres puntos que se pasan
208
         * como  par?metro
209
         *
210
         * @param p1 primer punto del c?rculo cuyo centro se quiere obtener
211
         * @param p2 segundo punto del c?rculo cuyo centro se quiere obtener
212
         * @param p3 tercer punto del c?rculo cuyo centro se quiere obtener
213
         *
214
         * @return Devuelve null si los puntos est?n alineados o no son 3 puntos
215
         *                    distintos
216
         */
217
        public static Point2D getCenter(Point2D p1, Point2D p2, Point2D p3) {
218
                if (p1.equals(p2) || p2.equals(p3) || p1.equals(p3)) {
219
                        return null;
220
                }
221
222
                Point2D[] perp1 = getPerpendicular(p1, p2,
223
                                new Point2D.Double((p1.getX() + p2.getX()) / 2,
224
                                        (p1.getY() + p2.getY()) / 2));
225
                Point2D[] perp2 = getPerpendicular(p2, p3,
226
                                new Point2D.Double((p2.getX() + p3.getX()) / 2,
227
                                        (p2.getY() + p3.getY()) / 2));
228
229
                return getIntersection(perp1[0], perp1[1], perp2[0], perp2[1]);
230
        }
231
        /**
232
         * Devuelve el punto de la intersecci?n entre las lineas p1-p2 y p3-p4.
233
         *
234
         * @param p1 punto de la recta p1-p2
235
         * @param p2 punto de la recta p1-p2
236
         * @param p3 punto de la recta p3-p4
237
         * @param p4 punto de la recta p3-p4
238
         *
239
         * @return DOCUMENT ME!
240
         *
241
         * @throws RuntimeException DOCUMENT ME!
242
         */
243
        public static Point2D getIntersection(Point2D p1, Point2D p2, Point2D p3,
244
                Point2D p4) {
245
                double m1 = Double.POSITIVE_INFINITY;
246
247
                if ((p2.getX() - p1.getX()) != 0) {
248
                        m1 = (p2.getY() - p1.getY()) / (p2.getX() - p1.getX());
249
                }
250
251
                double m2 = Double.POSITIVE_INFINITY;
252
253
                if ((p4.getX() - p3.getX()) != 0) {
254
                        m2 = (p4.getY() - p3.getY()) / (p4.getX() - p3.getX());
255
                }
256
257
                if ((m1 == Double.POSITIVE_INFINITY) &&
258
                                (m2 == Double.POSITIVE_INFINITY)) {
259
                        return null;
260
                }
261
262
                double b1 = p2.getY() - (m1 * p2.getX());
263
264
                double b2 = p4.getY() - (m2 * p4.getX());
265
266
                if ((m1 != Double.POSITIVE_INFINITY) &&
267
                                (m2 != Double.POSITIVE_INFINITY)) {
268
                        if (m1 == m2) {
269
                                return null;
270
                        }
271
272
                        double x = (b2 - b1) / (m1 - m2);
273
274
                        return new Point2D.Double(x, (m1 * x) + b1);
275
                } else if (m1 == Double.POSITIVE_INFINITY) {
276
                        double x = p1.getX();
277
278
                        return new Point2D.Double(x, (m2 * x) + b2);
279
                } else if (m2 == Double.POSITIVE_INFINITY) {
280
                        double x = p3.getX();
281
282
                        return new Point2D.Double(x, (m1 * x) + b1);
283
                }
284
285
                //no llega nunca
286
                throw new RuntimeException("BUG!");
287
        }
288 3768 caballero
        /**
289
         * Obtiene el ?ngulo del vector que se pasa como par?metro con el vector
290
         * horizontal de izquierda a derecha
291
         *
292
         * @param start punto origen del vector
293
         * @param end punto destino del vector
294
         *
295
         * @return angulo en radianes
296
         */
297
        public static double getAngle(Point2D start, Point2D end) {
298
                double angle = Math.acos((end.getX() - start.getX()) / start.distance(
299
                                        end));
300 3748 caballero
301 3768 caballero
                if (start.getY() > end.getY()) {
302
                        angle = -angle;
303
                }
304
305
                if (angle < 0) {
306
                        angle += (2 * Math.PI);
307
                }
308
309
                return angle;
310
        }
311
        /**
312
         * Devuelve la distancia desde angle1 a angle2. Angulo en radianes de
313
         * diferencia entre angle1 y angle2 en sentido antihorario
314
         *
315
         * @param angle1 angulo en radianes. Debe ser positivo y no dar ninguna
316
         *                   vuelta a la circunferencia
317
         * @param angle2 angulo en radianes. Debe ser positivo y no dar ninguna
318
         *                   vuelta a la circunferencia
319
         *
320
         * @return distancia entre los ?ngulos
321
         */
322
        public static double angleDistance(double angle1, double angle2) {
323
                if (angle1 < angle2) {
324
                        return angle2 - angle1;
325
                } else {
326
                        return ((Math.PI * 2) - angle1) + angle2;
327
                }
328
        }
329
        /**
330
         * Devuelve el punto de la recta que viene dada por los puntos p1 y p2 a
331
         * una distancia radio de p1.
332
         *
333
         * @param p1 DOCUMENT ME!
334
         * @param p2 DOCUMENT ME!
335
         * @param radio DOCUMENT ME!
336
         *
337
         * @return DOCUMENT ME!
338
         */
339
        public static Point2D getPoint(Point2D p1, Point2D p2, double radio) {
340
                Point2D paux = new Point2D.Double(p2.getX() - p1.getX(),
341
                                p2.getY() - p1.getY());
342
                double v = Math.sqrt(Math.pow((double) paux.getX(), (double) 2) +
343
                                Math.pow((double) paux.getY(), (double) 2));
344
                paux = new Point2D.Double(paux.getX() / v, paux.getY() / v);
345
346
                Point2D aux1 = new Point2D.Double(p1.getX() + (radio * paux.getX()),
347
                                p1.getY() + (radio * paux.getY()));
348
349
                return aux1;
350
        }
351
        /**
352
         * Devuelve la menor distancia desde angle1 a angle2.
353
         *
354
         * @param angle1 angulo en radianes. Debe ser positivo y no dar ninguna
355
         *                   vuelta a la circunferencia
356
         * @param angle2 angulo en radianes. Debe ser positivo y no dar ninguna
357
         *                   vuelta a la circunferencia
358
         *
359
         * @return distancia entre los ?ngulos
360
         */
361
        public static double absoluteAngleDistance(double angle1, double angle2) {
362
                double d = Math.abs(angle1 - angle2);
363
364
                if (d < Math.PI) {
365
                        return d;
366
                } else {
367
                        if (angle1 < angle2) {
368
                                angle2 -= (Math.PI * 2);
369
                        } else {
370
                                angle1 -= (Math.PI * 2);
371
                        }
372
373
                        return Math.abs(angle1 - angle2);
374
                }
375
        }
376
        /**
377
         * Obtiene un arco a partir de 3 puntos. Devuelve null si no se puede crear
378
         * el arco porque los puntos est?n alineados o los 3 puntos no son
379
         * distintos
380
         *
381
         * @param p1
382
         * @param p2
383
         * @param p3
384
         *
385
         * @return Arco
386
         */
387
        public static Arc2D createArc(Point2D p1, Point2D p2, Point2D p3) {
388
                Point2D center = getCenter(p1, p2, p3);
389
390
                if (center == null) {
391
                        return null;
392
                }
393
394
                double angle1 = getAngle(center, p1);
395
                double angle2 = getAngle(center, p3);
396
                double extent = angleDistance(angle1, angle2);
397
398
                Coordinate[] coords = new Coordinate[4];
399
                coords[0] = new Coordinate(p1.getX(), p1.getY());
400
                coords[1] = new Coordinate(p2.getX(), p2.getY());
401
                coords[2] = new Coordinate(p3.getX(), p3.getY());
402
                coords[3] = new Coordinate(p1.getX(), p1.getY());
403
404
                if (!RobustCGAlgorithms.isCCW(coords)) {
405
                        extent = (Math.PI * 2) - extent;
406
                } else {
407
                        extent = -extent;
408
                }
409
410
                //System.err.println("angle1:" + angle1);
411
                //System.err.println("angle2:" + getAngle(center, p2));
412
                //System.err.println("angle3:" + angle2);
413
                //System.err.println("extent:" + extent);
414
                double Radio = p1.distance(center);
415
                double xR = center.getX() - Radio;
416
                double yR = center.getY() - Radio;
417
                double w = 2.0 * Radio;
418
                double h = w;
419
420
                Rectangle2D.Double rBounds = new Rectangle2D.Double(xR, yR, w, h);
421
                Arc2D.Double resul = new Arc2D.Double(rBounds,
422
                                Math.toDegrees((Math.PI * 2) - angle1), Math.toDegrees(extent),
423
                                Arc2D.OPEN);
424
425
                return resul;
426
        }
427 5126 fjp
428 3768 caballero
        /**
429 5126 fjp
         * Obtiene un arco a partir del
430
         *  centro del arco y punto inicio y punto final
431
         *  Suponemos un Arco definicio CCW (CounterClockWise)
432
         * @param center
433
         * @param init
434
         * @param end
435
         *
436
         * @return Arco
437
         */
438
        public static Arc2D createArc2points(Point2D center, Point2D init, Point2D end) {
439
440
                double angle1 = getAngle(center, init);
441
                double angle2 = getAngle(center, end);
442
                double extent = angleDistance(angle1, angle2);
443
444
                extent = -extent; // CCW
445
446
                //System.err.println("angle1:" + angle1);
447
                //System.err.println("angle2:" + getAngle(center, p2));
448
                //System.err.println("angle3:" + angle2);
449
                //System.err.println("extent:" + extent);
450
                double Radio = init.distance(center);
451
                double xR = center.getX() - Radio;
452
                double yR = center.getY() - Radio;
453
                double w = 2.0 * Radio;
454
                double h = w;
455
456
                Rectangle2D.Double rBounds = new Rectangle2D.Double(xR, yR, w, h);
457
                Arc2D.Double resul = new Arc2D.Double(rBounds,
458
                                Math.toDegrees((Math.PI * 2) - angle1), Math.toDegrees(extent),
459
                                Arc2D.OPEN);
460
461
                return resul;
462
        }
463
464
        /**
465 5076 caballero
         * Devuelve el punto a una distancia radio del punto p1 y aplicandole un ?ngulo an.
466 3784 caballero
         * una distancia radio de p1.
467
         *
468
         * @param p1 DOCUMENT ME!
469
         * @param p2 DOCUMENT ME!
470
         * @param radio DOCUMENT ME!
471
         *
472
         * @return DOCUMENT ME!
473
         */
474
        public static Point2D getPoint(Point2D p1, double an, double radio) {
475
                double x=(radio*Math.cos(an))+p1.getX();
476
                double y=(radio*Math.sin(an))+p1.getY();
477
478
                Point2D p=new Point2D.Double(x,y);
479
480
                return p;
481
        }
482
        /**
483 3768 caballero
         * DOCUMENT ME!
484
         *
485
         * @param antp DOCUMENT ME!
486
         * @param lastp DOCUMENT ME!
487
         * @param interp DOCUMENT ME!
488
         * @param point DOCUMENT ME!
489
         *
490
         * @return DOCUMENT ME!
491
         */
492
        public static boolean isLowAngle(Point2D antp, Point2D lastp,
493
                Point2D interp, Point2D point) {
494
                ///double ob=lastp.distance(point);
495
                ///Point2D[] aux=getPerpendicular(lastp,interp,point);
496
                ///Point2D intersect=getIntersection(aux[0],aux[1],lastp,interp);
497
                ///double pb=intersect.distance(point);
498
                ///double a=Math.asin(pb/ob);
499
                Coordinate[] coords = new Coordinate[4];
500
                coords[0] = new Coordinate(lastp.getX(), lastp.getY());
501
                coords[1] = new Coordinate(interp.getX(), interp.getY());
502
                coords[2] = new Coordinate(point.getX(), point.getY());
503
                coords[3] = new Coordinate(lastp.getX(), lastp.getY());
504
505
                try {
506
                        double angle1 = getAngle(antp, lastp);
507
                        System.out.println("angle1= " + angle1);
508
509
                        double angle2 = getAngle(lastp, point);
510
                        System.out.println("angle2= " + angle2);
511
512
                        /*if (lastp.getX()<antp.getX()){
513
                           System.out.println("angleDiff 2 1= "+angleDistance(angle2,angle1));
514
                           System.out.println("angleDiff 1 2= "+angleDistance(angle1,angle2));
515
                           if (angleDistance(angle2,angle1)>Math.PI){
516

517
                           if (RobustCGAlgorithms.isCCW(coords)) {
518
                                   System.out.println("izquierda,arriba,true");
519
                                   return true;
520
                           } else{
521
                                   System.out.println("izquierda,arriba,false");
522
                           }
523
                           }else {
524
                                   if (!RobustCGAlgorithms.isCCW(coords)) {
525
                                           System.out.println("izquierda,abajo,true");
526
                                           return true;
527
                                   } else{
528
                                           System.out.println("izquierda,abajo,false");
529
                                   }
530
                           }
531
                           }else if (lastp.getX()>antp.getX()){
532
                         */
533
                        System.out.println("angleDifl 2 1= " +
534
                                angleDistance(angle2, angle1));
535
                        System.out.println("angleDifl 1 2= " +
536
                                angleDistance(angle1, angle2));
537
538
                        if (angleDistance(angle2, angle1) > Math.PI) {
539
                                if (RobustCGAlgorithms.isCCW(coords)) {
540
                                        System.out.println("derecha,arriba,true");
541
542
                                        return true;
543
                                } else {
544
                                        System.out.println("derecha,arriba,false");
545
                                }
546
                        } else {
547
                                if (!RobustCGAlgorithms.isCCW(coords)) {
548
                                        System.out.println("derecha,abajo,true");
549
550
                                        return true;
551
                                } else {
552
                                        System.out.println("derecha,abajo,false");
553
                                }
554
                        }
555
556
                        //}
557
                } catch (Exception e) {
558
                        System.out.println("false");
559
560
                        return true;
561
                }
562
563
                return false;
564
        }
565 3904 fjp
        public static void rotateGeom(IGeometry geometry, double radAngle, double basex, double basey) {
566
                AffineTransform at = new AffineTransform();
567
                at.rotate(radAngle,basex,basey);
568
                geometry.transform(at);
569 5076 caballero
570 3904 fjp
        }
571
        public static void moveGeom(IGeometry geometry, double dx, double dy) {
572
        AffineTransform at = new AffineTransform();
573
        at.translate(dx, dy);
574
        geometry.transform(at);
575 3768 caballero
576 5076 caballero
577 3904 fjp
        }
578
        public static void scaleGeom(IGeometry geometry, Point2D basePoint, double sx, double sy) {
579
                AffineTransform at = new AffineTransform();
580
                at.setToTranslation(basePoint.getX(),basePoint.getY());
581
                at.scale(sx,sy);
582
                at.translate(-basePoint.getX(),-basePoint.getY());
583 5076 caballero
                geometry.transform(at);
584 3904 fjp
        }
585
586 1430 fjp
}