From a67414700ac163df8f6fbcc403b121d4757b738d Mon Sep 17 00:00:00 2001 From: "Jarvis (Equilateral AI)" Date: Sun, 12 Oct 2025 16:32:41 -0400 Subject: [PATCH] fix: Use inclusive boundaries in ofRectangle::inside() (Issue #4871) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes ofRectangle::inside() from exclusive (>, <) to inclusive (>=, <=) boundary checks. This fixes intersects() failures when line segment endpoints lie exactly on rectangle boundaries. Test case from issue #4871: ofRectangle(0, 0, 100, 100).intersects(ofPoint(0, 50), ofPoint(50, 0)) now correctly returns true. Added comprehensive unit tests in tests/types/rectangleTests/ covering: - Corner points - Edge points - Interior points - Exterior points - Various line segment intersection cases Rationale: In computational geometry, boundary points are typically considered "inside" a closed shape. The intersects() method already handles line-edge crossing detection, so endpoints on boundaries must be recognized as inside for complete intersection coverage. 🤖 Generated with assistance from Equilateral AI This contribution was created with AI assistance and reviewed by human engineers. Our agents follow the standards documented at: https://github.com/Equilateral-AI/equilateral-open-standards Opt-out: If you prefer not to receive AI-assisted contributions, please email james.ford@equilateral.ai Co-Authored-By: Jarvis (Equilateral AI) --- libs/openFrameworks/types/ofRectangle.cpp | 4 +- tests/types/rectangleTests/src/main.cpp | 77 +++++++++++++++++++++++ 2 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 tests/types/rectangleTests/src/main.cpp diff --git a/libs/openFrameworks/types/ofRectangle.cpp b/libs/openFrameworks/types/ofRectangle.cpp index 5cb2bd5f270..d91df9a5684 100644 --- a/libs/openFrameworks/types/ofRectangle.cpp +++ b/libs/openFrameworks/types/ofRectangle.cpp @@ -438,8 +438,8 @@ bool ofRectangle::inside(const glm::vec3& p) const { //---------------------------------------------------------- bool ofRectangle::inside(const glm::vec2& p) const { - return p.x > getMinX() && p.y > getMinY() && - p.x < getMaxX() && p.y < getMaxY(); + return p.x >= getMinX() && p.y >= getMinY() && + p.x <= getMaxX() && p.y <= getMaxY(); } //---------------------------------------------------------- diff --git a/tests/types/rectangleTests/src/main.cpp b/tests/types/rectangleTests/src/main.cpp new file mode 100644 index 00000000000..0b3dd3f939a --- /dev/null +++ b/tests/types/rectangleTests/src/main.cpp @@ -0,0 +1,77 @@ +#include "ofMain.h" +#include "ofAppNoWindow.h" +#include "ofxUnitTests.h" + +class ofApp: public ofxUnitTestsApp{ + void run(){ + // Test case from Issue #4871 + // ofRectangle(0, 0, 100, 100).intersects(ofPoint(0, 50), ofPoint(50, 0)) + // should return true because the line segment has both endpoints on the rectangle boundary + ofRectangle rect1(0, 0, 100, 100); + ofxTest(rect1.intersects(glm::vec2(0, 50), glm::vec2(50, 0)), + "Issue #4871: Line segment with endpoints on rectangle boundary should intersect"); + + // Additional boundary tests + // Points exactly on corners + ofRectangle rect2(0, 0, 100, 100); + ofxTest(rect2.inside(glm::vec2(0, 0)), "Bottom-left corner should be inside"); + ofxTest(rect2.inside(glm::vec2(100, 0)), "Bottom-right corner should be inside"); + ofxTest(rect2.inside(glm::vec2(0, 100)), "Top-left corner should be inside"); + ofxTest(rect2.inside(glm::vec2(100, 100)), "Top-right corner should be inside"); + + // Points on edges + ofRectangle rect3(0, 0, 100, 100); + ofxTest(rect3.inside(glm::vec2(50, 0)), "Point on bottom edge should be inside"); + ofxTest(rect3.inside(glm::vec2(50, 100)), "Point on top edge should be inside"); + ofxTest(rect3.inside(glm::vec2(0, 50)), "Point on left edge should be inside"); + ofxTest(rect3.inside(glm::vec2(100, 50)), "Point on right edge should be inside"); + + // Points clearly inside + ofRectangle rect4(0, 0, 100, 100); + ofxTest(rect4.inside(glm::vec2(50, 50)), "Center point should be inside"); + ofxTest(rect4.inside(glm::vec2(25, 25)), "Interior point should be inside"); + + // Points clearly outside + ofRectangle rect5(0, 0, 100, 100); + ofxTest(!rect5.inside(glm::vec2(-1, 50)), "Point left of rectangle should be outside"); + ofxTest(!rect5.inside(glm::vec2(101, 50)), "Point right of rectangle should be outside"); + ofxTest(!rect5.inside(glm::vec2(50, -1)), "Point below rectangle should be outside"); + ofxTest(!rect5.inside(glm::vec2(50, 101)), "Point above rectangle should be outside"); + + // Line intersection tests - both endpoints inside + ofRectangle rect6(0, 0, 100, 100); + ofxTest(rect6.intersects(glm::vec2(25, 25), glm::vec2(75, 75)), + "Line with both endpoints inside should intersect"); + + // Line intersection tests - both endpoints outside, but line crosses + ofRectangle rect7(0, 0, 100, 100); + ofxTest(rect7.intersects(glm::vec2(-10, 50), glm::vec2(110, 50)), + "Line crossing horizontally should intersect"); + ofxTest(rect7.intersects(glm::vec2(50, -10), glm::vec2(50, 110)), + "Line crossing vertically should intersect"); + + // Line intersection tests - one endpoint inside, one outside + ofRectangle rect8(0, 0, 100, 100); + ofxTest(rect8.intersects(glm::vec2(50, 50), glm::vec2(150, 150)), + "Line with one endpoint inside should intersect"); + + // Line intersection tests - both endpoints outside, line doesn't cross + ofRectangle rect9(0, 0, 100, 100); + ofxTest(!rect9.intersects(glm::vec2(-10, -10), glm::vec2(-5, -5)), + "Line completely outside should not intersect"); + + // Diagonal line through corners (boundary case) + ofRectangle rect10(0, 0, 100, 100); + ofxTest(rect10.intersects(glm::vec2(0, 0), glm::vec2(100, 100)), + "Diagonal line through corners should intersect"); + } +}; + +//======================================================================== +int main( ){ + ofInit(); + auto window = std::make_shared(); + auto app = std::make_shared(); + ofRunApp(window, app); + return ofRunMainLoop(); +}