1 /**********************************************************************
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
6 * Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
7 * Copyright (C) 2005-2006 Refractions Research Inc.
8 * Copyright (C) 2001-2002 Vivid Solutions Inc.
10 * This is free software; you can redistribute and/or modify it under
11 * the terms of the GNU Lesser General Public Licence as published
12 * by the Free Software Foundation.
13 * See the COPYING file for more information.
15 **********************************************************************
17 * Last port: geomgraph/EdgeEndStar.java r428 (JTS-1.12+)
19 **********************************************************************/
21 #include <geos/util/TopologyException.h>
22 #include <geos/geomgraph/EdgeEndStar.h>
23 #include <geos/algorithm/locate/SimplePointInAreaLocator.h>
24 #include <geos/geom/Location.h>
25 #include <geos/geomgraph/Label.h>
26 #include <geos/geomgraph/Position.h>
27 #include <geos/geomgraph/GeometryGraph.h>
38 //using namespace std;
39 //using namespace geos::algorithm;
40 using namespace geos::geom
;
43 namespace geomgraph
{ // geos.geomgraph
46 EdgeEndStar::EdgeEndStar()
50 ptInAreaLocation
[0]=Location::UNDEF
;
51 ptInAreaLocation
[1]=Location::UNDEF
;
56 EdgeEndStar::getCoordinate()
58 static Coordinate
nullCoord(DoubleNotANumber
, DoubleNotANumber
, DoubleNotANumber
);
59 if (edgeMap
.size()==0) return nullCoord
;
61 EdgeEndStar::iterator it
=begin();
64 return e
->getCoordinate();
69 EdgeEndStar::getCoordinate() const
71 return const_cast<EdgeEndStar
*>(this)->getCoordinate();
76 EdgeEndStar::getNextCW(EdgeEnd
*ee
)
78 EdgeEndStar::iterator it
=find(ee
);
79 if ( it
==end() ) return NULL
;
80 if ( it
==begin() ) { it
=end(); --it
; }
87 EdgeEndStar::computeLabelling(std::vector
<GeometryGraph
*> *geomGraph
)
88 //throw(TopologyException *)
90 computeEdgeEndLabels((*geomGraph
)[0]->getBoundaryNodeRule());
92 // Propagate side labels around the edges in the star
93 // for each parent Geometry
95 // these calls can throw a TopologyException
96 propagateSideLabels(0);
97 propagateSideLabels(1);
100 * If there are edges that still have null labels for a geometry
101 * this must be because there are no area edges for that geometry
102 * incident on this node.
103 * In this case, to label the edge for that geometry we must test
104 * whether the edge is in the interior of the geometry.
105 * To do this it suffices to determine whether the node for the
106 * edge is in the interior of an area.
107 * If so, the edge has location INTERIOR for the geometry.
108 * In all other cases (e.g. the node is on a line, on a point, or
109 * not on the geometry at all) the edge
110 * has the location EXTERIOR for the geometry.
112 * Note that the edge cannot be on the BOUNDARY of the geometry,
113 * since then there would have been a parallel edge from the
114 * Geometry at this node also labelled BOUNDARY
115 * and this edge would have been labelled in the previous step.
117 * This code causes a problem when dimensional collapses are present,
118 * since it may try and determine the location of a node where a
119 * dimensional collapse has occurred.
120 * The point should be considered to be on the EXTERIOR
121 * of the polygon, but locate() will return INTERIOR, since it is
122 * passed the original Geometry, not the collapsed version.
124 * If there are incident edges which are Line edges labelled BOUNDARY,
125 * then they must be edges resulting from dimensional collapses.
126 * In this case the other edges can be labelled EXTERIOR for this
129 * MD 8/11/01 - NOT TRUE! The collapsed edges may in fact be in the
130 * interior of the Geometry, which means the other edges should be
131 * labelled INTERIOR for this Geometry.
132 * Not sure how solve this... Possibly labelling needs to be split
133 * into several phases:
134 * area label propagation, symLabel merging, then finally null label
137 bool hasDimensionalCollapseEdge
[2]={false,false};
139 EdgeEndStar::iterator endIt
=end();
140 for (EdgeEndStar::iterator it
=begin(); it
!=endIt
; ++it
)
144 const Label
& label
= e
->getLabel();
145 for(int geomi
=0; geomi
<2; geomi
++)
147 if (label
.isLine(geomi
) && label
.getLocation(geomi
) == Location::BOUNDARY
)
148 hasDimensionalCollapseEdge
[geomi
]=true;
152 for (EdgeEndStar::iterator it
=begin(); it
!=end(); ++it
)
156 Label
& label
= e
->getLabel();
157 for(int geomi
=0; geomi
<2; ++geomi
)
159 if (label
.isAnyNull(geomi
)) {
160 int loc
=Location::UNDEF
;
161 if (hasDimensionalCollapseEdge
[geomi
]){
162 loc
=Location::EXTERIOR
;
164 Coordinate
& p
=e
->getCoordinate();
165 loc
= getLocation(geomi
, p
, geomGraph
);
167 label
.setAllLocationsIfNull(geomi
, loc
);
175 EdgeEndStar::computeEdgeEndLabels(
176 const algorithm::BoundaryNodeRule
& boundaryNodeRule
)
178 // Compute edge label for each EdgeEnd
179 for (EdgeEndStar::iterator it
=begin(); it
!=end(); ++it
)
183 ee
->computeLabel(boundaryNodeRule
);
189 EdgeEndStar::getLocation(int geomIndex
,
190 const Coordinate
& p
, std::vector
<GeometryGraph
*> *geom
)
192 // compute location only on demand
193 if (ptInAreaLocation
[geomIndex
]==Location::UNDEF
)
195 ptInAreaLocation
[geomIndex
]=algorithm::locate::SimplePointInAreaLocator::locate(p
,
196 (*geom
)[geomIndex
]->getGeometry());
198 return ptInAreaLocation
[geomIndex
];
203 EdgeEndStar::isAreaLabelsConsistent(const GeometryGraph
& geomGraph
)
205 computeEdgeEndLabels(geomGraph
.getBoundaryNodeRule());
206 return checkAreaLabelsConsistent(0);
211 EdgeEndStar::checkAreaLabelsConsistent(int geomIndex
)
213 // Since edges are stored in CCW order around the node,
214 // As we move around the ring we move from the right to
215 // the left side of the edge
217 // if no edges, trivially consistent
218 if (edgeMap
.size()==0) return true;
220 // initialize startLoc to location of last L side (if any)
222 const Label
& startLabel
= (*rbegin())->getLabel();
223 int startLoc
= startLabel
.getLocation(geomIndex
, Position::LEFT
);
225 // Found unlabelled area edge
226 assert(startLoc
!=Location::UNDEF
);
228 int currLoc
=startLoc
;
230 for (EdgeEndStar::iterator it
=begin(), itEnd
=end(); it
!=itEnd
; ++it
)
234 const Label
& eLabel
= e
->getLabel();
236 // we assume that we are only checking a area
238 // Found non-area edge
239 assert(eLabel
.isArea(geomIndex
));
241 int leftLoc
=eLabel
.getLocation(geomIndex
, Position::LEFT
);
242 int rightLoc
=eLabel
.getLocation(geomIndex
, Position::RIGHT
);
243 // check that edge is really a boundary between inside and outside!
244 if (leftLoc
==rightLoc
) {
247 // check side location conflict
248 //assert(rightLoc == currLoc); // "side location conflict " + locStr);
249 if (rightLoc
!=currLoc
) {
259 EdgeEndStar::propagateSideLabels(int geomIndex
)
260 //throw(TopologyException *)
262 // Since edges are stored in CCW order around the node,
263 // As we move around the ring we move from the right to the
264 // left side of the edge
265 int startLoc
=Location::UNDEF
;
267 EdgeEndStar::iterator beginIt
=begin();
268 EdgeEndStar::iterator endIt
=end();
269 EdgeEndStar::iterator it
;
271 // initialize loc to location of last L side (if any)
272 for (EdgeEndStar::iterator it
=beginIt
; it
!=endIt
; ++it
)
276 const Label
& label
= e
->getLabel();
277 if (label
.isArea(geomIndex
) &&
278 label
.getLocation(geomIndex
,Position::LEFT
) != Location::UNDEF
)
280 startLoc
= label
.getLocation(geomIndex
, Position::LEFT
);
284 // no labelled sides found, so no labels to propagate
285 if (startLoc
==Location::UNDEF
) return;
287 int currLoc
=startLoc
;
288 for (it
=beginIt
; it
!=endIt
; ++it
)
292 Label
& label
= e
->getLabel();
293 // set null ON values to be in current location
294 if (label
.getLocation(geomIndex
,Position::ON
) == Location::UNDEF
)
296 label
.setLocation(geomIndex
,Position::ON
,currLoc
);
299 // set side labels (if any)
300 // if (label.isArea()) //ORIGINAL
301 if (label
.isArea(geomIndex
))
303 int leftLoc
=label
.getLocation(geomIndex
,
306 int rightLoc
=label
.getLocation(geomIndex
,
309 // if there is a right location, that is the next
310 // location to propagate
311 if (rightLoc
!=Location::UNDEF
) {
312 if (rightLoc
!=currLoc
)
313 throw util::TopologyException("side location conflict",
315 if (leftLoc
==Location::UNDEF
) {
316 // found single null side at e->getCoordinate()
322 * RHS is null - LHS must be null too.
323 * This must be an edge from the other
324 * geometry, which has no location
325 * labelling for this geometry.
326 * This edge must lie wholly inside or
327 * outside the other geometry (which is
328 * determined by the current location).
329 * Assign both sides to be the current
332 // found single null side
333 assert(label
.getLocation(geomIndex
,
334 Position::LEFT
)==Location::UNDEF
);
336 label
.setLocation(geomIndex
,Position::RIGHT
,
338 label
.setLocation(geomIndex
,Position::LEFT
,
347 EdgeEndStar::print() const
349 std::ostringstream s
;
355 operator<< (std::ostream
& os
, const EdgeEndStar
& es
)
357 os
<< "EdgeEndStar: " << es
.getCoordinate() << "\n";
358 for (EdgeEndStar::const_iterator it
=es
.begin(), itEnd
=es
.end(); it
!=itEnd
; ++it
)
360 const EdgeEnd
*e
=*it
;
367 } // namespace geos.geomgraph