Skip to content

Commit c227e65

Browse files
committed
make polygon plotting work
1 parent b319739 commit c227e65

File tree

7 files changed

+117
-22
lines changed

7 files changed

+117
-22
lines changed

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ authors = ["SimonDanisch <[email protected]>"]
44
version = "0.2.15"
55

66
[deps]
7+
EarCut_jll = "5ae413db-bbd1-5e63-b57d-d24a61df00f5"
78
IterTools = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
89
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
910
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

src/GeometryBasics.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module GeometryBasics
22

33
using StaticArrays, Tables, StructArrays, IterTools, LinearAlgebra
4+
using EarCut_jll
45

56
using Base: @propagate_inbounds
67

@@ -12,15 +13,15 @@ module GeometryBasics
1213
include("viewtypes.jl")
1314
include("geometry_primitives.jl")
1415
include("rectangles.jl")
15-
include("triangulation.jl")
1616
include("meshes.jl")
17+
include("triangulation.jl")
1718
include("lines.jl")
1819
include("boundingboxes.jl")
1920

2021
export AbstractGeometry, GeometryPrimitive
2122
export Mat, Point, Vec
2223
export LineFace, Polytope, Line, NgonFace, convert_simplex
23-
export LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon
24+
export LineString, AbstractPolygon, Polygon, MultiPoint, MultiLineString, MultiPolygon
2425
export Simplex, connect, Triangle, NSimplex, Tetrahedron
2526
export QuadFace, metafree, coordinates, TetrahedronFace
2627
export TupleView, SimplexFace, Mesh, meta
@@ -36,7 +37,7 @@ module GeometryBasics
3637
export AbstractMesh, Mesh, TriangleMesh
3738
export GLNormalMesh2D, PlainTriangleMesh
3839
export MetaT, meta_table
39-
40+
4041
# all the different predefined mesh types
4142
# Note: meshes can contain arbitrary meta information,
4243
export AbstractMesh, TriangleMesh, PlainMesh, GLPlainMesh, GLPlainMesh2D, GLPlainMesh3D

src/basic_types.jl

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ function Polytope(::Type{<: NNgon{N}}, P::Type{<: AbstractPoint{NDim, T}}) where
9292
return Ngon{NDim, T, N, P}
9393
end
9494

95-
9695
const LineP{Dim, T, P <: AbstractPoint{Dim, T}} = Ngon{Dim, T, 2, P}
9796
const Line{Dim, T} = LineP{Dim, T, Point{Dim, T}}
9897

@@ -111,6 +110,17 @@ const Quadrilateral{Dim, T} = Ngon{Dim, T, 4, P} where P <: AbstractPoint{Dim, T
111110
Base.show(io::IO, x::Quadrilateral) = print(io, "Quad(", join(x, ", "), ")")
112111
Base.summary(io::IO, x::Type{<: Quadrilateral}) = print(io, "Quad")
113112

113+
function coordinates(lines::AbstractArray{LineP{Dim, T, PointType}}) where {Dim, T, PointType}
114+
if lines isa Base.ReinterpretArray
115+
return coordinates(lines.parent)
116+
else
117+
result = PointType[]
118+
for line in lines
119+
append!(result, coordinates(line))
120+
end
121+
return result
122+
end
123+
end
114124

115125
"""
116126
A `Simplex` is a generalization of an N-dimensional tetrahedra and can be thought
@@ -181,7 +191,7 @@ struct LineString{
181191
points::V
182192
end
183193

184-
coordinates(x::LineString) = x.points
194+
coordinates(x::LineString) = coordinates(x.points)
185195

186196
Base.copy(x::LineString) = LineString(copy(x.points))
187197
Base.size(x::LineString) = size(coordinates(x))
@@ -276,6 +286,22 @@ function Polygon(exterior::AbstractVector{P}, faces::AbstractVector{<: LineFace}
276286
return Polygon(LineString(exterior, faces))
277287
end
278288

289+
function Polygon(exterior::AbstractVector{P}, interior::AbstractVector{<:AbstractVector{P}}) where P <: AbstractPoint{Dim, T} where {Dim, T}
290+
return Polygon(LineString(exterior), LineString.(interior))
291+
end
292+
293+
function coordinates(polygon::Polygon{N, T, PointType}) where {N, T, PointType}
294+
exterior = coordinates(polygon.exterior)
295+
if isempty(polygon.interiors)
296+
return exterior
297+
else
298+
result = PointType[]
299+
append!(result, exterior)
300+
foreach(x-> append!(result, coordinates(x)), polygon.interiors)
301+
return result
302+
end
303+
end
304+
279305
"""
280306
MultiPolygon(polygons::AbstractPolygon)
281307
"""

src/interfaces.jl

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,12 @@ faces(tesselation::Tesselation) = faces(tesselation.primitive, nvertices(tessela
7575
normals(tesselation::Tesselation) = normals(tesselation.primitive, nvertices(tesselation))
7676
texturecoordinates(tesselation::Tesselation) = texturecoordinates(tesselation.primitive, nvertices(tesselation))
7777

78-
7978
## Decompose methods
8079
# Dispatch type to make `decompose(UV{Vec2f0}, primitive)` work
8180
# and to pass through tesselation information
8281

8382
# Types that can be converted to a mesh via the functions below
84-
const Meshable{Dim, T} = Union{Tesselation{Dim, T}, Mesh{Dim, T},
83+
const Meshable{Dim, T} = Union{Tesselation{Dim, T}, Mesh{Dim, T}, AbstractPolygon{Dim, T},
8584
GeometryPrimitive{Dim, T}, AbstractVector{<: AbstractPoint{Dim, T}}}
8685

8786
struct UV{T} end
@@ -104,27 +103,22 @@ function decompose(::Type{P}, primitive) where {P<:AbstractPoint}
104103
return collect_with_eltype(P, metafree(coordinates(primitive)))
105104
end
106105

106+
function decompose(::Type{P}, primitive) where {P<:AbstractPoint}
107+
return collect_with_eltype(P, metafree(coordinates(primitive)))
108+
end
109+
107110
function decompose(::Type{Point}, primitive::Meshable{Dim, T}) where {Dim, T}
108111
return collect_with_eltype(Point{Dim, T}, metafree(coordinates(primitive)))
109112
end
113+
function decompose(::Type{Point}, primitive::LineString{Dim, T}) where {Dim, T}
114+
return collect_with_eltype(Point{Dim, T}, metafree(coordinates(primitive)))
115+
end
116+
110117

111118
function decompose(::Type{T}, primitive) where {T}
112119
return collect_with_eltype(T, primitive)
113120
end
114121

115-
function decompose(::Type{P}, pol::Polygon) where {P<:AbstractPoint}
116-
if isempty(pol.interiors)
117-
return decompose(P, pol.exterior)
118-
else
119-
arr = copy(decompose(P, pol.exterior))
120-
for i in pol.interiors
121-
append!(arr, decompose(P, i))
122-
end
123-
return arr
124-
end
125-
end
126-
127-
decompose(::Type{P}, ls::LineString) where {P<:AbstractPoint} = ls.points.parent.data
128122
decompose_uv(primitive) = decompose(UV(), primitive)
129123
decompose_uvw(primitive) = decompose(UVW(), primitive)
130124
decompose_normals(primitive) = decompose(Normal(), primitive)

src/meshes.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ function normals(mesh::AbstractMesh)
1414
return nothing
1515
end
1616

17-
1817
const GLTriangleElement = Triangle{3, Float32}
1918
const GLTriangleFace = TriangleFace{GLIndex}
2019
const PointWithUV{Dim, T} = PointMeta{Dim, T, Point{Dim, T}, (:uv,), Tuple{Vec{2, T}}}
@@ -144,14 +143,19 @@ Polygon triangluation!
144143
function mesh(polygon::AbstractVector{P}; pointtype=P, facetype=GLTriangleFace,
145144
normaltype=nothing) where {P<:AbstractPoint{2}}
146145

146+
return mesh(Polygon(polygon); pointtype, facetype, normaltype)
147+
end
148+
149+
function mesh(polygon::AbstractPolygon{Dim, T}; pointtype=Point{Dim, T}, facetype=GLTriangleFace,
150+
normaltype=nothing) where {Dim, T}
151+
147152
faces = decompose(facetype, polygon)
148153
positions = decompose(pointtype, polygon)
149154

150155
if normaltype !== nothing
151156
n = normals(positions, faces; normaltype=normaltype)
152157
positions = meta(positions; normals=n)
153158
end
154-
155159
return Mesh(positions, faces)
156160
end
157161

src/triangulation.jl

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,70 @@ function decompose(::Type{FaceType}, points::AbstractArray{P}) where {P<:Abstrac
169169

170170
return result
171171
end
172+
173+
174+
function earcut_triangulate(polygon::Vector{Vector{Point{2, Float64}}})
175+
lengths = map(x-> UInt32(length(x)), polygon)
176+
len = UInt32(length(lengths))
177+
array = ccall(
178+
(:u32_triangulate_f64, libearcut),
179+
Tuple{Ptr{GLTriangleFace}, Cint},
180+
(Ptr{Ptr{Float64}}, Ptr{UInt32}, UInt32),
181+
polygon, lengths, len
182+
)
183+
return unsafe_wrap(Vector{GLTriangleFace}, array[1], array[2])
184+
end
185+
186+
function earcut_triangulate(polygon::Vector{Vector{Point{2, Float32}}})
187+
lengths = map(x-> UInt32(length(x)), polygon)
188+
len = UInt32(length(lengths))
189+
array = ccall(
190+
(:u32_triangulate_f32, libearcut),
191+
Tuple{Ptr{GLTriangleFace}, Cint},
192+
(Ptr{Ptr{Float32}}, Ptr{UInt32}, UInt32),
193+
polygon, lengths, len
194+
)
195+
return unsafe_wrap(Vector{GLTriangleFace}, array[1], array[2])
196+
end
197+
198+
function earcut_triangulate(polygon::Vector{Vector{Point{2, Int64}}})
199+
lengths = map(x-> UInt32(length(x)), polygon)
200+
len = UInt32(length(lengths))
201+
array = ccall(
202+
(:u32_triangulate_i64, libearcut),
203+
Tuple{Ptr{GLTriangleFace}, Cint},
204+
(Ptr{Ptr{Int64}}, Ptr{UInt32}, UInt32),
205+
polygon, lengths, len
206+
)
207+
return unsafe_wrap(Vector{GLTriangleFace}, array[1], array[2])
208+
end
209+
210+
function earcut_triangulate(polygon::Vector{Vector{Point{2, Int32}}})
211+
lengths = map(x-> UInt32(length(x)), polygon)
212+
len = UInt32(length(lengths))
213+
array = ccall(
214+
(:u32_triangulate_i32, libearcut),
215+
Tuple{Ptr{GLTriangleFace}, Cint},
216+
(Ptr{Ptr{Int32}}, Ptr{UInt32}, UInt32),
217+
polygon, lengths, len
218+
)
219+
return unsafe_wrap(Vector{GLTriangleFace}, array[1], array[2])
220+
end
221+
222+
best_earcut_eltype(x) = Float64
223+
best_earcut_eltype(::Type{Float64}) = Float64
224+
best_earcut_eltype(::Type{<:AbstractFloat}) = Float32
225+
best_earcut_eltype(::Type{Int64}) = Int64
226+
best_earcut_eltype(::Type{Int32}) = Int32
227+
best_earcut_eltype(::Type{<:Integer}) = Int64
228+
229+
function faces(polygon::Polygon{Dim, T}) where {Dim, T}
230+
if isempty(polygon.interiors)
231+
return decompose(GLTriangleFace, coordinates(polygon))
232+
else
233+
PT = Point{Dim, best_earcut_eltype(T)}
234+
points = [decompose(PT, polygon.exterior)]
235+
foreach(x-> push!(points, decompose(PT, x)), polygon.interiors)
236+
return earcut_triangulate(points)
237+
end
238+
end

src/viewtypes.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ struct TupleView{T, N, Skip, A} <: AbstractVector{T}
3636
connect::Bool
3737
end
3838

39+
coordinates(tw::TupleView) = coordinates(tw.data)
40+
3941
function Base.size(x::TupleView{T, N, M}) where {T, N, M}
4042
nitems = length(x.data) ÷ (N - (N - M))
4143
nitems = nitems - max(N - M, 0)

0 commit comments

Comments
 (0)