Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libTopology / src / org / gvsig / topology / topologyrules / LineMustNotHavePseudonodes.java @ 23156

History | View | Annotate | Download (10.9 KB)

1
/*
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
package org.gvsig.topology.topologyrules;
51

    
52
import java.awt.Color;
53
import java.awt.geom.Rectangle2D;
54
import java.util.ArrayList;
55
import java.util.List;
56

    
57
import org.gvsig.fmap.core.FGeometryUtil;
58
import org.gvsig.fmap.core.NewFConverter;
59
import org.gvsig.jts.JtsUtil;
60
import org.gvsig.jts.SnappingCoordinateMapWithCounter;
61
import org.gvsig.topology.AbstractTopologyRule;
62
import org.gvsig.topology.IRuleWithClusterTolerance;
63
import org.gvsig.topology.ITopologyErrorFix;
64
import org.gvsig.topology.Messages;
65
import org.gvsig.topology.Topology;
66
import org.gvsig.topology.TopologyError;
67
import org.gvsig.topology.TopologyRuleDefinitionException;
68
import org.gvsig.topology.errorfixes.RemovePseudoNodeFix;
69

    
70
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
71
import com.iver.cit.gvsig.fmap.core.FShape;
72
import com.iver.cit.gvsig.fmap.core.IFeature;
73
import com.iver.cit.gvsig.fmap.core.IGeometry;
74
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
75
import com.iver.cit.gvsig.fmap.core.SymbologyFactory;
76
import com.iver.cit.gvsig.fmap.core.symbols.MultiShapeSymbol;
77
import com.iver.cit.gvsig.fmap.drivers.IFeatureIterator;
78
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
79
import com.iver.cit.gvsig.util.SnappingCoordinateMap;
80
import com.vividsolutions.jts.geom.Coordinate;
81
import com.vividsolutions.jts.geom.Envelope;
82
import com.vividsolutions.jts.geom.Geometry;
83
import com.vividsolutions.jts.geom.GeometryCollection;
84
import com.vividsolutions.jts.geom.LineString;
85
import com.vividsolutions.jts.geom.MultiLineString;
86

    
87
/**
88
 * This rule checks that lines of a line layer dont have pseudonodes ends (a
89
 * point that touchs one only another line). <br>
90
 * If a dangling node is an end point of a line that doesnt touch another line,
91
 * a pseudonode is a point that only touch one line. (we could dissolve these
92
 * two lines).
93
 */
94
public class LineMustNotHavePseudonodes extends AbstractTopologyRule implements
95
                IRuleWithClusterTolerance {
96

    
97
        final static String RULE_NAME = Messages.getText("must_not_have_pseudonodes");
98

    
99
        double clusterTol;
100
        
101
        protected SnappingCoordinateMap pseudoNodesCoordMap = null;
102
        
103
        /**
104
         * Symbol for topology errors caused by a violation of this rule.
105
         */
106
        protected MultiShapeSymbol errorSymbol = DEFAULT_ERROR_SYMBOL;
107
        
108
        private static List<ITopologyErrorFix> automaticErrorFixes =
109
                new ArrayList<ITopologyErrorFix>();
110
        static{
111
                automaticErrorFixes.add(new RemovePseudoNodeFix());
112
                
113
        }
114
        
115
        protected static final Color DEFAULT_ERROR_COLOR = Color.PINK;
116
        
117
        
118
        protected static final MultiShapeSymbol DEFAULT_ERROR_SYMBOL = 
119
                (MultiShapeSymbol) SymbologyFactory.createDefaultSymbolByShapeType(FShape.MULTI, 
120
                                                                                        DEFAULT_ERROR_COLOR);
121
        static{
122
                DEFAULT_ERROR_SYMBOL.setDescription(RULE_NAME);
123
                DEFAULT_ERROR_SYMBOL.setSize(3);
124
        }
125
        
126

    
127
        public LineMustNotHavePseudonodes(Topology topology, FLyrVect originLyr,
128
                        double clusterTolerance) {
129
                super(topology, originLyr);
130
                setClusterTolerance(clusterTolerance);
131
                
132

    
133
        }
134

    
135
        public LineMustNotHavePseudonodes() {
136
        }
137

    
138
        public String getName() {
139
                return RULE_NAME;
140
        }
141

    
142
        public void checkPreconditions() throws TopologyRuleDefinitionException {
143
                try {
144
                        int shapeType = this.originLyr.getShapeType();
145
                        if (FGeometryUtil.getDimensions(shapeType) != 1 && shapeType != FShape.MULTI)
146
                                throw new TopologyRuleDefinitionException(
147
                                                "LineMustNotHavePseudonodes requires a lineal geometry type");
148
                } catch (ReadDriverException e) {
149
                        e.printStackTrace();
150
                        throw new TopologyRuleDefinitionException(
151
                                        "Error leyendo el tipo de geometria del driver", e);
152
                }
153
        }
154
        
155
        public void ruleChecked(){
156
                super.ruleChecked();
157
                
158
                this.pseudoNodesCoordMap = new SnappingCoordinateMap(this.clusterTol);
159
        }
160

    
161
        public void validateFeature(IFeature feature) {
162
                IGeometry geom = feature.getGeometry();
163
                int shapeType = geom.getGeometryType();
164
                if (shapeType != FShape.LINE && shapeType != FShape.ARC
165
                                && shapeType != FShape.LINE + FShape.Z)
166
                        return;
167

    
168
                Geometry jtsGeom = NewFConverter.toJtsGeometry(geom);
169

    
170
                process(jtsGeom, feature);
171
        }
172

    
173
        protected void process(Geometry geometry, IFeature feature) {
174
                if (geometry instanceof GeometryCollection) {
175
                        GeometryCollection geomCol = (GeometryCollection) geometry;
176
                        for (int i = 0; i < geomCol.getNumGeometries(); i++) {
177
                                Geometry geomI = geomCol.getGeometryN(i);
178
                                process(geomI, feature);
179
                        }
180
                } else if (geometry instanceof LineString) {
181
                        LineString lineString = (LineString) geometry;
182
                        Envelope lnEnv = lineString.getEnvelopeInternal();
183
                         
184
                        //We try to extend a bit the original envelope to ensure
185
                        //recovering geometries in the limit
186
                        double minX = lnEnv.getMinX() - 10;
187
                        double minY = lnEnv.getMinY() - 10;
188
                        double maxX = lnEnv.getMaxX() + 10;
189
                        double maxY = lnEnv.getMaxY() + 10;
190

    
191
                        Rectangle2D rect = new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY);
192
                        
193
                        SnappingCoordinateMapWithCounter coordinateMap = new SnappingCoordinateMapWithCounter(
194
                                        getClusterTolerance());
195

    
196
                        // we consideer  pseudonode a coordinate with degree 2 (it only
197
                        // connects two geometries)
198
                        Coordinate firstPoint = lineString.getCoordinateN(0);
199
                        coordinateMap.put(firstPoint, firstPoint);
200

    
201
                        Coordinate lastPoint = lineString.getCoordinateN(lineString
202
                                        .getNumPoints() - 1);
203
                        coordinateMap.put(lastPoint, lastPoint);
204

    
205
                        try {
206
                                IFeatureIterator neighbours = originLyr.getSource()
207
                                                .getFeatureIterator(rect, null, null, false);
208
                                while (neighbours.hasNext()) {
209
                                        IFeature neighbourFeature = neighbours.next();
210
                                        if (neighbourFeature.getID().equalsIgnoreCase(
211
                                                        feature.getID()))
212
                                                continue;
213
                                        Geometry geom2 = NewFConverter.toJtsGeometry(neighbourFeature.getGeometry());
214
                                        ArrayList<LineString> geometriesToProcess = new ArrayList<LineString>();
215
                                        if (geom2 instanceof LineString) {
216
                                                geometriesToProcess.add((LineString) geom2);
217
                                        } else if (geom2 instanceof MultiLineString) {
218
                                                MultiLineString multiLine = (MultiLineString) geom2;
219
                                                int numLines = multiLine.getNumGeometries();
220
                                                for (int i = 0; i < numLines; i++) {
221
                                                        LineString line = (LineString) multiLine
222
                                                                        .getGeometryN(i);
223
                                                        geometriesToProcess.add(line);
224
                                                }
225
                                        } else if (geom2 instanceof GeometryCollection) {
226
                                                MultiLineString multiLine = JtsUtil
227
                                                                .convertToMultiLineString((GeometryCollection) geom2);
228
                                                int numLines = multiLine.getNumGeometries();
229
                                                for (int i = 0; i < numLines; i++) {
230
                                                        LineString line = (LineString) multiLine
231
                                                                        .getGeometryN(i);
232
                                                        geometriesToProcess.add(line);
233
                                                }
234
                                        } else {
235
                                                System.out.println("Encontrado:" + geom2.toString()
236
                                                                + " en regla de dangles");
237
                                        }
238

    
239
                                        int numGeometries = geometriesToProcess.size();
240
                                        for (int i = 0; i < numGeometries; i++) {
241
                                                LineString lineString2 = geometriesToProcess.get(i);
242
                                                Coordinate firstPoint2 = lineString2.getCoordinateN(0);
243
                                                Coordinate lastPoint2 = lineString2.getCoordinateN(lineString2
244
                                                                .getNumPoints() - 1);
245
                                                
246
                                                coordinateMap.put(lastPoint2, lastPoint);
247
                                                coordinateMap.put(firstPoint2, firstPoint);
248

    
249
                                        }//for
250

    
251
                                }//while
252
                                
253
                                int firstPointDegree = coordinateMap.getCount(firstPoint);
254
                                int lastPointDegree = coordinateMap.getCount(lastPoint);
255
                                
256
                                if(firstPointDegree == 2){//A pseudonode is a node with degree 2, it only connects two lines
257
                                        
258
                                        //we dont add two times the same error
259
                                        Coordinate existingNode = (Coordinate) pseudoNodesCoordMap.get(firstPoint);
260
                                        if(existingNode == null){
261
                                                IGeometry errorGeom = 
262
                                                        ShapeFactory.createPoint2D(firstPoint.x,
263
                                                                                                           firstPoint.y);
264
                                            TopologyError topologyError = 
265
                                                        new TopologyError(errorGeom, 
266
                                                                                                this, 
267
                                                                                         feature,
268
                                                                                        topology);
269
                                            topologyError.setID(errorContainer.getErrorFid());
270
                                            addTopologyError(topologyError);
271
                                            
272
                                            pseudoNodesCoordMap.put(firstPoint, firstPoint);
273
                                        }
274
                                }
275
                                
276
                                if(lastPointDegree == 2){
277
                                        Coordinate existingNode = (Coordinate) pseudoNodesCoordMap.get(lastPoint);
278
                                        if(existingNode == null){
279
                                                IGeometry errorGeom = 
280
                                                        ShapeFactory.createPoint2D(lastPoint.x,
281
                                                                        lastPoint.y);
282
                                            TopologyError topologyError = 
283
                                                        new TopologyError(errorGeom, 
284
                                                                                                this, 
285
                                                                                         feature,
286
                                                                                        topology);
287
                                            topologyError.setID(errorContainer.getErrorFid());
288
                                            addTopologyError(topologyError);
289
                                            
290
                                            pseudoNodesCoordMap.put(lastPoint, lastPoint);
291
                                        }
292
                                }
293

    
294
                        } catch (ReadDriverException e) {
295
                                e.printStackTrace();
296
                                return;
297
                        }
298
                } else {
299
                        System.out.println("Encontrado:" + geometry.toString()
300
                                        + " en regla de dangles");
301
                }
302
        }
303

    
304
        public double getClusterTolerance() {
305
                return clusterTol;
306
        }
307

    
308
        public void setClusterTolerance(double clusterTolerance) {
309
                this.clusterTol = clusterTolerance;
310
                pseudoNodesCoordMap = new SnappingCoordinateMap(clusterTolerance);
311
        }
312

    
313
        public boolean acceptsOriginLyr(FLyrVect lyr) {
314
                try {
315
                        int shapeType = lyr.getShapeType();
316
                        return (FGeometryUtil.getDimensions(shapeType) == 1);
317
                } catch (ReadDriverException e) {
318
                        e.printStackTrace();
319
                        return false;
320
                }
321
        }
322

    
323
        public List<ITopologyErrorFix> getAutomaticErrorFixes() {
324
                return automaticErrorFixes;
325
        }
326

    
327
        public MultiShapeSymbol getDefaultErrorSymbol() {
328
                return DEFAULT_ERROR_SYMBOL;
329
        }
330

    
331
        public MultiShapeSymbol getErrorSymbol() {
332
                return errorSymbol;
333
        }
334
        
335
        public void setErrorSymbol(MultiShapeSymbol errorSymbol) {
336
                this.errorSymbol = errorSymbol;
337
        }
338

    
339
}