diff --git a/src/backends.jl b/src/backends.jl index 85ebfe98a..1387ae184 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -352,6 +352,7 @@ const _gr_seriestype = [ :scatter3d, :surface, :wireframe, + :mesh3d, :volume, :shape, ] diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 41b98e968..1f2fbd9d2 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -524,7 +524,7 @@ function gr_draw_colorbar(cbar::GRColorbar, sp::Subplot, clims, viewport_plotare levels = _cbar_unique(contour_levels.(series, Ref(clims)), "levels") # GR implicitly uses the maximal z value as the highest level if levels[end] < clims[2] - @warn("GR: highest contour level less than maximal z value is not supported.") + @warn "GR: highest contour level less than maximal z value is not supported." # replace levels, rather than assign to levels[end], to ensure type # promotion in case levels is an integer array levels = [levels[1:end-1]; clims[2]] @@ -1676,7 +1676,7 @@ function gr_add_series(sp, series) end elseif st === :contour gr_draw_contour(series, x, y, z, clims) - elseif st in (:surface, :wireframe) + elseif st in (:surface, :wireframe, :mesh3d) gr_draw_surface(series, x, y, z, clims) elseif st === :volume sp[:legend] = :none @@ -1832,7 +1832,7 @@ function gr_draw_contour(series, x, y, z, clims) h = gr_contour_levels(series, clims) if series[:fillrange] !== nothing if series[:fillcolor] != series[:linecolor] && !is_lc_black - @warn("GR: filled contour only supported with black contour lines") + @warn "GR: filled contour only supported with black contour lines" end GR.contourf(x, y, h, z, series[:contour_labels] == true ? 1 : 0) else @@ -1843,7 +1843,8 @@ end function gr_draw_surface(series, x, y, z, clims) e_kwargs = series[:extra_kwargs] - if series[:seriestype] === :surface + st = series[:seriestype] + if st === :surface fillalpha = get_fillalpha(series) fillcolor = get_fillcolor(series) # NOTE: setting nx = 0 or ny = 0 disables GR.gridit interpolation @@ -1858,9 +1859,41 @@ function gr_draw_surface(series, x, y, z, clims) else GR.gr3.surface(x, y, z, d_opt) end - else # wireframe + elseif st === :wireframe GR.setfillcolorind(0) GR.surface(x, y, z, get(e_kwargs, :display_option, GR.OPTION_FILLED_MESH)) + elseif st === :mesh3d + @warn "GR: mesh3d is experimental (no face colors)" + conn = series[:connections] + if typeof(conn) <: Tuple{Array, Array, Array} + ci, cj, ck = conn + if !(length(ci) == length(cj) == length(ck)) + throw(ArgumentError("Argument connections must consist of equally sized arrays.")) + end + else + throw(ArgumentError("Argument connections has to be a tuple of three arrays.")) + end + X = zeros(eltype(x), 4length(ci)) + Y = zeros(eltype(y), 4length(cj)) + Z = zeros(eltype(z), 4length(ck)) + @inbounds for I ∈ 1:length(ci) + i = ci[I] + 1 # connections are 0-based + j = cj[I] + 1 + k = ck[I] + 1 + m = 4(I - 1) + 1; n = m + 1; o = m + 2; p = m + 3 + X[m] = X[p] = x[i] + Y[m] = Y[p] = y[i] + Z[m] = Z[p] = z[i] + X[n] = x[j] + Y[n] = y[j] + Z[n] = z[j] + X[o] = x[k] + Y[o] = y[k] + Z[o] = z[k] + end + GR.polyline3d(X, Y, Z) + else + throw(ArgumentError("Not handled !")) end end diff --git a/src/examples.jl b/src/examples.jl index eb99e5fe3..af91f05e9 100644 --- a/src/examples.jl +++ b/src/examples.jl @@ -998,33 +998,37 @@ const _examples = PlotExample[ end] ), PlotExample( # 47 - "Mesh3d", - """ - Allows to plot arbitrary 3d meshes. If only x,y,z are given the mesh is generated automatically. - You can also specify the connections using the connections keyword. - The connections are specified using a tuple of vectors. Each vector contains the 0-based indices of one point of a triangle, - such that elements at the same position of these vectors form a triangle. - """, - [ - :( - begin - # specify the vertices - x=[0, 1, 2, 0] - y=[0, 0, 1, 2] - z=[0, 2, 0, 1] + "Mesh3d", + """ + Allows to plot arbitrary 3d meshes. If only x,y,z are given the mesh is generated automatically. + You can also specify the connections using the connections keyword. + The connections are specified using a tuple of vectors. Each vector contains the 0-based indices of one point of a triangle, + such that elements at the same position of these vectors form a triangle. + """, + [ + :( + begin + # specify the vertices + x=[0, 1, 2, 0] + y=[0, 0, 1, 2] + z=[0, 2, 0, 1] - # specify the triangles - # every column is one triangle, - # where the values denote the indices of the vertices of the triangle - i=[0, 0, 0, 1] - j=[1, 2, 3, 2] - k=[2, 3, 1, 3] + # specify the triangles + # every column is one triangle, + # where the values denote the indices of the vertices of the triangle + i=[0, 0, 0, 1] + j=[1, 2, 3, 2] + k=[2, 3, 1, 3] - # the four triangles gives above give a tetrahedron - mesh3d(x,y,z;connections=(i,j,k)) - end - ), - ], + # the four triangles gives above give a tetrahedron + mesh3d( + x, y, z; connections=(i, j, k), + title="triangles", xlabel="x", ylabel="y", zlabel="z", + legend=:none, margin=2Plots.mm + ) + end + ), + ], ), PlotExample( # 48 "Vectors of markershapes and segments", @@ -1214,7 +1218,7 @@ const _examples = PlotExample[ # Some constants for PlotDocs and PlotReferenceImages _animation_examples = [2, 31] _backend_skips = Dict( - :gr => [25, 30, 47], + :gr => [25, 30], :pyplot => [2, 25, 30, 31, 47, 49, 55], :plotlyjs => [2, 21, 24, 25, 30, 31, 49, 51, 55], :plotly => [2, 21, 24, 25, 30, 31, 49, 50, 51, 55],