Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_geometries / src / org / gvsig / fmap / geom / util / UtilFunctions.java @ 21308

History | View | Annotate | Download (17.2 KB)

1
/*
2
 * Created on 10-feb-2005
3
 *
4
 * gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
5
 *
6
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
7
 *
8
 * 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
 *
13
 * 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
 *
18
 * 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
 *
22
 * 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
 *
34
 *    or
35
 *
36
 *   IVER T.I. S.A
37
 *   Salamanca 50
38
 *   46005 Valencia
39
 *   Spain
40
 *
41
 *   +34 963163400
42
 *   dac@iver.es
43
 */
44
package org.gvsig.fmap.geom.util;
45

    
46
import java.awt.geom.AffineTransform;
47
import java.awt.geom.Arc2D;
48
import java.awt.geom.Point2D;
49
import java.awt.geom.Rectangle2D;
50

    
51
import org.gvsig.fmap.geom.Geometry;
52

    
53
import com.vividsolutions.jts.algorithm.RobustCGAlgorithms;
54
import com.vividsolutions.jts.geom.Coordinate;
55

    
56
/**
57
 * @author FJP
58
 *
59
 * TODO To change the template for this generated type comment go to
60
 * Window - Preferences - Java - Code Generation - Code and Comments
61
 */
62
public class UtilFunctions {
63
    static public Arc2D createCircle(Point2D p1, Point2D p2, Point2D p3) //, Graphics g)
64
    {
65
        double xC, yC, w, h;
66

    
67
        // Calculamos 2 secantes, tiramos perpendiculares por sus puntos
68
        // medios y obtenemos el centro. Luego calculamos el radio.
69
        // Puntos medios de los segmentos.
70
        double xm1, ym1, xm2, ym2;
71
        xm1 = (p1.getX() + p2.getX())/ 2.0;
72
        ym1 = (p1.getY() + p2.getY())/ 2.0;
73
        xm2 = (p2.getX() + p3.getX())/ 2.0;
74
        ym2 = (p2.getY() + p3.getY())/ 2.0;
75

    
76
        /* g.setColor(Color.GRAY);
77
        g.draw3DRect((int)xm1, (int) ym1, 1, 1, true);
78
        g.draw3DRect((int)xm2, (int) ym2, 1, 1, true); */
79
        // Pendientes de las perpendiculares y constantes
80
        double mP1=0, mP2=0, A1, A2;
81
        boolean bPerp1 = false;
82
        //boolean bPerp2 = false;
83
        if (p2.getY() - p1.getY() == 0)
84
        {
85
            A1 = ym1;
86
            bPerp1 = true;
87
        }
88
        else
89
        {
90
            mP1 = (p2.getX() - p1.getX()) /(p1.getY() - p2.getY());
91
            A1 = ym1 - xm1 * mP1;
92
        }
93
        if (p2.getY() - p3.getY() == 0)
94
        {
95
            A2 = ym2;
96
            //bPerp2 = true;
97
        }
98
        else
99
        {
100
            mP2 = (p3.getX() - p2.getX()) /(p2.getY() - p3.getY());
101
            A2 = ym2 - xm2 * mP2;
102
        }
103
        if (mP2 == mP1)
104
        {
105
            return null; // Error, 3 puntos alineados. No puede pasar un arco
106
        }
107
        else
108
        {
109
            xC = (A2 - A1)/(mP1-mP2);
110
            if (!bPerp1)
111
                yC = xC * mP1 + A1;
112
            else
113
                yC = xC * mP2 + A2;
114
        }
115
        double Radio = p1.distance(xC, yC);
116
        double xR = xC - Radio ;
117
        double yR = yC - Radio ;
118
        w = 2.0* Radio;
119
        h = w;
120
        Rectangle2D.Double rBounds = new Rectangle2D.Double(xR,yR, w,h);
121
        Arc2D.Double resul = new Arc2D.Double(rBounds, 0.0, 360.0, Arc2D.OPEN);
122
                /* g.setColor(Color.RED);
123
                ((Graphics2D) g).draw(resul);
124
                g.setColor(Color.BLUE);
125
                ((Graphics2D) g).draw(rBounds);
126
                g.draw3DRect((int)p1.getX(), (int) p1.getY(), 1, 1, true);
127
                g.draw3DRect((int)p2.getX(), (int) p2.getY(), 2, 2, true);
128
                g.draw3DRect((int)p3.getX(), (int) p3.getY(), 1, 1, true);
129
                g.drawString("1", (int) p1.getX(), (int) p1.getY());
130
                g.drawString("2", (int) p2.getX(), (int) p2.getY());
131
                g.drawString("3", (int) p3.getX(), (int) p3.getY());
132
                g.drawString("C", (int) xC, (int) yC);
133
                g.draw3DRect((int)xC, (int) yC, 2, 2, true); */
134

    
135
        return resul;
136
    }
137
    /**
138
         * Obtiene un par de puntos que definen la recta perpendicular a p1-p2 que
139
         * pasa por el punto perp
140
         *
141
         * @param p1 punto de la recta p1-p2
142
         * @param p2 punto de la recta p1-p2
143
         * @param perp Punto por el que pasa la recta perpendicular, debe ser
144
         *                   distinto a p2
145
         *
146
         * @return Array con dos puntos que definen la recta resultante
147
         */
148
        public static Point2D[] getPerpendicular(Point2D p1, Point2D p2,
149
                Point2D perp) {
150
                if ((p2.getY() - p1.getY()) == 0) {
151
                        return new Point2D[] {
152
                                new Point2D.Double(perp.getX(), 0),
153
                                new Point2D.Double(perp.getX(), 1)
154
                        };
155
                }
156

    
157
                //Pendiente de la recta perpendicular
158
                double m = (p1.getX() - p2.getX()) / (p2.getY() - p1.getY());
159

    
160
                //b de la funcion de la recta perpendicular
161
                double b = perp.getY() - (m * perp.getX());
162

    
163
                //Obtenemos un par de puntos
164
                Point2D[] res = new Point2D[2];
165

    
166
                res[0] = new Point2D.Double(0, (m * 0) + b);
167
                res[1] = new Point2D.Double(1000, (m * 1000) + b);
168

    
169
                return res;
170
        }
171
        public static Point2D[] getParallel(Point2D p1,Point2D p2,double distance) {
172
                Point2D[] pParallel=new Point2D[2];
173
                pParallel[0]=getPerpendicularPoint(p1,p2,p1,distance);
174
                pParallel[1]=getPerpendicularPoint(p1,p2,p2,distance);
175
                return pParallel;
176
        }
177

    
178
        /**
179
         * Obtiene el punto que se encuentra a una distancia 'dist' de la recta
180
         * p1-p2 y se encuentra en la recta perpendicular que pasa por perpPoint
181
         *
182
         * @param p1 Punto de la recta p1-p2
183
         * @param p2 Punto de la recta p1-p2
184
         * @param perpPoint Punto de la recta perpendicular
185
         * @param dist Distancia del punto que se quiere obtener a la recta p1-p2
186
         *
187
         * @return DOCUMENT ME!
188
         */
189
        public static Point2D getPerpendicularPoint(Point2D p1, Point2D p2,
190
                Point2D perpPoint, double dist) {
191
                Point2D[] p = getPerpendicular(p1, p2, perpPoint);
192
                Point2D unit = getUnitVector(p[0], p[1]);
193

    
194
                return new Point2D.Double(perpPoint.getX() + (unit.getX() * dist),
195
                        perpPoint.getY() + (unit.getY() * dist));
196
        }
197

    
198
        /**
199
         * Devuelve un vector unitario en forma de punto a partir de dos puntos.
200
         *
201
         * @param p1 punto origen.
202
         * @param p2 punto destino.
203
         *
204
         * @return vector unitario.
205
         */
206
        public static Point2D getUnitVector(Point2D p1, Point2D p2) {
207
                Point2D paux = new Point2D.Double(p2.getX() - p1.getX(),
208
                                p2.getY() - p1.getY());
209
                double v = Math.sqrt(Math.pow(paux.getX(), 2d) +
210
                                Math.pow(paux.getY(), 2d));
211
                paux = new Point2D.Double(paux.getX() / v, paux.getY() / v);
212

    
213
                return paux;
214
        }
215
        /**
216
         * Obtiene el centro del c?rculo que pasa por los tres puntos que se pasan
217
         * como  par?metro
218
         *
219
         * @param p1 primer punto del c?rculo cuyo centro se quiere obtener
220
         * @param p2 segundo punto del c?rculo cuyo centro se quiere obtener
221
         * @param p3 tercer punto del c?rculo cuyo centro se quiere obtener
222
         *
223
         * @return Devuelve null si los puntos est?n alineados o no son 3 puntos
224
         *                    distintos
225
         */
226
        public static Point2D getCenter(Point2D p1, Point2D p2, Point2D p3) {
227
                if (p1.equals(p2) || p2.equals(p3) || p1.equals(p3)) {
228
                        return null;
229
                }
230

    
231
                Point2D[] perp1 = getPerpendicular(p1, p2,
232
                                new Point2D.Double((p1.getX() + p2.getX()) / 2,
233
                                        (p1.getY() + p2.getY()) / 2));
234
                Point2D[] perp2 = getPerpendicular(p2, p3,
235
                                new Point2D.Double((p2.getX() + p3.getX()) / 2,
236
                                        (p2.getY() + p3.getY()) / 2));
237

    
238
                return getIntersection(perp1[0], perp1[1], perp2[0], perp2[1]);
239
        }
240

    
241

    
242
        /**
243
         * Devuelve el punto de la intersecci?n entre las lineas p1-p2 y p3-p4.
244
         *
245
         * @param p1 punto de la recta p1-p2
246
         * @param p2 punto de la recta p1-p2
247
         * @param p3 punto de la recta p3-p4
248
         * @param p4 punto de la recta p3-p4
249
         *
250
         * @return DOCUMENT ME!
251
         *
252
         * @throws RuntimeException DOCUMENT ME!
253
         */
254
        public static Point2D getIntersection(Point2D p1, Point2D p2, Point2D p3,
255
                Point2D p4) {
256
                double m1 = Double.POSITIVE_INFINITY;
257

    
258
                if ((p2.getX() - p1.getX()) != 0) {
259
                        m1 = (p2.getY() - p1.getY()) / (p2.getX() - p1.getX());
260
                }
261

    
262
                double m2 = Double.POSITIVE_INFINITY;
263

    
264
                if ((p4.getX() - p3.getX()) != 0) {
265
                        m2 = (p4.getY() - p3.getY()) / (p4.getX() - p3.getX());
266
                }
267

    
268
                if ((m1 == Double.POSITIVE_INFINITY) &&
269
                                (m2 == Double.POSITIVE_INFINITY)) {
270
                        return null;
271
                }
272

    
273
                double b1 = p2.getY() - (m1 * p2.getX());
274

    
275
                double b2 = p4.getY() - (m2 * p4.getX());
276

    
277
                if ((m1 != Double.POSITIVE_INFINITY) &&
278
                                (m2 != Double.POSITIVE_INFINITY)) {
279
                        if (m1 == m2) {
280
                                return null;
281
                        }
282

    
283
                        double x = (b2 - b1) / (m1 - m2);
284

    
285
                        return new Point2D.Double(x, (m1 * x) + b1);
286
                } else if (m1 == Double.POSITIVE_INFINITY) {
287
                        double x = p1.getX();
288

    
289
                        return new Point2D.Double(x, (m2 * x) + b2);
290
                } else if (m2 == Double.POSITIVE_INFINITY) {
291
                        double x = p3.getX();
292

    
293
                        return new Point2D.Double(x, (m1 * x) + b1);
294
                }
295

    
296
                //no llega nunca
297
                throw new RuntimeException("BUG!");
298
        }
299
        /**
300
         * Obtiene el ?ngulo del vector que se pasa como par?metro con el vector
301
         * horizontal de izquierda a derecha
302
         *
303
         * @param start punto origen del vector
304
         * @param end punto destino del vector
305
         *
306
         * @return angulo en radianes
307
         */
308
        public static double getAngle(Point2D start, Point2D end) {
309
                double angle = Math.acos((end.getX() - start.getX()) / start.distance(
310
                                        end));
311

    
312
                if (start.getY() > end.getY()) {
313
                        angle = -angle;
314
                }
315

    
316
                if (angle < 0) {
317
                        angle += (2 * Math.PI);
318
                }
319

    
320
                return angle;
321
        }
322
        /**
323
         * Devuelve la distancia desde angle1 a angle2. Angulo en radianes de
324
         * diferencia entre angle1 y angle2 en sentido antihorario
325
         *
326
         * @param angle1 angulo en radianes. Debe ser positivo y no dar ninguna
327
         *                   vuelta a la circunferencia
328
         * @param angle2 angulo en radianes. Debe ser positivo y no dar ninguna
329
         *                   vuelta a la circunferencia
330
         *
331
         * @return distancia entre los ?ngulos
332
         */
333
        public static double angleDistance(double angle1, double angle2) {
334
                if (angle1 < angle2) {
335
                        return angle2 - angle1;
336
                } else {
337
                        return ((Math.PI * 2) - angle1) + angle2;
338
                }
339
        }
340
        /**
341
         * Devuelve el punto de la recta que viene dada por los puntos p1 y p2 a
342
         * una distancia radio de p1.
343
         *
344
         * @param p1 DOCUMENT ME!
345
         * @param p2 DOCUMENT ME!
346
         * @param radio DOCUMENT ME!
347
         *
348
         * @return DOCUMENT ME!
349
         */
350
        public static Point2D getPoint(Point2D p1, Point2D p2, double radio) {
351
                Point2D paux = new Point2D.Double(p2.getX() - p1.getX(),
352
                                p2.getY() - p1.getY());
353
                double v = Math.sqrt(Math.pow(paux.getX(), 2d) +
354
                                Math.pow(paux.getY(), 2d));
355
                paux = new Point2D.Double(paux.getX() / v, paux.getY() / v);
356

    
357
                Point2D aux1 = new Point2D.Double(p1.getX() + (radio * paux.getX()),
358
                                p1.getY() + (radio * paux.getY()));
359

    
360
                return aux1;
361
        }
362
        /**
363
         * Devuelve la menor distancia desde angle1 a angle2.
364
         *
365
         * @param angle1 angulo en radianes. Debe ser positivo y no dar ninguna
366
         *                   vuelta a la circunferencia
367
         * @param angle2 angulo en radianes. Debe ser positivo y no dar ninguna
368
         *                   vuelta a la circunferencia
369
         *
370
         * @return distancia entre los ?ngulos
371
         */
372
        public static double absoluteAngleDistance(double angle1, double angle2) {
373
                double d = Math.abs(angle1 - angle2);
374

    
375
                if (d < Math.PI) {
376
                        return d;
377
                } else {
378
                        if (angle1 < angle2) {
379
                                angle2 -= (Math.PI * 2);
380
                        } else {
381
                                angle1 -= (Math.PI * 2);
382
                        }
383

    
384
                        return Math.abs(angle1 - angle2);
385
                }
386
        }
387
        /**
388
         * Obtiene un arco a partir de 3 puntos. Devuelve null si no se puede crear
389
         * el arco porque los puntos est?n alineados o los 3 puntos no son
390
         * distintos
391
         *
392
         * @param p1
393
         * @param p2
394
         * @param p3
395
         *
396
         * @return Arco
397
         */
398
        public static Arc2D createArc(Point2D p1, Point2D p2, Point2D p3) {
399
                Point2D center = getCenter(p1, p2, p3);
400

    
401
                if (center == null) {
402
                        return null;
403
                }
404

    
405
                double angle1 = getAngle(center, p1);
406
                double angle2 = getAngle(center, p3);
407
                double extent = angleDistance(angle1, angle2);
408

    
409
                Coordinate[] coords = new Coordinate[4];
410
                coords[0] = new Coordinate(p1.getX(), p1.getY());
411
                coords[1] = new Coordinate(p2.getX(), p2.getY());
412
                coords[2] = new Coordinate(p3.getX(), p3.getY());
413
                coords[3] = new Coordinate(p1.getX(), p1.getY());
414

    
415
                if (!RobustCGAlgorithms.isCCW(coords)) {
416
                        extent = (Math.PI * 2) - extent;
417
                } else {
418
                        extent = -extent;
419
                }
420

    
421
                //System.err.println("angle1:" + angle1);
422
                //System.err.println("angle2:" + getAngle(center, p2));
423
                //System.err.println("angle3:" + angle2);
424
                //System.err.println("extent:" + extent);
425
                double Radio = p1.distance(center);
426
                double xR = center.getX() - Radio;
427
                double yR = center.getY() - Radio;
428
                double w = 2.0 * Radio;
429
                double h = w;
430

    
431
                Rectangle2D.Double rBounds = new Rectangle2D.Double(xR, yR, w, h);
432
                Arc2D.Double resul = new Arc2D.Double(rBounds,
433
                                Math.toDegrees((Math.PI * 2) - angle1), Math.toDegrees(extent),
434
                                Arc2D.OPEN);
435

    
436
                return resul;
437
        }
438

    
439
        /**
440
         * Obtiene un arco a partir del
441
         *  centro del arco y punto inicio y punto final
442
         *  Suponemos un Arco definicio CCW (CounterClockWise)
443
         * @param center
444
         * @param init
445
         * @param end
446
         *
447
         * @return Arco
448
         */
449
        public static Arc2D createArc2points(Point2D center, Point2D init, Point2D end) {
450

    
451
                double angle1 = getAngle(center, init);
452
                double angle2 = getAngle(center, end);
453
                double extent = angleDistance(angle1, angle2);
454

    
455
                extent = -extent; // CCW
456

    
457
                //System.err.println("angle1:" + angle1);
458
                //System.err.println("angle2:" + getAngle(center, p2));
459
                //System.err.println("angle3:" + angle2);
460
                //System.err.println("extent:" + extent);
461
                double Radio = init.distance(center);
462
                double xR = center.getX() - Radio;
463
                double yR = center.getY() - Radio;
464
                double w = 2.0 * Radio;
465
                double h = w;
466

    
467
                Rectangle2D.Double rBounds = new Rectangle2D.Double(xR, yR, w, h);
468
                Arc2D.Double resul = new Arc2D.Double(rBounds,
469
                                Math.toDegrees((Math.PI * 2) - angle1), Math.toDegrees(extent),
470
                                Arc2D.OPEN);
471

    
472
                return resul;
473
        }
474

    
475
        /**
476
         * Devuelve el punto a una distancia radio del punto p1 y aplicandole un ?ngulo an.
477
         * una distancia radio de p1.
478
         *
479
         * @param p1 DOCUMENT ME!
480
         * @param p2 DOCUMENT ME!
481
         * @param radio DOCUMENT ME!
482
         *
483
         * @return DOCUMENT ME!
484
         */
485
        public static Point2D getPoint(Point2D p1, double an, double radio) {
486
                double x=(radio*Math.cos(an))+p1.getX();
487
                double y=(radio*Math.sin(an))+p1.getY();
488

    
489
                Point2D p=new Point2D.Double(x,y);
490

    
491
                return p;
492
        }
493
        /**
494
         * DOCUMENT ME!
495
         *
496
         * @param antp DOCUMENT ME!
497
         * @param lastp DOCUMENT ME!
498
         * @param interp DOCUMENT ME!
499
         * @param point DOCUMENT ME!
500
         *
501
         * @return DOCUMENT ME!
502
         */
503
        public static boolean isLowAngle(Point2D antp, Point2D lastp,
504
                Point2D interp, Point2D point) {
505
                ///double ob=lastp.distance(point);
506
                ///Point2D[] aux=getPerpendicular(lastp,interp,point);
507
                ///Point2D intersect=getIntersection(aux[0],aux[1],lastp,interp);
508
                ///double pb=intersect.distance(point);
509
                ///double a=Math.asin(pb/ob);
510
                Coordinate[] coords = new Coordinate[4];
511
                coords[0] = new Coordinate(lastp.getX(), lastp.getY());
512
                coords[1] = new Coordinate(interp.getX(), interp.getY());
513
                coords[2] = new Coordinate(point.getX(), point.getY());
514
                coords[3] = new Coordinate(lastp.getX(), lastp.getY());
515

    
516
                try {
517
                        double angle1 = getAngle(antp, lastp);
518
                        System.out.println("angle1= " + angle1);
519

    
520
                        double angle2 = getAngle(lastp, point);
521
                        System.out.println("angle2= " + angle2);
522

    
523
                        /*if (lastp.getX()<antp.getX()){
524
                           System.out.println("angleDiff 2 1= "+angleDistance(angle2,angle1));
525
                           System.out.println("angleDiff 1 2= "+angleDistance(angle1,angle2));
526
                           if (angleDistance(angle2,angle1)>Math.PI){
527

528
                           if (RobustCGAlgorithms.isCCW(coords)) {
529
                                   System.out.println("izquierda,arriba,true");
530
                                   return true;
531
                           } else{
532
                                   System.out.println("izquierda,arriba,false");
533
                           }
534
                           }else {
535
                                   if (!RobustCGAlgorithms.isCCW(coords)) {
536
                                           System.out.println("izquierda,abajo,true");
537
                                           return true;
538
                                   } else{
539
                                           System.out.println("izquierda,abajo,false");
540
                                   }
541
                           }
542
                           }else if (lastp.getX()>antp.getX()){
543
                         */
544
                        System.out.println("angleDifl 2 1= " +
545
                                angleDistance(angle2, angle1));
546
                        System.out.println("angleDifl 1 2= " +
547
                                angleDistance(angle1, angle2));
548

    
549
                        if (angleDistance(angle2, angle1) > Math.PI) {
550
                                if (RobustCGAlgorithms.isCCW(coords)) {
551
                                        System.out.println("derecha,arriba,true");
552

    
553
                                        return true;
554
                                } else {
555
                                        System.out.println("derecha,arriba,false");
556
                                }
557
                        } else {
558
                                if (!RobustCGAlgorithms.isCCW(coords)) {
559
                                        System.out.println("derecha,abajo,true");
560

    
561
                                        return true;
562
                                } else {
563
                                        System.out.println("derecha,abajo,false");
564
                                }
565
                        }
566

    
567
                        //}
568
                } catch (Exception e) {
569
                        System.out.println("false");
570

    
571
                        return true;
572
                }
573

    
574
                return false;
575
        }
576
        
577
        /* movido a AbstractPrimitive */
578
        
579
        public static void rotateGeom(Geometry geometry, double radAngle, double basex, double basey) {
580
                AffineTransform at = new AffineTransform();
581
                at.rotate(radAngle,basex,basey);
582
                geometry.transform(at);
583

    
584
        }
585
        public static void moveGeom(Geometry geometry, double dx, double dy) {
586
        AffineTransform at = new AffineTransform();
587
        at.translate(dx, dy);
588
        geometry.transform(at);
589

    
590

    
591
        }
592
        public static void scaleGeom(Geometry geometry, Point2D basePoint, double sx, double sy) {
593
                AffineTransform at = new AffineTransform();
594
                at.setToTranslation(basePoint.getX(),basePoint.getY());
595
                at.scale(sx,sy);
596
                at.translate(-basePoint.getX(),-basePoint.getY());
597
                geometry.transform(at);
598
        }
599

    
600

    
601
}