[geos-commits] r2628 - in trunk:
source/headers/geos/operation/buffer source/operation/buffer
tests/xmltester
svn_geos at osgeo.org
svn_geos at osgeo.org
Sun Sep 27 16:43:06 EDT 2009
Author: strk
Date: 2009-09-27 16:43:03 -0400 (Sun, 27 Sep 2009)
New Revision: 2628
Modified:
trunk/source/headers/geos/operation/buffer/BufferBuilder.h
trunk/source/headers/geos/operation/buffer/OffsetCurveBuilder.h
trunk/source/operation/buffer/BufferBuilder.cpp
trunk/source/operation/buffer/OffsetCurveBuilder.cpp
trunk/source/operation/buffer/OffsetCurveVertexList.h
trunk/tests/xmltester/XMLTester.cpp
Log:
Re-introduce the singlesided buffer patch. Tests still need to be worked on.
Modified: trunk/source/headers/geos/operation/buffer/BufferBuilder.h
===================================================================
--- trunk/source/headers/geos/operation/buffer/BufferBuilder.h 2009-09-21 19:47:45 UTC (rev 2627)
+++ trunk/source/headers/geos/operation/buffer/BufferBuilder.h 2009-09-27 20:43:03 UTC (rev 2628)
@@ -206,6 +206,11 @@
geom::Geometry* buffer(const geom::Geometry *g, double distance);
// throw (GEOSException);
+ /// Not in JTS: this is a GEOS extension
+ geom::Geometry* bufferLineSingleSided( const geom::Geometry* g,
+ double distance, bool leftSide ) ;
+ // throw (GEOSException);
+
};
} // namespace geos::operation::buffer
Modified: trunk/source/headers/geos/operation/buffer/OffsetCurveBuilder.h
===================================================================
--- trunk/source/headers/geos/operation/buffer/OffsetCurveBuilder.h 2009-09-21 19:47:45 UTC (rev 2627)
+++ trunk/source/headers/geos/operation/buffer/OffsetCurveBuilder.h 2009-09-27 20:43:03 UTC (rev 2628)
@@ -91,6 +91,25 @@
std::vector<geom::CoordinateSequence*>& lineList);
/**
+ * This method handles single points as well as lines.
+ *
+ * Lines are assumed to <b>not</b> be closed (the function will not
+ * fail for closed lines, but will generate superfluous line caps).
+ *
+ * @param lineList the std::vector to which CoordinateSequences will
+ * be pushed_back
+ * @param leftSide indicates that the left side buffer will be
+ * obtained/skipped
+ * @param rightSide indicates that the right side buffer will
+ * be obtained/skipped
+ *
+ * NOTE: this is a GEOS extension
+ */
+ void getSingleSidedLineCurve(const geom::CoordinateSequence* inputPts,
+ double distance, std::vector<geom::CoordinateSequence*>& lineList,
+ bool leftSide, bool rightSide ) ;
+
+ /**
* This method handles the degenerate cases of single points and lines,
* as well as rings.
*
@@ -229,6 +248,9 @@
int side;
+ // Not in JTS, used for single-sided buffers
+ int endCapIndex;
+
void init(double newDistance);
/**
Modified: trunk/source/operation/buffer/BufferBuilder.cpp
===================================================================
--- trunk/source/operation/buffer/BufferBuilder.cpp 2009-09-21 19:47:45 UTC (rev 2627)
+++ trunk/source/operation/buffer/BufferBuilder.cpp 2009-09-27 20:43:03 UTC (rev 2628)
@@ -26,11 +26,15 @@
#include <geos/geom/Geometry.h>
#include <geos/geom/Polygon.h>
#include <geos/geom/GeometryCollection.h>
+#include <geos/geom/LineString.h>
+#include <geos/geom/MultiLineString.h>
#include <geos/operation/buffer/BufferBuilder.h>
#include <geos/operation/buffer/OffsetCurveBuilder.h>
#include <geos/operation/buffer/OffsetCurveSetBuilder.h>
#include <geos/operation/buffer/BufferSubgraph.h>
#include <geos/operation/buffer/SubgraphDepthLocater.h>
+#include <geos/operation/overlay/OverlayOp.h>
+#include <geos/operation/linemerge/LineMerger.h>
#include <geos/algorithm/LineIntersector.h>
#include <geos/noding/IntersectionAdder.h>
#include <geos/noding/SegmentString.h>
@@ -64,6 +68,7 @@
using namespace geos::noding;
using namespace geos::algorithm;
using namespace geos::operation::overlay;
+using namespace geos::operation::linemerge;
namespace geos {
namespace operation { // geos.operation
@@ -102,6 +107,166 @@
/*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 ) return NULL;
+
+ // 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 = buffer( l, distance );
+
+ // Create MultiLineStrings from this polygon.
+ Geometry* bufLineString = buf->getBoundary();
+
+ // Then, get the raw (i.e. unnoded) single sided offset curve.
+ OffsetCurveBuilder curveBuilder( precisionModel, modParams );
+ std::vector< CoordinateSequence* > lineList;
+ curveBuilder.getSingleSidedLineCurve( g->getCoordinates(), distance,
+ lineList, leftSide, !leftSide );
+
+ // Create a SegmentString from these coordinates.
+ SegmentString::NonConstVect curveList;
+ for ( unsigned int i = 0; i < lineList.size(); ++i )
+ {
+ CoordinateSequence* seq = lineList[i];
+ curveList.push_back( new NodedSegmentString( seq, NULL ) );
+ }
+
+ // 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; i < nodedEdges->size(); ++i )
+ {
+ singleSidedNodedEdges->push_back( geomFact->createLineString(
+ ( *nodedEdges )[i]->getCoordinates() ) );
+ }
+ Geometry* singleSided = geomFact->createMultiLineString(
+ singleSidedNodedEdges );
+
+ // 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 );
+
+ // Merge result lines together.
+ LineMerger lineMerge;
+ lineMerge.add( intersectedLines );
+ 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 );
+
+ return geomFact->createMultiLineString( mergedLinesGeom );
+}
+
+/*public*/
+Geometry*
BufferBuilder::buffer(const Geometry *g, double distance)
// throw(GEOSException *)
{
Modified: trunk/source/operation/buffer/OffsetCurveBuilder.cpp
===================================================================
--- trunk/source/operation/buffer/OffsetCurveBuilder.cpp 2009-09-21 19:47:45 UTC (rev 2627)
+++ trunk/source/operation/buffer/OffsetCurveBuilder.cpp 2009-09-27 20:43:03 UTC (rev 2628)
@@ -82,6 +82,7 @@
offset0(),
offset1(),
side(0),
+ endCapIndex(0),
vertexLists()
{
// compute intersections in full precision, to provide accuracy
@@ -144,6 +145,62 @@
/*public*/
void
+OffsetCurveBuilder::getSingleSidedLineCurve(const CoordinateSequence* inputPts,
+ double distance, vector<CoordinateSequence*>& lineList, bool leftSide,
+ bool rightSide)
+{
+ // A zero or negative width buffer of a line/point is empty.
+ if ( distance <= 0.0 ) return ;
+
+ init( distance ) ;
+
+ if ( inputPts->getSize() < 2 )
+ {
+ // No cap, so just return.
+ return ;
+ }
+ else
+ {
+ computeLineBufferCurve( *inputPts ) ;
+ }
+
+ // NOTE: we take ownership of lineCoord here ...
+ CoordinateSequence* lineCoord = vertexList->getCoordinates() ;
+
+ // [swong] April 24, 2008
+ // Left side: index [n-2] to [endCapIndex]
+ // Right side: index [endCapIndex] to [n-2]
+ // Where n is the last index (size-1).
+ int n = lineCoord->size() - 1 ;
+
+ // Add the left side curve to the line list.
+ if ( leftSide )
+ {
+ CoordinateArraySequence* coordSeq = new CoordinateArraySequence() ;
+ coordSeq->add( ( *lineCoord )[n-2] ) ;
+ coordSeq->add( ( *lineCoord )[n-1] ) ;
+ for ( int i = 0 ; i <= endCapIndex ; ++i )
+ {
+ coordSeq->add( ( *lineCoord )[i] ) ;
+ }
+ lineList.push_back( coordSeq ) ;
+ }
+
+ // Add the right side curve to the line list.
+ if ( rightSide )
+ {
+ CoordinateArraySequence* coordSeq = new CoordinateArraySequence() ;
+ for ( int i = endCapIndex ; i <= n-2 ; ++i )
+ {
+ coordSeq->add( ( *lineCoord )[i] ) ;
+ }
+
+ lineList.push_back( coordSeq ) ;
+ }
+}
+
+/*public*/
+void
OffsetCurveBuilder::getRingCurve(const CoordinateSequence *inputPts,
int side, double distance,
vector<CoordinateSequence*>& lineList)
@@ -226,6 +283,10 @@
// add line cap for end of line
addLineEndCap(simp1[n1-1], simp1[n1]);
+ // Record the index of the end of line cap.
+ endCapIndex = vertexList->size() - 2 ;
+
+
//---------- compute points for right side of line
#ifndef SKIP_INPUT_SIMPLIFICATION
// Simplify the appropriate side of the line before generating
Modified: trunk/source/operation/buffer/OffsetCurveVertexList.h
===================================================================
--- trunk/source/operation/buffer/OffsetCurveVertexList.h 2009-09-21 19:47:45 UTC (rev 2627)
+++ trunk/source/operation/buffer/OffsetCurveVertexList.h 2009-09-27 20:43:03 UTC (rev 2628)
@@ -157,6 +157,8 @@
return ret;
}
+ inline int size() const { return ptList ? ptList->size() : 0 ; }
+
};
std::ostream& operator<< (std::ostream& os, const OffsetCurveVertexList& lst)
Modified: trunk/tests/xmltester/XMLTester.cpp
===================================================================
--- trunk/tests/xmltester/XMLTester.cpp 2009-09-21 19:47:45 UTC (rev 2627)
+++ trunk/tests/xmltester/XMLTester.cpp 2009-09-27 20:43:03 UTC (rev 2628)
@@ -852,9 +852,6 @@
expected_result=printGeom(gRes.get());
}
-// disabled till we have an actual api exposed for that
-// (and probably a different name)
-#if 0
else if (opName=="buffersinglesided")
{
using namespace operation::buffer;
@@ -921,7 +918,6 @@
actual_result=printGeom(gRealRes.get());
expected_result=printGeom(gRes.get());
}
-#endif
else if (opName=="buffermitredjoin")
{
More information about the geos-commits
mailing list