-
-
Notifications
You must be signed in to change notification settings - Fork 313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pushing the recipe system with advanced mesh plots #893
Comments
The docs seem outdated, since the first argument isn't actually optional. function convert_arguments(p::AbstractPlotting.PointBased, pset::PointSet)
vecs = [coordinates(pset[i]) for i in 1:nelements(pset)]
return convert_arguments(p, vecs) # recursive convert, since we need to convert to points
end |
I still get the same error here. Maybe the version? I am on AbstractPlotting.jl v0.15.26 and Makie.jl v0.12. |
Also am I correct to say that all the recipe-related code lives in AbstractPlotting.jl nowadays? I would like to contribute to it to make sure that everything works smoothly with custom types, and that we can exchange data at a fundamental layer with built-in Julia Arrays. |
Ah try |
So what would be the path to contributing to the plot recipe system? Any guidelines? |
If you have a set of issues opened that are related to the recipe system, I can try to address some of them. |
So, as you may have noticed, recipes have been a bit neglected. Feel free to ping me on slack or github to discuss whatever problems you're running into. |
That sounds like a good plan. I will put up a repository with just the recipes and then we can evolve it alongside the recipe system itself and its documentation. |
I have created a playground package as planned in https://github.com/JuliaGeometry/MeshViz.jl It would be great if we could fix the recipe system to work out of the box with a single |
With Makie.jl v0.13.4 the recipes defined in MeshViz.jl are working as expected. Following the plan, I am trying to write recipes for Meshes.jl types to push the recipe system to its limits. This is the current version of the module: module MeshViz
using Meshes
import Makie
import Makie: convert_arguments
import Makie: plottype
# ---------
# PointSet
# ---------
plottype(::PointSet) = Makie.Scatter
convert_arguments(P::Type{<:Makie.Scatter}, pset::PointSet) =
convert_arguments(P, coordinates.(pset))
# -----------
# SimpleMesh
# -----------
plottype(::SimpleMesh) = Makie.Mesh
function convert_arguments(P::Type{<:Makie.Mesh}, mesh::SimpleMesh)
# retrieve geometry + topology
verts = vertices(mesh)
topo = topology(mesh)
elems = elements(topo)
# convert to Julia arrays
coords = reduce(hcat, coordinates(v) for v in verts)'
connec = reduce(hcat, collect(indices(e)) for e in elems)'
convert_arguments(P, coords, connec)
end
end So plotting a SimpleMesh is straightforward: julia> using Meshes, MeshViz
julia> using GLMakie
julia> mesh = SimpleMesh(Point2[(0,0),(1,0),(1,1),(0,1)], connect.([(1,2,3),(3,4,1)]))
2 SimpleMesh{2,Float64}
4 vertices
└─Point(0.0, 0.0)
└─Point(1.0, 0.0)
└─Point(1.0, 1.0)
└─Point(0.0, 1.0)
2 elements
└─Triangle(1, 2, 3)
└─Triangle(3, 4, 1)
julia> plot(mesh) But I can't find an attribute to show the wireframe (i.e. edges of the triangles). Is it currently possible? To give some context, here is how you can get access to the edges of the mesh without repetition: julia> # convert to half-edge data structure for topological relations
julia> t = convert(HalfEdgeTopology, topology(mesh))
HalfEdgeTopology(HalfEdge[HalfEdge(1, 1), HalfEdge(2, nothing), HalfEdge(3, 1), HalfEdge(1, 2), HalfEdge(4, 2), HalfEdge(1, nothing), HalfEdge(3, 2), HalfEdge(4, nothing), HalfEdge(2, 1), HalfEdge(3, nothing)], Dict(2 => 4, 1 => 1), Dict(4 => 5, 2 => 9, 3 => 3, 1 => 1), Dict((3, 2) => 5, (1, 2) => 1, (3, 1) => 2, (1, 3) => 2, (4, 1) => 3, (2, 1) => 1, (1, 4) => 3, (3, 4) => 4, (4, 3) => 4, (2, 3) => 5…))
julia> # boundary relation that maps edges to vertices
julia> ∂ = Boundary{1,0}(t)
Boundary{1, 0, HalfEdgeTopology}(HalfEdgeTopology(HalfEdge[HalfEdge(1, 1), HalfEdge(2, nothing), HalfEdge(3, 1), HalfEdge(1, 2), HalfEdge(4, 2), HalfEdge(1, nothing), HalfEdge(3, 2), HalfEdge(4, nothing), HalfEdge(2, 1), HalfEdge(3, nothing)], Dict(2 => 4, 1 => 1), Dict(4 => 5, 2 => 9, 3 => 3, 1 => 1), Dict((3, 2) => 5, (1, 2) => 1, (3, 1) => 2, (1, 3) => 2, (4, 1) => 3, (2, 1) => 1, (1, 4) => 3, (3, 4) => 4, (4, 3) => 4, (2, 3) => 5…)))
julia> # loop over edges and print incident vertices
julia> for i in 1:nfacets(t)
@show ∂(i)
end
∂(i) = [1, 2]
∂(i) = [3, 1]
∂(i) = [4, 1]
∂(i) = [3, 4]
∂(i) = [2, 3] With the pairs of indices above I can use the global vector of vertices to create a lines plot. Can you help explain how this can be done with the current version of the recipe system? |
You should be able to plot |
You mean defining a full recipe instead of a type recipe, right? So that I can call multiple commands instead of just converting the input type to coordinates and connectivities. |
I managed to write full type recipes and they are working nicely: I have a few questions regarding recipe attributes:
|
|
It's a separate attribute because often patch-like plots (poly, density, etc) should have different colors than lines or markers. Often this is a difference in alpha only. |
Got it, thanks. I am able to plot triangle meshes, it looks great: using Meshes, MeshViz # master
import GLMakie
using PlyIO
function readply(fname)
ply = load_ply(fname)
x = ply["vertex"]["x"]
y = ply["vertex"]["y"]
z = ply["vertex"]["z"]
points = Meshes.Point.(x, y, z)
connec = [connect(Tuple(c.+1)) for c in ply["face"]["vertex_indices"]]
SimpleMesh(points, connec)
end
mesh = readply("beethoven.ply")
viz(mesh) mesh = readply("iphi.ply")
viz(mesh) Now I will try to add an option for showing the edges of the triangles. What is the recommended method to add new attributes in a plot recipe? For example, suppose I want to add a keyword option |
Another quick question. Is it correct to say that OpenGL and related libraries know how to plot triangles efficiently but not necessarily quadrangles, pentagons, etc? I need to split the n-gons into triangles before calling the Makie.mesh! function, correct? |
Yeah, it will all be triangles ;) It handles all the ngons from GeometryBasics as it knows how to convert them to triangles, so I guess you'd need to do the same for Meshes.jl. |
What about the wireframe? Is it a similar situation where OpenGL provides an efficient routine for plotting the edges given a list of triangles? Or in this case we really need to provide a list of segments? |
Well, you need to draw lines, so no triangles ;) But yes, that means you need to generate the list of linesegments! |
Awesome, I will work on it, it should be straightforward with the half-edge structure. Will report the results soon. |
Recipes with color working nicely too: using Meshes, MeshViz
import GLMakie
mesh = readply("dragon.ply")
viz(mesh, elementcolor=1:nelements(mesh)) I tried playing with the |
Not really. The problem is, that we're coloring the vertices, which get interpolated by default. |
Got it, thanks. Before researching this direction, I would like to ask if it would be ok to refactor some of the existing recipes like Mesh, Poly, Wireframe, and Linesegments so that they all accept the same shape of coordinates and connectivities. For example, it would be nice if all recipes accepted a list of vertices as a |
I've finished writing most of the recipes I need. You can find examples here: https://discourse.julialang.org/t/ann-announcing-meshes-jl/53973/33 I wonder if there is a simple method to find out the coordinates of the corners of the axis, as well as the pixel size. The ultimate goal is to be able to filter geometries inside a given zoom level, and after filtering is done, do a simplification of geometries based on the pixel size so that very big geometries in terms of vertices are simplified to smaller geometries when seen from far away. This is what advanced GIS software do to avoid plotting thousands of thousands of vertices of polygons every time. |
Very nice :) Yes, there are lots of improvements we can introduce, if we really want to enable high performance display of large meshes. |
Can't you get a size estimate quite easily via boundingbox? |
I need the limits of the axis in data coordinates. I could then use these limits to filter the geometries that are visible given the current zoom level. Makes sense? |
I guess for 3D we'll need the camera Frustum.. |
Nice, I will take a look at the 2D case when I find some time. I need to switch tasks to handle other priorities now, but will come back at some point. I fully agree that some of the algorithms in Meshes.jl could be dispatched on the GPU when one is available for state of the art speed 🚀 |
Closing as solved. The recipes are working, there is a lot of code repetition, but I think things will get better in the future with the recipe system. |
According to the documentation, we could simply add a method to
convert_arguments
to get a plot for a custom type:When I try to plot however, I get an error:
What am I missing?
The text was updated successfully, but these errors were encountered: