[geos-commits] [SCM] GEOS branch main updated. 4ae3f0536735923dc93d6ea8a1e0dadafc791af1
git at osgeo.org
git at osgeo.org
Fri May 2 10:02:43 PDT 2025
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GEOS".
The branch, main has been updated
via 4ae3f0536735923dc93d6ea8a1e0dadafc791af1 (commit)
from 06f74885cb1fd6790bd9286ee2cd8433a349b890 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 4ae3f0536735923dc93d6ea8a1e0dadafc791af1
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date: Fri May 2 10:01:48 2025 -0700
Add MaximumInscribedCircle fast exact calculation for simple shapes, port of https://github.com/locationtech/jts/pull/1123
diff --git a/include/geos/algorithm/Angle.h b/include/geos/algorithm/Angle.h
index a2ea53a48..164c89844 100644
--- a/include/geos/algorithm/Angle.h
+++ b/include/geos/algorithm/Angle.h
@@ -147,6 +147,19 @@ public:
const geom::CoordinateXY& tail,
const geom::CoordinateXY& tip2);
+ /// Computes the angle of the unoriented bisector
+ /// of the smallest angle between two vectors.
+ /// The computed angle will be in the range (-Pi, Pi].
+ ///
+ /// @param tip1 the tip of v1
+ /// @param tail the tail of each vector
+ /// @param tip2 the tip of v2
+ /// @return the angle of the bisector between v1 and v2
+ ///
+ static double bisector(const geom::CoordinateXY& tip1,
+ const geom::CoordinateXY& tail,
+ const geom::CoordinateXY& tip2);
+
/// Computes the interior angle between two segments of a ring.
///
/// The ring is assumed to be oriented in a clockwise direction.
@@ -230,7 +243,6 @@ public:
/// @param rCos the result of cos(ang)
///
static inline void sinCosSnap(const double ang, double& rSin, double& rCos) {
- // calculate both; may be optimized with FSINCOS instruction
rSin = std::sin(ang);
rCos = std::cos(ang);
// snap near-zero values
@@ -238,6 +250,16 @@ public:
if (std::fabs(rCos) < 5e-16) rCos = 0.0;
}
+ /// Projects a point by a given angle and distance.
+ ///
+ /// @param p the point to project
+ /// @param angle the angle at which to project
+ /// @param dist the distance to project
+ /// @return the projected point
+ ///
+ static geom::CoordinateXY project(const geom::CoordinateXY& p,
+ double angle, double dist);
+
};
diff --git a/include/geos/algorithm/construct/ExactMaxInscribedCircle.h b/include/geos/algorithm/construct/ExactMaxInscribedCircle.h
new file mode 100644
index 000000000..d41866ef6
--- /dev/null
+++ b/include/geos/algorithm/construct/ExactMaxInscribedCircle.h
@@ -0,0 +1,122 @@
+/**********************************************************************
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.osgeo.org
+ *
+ * Copyright (c) 2020 Martin Davis
+ * Copyright (C) 2020 Paul Ramsey <pramsey at 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/ExactMaxInscribedCircle.java
+ * https://github.com/locationtech/jts/commit/8d5ced1b784d232e1eecf5df4b71873e8822336a
+ *
+ **********************************************************************/
+
+#pragma once
+
+#include <geos/geom/Coordinate.h>
+#include <geos/geom/LineSegment.h>
+
+#include <array>
+// #include <queue>
+
+
+
+namespace geos {
+namespace geom {
+class CoordinateSequence;
+class Geometry;
+class Polygon;
+}
+}
+
+namespace geos {
+namespace algorithm { // geos::algorithm
+namespace construct { // geos::algorithm::construct
+
+/**
+ * Computes the Maximum Inscribed Circle for some kinds of convex polygons.
+ * It determines the circle center point by computing Voronoi node points
+ * and testing them for distance to generating edges.
+ * This is more precise than iterated approximation,
+ * and faster for small polygons (such as triangles and convex quadrilaterals).
+ *
+ * @author Martin Davis
+ *
+ */
+class GEOS_DLL ExactMaxInscribedCircle {
+
+ using CoordinateSequence = geos::geom::CoordinateSequence;
+ using CoordinateXY = geos::geom::CoordinateXY;
+ using LineSegment = geos::geom::LineSegment;
+ using Polygon = geos::geom::Polygon;
+
+public:
+
+ ExactMaxInscribedCircle();
+
+ /**
+ * Tests whether a given geometry is supported by this class.
+ * Currently only triangles and convex quadrilaterals are supported.
+ *
+ * @param geom an areal geometry
+ * @return true if the geometry shape can be evaluated
+ */
+ static bool isSupported(const geom::Geometry* geom);
+
+ static std::pair<CoordinateXY, CoordinateXY> computeRadius(const Polygon* polygon);
+
+
+private:
+
+ static bool isTriangle(const Polygon* polygon);
+
+ static bool isQuadrilateral(const Polygon* polygon);
+
+ static std::pair<CoordinateXY, CoordinateXY> computeTriangle(const CoordinateSequence* ring);
+
+ /**
+ * The Voronoi nodes of a convex polygon occur at the intersection point
+ * of two bisectors of each triplet of edges.
+ * The Maximum Inscribed Circle center is the node
+ * is the farthest distance from the generating edges.
+ * For a quadrilateral there are 4 distinct edge triplets,
+ * at each edge with its adjacent edges.
+ *
+ * @param ring the polygon ring
+ * @return an array containing the incircle center and radius points
+ */
+ static std::pair<CoordinateXY, CoordinateXY> computeConvexQuadrilateral(const CoordinateSequence* ring);
+
+ static std::array<LineSegment, 4> computeBisectors(const CoordinateSequence* ptsCW,
+ double diameter);
+
+ static CoordinateXY nearestEdgePt(const CoordinateSequence* ring,
+ const CoordinateXY& pt);
+
+ static LineSegment computeConvexBisector(const CoordinateSequence* pts,
+ std::size_t index, double len);
+
+ static bool isConvex(const Polygon* polygon);
+
+ static bool isConvex(const CoordinateSequence* ring);
+
+ static bool isConvex(const CoordinateXY& p0,
+ const CoordinateXY& p1,
+ const CoordinateXY& p2);
+
+ static bool isPointInConvexRing(const CoordinateSequence* ringCW,
+ const CoordinateXY& p);
+
+};
+
+
+} // geos::algorithm::construct
+} // geos::algorithm
+} // geos
diff --git a/include/geos/algorithm/construct/MaximumInscribedCircle.h b/include/geos/algorithm/construct/MaximumInscribedCircle.h
index af4260c49..17d2a88a3 100644
--- a/include/geos/algorithm/construct/MaximumInscribedCircle.h
+++ b/include/geos/algorithm/construct/MaximumInscribedCircle.h
@@ -139,6 +139,8 @@ private:
double distanceToBoundary(const geom::Point& pt);
double distanceToBoundary(double x, double y);
void compute();
+ void computeApproximation();
+ void createResult(const geom::CoordinateXY& c, const geom::CoordinateXY& r);
/* private class */
class Cell {
diff --git a/include/geos/geom/Triangle.h b/include/geos/geom/Triangle.h
index 663f50ec5..0f54cb9ee 100644
--- a/include/geos/geom/Triangle.h
+++ b/include/geos/geom/Triangle.h
@@ -45,6 +45,11 @@ public:
*/
void inCentre(CoordinateXY& resultPoint);
+ static CoordinateXY inCentre(
+ const CoordinateXY& p0,
+ const CoordinateXY& p1,
+ const CoordinateXY& p2);
+
/** \brief
* Computes the circumcentre of a triangle.
*
diff --git a/src/algorithm/Angle.cpp b/src/algorithm/Angle.cpp
index 7069607f5..f9e176768 100644
--- a/src/algorithm/Angle.cpp
+++ b/src/algorithm/Angle.cpp
@@ -118,6 +118,19 @@ Angle::angleBetweenOriented(const geom::CoordinateXY& tip1,
return angDel;
}
+
+/* public static */
+double
+Angle::bisector(const geom::CoordinateXY& tip1,
+ const geom::CoordinateXY& tail,
+ const geom::CoordinateXY& tip2)
+{
+ double angDel = angleBetweenOriented(tip1, tail, tip2);
+ double angBi = angle(tail, tip1) + angDel / 2;
+ return normalize(angBi);
+}
+
+
/* public static */
double
Angle::interiorAngle(const geom::CoordinateXY& p0, const geom::CoordinateXY& p1,
@@ -187,20 +200,32 @@ Angle::diff(double ang1, double ang2)
{
double delAngle;
- if(ang1 < ang2) {
+ if (ang1 < ang2) {
delAngle = ang2 - ang1;
}
else {
delAngle = ang1 - ang2;
}
- if(delAngle > MATH_PI) {
+ if (delAngle > MATH_PI) {
delAngle = PI_TIMES_2 - delAngle;
}
return delAngle;
}
+/* public static */
+geom::CoordinateXY
+Angle::project(const geom::CoordinateXY& p, double angle, double dist)
+{
+ double cosSnap, sinSnap;
+ sinCosSnap(angle, sinSnap, cosSnap);
+ double x = p.x + dist * cosSnap;
+ double y = p.y + dist * sinSnap;
+ return geom::CoordinateXY(x, y);
+}
+
+
} // namespace geos.algorithm
} //namespace geos
diff --git a/src/algorithm/construct/ExactMaxInscribedCircle.cpp b/src/algorithm/construct/ExactMaxInscribedCircle.cpp
new file mode 100644
index 000000000..561133af4
--- /dev/null
+++ b/src/algorithm/construct/ExactMaxInscribedCircle.cpp
@@ -0,0 +1,267 @@
+/**********************************************************************
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.osgeo.org
+ *
+ * Copyright (c) 2020 Martin Davis
+ * Copyright (C) 2020 Paul Ramsey <pramsey at 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/ExactMaxInscribedCircle.java
+ * https://github.com/locationtech/jts/commit/8d5ced1b784d232e1eecf5df4b71873e8822336a
+ *
+ **********************************************************************/
+
+#include <geos/algorithm/construct/ExactMaxInscribedCircle.h>
+#include <geos/algorithm/Angle.h>
+#include <geos/algorithm/Orientation.h>
+#include <geos/geom/Coordinate.h>
+#include <geos/geom/CoordinateSequence.h>
+#include <geos/geom/Geometry.h>
+#include <geos/geom/LineSegment.h>
+#include <geos/geom/LinearRing.h>
+#include <geos/geom/Polygon.h>
+#include <geos/geom/Triangle.h>
+#include <geos/util/IllegalArgumentException.h>
+
+#include <typeinfo> // for dynamic_cast
+
+
+using namespace geos::geom;
+
+
+namespace geos {
+namespace algorithm { // geos.algorithm
+namespace construct { // geos.algorithm.construct
+
+
+/* public static */
+bool
+ExactMaxInscribedCircle::isSupported(const Geometry* geom)
+{
+ /* isSimplePolygon() */
+ /* TODO replace with geometryid test */
+ const Polygon* polygon = dynamic_cast<const Polygon*>(geom);
+ if (polygon == nullptr)
+ return false;
+ if (polygon->getNumInteriorRing() > 0)
+ return false;
+
+ if (isTriangle(polygon))
+ return true;
+ if (isQuadrilateral(polygon) && isConvex(polygon))
+ return true;
+ return false;
+}
+
+/* private static */
+bool
+ExactMaxInscribedCircle::isTriangle(const Polygon* polygon)
+{
+ return polygon->getNumPoints() == 4;
+}
+
+/* private static */
+bool
+ExactMaxInscribedCircle::isQuadrilateral(const Polygon* polygon)
+{
+ return polygon->getNumPoints() == 5;
+}
+
+/* public static */
+std::pair<CoordinateXY, CoordinateXY>
+ExactMaxInscribedCircle::computeRadius(const Polygon* polygon)
+{
+ const LinearRing* exRing = polygon->getExteriorRing();
+ const CoordinateSequence* ring = exRing->getCoordinatesRO();
+ if (exRing->getNumPoints() == 4)
+ return computeTriangle(ring);
+ else if (exRing->getNumPoints() == 5)
+ return computeConvexQuadrilateral(ring);
+ throw util::IllegalArgumentException("Input must be a triangle or convex quadrilateral");
+}
+
+/* private static */
+std::pair<CoordinateXY, CoordinateXY>
+ExactMaxInscribedCircle::computeTriangle(const CoordinateSequence* ring)
+{
+ CoordinateXY center = Triangle::inCentre(
+ ring->getAt(0), ring->getAt(1), ring->getAt(2));
+ LineSegment seg(ring->getAt(0), ring->getAt(1));
+ CoordinateXY radius = seg.project(center);
+ std::pair<CoordinateXY, CoordinateXY> result;
+ result.first = center;
+ result.second = radius;
+ return result;
+}
+
+/* private static */
+std::pair<CoordinateXY, CoordinateXY>
+ExactMaxInscribedCircle::computeConvexQuadrilateral(const CoordinateSequence* ring)
+{
+ /* Ensure ring is clockwise */
+ const CoordinateSequence* ringCW = ring;
+ std::unique_ptr<CoordinateSequence> ringPtr; // storage if we have to reverse
+ if (Orientation::isCCW(ring)) {
+ ringPtr = ring->clone();
+ ringPtr->reverse();
+ ringCW = ringPtr.get();
+ }
+
+ double diameter = ringCW->getEnvelope().getDiameter();
+
+ //-- compute corner bisectors
+ std::array<LineSegment, 4> bisector = computeBisectors(ringCW, diameter);
+ //-- compute nodes and find interior one farthest from sides
+ double maxDist = -1;
+ CoordinateXY center;
+ CoordinateXY radius;
+ for (std::size_t i = 0; i < 4; i++) {
+ LineSegment& b1 = bisector[i];
+ std::size_t i2 = (i + 1) % 4;
+ LineSegment& b2 = bisector[i2];
+
+ CoordinateXY nodePt = b1.intersection(b2);
+
+ //-- only interior nodes are considered
+ if (! isPointInConvexRing(ringCW, nodePt)) {
+ continue;
+ }
+
+ //-- check if node is further than current max center
+ CoordinateXY r = nearestEdgePt(ringCW, nodePt);
+ double dist = nodePt.distance(r);
+ if (maxDist < 0 || dist > maxDist) {
+ center = nodePt;
+ radius = r;
+ maxDist = dist;
+ }
+ }
+ std::pair<CoordinateXY, CoordinateXY> result;
+ result.first = center;
+ result.second = radius;
+ return result;
+}
+
+/* private static */
+std::array<LineSegment, 4>
+ExactMaxInscribedCircle::computeBisectors(
+ const CoordinateSequence* ptsCW, double diameter)
+{
+ std::array<LineSegment, 4> bisector;
+ for (std::size_t i = 0; i < 4; i++) {
+ bisector[i] = computeConvexBisector(ptsCW, i, diameter);
+ }
+ return bisector;
+}
+
+/* private static */
+CoordinateXY
+ExactMaxInscribedCircle::nearestEdgePt(const CoordinateSequence* ring,
+ const CoordinateXY& pt)
+{
+ CoordinateXY nearestPt;
+ CoordinateXY r;
+ double minDist = -1;
+ for (std::size_t i = 0; i < ring->size() - 1; i++) {
+ LineSegment edge(ring->getAt(i), ring->getAt(i + 1));
+ edge.closestPoint(pt, r);
+ double dist = pt.distance(r);
+ if (minDist < 0 || dist < minDist) {
+ minDist = dist;
+ nearestPt = r;
+ }
+ }
+ return nearestPt;
+}
+
+/* private static */
+LineSegment
+ExactMaxInscribedCircle::computeConvexBisector(
+ const CoordinateSequence* pts, std::size_t index, double len)
+{
+ const CoordinateXY& basePt = pts->getAt(index);
+ std::size_t iPrev = index == 0 ? pts->size() - 2 : index - 1;
+ std::size_t iNext = index >= pts->size() ? 0 : index + 1;
+ const CoordinateXY& pPrev = pts->getAt(iPrev);
+ const CoordinateXY& pNext = pts->getAt(iNext);
+ if (! isConvex(pPrev, basePt, pNext))
+ throw util::IllegalArgumentException("Input is not convex");
+ double bisectAng = Angle::bisector(pPrev, basePt, pNext);
+ CoordinateXY endPt = Angle::project(basePt, bisectAng, len);
+ return LineSegment(basePt.x, basePt.y, endPt.x, endPt.y);
+}
+
+/* private static */
+bool
+ExactMaxInscribedCircle::isConvex(const Polygon* polygon)
+{
+ const LinearRing* shell = polygon->getExteriorRing();
+ return isConvex(shell->getCoordinatesRO());
+}
+
+/* private static */
+bool
+ExactMaxInscribedCircle::isConvex(const CoordinateSequence* ring)
+{
+ /**
+ * A ring cannot be all concave, so if it has a consistent
+ * orientation it must be convex.
+ */
+ std::size_t n = ring->size();
+ if (n < 4)
+ return false;
+ int ringOrient = 0;
+ for (std::size_t i = 0; i < n - 1; i++) {
+ std::size_t i1 = i + 1;
+ std::size_t i2 = (i1 >= n - 1) ? 1 : i1 + 1;
+ int orient = Orientation::index(
+ ring->getAt(i),
+ ring->getAt(i1),
+ ring->getAt(i2));
+ if (orient == Orientation::COLLINEAR)
+ continue;
+ if (ringOrient == 0) {
+ ringOrient = orient;
+ }
+ else if (orient != ringOrient) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/* private static */
+bool
+ExactMaxInscribedCircle::isConvex(const CoordinateXY& p0,
+ const CoordinateXY& p1,
+ const CoordinateXY& p2)
+{
+ return Orientation::CLOCKWISE == Orientation::index(p0, p1, p2);
+}
+
+/* private static */
+bool
+ExactMaxInscribedCircle::isPointInConvexRing(const CoordinateSequence* ringCW,
+ const CoordinateXY& p)
+{
+ for (std::size_t i = 0; i < ringCW->size() - 1; i++) {
+ const CoordinateXY& p0 = ringCW->getAt(i);
+ const CoordinateXY& p1 = ringCW->getAt(i + 1);
+ int orient = Orientation::index(p0, p1, p);
+ if (orient == Orientation::COUNTERCLOCKWISE)
+ return false;
+ }
+ return true;
+}
+
+
+} // namespace geos.algorithm.construct
+} // namespace geos.algorithm
+} // namespace geos
diff --git a/src/algorithm/construct/MaximumInscribedCircle.cpp b/src/algorithm/construct/MaximumInscribedCircle.cpp
index a8f83d1be..686b9aa30 100644
--- a/src/algorithm/construct/MaximumInscribedCircle.cpp
+++ b/src/algorithm/construct/MaximumInscribedCircle.cpp
@@ -18,6 +18,7 @@
**********************************************************************/
#include <geos/algorithm/construct/MaximumInscribedCircle.h>
+#include <geos/algorithm/construct/ExactMaxInscribedCircle.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/Envelope.h>
@@ -174,10 +175,45 @@ MaximumInscribedCircle::createInteriorPointCell(const Geometry* geom)
void
MaximumInscribedCircle::compute()
{
-
// check if already computed
if (done) return;
+ /**
+ * Handle empty or flat geometries.
+ */
+ if (inputGeom->getArea() == 0.0) {
+ const CoordinateXY* c = inputGeom->getCoordinate();
+ createResult(*c, *c);
+ return;
+ }
+
+ /**
+ * Optimization for small simple convex polygons
+ */
+ if (ExactMaxInscribedCircle::isSupported(inputGeom)) {
+ auto polygonal = static_cast<const Polygon*>(inputGeom);
+ std::pair<CoordinateXY, CoordinateXY> centreRadius = ExactMaxInscribedCircle::computeRadius(polygonal);
+ createResult(centreRadius.first, centreRadius.second);
+ return;
+ }
+
+ computeApproximation();
+}
+
+
+/* private */
+void MaximumInscribedCircle::createResult(
+ const CoordinateXY& c, const CoordinateXY& r)
+{
+ centerPt = c;
+ radiusPt = r;
+}
+
+
+/* private */
+void
+MaximumInscribedCircle::computeApproximation()
+{
// Priority queue of cells, ordered by maximum distance from boundary
Cell::CellQueue cellQueue;
diff --git a/src/geom/Triangle.cpp b/src/geom/Triangle.cpp
index 90dad34cd..61241b127 100644
--- a/src/geom/Triangle.cpp
+++ b/src/geom/Triangle.cpp
@@ -51,6 +51,19 @@ Triangle::inCentre(CoordinateXY& result)
result = CoordinateXY(inCentreX, inCentreY);
}
+
+CoordinateXY
+Triangle::inCentre(const CoordinateXY& p0,
+ const CoordinateXY& p1,
+ const CoordinateXY& p2)
+{
+ Triangle tri(p0, p1, p2);
+ CoordinateXY result;
+ tri.inCentre(result);
+ return result;
+}
+
+
void
Triangle::circumcentre(CoordinateXY& result)
{
diff --git a/tests/unit/algorithm/construct/MaximumInscribedCircleTest.cpp b/tests/unit/algorithm/construct/MaximumInscribedCircleTest.cpp
index dcab53cc8..4f10b0c29 100644
--- a/tests/unit/algorithm/construct/MaximumInscribedCircleTest.cpp
+++ b/tests/unit/algorithm/construct/MaximumInscribedCircleTest.cpp
@@ -119,8 +119,7 @@ group test_mic_group("geos::algorithm::construct::MaximumInscribedCircle");
//
template<>
template<>
-void object::test<1>
-()
+void object::test<1> ()
{
checkCircle("POLYGON ((100 200, 200 200, 200 100, 100 100, 100 200))",
0.001, 150, 150, 50);
@@ -131,8 +130,7 @@ void object::test<1>
//
template<>
template<>
-void object::test<2>
-()
+void object::test<2> ()
{
checkCircle("POLYGON ((150 250, 50 150, 150 50, 250 150, 150 250))",
0.001, 150, 150, 70.71 );
@@ -143,8 +141,7 @@ void object::test<2>
//
template<>
template<>
-void object::test<3>
-()
+void object::test<3> ()
{
std::unique_ptr<Geometry> geom(reader_.read("POINT (100 100)"));
std::unique_ptr<Geometry> circle(geom->buffer(100, 20));
@@ -157,8 +154,7 @@ void object::test<3>
//
template<>
template<>
-void object::test<4>
-()
+void object::test<4> ()
{
checkCircle("MULTIPOLYGON (((150 200, 100 150, 150 100, 250 150, 150 200)), ((400 250, 300 150, 400 50, 560 150, 400 250)))",
0.001, 411.38877, 149.9996185, 78.7634662 );
@@ -169,8 +165,7 @@ void object::test<4>
//
template<>
template<>
-void object::test<5>
-()
+void object::test<5> ()
{
checkCircle("POLYGON ((100 100, 200 200, 100 100, 100 100))",
0.01, 100, 100, 0 );
@@ -182,8 +177,7 @@ void object::test<5>
// //
template<>
template<>
-void object::test<6>
-()
+void object::test<6> ()
{
checkCircle("POLYGON ((100 100, 100 100, 100 100, 100 100))",
0.01, 100, 100, 0 );
@@ -194,8 +188,7 @@ void object::test<6>
// //
template<>
template<>
-void object::test<7>
-()
+void object::test<7> ()
{
checkCircle("POLYGON((1 2, 1 2, 1 2, 1 2, 3 2, 1 2))",
0.01, 1, 2, 0 );
@@ -204,8 +197,7 @@ void object::test<7>
// Exception thrown to avoid infinite loop with infinite envelope
template<>
template<>
-void object::test<8>
-()
+void object::test<8> ()
{
auto g1 = reader_.read("POLYGON ((0 0, 1 0, 1 1, 0 Inf, 0 0))");
try {
@@ -232,8 +224,7 @@ void object::test<8>
// testNearlyFlat
template<>
template<>
-void object::test<9>
-()
+void object::test<9> ()
{
checkCircle("POLYGON ((59.3 100.00000000000001, 99.7 100.00000000000001, 99.7 100, 59.3 100, 59.3 100.00000000000001))",
0.01 );
@@ -242,8 +233,7 @@ void object::test<9>
// testVeryThin
template<>
template<>
-void object::test<10>
-()
+void object::test<10> ()
{
checkCircle("POLYGON ((100 100, 200 300, 300 100, 450 250, 300 99.999999, 200 299.99999, 100 100))",
0.01 );
@@ -254,12 +244,57 @@ void object::test<10>
//
template<>
template<>
-void object::test<11>
-()
+void object::test<11> ()
{
checkCircle("POLYGON((0 -10,-7.07107 -7.07107,-10 0,-7.07107 7.07107,0 10,7.07107 7.07107,10 0,7.07107 -7.07107,0 -10))",
0.1, 0, 0, 9.2387);
}
+/* testTriangleRight() */
+template<>
+template<>
+void object::test<12> ()
+{
+ checkCircle("POLYGON ((1 1, 1 9, 9 1, 1 1))",
+ 0.001, 3.343, 3.343, 2.343 );
+}
+
+/* testTriangleObtuse */
+template<>
+template<>
+void object::test<13> ()
+{
+ checkCircle("POLYGON ((1 1, 1 9, 2 2, 1 1))",
+ 0.01, 1.485, 2.173, 0.485 );
+}
+
+/* testThinQuad */
+template<>
+template<>
+void object::test<14> ()
+{
+ checkCircle("POLYGON ((1 2, 9 3, 9 1, 1 1, 1 2))",
+ 0.001, 8.0623, 1.9377, 0.93774 );
+}
+
+/* testChevron */
+template<>
+template<>
+void object::test<15> ()
+{
+ checkCircle("POLYGON ((1 1, 6 9, 3.7 2.5, 9 1, 1 1))",
+ 0.001, 2.82, 2.008, 1.008 );
+}
+
+/* testChevronFat */
+template<>
+template<>
+void object::test<16> ()
+{
+ checkCircle("POLYGON ((1 1, 6 9, 5.9 5, 9 1, 1 1))",
+ 0.001, 4.7545, 3.0809, 2.081 );
+}
+
+
} // namespace tut
-----------------------------------------------------------------------
Summary of changes:
include/geos/algorithm/Angle.h | 24 +-
.../algorithm/construct/ExactMaxInscribedCircle.h | 122 ++++++++++
.../algorithm/construct/MaximumInscribedCircle.h | 2 +
include/geos/geom/Triangle.h | 5 +
src/algorithm/Angle.cpp | 29 ++-
.../construct/ExactMaxInscribedCircle.cpp | 267 +++++++++++++++++++++
src/algorithm/construct/MaximumInscribedCircle.cpp | 38 ++-
src/geom/Triangle.cpp | 13 +
.../construct/MaximumInscribedCircleTest.cpp | 79 ++++--
9 files changed, 553 insertions(+), 26 deletions(-)
create mode 100644 include/geos/algorithm/construct/ExactMaxInscribedCircle.h
create mode 100644 src/algorithm/construct/ExactMaxInscribedCircle.cpp
hooks/post-receive
--
GEOS
More information about the geos-commits
mailing list