Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extGraph_predes / src / com / iver / cit / gvsig / topology / SnappingOverlayOperation.java @ 8031

History | View | Annotate | Download (24.2 KB)

1
/*
2
 * Created on 12-sep-2006 by azabala
3
 *
4
 */
5
package com.iver.cit.gvsig.topology;
6

    
7
import java.util.ArrayList;
8
import java.util.Iterator;
9
import java.util.List;
10

    
11
import com.iver.cit.gvsig.topology.algorithms.SnapPointLocator;
12
import com.iver.cit.gvsig.topology.geomgraph.SnapEdgeList;
13
import com.iver.cit.gvsig.topology.geomgraph.SnappingPlanarGraph;
14
import com.vividsolutions.jts.algorithm.CGAlgorithms;
15
import com.vividsolutions.jts.algorithm.LineIntersector;
16
import com.vividsolutions.jts.algorithm.PointLocator;
17
import com.vividsolutions.jts.geom.Coordinate;
18
import com.vividsolutions.jts.geom.Geometry;
19
import com.vividsolutions.jts.geom.GeometryFactory;
20
import com.vividsolutions.jts.geom.Location;
21
import com.vividsolutions.jts.geom.Point;
22
import com.vividsolutions.jts.geomgraph.Depth;
23
import com.vividsolutions.jts.geomgraph.DirectedEdge;
24
import com.vividsolutions.jts.geomgraph.DirectedEdgeStar;
25
import com.vividsolutions.jts.geomgraph.Edge;
26
import com.vividsolutions.jts.geomgraph.EdgeList;
27
import com.vividsolutions.jts.geomgraph.Label;
28
import com.vividsolutions.jts.geomgraph.Node;
29
import com.vividsolutions.jts.geomgraph.PlanarGraph;
30
import com.vividsolutions.jts.geomgraph.Position;
31
import com.vividsolutions.jts.geomgraph.SnappingGeometryGraph;
32
import com.vividsolutions.jts.io.ParseException;
33
import com.vividsolutions.jts.operation.overlay.LineBuilder;
34
import com.vividsolutions.jts.operation.overlay.OverlayNodeFactory;
35
import com.vividsolutions.jts.operation.overlay.OverlayOp;
36
import com.vividsolutions.jts.operation.overlay.PointBuilder;
37
import com.vividsolutions.jts.operation.overlay.PolygonBuilder;
38
import com.vividsolutions.jts.operation.overlay.SnapPolygonBuilder;
39
import com.vividsolutions.jts.util.Assert;
40

    
41
/**
42
 * TODO 
43
 * El codigo esta lleno de coordinateA.distance(coordinateB)
44
 * <= snapTolerance;
45
 * 
46
 * CAMBIAR POR SnapCoordinate, de forma que equals haga
47
 * esta comprobacin
48
 * 
49
 * 
50
 */
51
public class SnappingOverlayOperation extends OverlayOp {
52
        
53
        private final SnapPointLocator ptLocator = new SnapPointLocator();
54
        private GeometryFactory geomFact;
55
        private Geometry resultGeom;
56

    
57
        protected final LineIntersector li;
58
        
59
        protected double snapTolerance;
60
        
61
        
62
        /*Planar graph of the overlay operation*/
63
        private SnappingPlanarGraph graph;
64
        
65
        /*Geometry graph of each individual geometry*/
66
        private SnappingGeometryGraph[] arg;
67

    
68
        
69
        /*It saves all the new edges resulting from intersections of
70
         * edges of geometries A and B. It is a temporal repository, before
71
         * to save them in SnappingPlanarGraph*/
72
        private SnapEdgeList edgeList = null;
73

    
74
        
75
/*
76
 * El resultado de una operacion de overlay puede contener
77
 * puntos, lineas y poligonos.
78
 * */        
79
        private List resultPolyList = new ArrayList();
80

    
81
        private List resultLineList = new ArrayList();
82

    
83
        private List resultPointList = new ArrayList();
84
        
85

    
86
        
87
        public static Geometry overlayOp(Geometry geom0, Geometry geom1,
88
                        int opCode, double tolerance) {
89
                SnappingOverlayOperation gov = new SnappingOverlayOperation(geom0,
90
                                geom1, tolerance);
91
                Geometry geomOv = gov.getResultGeometry(opCode);
92
                return geomOv;
93
        }
94
        
95

    
96
        
97
        public SnappingOverlayOperation(Geometry g0, Geometry g1, double tolerance) {
98
                super(g0, g1);
99
                graph = new SnappingPlanarGraph(new OverlayNodeFactory(), tolerance);
100
                arg = new SnappingGeometryGraph[2];
101
                arg[0] = new SnappingGeometryGraph(tolerance, 0, g0);
102
                arg[1] = new SnappingGeometryGraph(tolerance, 1, g1);
103
                geomFact = g0.getFactory();
104
                li = new SnapLineIntersector(tolerance);
105
                edgeList = new SnapEdgeList(tolerance);
106
                this.snapTolerance = tolerance;
107
        }
108

    
109
        public Geometry getResultGeometry(int funcCode) {
110
                computeOverlay(funcCode);
111
                return resultGeom;
112
        }
113

    
114
        
115
        public PlanarGraph getGraph() {
116
                return graph;
117
        }
118

    
119
        
120
        /*
121
         * ************************************************************
122
         * METODO PRINCIPAL
123
         * ************************************************************
124
         * */
125
        private void computeOverlay(int opCode) {
126
                
127
                /*
128
                 * Se copian los NODOS de las dos geometrias. 
129
                 * ESTO ES IMPORTANTE, PUES:
130
                 * a) un punto origina un nodo.
131
                 * b) una linea origina dos nodos
132
                 * c) un poligono origina un nodo.
133
                 * 
134
                 * */
135
                copyPoints(0);
136
                copyPoints(1);
137
                
138
                arg[0].computeSelfNodes(li, false);
139
                arg[1].computeSelfNodes(li, false);
140

    
141
                
142
                /*
143
                 * Calcula las intersecciones.
144
                 * Se supone que daran lugar a Nodes, ?NO?
145
                 * Como resultado, cada Edge guardar? en sus EdgeIntersectionList
146
                 * las intersecciones que hay en sus segmentos (EdgeIntersection).
147
                 * 
148
                 * Estas intersecciones se representan por:
149
                 * -segmento del edge en que ocurren.
150
                 * -coordenada
151
                 * -distancia al primer vertice del segmento
152
                 * 
153
                 * ?OJO? COMO RESULTADO DE ESTO NO SE GENERAN EJES NUEVOS.
154
                 * PARA HACER SNAP EN LAS INTERSECCIONES TENDRIAMOS QUE RETOCAR LA 
155
                 * CLASE EDGEINTERSECTIONLIST
156
                 * 
157
                 * */
158
                arg[0].computeEdgeIntersections(arg[1], li, true);
159
                /*
160
                 * Ahora lo que se hace es: para cada Edge del grafo,
161
                 * se parte (en funci?n de sus intersecciones) y se a?aden
162
                 * los Edges fragmentados a la colecci?n baseSplitEdges
163
                 * 
164
                 * */
165
                
166
                List baseSplitEdges = new ArrayList();
167
                arg[0].computeSplitEdges(baseSplitEdges);
168
                //TODO Quizas la clave est? tambien en la 2? geometria
169
                arg[1].computeSplitEdges(baseSplitEdges);
170
                
171
                
172
                /*
173
                 * Edges resulting of A intersection B, that are in baseSplitEdges 
174
                 * Collection, are saved in EdgeList.
175
                 * ?OJO? Si aparecen ejes repetidos, no se duplican (pero si 
176
                 * que se cambia su etiqueta)
177
                 * */
178
                //Se copian los nuevos Edges generados en EdgeList
179
                insertUniqueEdges(baseSplitEdges);
180
                
181
                
182
                /*Se etiquetan*/
183
                computeLabelsFromDepths();
184
                
185
                /*
186
                 * Quita los Edges que hayan sufrido colapso dimensional
187
                 * (en la documentac?on de JTS viene algo de esto)
188
                 * */
189
                replaceCollapsedEdges();
190

    
191
                
192
        /*
193
         * Finalmente, se a?ade al SnappingPlanarGraph resultado los Edges
194
         * calculados como fruto de las intersecciones (contenidos en EdgeList).
195
         * 
196
         * Aqu? se hace algo muy importante tambi?n: se a?aden nuevos nodos
197
         * al grafo (correspondientes con los extremos de los nuevos Edge
198
         * que no estuvieran ya en el grafo)
199
         * 
200
         * */
201
                graph.addEdges(edgeList.getEdges());
202
                
203
                
204
                computeLabelling();
205
                labelIncompleteNodes();
206
                
207
                /**
208
                 * The ordering of building the result Geometries is important. Areas
209
                 * must be built before lines, which must be built before points. This
210
                 * is so that lines which are covered by areas are not included
211
                 * explicitly, and similarly for points.
212
                 */
213
                findResultAreaEdges(opCode);
214
                cancelDuplicateResultEdges();
215
                
216
                
217
                //TODO Todos los builders deber?n usar los metodos snap de locator
218
                SnapPolygonBuilder polyBuilder = new SnapPolygonBuilder(geomFact, cga);
219
                polyBuilder.add(graph);
220
                resultPolyList = polyBuilder.getPolygons();
221

    
222
                LineBuilder lineBuilder = new LineBuilder(this, geomFact, ptLocator);
223
                resultLineList = lineBuilder.build(opCode);
224

    
225
                PointBuilder pointBuilder = new PointBuilder(this, geomFact, ptLocator){
226
                         public List build(int opCode)
227
                          {
228
                                 for (Iterator nodeit = getGraph().getNodes().iterator(); nodeit.hasNext(); ) {
229
                                      Node n = (Node) nodeit.next();
230

    
231
                                      // filter out nodes which are known to be in the result
232
                                      if (n.isInResult())
233
                                        continue;
234
                                      // if an incident edge is in the result, then the node coordinate is included already
235
                                      if (n.isIncidentEdgeInResult())
236
                                        continue;
237
                                      if (n.getEdges().getDegree() == 0 || opCode == OverlayOp.INTERSECTION) {
238

    
239
                                        /**
240
                                         * For nodes on edges, only INTERSECTION can result in edge nodes being included even
241
                                         * if none of their incident edges are included
242
                                         */
243
                                          Label label = n.getLabel();
244
                                          if (SnappingOverlayOperation.checkLabelLocation(label.getLocation(0),
245
                                                          label.getLocation(1), opCode)) {
246
                                            filterCoveredNodeToPoint(n);
247
                                          }
248
                                      }
249
                                 }
250
                            return resultPointList;
251
                          }
252
                         
253
                         
254
                                 
255
                         private void filterCoveredNodeToPoint(Node n)
256
                          {
257
                            Coordinate coord = n.getCoordinate();
258
                            if (! isCoveredByLA(coord)) {
259
                              Point pt = geomFact.createPoint(coord);
260
                              resultPointList.add(pt);
261
                            }
262
                          }        
263
                };
264
                resultPointList = pointBuilder.build(opCode);
265

    
266
                // gather the results from all calculations into a single Geometry for
267
                // the result set
268
                resultGeom = computeGeometry(resultPointList, resultLineList,
269
                                resultPolyList);
270
        }
271
        
272
        
273
         /**
274
           * This method will handle arguments of Location.NONE correctly
275
           *
276
           * @return true if the locations correspond to the opCode
277
           */
278
          public static boolean isResultOfOp(int loc0, int loc1, int opCode)
279
          {
280
            if (loc0 == Location.BOUNDARY) loc0 = Location.INTERIOR;
281
            if (loc1 == Location.BOUNDARY) loc1 = Location.INTERIOR;
282
            switch (opCode) {
283
            case INTERSECTION:
284
              return loc0 == Location.INTERIOR
285
                  && loc1 == Location.INTERIOR;
286
            case UNION:
287
              return loc0 == Location.INTERIOR
288
                  || loc1 == Location.INTERIOR;
289
            case DIFFERENCE:
290
              return loc0 == Location.INTERIOR
291
                  && loc1 != Location.INTERIOR;
292
            case SYMDIFFERENCE:
293
              return   (     loc0 == Location.INTERIOR &&  loc1 != Location.INTERIOR)
294
                    || (     loc0 != Location.INTERIOR &&  loc1 == Location.INTERIOR);
295
            }
296
            return false;
297
          }
298
          
299
          public static boolean isResultOfOp(Label label, int opCode)
300
          {
301
            int loc0 = label.getLocation(0);
302
            int loc1 = label.getLocation(1);
303
            return isResultOfOp(loc0, loc1, opCode);
304
          }
305

    
306
        
307
        //TODO Quitar esto de aqui
308
        
309
         public static boolean checkLabelLocation(int loc0, int loc1, int opCode)
310
          {
311
            if (loc0 == Location.BOUNDARY) loc0 = Location.INTERIOR;
312
            if (loc1 == Location.BOUNDARY) loc1 = Location.INTERIOR;
313
            switch (opCode) {
314
            case INTERSECTION:
315
              return loc0 == Location.INTERIOR
316
                  && loc1 == Location.INTERIOR;
317
            case UNION:
318
              return loc0 == Location.INTERIOR
319
                  || loc1 == Location.INTERIOR;
320
            case DIFFERENCE:
321
              return loc0 == Location.INTERIOR
322
                  && loc1 != Location.INTERIOR;
323
            case SYMDIFFERENCE:
324
              return   (     loc0 == Location.INTERIOR &&  loc1 != Location.INTERIOR)
325
                    || (     loc0 != Location.INTERIOR &&  loc1 == Location.INTERIOR);
326
            }
327
            return false;
328
          }
329

    
330
        private void insertUniqueEdges(List edges) {
331
                for (Iterator i = edges.iterator(); i.hasNext();) {
332
                        Edge e = (Edge) i.next();
333
                        insertUniqueEdge(e);
334
                }
335
        }
336

    
337
        /**
338
         * Insert an edge from one of the noded input graphs. Checks edges that are
339
         * inserted to see if an identical edge already exists. If so, the edge is
340
         * not inserted, but its label is merged with the existing edge.
341
         */
342
        protected void insertUniqueEdge(Edge e) {
343
                
344
                //TODO Crear una clase SnapEdge y SnapEdgeList puede ser necesario???
345
                //creo que si pq SnapEdgeList mantiene una cache que no considera snap
346
                Edge existingEdge = edgeList.findEqualEdge(e);
347
                // If an identical edge already exists, simply update its label
348
                if (existingEdge != null) {
349
                        Label existingLabel = existingEdge.getLabel();
350
                        Label labelToMerge = e.getLabel();
351
                        
352
                        // check if new edge is in reverse direction to existing edge
353
                        // if so, must flip the label before merging it
354
                        if (!existingEdge.isPointwiseEqual(e)) {
355
                                labelToMerge = new Label(e.getLabel());
356
                                labelToMerge.flip();
357
                        }
358
                        Depth depth = existingEdge.getDepth();
359
                        // if this is the first duplicate found for this edge, initialize
360
                        // the depths
361
                        if (depth.isNull()) {
362
                                depth.add(existingLabel);
363
                        }
364
                        depth.add(labelToMerge);
365
                        existingLabel.merge(labelToMerge);
366
                } else { // no matching existing edge was found
367
                        // add this new edge to the list of edges in this graph
368
                        edgeList.add(e);
369
                }
370
        }
371

    
372
        
373
        /**
374
         * Update the labels for edges according to their depths. For each edge, the
375
         * depths are first normalized. Then, if the depths for the edge are equal,
376
         * this edge must have collapsed into a line edge. If the depths are not
377
         * equal, update the label with the locations corresponding to the depths
378
         * (i.e. a depth of 0 corresponds to a Location of EXTERIOR, a depth of 1
379
         * corresponds to INTERIOR)
380
         */
381
        private void computeLabelsFromDepths() {
382
                for (Iterator it = edgeList.iterator(); it.hasNext();) {
383
                        Edge e = (Edge) it.next();
384
                        Label lbl = e.getLabel();
385
                        Depth depth = e.getDepth();
386
                        /*
387
                         * Only check edges for which there were duplicates, since these are
388
                         * the only ones which might be the result of dimensional collapses.
389
                         */
390
                        if (!depth.isNull()) {
391
                                depth.normalize();
392
                                for (int i = 0; i < 2; i++) {
393
                                        if (!lbl.isNull(i) && lbl.isArea() && !depth.isNull(i)) {
394
                                                /**
395
                                                 * if the depths are equal, this edge is the result of
396
                                                 * the dimensional collapse of two or more edges. It has
397
                                                 * the same location on both sides of the edge, so it
398
                                                 * has collapsed to a line.
399
                                                 */
400
                                                if (depth.getDelta(i) == 0) {
401
                                                        lbl.toLine(i);
402
                                                } else {
403
                                                        /**
404
                                                         * This edge may be the result of a dimensional
405
                                                         * collapse, but it still has different locations on
406
                                                         * both sides. The label of the edge must be updated
407
                                                         * to reflect the resultant side locations indicated
408
                                                         * by the depth values.
409
                                                         */
410
                                                        Assert
411
                                                                        .isTrue(!depth.isNull(i, Position.LEFT),
412
                                                                                        "depth of LEFT side has not been initialized");
413
                                                        lbl.setLocation(i, Position.LEFT, depth
414
                                                                        .getLocation(i, Position.LEFT));
415
                                                        Assert
416
                                                                        .isTrue(!depth.isNull(i, Position.RIGHT),
417
                                                                                        "depth of RIGHT side has not been initialized");
418
                                                        lbl.setLocation(i, Position.RIGHT, depth
419
                                                                        .getLocation(i, Position.RIGHT));
420
                                                }
421
                                        }
422
                                }
423
                        }
424
                }
425
        }
426

    
427
        /**
428
         * If edges which have undergone dimensional collapse are found, replace
429
         * them with a new edge which is a L edge
430
         */
431
        private void replaceCollapsedEdges() {
432
                List newEdges = new ArrayList();
433
                for (Iterator it = edgeList.iterator(); it.hasNext();) {
434
                        Edge e = (Edge) it.next();
435
                        if (e.isCollapsed()) {
436
                                //        Debug.print(e);
437
                                it.remove();
438
                                newEdges.add(e.getCollapsedEdge());
439
                        }
440
                }
441
                edgeList.addAll(newEdges);
442
        }
443

    
444
        /**
445
         * Copy all nodes from an arg geometry into this graph. The node label in
446
         * the arg geometry overrides any previously computed label for that
447
         * argIndex. (E.g. a node may be an intersection node with a previously
448
         * computed label of BOUNDARY, but in the original arg Geometry it is
449
         * actually in the interior due to the Boundary Determination Rule)
450
         */
451
        private void copyPoints(int argIndex) {
452
                for (Iterator i = arg[argIndex].getNodeIterator(); i.hasNext();) {
453
                        Node graphNode = (Node) i.next();
454
                        Node newNode = graph.addNode(graphNode.getCoordinate());
455
                        newNode.setLabel(argIndex, graphNode.getLabel().getLocation(
456
                                        argIndex));
457
                }
458
        }
459

    
460
        /**
461
         * Compute initial labelling for all DirectedEdges at each node. In this
462
         * step, DirectedEdges will acquire a complete labelling (i.e. one with
463
         * labels for both Geometries) only if they are incident on a node which has
464
         * edges for both Geometries
465
         */
466
        private void computeLabelling() {
467
                for (Iterator nodeit = graph.getNodes().iterator(); nodeit.hasNext();) {
468
                        Node node = (Node) nodeit.next();
469
                        node.getEdges().computeLabelling(arg);
470
                }
471
                mergeSymLabels();
472
                updateNodeLabelling();
473
                
474
        }
475

    
476
        /**
477
         * For nodes which have edges from only one Geometry incident on them, the
478
         * previous step will have left their dirEdges with no labelling for the
479
         * other Geometry. However, the sym dirEdge may have a labelling for the
480
         * other Geometry, so merge the two labels.
481
         */
482
        private void mergeSymLabels() {
483
                for (Iterator nodeit = graph.getNodes().iterator(); nodeit.hasNext();) {
484
                        Node node = (Node) nodeit.next();
485
                        ((DirectedEdgeStar) node.getEdges()).mergeSymLabels();
486
                }
487
        }
488

    
489
        private void updateNodeLabelling() {
490
                // update the labels for nodes
491
                // The label for a node is updated from the edges incident on it
492
                // (Note that a node may have already been labelled
493
                // because it is a point in one of the input geometries)
494
                for (Iterator nodeit = graph.getNodes().iterator(); nodeit.hasNext();) {
495
                        Node node = (Node) nodeit.next();
496
                        Label lbl = ((DirectedEdgeStar) node.getEdges()).getLabel();
497
                        Label otherLbl = node.getLabel();
498
                        otherLbl.merge(lbl);
499
                }
500
        }
501

    
502
        /**
503
         * Incomplete nodes are nodes whose labels are incomplete. (e.g. the
504
         * location for one Geometry is null). These are either isolated nodes, or
505
         * nodes which have edges from only a single Geometry incident on them.
506
         * 
507
         * Isolated nodes are found because nodes in one graph which don't intersect
508
         * nodes in the other are not completely labelled by the initial process of
509
         * adding nodes to the nodeList. To complete the labelling we need to check
510
         * for nodes that lie in the interior of edges, and in the interior of
511
         * areas.
512
         * <p>
513
         * When each node labelling is completed, the labelling of the incident
514
         * edges is updated, to complete their labelling as well.
515
         */
516
        private void labelIncompleteNodes() {
517
                for (Iterator ni = graph.getNodes().iterator(); ni.hasNext();) {
518
                        Node n = (Node) ni.next();
519
                        Label label = n.getLabel();
520
                        if (n.isIsolated()) {
521
                                if (label.isNull(0))
522
                                        labelIncompleteNode(n, 0);
523
                                else
524
                                        labelIncompleteNode(n, 1);
525
                        }
526
                        // now update the labelling for the DirectedEdges incident on this
527
                        // node
528
                        ((DirectedEdgeStar) n.getEdges()).updateLabelling(label);
529
                }
530
        }
531

    
532
        /**
533
         * Label an isolated node with its relationship to the target geometry.
534
         */
535
        private void labelIncompleteNode(Node n, int targetIndex) {
536
            //TODO Ver si el pointLocator deberia snapear
537
                Coordinate coord = n.getCoordinate();
538
            Geometry geom = arg[targetIndex].getGeometry();
539
                int loc = ptLocator.locate(coord, geom, snapTolerance);
540
                n.getLabel().setLocation(targetIndex, loc);
541
        }
542

    
543
        /**
544
         * Find all edges whose label indicates that they are in the result area(s),
545
         * according to the operation being performed. Since we want polygon shells
546
         * to be oriented CW, choose dirEdges with the interior of the result on the
547
         * RHS. Mark them as being in the result. Interior Area edges are the result
548
         * of dimensional collapses. They do not form part of the result area
549
         * boundary.
550
         */
551
        private void findResultAreaEdges(int opCode) {
552
                for (Iterator it = graph.getEdgeEnds().iterator(); it.hasNext();) {
553
                        DirectedEdge de = (DirectedEdge) it.next();
554
                        // mark all dirEdges with the appropriate label
555
                        Label label = de.getLabel();
556
                        if (label.isArea()
557
                                        && !de.isInteriorAreaEdge()
558
                                        && isResultOfOp(label.getLocation(0, Position.RIGHT), label
559
                                                        .getLocation(1, Position.RIGHT), opCode)) {
560
                                de.setInResult(true);
561
                                //        Debug.print("in result "); Debug.println(de);
562
                        }
563
                }
564
        }
565

    
566
        /**
567
         * If both a dirEdge and its sym are marked as being in the result, cancel
568
         * them out.
569
         */
570
        private void cancelDuplicateResultEdges() {
571
                // remove any dirEdges whose sym is also included
572
                // (they "cancel each other out")
573
                for (Iterator it = graph.getEdgeEnds().iterator(); it.hasNext();) {
574
                        DirectedEdge de = (DirectedEdge) it.next();
575
                        DirectedEdge sym = de.getSym();
576
                        if (de.isInResult() && sym.isInResult()) {
577
                                de.setInResult(false);
578
                                sym.setInResult(false);
579
                                //        Debug.print("cancelled "); Debug.println(de);
580
                                // Debug.println(sym);
581
                        }
582
                }
583
        }
584

    
585
        /**
586
         * This method is used to decide if a point node should be included in the
587
         * result or not.
588
         * 
589
         * @return true if the coord point is covered by a result Line or Area
590
         *         geometry
591
         */
592
        public boolean isCoveredByLA(Coordinate coord) {
593
                if (isCovered(coord, resultLineList))
594
                        return true;
595
                if (isCovered(coord, resultPolyList))
596
                        return true;
597
                return false;
598
        }
599

    
600
        /**
601
         * This method is used to decide if an L edge should be included in the
602
         * result or not.
603
         * 
604
         * @return true if the coord point is covered by a result Area geometry
605
         */
606
        public boolean isCoveredByA(Coordinate coord) {
607
                if (isCovered(coord, resultPolyList))
608
                        return true;
609
                return false;
610
        }
611

    
612
        /**
613
         * @return true if the coord is located in the interior or boundary of a
614
         *         geometry in the list.
615
         */
616
        private boolean isCovered(Coordinate coord, List geomList) {
617
                for (Iterator it = geomList.iterator(); it.hasNext();) {
618
                        Geometry geom = (Geometry) it.next();
619
                        int loc = ptLocator.locate(coord, geom, snapTolerance);
620
                        if (loc != Location.EXTERIOR)
621
                                return true;
622
                }
623
                return false;
624
        }
625

    
626
        private Geometry computeGeometry(List resultPointList, List resultLineList,
627
                        List resultPolyList) {
628
                List geomList = new ArrayList();
629
                // element geometries of the result are always in the order P,L,A
630
                geomList.addAll(resultPointList);
631
                geomList.addAll(resultLineList);
632
                geomList.addAll(resultPolyList);
633
                // build the most specific geometry possible
634
                return geomFact.buildGeometry(geomList);
635
        }
636
        
637
        
638
        public static void main(String[] args){
639
                GeometryFactory factory = new GeometryFactory();
640
                com.vividsolutions.jts.io.WKTReader reader = new com.vividsolutions.jts.io.WKTReader(factory);
641
                Geometry a, b, c, d;
642
                try {
643
                
644
                        //Snap en un extremo y en un vertice intermedio
645
                        a = reader.read("LINESTRING(0.001 0.001, 5.001 5.001)");
646
                        b = reader.read("LINESTRING(2.1 -3, 0.0 -0.001, -2.22 4.88, 10.0 10.0, 5.002 5.002)");
647
                        System.out.println(SnappingOverlayOperation.overlayOp(a, b, OverlayOp.INTERSECTION, 0.01));                        
648
//                        //snap mediante l?neas paralelas
649
                        c = reader.read("LINESTRING(0 0, 5 0, 10 0.001)");
650
                        d = reader.read("LINESTRING(0.001 0.01, 5.001 0.002, 10.001 0.002)");                
651
                        long t0 = System.currentTimeMillis();
652
                        System.out.println(SnappingOverlayOperation.overlayOp(c, d, OverlayOp.INTERSECTION, 0.1));                
653
                        long t1 = System.currentTimeMillis();
654
                        System.out.println(OverlayOp.overlayOp(c, d, OverlayOp.INTERSECTION));
655
                        long t2 = System.currentTimeMillis();
656
                        System.out.println("Con snap: "+(t1-t0)+" ms");
657
                        System.out.println("Sin snap: "+(t2-t1)+" ms");
658
                        
659
                        d = reader.read("LINESTRING(0 0, 5 0, 10 0.001)");
660
                        System.out.println(OverlayOp.overlayOp(c, d, OverlayOp.INTERSECTION));
661
                        
662
                        //lineas paralelas a una distancia superior a la de snap
663
                        //(para comprobar el criterio de paralelismo en LineIntersector
664
                        c = reader.read("LINESTRING(0 0, 5 0, 10 0.001)");
665
                        d = reader.read("LINESTRING(0 0.11, 5 0.12, 10 0.14)");
666
                        System.out.println(SnappingOverlayOperation.overlayOp(c, d, OverlayOp.INTERSECTION, 0.001));
667
//                        
668
                        c = reader.read("LINESTRING(1 0, 3 2)");
669
                        d = reader.read("LINESTRING(3.05 2.01, 5 1.25, 0.25 1.75)");
670
                        System.out.println(OverlayOp.overlayOp(c, d, OverlayOp.INTERSECTION));
671
                        System.out.println((SnappingOverlayOperation.overlayOp(c, d, OverlayOp.INTERSECTION, 0.1)));
672
//                        
673
//                        
674
                        d = reader.read("LINESTRING(3 2, 5 1.25, 0.25 1.75)");
675
                        System.out.println(OverlayOp.overlayOp(c, d, OverlayOp.INTERSECTION));
676
                        System.out.println((SnappingOverlayOperation.overlayOp(c, d, OverlayOp.INTERSECTION, 0.1)));
677
                        
678
                        //Que un pol?gono est? cerrado o no no es snap, sino regla topologica
679
                        
680
                        //TODO CON POLIGONOS EST? DANDO PROBLEMAS. HABRA QUE REVISAR LINEAS Y POLIGONOS
681
//                        c = reader.read("POLYGON((0 0, 0 5, 5 5, 5 0,  0 0))");
682
//                        d = reader.read("POLYGON((-0.01 0, 3 8, 6 6 ,  -0.01 0))");
683
                        
684
                        c = reader.read("POLYGON((5 0, 5 5, 10 5, 10 0,  5 0))");
685
                        d = reader.read("POLYGON((4 3, 4.99 3.5, 10.01 3.5, 12 3,  4 3))");
686
                        
687
                        
688
                        
689
                        //REVISI?N TOPOLOGICA 
690
                        /*
691
                         * Un aspecto esencial de la topologia en JTS es el etiquetado.
692
                         * Todo Eje del grafo asociado a un pol?gono tiene una etiqueta o Label, 
693
                         * con tres valores posibles para la izquierda, derecha y encima del poligono
694
                         * (EXTERIOR, BOUNDARY, INTERIOR)
695
                         * 
696
                         * Por tanto, si la orientaci?n no es la correcta, todo se va al traste
697
                         * (pues las cosas se invierten especularmente)
698
                         * */
699
                        if(CGAlgorithms.isCCW(c.getCoordinates())){
700
                                System.out.println("Anillo exterior de poligono en orden incorrecto");
701
                            System.out.println(c.toText());
702
                                System.exit(-2);
703
                        }
704
                        if(CGAlgorithms.isCCW(d.getCoordinates())){
705
                                System.out.println("Anillo exterior de poligono en orden incorrecto");
706
                                   System.out.println(d.toText());
707
                                System.exit(-2);
708
                        }
709
                
710
                        System.out.println((SnappingOverlayOperation.overlayOp(c, d, OverlayOp.INTERSECTION, 0.1)));
711

    
712
                        Geometry pol1 = reader.read("POLYGON((0 0, -5 0, -10 5, 0 10,  10 5, 5 0, 0 0))");
713
                        Geometry pol2 = reader.read("POLYGON((10.01 0, 5 5, 5 10, 10 10, 10.01 0))");
714
                        
715
                        System.out.println((SnappingOverlayOperation.overlayOp(pol1, pol2, OverlayOp.INTERSECTION, 0.1)));
716
                        System.out.println((OverlayOp.overlayOp(pol1, pol2, OverlayOp.INTERSECTION)));
717
                        
718
                        
719
                } catch (ParseException e) {
720
                        e.printStackTrace();
721
                }
722
                   
723

    
724
        }
725

    
726
}