-
Notifications
You must be signed in to change notification settings - Fork 29
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
Mesh Plotting #218
Mesh Plotting #218
Conversation
src/ConstructiveSolidGeometry/plotting/SurfacePrimitives/ConeMantle.jl
Outdated
Show resolved
Hide resolved
src/ConstructiveSolidGeometry/plotting/SurfacePrimitives/ConeMantle.jl
Outdated
Show resolved
Hide resolved
struct PolyMesh{T,N} | ||
x::Vector{SVector{N,T}} | ||
y::Vector{SVector{N,T}} | ||
z::Vector{SVector{N,T}} | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify: PolyMesh
is an auxiliary struct for plotting using mesh3d
in GR
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now this it is its only purpose. However, I will need PolyMesh{T,3} for when I plot surfaces for which I cannot write a analytical mesh. These arbitrary meshes will be generated by the JuliaGeometry/VoronoiDelaunay.jl package and then stored in a PolyMesh{T,3}
(which contains vectors of triangle vertices. PolyMesh{T,4}
contains vectors of quadrangle vertices). Note that pyplot() understands PolyMesh{T} aswell. So in theory we do not need to check for the backend and can always pass a PolyMesh. But we save time by not doing this in pyplot(). Another reason to use Mesh{T} is that pyplot() looks really nice with this structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all is very annoying... I don't mean you implementation but this whole Plots.jl, GR/PyPlot stuff for 3D plots...
Meshes.jl actually seems to make really nice progress and provides a mesh struct we can use.
using Plots
using Meshes
T = Float64
p0 = Point3([0,0,0])
px = Point3([1,0,0])
py = Point3([0,1,0])
pz = Point3([0,0,1])
# mesh of three triangles, just as an example
mesh = SimpleMesh([p0, px, py, pz], [connect((1, 2, 3)), connect((1, 2, 4))])
plot(mesh)
This produces a wireframe in GR. With PyPlot it throws an error....
I would favor to use the mesh from Meshes.jl and, as they also provide already plot recipes for Plots.jl
(even though they plot usually with MeshViz.jl), talk to them regarding your workaround for plotting nice surfaces via PyPlot to their package. They suggest to contact them via https://julialang.zulipchat.com/#narrow/stream/275558-meshes.2Ejl before making issues on GitHub. Maybe we could also improve/contribute to Plots.jl directly.
And we might talk to Josef Heinen regarding face support from GR.jl.
I know this will increase the time until everything is through, but I think this is the better way and will reduce the amount of code in our package as we would only need to implement the connections for the vertices of our volume primitives to create the meshes.
src/ConstructiveSolidGeometry/plotting/SurfacePrimitives/ConeMantle.jl
Outdated
Show resolved
Hide resolved
src/ConstructiveSolidGeometry/plotting/SurfacePrimitives/ConeMantle.jl
Outdated
Show resolved
Hide resolved
end | ||
end | ||
if !haskey(plotattributes, :show_normal) || plotattributes[:show_normal] | ||
if !haskey(plotattributes, :show_normal) || plotattributes[:show_normal] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is !haskey
intended, i.e. default to plot it if not specified?
I would personally prefer haskey
and only plot it if explicitly specified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is not my code, but I agree
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we should set the default to false
.
Will this PR introduce mesh plotting only for |
This PR is meant to add mesh methods for all surface primitives. However, I started it with only one, to see if you liked the way its implemented before I proceed |
The current status of plotting now is:
Some pyplot() examples follow. All of them have also been tested to work in gr(). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we really should talk to the Plots.jl, GR.jl & PyPlot.jl people and make this right.
Even if this needs some time.
But there seems plenty of other people wanting this feature. So it would be a really nice contribution to the Julia Ecosystem. And it would reduce the amount of code we have to maintain.
Project.toml
Outdated
@@ -30,6 +30,7 @@ StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" | |||
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" | |||
TypedTables = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9" | |||
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" | |||
VoronoiDelaunay = "72f80fcb-8c52-57d9-aff0-40c1a3526986" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not see the reason why we would need this dependency.
It also does not seem to be really maintained. Last commit in January and the last release is almost one year old. Also the last issues did not received any comments.
struct PolyMesh{T,N} | ||
x::Vector{SVector{N,T}} | ||
y::Vector{SVector{N,T}} | ||
z::Vector{SVector{N,T}} | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all is very annoying... I don't mean you implementation but this whole Plots.jl, GR/PyPlot stuff for 3D plots...
Meshes.jl actually seems to make really nice progress and provides a mesh struct we can use.
using Plots
using Meshes
T = Float64
p0 = Point3([0,0,0])
px = Point3([1,0,0])
py = Point3([0,1,0])
pz = Point3([0,0,1])
# mesh of three triangles, just as an example
mesh = SimpleMesh([p0, px, py, pz], [connect((1, 2, 3)), connect((1, 2, 4))])
plot(mesh)
This produces a wireframe in GR. With PyPlot it throws an error....
I would favor to use the mesh from Meshes.jl and, as they also provide already plot recipes for Plots.jl
(even though they plot usually with MeshViz.jl), talk to them regarding your workaround for plotting nice surfaces via PyPlot to their package. They suggest to contact them via https://julialang.zulipchat.com/#narrow/stream/275558-meshes.2Ejl before making issues on GitHub. Maybe we could also improve/contribute to Plots.jl directly.
And we might talk to Josef Heinen regarding face support from GR.jl.
I know this will increase the time until everything is through, but I think this is the better way and will reduce the amount of code in our package as we would only need to implement the connections for the vertices of our volume primitives to create the meshes.
end | ||
end | ||
if !haskey(plotattributes, :show_normal) || plotattributes[:show_normal] | ||
if !haskey(plotattributes, :show_normal) || plotattributes[:show_normal] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we should set the default to false
.
I added mesh plotting via the seriestype So, once Plots.jl makes a new release we can remove the special case for the PyPlot backend and do not have to write backend dependent code. I am in contact with Josef Heinen (GR.jl) to get support of filled faces also in GR. |
Awesome! |
Okay, so now it is (will be) also supported by GR :) |
So (once the PR in Plots.jl is through) we only need one struct for a mesh: I would suggest this: struct mesh{T}
x::Array{T}
y::Array{T}
z::Array{T}
connections::Vector{Vector{T}} # We probably could also use `VectorOfVectors` from `ArraysOfArrays.jl`
end so we can use a recipe like @recipe function f(m::Mesh)
seriestype := :mesh3d
connections =: m.connections
m.x, m.y, m.z
end Regarding the structure of T = Float64
p0 = T[0,0,0]
p1 = T[1,0,0]
p2 = T[0,1,0]
p3 = T[1,1,0]
p4 = T[1/2,1/2,1]
pts = [p0, p1, p2, p3, p4]
x, y, z = broadcast(i -> getindex.(pts, i), (1,2,3))
connections = [ # Pyramide
[1, 2, 4, 3], # Quadrangle
[1, 2, 5], # Triangle
[2, 4, 5], # Triangle
[4, 3, 5], # Triangle
[3, 1, 5] # Triangle
] |
Backend independent meshing implementation using development branch of Plots (https://github.com/lmh91/Plots.jl/tree/gr_mesh3d) by @lmh91.
conemantle_tranformed = CSG.ConeMantle{T,Tuple{T,T},Nothing,:outwards}((1,2),nothing,1,CartesianPoint{T}(1,0,0),RotY(π/2))
es = CSG.EllipticalSurface{T,Tuple{T,T},Nothing}((1,2),nothing, zero(CartesianPoint{T}), RotX(π/6))
n = 6
polygon = CSG.Polygon{n,T}([RotX(π/4)*Pt(cos(i), sin(i),0) for i in 0:2π/n:2π-2π/n])
em = CSG.EllipsoidMantle{T,T,Tuple{T,T},Tuple{T,T},:ouwards}(1,(0,3π/2),(0,π/2), zero(CartesianPoint{T}), RotX(0))
tm = CSG.TorusMantle{T,Tuple{T,T},Tuple{T,T},:outwards}(2,1,(0,3π/2),(0,3π/2),CartesianPoint{T}(1,1,1), RotX(π/4)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice! Just some minor things, see comments.
The PR in Plots.jl it through and the release |
I tried this out but it didn't work (my Plots was not up to date). |
I asked in the Julia Plotting channel on Slack about this. Maybe there is a way. |
How do I plot the detector using meshes? |
function _get_n_points_in_arc_φ(p::AbstractSurfacePrimitive, n::Int64)::Int64 | ||
φMin, φMax = get_φ_limits(p) | ||
f = (φMax - φMin)/(2π) | ||
Int(ceil(n*f)) | ||
end | ||
|
||
function _get_n_points_in_arc_θ(p::AbstractSurfacePrimitive, n::Int64)::Int64 | ||
θMin, θMax = get_θ_limits(p) | ||
f = (θMax - θMin)/(2π) | ||
Int(ceil(n*f)) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am getting an error that these functions are not defined when trying to plot a detector.
I guess they need to go before all the includes
in this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems to be on your side. I was just able to plot a detector locally.
Also, the docs build went through where a detector is plotted.
I used:
using Plots, SolidStateDetectors
T = Float32
sim = Simulation{T}(SSD_examples[:InvertedCoax])
plot(sim.detector)
Added mesh plotting for ConeMantle. Supported in pyplot() and gr(). Note that the only way to do this in gr() is using
st = :mesh3d
which is "experimental". Previouslyst = :surface
was able to properly color the face of a triangle in gr(), now it needs 5 or more points to work, and no longer respects the boundaries set by the points. Therefore:mesh3d
must be used. For consistency whensurface()
or equivalentlyplot(; st = :surface)
is called, pyplot() uses:surface
and gr() uses:mesh3d
to produce a visually equivalent result. The experimental:mesh3d
gives the warning (directly from GR, not from SSD)GR: mesh3d is experimental (no face colors)
for each element in the series. As stated, there are no face colors yet, and therefore it will look like a dense wireframe for now.To achieve the desired plot
mesh(cm::ConeMantle{T})
is called. This will return aMesh{T}
. A plot recipe forMesh
is provided. Its fields are 3 matrices, which pyplot():surface
takes as input.With, gr() this does not work. So we turn to
:mesh3d
. However,:mesh3d
takes arrays as inputs: a list of points just like:path3d
. The keywordconnections
is used to tell how these points assemble into triangles (whose faces will be filled - someday). The functionpolymesh
is provided to turn aMesh{T}
into aPolyMesh{T,4}
whose fields are arrays of 4 points.Mesh{T}
naturally deconstructs into quadrangels instead of triangles and thereforePolyMesh{T,4}
is used. In the futurePolyMesh{T,3}
will be useful for other meshes which deconstruct more naturally into triangles.3 examples follow
pyplot(); surface(cylindermantle)
gr(); surface(cylindermantle)
pyplot(); surface(conemantle_tranformed)
gr(); surface(conemantle_tranformed)
pyplot(); surface(conemantle_partial)
gr(); surface(conemantle_partial)