root / trunk / libraries / libTopology / src / org / gvsig / topology / topologyrules / JtsValidRule.java @ 18253
History | View | Annotate | Download (9.82 KB)
1 | 14154 | azabala | /*
|
---|---|---|---|
2 | * Created on 07-sep-2007
|
||
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 | */
|
||
50 | 13329 | azabala | package org.gvsig.topology.topologyrules; |
51 | |||
52 | 14443 | azabala | import java.util.ArrayList; |
53 | import java.util.Iterator; |
||
54 | import java.util.List; |
||
55 | 14154 | azabala | |
56 | 16256 | azabala | import org.apache.log4j.Logger; |
57 | 13329 | azabala | import org.gvsig.topology.AbstractTopologyRule; |
58 | 17054 | azabala | import org.gvsig.topology.IRuleWithClusterTolerance; |
59 | 14566 | azabala | import org.gvsig.topology.ITopologyErrorContainer; |
60 | 14443 | azabala | import org.gvsig.topology.ITopologyRule; |
61 | import org.gvsig.topology.Messages; |
||
62 | 16256 | azabala | import org.gvsig.topology.Topology; |
63 | import org.gvsig.topology.TopologyRuleFactory; |
||
64 | 14443 | azabala | import org.gvsig.topology.topologyrules.jtsisvalidrules.GeometryMustHaveValidCoordinates; |
65 | import org.gvsig.topology.topologyrules.jtsisvalidrules.GeometryMustNotHaveFewPoints; |
||
66 | 14566 | azabala | import org.gvsig.topology.topologyrules.jtsisvalidrules.IGeometryMustBeClosed; |
67 | 14443 | azabala | import org.gvsig.topology.topologyrules.jtsisvalidrules.MultiPolygonMustNotHaveNestedShells; |
68 | import org.gvsig.topology.topologyrules.jtsisvalidrules.PolygonHolesMustBeInShell; |
||
69 | import org.gvsig.topology.topologyrules.jtsisvalidrules.PolygonHolesMustNotBeNested; |
||
70 | 16256 | azabala | import org.gvsig.topology.topologyrules.jtsisvalidrules.PolygonMustHaveConnectedInterior; |
71 | 14443 | azabala | import org.gvsig.topology.topologyrules.jtsisvalidrules.PolygonMustNotHaveDuplicatedRings; |
72 | import org.gvsig.topology.topologyrules.jtsisvalidrules.PolygonMustNotHaveSelfIntersectedRings; |
||
73 | 13329 | azabala | |
74 | 14443 | azabala | import com.hardcode.gdbms.driver.exceptions.ReadDriverException; |
75 | import com.iver.cit.gvsig.fmap.core.FShape; |
||
76 | 14154 | azabala | import com.iver.cit.gvsig.fmap.core.IFeature; |
77 | 14443 | azabala | import com.iver.cit.gvsig.fmap.layers.FLyrVect; |
78 | 16256 | azabala | import com.iver.utiles.XMLEntity; |
79 | 13329 | azabala | |
80 | /**
|
||
81 | 14443 | azabala | * Any validated geometry must be a right JTS geometry.
|
82 | *
|
||
83 | * A JTS geometry to be valid must check:
|
||
84 | * <ul>
|
||
85 | * <li>Must pass IsValidOp.</li>
|
||
86 | * <li>Polygon's shells must not selfintersect.</li>
|
||
87 | * <li>Polygon's holes must not selfintersect.</li>
|
||
88 | * <li>Polygon's rings must be closed.</li>
|
||
89 | * <li>Polygon's with only three collinear points are not allowed
|
||
90 | * (this is a collapsed polygon to a line)</li>
|
||
91 | * <li>Polygon's shell must have coordinates in CCW</li>
|
||
92 | * <li>Polygon's holes must have coordinates in CCCW</li>
|
||
93 | * <li>Polygon's holes must not touch in more than one point</li>
|
||
94 | * <li>Polygon's holes could not be null</li>
|
||
95 | * <li>Polygon's holes must be contained by polygon shell</li>
|
||
96 | * <li>If a polygon has its exterior ring to null, but it has a hole, probably
|
||
97 | the order of the coordinates must be inverted.</li>
|
||
98 | <li>A polygon must not have repeated holes</li>
|
||
99 | <li>A polyline cant have two equals points.
|
||
100 | </ul>
|
||
101 | *
|
||
102 | 13329 | azabala | */
|
103 | 17054 | azabala | public class JtsValidRule extends AbstractTopologyRule implements IRuleWithClusterTolerance { |
104 | 14154 | azabala | |
105 | 16256 | azabala | private static String ruleName = Messages.getText("must_be_jts_valid"); |
106 | 14443 | azabala | |
107 | 16256 | azabala | private static Logger logger = Logger.getLogger(JtsValidRule.class.getName()); |
108 | 14443 | azabala | |
109 | List<ITopologyRule> jtsRules = new ArrayList<ITopologyRule>(); |
||
110 | |||
111 | |||
112 | 14566 | azabala | private double snapTolerance; |
113 | |||
114 | |||
115 | public JtsValidRule(FLyrVect originLyr, double snapTolerance){ |
||
116 | 16256 | azabala | this(null, originLyr, snapTolerance); |
117 | } |
||
118 | |||
119 | 16396 | azabala | public JtsValidRule(){}
|
120 | |||
121 | 16256 | azabala | public JtsValidRule(Topology topology, FLyrVect originLyr, double snapTolerance){ |
122 | super(topology, originLyr);
|
||
123 | 17054 | azabala | setClusterTolerance(snapTolerance); |
124 | 14443 | azabala | } |
125 | |||
126 | public void setOriginLyr(FLyrVect originLyr){ |
||
127 | super.setOriginLyr(originLyr);
|
||
128 | initialize(); |
||
129 | } |
||
130 | |||
131 | 14566 | azabala | public void setTopologyErrorContainer(ITopologyErrorContainer errorContainer){ |
132 | super.setTopologyErrorContainer(errorContainer);
|
||
133 | Iterator<ITopologyRule> iterator = jtsRules.iterator();
|
||
134 | while(iterator.hasNext()){
|
||
135 | ITopologyRule rule = iterator.next(); |
||
136 | rule.setTopologyErrorContainer(this.errorContainer);
|
||
137 | } |
||
138 | } |
||
139 | |||
140 | 14443 | azabala | private void initialize() { |
141 | try {
|
||
142 | int shapeType = this.getOriginLyr().getShapeType(); |
||
143 | |||
144 | switch(shapeType){
|
||
145 | case FShape.POINT:
|
||
146 | case FShape.TEXT:
|
||
147 | case FShape.MULTIPOINT:
|
||
148 | jtsRules.add(getValidCoordsRule()); |
||
149 | break;
|
||
150 | |||
151 | |||
152 | case FShape.ARC:
|
||
153 | case FShape.CIRCLE:
|
||
154 | case FShape.ELLIPSE:
|
||
155 | case FShape.LINE:
|
||
156 | jtsRules.add(getValidCoordsRule()); |
||
157 | jtsRules.add(getFewPointsRule()); |
||
158 | break;
|
||
159 | |||
160 | |||
161 | case FShape.MULTI://If type is multi, it will have all rules |
||
162 | jtsRules.add(getValidCoordsRule()); |
||
163 | jtsRules.add(getFewPointsRule()); |
||
164 | jtsRules.add(getClosedRingsRule()); |
||
165 | jtsRules.add(getHolesInShellRule()); |
||
166 | jtsRules.add(getHolesNotNestedRule()); |
||
167 | jtsRules.add(getIntersectingRingsRule()); |
||
168 | jtsRules.add(getNestedShellsRule()); |
||
169 | jtsRules.add(getNotDuplicatedRingsRule()); |
||
170 | jtsRules.add(getSelfIntersectingRingRule()); |
||
171 | |||
172 | break;
|
||
173 | |||
174 | case FShape.POLYGON://polygon geometries wont check for nested shells |
||
175 | jtsRules.add(getValidCoordsRule()); |
||
176 | jtsRules.add(getFewPointsRule()); |
||
177 | jtsRules.add(getClosedRingsRule()); |
||
178 | jtsRules.add(getHolesInShellRule()); |
||
179 | jtsRules.add(getHolesNotNestedRule()); |
||
180 | jtsRules.add(getIntersectingRingsRule()); |
||
181 | jtsRules.add(getNotDuplicatedRingsRule()); |
||
182 | jtsRules.add(getSelfIntersectingRingRule()); |
||
183 | break;
|
||
184 | |||
185 | case FShape.NULL:
|
||
186 | return;
|
||
187 | } |
||
188 | |||
189 | } catch (ReadDriverException e) {
|
||
190 | 16256 | azabala | logger.error("Error initializing JTS valid rule. "+
|
191 | "Couldnt read shape type of layer", e);
|
||
192 | 14443 | azabala | } |
193 | } |
||
194 | |||
195 | |||
196 | private GeometryMustHaveValidCoordinates getValidCoordsRule(){
|
||
197 | 16256 | azabala | GeometryMustHaveValidCoordinates rule = new GeometryMustHaveValidCoordinates(topology, originLyr);
|
198 | 14443 | azabala | rule.setTopologyErrorContainer(this.getTopologyErrorContainer());
|
199 | return rule;
|
||
200 | } |
||
201 | |||
202 | private GeometryMustNotHaveFewPoints getFewPointsRule(){
|
||
203 | 16256 | azabala | GeometryMustNotHaveFewPoints rule = new GeometryMustNotHaveFewPoints(topology, originLyr);
|
204 | 14443 | azabala | rule.setTopologyErrorContainer(this.getTopologyErrorContainer());
|
205 | return rule;
|
||
206 | 14154 | azabala | |
207 | } |
||
208 | 14443 | azabala | |
209 | 14566 | azabala | private IGeometryMustBeClosed getClosedRingsRule(){
|
210 | 16256 | azabala | IGeometryMustBeClosed rule = new IGeometryMustBeClosed(topology, originLyr, snapTolerance);
|
211 | 14443 | azabala | rule.setTopologyErrorContainer(this.getTopologyErrorContainer());
|
212 | return rule;
|
||
213 | 14154 | azabala | } |
214 | 14443 | azabala | |
215 | private MultiPolygonMustNotHaveNestedShells getNestedShellsRule(){
|
||
216 | MultiPolygonMustNotHaveNestedShells rule = |
||
217 | 16256 | azabala | new MultiPolygonMustNotHaveNestedShells(topology, originLyr);
|
218 | 14443 | azabala | rule.setTopologyErrorContainer(this.getTopologyErrorContainer());
|
219 | return rule;
|
||
220 | 14154 | azabala | |
221 | } |
||
222 | 14443 | azabala | |
223 | private PolygonHolesMustBeInShell getHolesInShellRule(){
|
||
224 | 16256 | azabala | PolygonHolesMustBeInShell rule = new PolygonHolesMustBeInShell(topology, originLyr, snapTolerance);
|
225 | 14443 | azabala | rule.setTopologyErrorContainer(this.getTopologyErrorContainer());
|
226 | return rule;
|
||
227 | } |
||
228 | |||
229 | private PolygonHolesMustNotBeNested getHolesNotNestedRule(){
|
||
230 | 16256 | azabala | PolygonHolesMustNotBeNested rule = new PolygonHolesMustNotBeNested(topology, originLyr);
|
231 | 14443 | azabala | rule.setTopologyErrorContainer(this.getTopologyErrorContainer());
|
232 | return rule;
|
||
233 | } |
||
234 | |||
235 | private PolygonMustNotHaveDuplicatedRings getNotDuplicatedRingsRule(){
|
||
236 | 14566 | azabala | PolygonMustNotHaveDuplicatedRings rule = |
237 | 16256 | azabala | new PolygonMustNotHaveDuplicatedRings(topology, originLyr, snapTolerance);
|
238 | 14443 | azabala | rule.setTopologyErrorContainer(this.getTopologyErrorContainer());
|
239 | return rule;
|
||
240 | } |
||
241 | |||
242 | 16256 | azabala | private PolygonMustHaveConnectedInterior getIntersectingRingsRule(){
|
243 | PolygonMustHaveConnectedInterior rule = new PolygonMustHaveConnectedInterior(topology, originLyr);
|
||
244 | 14443 | azabala | rule.setTopologyErrorContainer(this.getTopologyErrorContainer());
|
245 | return rule;
|
||
246 | } |
||
247 | |||
248 | private PolygonMustNotHaveSelfIntersectedRings getSelfIntersectingRingRule(){
|
||
249 | 16256 | azabala | PolygonMustNotHaveSelfIntersectedRings rule = new PolygonMustNotHaveSelfIntersectedRings(topology, originLyr, snapTolerance);
|
250 | 14443 | azabala | rule.setTopologyErrorContainer(this.getTopologyErrorContainer());
|
251 | return rule;
|
||
252 | } |
||
253 | |||
254 | |||
255 | public void validateFeature(IFeature feature) { |
||
256 | Iterator<ITopologyRule> it = this.jtsRules.iterator(); |
||
257 | while(it.hasNext()){
|
||
258 | ITopologyRule rule = it.next(); |
||
259 | rule.validateFeature(feature); |
||
260 | } |
||
261 | } |
||
262 | 14154 | azabala | |
263 | 18253 | azabala | public String getName() { |
264 | 14443 | azabala | return ruleName;
|
265 | 14154 | azabala | } |
266 | 14566 | azabala | /*
|
267 | * This rule accepts point, line and polygon layers.
|
||
268 | * TODO Maybe must we check for getNumGeometries() > 0
|
||
269 | * for layer??
|
||
270 | *
|
||
271 | * */
|
||
272 | 14443 | azabala | public void checkPreconditions() { |
273 | 14154 | azabala | } |
274 | 16256 | azabala | |
275 | public XMLEntity getXMLEntity(){
|
||
276 | XMLEntity xml = super.getXMLEntity();
|
||
277 | xml.putProperty("numberOfRules", jtsRules.size());
|
||
278 | Iterator<ITopologyRule> rulesIt = jtsRules.iterator();
|
||
279 | while(rulesIt.hasNext()){
|
||
280 | ITopologyRule rule = rulesIt.next(); |
||
281 | xml.addChild(rule.getXMLEntity()); |
||
282 | } |
||
283 | return xml;
|
||
284 | } |
||
285 | |||
286 | public void setXMLEntity(XMLEntity xml){ |
||
287 | super.setXMLEntity(xml);
|
||
288 | if(xml.contains("numberOfRules")){ |
||
289 | int numberOfRules = xml.getIntProperty("numberOfRules"); |
||
290 | for(int i = 0; i < numberOfRules; i++){ |
||
291 | XMLEntity subRuleXML = xml.getChild(i); |
||
292 | //TODO Incluir llamada a RuleFactory y add(rule)
|
||
293 | 16320 | azabala | ITopologyRule rule = TopologyRuleFactory.createFromXML(topology, subRuleXML); |
294 | 16256 | azabala | jtsRules.add(rule); |
295 | }//for
|
||
296 | }//if
|
||
297 | } |
||
298 | 17054 | azabala | |
299 | public double getClusterTolerance() { |
||
300 | return this.snapTolerance; |
||
301 | } |
||
302 | |||
303 | public void setClusterTolerance(double clusterTolerance) { |
||
304 | this.snapTolerance = clusterTolerance;
|
||
305 | initialize(); |
||
306 | } |
||
307 | 13329 | azabala | } |