Esempio n. 1
0
/* 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());
		}
	}
}
Esempio n. 2
0
/* 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;
}
Esempio n. 3
0
 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];
}
Esempio n. 5
0
/* 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);
		}
	}
}
Esempio n. 6
0
/* 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]);
	}
}
/* 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::buffer(const Geometry *g, double distance)
	// throw(GEOSException *)
{
	const PrecisionModel *precisionModel=workingPrecisionModel;
	if (precisionModel==NULL)
		precisionModel=g->getPrecisionModel();

	assert(precisionModel);
	assert(g);

	// factory must be the same as the one used by the input
	geomFact=g->getFactory();

	OffsetCurveBuilder curveBuilder(precisionModel, bufParams);
	OffsetCurveSetBuilder curveSetBuilder(*g, distance, curveBuilder);

	std::vector<SegmentString*>& bufferSegStrList=curveSetBuilder.getCurves();

#if GEOS_DEBUG
	std::cerr << "OffsetCurveSetBuilder got " << bufferSegStrList.size()
	          << " curves" << std::endl;
#endif
	// short-circuit test
	if (bufferSegStrList.size()<=0) {
		return createEmptyResultGeometry();
	}

#if GEOS_DEBUG
	std::cerr<<"BufferBuilder::buffer computing NodedEdges"<<std::endl;
#endif

#if JTS_DEBUG
std::cerr << "before noding: SegStr # " << bufferSegStrList.size() << std::endl;
for (size_t i = 0, n=bufferSegStrList.size(); i<n; i++)
{
 	SegmentString* segStr = bufferSegStrList[i];
	std::cerr << "SegStr " << i << ": pts # " << segStr->size()
		<< " nodes # " << segStr->getNodeList().size()
		<< std::endl;
}
#endif

	computeNodedEdges(bufferSegStrList, precisionModel);

#if JTS_DEBUG
std::cerr << "after noding: SegStr # " << bufferSegStrList.size() << std::endl;
for (size_t i = 0, n=bufferSegStrList.size(); i<n; i++)
{
 	SegmentString* segStr = bufferSegStrList[i];
	std::cerr << "SegStr " << i << ": pts # " << segStr->size()
		<< " nodes # " << segStr->getNodeList().size()
		<< std::endl;
}
#endif

#if GEOS_DEBUG > 1
	std::cerr << std::endl << edgeList << std::endl;
#endif

	Geometry* resultGeom=NULL;
	std::auto_ptr< std::vector<Geometry*> > resultPolyList;
	std::vector<BufferSubgraph*> subgraphList;

	try {
		PlanarGraph graph(OverlayNodeFactory::instance());
		graph.addEdges(edgeList.getEdges());

		createSubgraphs(&graph, subgraphList);
#if GEOS_DEBUG
	std::cerr<<"Created "<<subgraphList.size()<<" subgraphs"<<std::endl;
#if GEOS_DEBUG > 1
	for (size_t i=0, n=subgraphList.size(); i<n; i++)
		std::cerr << std::setprecision(10) << *(subgraphList[i]) << std::endl;
#endif
#endif
		PolygonBuilder polyBuilder(geomFact);
		buildSubgraphs(subgraphList, polyBuilder);
		resultPolyList.reset( polyBuilder.getPolygons() );
#if GEOS_DEBUG
	std::cerr << "PolygonBuilder got " << resultPolyList->size()
	          << " polygons" << std::endl;
#if GEOS_DEBUG > 1
	for (size_t i=0, n=resultPolyList->size(); i<n; i++)
		std::cerr << (*resultPolyList)[i]->toString() << std::endl;
#endif
#endif
		// just in case ...
		if ( resultPolyList->empty() )
		{
			for (size_t i=0, n=subgraphList.size(); i<n; i++)
				delete subgraphList[i];
			return createEmptyResultGeometry();
		}

		// resultPolyList ownership transferred here
		resultGeom=geomFact->buildGeometry(resultPolyList.release());
	} catch (const util::GEOSException& /* exc */) {
		for (size_t i=0, n=subgraphList.size(); i<n; i++)
			delete subgraphList[i];
		throw;
	} 

	for (size_t i=0, n=subgraphList.size(); i<n; i++)
		delete subgraphList[i];

	return resultGeom;
}
/*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;
   }
}