/********************************************************************** * * GEOS - Geometry Engine Open Source * http://geos.osgeo.org * * Copyright (C) 2011 Sandro Santilli * * This is free software; you can redistribute and/or modify it under * the terms of the GNU Lesser General Public Licence as published * by the Free Software Foundation. * See the COPYING file for more information. * ********************************************************************** * * Last port: operation/buffer/OffsetSegmentGenerator.java r378 (JTS-1.12) * **********************************************************************/ #ifndef GEOS_OP_BUFFER_OFFSETSEGMENTGENERATOR_H #define GEOS_OP_BUFFER_OFFSETSEGMENTGENERATOR_H #include #include #include // for composition #include // for composition #include // for composition #include // for composition #include // for composition #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) // warning C4251: needs to have dll-interface to be used by clients of class #endif // Forward declarations namespace geos { namespace geom { class CoordinateSequence; class PrecisionModel; } } namespace geos { namespace operation { // geos.operation namespace buffer { // geos.operation.buffer /** * Generates segments which form an offset curve. * Supports all end cap and join options * provided for buffering. * Implements various heuristics to * produce smoother, simpler curves which are * still within a reasonable tolerance of the * true curve. * * @author Martin Davis * */ class GEOS_DLL OffsetSegmentGenerator { public: /* * @param nBufParams buffer parameters, this object will * keep a reference to the passed parameters * so caller must make sure the object is * kept alive for the whole lifetime of * the buffer builder. */ OffsetSegmentGenerator(const geom::PrecisionModel *newPrecisionModel, const BufferParameters& bufParams, double distance); /** * Tests whether the input has a narrow concave angle * (relative to the offset distance). * In this case the generated offset curve will contain self-intersections * and heuristic closing segments. * This is expected behaviour in the case of buffer curves. * For pure offset curves, * the output needs to be further treated * before it can be used. * * @return true if the input has a narrow concave angle */ bool hasNarrowConcaveAngle() const { return _hasNarrowConcaveAngle; } void initSideSegments(const geom::Coordinate &nS1, const geom::Coordinate &nS2, int nSide); /// Get coordinates by taking ownership of them // /// After this call, the coordinates reference in /// this object are dropped. Calling twice will /// segfault... /// /// FIXME: refactor memory management of this /// void getCoordinates(std::vector& to) { to.push_back(segList.getCoordinates()); } void closeRing() { segList.closeRing(); } /// Adds a CW circle around a point void createCircle(const geom::Coordinate &p, double distance); /// Adds a CW square around a point void createSquare(const geom::Coordinate &p, double distance); /// Add first offset point void addFirstSegment() { segList.addPt(offset1.p0); } /// Add last offset point void addLastSegment() { segList.addPt(offset1.p1); } void addNextSegment(const geom::Coordinate &p, bool addStartPoint); /// \brief /// Add an end cap around point p1, terminating a line segment /// coming from p0 void addLineEndCap(const geom::Coordinate &p0, const geom::Coordinate &p1); void addSegments(const geom::CoordinateSequence& pts, bool isForward) { segList.addPts(pts, isForward); } private: /** * Factor which controls how close offset segments can be to * skip adding a filler or mitre. */ static const double OFFSET_SEGMENT_SEPARATION_FACTOR; // 1.0E-3; /** * Factor which controls how close curve vertices on inside turns * can be to be snapped */ static const double INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR; // 1.0E-3; /** * Factor which controls how close curve vertices can be to be snapped */ static const double CURVE_VERTEX_SNAP_DISTANCE_FACTOR; // 1.0E-6; /** * Factor which determines how short closing segs can be for round buffers */ static const int MAX_CLOSING_SEG_LEN_FACTOR = 80; /** \brief * the max error of approximation (distance) between a quad segment and * the true fillet curve */ double maxCurveSegmentError; // 0.0 /** \brief * The angle quantum with which to approximate a fillet curve * (based on the input # of quadrant segments) */ double filletAngleQuantum; /// The Closing Segment Factor controls how long "closing /// segments" are. Closing segments are added at the middle of /// inside corners to ensure a smoother boundary for the buffer /// offset curve. In some cases (particularly for round joins /// with default-or-better quantization) the closing segments /// can be made quite short. This substantially improves /// performance (due to fewer intersections being created). /// /// A closingSegFactor of 0 results in lines to the corner vertex. /// A closingSegFactor of 1 results in lines halfway /// to the corner vertex. /// A closingSegFactor of 80 results in lines 1/81 of the way /// to the corner vertex (this option is reasonable for the very /// common default situation of round joins and quadrantSegs >= 8). /// /// The default is 1. /// int closingSegLengthFactor; // 1; /// Owned by this object, destroyed by dtor // /// This actually gets created multiple times /// and each of the old versions is pushed /// to the ptLists std::vector to ensure all /// created CoordinateSequences are properly /// destroyed. /// OffsetSegmentString segList; double distance; const geom::PrecisionModel* precisionModel; const BufferParameters& bufParams; algorithm::LineIntersector li; geom::Coordinate s0, s1, s2; geom::LineSegment seg0; geom::LineSegment seg1; geom::LineSegment offset0; geom::LineSegment offset1; int side; bool _hasNarrowConcaveAngle; // =false void addCollinear(bool addStartPoint); /// The mitre will be beveled if it exceeds the mitre ratio limit. // /// @param offset0 the first offset segment /// @param offset1 the second offset segment /// @param distance the offset distance /// void addMitreJoin(const geom::Coordinate& p, const geom::LineSegment& offset0, const geom::LineSegment& offset1, double distance); /// Adds a limited mitre join connecting the two reflex offset segments. // /// A limited mitre is a mitre which is beveled at the distance /// determined by the mitre ratio limit. /// /// @param offset0 the first offset segment /// @param offset1 the second offset segment /// @param distance the offset distance /// @param mitreLimit the mitre limit ratio /// void addLimitedMitreJoin( const geom::LineSegment& offset0, const geom::LineSegment& offset1, double distance, double mitreLimit); /// \brief /// Adds a bevel join connecting the two offset segments /// around a reflex corner. // /// @param offset0 the first offset segment /// @param offset1 the second offset segment /// void addBevelJoin(const geom::LineSegment& offset0, const geom::LineSegment& offset1); static const double PI; // 3.14159265358979 // Not in JTS, used for single-sided buffers int endCapIndex; void init(double newDistance); /** * Use a value which results in a potential distance error which is * significantly less than the error due to * the quadrant segment discretization. * For QS = 8 a value of 100 is reasonable. * This should produce a maximum of 1% distance error. */ static const double SIMPLIFY_FACTOR; // 100.0; /// Adds the offset points for an outside (convex) turn // /// @param orientation /// @param addStartPoint /// void addOutsideTurn(int orientation, bool addStartPoint); /// Adds the offset points for an inside (concave) turn // /// @param orientation /// @param addStartPoint /// void addInsideTurn(int orientation, bool addStartPoint); /** \brief * Compute an offset segment for an input segment on a given * side and at a given distance. * * The offset points are computed in full double precision, * for accuracy. * * @param seg the segment to offset * @param side the side of the segment the offset lies on * @param distance the offset distance * @param offset the points computed for the offset segment */ void computeOffsetSegment(const geom::LineSegment& seg, int side, double distance, geom::LineSegment& offset); /** * Adds points for a circular fillet around a reflex corner. * * Adds the start and end points * * @param p base point of curve * @param p0 start point of fillet curve * @param p1 endpoint of fillet curve * @param direction the orientation of the fillet * @param radius the radius of the fillet */ void addFillet(const geom::Coordinate &p, const geom::Coordinate &p0, const geom::Coordinate &p1, int direction, double radius); /** * Adds points for a circular fillet arc between two specified angles. * * The start and end point for the fillet are not added - * the caller must add them if required. * * @param direction is -1 for a CW angle, 1 for a CCW angle * @param radius the radius of the fillet */ void addFillet(const geom::Coordinate &p, double startAngle, double endAngle, int direction, double radius); private: // An OffsetSegmentGenerator cannot be copied because of member "const BufferParameters& bufParams" // Not declaring these functions triggers MSVC warning C4512: "assignment operator could not be generated" OffsetSegmentGenerator(const OffsetSegmentGenerator&); void operator=(const OffsetSegmentGenerator&); }; } // namespace geos::operation::buffer } // namespace geos::operation } // namespace geos #ifdef _MSC_VER #pragma warning(pop) #endif #endif // ndef GEOS_OP_BUFFER_OFFSETSEGMENTGENERATOR_H