/********************************************************************** * * GEOS - Geometry Engine Open Source * http://geos.osgeo.org * * Copyright (C) 2020 Paul Ramsey * * 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: algorithm/construct/MaximumInscribedCircle.java * https://github.com/locationtech/jts/commit/98274a7ea9b40651e9de6323dc10fb2cac17a245 * **********************************************************************/ #pragma once #include #include #include #include #include #include #include namespace geos { namespace geom { class Coordinate; class Envelope; class Geometry; class GeometryFactory; class LineString; class Point; } } using geos::algorithm::locate::IndexedPointInAreaLocator; using geos::operation::distance::IndexedFacetDistance; namespace geos { namespace algorithm { // geos::algorithm namespace construct { // geos::algorithm::construct /** * Computes the Euclidean distance (L2 metric) from a Point to a Geometry. * * Also computes two points which are separated by the distance. */ class GEOS_DLL MaximumInscribedCircle { public: MaximumInscribedCircle(const geom::Geometry* polygonal, double tolerance); ~MaximumInscribedCircle() = default; /** * Gets the center point of the maximum inscribed circle * (up to the tolerance distance). * * @return the center point of the maximum inscribed circle */ std::unique_ptr getCenter(); /** * Gets a point defining the radius of the Maximum Inscribed Circle. * This is a point on the boundary which is * nearest to the computed center of the Maximum Inscribed Circle. * The line segment from the center to this point * is a radius of the constructed circle, and this point * lies on the boundary of the circle. * * @return a point defining the radius of the Maximum Inscribed Circle */ std::unique_ptr getRadiusPoint(); /** * Gets a line representing a radius of the Largest Empty Circle. * * @return a line from the center of the circle to a point on the edge */ std::unique_ptr getRadiusLine(); /** * Computes the center point of the Maximum Inscribed Circle * of a polygonal geometry, up to a given tolerance distance. * * @param polygonal a polygonal geometry * @param tolerance the distance tolerance for computing the center point * @return the center point of the maximum inscribed circle */ static std::unique_ptr getCenter(const geom::Geometry* polygonal, double tolerance); /** * Computes a radius line of the Maximum Inscribed Circle * of a polygonal geometry, up to a given tolerance distance. * * @param polygonal a polygonal geometry * @param tolerance the distance tolerance for computing the center point * @return a line from the center to a point on the circle */ static std::unique_ptr getRadiusLine(const geom::Geometry* polygonal, double tolerance); /** * Computes the maximum number of iterations allowed. * Uses a heuristic based on the area of the input geometry * and the tolerance distance. * The number of tolerance-sized cells that cover the input geometry area * is computed, times a safety factor. * This prevents massive numbers of iterations and created cells * for casees where the input geometry has extremely small area * (e.g. is very thin). * * @param geom the input geometry * @param toleranceDist the tolerance distance * @return the maximum number of iterations allowed */ static std::size_t computeMaximumIterations(const geom::Geometry* geom, double toleranceDist); private: /* private members */ const geom::Geometry* inputGeom; std::unique_ptr inputGeomBoundary; double tolerance; IndexedFacetDistance indexedDistance; IndexedPointInAreaLocator ptLocator; const geom::GeometryFactory* factory; bool done; geom::CoordinateXY centerPt; geom::CoordinateXY radiusPt; /* private methods */ double distanceToBoundary(const geom::Coordinate& c); double distanceToBoundary(double x, double y); void compute(); /* private class */ class Cell { private: static constexpr double SQRT2 = 1.4142135623730951; double x; double y; double hSize; double distance; double maxDist; public: Cell(double p_x, double p_y, double p_hSize, double p_distanceToBoundary) : x(p_x) , y(p_y) , hSize(p_hSize) , distance(p_distanceToBoundary) , maxDist(p_distanceToBoundary+(p_hSize*SQRT2)) {}; geom::Envelope getEnvelope() const { geom::Envelope env(x-hSize, x+hSize, y-hSize, y+hSize); return env; } double getMaxDistance() const { return maxDist; } double getDistance() const { return distance; } double getHSize() const { return hSize; } double getX() const { return x; } double getY() const { return y; } bool operator< (const Cell& rhs) const { return maxDist < rhs.maxDist; } bool operator> (const Cell& rhs) const { return maxDist > rhs.maxDist; } bool operator==(const Cell& rhs) const { return maxDist == rhs.maxDist; } /** * The Cell priority queue is sorted by the natural order of maxDistance. * std::priority_queue sorts with largest first, * which is what is needed for this algorithm. */ using CellQueue = std::priority_queue; }; void createInitialGrid(const geom::Envelope* env, Cell::CellQueue& cellQueue); Cell createInteriorPointCell(const geom::Geometry* geom); }; } // geos::algorithm::construct } // geos::algorithm } // geos