Polygon: Perform clip operation on existing object instead of returning a new clipped one
This commit is contained in:
parent
63cea992a0
commit
b1de220958
|
@ -1481,9 +1481,10 @@ void Monitor::DumpZoneImage(const char *zone_string) {
|
||||||
zone_image->Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB);
|
zone_image->Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB);
|
||||||
}
|
}
|
||||||
|
|
||||||
extra_zone = extra_zone.GetClipped(Box({0, 0},
|
extra_zone.Clip(Box(
|
||||||
{static_cast<int32>(zone_image->Width()),
|
{0, 0},
|
||||||
static_cast<int32>(zone_image->Height())}));
|
{static_cast<int32>(zone_image->Width()), static_cast<int32>(zone_image->Height())}
|
||||||
|
));
|
||||||
|
|
||||||
for (const Zone &zone : zones) {
|
for (const Zone &zone : zones) {
|
||||||
if (exclude_id && (!extra_colour || !extra_zone.GetVertices().empty()) && zone.Id() == exclude_id) {
|
if (exclude_id && (!extra_colour || !extra_zone.GetVertices().empty()) && zone.Id() == exclude_id) {
|
||||||
|
|
|
@ -22,47 +22,56 @@
|
||||||
#include "zm_line.h"
|
#include "zm_line.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
Polygon::Polygon(std::vector<Vector2> vertices) : vertices_(std::move(vertices)) {
|
Polygon::Polygon(std::vector<Vector2> vertices) : vertices_(std::move(vertices)), area(0) {
|
||||||
int min_x = -1;
|
UpdateExtent();
|
||||||
int max_x = -1;
|
UpdateArea();
|
||||||
int min_y = -1;
|
UpdateCentre();
|
||||||
int max_y = -1;
|
|
||||||
for (const Vector2 &vertex : vertices_) {
|
|
||||||
if (min_x == -1 || vertex.x_ < min_x)
|
|
||||||
min_x = vertex.x_;
|
|
||||||
if (max_x == -1 || vertex.x_ > max_x)
|
|
||||||
max_x = vertex.x_;
|
|
||||||
if (min_y == -1 || vertex.y_ < min_y)
|
|
||||||
min_y = vertex.y_;
|
|
||||||
if (max_y == -1 || vertex.y_ > max_y)
|
|
||||||
max_y = vertex.y_;
|
|
||||||
}
|
|
||||||
extent = Box({min_x, min_y}, {max_x, max_y});
|
|
||||||
|
|
||||||
calcArea();
|
|
||||||
calcCentre();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Polygon::calcArea() {
|
void Polygon::UpdateExtent() {
|
||||||
double float_area = 0.0L;
|
if (vertices_.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int min_x = vertices_[0].x_;
|
||||||
|
int max_x = 0;
|
||||||
|
int min_y = vertices_[0].y_;
|
||||||
|
int max_y = 0;
|
||||||
|
for (const Vector2 &vertex : vertices_) {
|
||||||
|
min_x = std::min(min_x, vertex.x_);
|
||||||
|
max_x = std::max(max_x, vertex.x_);
|
||||||
|
min_y = std::min(min_y, vertex.y_);
|
||||||
|
max_y = std::max(max_y, vertex.y_);
|
||||||
|
}
|
||||||
|
|
||||||
|
extent = Box({min_x, min_y}, {max_x, max_y});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Polygon::UpdateArea() {
|
||||||
|
double float_area = 0.0;
|
||||||
for (size_t i = 0, j = vertices_.size() - 1; i < vertices_.size(); j = i++) {
|
for (size_t i = 0, j = vertices_.size() - 1; i < vertices_.size(); j = i++) {
|
||||||
double trap_area = ((vertices_[i].x_ - vertices_[j].x_) * ((vertices_[i].y_ + vertices_[j].y_))) / 2.0L;
|
double trap_area = ((vertices_[i].x_ - vertices_[j].x_) * ((vertices_[i].y_ + vertices_[j].y_))) / 2.0;
|
||||||
float_area += trap_area;
|
float_area += trap_area;
|
||||||
}
|
}
|
||||||
area = (int) round(fabs(float_area));
|
|
||||||
|
area = static_cast<int32>(std::lround(std::fabs(float_area)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Polygon::calcCentre() {
|
void Polygon::UpdateCentre() {
|
||||||
if (!area && !vertices_.empty())
|
if (!area && !vertices_.empty())
|
||||||
calcArea();
|
UpdateArea();
|
||||||
double float_x = 0.0L, float_y = 0.0L;
|
|
||||||
|
double float_x = 0.0;
|
||||||
|
double float_y = 0.0;
|
||||||
for (size_t i = 0, j = vertices_.size() - 1; i < vertices_.size(); j = i++) {
|
for (size_t i = 0, j = vertices_.size() - 1; i < vertices_.size(); j = i++) {
|
||||||
float_x += ((vertices_[i].y_ - vertices_[j].y_) * ((vertices_[i].x_ * 2) + (vertices_[i].x_ * vertices_[j].x_) + (vertices_[j].x_ * 2)));
|
float_x += ((vertices_[i].y_ - vertices_[j].y_)
|
||||||
float_y += ((vertices_[j].x_ - vertices_[i].x_) * ((vertices_[i].y_ * 2) + (vertices_[i].y_ * vertices_[j].y_) + (vertices_[j].y_ * 2)));
|
* ((vertices_[i].x_ * 2) + (vertices_[i].x_ * vertices_[j].x_) + (vertices_[j].x_ * 2)));
|
||||||
|
float_y += ((vertices_[j].x_ - vertices_[i].x_)
|
||||||
|
* ((vertices_[i].y_ * 2) + (vertices_[i].y_ * vertices_[j].y_) + (vertices_[j].y_ * 2)));
|
||||||
}
|
}
|
||||||
float_x /= (6 * area);
|
float_x /= (6 * area);
|
||||||
float_y /= (6 * area);
|
float_y /= (6 * area);
|
||||||
centre = Vector2((int) round(float_x), (int) round(float_y));
|
|
||||||
|
centre = Vector2(static_cast<int32>(std::lround(float_x)), static_cast<int32>(std::lround(float_y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Polygon::Contains(const Vector2 &coord) const {
|
bool Polygon::Contains(const Vector2 &coord) const {
|
||||||
|
@ -77,10 +86,10 @@ bool Polygon::Contains(const Vector2 &coord) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clip the polygon to a rectangular boundary box using the Sutherland-Hodgman algorithm
|
// Clip the polygon to a rectangular boundary box using the Sutherland-Hodgman algorithm
|
||||||
Polygon Polygon::GetClipped(const Box &boundary) {
|
void Polygon::Clip(const Box &boundary) {
|
||||||
std::vector<Vector2> clipped_vertices = vertices_;
|
std::vector<Vector2> clipped_vertices = vertices_;
|
||||||
|
|
||||||
for (LineSegment const& clip_edge : boundary.Edges()) {
|
for (LineSegment const &clip_edge : boundary.Edges()) {
|
||||||
// convert our line segment to an infinite line
|
// convert our line segment to an infinite line
|
||||||
Line clip_line = Line(clip_edge);
|
Line clip_line = Line(clip_edge);
|
||||||
|
|
||||||
|
@ -105,5 +114,8 @@ Polygon Polygon::GetClipped(const Box &boundary) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Polygon(clipped_vertices);
|
vertices_ = clipped_vertices;
|
||||||
|
UpdateExtent();
|
||||||
|
UpdateArea();
|
||||||
|
UpdateCentre();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ struct Edge {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This class represents convex or concave non-self-intersecting polygons.
|
||||||
class Polygon {
|
class Polygon {
|
||||||
public:
|
public:
|
||||||
Polygon() : area(0) {}
|
Polygon() : area(0) {}
|
||||||
|
@ -55,11 +56,12 @@ class Polygon {
|
||||||
|
|
||||||
bool Contains(const Vector2 &coord) const;
|
bool Contains(const Vector2 &coord) const;
|
||||||
|
|
||||||
Polygon GetClipped(const Box &boundary);
|
void Clip(const Box &boundary);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void calcArea();
|
void UpdateExtent();
|
||||||
void calcCentre();
|
void UpdateArea();
|
||||||
|
void UpdateCentre();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Vector2> vertices_;
|
std::vector<Vector2> vertices_;
|
||||||
|
|
|
@ -885,7 +885,7 @@ std::vector<Zone> Zone::Load(Monitor *monitor) {
|
||||||
polygon.Extent().Hi().x_,
|
polygon.Extent().Hi().x_,
|
||||||
polygon.Extent().Hi().y_);
|
polygon.Extent().Hi().y_);
|
||||||
|
|
||||||
polygon = polygon.GetClipped(Box(
|
polygon.Clip(Box(
|
||||||
{0, 0},
|
{0, 0},
|
||||||
{static_cast<int32>(monitor->Width()), static_cast<int32>(monitor->Height())}
|
{static_cast<int32>(monitor->Width()), static_cast<int32>(monitor->Height())}
|
||||||
));
|
));
|
||||||
|
|
|
@ -56,16 +56,16 @@ TEST_CASE("Polygon: clipping") {
|
||||||
REQUIRE(p.Extent().Size() == Vector2(8, 7));
|
REQUIRE(p.Extent().Size() == Vector2(8, 7));
|
||||||
|
|
||||||
SECTION("boundary box larger than polygon") {
|
SECTION("boundary box larger than polygon") {
|
||||||
Polygon c = p.GetClipped(Box({1, 0}, {11, 9}));
|
p.Clip(Box({1, 0}, {11, 9}));
|
||||||
|
|
||||||
REQUIRE(c.GetVertices().size() == 11);
|
REQUIRE(p.GetVertices().size() == 11);
|
||||||
REQUIRE(c.Extent().Size() == Vector2(8, 7));
|
REQUIRE(p.Extent().Size() == Vector2(8, 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("boundary box smaller than polygon") {
|
SECTION("boundary box smaller than polygon") {
|
||||||
Polygon c = p.GetClipped(Box({2, 4}, {10, 7}));
|
p.Clip(Box({2, 4}, {10, 7}));
|
||||||
|
|
||||||
REQUIRE(c.GetVertices().size() == 8);
|
REQUIRE(p.GetVertices().size() == 8);
|
||||||
REQUIRE(c.Extent().Size() == Vector2(8, 3));
|
REQUIRE(p.Extent().Size() == Vector2(8, 3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue