DYT/Tool/OpenSceneGraph-3.6.5/include/geos/algorithm/construct/MaximumInscribedCircle.h
2024-12-25 07:49:36 +08:00

222 lines
6.5 KiB
C++

/**********************************************************************
*
* GEOS - Geometry Engine Open Source
* http://geos.osgeo.org
*
* Copyright (C) 2020 Paul Ramsey <pramsey@cleverelephant.ca>
*
* 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 <geos/geom/Coordinate.h>
#include <geos/geom/Point.h>
#include <geos/geom/Envelope.h>
#include <geos/algorithm/locate/IndexedPointInAreaLocator.h>
#include <geos/operation/distance/IndexedFacetDistance.h>
#include <memory>
#include <queue>
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<geom::Point> 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<geom::Point> 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<geom::LineString> 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<geom::Point> 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<geom::LineString> 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<geom::Geometry> 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<Cell>;
};
void createInitialGrid(const geom::Envelope* env, Cell::CellQueue& cellQueue);
Cell createInteriorPointCell(const geom::Geometry* geom);
};
} // geos::algorithm::construct
} // geos::algorithm
} // geos