Clipper.jl
Clipper.jl is a Julia wrapper for Angus Johnson's Clipper library (ver. 6.4.2).
It can be used for the following two tasks:
- offsetting a polygon
- compute boolean operations between two or more polygons
General description of a polygon
A polygon consists of a list of vertices $v_1, \dots, v_n$ such that $v_1$ is connected to $v_2$ and $v_n$. $v_i$ is connected to $v_{i-1}$ and $v_{i+1}$. All functionality in Clipper only works with vertices that have discrete coordinates. Therefore the struct IntPoint
is used. Points which consist of two floating point coordinates can however be easily converted using the IntPoint
method.
p = (1.1, 2.1)
ip = IntPoint(p..., 1, 3) # [110, 210]
Here 1
is the magnitude and 3
is the number of significant digits.
There is also the function tofloat
which can be used to convert a IntPoint
back to the floating point coordinates.
tofloat(ip, 1, 3) # (1.1, 2.1)
Using broadcasting you can also easily convert several points like a whole polygon this way:
ps = rand(100, 2)
ips = IntPoint.(ps[:,1], ps[:,2], 1, 3)
and back
tofloat.(ips, 1, 3)
Offsetting a polygon
Original Clipper documentation.
A polygon can be offset (inflated/deflated) in the following way using Clipper.jl:
polygon = IntPoint[]
push!(polygon, IntPoint(348,257))
push!(polygon, IntPoint(364,148))
push!(polygon, IntPoint(362,148))
push!(polygon, IntPoint(326,241))
push!(polygon, IntPoint(295,219))
push!(polygon, IntPoint(258,88))
push!(polygon, IntPoint(440,129))
push!(polygon, IntPoint(370,196))
push!(polygon, IntPoint(372,275))
co = ClipperOffset()
add_path!(co, polygon, JoinTypeRound, EndTypeClosedPolygon)
offset_polygons = execute(co, -7.0)
In the image above the blue polygon is the initial polygon and by offsetting it two polygons are created which are drawn as the filled green polygons.
We can also inflate the polygon by using a positive value in the execute function.
offset_polygons = execute(co, 7.0)
In this example we can visualize the meaning of the third argument in the add_path!
function which is currently set to JoinTypeRound
.
co = ClipperOffset()
add_path!(co, polygon, JoinTypeRound, EndTypeClosedPolygon)
round_offset_polygons = execute(co, 7.0)
co = ClipperOffset()
add_path!(co, polygon, JoinTypeSquare, EndTypeClosedPolygon)
square_offset_polygons = execute(co, 7.0)
co = ClipperOffset()
add_path!(co, polygon, JoinTypeMiter, EndTypeClosedPolygon)
miter_offset_polygons = execute(co, 7.0)
JoinTypeRound
produces rounded corners, JoinTypeSquare
produces squared corners. In the case of JoinTypeMiter
it depends on the degree of the angle or in different words the maximum offsetted distance if corners. would not be squared. If the maximum distance is bigger than MiterLimit * delta
than it is squared which would be the case in the upper right corner.
The MiterLimit
is the first argument of ClipperOffset
for example ClipperOffset(3.0)
would set it to 3.0
(default is 2.0
). delta
is simply the distance we want to offset in our case above we set it to 7.0
as the second parameter of the execute
function.
The three different types are also explained in the official documentation.
Boolean operations between two or more polygons
Needs to be written. Feel free to open a PR.