/********************************************************************** * $Id: BufferOp.cpp,v 1.35 2004/11/08 15:58:13 strk Exp $ * * GEOS - Geometry Engine Open Source * http://geos.refractions.net * * Copyright (C) 2001-2002 Vivid Solutions Inc. * * 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. * **********************************************************************/ #include #include #include #ifndef DEBUG #define DEBUG 0 #endif //#define PROFILE 1 namespace geos { #if PROFILE static Profiler *profiler = Profiler::instance(); #endif /** * Compute a reasonable scale factor to limit the precision of * a given combination of Geometry and buffer distance-> * The scale factor is based on a heuristic-> * * @param g the Geometry being buffered * @param distance the buffer distance * @param maxPrecisionDigits the mzx # of digits that should be allowed by * the precision determined by the computed scale factor * * @return a scale factor that allows a reasonable amount of precision for the buffer computation */ double BufferOp::precisionScaleFactor(Geometry *g,double distance,int maxPrecisionDigits){ const Envelope *env=g->getEnvelopeInternal(); double envSize=max(env->getHeight(), env->getWidth()); //delete env; double expandByDistance=distance > 0.0 ? distance : 0.0; double bufEnvSize=envSize + 2 * expandByDistance; // the smallest power of 10 greater than the buffer envelope int bufEnvLog10=(int) (log(bufEnvSize) / log(10.0) + 1.0); int minUnitLog10=bufEnvLog10 - maxPrecisionDigits; // scale factor is inverse of min Unit size, so flip sign of exponent double scaleFactor=pow(10.0,-minUnitLog10); return scaleFactor; } /** * Computes the buffer of a geometry for a given buffer distance-> * * @param g the geometry to buffer * @param distance the buffer distance * @return the buffer of the input geometry */ Geometry* BufferOp::bufferOp(Geometry *g, double distance){ Geometry *ret = BufferOp(g).getResultGeometry(distance); #if PROFILE cerr<<*profiler< * * @param g the geometry to buffer * @param distance the buffer distance * @param quadrantSegments the number of segments used to approximate a quarter circle * @return the buffer of the input geometry * */ Geometry* BufferOp::bufferOp(Geometry *g, double distance, int quadrantSegments) { BufferOp bufOp=BufferOp(g); bufOp.setQuadrantSegments(quadrantSegments); return bufOp.getResultGeometry(distance); } int BufferOp::MAX_PRECISION_DIGITS=12; /** * Initializes a buffer computation for the given geometry * * @param g the geometry to buffer */ BufferOp::BufferOp(Geometry *g) { quadrantSegments=OffsetCurveBuilder::DEFAULT_QUADRANT_SEGMENTS; endCapStyle=BufferOp::CAP_ROUND; argGeom = g; resultGeometry=NULL; saveException=NULL; } /** * Specifies the end cap style of the generated buffer-> * The styles supported are {@link CAP_ROUND}, {@link CAP_BUTT}, and {@link CAP_SQUARE}-> * The default is CAP_ROUND-> * * @param endCapStyle the end cap style to specify */ void BufferOp::setEndCapStyle(int nEndCapStyle){ endCapStyle=nEndCapStyle; } /** * Specifies the end cap style of the generated buffer-> * The styles supported are {@link CAP_ROUND}, {@link CAP_BUTT}, and {@link CAP_SQUARE}-> * The default is CAP_ROUND-> * * @param endCapStyle the end cap style to specify */ void BufferOp::setQuadrantSegments(int nQuadrantSegments){ quadrantSegments=nQuadrantSegments; } /** * Returns the buffer computed for a geometry for a given buffer distance-> * * @param g the geometry to buffer * @param distance the buffer distance * @return the buffer of the input geometry */ Geometry* BufferOp::getResultGeometry(double nDistance){ distance=nDistance; computeGeometry(); return resultGeometry; } /* * Computes the buffer for a geometry for a given buffer distance * and accuracy of approximation-> * * @param g the geometry to buffer * @param distance the buffer distance * @param quadrantSegments the number of segments used to approximate * a quarter circle * @return the buffer of the input geometry * * @deprecated use setQuadrantSegments instead */ Geometry* BufferOp::getResultGeometry(double nDistance, int nQuadrantSegments){ distance=nDistance; setQuadrantSegments(nQuadrantSegments); computeGeometry(); return resultGeometry; } void BufferOp::computeGeometry() { #if DEBUG cerr<<"BufferOp::computeGeometry: trying with original precision"<start("BufferOp::bufferOriginalPrecision()"); #endif bufferOriginalPrecision(); #if PROFILE profiler->stop("BufferOp::bufferOriginalPrecision()"); #endif if (resultGeometry!=NULL) return; // try and compute with decreasing precision for (int precDigits=MAX_PRECISION_DIGITS; precDigits >= 0; precDigits--) { #if DEBUG cerr<<"BufferOp::computeGeometry: trying with precDigits "<toString()<toString()<