/* private */ void NodingValidator::checkInteriorIntersections( const SegmentString& e0, unsigned int segIndex0, const SegmentString& e1, unsigned int segIndex1) { if (&e0 == &e1 && segIndex0 == segIndex1) return; const Coordinate& p00 = e0.getCoordinates()->getAt(segIndex0); const Coordinate& p01 = e0.getCoordinates()->getAt(segIndex0 + 1); const Coordinate& p10 = e1.getCoordinates()->getAt(segIndex1); const Coordinate& p11 = e1.getCoordinates()->getAt(segIndex1 + 1); li.computeIntersection(p00, p01, p10, p11); if (li.hasIntersection()) { if (li.isProper() || hasInteriorIntersection(li, p00, p01) || hasInteriorIntersection(li, p10, p11)) { throw util::TopologyException( "found non-noded intersection at " + p00.toString() + "-" + p01.toString() + " and " + p10.toString() + "-" + p11.toString()); } } }
/* private */ void NodingValidator::checkInteriorIntersections(const SegmentString& ss0, const SegmentString& ss1) { const CoordinateSequence& pts0 = *(ss0.getCoordinates()); const CoordinateSequence& pts1 = *(ss1.getCoordinates()); for (unsigned int i0=0, n0=pts0.size(); i0<n0-1; i0++) { for (unsigned int i1=0, n1=pts1.size(); i1<n1-1; i1++) { checkInteriorIntersections(ss0, i0, ss1, i1); } } }
/* private */ std::auto_ptr<geom::Geometry> GeometryNoder::toGeometry(SegmentString::NonConstVect& nodedEdges) { const geom::GeometryFactory *geomFact = argGeom.getFactory(); std::set< OrientedCoordinateArray > ocas; // Create a geometry out of the noded substrings. std::vector< geom::Geometry* >* lines = new std::vector< geom::Geometry * >(); lines->reserve(nodedEdges.size()); for ( unsigned int i = 0, n = nodedEdges.size(); i < n; ++i ) { SegmentString* ss = nodedEdges [i]; const geom::CoordinateSequence* coords = ss->getCoordinates(); // Check if an equivalent edge is known OrientedCoordinateArray oca1( *coords ); if ( ocas.insert(oca1).second ) { geom::Geometry* tmp = geomFact->createLineString( coords->clone() ); lines->push_back( tmp ); } } std::auto_ptr<geom::Geometry> noded ( geomFact->createMultiLineString( lines ) ); return noded; }
/* private */ void NodingValidator::checkCollapses(const SegmentString& ss) const { const CoordinateSequence& pts = *(ss.getCoordinates()); for (unsigned int i=0, n=pts.getSize()-2; i<n; ++i) { checkCollapse(pts[i], pts[i + 1], pts[i + 2]); } }
GeomPtr getGeometry(SegStrVct& vct) { GeomVct* lines = new GeomVct; for(SegStrVct::size_type i = 0, n = vct.size(); i < n; ++i) { SegmentString* ss = vct[i]; lines->push_back(gf_->createLineString(*(ss->getCoordinates()))); } return GeomPtr(gf_->createMultiLineString(lines)); }
OffsetCurveSetBuilder::~OffsetCurveSetBuilder() { for (size_t i=0, n=curveList.size(); i<n; ++i) { SegmentString* ss = curveList[i]; delete ss->getCoordinates(); delete ss; } for (size_t i=0, n=newLabels.size(); i<n; ++i) delete newLabels[i]; }
/* private */ void BufferBuilder::computeNodedEdges(SegmentString::NonConstVect& bufferSegStrList, const PrecisionModel *precisionModel) // throw(GEOSException) { Noder* noder = getNoder( precisionModel ); noder->computeNodes(&bufferSegStrList); SegmentString::NonConstVect* nodedSegStrings = \ noder->getNodedSubstrings(); for (SegmentString::NonConstVect::iterator i=nodedSegStrings->begin(), e=nodedSegStrings->end(); i!=e; ++i) { SegmentString* segStr = *i; const Label* oldLabel = static_cast<const Label*>(segStr->getData()); CoordinateSequence* cs = CoordinateSequence::removeRepeatedPoints(segStr->getCoordinates()); if ( cs->size() < 2 ) { delete cs; // we need to take care of the memory here as cs is a new sequence return; // don't insert collapsed edges } // we need to clone SegmentString coordinates // as Edge will take ownership of them // TODO: find a way to transfer ownership instead // Who will own the edge ? FIXME: find out and handle that! Edge* edge = new Edge(cs, new Label(*oldLabel)); // will take care of the Edge ownership insertUniqueEdge(edge); } if ( nodedSegStrings != &bufferSegStrList ) { delete nodedSegStrings; } if ( noder != workingNoder ) delete noder; }
/*public*/ Geometry* BufferBuilder::bufferLineSingleSided( const Geometry* g, double distance, bool leftSide ) { // Returns the line used to create a single-sided buffer. // Input requirement: Must be a LineString. const LineString* l = dynamic_cast< const LineString* >( g ); if ( !l ) throw util::IllegalArgumentException("BufferBuilder::bufferLineSingleSided only accept linestrings"); // Get geometry factory and precision model. const PrecisionModel* precisionModel = workingPrecisionModel; if ( !precisionModel ) precisionModel = l->getPrecisionModel(); assert( precisionModel ); assert( l ); geomFact = l->getFactory(); // First, generate the two-sided buffer using a butt-cap. BufferParameters modParams = bufParams; modParams.setEndCapStyle(BufferParameters::CAP_FLAT); Geometry* buf = 0; // This is a (temp?) hack to workaround the fact that // BufferBuilder BufferParamaters are immutable after // construction, while we want to force the end cap // style to FLAT for single-sided buffering { BufferBuilder tmp(modParams); buf = tmp.buffer( l, distance ); } // Create MultiLineStrings from this polygon. Geometry* bufLineString = buf->getBoundary(); #ifdef GEOS_DEBUG_SSB std::cerr << "input|" << *l << std::endl; std::cerr << "buffer|" << *bufLineString << std::endl; #endif // Then, get the raw (i.e. unnoded) single sided offset curve. OffsetCurveBuilder curveBuilder( precisionModel, modParams ); std::vector< CoordinateSequence* > lineList; std::auto_ptr< CoordinateSequence > coords ( g->getCoordinates() ); curveBuilder.getSingleSidedLineCurve( coords.get(), distance, lineList, leftSide, !leftSide ); coords.reset(); // Create a SegmentString from these coordinates. SegmentString::NonConstVect curveList; for ( unsigned int i = 0; i < lineList.size(); ++i ) { CoordinateSequence* seq = lineList[i]; SegmentString* ss = new NodedSegmentString(seq, NULL); curveList.push_back( ss ); } // Node these SegmentStrings. Noder* noder = getNoder( precisionModel ); noder->computeNodes( &curveList ); SegmentString::NonConstVect* nodedEdges = noder->getNodedSubstrings(); // Create a geometry out of the noded substrings. std::vector< Geometry* >* singleSidedNodedEdges = new std::vector< Geometry * >(); for ( unsigned int i = 0, n = nodedEdges->size(); i < n; ++i ) { SegmentString* ss = ( *nodedEdges )[i]; Geometry* tmp = geomFact->createLineString( ss->getCoordinates()->clone() ); singleSidedNodedEdges->push_back( tmp ); } if ( nodedEdges != &curveList ) delete nodedEdges; for (size_t i=0, n=curveList.size(); i<n; ++i) delete curveList[i]; curveList.clear(); for (size_t i=0, n=lineList.size(); i<n; ++i) delete lineList[i]; lineList.clear(); Geometry* singleSided = geomFact->createMultiLineString( singleSidedNodedEdges ); #ifdef GEOS_DEBUG_SSB std::cerr << "edges|" << *singleSided << std::endl; #endif // Use the boolean operation intersect to obtain the line segments lying // on both the butt-cap buffer and this multi-line. //Geometry* intersectedLines = singleSided->intersection( bufLineString ); // NOTE: we use Snapped overlay because the actual buffer boundary might // diverge from original offset curves due to the addition of // intersections with caps and joins curves using geos::operation::overlay::snap::SnapOverlayOp; Geometry* intersectedLines = SnapOverlayOp::overlayOp(*singleSided, *bufLineString, OverlayOp::opINTERSECTION).release(); #ifdef GEOS_DEBUG_SSB std::cerr << "intersection" << "|" << *intersectedLines << std::endl; #endif // Merge result lines together. LineMerger lineMerge; lineMerge.add( intersectedLines ); std::auto_ptr< std::vector< LineString* > > mergedLines ( lineMerge.getMergedLineStrings() ); // Convert the result into a std::vector< Geometry* >. std::vector< Geometry* >* mergedLinesGeom = new std::vector< Geometry* >(); const Coordinate& startPoint = l->getCoordinatesRO()->front(); const Coordinate& endPoint = l->getCoordinatesRO()->back(); while( !mergedLines->empty() ) { // Remove end points if they are a part of the original line to be // buffered. CoordinateSequence::AutoPtr coords(mergedLines->back()->getCoordinates()); if ( NULL != coords.get() ) { // Use 98% of the buffer width as the point-distance requirement - this // is to ensure that the point that is "distance" +/- epsilon is not // included. const double ptDistAllowance = 0.98 * distance; // Use 102% of the buffer width as the line-length requirement - this // is to ensure that line segments that is length "distance" +/- // epsilon is removed. const double segLengthAllowance = 1.02 * distance; // Clean up the front of the list. // Loop until the line's end is not inside the buffer width from // the startPoint. while ( coords->size() > 1 && coords->front().distance( startPoint ) < ptDistAllowance ) { // Record the end segment length. double segLength = coords->front().distance( ( *coords )[1] ); // Stop looping if there are no more points, or if the segment // length is larger than the buffer width. if ( coords->size() <= 1 || segLength > segLengthAllowance ) { break; } // If the first point is less than buffer width away from the // reference point, then delete the point. coords->deleteAt( 0 ); } while ( coords->size() > 1 && coords->front().distance( endPoint ) < ptDistAllowance ) { double segLength = coords->front().distance( ( *coords )[1] ); if ( coords->size() <= 1 || segLength > segLengthAllowance ) { break; } coords->deleteAt( 0 ); } // Clean up the back of the list. while ( coords->size() > 1 && coords->back().distance( startPoint ) < ptDistAllowance ) { double segLength = coords->back().distance( ( *coords )[coords->size()-2] ); if ( coords->size() <= 1 || segLength > segLengthAllowance ) { break; } coords->deleteAt( coords->size()-1 ); } while ( coords->size() > 1 && coords->back().distance( endPoint ) < ptDistAllowance ) { double segLength = coords->back().distance( ( *coords )[coords->size()-2] ); if ( coords->size() <= 1 || segLength > segLengthAllowance ) { break; } coords->deleteAt( coords->size()-1 ); } // Add the coordinates to the resultant line string. if ( coords->size() > 1 ) { mergedLinesGeom->push_back( geomFact->createLineString( coords.release() ) ); } } geomFact->destroyGeometry( mergedLines->back() ); mergedLines->pop_back(); } // Clean up. if ( noder != workingNoder ) delete noder; geomFact->destroyGeometry( buf ); geomFact->destroyGeometry( bufLineString ); geomFact->destroyGeometry( singleSided ); geomFact->destroyGeometry( intersectedLines ); if ( mergedLinesGeom->size() > 1 ) return geomFact->createMultiLineString( mergedLinesGeom ); else { // Must be a single line Geometry* single = (*mergedLinesGeom)[0]; delete mergedLinesGeom; return single; } }