Statistics
| Revision:

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

History | View | Annotate | Download (7.92 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 org.gvsig.jts.JtsUtil;
52
import org.gvsig.topology.AbstractTopologyRule;
53
import org.gvsig.topology.Messages;
54
import org.gvsig.topology.Topology;
55
import org.gvsig.topology.TopologyError;
56
import org.gvsig.topology.TopologyRuleDefinitionException;
57
import org.gvsig.topology.topologyrules.JtsValidRule;
58

    
59
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
60
import com.iver.cit.gvsig.fmap.core.FPoint2D;
61
import com.iver.cit.gvsig.fmap.core.FShape;
62
import com.iver.cit.gvsig.fmap.core.IFeature;
63
import com.iver.cit.gvsig.fmap.core.IGeometry;
64
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
65
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
66
import com.vividsolutions.jts.algorithm.CGAlgorithms;
67
import com.vividsolutions.jts.geom.Coordinate;
68
import com.vividsolutions.jts.geom.Geometry;
69
import com.vividsolutions.jts.geom.GeometryCollection;
70
import com.vividsolutions.jts.geom.LinearRing;
71
import com.vividsolutions.jts.geom.MultiPolygon;
72
import com.vividsolutions.jts.geom.Polygon;
73
import com.vividsolutions.jts.geomgraph.GeometryGraph;
74

    
75
public class MultiPolygonMustNotHaveNestedShells extends AbstractTopologyRule {
76

    
77
        JtsValidRule parentRule;
78
        
79
        public JtsValidRule getParentRule() {
80
                return parentRule;
81
        }
82

    
83
        public void setParentRule(JtsValidRule parentRule) {
84
                this.parentRule = parentRule;
85
        }
86

    
87
        public MultiPolygonMustNotHaveNestedShells(Topology topology,
88
                        FLyrVect originLyr) {
89
                super(topology, originLyr);
90
        }
91
        
92
        public MultiPolygonMustNotHaveNestedShells(FLyrVect originLyr) {
93
                super(originLyr);
94
        }
95
        
96
        public MultiPolygonMustNotHaveNestedShells(){}
97

    
98
        public String getName() {
99
                return Messages.getText("POLYGON_MUST_NOT_HAVE_DUPLICATED_RINGS");
100
        }
101

    
102
        public void checkPreconditions() throws TopologyRuleDefinitionException {
103
                int shapeType;
104
                try {
105
                        shapeType = this.originLyr.getShapeType();
106
                        if (shapeType != FShape.MULTI)
107
                                throw new TopologyRuleDefinitionException(
108
                                                "La regla ShellsNotNested solo aplica sobre multipoligonos");
109
                } catch (ReadDriverException e) {
110
                        throw new TopologyRuleDefinitionException(
111
                                        "Error al tratar de verificar el tipo de geometria");
112
                }
113
        }
114

    
115
        private void checkShellsNotNested(MultiPolygon mp, GeometryGraph graph,
116
                        IFeature feature) {
117
                for (int i = 0; i < mp.getNumGeometries(); i++) {
118
                        Polygon p = (Polygon) mp.getGeometryN(i);
119
                        LinearRing shell = (LinearRing) p.getExteriorRing();
120
                        for (int j = 0; j < mp.getNumGeometries(); j++) {
121
                                if (i == j)
122
                                        continue;
123
                                Polygon p2 = (Polygon) mp.getGeometryN(j);
124
                                checkShellNotNested(shell, p2, graph, feature);
125
                        }// for
126
                }// for
127
        }
128

    
129
        /**
130
         * Check if a shell is incorrectly nested within a polygon. This is the case
131
         * if the shell is inside the polygon shell, but not inside a polygon hole.
132
         * (If the shell is inside a polygon hole, the nesting is valid.)
133
         * <p>
134
         * The algorithm used relies on the fact that the rings must be properly
135
         * contained. E.g. they cannot partially overlap (this has been previously
136
         * checked by <code>checkRelateConsistency</code> )
137
         */
138
        private void checkShellNotNested(LinearRing shell, Polygon p,
139
                        GeometryGraph graph, IFeature feature) {
140

    
141
                Coordinate[] shellPts = shell.getCoordinates();
142
                // test if shell is inside polygon shell
143
                LinearRing polyShell = (LinearRing) p.getExteriorRing();
144
                Coordinate[] polyPts = polyShell.getCoordinates();
145
                Coordinate shellPt = JtsUtil.findPtNotNode(shellPts, polyShell, graph);
146
                // if no point could be found, we can assume that the shell is outside
147
                // the polygon
148
                if (shellPt == null)
149
                        return;
150
                boolean insidePolyShell = CGAlgorithms.isPointInRing(shellPt, polyPts);
151
                if (!insidePolyShell)
152
                        return;
153

    
154
                // if no holes, this is an error!
155
                if (p.getNumInteriorRing() <= 0) {
156
                        FPoint2D point = new FPoint2D(shellPt.x, shellPt.y);
157
                        IGeometry errorGeometry = ShapeFactory.createGeometry(point);
158
                        AbstractTopologyRule violatedRule = null;
159
                        if(this.parentRule != null)
160
                                violatedRule = parentRule;
161
                        else
162
                                violatedRule = this;
163
                        TopologyError topologyError = 
164
                                new TopologyError(errorGeometry,violatedRule, feature, topology);
165
                        addTopologyError(topologyError);
166
                }
167

    
168
                /**
169
                 * Check if the shell is inside one of the holes. This is the case if
170
                 * one of the calls to checkShellInsideHole returns a null coordinate.
171
                 * Otherwise, the shell is not properly contained in a hole, which is an
172
                 * error.
173
                 */
174
                Coordinate badNestedPt = null;
175
                for (int i = 0; i < p.getNumInteriorRing(); i++) {
176
                        LinearRing hole = (LinearRing) p.getInteriorRingN(i);
177
                        badNestedPt = checkShellInsideHole(shell, hole, graph);
178
                        if (badNestedPt == null)
179
                                return;
180
                }
181
                FPoint2D point = new FPoint2D(badNestedPt.x, badNestedPt.y);
182
                IGeometry errorGeometry = ShapeFactory.createGeometry(point);
183
                AbstractTopologyRule violatedRule = null;
184
                if(this.parentRule != null)
185
                        violatedRule = parentRule;
186
                else
187
                        violatedRule = this;
188
                TopologyError error = 
189
                        new TopologyError(errorGeometry, violatedRule, feature, topology);
190
                addTopologyError(error);
191
        }
192

    
193
        private Coordinate checkShellInsideHole(LinearRing shell, LinearRing hole,
194
                        GeometryGraph graph) {
195
                Coordinate[] shellPts = shell.getCoordinates();
196
                Coordinate[] holePts = hole.getCoordinates();
197
                // TODO: improve performance of this - by sorting pointlists for
198
                // instance?
199
                Coordinate shellPt = JtsUtil.findPtNotNode(shellPts, hole, graph);
200
                // if point is on shell but not hole, check that the shell is inside the
201
                // hole
202
                if (shellPt != null) {
203
                        boolean insideHole = CGAlgorithms.isPointInRing(shellPt, holePts);
204
                        if (!insideHole) {
205
                                return shellPt;
206
                        }
207
                }
208
                Coordinate holePt = JtsUtil.findPtNotNode(holePts, shell, graph);
209
                // if point is on hole but not shell, check that the hole is outside the
210
                // shell
211
                if (holePt != null) {
212
                        boolean insideShell = CGAlgorithms.isPointInRing(holePt, shellPts);
213
                        if (insideShell) {
214
                                return holePt;
215
                        }
216
                        return null;
217
                }
218
                return null;
219
        }
220

    
221
        
222

    
223
        public void validateFeature(IFeature feature) {
224
                Geometry geometry = feature.getGeometry().toJTSGeometry();
225
                if(geometry instanceof MultiPolygon){
226
                        MultiPolygon multiPolygon = (MultiPolygon) geometry;
227
                        checkShellsNotNested(multiPolygon, new GeometryGraph(0, multiPolygon), feature);
228
                }else if(geometry instanceof GeometryCollection){
229
                        GeometryCollection geomCol = (GeometryCollection) geometry;
230
                        MultiPolygon multiPol = JtsUtil.convertIfPossible(geomCol);
231
                        if(multiPol.getNumGeometries() > 0)
232
                        {
233
                                checkShellsNotNested(multiPol, new GeometryGraph(0, multiPol), feature );
234
                        }
235
                }        
236
        }
237
        
238
        
239
}