• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

paulmthompson / WhiskerToolbox / 16272883191

14 Jul 2025 04:46PM UTC coverage: 75.171% (+1.0%) from 74.211%
16272883191

push

github

paulmthompson
update added in martinez-rueda source code with adapter for polygon intersections

533 of 821 new or added lines in 12 files covered. (64.92%)

14989 of 19940 relevant lines covered (75.17%)

2144.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.14
/src/WhiskerToolbox/CoreGeometry/src/polygon_adapter.cpp
1
#include "CoreGeometry/polygon_adapter.hpp"
2
#include <stdexcept>
3
#include <limits>
4

5
cbop::Point_2 PolygonAdapter::toMartinezPoint(const Point2D<float>& point) {
168✔
6
    return cbop::Point_2(static_cast<double>(point.x), static_cast<double>(point.y));
168✔
7
}
8

9
Point2D<float> PolygonAdapter::fromMartinezPoint(const cbop::Point_2& martinez_point) {
83✔
10
    return Point2D<float>(static_cast<float>(martinez_point.x()), static_cast<float>(martinez_point.y()));
83✔
11
}
12

13
cbop::Polygon PolygonAdapter::toMartinezPolygon(const Polygon& polygon) {
44✔
14
    cbop::Polygon martinez_polygon;
44✔
15
    
16
    if (!polygon.isValid()) {
44✔
NEW
17
        return martinez_polygon; // Return empty polygon
×
18
    }
19
    
20
    const auto& vertices = polygon.getVertices();
44✔
21
    if (vertices.size() < 3) {
44✔
NEW
22
        return martinez_polygon; // Return empty polygon
×
23
    }
24
    
25
    // Create the main contour
26
    cbop::Contour contour;
44✔
27
    for (const auto& vertex : vertices) {
212✔
28
        contour.add(toMartinezPoint(vertex));
168✔
29
    }
30
    
31
    // Add the contour to the polygon
32
    martinez_polygon.push_back(contour);
44✔
33
    
34
    return martinez_polygon;
44✔
35
}
44✔
36

37
Polygon PolygonAdapter::fromMartinezPolygon(const cbop::Polygon& martinez_polygon) {
22✔
38
    if (martinez_polygon.ncontours() == 0) {
22✔
39
        return Polygon(std::vector<Point2D<float>>{}); // Return empty polygon
6✔
40
    }
41
    
42
    if (martinez_polygon.ncontours() == 1) {
19✔
43
        // Simple case: single contour
44
        const cbop::Contour& main_contour = martinez_polygon.contour(0);
16✔
45
        
46
        std::vector<Point2D<float>> vertices;
16✔
47
        vertices.reserve(main_contour.nvertices());
16✔
48
        
49
        for (unsigned int i = 0; i < main_contour.nvertices(); ++i) {
99✔
50
            vertices.push_back(fromMartinezPoint(main_contour.vertex(i)));
83✔
51
        }
52
        
53
        return Polygon(vertices);
16✔
54
    } else {
16✔
55
        // Multiple contours case: create a bounding box that encompasses all contours
56
        // This is a reasonable approximation when we need to return a single polygon
57
        // but the actual result has multiple disjoint regions
58
        
59
        // Find the bounding box of all contours
60
        double min_x = std::numeric_limits<double>::max();
3✔
61
        double min_y = std::numeric_limits<double>::max();
3✔
62
        double max_x = std::numeric_limits<double>::lowest();
3✔
63
        double max_y = std::numeric_limits<double>::lowest();
3✔
64
        
65
        for (unsigned int c = 0; c < martinez_polygon.ncontours(); ++c) {
9✔
66
            const cbop::Contour& contour = martinez_polygon.contour(c);
6✔
67
            if (contour.external()) { // Only consider external contours, not holes
6✔
68
                for (unsigned int i = 0; i < contour.nvertices(); ++i) {
30✔
69
                    const cbop::Point_2& pt = contour.vertex(i);
24✔
70
                    min_x = std::min(min_x, pt.x());
24✔
71
                    min_y = std::min(min_y, pt.y());
24✔
72
                    max_x = std::max(max_x, pt.x());
24✔
73
                    max_y = std::max(max_y, pt.y());
24✔
74
                }
75
            }
76
        }
77
        
78
        // Create a rectangular polygon from the bounding box
79
        BoundingBox bbox(static_cast<float>(min_x), static_cast<float>(min_y), 
3✔
80
                        static_cast<float>(max_x), static_cast<float>(max_y));
3✔
81
        return Polygon(bbox);
3✔
82
    }
83
}
84

85
Polygon PolygonAdapter::performBooleanOperation(const Polygon& poly1, const Polygon& poly2, cbop::BooleanOpType operation) {
27✔
86
    if (!poly1.isValid() || !poly2.isValid()) {
27✔
87
        // Handle degenerate cases
88
        switch (operation) {
5✔
89
            case cbop::UNION:
3✔
90
                return poly1.isValid() ? poly1 : poly2;
3✔
91
            case cbop::INTERSECTION:
1✔
92
                return Polygon(std::vector<Point2D<float>>{}); // Empty polygon
2✔
93
            case cbop::DIFFERENCE:
1✔
94
                return poly1.isValid() ? poly1 : Polygon(std::vector<Point2D<float>>{});
1✔
NEW
95
            case cbop::XOR:
×
NEW
96
                return poly1.isValid() ? poly1 : poly2;
×
NEW
97
            default:
×
NEW
98
                return Polygon(std::vector<Point2D<float>>{});
×
99
        }
100
    }
101
    
102
    try {
103
        // Convert to Martinez-Rueda format
104
        cbop::Polygon martinez_poly1 = toMartinezPolygon(poly1);
22✔
105
        cbop::Polygon martinez_poly2 = toMartinezPolygon(poly2);
22✔
106
        cbop::Polygon result_polygon;
22✔
107
        
108
        // Perform the boolean operation
109
        cbop::compute(martinez_poly1, martinez_poly2, result_polygon, operation);
22✔
110
        
111
        // Convert back to our format
112
        return fromMartinezPolygon(result_polygon);
22✔
113
    }
22✔
NEW
114
    catch (const std::exception& e) {
×
115
        // If the operation fails, return an empty polygon
116
        // In a production system, you might want to log this error
NEW
117
        return Polygon(std::vector<Point2D<float>>{});
×
NEW
118
    }
×
119
}
120

121
Polygon PolygonAdapter::performUnion(const Polygon& poly1, const Polygon& poly2) {
10✔
122
    return performBooleanOperation(poly1, poly2, cbop::UNION);
10✔
123
}
124

125
Polygon PolygonAdapter::performIntersection(const Polygon& poly1, const Polygon& poly2) {
11✔
126
    return performBooleanOperation(poly1, poly2, cbop::INTERSECTION);
11✔
127
}
128

129
Polygon PolygonAdapter::performDifference(const Polygon& poly1, const Polygon& poly2) {
6✔
130
    return performBooleanOperation(poly1, poly2, cbop::DIFFERENCE);
6✔
131
}
132

NEW
133
Polygon PolygonAdapter::performXor(const Polygon& poly1, const Polygon& poly2) {
×
NEW
134
    return performBooleanOperation(poly1, poly2, cbop::XOR);
×
135
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc