Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libTopology / src / org / gvsig / topology / topologyrules / jtsisvalidrules / PolygonHolesMustNotBeNested.java @ 16396

History | View | Annotate | Download (8.17 KB)

1
/*
2
 * Created on 10-abr-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: 
47
 * $Log: 
48
 */
49
package org.gvsig.topology.topologyrules.jtsisvalidrules;
50

    
51
import java.awt.geom.Point2D;
52
import java.util.ArrayList;
53
import java.util.HashMap;
54
import java.util.List;
55

    
56
import org.gvsig.fmap.core.FGeometryUtil;
57
import org.gvsig.jts.JtsUtil;
58
import org.gvsig.topology.AbstractTopologyRule;
59
import org.gvsig.topology.Messages;
60
import org.gvsig.topology.Topology;
61
import org.gvsig.topology.TopologyError;
62
import org.gvsig.topology.TopologyRuleDefinitionException;
63

    
64
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
65
import com.iver.cit.gvsig.fmap.core.FShape;
66
import com.iver.cit.gvsig.fmap.core.IFeature;
67
import com.iver.cit.gvsig.fmap.core.IGeometry;
68
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
69
import com.vividsolutions.jts.algorithms.SnapCGAlgorithms;
70
import com.vividsolutions.jts.geom.Coordinate;
71
import com.vividsolutions.jts.geom.Geometry;
72
import com.vividsolutions.jts.geom.GeometryCollection;
73
import com.vividsolutions.jts.geom.LinearRing;
74
import com.vividsolutions.jts.geom.MultiPolygon;
75
import com.vividsolutions.jts.geom.Polygon;
76
import com.vividsolutions.jts.geomgraph.GeometryGraph;
77
import com.vividsolutions.jts.precision.EnhancedPrecisionOp;
78

    
79
public class PolygonHolesMustNotBeNested extends AbstractTopologyRule {
80
        
81
        public PolygonHolesMustNotBeNested(FLyrVect originLyr){
82
                super(originLyr);
83
        }
84
        
85
        public PolygonHolesMustNotBeNested(Topology topology, FLyrVect originLyr){
86
                super(topology, originLyr);
87
        }
88
        
89
        public PolygonHolesMustNotBeNested(){
90
                
91
        }
92
        
93
        public String getDescription() {
94
                return Messages.getText("POLYGON_MUST_NOT_HAVE_DUPLICATED_RINGS");
95
        }
96

    
97
        public void checkPreconditions() throws TopologyRuleDefinitionException {
98
                int shapeType;
99
                try {
100
                        shapeType = this.originLyr.getShapeType();
101
                        int numDimensions = FGeometryUtil.getDimensions(shapeType);
102
                        if(numDimensions != 2)
103
                                throw new TopologyRuleDefinitionException("HolesNotNested solo aplica sobre capas de dimension 2");
104
                } catch (ReadDriverException e) {
105
                        throw new TopologyRuleDefinitionException(
106
                                        "Error al tratar de verificar el tipo de geometria");
107
                }
108
        }
109

    
110
        public void validateFeature(IFeature feature) {
111
                Geometry jtsGeo  = FGeometryUtil.toJtsPolygon((FShape)feature.getGeometry().getInternalShape());
112
                if (jtsGeo instanceof Polygon) {
113
                        checkHoles((Polygon)jtsGeo, new GeometryGraph(0, jtsGeo), feature);
114
                } else if (jtsGeo instanceof MultiPolygon) {
115
                        MultiPolygon multiPoly = (MultiPolygon)jtsGeo;
116
                        for(int i = 0; i < multiPoly.getNumGeometries(); i++){
117
                                Polygon polygon = (Polygon) multiPoly.getGeometryN(i);
118
                                checkHoles( polygon, new GeometryGraph(0, polygon), feature);
119
                        }
120
                }else if(jtsGeo instanceof GeometryCollection){
121
                        MultiPolygon multiPoly = JtsUtil.convertIfPossible((GeometryCollection) jtsGeo);
122
                        for(int i = 0; i < multiPoly.getNumGeometries(); i++){
123
                                Polygon polygon = (Polygon) multiPoly.getGeometryN(i);
124
                                checkHoles( polygon, new GeometryGraph(0, polygon), feature);
125
                        }
126
                }
127
        }
128

    
129
        private void checkHoles(Polygon p, GeometryGraph graph, IFeature feature) {
130
                /*
131
                 * Holes only can touch in a single point.
132
                 * If this condition is not passed, we wont check for nested holes
133
                 */
134
                boolean disjointHoles = true;
135
                
136
                class MapEntry {
137
                        int i;
138
                        int j;
139
                        
140
                        MapEntry(int i, int j){
141
                                this.i = i;
142
                                this.j = j;
143
                        }
144
                        
145
                        public boolean equals(Object o){
146
                                if(! (o instanceof MapEntry))
147
                                        return false;
148
                                MapEntry other = (MapEntry)o;
149
                                
150
                                return (other.i == i && other.j == j) || (other.i == j && other.j == i);
151
                        }
152
                        
153
                        public int hashCode(){
154
                                return 1;
155
                        }
156
                }
157
                HashMap<MapEntry, MapEntry> checkedHoles = new HashMap<MapEntry, MapEntry>();
158
                
159
                 for (int i = 0; i < p.getNumInteriorRing(); i++) {
160
                         LinearRing innerHole = (LinearRing) p.getInteriorRingN(i);
161
                         Polygon innerHoleAsPoly = JtsUtil.geomFactory.createPolygon(innerHole, null);
162
                         for (int j = 0; j < p.getNumInteriorRing(); j++) {
163
                                 if ( i == j)
164
                                         continue;
165
                                 
166
                                 MapEntry entry = new MapEntry(i, j);
167
                                 if(checkedHoles.get(entry) != null)
168
                                         continue;
169
                                 
170
                                 checkedHoles.put(entry, entry);
171
                                 
172
                                 LinearRing testHole = (LinearRing) p.getInteriorRingN(j);
173
                                 Polygon testHoleAsPoly = JtsUtil.geomFactory.createPolygon(testHole, null);
174
                                 //TODO Use PreparedGeometry in the next stable release of JTS
175
                                 Geometry intersection = EnhancedPrecisionOp.intersection(innerHoleAsPoly, testHoleAsPoly);
176
                                 Coordinate[] intersectionCoords = intersection.getCoordinates();
177
                                 if(intersectionCoords.length > 1){
178
                                         disjointHoles = false;
179
                                         Point2D[] pt2d = FGeometryUtil.getCoordinatesAsPoint2D(intersectionCoords);
180
                                         IGeometry errorGeometry = FGeometryUtil.createFPolygon(pt2d);
181
                                         addError(errorGeometry, feature);
182
                                 }
183
                         }//for i
184
                 }//for j
185
                 
186
                 if(! disjointHoles)
187
                         return;
188
                
189
                
190
                /*
191
                 * Holes must not be nested (a hole inside a hole)
192
                 * */
193
                 List<Coordinate> insidePoints = new ArrayList<Coordinate>();
194
                 for (int i = 0; i < p.getNumInteriorRing(); i++) {
195
                      LinearRing innerHole = (LinearRing) p.getInteriorRingN(i);
196
                      Coordinate[] innerHolePts = innerHole.getCoordinates();
197
                      for (int j = 0; j < p.getNumInteriorRing(); j++) {
198
                        // don't test hole against itself!
199
                        if (i == j) continue;
200

    
201
                        LinearRing searchHole = (LinearRing) p.getInteriorRingN(j);
202
                        // if envelopes don't overlap, holes are not nested
203
                        if (! innerHole.getEnvelopeInternal().intersects(searchHole.getEnvelopeInternal()))
204
                          continue;
205

    
206
                        Coordinate[] searchHolePts = searchHole.getCoordinates();
207
                        Coordinate innerholePt = JtsUtil.findPtNotNode(innerHolePts, searchHole, graph);
208
                               
209
                        boolean inside = SnapCGAlgorithms.isPointInRing(innerholePt, searchHolePts);
210
                        if ( inside ) {
211
                                 insidePoints.add(innerholePt);
212
                        }//if
213
                      
214
                      }//for j
215
                      if(insidePoints.size() > 0){
216
                          Coordinate[] coords = new Coordinate[insidePoints.size()];
217
                              insidePoints.toArray(coords);
218
                              Point2D[] pt2d = FGeometryUtil.getCoordinatesAsPoint2D(coords);
219
                              IGeometry geometry = FGeometryUtil.createFPolygon(pt2d);
220
                              addError(geometry, feature);
221
                        }
222
                      
223
                    }//for i
224
//                 if (!isNonNested) {
225
//                                IFeature[] features = {feature};
226
//                                Coordinate nestedPoint = nestedTester.getNestedPoint();
227
//                                FPoint2D pt = new FPoint2D(nestedPoint.x, nestedPoint.y);
228
//                                IGeometry errorGeometry = ShapeFactory.createGeometry(pt);
229
//                                TopologyError error = new TopologyError(errorGeometry, this, features);
230
//                                addTopologyError(error);
231
//                        }
232
        }
233
        
234
        
235
        private void addError(IGeometry geo, IFeature feature){
236
                   IFeature[] features = {feature};
237
              TopologyError error = 
238
                      new TopologyError(geo, this, features, topology);
239
              addTopologyError(error);
240
        }
241
}