source: osm/applications/editors/josm/plugins/opendata/includes/com/vividsolutions/jts/operation/IsSimpleOp.java@ 28000

Last change on this file since 28000 was 28000, checked in by donvip, 12 years ago

Import new "opendata" JOSM plugin

File size: 7.4 KB
Line 
1
2
3/*
4 * The JTS Topology Suite is a collection of Java classes that
5 * implement the fundamental operations required to validate a given
6 * geo-spatial data set to a known topological specification.
7 *
8 * Copyright (C) 2001 Vivid Solutions
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * For more information, contact:
25 *
26 * Vivid Solutions
27 * Suite #1A
28 * 2328 Government Street
29 * Victoria BC V8T 5G5
30 * Canada
31 *
32 * (250)385-6040
33 * www.vividsolutions.com
34 */
35package com.vividsolutions.jts.operation;
36
37import java.util.Iterator;
38import java.util.Map;
39import java.util.Set;
40import java.util.TreeMap;
41import java.util.TreeSet;
42
43import com.vividsolutions.jts.algorithm.BoundaryNodeRule;
44import com.vividsolutions.jts.algorithm.LineIntersector;
45import com.vividsolutions.jts.algorithm.RobustLineIntersector;
46import com.vividsolutions.jts.geom.Coordinate;
47import com.vividsolutions.jts.geom.Geometry;
48import com.vividsolutions.jts.geom.LineString;
49import com.vividsolutions.jts.geom.MultiLineString;
50import com.vividsolutions.jts.geom.MultiPoint;
51import com.vividsolutions.jts.geom.Point;
52import com.vividsolutions.jts.geomgraph.Edge;
53import com.vividsolutions.jts.geomgraph.EdgeIntersection;
54import com.vividsolutions.jts.geomgraph.GeometryGraph;
55import com.vividsolutions.jts.geomgraph.index.SegmentIntersector;
56
57/**
58 * Tests whether a <code>Geometry</code> is simple.
59 * In general, the SFS specification of simplicity
60 * follows the rule:
61 * <ul>
62 * <li> A Geometry is simple if and only if the only self-intersections are at
63 * boundary points.
64 * </ul>
65 * This definition relies on the definition of boundary points.
66 * The SFS uses the Mod-2 rule to determine which points are on the boundary of
67 * lineal geometries, but this class supports
68 * using other {@link BoundaryNodeRule}s as well.
69 * <p>
70 * Simplicity is defined for each {@link Geometry} subclass as follows:
71 * <ul>
72 * <li>Valid polygonal geometries are simple by definition, so
73 * <code>isSimple</code> trivially returns true.
74 * (Hint: in order to check if a polygonal geometry has self-intersections,
75 * use {@link Geometry#isValid}).
76 * <li>Linear geometries are simple iff they do not self-intersect at points
77 * other than boundary points.
78 * (Using the Mod-2 rule, this means that closed linestrings
79 * cannot be touched at their endpoints, since these are
80 * interior points, not boundary points).
81 * <li>Zero-dimensional geometries (points) are simple iff they have no
82 * repeated points.
83 * <li>Empty <code>Geometry</code>s are always simple
84 * </ul>
85 *
86 * @see BoundaryNodeRule
87 *
88 * @version 1.7
89 */
90public class IsSimpleOp
91{
92 private Geometry geom;
93 private boolean isClosedEndpointsInInterior = true;
94
95
96 /**
97 * Creates a simplicity checker using the default SFS Mod-2 Boundary Node Rule
98 *
99 * @param geom the geometry to test
100 */
101 public IsSimpleOp(Geometry geom) {
102 this.geom = geom;
103 }
104
105 /**
106 * Tests whether the geometry is simple.
107 *
108 * @return true if the geometry is simple
109 */
110 public boolean isSimple()
111 {
112 if (geom instanceof LineString) return isSimpleLinearGeometry(geom);
113 if (geom instanceof MultiLineString) return isSimpleLinearGeometry(geom);
114 if (geom instanceof MultiPoint) return isSimpleMultiPoint((MultiPoint) geom);
115 // all other geometry types are simple by definition
116 return true;
117 }
118
119 private boolean isSimpleMultiPoint(MultiPoint mp)
120 {
121 if (mp.isEmpty()) return true;
122 Set points = new TreeSet();
123 for (int i = 0; i < mp.getNumGeometries(); i++) {
124 Point pt = (Point) mp.getGeometryN(i);
125 Coordinate p = pt.getCoordinate();
126 if (points.contains(p)) {
127 return false;
128 }
129 points.add(p);
130 }
131 return true;
132 }
133
134 private boolean isSimpleLinearGeometry(Geometry geom)
135 {
136 if (geom.isEmpty()) return true;
137 GeometryGraph graph = new GeometryGraph(0, geom);
138 LineIntersector li = new RobustLineIntersector();
139 SegmentIntersector si = graph.computeSelfNodes(li, true);
140 // if no self-intersection, must be simple
141 if (! si.hasIntersection()) return true;
142 if (si.hasProperIntersection()) {
143 return false;
144 }
145 if (hasNonEndpointIntersection(graph)) return false;
146 if (isClosedEndpointsInInterior) {
147 if (hasClosedEndpointIntersection(graph)) return false;
148 }
149 return true;
150 }
151
152 /**
153 * For all edges, check if there are any intersections which are NOT at an endpoint.
154 * The Geometry is not simple if there are intersections not at endpoints.
155 */
156 private boolean hasNonEndpointIntersection(GeometryGraph graph)
157 {
158 for (Iterator i = graph.getEdgeIterator(); i.hasNext(); ) {
159 Edge e = (Edge) i.next();
160 int maxSegmentIndex = e.getMaximumSegmentIndex();
161 for (Iterator eiIt = e.getEdgeIntersectionList().iterator(); eiIt.hasNext(); ) {
162 EdgeIntersection ei = (EdgeIntersection) eiIt.next();
163 if (! ei.isEndPoint(maxSegmentIndex)) {
164 return true;
165 }
166 }
167 }
168 return false;
169 }
170
171 private static class EndpointInfo {
172 boolean isClosed;
173 int degree;
174
175 public EndpointInfo()
176 {
177 isClosed = false;
178 degree = 0;
179 }
180
181 public void addEndpoint(boolean isClosed)
182 {
183 degree++;
184 this.isClosed |= isClosed;
185 }
186 }
187
188 /**
189 * Tests that no edge intersection is the endpoint of a closed line.
190 * This ensures that closed lines are not touched at their endpoint,
191 * which is an interior point according to the Mod-2 rule
192 * To check this we compute the degree of each endpoint.
193 * The degree of endpoints of closed lines
194 * must be exactly 2.
195 */
196 private boolean hasClosedEndpointIntersection(GeometryGraph graph)
197 {
198 Map endPoints = new TreeMap();
199 for (Iterator i = graph.getEdgeIterator(); i.hasNext(); ) {
200 Edge e = (Edge) i.next();
201 boolean isClosed = e.isClosed();
202 Coordinate p0 = e.getCoordinate(0);
203 addEndpoint(endPoints, p0, isClosed);
204 Coordinate p1 = e.getCoordinate(e.getNumPoints() - 1);
205 addEndpoint(endPoints, p1, isClosed);
206 }
207
208 for (Iterator i = endPoints.values().iterator(); i.hasNext(); ) {
209 EndpointInfo eiInfo = (EndpointInfo) i.next();
210 if (eiInfo.isClosed && eiInfo.degree != 2) {
211 return true;
212 }
213 }
214 return false;
215 }
216
217 /**
218 * Add an endpoint to the map, creating an entry for it if none exists
219 */
220 private void addEndpoint(Map endPoints, Coordinate p, boolean isClosed)
221 {
222 EndpointInfo eiInfo = (EndpointInfo) endPoints.get(p);
223 if (eiInfo == null) {
224 eiInfo = new EndpointInfo();
225 endPoints.put(p, eiInfo);
226 }
227 eiInfo.addEndpoint(isClosed);
228 }
229
230}
Note: See TracBrowser for help on using the repository browser.