Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libFMap / src / com / vividsolutions / jts / operation / overlay / SnapLineIntersector.java @ 9178

History | View | Annotate | Download (12.9 KB)

1
/*
2
 * Created on 27-sep-2006
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
/* CVS MESSAGES:
45
 *
46
 * $Id: SnapLineIntersector.java 9178 2006-12-04 19:30:23Z azabala $
47
 * $Log$
48
 * Revision 1.1  2006-12-04 19:30:23  azabala
49
 * *** empty log message ***
50
 *
51
 * Revision 1.1  2006/10/19 16:06:48  azabala
52
 * *** empty log message ***
53
 *
54
 * Revision 1.1  2006/10/17 18:25:53  azabala
55
 * *** empty log message ***
56
 *
57
 * Revision 1.1  2006/10/05 19:20:57  azabala
58
 * first version in cvs
59
 *
60
 * Revision 1.1  2006/10/02 19:06:56  azabala
61
 * *** empty log message ***
62
 *
63
 *
64
 */
65
package com.vividsolutions.jts.operation.overlay;
66

    
67
import com.vividsolutions.jts.algorithm.CGAlgorithms;
68
import com.vividsolutions.jts.algorithm.RobustLineIntersector;
69
import com.vividsolutions.jts.geom.Coordinate;
70
import com.vividsolutions.jts.geom.Envelope;
71
import com.vividsolutions.jts.geom.LineSegment;
72

    
73
public class SnapLineIntersector extends RobustLineIntersector {
74

    
75
        double snapTolerance;
76

    
77
        public SnapLineIntersector(double snapTolerance) {
78
                super();
79
                this.snapTolerance = snapTolerance;
80
        }
81

    
82
        public void computeIntersection(Coordinate p, Coordinate p1, Coordinate p2) {
83
                isProper = false;
84
                Envelope snapEnvelope = new Envelope(p.x - snapTolerance,
85
                                p.x + snapTolerance,
86
                                p.y - snapTolerance,
87
                                p.y + snapTolerance);
88
                Envelope segmentEnvelope = new Envelope(p1, p2);
89
                if(segmentEnvelope.intersects(snapEnvelope))
90
                {
91
                        LineSegment segment = new LineSegment(p1, p2);
92
                        /*
93
                         * TODO SERIA MUY INTERESANTE QUE, ADEMAS DE VER SI EL PUNTO MAS
94
                         * PROXIMO DEL SEGMENTO AL PUNTO DADO ENTRA EN SNAP, VER TAMBI?N EL
95
                         * REGISTRO DE NODOS (NODEMAP)????
96
                         * 
97
                         */
98
                        Coordinate intersectionCandidate = segment.closestPoint(p);
99
                        if (intersectionCandidate.distance(p) <= snapTolerance) {
100
                                isProper = true;
101
                                //verify if it is an extreme point
102
                                if (intersectionCandidate.distance(p1) <= snapTolerance) {
103
                                        isProper = false;
104
                                        result = DO_INTERSECT;
105
                                        intPt[0] = p1;//we snaps to the point
106
                                }
107
                                
108
                                if (intersectionCandidate.distance(p2) <= snapTolerance){
109
                                        isProper = false;
110
                                        result = DO_INTERSECT;
111
                                        intPt[0] = p2;//we snaps to the point
112
                                }
113
                                
114
                                result = DO_INTERSECT;
115
                                intPt[0] = intersectionCandidate;
116
                                return;
117
                        }//distance < snap tolerance
118
                }//segmentEnvelope 
119
                result = DONT_INTERSECT;
120
        }
121
        
122
        
123
        
124
        
125
        public int computeIntersect(Coordinate p1, Coordinate p2,
126
                                                                Coordinate q1, Coordinate q2) {
127
                isProper = false;
128
                Envelope env1 = new Envelope(p1, p2);
129
                double newMinX = env1.getMinX() - snapTolerance;
130
                double newMaxX = env1.getMaxX() + snapTolerance;
131
                double newMinY = env1.getMinY() - snapTolerance;
132
                double newMaxY = env1.getMaxY() + snapTolerance;
133
                env1 = new Envelope(newMinX, newMaxX, newMinY, newMaxY);
134
                
135
                Envelope env2 = new Envelope(q1, q2);
136
                newMinX = env2.getMinX() - snapTolerance;
137
                newMaxX = env2.getMaxX() + snapTolerance;
138
                newMinY = env2.getMinY() - snapTolerance;
139
                newMaxY = env2.getMaxY() + snapTolerance;
140
                env2 = new Envelope(newMinX, newMaxX, newMinY, newMaxY);
141
                
142
                if(! env1.intersects(env2))
143
                        return DONT_INTERSECT;
144
                
145
                /*
146
                 * Algoritmo para calcular interseccion de dos segmentos aplicando snapping
147
                 * */
148
        
149
                //1-vemos si intersectan sin necesidad de snap
150
                int test = super.computeIntersect(p1, p2, q1, q2);
151
                if(test != DONT_INTERSECT)
152
                        return test;
153
                
154
        
155
                //2-Vemos si son paralelos, y la distancia que los separa es inferior
156
                //a la de snap (si fuesen coincidentes ya habr?a sido detectado
157
                
158
           //condiciones de paralelismo en funci?n del producto escalar
159
                //ver http://www.faqs.org/faqs/graphics/algorithms-faq/
160
                //distancia de punto a recta y de recta a recta
161
            double r_bot = (p2.x-p1.x)*(q2.y-q1.y) - (p2.y-p1.y)*(q2.x-q1.x);
162
            
163
            /*
164
             * Ahora mismo no recuerdo el significado matem?tico de r_bot
165
             * (es  (Dx1 * Dy2) - (Dy1 * Dx2) siendo (Dx1,Dy1) (Dx2, Dy2)
166
             * los vectores que se est? tratando de ver si son paralelos...
167
             * 
168
             * Como no tengo claro qu? es, la condici?n de snap va a ser
169
             * la distancia de snap
170
             * */
171
            
172
           // boolean parallels = (r_bot==0);
173
            
174
            boolean parallels = (Math.abs(r_bot) <= snapTolerance);
175
            
176
            
177
            if  ( parallels ) {      
178
                    //Son paralelos
179
                    double distance1 = CGAlgorithms.distancePointLine(p1, q1, q2);
180
                    double distance2 = CGAlgorithms.distancePointLine(p2, q1, q2);
181
                    double distance = Math.min(distance1, distance2);
182
                    if(distance <= snapTolerance)
183
                            return computeCollinearIntersection(p1, p2, q1, q2);
184
                    else 
185
                            return DONT_INTERSECT;
186
            }
187
            
188
            //Ultimo intento. Probamos a intersectar cada uno de los vertices de la
189
            //linea de entrada
190
            computeIntersection(p1, q1, q2);
191
            if(this.hasIntersection()){
192
                    return result;
193
            }
194
            computeIntersection(p2, q1, q2);
195
            if(this.hasIntersection())
196
            {
197
                    return result;
198
            }
199
                return DONT_INTERSECT;
200
        }
201
        
202
        /**
203
         * Returns t param for point P of vector AB in the parametric line equation
204
         * P = t*AB
205
         * 
206
         * @param p
207
         * @param A
208
         * @param B
209
         */
210
        private double getParametrizedLineFactor(Coordinate p, Coordinate A, Coordinate B){
211
                 double r = ( (p.x - A.x) * (B.x - A.x) + (p.y - A.y) * (B.y - A.y) )
212
         /
213
       ( (B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y) );
214
                 return r;
215
        }
216

    
217
        
218
        /*
219
         * Computes collinear intersections, but instead of considering envelope 
220
         * intersections, it applies parametrized line equations (ideal to snap)
221
         * */
222
        private int computeCollinearIntersection(Coordinate p1, Coordinate p2,
223
                        Coordinate q1, Coordinate q2) {
224

    
225
                /*
226
                 * TODO
227
                 * Estamos teniendo un problema: La clase SegmentIntersector hace el
228
                 * siguiente uso de computeCollinearIntersection:
229
                 * 
230
                 * li.computeIntersection(p00, p01, p10, p11);
231
           if (li.hasIntersection()) {
232
                              numIntersections++;
233
           if (! isTrivialIntersection(e0, segIndex0, e1, segIndex1)) {
234
                           hasIntersection = true;
235
                           if (includeProper || ! li.isProper() ) {
236
                                   e0.addIntersections(li, segIndex0, 0);
237
                                   e1.addIntersections(li, segIndex1, 1);
238
                }
239
               if (li.isProper()) {
240
                            properIntersectionPoint = 
241
                            (Coordinate) li.getIntersection(0).clone();
242
                           hasProper = true;
243
                           if (! isBoundaryPoint(li, bdyNodes))
244
                                hasProperInterior = true;
245
               }
246
               
247
               Y esto aparece comentado:
248
                       //if (li.isCollinear())
249
                        //hasCollinear = true;
250
               
251
               En estas circunstancias no se est? recuperando
252
               el segundo punto de la intersecci?n colineal, ni se 
253
               verifica que es una intersecci?n colineal
254
     
255
                 * */
256
                
257
                
258
                /*
259
                 * TODO Otro problema: a la hora de calcular la intersecci?n entre dos
260
                 * segmentos colineales, definir bien CUAL VA A SNAPEAR SOBRE CUAL.
261
                 * 
262
                 * Es decir, en grafoA.computeIntersect(grafoB), las coordenadas del GeometryGraph
263
                 * B se mover?n a las l?neas del GeometryGraph B
264
                 * 
265
                 * ESTO NO ES TAN IMPORTANTE COMO SNAPEAR EdgeIntersection y Coordinate
266
                 * de un Edge
267
                 * 
268
                 * */
269
                
270
                /*
271
                 * We compute params of p1 and p2 point in q1q2 parametric
272
                 * line equation
273
                 * */                
274
                
275
                
276
//REHACER ESTO
277
//DADAS DOS LINEAS PARALELAS, SI EST?N A UNA DISTANCIA (LAS LINEAS)
278
//INTERIOR A LA DE SNAP, HAY QUE CONSIDERARLAS COLINEALES..........
279
//PERO ES MUY IMPORTANTE SNAPEAR P1 CON Q1-Q2 Y P2 CON Q1-Q2 PARA QUE
280
//NO SALGAN COSAS RARAS (EDGEINTERSECTION NO PROPIAS)
281
//
282
//TAMBIEN HAY QUE DEFINIR UNA POLITICA DE SNAP:
283
//QUE LINEA SE MANTIENE Y QUE LINEA SE MUEVE
284
//(NO HACER ARBITRARIAMENTE)
285
                
286
                double rP1 = getParametrizedLineFactor(p1, q1, q2);
287
                double rP2 = getParametrizedLineFactor(p2, q1, q2);
288
                
289
                if(rP1 <= 0 && rP2 <= 0)
290
                {
291
                        // p1---p2--q1----q2
292
                        intPt[0] = q1;
293
                        return DO_INTERSECT;
294
                }
295
                
296
                if(rP1 <= 0 && ( (rP2 > 0 && rP2 <=1))){
297
                        // p1---q1---p2----q2
298
                        isProper = false;
299
                        intPt[0] = q1;
300
                        intPt[1] = p2;
301
                        return COLLINEAR;
302
                }
303
                
304
                if( (rP1 >0 && rP1 <=1) && (rP2 > 0 && rP2 <= 1)){
305
                        //p1--q1---q2---p2
306
                        intPt[0] = q1;
307
                        intPt[1] = q2;
308
                        return COLLINEAR;
309
                }
310
                
311
                if((rP1 >0 && rP1 <= 1) && (rP2 > 1)){
312
                        //q1--p1--q2--p2
313
                        intPt[0] = p1;
314
                        intPt[1] = q2;
315
                        return COLLINEAR;
316
                        
317
                }
318
                
319
                if((rP1 < 0) && (rP2 > 1)){
320
                        //p1---q1---q2--p2
321
                        intPt[0] = q1;
322
                        intPt[1] = q2;
323
                        return COLLINEAR;
324
                }
325
                
326
                if((rP1 > 1) && (rP2 > 1)){
327
                        //q1--q2--p1--p2
328
                        intPt[0] = q2;
329
                        return DO_INTERSECT;
330
                }
331
                return DONT_INTERSECT;
332
        }
333

    
334
        
335
        
336

    
337
        /**
338
         * Test whether a point lies in the envelopes of both input segments. A
339
         * correctly computed intersection point should return <code>true</code>
340
         * for this test. Since this test is for debugging purposes only, no attempt
341
         * is made to optimize the envelope test.
342
         * 
343
         * @return <code>true</code> if the input point lies within both input
344
         *         segment envelopes
345
         */
346
        private boolean isInSegmentEnvelopes(Coordinate intPt) {
347
                Envelope env0 = new Envelope(inputLines[0][0], inputLines[0][1]);
348
                Envelope env1 = new Envelope(inputLines[1][0], inputLines[1][1]);
349
                
350
                
351
            Envelope snapEnvelope = new Envelope(intPt.x - snapTolerance,
352
                                                                                            intPt.x + snapTolerance,
353
                                                                                            intPt.y - snapTolerance,
354
                                                                                            intPt.y + snapTolerance);
355
            //TODO Review if we must chech for intersections of containtment
356
                return env0.intersects(snapEnvelope) && env1.intersects(snapEnvelope);
357
//                return env0.contains(intPt) && env1.contains(intPt);
358
        }
359
        
360
        
361
        /***********************************
362
         * *********************************
363
         * Overwrited methods of LineIntersector
364
         * *********************************
365
         * *********************************
366
         * */
367
        
368
          /**
369
           * Test whether a point is a intersection point of two line segments.
370
           * Note that if the intersection is a line segment, this method only tests for
371
           * equality with the endpoints of the intersection segment.
372
           * It does <b>not</b> return true if
373
           * the input point is internal to the intersection segment.
374
           *
375
           * @return true if the input point is one of the intersection points.
376
           */
377
          public boolean isIntersection(Coordinate pt) {
378
            for (int i = 0; i < result; i++) {
379
              if (intPt[i].distance(pt) <= snapTolerance) {
380
                return true;
381
              }
382
            }
383
            return false;
384
          }
385

    
386
         
387
          /**
388
           * Tests whether either intersection point is an interior point of the specified input segment.
389
           *
390
           * @return <code>true</code> if either intersection point is in the interior of the input segment
391
           */
392
          public boolean isInteriorIntersection(int inputLineIndex)
393
          {
394
            for (int i = 0; i < result; i++) {
395
              if (! (   intPt[i].distance(inputLines[inputLineIndex][0] ) <= snapTolerance
396
                     || intPt[i].distance(inputLines[inputLineIndex][1])<= snapTolerance )) {
397
                return true;
398
              }
399
            }
400
            return false;
401
          }
402

    
403
          /*
404
           * TODO
405
           * Estos dos metodos finales hacen uso de static getEdgeDistance, que se ha
406
           * hecho sin tener en cuenta ning?n tipo de snap o redondeo.
407
           * 
408
           * No se en que puede afectar (comprobar)
409
           * 
410
           * 
411
           * */
412
          protected void computeIntLineIndex(int segmentIndex) {
413
            double dist0 = getEdgeDistance(segmentIndex, 0);
414
            double dist1 = getEdgeDistance(segmentIndex, 1);
415
            if (dist0 > dist1) {
416
              intLineIndex[segmentIndex][0] = 0;
417
              intLineIndex[segmentIndex][1] = 1;
418
            }
419
            else {
420
              intLineIndex[segmentIndex][0] = 1;
421
              intLineIndex[segmentIndex][1] = 0;
422
            }
423
          }
424

    
425
          /**
426
           * Computes the "edge distance" of an intersection point along the specified input line segment.
427
           *
428
           * @param segmentIndex is 0 or 1
429
           * @param intIndex is 0 or 1
430
           *
431
           * @return the edge distance of the intersection point
432
           */
433
          public double getEdgeDistance(int segmentIndex, int intIndex) {
434
            double dist = computeEdgeDistance(intPt[intIndex], inputLines[segmentIndex][0],
435
                inputLines[segmentIndex][1]);
436
            return dist;
437
          }
438

    
439
}