[geos-commits] [SCM] GEOS branch main updated. 4d1795abc69d644d97c820639e3519065419407e
git at osgeo.org
git at osgeo.org
Wed Oct 28 16:44:50 PDT 2026
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 4d1795abc69d644d97c820639e3519065419407e (commit)
from a2525885ffe40a641bb1521c2cdb013f8a64ba34 (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 4d1795abc69d644d97c820639e3519065419407e
Author: Daniel Baston <dbaston at gmail.com>
Date: Wed Oct 28 19:44:26 2026 -0400
CircularArcs: fix containsAngle for non-normalized angles (#1579)
diff --git a/include/geos/algorithm/CircularArcs.h b/include/geos/algorithm/CircularArcs.h
index a563e8f12..4b6fab60a 100644
--- a/include/geos/algorithm/CircularArcs.h
+++ b/include/geos/algorithm/CircularArcs.h
@@ -98,10 +98,12 @@ public:
const geom::CoordinateXY& p0, const geom::CoordinateXY& p1,
geom::CoordinateXY& isect0, geom::CoordinateXY& isect1);
- /** Returns whether an angle is included between two other angles.
+ /** Returns whether an angle is included between two other angles. The angles
+ * do not need to be normalized. If the start and end angles are the same,
+ * the input is assumed to represent a full circle.
*
* @param t0 starting angle (radians)
- * @param t2 ending engle (radians)
+ * @param t2 ending angle (radians)
* @param isCCW whether the interval from t0 to t2 is counterclockwise
* @param theta angle to test (radians)
* @return true if theta is included between t0 and t2
diff --git a/src/algorithm/CircularArcs.cpp b/src/algorithm/CircularArcs.cpp
index 03fc02cda..f997f19f0 100644
--- a/src/algorithm/CircularArcs.cpp
+++ b/src/algorithm/CircularArcs.cpp
@@ -416,10 +416,6 @@ CircularArcs::circleIntersectsSegment(const CoordinateXY& center, double r,
bool
CircularArcs::containsAngle(double t0, double t2, bool isCCW, double theta)
{
- if (theta == t0 || theta == t2) {
- return true;
- }
-
if (isCCW) {
std::swap(t0, t2);
}
@@ -427,15 +423,9 @@ CircularArcs::containsAngle(double t0, double t2, bool isCCW, double theta)
t2 -= t0;
theta -= t0;
- if (t2 < 0) {
- t2 += 2*MATH_PI;
- }
- if (theta < 0) {
- theta += 2*MATH_PI;
- }
-
- return theta >= t2;
+ const auto norm = Angle::normalizePositive(theta);
+ return norm == 0 || norm >= Angle::normalizePositive(t2);
}
bool
diff --git a/tests/unit/algorithm/CircularArcsTest.cpp b/tests/unit/algorithm/CircularArcsTest.cpp
index 07eda9cab..a19ccb50d 100644
--- a/tests/unit/algorithm/CircularArcsTest.cpp
+++ b/tests/unit/algorithm/CircularArcsTest.cpp
@@ -20,8 +20,41 @@ namespace tut {
struct test_circulararcs_data {
const double eps = 1e-8;
+ static constexpr int CCW_ = geos::algorithm::Orientation::COUNTERCLOCKWISE;
+ static constexpr int CW_ = geos::algorithm::Orientation::CLOCKWISE;
+ static constexpr int BOTH_ = 0;
+ static constexpr int NONE_ = -2;
+
using XY = CoordinateXY;
+ static void checkAngleContained(double theta, double t0, double t2, int orientation)
+ {
+ std::string angleRange = std::to_string(t0) + " to " + std::to_string(t2);
+
+ if (orientation == CCW_) {
+ ensure(std::to_string(theta) + " should be contained in ccw angle from " + angleRange,
+ CircularArcs::containsAngle(t0, t2, true, theta));
+ ensure(std::to_string(theta) + " should not be contained in cw angle from " + angleRange,
+ !CircularArcs::containsAngle(t0, t2, false, theta));
+ }
+ else if (orientation == CW_) {
+ ensure(std::to_string(theta) + " should not be contained in ccw angle from " + angleRange,
+ !CircularArcs::containsAngle(t0, t2, true, theta));
+ ensure(std::to_string(theta) + " should be contained in cw angle from " + angleRange,
+ CircularArcs::containsAngle(t0, t2, false, theta));
+ } else if (orientation == BOTH_) {
+ ensure(std::to_string(theta) + " should be contained in ccw angle from " + angleRange,
+ CircularArcs::containsAngle(t0, t2, true, theta));
+ ensure(std::to_string(theta) + " should be contained in cw angle from " + angleRange,
+ CircularArcs::containsAngle(t0, t2, false, theta));
+ } else {
+ ensure(std::to_string(theta) + " should not be contained in ccw angle from " + angleRange,
+ !CircularArcs::containsAngle(t0, t2, true, theta));
+ ensure(std::to_string(theta) + " should not be contained in cw angle from " + angleRange,
+ !CircularArcs::containsAngle(t0, t2, false, theta));
+ }
+ }
+
void checkEnvelope(const CoordinateXY& p0, const CoordinateXY& p1, const CoordinateXY& p2,
double xmin, double ymin, double xmax, double ymax) const
{
@@ -970,4 +1003,44 @@ set_test_name("getMidpointAngle");
ensure_equals(CircularArcs::getMidpointAngle(0, 0, false), MATH_PI);
}
+
+template<>
+template<>
+void object::test<71>()
+{
+ set_test_name("containsAngle");
+
+ using geos::algorithm::Orientation;
+
+ checkAngleContained(MATH_PI / 2, 0, MATH_PI, CCW_);
+ checkAngleContained(MATH_PI / 2, 2*MATH_PI, 3*MATH_PI, CCW_);
+ checkAngleContained(5*MATH_PI / 2, 2*MATH_PI, 3*MATH_PI, CCW_);
+ checkAngleContained(-MATH_PI / 2, 0, MATH_PI, CW_);
+ checkAngleContained(2.5 + MATH_PI, -2.5, 0, CCW_);
+
+ checkAngleContained(0, -MATH_PI / 2, MATH_PI / 2, CCW_);
+ checkAngleContained(2*MATH_PI, -MATH_PI / 2, MATH_PI / 2, CCW_);
+ checkAngleContained(4*MATH_PI, -MATH_PI / 2, MATH_PI / 2, CCW_);
+ checkAngleContained(-2*MATH_PI, -MATH_PI / 2, MATH_PI / 2, CCW_);
+ checkAngleContained(-4*MATH_PI, -MATH_PI / 2, MATH_PI / 2, CCW_);
+
+ checkAngleContained(MATH_PI, 3*MATH_PI/4, -3*MATH_PI/4, CCW_);
+ checkAngleContained(-MATH_PI, 3*MATH_PI/4, -3*MATH_PI/4, CCW_);
+ checkAngleContained(0, 3*MATH_PI/4, -3*MATH_PI/4, CW_);
+ checkAngleContained(MATH_PI/2, 3*MATH_PI/4, -3*MATH_PI/4, CW_);
+
+ // theta == t0
+ checkAngleContained(0, 0, 0, BOTH_);
+ checkAngleContained(0, 0, MATH_PI, BOTH_);
+ checkAngleContained(2*MATH_PI, 0, MATH_PI, BOTH_);
+
+ // t0 == t2, t0 == 0, full circle
+ checkAngleContained(MATH_PI, 0, 0, BOTH_);
+ checkAngleContained(MATH_PI, 0, 2*MATH_PI, BOTH_);
+
+ // t0 == t2, t0 != 0, full circle
+ checkAngleContained(MATH_PI, MATH_PI/4, MATH_PI/4, BOTH_);
+ checkAngleContained(MATH_PI, MATH_PI/4, 9*MATH_PI/4, BOTH_);
+}
+
}
-----------------------------------------------------------------------
Summary of changes:
include/geos/algorithm/CircularArcs.h | 6 ++-
src/algorithm/CircularArcs.cpp | 14 +-----
tests/unit/algorithm/CircularArcsTest.cpp | 73 +++++++++++++++++++++++++++++++
3 files changed, 79 insertions(+), 14 deletions(-)
hooks/post-receive
--
GEOS
More information about the geos-commits
mailing list