/* 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 ScaledNoder::scale(SegmentString::NonConstVect& segStrings) const { Scaler scaler(*this); for (SegmentString::NonConstVect::const_iterator i0=segStrings.begin(), i0End=segStrings.end(); i0!=i0End; ++i0) { SegmentString* ss=*i0; CoordinateSequence* cs=ss->getCoordinates(); #ifndef NDEBUG size_t npts = cs->size(); #endif cs->apply_rw(&scaler); assert(cs->size() == npts); // Actually, we should be creating *new* // SegmentStrings here, but who's going // to delete them then ? And is it worth // the memory cost ? cs->removeRepeatedPoints(); } }
/* public */ std::auto_ptr<geom::Geometry> GeometryNoder::getNoded() { SegmentString::NonConstVect lineList; extractSegmentStrings(argGeom, lineList); Noder& noder = getNoder(); SegmentString::NonConstVect* nodedEdges = 0; try { noder.computeNodes( &lineList ); nodedEdges = noder.getNodedSubstrings(); } catch (const std::exception& ex) { for (size_t i=0, n=lineList.size(); i<n; ++i) delete lineList[i]; throw ex; } std::auto_ptr<geom::Geometry> noded = toGeometry(*nodedEdges); for ( unsigned int i = 0, n = nodedEdges->size(); i < n; ++i ) delete ( *nodedEdges )[i]; delete nodedEdges; for (size_t i=0, n=lineList.size(); i<n; ++i) delete lineList[i]; return noded; }
/*public*/ void MCIndexSnapRounder::computeVertexSnaps(SegmentString::NonConstVect& edges) { SegmentString::NonConstVect::iterator i=edges.begin(), e=edges.end(); for (; i!=e; ++i) { NodedSegmentString* edge0 = dynamic_cast<NodedSegmentString*>(*i); assert(edge0); computeVertexSnaps(edge0); } }
/*private*/ void SimpleSnapRounder::computeSnaps(const SegmentString::NonConstVect& segStrings, vector<Coordinate>& snapPts) { for (SegmentString::NonConstVect::const_iterator i=segStrings.begin(), iEnd=segStrings.end(); i!=iEnd; ++i) { NodedSegmentString* ss = dynamic_cast<NodedSegmentString*>(*i); computeSnaps(ss, snapPts); } }
/* public static */ void NodedSegmentString::getNodedSubstrings( const SegmentString::NonConstVect& segStrings, SegmentString::NonConstVect *resultEdgeList) { assert(resultEdgeList); for ( SegmentString::NonConstVect::const_iterator i=segStrings.begin(), iEnd=segStrings.end(); i != iEnd; ++i ) { NodedSegmentString* ss = dynamic_cast<NodedSegmentString*>(*i); assert(ss); ss->getNodeList().addSplitEdges(resultEdgeList); } }
/*private*/ void ScaledNoder::rescale(SegmentString::NonConstVect& segStrings) const { ReScaler rescaler(*this); for (SegmentString::NonConstVect::const_iterator i0=segStrings.begin(), i0End=segStrings.end(); i0!=i0End; ++i0) { SegmentString* ss=*i0; ss->getCoordinates()->apply_rw(&rescaler); } }
/*public*/ void SimpleSnapRounder::computeVertexSnaps(const SegmentString::NonConstVect& edges) { for (SegmentString::NonConstVect::const_iterator i0=edges.begin(), i0End=edges.end(); i0!=i0End; ++i0) { NodedSegmentString* edge0 = dynamic_cast<NodedSegmentString*>(*i0); assert(edge0); for (SegmentString::NonConstVect::const_iterator i1=edges.begin(), i1End=edges.end(); i1!=i1End; ++i1) { NodedSegmentString* edge1 = dynamic_cast<NodedSegmentString*>(*i1); assert(edge1); computeVertexSnaps(edge0, edge1); } } }
/* 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; }
/* private */ void NodingValidator::checkEndPtVertexIntersections(const Coordinate& testPt, const SegmentString::NonConstVect& segStrings) const { for (SegmentString::NonConstVect::const_iterator it = segStrings.begin(), itEnd = segStrings.end(); it != itEnd; ++it) { const SegmentString* ss0 = *it; const CoordinateSequence& pts = *(ss0->getCoordinates()); for (unsigned int j=1, n=pts.size()-1; j<n; ++j) { if (pts[j].equals(testPt)) { stringstream s; s<<"found endpt/interior pt intersection "; s<<"at index "<<j<<" :pt "<<testPt; throw util::TopologyException(s.str()); } } } }
/*private*/ void SimpleSnapRounder::checkCorrectness( SegmentString::NonConstVect& inputSegmentStrings) { SegmentString::NonConstVect resultSegStrings; NodedSegmentString::getNodedSubstrings( inputSegmentStrings.begin(), inputSegmentStrings.end(), &resultSegStrings ); NodingValidator nv(resultSegStrings); try { nv.checkValid(); } catch (const std::exception &ex) { for ( SegmentString::NonConstVect::iterator i=resultSegStrings.begin(), e=resultSegStrings.end(); i!=e; ++i ) { delete *i; } std::cerr << ex.what() << std::endl; throw; } for ( SegmentString::NonConstVect::iterator i=resultSegStrings.begin(), e=resultSegStrings.end(); i!=e; ++i ) { delete *i; } }
/*public*/ void MCIndexSnapRounder::computeVertexSnaps(SegmentString::NonConstVect& edges) { for_each(edges.begin(), edges.end(), bind1st(mem_fun(&MCIndexSnapRounder::computeEdgeVertexSnaps), this)); }
/*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; } }