mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-11-05 04:02:56 -05:00
fix: clamp percentage polygon to width-1/height-1
ParsePercentagePolygon clamped to [0, width] / [0, height], so a new zone created at 100% produced pixel coords equal to the monitor dimensions. The rasterizer requires hi_x < width and hi_y < height, so the runtime then logged warnings like "polygon hi_x (1920) >= image width (1920), clamping". Clamp to width-1 / height-1 instead. Updates existing tests that encoded the previous behavior.
This commit is contained in:
1 parent
4a167f7f30
commit
e1eb7876c6
2 files changed
+24
-23
No files matched your search
+4
-3
@@ -862,9 +862,10 @@ bool Zone::ParsePercentagePolygon(const char *poly_string, unsigned int width, u
|
||||
int32 px_x = static_cast<int32>(std::lround(pct_x * mon_w / 100.0));
|
||||
int32 px_y = static_cast<int32>(std::lround(pct_y * mon_h / 100.0));
|
||||
|
||||
// Clamp to monitor bounds
|
||||
px_x = std::clamp(px_x, static_cast<int32>(0), static_cast<int32>(width));
|
||||
px_y = std::clamp(px_y, static_cast<int32>(0), static_cast<int32>(height));
|
||||
// Clamp to monitor bounds. Max valid pixel index is width-1/height-1;
|
||||
// values equal to width/height cause out-of-bounds warnings in the rasterizer.
|
||||
px_x = std::clamp(px_x, static_cast<int32>(0), static_cast<int32>(width) - 1);
|
||||
px_y = std::clamp(px_y, static_cast<int32>(0), static_cast<int32>(height) - 1);
|
||||
|
||||
Debug(3, "Percentage coord %.2f,%.2f -> pixel %d,%d", pct_x, pct_y, px_x, px_y);
|
||||
vertices.emplace_back(px_x, px_y);
|
||||
|
||||
+20
-20
@@ -28,9 +28,9 @@ TEST_CASE("Zone::ParsePercentagePolygon: full-frame zone at 1920x1080", "[Zone]"
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(polygon.GetVertices().size() == 4);
|
||||
REQUIRE(polygon.GetVertices()[0] == Vector2(0, 0));
|
||||
REQUIRE(polygon.GetVertices()[1] == Vector2(1920, 0));
|
||||
REQUIRE(polygon.GetVertices()[2] == Vector2(1920, 1080));
|
||||
REQUIRE(polygon.GetVertices()[3] == Vector2(0, 1080));
|
||||
REQUIRE(polygon.GetVertices()[1] == Vector2(1919, 0));
|
||||
REQUIRE(polygon.GetVertices()[2] == Vector2(1919, 1079));
|
||||
REQUIRE(polygon.GetVertices()[3] == Vector2(0, 1079));
|
||||
}
|
||||
|
||||
TEST_CASE("Zone::ParsePercentagePolygon: center 50% zone", "[Zone]") {
|
||||
@@ -68,8 +68,8 @@ TEST_CASE("Zone::ParsePercentagePolygon: different resolution", "[Zone]") {
|
||||
640, 480, polygon);
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(polygon.GetVertices()[1] == Vector2(640, 0));
|
||||
REQUIRE(polygon.GetVertices()[2] == Vector2(640, 480));
|
||||
REQUIRE(polygon.GetVertices()[1] == Vector2(639, 0));
|
||||
REQUIRE(polygon.GetVertices()[2] == Vector2(639, 479));
|
||||
}
|
||||
|
||||
TEST_CASE("Zone::ParsePercentagePolygon: clamping beyond 100%", "[Zone]") {
|
||||
@@ -79,8 +79,8 @@ TEST_CASE("Zone::ParsePercentagePolygon: clamping beyond 100%", "[Zone]") {
|
||||
1920, 1080, polygon);
|
||||
|
||||
REQUIRE(result == true);
|
||||
// 110% should be clamped to monitor width
|
||||
REQUIRE(polygon.GetVertices()[1].x_ == 1920);
|
||||
// 110% should be clamped to max valid pixel index (width-1)
|
||||
REQUIRE(polygon.GetVertices()[1].x_ == 1919);
|
||||
}
|
||||
|
||||
TEST_CASE("Zone::ParsePercentagePolygon: triangle", "[Zone]") {
|
||||
@@ -114,9 +114,9 @@ TEST_CASE("Zone::ParsePercentagePolygon: integer coords still work", "[Zone]") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(polygon.GetVertices()[0] == Vector2(0, 0));
|
||||
REQUIRE(polygon.GetVertices()[1] == Vector2(1920, 0));
|
||||
REQUIRE(polygon.GetVertices()[2] == Vector2(1920, 1080));
|
||||
REQUIRE(polygon.GetVertices()[3] == Vector2(0, 1080));
|
||||
REQUIRE(polygon.GetVertices()[1] == Vector2(1919, 0));
|
||||
REQUIRE(polygon.GetVertices()[2] == Vector2(1919, 1079));
|
||||
REQUIRE(polygon.GetVertices()[3] == Vector2(0, 1079));
|
||||
}
|
||||
|
||||
TEST_CASE("Zone::ParsePolygonString: basic pixel parsing", "[Zone]") {
|
||||
@@ -166,9 +166,9 @@ TEST_CASE("Zone::ParsePercentagePolygon: percentage to pixel conversion", "[Zone
|
||||
auto const &verts = polygon.GetVertices();
|
||||
REQUIRE(verts.size() == 4);
|
||||
REQUIRE(verts[0] == Vector2(0, 0));
|
||||
REQUIRE(verts[1] == Vector2(1920, 0));
|
||||
REQUIRE(verts[2] == Vector2(1920, 1080));
|
||||
REQUIRE(verts[3] == Vector2(0, 1080));
|
||||
REQUIRE(verts[1] == Vector2(1919, 0));
|
||||
REQUIRE(verts[2] == Vector2(1919, 1079));
|
||||
REQUIRE(verts[3] == Vector2(0, 1079));
|
||||
}
|
||||
|
||||
SECTION("50% rectangle converts to half-resolution pixels") {
|
||||
@@ -184,16 +184,16 @@ TEST_CASE("Zone::ParsePercentagePolygon: percentage to pixel conversion", "[Zone
|
||||
}
|
||||
|
||||
SECTION("values are clamped to monitor bounds") {
|
||||
// 100% should clamp to exact monitor dimensions
|
||||
// 100% should clamp to max valid pixel index (width-1, height-1)
|
||||
bool ok = Zone::ParsePercentagePolygon("0,0 100,0 100,100 0,100", width, height, polygon);
|
||||
REQUIRE(ok);
|
||||
|
||||
auto const &verts = polygon.GetVertices();
|
||||
for (auto const &v : verts) {
|
||||
REQUIRE(v.x_ >= 0);
|
||||
REQUIRE(v.x_ <= static_cast<int>(width));
|
||||
REQUIRE(v.x_ < static_cast<int>(width));
|
||||
REQUIRE(v.y_ >= 0);
|
||||
REQUIRE(v.y_ <= static_cast<int>(height));
|
||||
REQUIRE(v.y_ < static_cast<int>(height));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,12 +213,12 @@ TEST_CASE("Zone: pixel values through ParsePercentagePolygon produce wrong resul
|
||||
auto const &verts = polygon.GetVertices();
|
||||
REQUIRE(verts.size() == 4);
|
||||
|
||||
// 639% of 1920 = 12268.8 -> clamped to 1920
|
||||
// 479% of 1080 = 5173.2 -> clamped to 1080
|
||||
// 639% of 1920 = 12268.8 -> clamped to width-1
|
||||
// 479% of 1080 = 5173.2 -> clamped to height-1
|
||||
// All non-zero coords get clamped to monitor bounds — the zone is
|
||||
// degenerate (covers the full monitor instead of a sub-region)
|
||||
REQUIRE(verts[1] == Vector2(static_cast<int>(width), 0));
|
||||
REQUIRE(verts[2] == Vector2(static_cast<int>(width), static_cast<int>(height)));
|
||||
REQUIRE(verts[1] == Vector2(static_cast<int>(width) - 1, 0));
|
||||
REQUIRE(verts[2] == Vector2(static_cast<int>(width) - 1, static_cast<int>(height) - 1));
|
||||
}
|
||||
|
||||
// --- Auto-detect format tests ---
|
||||
|
||||
Reference in new issue
Block a user