diff --git a/CHANGELOG.md b/CHANGELOG.md index b79bb6c..85bb5b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,12 @@ # Major changes -## v3.0 planned -- Remove plotting code (`plot_in_out`, `plot_triangulateio`, `tricircumcenter!`) -- Remove deprecated `triunsuitable` +## v3.0.0 June 23, 2025 +Cleanup release: moved plot methods for triangulateio structsto [GridVisualize.jl](https://wias-pdelib.github.io/GridVisualize.jl/stable/api/#Plotting-TriangulateIO) +No more Makie and Pyplot weakdeps and compat entries. + +- Breaking: + - Removed plotting code (`plot_in_out`, `plot_triangulateio`, `tricircumcenter!`) + - Removed deprecated `triunsuitable` in favor of `triunsuitable!`. ## v2.5.1 June 22, 2025 - Bump Makie compat to include 0.25 diff --git a/Project.toml b/Project.toml index 97d2fa0..fafa1ad 100644 --- a/Project.toml +++ b/Project.toml @@ -1,28 +1,13 @@ name = "Triangulate" uuid = "f7e6ffb2-c36d-4f8f-a77e-16e897189344" authors = ["Juergen Fuhrmann "] -version = "2.5.1" +version = "3.0.0" [deps] DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Triangle_jll = "5639c1d2-226c-5e70-8d55-b3095415a16a" -[weakdeps] -CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" -GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" -PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" - [compat] -CairoMakie = "0.10, 0.11, 0.12, 0.13, 0.14, 0.15" DocStringExtensions = "0.8, 0.9" -GLMakie = "0.8,0.9, 0.10, 0.11, 0.12, 0.13" -Printf = "1.6" -PyPlot = "2" Triangle_jll = "1.6.2" julia = "1.6" - -[extras] -CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" -GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" -PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" diff --git a/src/Triangulate.jl b/src/Triangulate.jl index bb50021..1c95b80 100644 --- a/src/Triangulate.jl +++ b/src/Triangulate.jl @@ -4,16 +4,13 @@ using Triangle_jll include("ctriangulateio.jl") include("triangulateio.jl") -include("plot.jl") export triangulate -export triunsuitable!, triunsuitable +export triunsuitable! export TriangulateIO export numberofpoints export numberofsegments export numberoftriangles export TriangulateError -export plot_triangulateio, plot_in_out -export isplots, ispyplot end diff --git a/src/plot.jl b/src/plot.jl deleted file mode 100644 index eb67cc6..0000000 --- a/src/plot.jl +++ /dev/null @@ -1,460 +0,0 @@ -# -# Plotting routines. -# - -""" -$(TYPEDSIGNATURES) - -Heuristic check if Plotter is PyPlot -""" -ispyplot(Plotter) = typeof(Plotter) == Module && isdefined(Plotter, :Gcf) - -""" -$(SIGNATURES) - -Heuristically check if Plotter is Makie/WGLMakie -""" -ismakie(Plotter) = (typeof(Plotter) == Module) && isdefined(Plotter, :Makie) - -# Plot color scale for grid colors. -function frgb(Plotter, i, max; pastel = false) - x = Float64(i - 1) / Float64(max) - if (x < 0.5) - r = 1.0 - 2.0 * x - g = 2.0 * x - b = 0.0 - else - r = 0.0 - g = 2.0 - 2.0 * x - b = 2.0 * x - 1.0 - end - if pastel - r = 0.5 + 0.5 * r - g = 0.5 + 0.5 * g - b = 0.5 + 0.5 * b - end - if ispyplot(Plotter) - return (r, g, b) - end - if ismakie(Plotter) - return Plotter.RGBA(r, g, b) - end - return nothing -end - -""" -$(SIGNATURES) - -Find the circumcenter of a triangle. - -Created from C source of Jonathan R Shewchuk - -Modified to return absolute coordinates. -""" -function tricircumcenter!(circumcenter, a, b, c) - - # Use coordinates relative to point `a' of the triangle. - xba = b[1] - a[1] - yba = b[2] - a[2] - xca = c[1] - a[1] - yca = c[2] - a[2] - - # Squares of lengths of the edges incident to `a'. - balength = xba * xba + yba * yba - calength = xca * xca + yca * yca - - # Calculate the denominator of the formulae. - # if EXACT - # Use orient2d() from http://www.cs.cmu.edu/~quake/robust.html - # to ensure a correctly signed (and reasonably accurate) result, - # avoiding any possibility of division by zero. - # denominator = 0.5 / orient2d((double*) b, (double*) c, (double*) a) - - # Take your chances with floating-point roundoff - denominator = 0.5 / (xba * yca - yba * xca) - - # Calculate offset (from `a') of circumcenter. - xcirca = (yca * balength - yba * calength) * denominator - ycirca = (xba * calength - xca * balength) * denominator - - # The result is returned both in terms of x-y coordinates and xi-eta - # coordinates, relative to the triangle's point `a' (that is, `a' is - # the origin of both coordinate systems). Hence, the x-y coordinates - # returned are NOT absolute; one must add the coordinates of `a' to - # find the absolute coordinates of the circumcircle. However, this means - # that the result is frequently more accurate than would be possible if - # absolute coordinates were returned, due to limited floating-point - # precision. In general, the circumradius can be computed much more - # accurately. - - circumcenter[1] = xcirca + a[1] - circumcenter[2] = ycirca + a[2] - - return circumcenter -end - -""" -$(TYPEDSIGNATURES) - -The plot function is not exported, but kept for backward compatibility. -""" -# plot(Plotter, tio; kwargs...) = plot_triangulateio(Plotter, tio; kwargs...) - - -global depwarned::Bool = false - - -""" -$(TYPEDSIGNATURES) - -Plot contents of triangulateio structure. -The plot module is passed as parameter. -This allows to keep the package free of heavy -plot package dependencies. -""" -function plot_triangulateio( - Plotter, - tio::TriangulateIO; - axis = nothing, - voronoi = nothing, - aspect = 1, - circumcircles = false, - ) - global depwarned - if !depwarned - @warn """ - Triangulate.plot_triangulateio() is deprecated and will be removed in the next release. - It is replaced by GridVisualize.plot_triangulateio() exported from GridVisualize.jl. - """ - depwarned = true - end - x = view(tio.pointlist, 1, :) - y = view(tio.pointlist, 2, :) - - xminmax = extrema(x) - yminmax = extrema(y) - - dx = xminmax[2] - xminmax[1] - dy = yminmax[2] - yminmax[1] - - if ispyplot(Plotter) - PyPlot = Plotter - ax = PyPlot.matplotlib.pyplot.gca() - ax.set_aspect(aspect) - if numberofpoints(tio) == 0 - return - end - - ax.set_ylim(yminmax[1] - dy / 10, yminmax[2] + dy / 10) - ax.set_xlim(xminmax[1] - dx / 10, xminmax[2] + dx / 10) - - PyPlot.scatter(x, y; s = 10, color = "b") - t = transpose(tio.trianglelist .- 1) - if size(tio.triangleattributelist, 2) > 0 - PyPlot.tripcolor(x, y, t, tio.triangleattributelist[1, :]; cmap = "Pastel2") - end - if numberoftriangles(tio) > 0 - PyPlot.triplot(x, y, t; color = "k") - if circumcircles - t = 0:(0.025 * π):(2π) - pycircle(x, y, r) = PyPlot.plot( - x .+ r .* cos.(t), - y .+ r .* sin.(t); - color = (0.4, 0.05, 0.4), - linewidth = 0.3 - ) - cc = zeros(2) - for itri in 1:numberoftriangles(tio) - trinodes = tio.trianglelist[:, itri] - a = tio.pointlist[:, trinodes[1]] - b = tio.pointlist[:, trinodes[2]] - c = tio.pointlist[:, trinodes[3]] - tricircumcenter!(cc, a, b, c) - r = sqrt((cc[1] - a[1])^2 + (cc[2] - a[2])^2) - pycircle(cc[1], cc[2], r) - PyPlot.scatter([cc[1]], [cc[2]]; s = 20, color = (0.4, 0.05, 0.4)) - end - end - end - - if numberoftriangles(tio) == 0 && numberofregions(tio) > 0 - x = tio.regionlist[1, :] - y = tio.regionlist[2, :] - r = tio.regionlist[3, :] - PyPlot.scatter(x, y; s = 20, c = r, cmap = "Dark2") - end - - if numberofsegments(tio) > 0 - lines = Any[] - rgb = Any[] - markermax = maximum(tio.segmentmarkerlist) - # see https://gist.github.com/gizmaa/7214002 - for i in 1:numberofsegments(tio) - x1 = tio.pointlist[1, tio.segmentlist[1, i]] - y1 = tio.pointlist[2, tio.segmentlist[1, i]] - x2 = tio.pointlist[1, tio.segmentlist[2, i]] - y2 = tio.pointlist[2, tio.segmentlist[2, i]] - push!(lines, collect(zip([x1, x2], [y1, y2]))) - push!(rgb, frgb(PyPlot, tio.segmentmarkerlist[i], markermax)) - end - ax.add_collection( - PyPlot.matplotlib.collections.LineCollection( - lines; - colors = rgb, - linewidth = 3 - ) - ) - end - - if numberoftriangles(tio) == 0 && numberofholes(tio) > 0 - x = tio.holelist[1, :] - y = tio.holelist[2, :] - PyPlot.scatter(x, y; s = 20, color = "k") - end - - if voronoi != nothing && numberofedges(voronoi) > 0 - bcx = sum(x) / length(x) - bcy = sum(y) / length(y) - wx = maximum(abs.(x .- bcx)) - wy = maximum(abs.(y .- bcy)) - ww = max(wx, wy) - - x = voronoi.pointlist[1, :] - y = voronoi.pointlist[2, :] - PyPlot.scatter(x, y; s = 10, color = "g") - for i in 1:numberofedges(voronoi) - i1 = voronoi.edgelist[1, i] - i2 = voronoi.edgelist[2, i] - if i1 > 0 && i2 > 0 - PyPlot.plot( - [voronoi.pointlist[1, i1], voronoi.pointlist[1, i2]], - [voronoi.pointlist[2, i1], voronoi.pointlist[2, i2]]; - color = "g" - ) - else - x0 = voronoi.pointlist[1, i1] - y0 = voronoi.pointlist[2, i1] - xn = voronoi.normlist[1, i] - yn = voronoi.normlist[2, i] - normscale = 1.0e10 - if x0 + normscale * xn > bcx + ww - normscale = abs((bcx + ww - x0) / xn) - end - if x0 + normscale * xn < bcx - ww - normscale = abs((bcx - ww - x0) / xn) - end - if y0 + normscale * yn > bcy + ww - normscale = abs((bcy + ww - y0) / yn) - end - if y0 + normscale * yn < bcy - ww - normscale = abs((bcy - ww - y0) / yn) - end - PyPlot.plot( - [x0, x0 + normscale * xn], - [y0, y0 + normscale * yn]; - color = "g" - ) - end - end - end - end - - return if ismakie(Plotter) - Makie = Plotter - if numberofpoints(tio) == 0 - return - end - - Makie.ylims!(axis, (yminmax[1] - dy / 10, yminmax[2] + dy / 10)) - Makie.xlims!(axis, (xminmax[1] - dx / 10, xminmax[2] + dx / 10)) - - points = reshape(reinterpret(Makie.Point{2, Cdouble}, tio.pointlist), numberofpoints(tio)) - - if numberoftriangles(tio) > 0 - if size(tio.triangleattributelist, 2) > 0 - attr = tio.triangleattributelist[1, :] - maxattr = maximum(attr) - for i in 1:numberoftriangles(tio) - Makie.poly!( - axis, - view(points, view(tio.trianglelist, :, i)); - strokecolor = :black, - strokewidth = 1, - color = frgb(Makie, attr[i], maxattr; pastel = true) - ) - end - - else - for i in 1:numberoftriangles(tio) - Makie.poly!( - axis, - view(points, view(tio.trianglelist, :, i)); - strokecolor = :black, - strokewidth = 1, - color = :white, - alpha = 0.75 - ) - end - end - end - - if circumcircles - col = Makie.RGB(0.4, 0.05, 0.4) - - t = 0:(0.025 * π):(2π) - circle(x, y, r) = Makie.lines!( - axis, - x .+ r .* cos.(t), - y .+ r .* sin.(t); - color = col, - linewidth = 0.3 - ) - cc = zeros(2) - for itri in 1:numberoftriangles(tio) - a = view(tio.pointlist, :, tio.trianglelist[1, itri]) - b = view(tio.pointlist, :, tio.trianglelist[2, itri]) - c = view(tio.pointlist, :, tio.trianglelist[3, itri]) - tricircumcenter!(cc, a, b, c) - r = sqrt((cc[1] - a[1])^2 + (cc[2] - a[2])^2) - circle(cc[1], cc[2], r) - Makie.scatter!(axis, [cc[1]], [cc[2]]; markersize = 5, color = col) - end - end - if numberofsegments(tio) > 0 - markermax = maximum(tio.segmentmarkerlist) - # see https://gist.github.com/gizmaa/7214002 - xx = zeros(2) - yy = zeros(2) - for i in 1:numberofsegments(tio) - xx[1] = tio.pointlist[1, tio.segmentlist[1, i]] - yy[1] = tio.pointlist[2, tio.segmentlist[1, i]] - xx[2] = tio.pointlist[1, tio.segmentlist[2, i]] - yy[2] = tio.pointlist[2, tio.segmentlist[2, i]] - Makie.lines!( - axis, - xx, - yy; - color = frgb(Makie, tio.segmentmarkerlist[i], markermax), - linewidth = 3 - ) - end - end - - if numberoftriangles(tio) == 0 && numberofregions(tio) > 0 - markermax = maximum(tio.regionlist) - xx = tio.regionlist[1, :] - yy = tio.regionlist[2, :] - r = tio.regionlist[3, :] - Makie.scatter!( - axis, - xx, - yy; - markersize = 10, - color = [frgb(Makie, r[i], markermax) for i in 1:numberofregions(tio)] - ) - end - - if numberoftriangles(tio) == 0 && numberofholes(tio) > 0 - xx = tio.holelist[1, :] - yy = tio.holelist[2, :] - Makie.scatter!(axis, xx, yy; markersize = 10, color = :brown) - end - - if voronoi != nothing && numberofedges(voronoi) > 0 - bcx = sum(x) / numberofpoints(tio) - bcy = sum(y) / numberofpoints(tio) - wx = maximum(abs.(x .- bcx)) - wy = maximum(abs.(y .- bcy)) - ww = max(wx, wy) - - x = voronoi.pointlist[1, :] - y = voronoi.pointlist[2, :] - Makie.scatter!(axis, x, y; markersize = 10, color = :green) - for i in 1:numberofedges(voronoi) - i1 = voronoi.edgelist[1, i] - i2 = voronoi.edgelist[2, i] - if i1 > 0 && i2 > 0 - Makie.lines!( - axis, - [voronoi.pointlist[1, i1], voronoi.pointlist[1, i2]], - [voronoi.pointlist[2, i1], voronoi.pointlist[2, i2]]; - color = :green - ) - else - x0 = voronoi.pointlist[1, i1] - y0 = voronoi.pointlist[2, i1] - xn = voronoi.normlist[1, i] - yn = voronoi.normlist[2, i] - normscale = 1.0e10 - if x0 + normscale * xn > bcx + ww - normscale = min(normscale, abs((bcx + ww - x0) / xn)) - end - if x0 + normscale * xn < bcx - ww - normscale = min(normscale, abs((bcx - ww - x0) / xn)) - end - if y0 + normscale * yn > bcy + ww - normscale = min(normscale, abs((bcy + ww - y0) / yn)) - end - if y0 + normscale * yn < bcy - ww - normscale = min(normscale, abs((bcy - ww - y0) / yn)) - end - Makie.lines!( - axis, - [x0, x0 + normscale * xn], - [y0, y0 + normscale * yn]; - color = :green - ) - end - end - end - Makie.scatter!(axis, points; markersize = 7.5, color = :black) - end -end - -""" -$(TYPEDSIGNATURES) - -Plot pair of triangulateio structures arranged -in two subplots. This is intendd for visualizing both input -and output data. -""" -function plot_in_out( - Plotter, - triin, - triout; - figure = nothing, - voronoi = nothing, - circumcircles = false, - title = "", - ) - if ispyplot(Plotter) - PyPlot = Plotter - PyPlot.clf() - PyPlot.subplots(; nrows = 1, ncols = 2) - PyPlot.suptitle(title) - PyPlot.subplot(121) - PyPlot.title("In") - plot_triangulateio(PyPlot, triin) - PyPlot.subplot(122) - PyPlot.title("Out") - plot_triangulateio(PyPlot, triout; voronoi = voronoi, circumcircles = circumcircles) - PyPlot.tight_layout() - return PyPlot.gcf() - end - - if ismakie(Plotter) - Makie = Plotter - Makie.Label(figure[1, 1:2], title) - ax_in = Makie.Axis(figure[2, 1]; title = "In", aspect = Makie.DataAspect()) - ax_out = Makie.Axis(figure[2, 2]; title = "Out", aspect = Makie.DataAspect()) - plot_triangulateio(Makie, triin; axis = ax_in) - plot_triangulateio( - Makie, - triout; - axis = ax_out, - voronoi = voronoi, - circumcircles = circumcircles, - ) - return figure - end -end diff --git a/src/triangulateio.jl b/src/triangulateio.jl index 7ea3ffb..0a2d5df 100644 --- a/src/triangulateio.jl +++ b/src/triangulateio.jl @@ -586,5 +586,3 @@ function triunsuitable!(unsuitable::Function; check_signature = true) triunsuitable_func = unsuitable return nothing end - -@deprecate triunsuitable(f; kwargs...) triunsuitable!(f; kwargs...) diff --git a/test/example_domains.jl b/test/example_domains.jl index 91eecc8..7e3c75a 100644 --- a/test/example_domains.jl +++ b/test/example_domains.jl @@ -13,29 +13,21 @@ using Triangulate using Test using Printf -injupyter() = (isdefined(Main, :IJulia) && Main.IJulia.inited) - -if injupyter() - import PyPlot -end # ### Constrained Delaunay triangulation (CDT) of a domain given by a segment list specifying its boundary. # # This is obtained by # specifying the "p" flag. -function example_domain_cdt(; Plotter = nothing) +function example_domain_cdt() triin = Triangulate.TriangulateIO() triin.pointlist = Matrix{Cdouble}([0.0 0.0; 1.0 0.0; 1.0 1.0; 0.6 0.6; 0.0 1.0]') triin.segmentlist = Matrix{Cint}([1 2; 2 3; 3 4; 4 5; 5 1]') triin.segmentmarkerlist = Vector{Int32}([1, 2, 3, 4, 5]) (triout, vorout) = triangulate("pQ", triin) - plot_in_out(Plotter, triin, triout; title = "Domain triangulation") @test numberofpoints(triout) >= numberofpoints(triin) @test numberofsegments(triout) >= numberofsegments(triin) return @test numberoftriangles(triout) > 0 end -# -injupyter() && example_domain_cdt(; Plotter = PyPlot); # ### Constrained Delaunay triangulation (CDT) of a domain given by a segment list specifying its boundary together with a maximum area constraint. # @@ -46,38 +38,34 @@ injupyter() && example_domain_cdt(; Plotter = PyPlot); # it to a string before using `@sprintf`. # Specifying only the maximum area constraint does not prevent very thin # triangles from occurring at the boundary. -function example_domain_cdt_area(; Plotter = nothing, maxarea = 0.05) +function example_domain_cdt_area(; maxarea = 0.05) triin = Triangulate.TriangulateIO() triin.pointlist = Matrix{Cdouble}([0.0 0.0; 1.0 0.0; 1.0 1.0; 0.6 0.6; 0.0 1.0]') triin.segmentlist = Matrix{Cint}([1 2; 2 3; 3 4; 4 5; 5 1]') triin.segmentmarkerlist = Vector{Int32}([1, 2, 3, 4, 5]) area = @sprintf("%.15f", maxarea) # Don't use exponential format! (triout, vorout) = triangulate("pa$(area)Q", triin) - plot_in_out(Plotter, triin, triout; voronoi = vorout, title = "Domain CDT with area constraint") @test numberofpoints(triout) >= numberofpoints(triin) @test numberofsegments(triout) >= numberofsegments(triin) return @test numberoftriangles(triout) > 0 end # -injupyter() && example_domain_cdt_area(; Plotter = PyPlot, maxarea = 0.05); # ### Boundary conforming Delaunay triangulation (BCDT) of a domain given by a segment list specifying its boundary # In addition to the area constraint specify the -D flag # in order to keep the triangle circumcenters within the domain. -function example_domain_bcdt_area(; Plotter = nothing, maxarea = 0.05) +function example_domain_bcdt_area(; maxarea = 0.05) triin = Triangulate.TriangulateIO() triin.pointlist = Matrix{Cdouble}([0.0 0.0; 1.0 0.0; 1.0 1.0; 0.6 0.6; 0.0 1.0]') triin.segmentlist = Matrix{Cint}([1 2; 2 3; 3 4; 4 5; 5 1]') triin.segmentmarkerlist = Vector{Int32}([1, 2, 3, 4, 5]) area = @sprintf("%.15f", maxarea) (triout, vorout) = triangulate("pa$(area)DQ", triin) - plot_in_out(Plotter, triin, triout; voronoi = vorout, title = "Boundary conforming Delaunay triangulation") @test numberofpoints(triout) >= numberofpoints(triin) @test numberofsegments(triout) >= numberofsegments(triin) return @test numberoftriangles(triout) > 0 end # -injupyter() && example_domain_bcdt_area(; Plotter = PyPlot, maxarea = 0.05); # ### Constrained Delaunay triangulation of a domain with minimum angle condition # @@ -88,7 +76,7 @@ injupyter() && example_domain_bcdt_area(; Plotter = PyPlot, maxarea = 0.05); # when creating triangulations for finite element or finite volume methods. # It the minimum angle is larger then 28.6 degrees, Triangle's algorithm may # run into an infinite loop. -function example_domain_qcdt_area(; Plotter = nothing, minangle = 20, maxarea = 0.05) +function example_domain_qcdt_area(; minangle = 20, maxarea = 0.05) triin = Triangulate.TriangulateIO() triin.pointlist = Matrix{Cdouble}([0.0 0.0; 1.0 0.0; 1.0 1.0; 0.6 0.6; 0.0 1.0]') triin.segmentlist = Matrix{Cint}([1 2; 2 3; 3 4; 4 5; 5 1]') @@ -96,13 +84,11 @@ function example_domain_qcdt_area(; Plotter = nothing, minangle = 20, maxarea = area = @sprintf("%.15f", maxarea) angle = @sprintf("%.15f", minangle) (triout, vorout) = triangulate("pa$(area)Qq$(angle)", triin) - plot_in_out(Plotter, triin, triout; voronoi = vorout, title = "Quality triangulation") @test numberofpoints(triout) >= numberofpoints(triin) @test numberofsegments(triout) >= numberofsegments(triin) return @test numberoftriangles(triout) > 0 end # -injupyter() && example_domain_qcdt_area(; Plotter = PyPlot, maxarea = 0.05, minangle = 20); # ### Triangulation of a domain with refinement callback # @@ -110,7 +96,7 @@ injupyter() && example_domain_qcdt_area(; Plotter = PyPlot, maxarea = 0.05, mina # which is activated via the "u" flag if it has been passed before calling triangulate. # In addition, the "q" flag allows to specify a minimum angle # constraint preventing skinny triangles. -function example_domain_localref(; Plotter = nothing, minangle = 20) +function example_domain_localref(; minangle = 20) center_x = 0.6 center_y = 0.6 localdist = 0.1 @@ -123,20 +109,18 @@ function example_domain_localref(; Plotter = nothing, minangle = 20) return qdist > 1.0e-5 && area > 0.1 * qdist end - triunsuitable(unsuitable) + triunsuitable!(unsuitable) triin = Triangulate.TriangulateIO() triin.pointlist = Matrix{Cdouble}([0.0 0.0; 1.0 0.0; 1.0 1.0; 0.6 0.6; 0.0 1.0]') triin.segmentlist = Matrix{Cint}([1 2; 2 3; 3 4; 4 5; 5 1]') triin.segmentmarkerlist = Vector{Int32}([1, 2, 3, 4, 5]) angle = @sprintf("%.15f", minangle) (triout, vorout) = triangulate("pauq$(angle)Q", triin) - plot_in_out(Plotter, triin, triout; voronoi = vorout, title = "Quality triangulation with local refinement") @test numberofpoints(triout) >= numberofpoints(triin) @test numberofsegments(triout) >= numberofsegments(triin) return @test numberoftriangles(triout) > 0 end # -injupyter() && example_domain_localref(; Plotter = PyPlot, minangle = 20); # ### Triangulation of a heterogeneous domain # @@ -149,7 +133,7 @@ injupyter() && example_domain_localref(; Plotter = PyPlot, minangle = 20); # With the "A" flag, the subdomain labels are spread to all triangles in the corresponding # subdomains, becoming available in `triangleattributelist[1,:]`. # With the "a" flag, the area constraints are applied in the corresponding subdomains. -function example_domain_regions(; Plotter = nothing, minangle = 20) +function example_domain_regions(; minangle = 20) triin = Triangulate.TriangulateIO() triin.pointlist = Matrix{Cdouble}([0.0 0.0; 0.5 0.0; 1.0 0.0; 1.0 1.0; 0.6 0.6; 0.0 1.0]') triin.segmentlist = Matrix{Cint}([1 2; 2 3; 3 4; 4 5; 5 6; 6 1; 2 5]') @@ -158,21 +142,19 @@ function example_domain_regions(; Plotter = nothing, minangle = 20) angle = @sprintf("%.15f", minangle) (triout, vorout) = triangulate("paAq$(angle)Q", triin) - plot_in_out(Plotter, triin, triout; voronoi = vorout, title = "Hetero domain triangulation") @test numberofpoints(triout) >= numberofpoints(triin) @test numberofsegments(triout) >= numberofsegments(triin) return @test numberoftriangles(triout) > 0 end # -injupyter() && example_domain_regions(; Plotter = PyPlot, minangle = 20); # ### Triangulation of a domain with holes # # The segment list specifies its boundary and the boundaries of the holes. # An additional hole list is specified which provides "hole points" in `holelist[1,:]` # and `holelist[2,:]`. -function example_domain_holes(; Plotter = nothing, minangle = 20, maxarea = 0.001) +function example_domain_holes(; minangle = 20, maxarea = 0.001) triin = Triangulate.TriangulateIO() triin.pointlist = Matrix{Cdouble}( [ @@ -197,11 +179,9 @@ function example_domain_holes(; Plotter = nothing, minangle = 20, maxarea = 0.00 angle = @sprintf("%.15f", minangle) (triout, vorout) = triangulate("pa$(area)q$(angle)Q", triin) - plot_in_out(Plotter, triin, triout; voronoi = vorout, title = "Domain with holes") @test numberofpoints(triout) >= numberofpoints(triin) @test numberofsegments(triout) >= numberofsegments(triin) return @test numberoftriangles(triout) > 0 end # -injupyter() && example_domain_holes(; Plotter = PyPlot, minangle = 20, maxarea = 0.05); diff --git a/test/example_pointsets.jl b/test/example_pointsets.jl index c7d985e..0efaa02 100644 --- a/test/example_pointsets.jl +++ b/test/example_pointsets.jl @@ -15,12 +15,6 @@ using Triangulate using Test -injupyter() = (isdefined(Main, :IJulia) && Main.IJulia.inited) - -if injupyter() - import PyPlot -end - # ### Delaunay triangulation of point set # # Create a set of random points in the plane and calculate @@ -37,16 +31,14 @@ end # For this and the next examples, the input list of points is created randomly, # but on a raster, preventing the appearance of too close points. # -function example_convex_hull(; Plotter = nothing, n = 10, raster = 10) +function example_convex_hull(; n = 10, raster = 10) triin = Triangulate.TriangulateIO() triin.pointlist = hcat(unique([Cdouble[rand(1:raster) / raster, rand(1:raster) / raster] for i in 1:n])...) (triout, vorout) = triangulate("Q", triin) - plot_in_out(Plotter, triin, triout; title = "Convex hull") @test numberofpoints(triin) == numberofpoints(triout) return @test numberoftriangles(triout) > 0 end # -injupyter() && example_convex_hull(; Plotter = PyPlot, n = 10, raster = 10); # ### Delaunay triangulation of point set with boundary # @@ -55,17 +47,15 @@ injupyter() && example_convex_hull(; Plotter = PyPlot, n = 10, raster = 10); # describing the boundary of the convex hull. In fact this is a constrained # Delaunay triangulation (CDT) where the boundary segments # are the seen constraining edges which must appear in the output. -function example_convex_hull_with_boundary(; Plotter = nothing, n = 10, raster = 10) +function example_convex_hull_with_boundary(; n = 10, raster = 10) triin = Triangulate.TriangulateIO() triin.pointlist = hcat(unique([Cdouble[rand(1:raster) / raster, rand(1:raster) / raster] for i in 1:n])...) (triout, vorout) = triangulate("cQ", triin) @test numberofpoints(triin) == numberofpoints(triout) @test numberoftriangles(triout) > 0 - @test numberofsegments(triout) > 0 - return plot_in_out(Plotter, triin, triout; title = "Convex hull with boundary") + return @test numberofsegments(triout) > 0 end # -injupyter() && example_convex_hull_with_boundary(; Plotter = PyPlot, n = 10, raster = 10); # ### Delaunay triangulation of point set with Voronoi diagram # @@ -80,17 +70,15 @@ injupyter() && example_convex_hull_with_boundary(; Plotter = PyPlot, n = 10, ras # of the convex hull are of infinite size. The corners of the Voronoi # cells are the circumcenters of the triangles. They can be far # outside of the triangulated domain. -function example_convex_hull_voronoi(; Plotter = nothing, n = 10, raster = 10) +function example_convex_hull_voronoi(; n = 10, raster = 10) triin = Triangulate.TriangulateIO() triin.pointlist = hcat(unique([Cdouble[rand(1:raster) / raster, rand(1:raster) / raster] for i in 1:n])...) (triout, vorout) = triangulate("vQ", triin) - plot_in_out(Plotter, triin, triout; voronoi = vorout, title = "Convex hull with Voronoi diagram") @test numberofpoints(triin) == numberofpoints(triout) @test numberoftriangles(triout) > 0 return @test numberofpoints(vorout) > 0 end # -injupyter() && example_convex_hull_voronoi(; Plotter = PyPlot, n = 10, raster = 10); # ### Boundary conforming Delaunay triangulation of point set # Specify "c" flag for convex hull segments, "v" flag for Voronoi @@ -100,12 +88,11 @@ injupyter() && example_convex_hull_voronoi(; Plotter = PyPlot, n = 10, raster = # lie within the convex hull. # Due to random input, there may be situations where Triangle fails with this task, # so we check for the corresponding exception. -function example_convex_hull_voronoi_delaunay(; Plotter = nothing, n = 10, raster = 10) +function example_convex_hull_voronoi_delaunay(; n = 10, raster = 10) triin = Triangulate.TriangulateIO() triin.pointlist = hcat(unique([Cdouble[rand(1:raster) / raster, rand(1:raster) / raster] for i in 1:n])...) return try (triout, vorout) = triangulate("vcDQ", triin) - plot_in_out(Plotter, triin, triout; voronoi = vorout, title = "Convex hull with Voronoi diagram") @test numberofpoints(triin) <= numberofpoints(triout) @test numberoftriangles(triout) > 0 @test numberofpoints(vorout) > 0 @@ -117,7 +104,6 @@ function example_convex_hull_voronoi_delaunay(; Plotter = nothing, n = 10, raste end end # -injupyter() && example_convex_hull_voronoi_delaunay(; Plotter = PyPlot, n = 10, raster = 10); # ### Constrained Delaunay triangulation (CDT) of a point set with edges # Constrained Delaunay triangulation (CDT) of a point set with @@ -127,17 +113,15 @@ injupyter() && example_convex_hull_voronoi_delaunay(; Plotter = PyPlot, n = 10, # which should become edges of the triangulation. Note that # the resulting triangulation is not Delaunay in the sense # given above. -function example_cdt(; Plotter = nothing, n = 10, raster = 10) +function example_cdt(; n = 10, raster = 10) triin = Triangulate.TriangulateIO() triin.pointlist = hcat(unique([Cdouble[rand(1:raster) / raster, rand(1:raster) / raster] for i in 1:n])...) npt = size(triin.pointlist, 2) triin.segmentlist = Matrix{Cint}([1 2; npt - 1 npt - 2; 1 npt]') triin.segmentmarkerlist = Vector{Cint}([2, 3, 4]) (triout, vorout) = triangulate("pcQ", triin) - plot_in_out(Plotter, triin, triout; title = "CDT") @test numberofpoints(triin) <= numberofpoints(triout) @test numberofsegments(triout) >= numberofsegments(triin) return @test numberoftriangles(triout) > 0 end # -injupyter() && example_cdt(; Plotter = PyPlot, n = 10, raster = 10);