svn-gvsig-desktop / trunk / libraries / libTopology / src / org / gvsig / topology / topologyrules / jtsisvalidrules / PolygonHolesMustNotBeNested.java @ 18995
History | View | Annotate | Download (8.52 KB)
1 | 14442 | azabala | /*
|
---|---|---|---|
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 | 16256 | azabala | 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 | 14442 | azabala | import org.gvsig.jts.JtsUtil; |
58 | import org.gvsig.topology.AbstractTopologyRule; |
||
59 | import org.gvsig.topology.Messages; |
||
60 | 16256 | azabala | import org.gvsig.topology.Topology; |
61 | 14442 | azabala | import org.gvsig.topology.TopologyError; |
62 | import org.gvsig.topology.TopologyRuleDefinitionException; |
||
63 | 18995 | azabala | import org.gvsig.topology.topologyrules.JtsValidRule; |
64 | 14442 | azabala | |
65 | 16256 | azabala | import com.hardcode.gdbms.driver.exceptions.ReadDriverException; |
66 | import com.iver.cit.gvsig.fmap.core.FShape; |
||
67 | 14442 | azabala | import com.iver.cit.gvsig.fmap.core.IFeature; |
68 | import com.iver.cit.gvsig.fmap.core.IGeometry; |
||
69 | 16256 | azabala | import com.iver.cit.gvsig.fmap.layers.FLyrVect; |
70 | import com.vividsolutions.jts.algorithms.SnapCGAlgorithms; |
||
71 | 14442 | azabala | import com.vividsolutions.jts.geom.Coordinate; |
72 | import com.vividsolutions.jts.geom.Geometry; |
||
73 | import com.vividsolutions.jts.geom.GeometryCollection; |
||
74 | import com.vividsolutions.jts.geom.LinearRing; |
||
75 | import com.vividsolutions.jts.geom.MultiPolygon; |
||
76 | import com.vividsolutions.jts.geom.Polygon; |
||
77 | import com.vividsolutions.jts.geomgraph.GeometryGraph; |
||
78 | 16256 | azabala | import com.vividsolutions.jts.precision.EnhancedPrecisionOp; |
79 | 14442 | azabala | |
80 | public class PolygonHolesMustNotBeNested extends AbstractTopologyRule { |
||
81 | 16256 | azabala | |
82 | 18995 | azabala | private JtsValidRule parentRule;
|
83 | |||
84 | 16256 | azabala | public PolygonHolesMustNotBeNested(FLyrVect originLyr){
|
85 | super(originLyr);
|
||
86 | } |
||
87 | |||
88 | public PolygonHolesMustNotBeNested(Topology topology, FLyrVect originLyr){
|
||
89 | super(topology, originLyr);
|
||
90 | } |
||
91 | |||
92 | 16396 | azabala | public PolygonHolesMustNotBeNested(){
|
93 | |||
94 | } |
||
95 | |||
96 | 18253 | azabala | public String getName() { |
97 | 14442 | azabala | return Messages.getText("POLYGON_MUST_NOT_HAVE_DUPLICATED_RINGS"); |
98 | } |
||
99 | |||
100 | public void checkPreconditions() throws TopologyRuleDefinitionException { |
||
101 | 16256 | azabala | int shapeType;
|
102 | try {
|
||
103 | shapeType = this.originLyr.getShapeType();
|
||
104 | int numDimensions = FGeometryUtil.getDimensions(shapeType);
|
||
105 | if(numDimensions != 2) |
||
106 | throw new TopologyRuleDefinitionException("HolesNotNested solo aplica sobre capas de dimension 2"); |
||
107 | } catch (ReadDriverException e) {
|
||
108 | throw new TopologyRuleDefinitionException( |
||
109 | "Error al tratar de verificar el tipo de geometria");
|
||
110 | } |
||
111 | 14442 | azabala | } |
112 | |||
113 | public void validateFeature(IFeature feature) { |
||
114 | 16256 | azabala | Geometry jtsGeo = FGeometryUtil.toJtsPolygon((FShape)feature.getGeometry().getInternalShape()); |
115 | 14442 | azabala | if (jtsGeo instanceof Polygon) { |
116 | 16256 | azabala | checkHoles((Polygon)jtsGeo, new GeometryGraph(0, jtsGeo), feature); |
117 | 14442 | azabala | } else if (jtsGeo instanceof MultiPolygon) { |
118 | MultiPolygon multiPoly = (MultiPolygon)jtsGeo; |
||
119 | for(int i = 0; i < multiPoly.getNumGeometries(); i++){ |
||
120 | Polygon polygon = (Polygon) multiPoly.getGeometryN(i); |
||
121 | 16256 | azabala | checkHoles( polygon, new GeometryGraph(0, polygon), feature); |
122 | 14442 | azabala | } |
123 | }else if(jtsGeo instanceof GeometryCollection){ |
||
124 | MultiPolygon multiPoly = JtsUtil.convertIfPossible((GeometryCollection) jtsGeo); |
||
125 | for(int i = 0; i < multiPoly.getNumGeometries(); i++){ |
||
126 | Polygon polygon = (Polygon) multiPoly.getGeometryN(i); |
||
127 | 16256 | azabala | checkHoles( polygon, new GeometryGraph(0, polygon), feature); |
128 | 14442 | azabala | } |
129 | } |
||
130 | } |
||
131 | |||
132 | 16256 | azabala | private void checkHoles(Polygon p, GeometryGraph graph, IFeature feature) { |
133 | /*
|
||
134 | * Holes only can touch in a single point.
|
||
135 | * If this condition is not passed, we wont check for nested holes
|
||
136 | */
|
||
137 | boolean disjointHoles = true; |
||
138 | |||
139 | class MapEntry { |
||
140 | int i;
|
||
141 | int j;
|
||
142 | |||
143 | MapEntry(int i, int j){ |
||
144 | this.i = i;
|
||
145 | this.j = j;
|
||
146 | } |
||
147 | |||
148 | public boolean equals(Object o){ |
||
149 | if(! (o instanceof MapEntry)) |
||
150 | return false; |
||
151 | MapEntry other = (MapEntry)o; |
||
152 | |||
153 | return (other.i == i && other.j == j) || (other.i == j && other.j == i);
|
||
154 | } |
||
155 | |||
156 | public int hashCode(){ |
||
157 | return 1; |
||
158 | } |
||
159 | 14442 | azabala | } |
160 | 16256 | azabala | HashMap<MapEntry, MapEntry> checkedHoles = new HashMap<MapEntry, MapEntry>(); |
161 | |||
162 | for (int i = 0; i < p.getNumInteriorRing(); i++) { |
||
163 | LinearRing innerHole = (LinearRing) p.getInteriorRingN(i); |
||
164 | Polygon innerHoleAsPoly = JtsUtil.geomFactory.createPolygon(innerHole, null); |
||
165 | for (int j = 0; j < p.getNumInteriorRing(); j++) { |
||
166 | if ( i == j)
|
||
167 | continue;
|
||
168 | |||
169 | MapEntry entry = new MapEntry(i, j);
|
||
170 | if(checkedHoles.get(entry) != null) |
||
171 | continue;
|
||
172 | |||
173 | checkedHoles.put(entry, entry); |
||
174 | |||
175 | LinearRing testHole = (LinearRing) p.getInteriorRingN(j); |
||
176 | Polygon testHoleAsPoly = JtsUtil.geomFactory.createPolygon(testHole, null); |
||
177 | //TODO Use PreparedGeometry in the next stable release of JTS
|
||
178 | Geometry intersection = EnhancedPrecisionOp.intersection(innerHoleAsPoly, testHoleAsPoly); |
||
179 | Coordinate[] intersectionCoords = intersection.getCoordinates();
|
||
180 | if(intersectionCoords.length > 1){ |
||
181 | disjointHoles = false;
|
||
182 | Point2D[] pt2d = FGeometryUtil.getCoordinatesAsPoint2D(intersectionCoords); |
||
183 | IGeometry errorGeometry = FGeometryUtil.createFPolygon(pt2d); |
||
184 | addError(errorGeometry, feature); |
||
185 | } |
||
186 | }//for i
|
||
187 | }//for j
|
||
188 | |||
189 | if(! disjointHoles)
|
||
190 | return;
|
||
191 | |||
192 | |||
193 | /*
|
||
194 | * Holes must not be nested (a hole inside a hole)
|
||
195 | * */
|
||
196 | List<Coordinate> insidePoints = new ArrayList<Coordinate>(); |
||
197 | for (int i = 0; i < p.getNumInteriorRing(); i++) { |
||
198 | LinearRing innerHole = (LinearRing) p.getInteriorRingN(i); |
||
199 | Coordinate[] innerHolePts = innerHole.getCoordinates();
|
||
200 | for (int j = 0; j < p.getNumInteriorRing(); j++) { |
||
201 | // don't test hole against itself!
|
||
202 | if (i == j) continue; |
||
203 | |||
204 | LinearRing searchHole = (LinearRing) p.getInteriorRingN(j); |
||
205 | // if envelopes don't overlap, holes are not nested
|
||
206 | if (! innerHole.getEnvelopeInternal().intersects(searchHole.getEnvelopeInternal()))
|
||
207 | continue;
|
||
208 | |||
209 | Coordinate[] searchHolePts = searchHole.getCoordinates();
|
||
210 | Coordinate innerholePt = JtsUtil.findPtNotNode(innerHolePts, searchHole, graph); |
||
211 | |||
212 | boolean inside = SnapCGAlgorithms.isPointInRing(innerholePt, searchHolePts);
|
||
213 | if ( inside ) {
|
||
214 | insidePoints.add(innerholePt); |
||
215 | }//if
|
||
216 | |||
217 | }//for j
|
||
218 | if(insidePoints.size() > 0){ |
||
219 | Coordinate[] coords = new Coordinate[insidePoints.size()]; |
||
220 | insidePoints.toArray(coords); |
||
221 | Point2D[] pt2d = FGeometryUtil.getCoordinatesAsPoint2D(coords); |
||
222 | IGeometry geometry = FGeometryUtil.createFPolygon(pt2d); |
||
223 | addError(geometry, feature); |
||
224 | } |
||
225 | |||
226 | }//for i
|
||
227 | // if (!isNonNested) {
|
||
228 | // IFeature[] features = {feature};
|
||
229 | // Coordinate nestedPoint = nestedTester.getNestedPoint();
|
||
230 | // FPoint2D pt = new FPoint2D(nestedPoint.x, nestedPoint.y);
|
||
231 | // IGeometry errorGeometry = ShapeFactory.createGeometry(pt);
|
||
232 | // TopologyError error = new TopologyError(errorGeometry, this, features);
|
||
233 | // addTopologyError(error);
|
||
234 | // }
|
||
235 | 14442 | azabala | } |
236 | 16256 | azabala | |
237 | |||
238 | private void addError(IGeometry geo, IFeature feature){ |
||
239 | 18995 | azabala | AbstractTopologyRule violatedRule = null;
|
240 | if(this.parentRule != null) |
||
241 | violatedRule = parentRule; |
||
242 | else
|
||
243 | violatedRule = this;
|
||
244 | 16320 | azabala | TopologyError error = |
245 | 18995 | azabala | new TopologyError(geo, violatedRule, feature, topology);
|
246 | 16256 | azabala | addTopologyError(error); |
247 | } |
||
248 | 18995 | azabala | |
249 | public JtsValidRule getParentRule() {
|
||
250 | return parentRule;
|
||
251 | } |
||
252 | |||
253 | public void setParentRule(JtsValidRule parentRule) { |
||
254 | this.parentRule = parentRule;
|
||
255 | } |
||
256 | 14442 | azabala | } |