Statistics
| Revision:

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

History | View | Annotate | Download (7.47 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

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

    
74
public class MultiPolygonMustNotHaveNestedShells extends AbstractTopologyRule {
75

    
76
        public MultiPolygonMustNotHaveNestedShells(Topology topology,
77
                        FLyrVect originLyr) {
78
                super(topology, originLyr);
79
        }
80
        
81
        public MultiPolygonMustNotHaveNestedShells(FLyrVect originLyr) {
82
                super(originLyr);
83
        }
84
        
85
        public MultiPolygonMustNotHaveNestedShells(){}
86

    
87
        public String getDescription() {
88
                return Messages.getText("POLYGON_MUST_NOT_HAVE_DUPLICATED_RINGS");
89
        }
90

    
91
        public void checkPreconditions() throws TopologyRuleDefinitionException {
92
                int shapeType;
93
                try {
94
                        shapeType = this.originLyr.getShapeType();
95
                        if (shapeType != FShape.MULTI)
96
                                throw new TopologyRuleDefinitionException(
97
                                                "La regla ShellsNotNested solo aplica sobre multipoligonos");
98
                } catch (ReadDriverException e) {
99
                        throw new TopologyRuleDefinitionException(
100
                                        "Error al tratar de verificar el tipo de geometria");
101
                }
102
        }
103

    
104
        private void checkShellsNotNested(MultiPolygon mp, GeometryGraph graph,
105
                        IFeature feature) {
106
                for (int i = 0; i < mp.getNumGeometries(); i++) {
107
                        Polygon p = (Polygon) mp.getGeometryN(i);
108
                        LinearRing shell = (LinearRing) p.getExteriorRing();
109
                        for (int j = 0; j < mp.getNumGeometries(); j++) {
110
                                if (i == j)
111
                                        continue;
112
                                Polygon p2 = (Polygon) mp.getGeometryN(j);
113
                                checkShellNotNested(shell, p2, graph, feature);
114
                        }// for
115
                }// for
116
        }
117

    
118
        /**
119
         * Check if a shell is incorrectly nested within a polygon. This is the case
120
         * if the shell is inside the polygon shell, but not inside a polygon hole.
121
         * (If the shell is inside a polygon hole, the nesting is valid.)
122
         * <p>
123
         * The algorithm used relies on the fact that the rings must be properly
124
         * contained. E.g. they cannot partially overlap (this has been previously
125
         * checked by <code>checkRelateConsistency</code> )
126
         */
127
        private void checkShellNotNested(LinearRing shell, Polygon p,
128
                        GeometryGraph graph, IFeature feature) {
129

    
130
                Coordinate[] shellPts = shell.getCoordinates();
131
                // test if shell is inside polygon shell
132
                LinearRing polyShell = (LinearRing) p.getExteriorRing();
133
                Coordinate[] polyPts = polyShell.getCoordinates();
134
                Coordinate shellPt = JtsUtil.findPtNotNode(shellPts, polyShell, graph);
135
                // if no point could be found, we can assume that the shell is outside
136
                // the polygon
137
                if (shellPt == null)
138
                        return;
139
                boolean insidePolyShell = CGAlgorithms.isPointInRing(shellPt, polyPts);
140
                if (!insidePolyShell)
141
                        return;
142

    
143
                // if no holes, this is an error!
144
                if (p.getNumInteriorRing() <= 0) {
145
                        IFeature[] features = { feature };
146
                        FPoint2D point = new FPoint2D(shellPt.x, shellPt.y);
147
                        IGeometry errorGeometry = ShapeFactory.createGeometry(point);
148
                        TopologyError topologyError = 
149
                                new TopologyError(errorGeometry,this, features, topology);
150
                        addTopologyError(topologyError);
151
                }
152

    
153
                /**
154
                 * Check if the shell is inside one of the holes. This is the case if
155
                 * one of the calls to checkShellInsideHole returns a null coordinate.
156
                 * Otherwise, the shell is not properly contained in a hole, which is an
157
                 * error.
158
                 */
159
                Coordinate badNestedPt = null;
160
                for (int i = 0; i < p.getNumInteriorRing(); i++) {
161
                        LinearRing hole = (LinearRing) p.getInteriorRingN(i);
162
                        badNestedPt = checkShellInsideHole(shell, hole, graph);
163
                        if (badNestedPt == null)
164
                                return;
165
                }
166
                IFeature[] features = { feature };
167
                FPoint2D point = new FPoint2D(badNestedPt.x, badNestedPt.y);
168
                IGeometry errorGeometry = ShapeFactory.createGeometry(point);
169
                TopologyError error = 
170
                        new TopologyError(errorGeometry, this, features, topology);
171
                addTopologyError(error);
172
        }
173

    
174
        private Coordinate checkShellInsideHole(LinearRing shell, LinearRing hole,
175
                        GeometryGraph graph) {
176
                Coordinate[] shellPts = shell.getCoordinates();
177
                Coordinate[] holePts = hole.getCoordinates();
178
                // TODO: improve performance of this - by sorting pointlists for
179
                // instance?
180
                Coordinate shellPt = JtsUtil.findPtNotNode(shellPts, hole, graph);
181
                // if point is on shell but not hole, check that the shell is inside the
182
                // hole
183
                if (shellPt != null) {
184
                        boolean insideHole = CGAlgorithms.isPointInRing(shellPt, holePts);
185
                        if (!insideHole) {
186
                                return shellPt;
187
                        }
188
                }
189
                Coordinate holePt = JtsUtil.findPtNotNode(holePts, shell, graph);
190
                // if point is on hole but not shell, check that the hole is outside the
191
                // shell
192
                if (holePt != null) {
193
                        boolean insideShell = CGAlgorithms.isPointInRing(holePt, shellPts);
194
                        if (insideShell) {
195
                                return holePt;
196
                        }
197
                        return null;
198
                }
199
                return null;
200
        }
201

    
202
        
203

    
204
        public void validateFeature(IFeature feature) {
205
                Geometry geometry = feature.getGeometry().toJTSGeometry();
206
                if(geometry instanceof MultiPolygon){
207
                        MultiPolygon multiPolygon = (MultiPolygon) geometry;
208
                        checkShellsNotNested(multiPolygon, new GeometryGraph(0, multiPolygon), feature);
209
                }else if(geometry instanceof GeometryCollection){
210
                        GeometryCollection geomCol = (GeometryCollection) geometry;
211
                        MultiPolygon multiPol = JtsUtil.convertIfPossible(geomCol);
212
                        if(multiPol.getNumGeometries() > 0)
213
                        {
214
                                checkShellsNotNested(multiPol, new GeometryGraph(0, multiPol), feature );
215
                        }
216
                }        
217
        }
218
        
219
        
220
}