C++ API¶
Usage¶
Basic Usage¶
using namespace poly_ops;
std::vector<point_t<int>> loop_a{
{58,42},
{36,52},
{20,34},
{32,13},
{55,18}};
std::vector<point_t<int>> loop_b{
{76,58},
{43,56},
{45,23},
{78,26}};
auto output = boolean_op<false,int>(loop_a,loop_b,bool_op::difference);
for(auto loop : output) {
for(point_t<int> p : loop) {
std::cout << p[0] << ',' << p[1] << '\n';
}
std::cout << '\n';
}
Or using the clipper
class:
clipper<int> clip;
clip.add_loops_subject(loop_a);
clip.add_loops_clip(loop_b);
auto output2 = clip.execute<false>(bool_op::xor_);
Using the clipper
class is more efficient than calling
boolean_op()
multiple times because the class will reuse the memory it
allocated.
In both cases, the output is meant to be a temporary object that is traversed only once (although there is no harm in traversing it multiple times) and consumed or stored in a data structure of the user’s choice. It references the internal representation used by the algorithm and is not sequential.
In the case of the clipper
class, the output references the data
owned by the class. If the class is destroyed or if any of its methods are
called, the output is invalidated. The exception is, given an instance of
clipper
clip, calling std::move(clip).execute<...>(...)
will
return an object that takes ownership of the data.
Input Data Format¶
The functions and methods of this library take sequences of 2-dimensional points, representing closed polygons, where each point is connected to the next point in the sequence, and the last point is connected to the first.
The inputs can either be ranges (objects that satisfy std::ranges::range) of
points (objects that satisfy point
), which represent individual
polygons, or ranges of ranges of points, which represent sets of polygons.
E.g. polygons can be added like this:
std::vector<poly_ops::point_t<int>> loop_a{...};
std::vector<poly_ops::point_t<int>> loop_b{...};
poly_ops::clipper<int> clip;
clip.add_loops_subject(loop_a);
clip.add_loops_subject(loop_b);
or like this:
std::vector<std::vector<poly_ops::point_t<int>>> loops{...};
poly_ops::clipper<int> clip;
clip.add_loops_subject(loops);
In the case of the clipper
class, instead of providing a range,
points can be added one at a time using a “point sink”:
poly_ops::clipper<int> clip;
/* the sink object needs to be destroyed before using any other method
on "clip", hence the curly braces here */
{
auto sink = clip.add_loop(poly_ops::bool_set::subject);
for(int i=0; i<100; ++i) sink(get_next_point(i));
sink({0,0});
}
Under the hood, all add_loops- methods and even the free functions use the point sink to avoid template bloat.
Except for the normalize
operation, the
operations interpret clockwise polygons (assuming positive X is right and
positive Y is down) and clockwise portions of self-intersecting polygons as
solid geometry and counter-clockwise polygons/parts as holes. Input polygons
with fewer than three points are silently discarded.
Union operation with polygon that is half clockwise and half counter-clockwise.¶
Custom Point Type in Input¶
By default, given a type T: point_t<T>, T[2] and std::span<T,2> satisfy
point
. To use your own point type in the input instead of one of
the above, specialize point_ops
like so:
struct MyPoint {
float X;
float Y;
};
template<> struct poly_ops::point_ops<MyPoint> {
static int get_x(const MyPoint &p) {
return static_cast<int>(MyPoint.X * 100.0f);
}
static int get_y(const MyPoint &p) {
return static_cast<int>(MyPoint.Y * 100.0f);
}
};
int main() {
...
std::vector<MyPoint> loop_a{
{5.8f,4.2f},
{3.6f,5.2f},
{2.0f,3.4f},
{3.2f,1.3f},
{5.5f,1.8f}};
std::vector<MyPoint> loop_b{
{7.6f,5.8f},
{4.3f,5.6f},
{4.5f,2.3f},
{7.8f,2.6f}};
auto output = poly_ops::boolean_op<false,int>(
loop_a,loop_b,poly_ops::bool_op::difference);
...
}
The functions and methods of poly_ops will still return instances of
point_t
.
Getting the Results as a Hierarchy¶
void print_indent(int level) {
for(int i=0; i<level; ++i) std::cout << " ";
}
void print_polygon(const poly_ops::temp_polygon_proxy<int> &poly,int level=0) {
for(auto p : poly) {
print_indent(level);
std::cout << p[0] << ',' << p[1] << '\n';
}
std::cout << '\n';
auto child_polys = poly.inner_loops();
if(!child_polys.empty()) {
print_indent(level);
std::cout << "nested polygons:\n";
for(auto child : child_polys) print_polygon(child,level+1);
}
}
int main() {
...
auto output = poly_ops::boolean_op<true,int>(subject_loops,clip_loops,bool_op::normalize);
for(auto loop : output) print_polygon(loop);
...
}
Coord Template Parameter¶
The Coord template parameter of the functions and classes of this library is
the type that will represent coordinate values. This can be any built-in signed
integer or any class that satisfies coordinate
. When using your
own class, coord_ops
needs to be specialized to provide equivalent
mathematical functions.
Index Template Parameter¶
The Index template parameter of the functions and classes of this library is the type that will represent the numeric indices of the points. By default, this is std::size_t. This library uses this type extensively in it’s internal data structures, thus using a smaller type can save some memory; however, it must be large enough to represent the total number of points plus two times the number of intersections, of a single operation. Unlike Coord, this must be one of the built-in integers.
Reference¶
- poly_ops/base.hpp
- poly_ops/clip.hpp
- poly_ops/offset.hpp
- poly_ops/large_ints.hpp
- Concepts
- Types
compound_xint
value_type
compound_xint()
compound_xint()
compound_xint()
compound_xint()
compound_xint()
operator=()
operator=()
operator-()
operator T()
negative()
operator bool()
operator compound_xint_ref<N>()
operator const_compound_xint_ref<N>()
hi()
hi()
lo()
lo()
operator[]()
operator[]()
size()
data()
data()
begin()
begin()
end()
end()
compound_int
compound_uint
_compound_xint_ref
compound_xint_ref
const_compound_xint_ref
sized_int
quot_rem
value_t
type
- Constants
- Functions
add()
sub()
mul()
divmod()
unmul()
abs()
countl_zero()
shift_right()
shift_left()
eq()
cmp()
negative()
negative()
operator==()
operator==()
operator+()
operator+()
operator-()
operator-()
operator*()
operator*()
operator/()
operator/()
operator+=()
operator-=()
operator>>()
operator>>=()
operator<<()
operator<<=()
operator<=>()
operator""_compi()