Plot lots of surfaces with normals

I have an array of named tuples, each of which describes a 3D panel. Panels corners, centers, areas, normal vector, etc. I want to plot the panels and be able to apply a color to each one. I would like to use Plots and plotlyjs() so it’s easy to interact with in a Pluto notebook. The fallback can be gr().

The problem I’m having is that I need to plot the panels 1-by-1 to apply the array of colors, but this is super slow. Even slower if I want to add the normal arrow to each. I tried plotting the quiver after all the panels, but the z-ordering doesn’t work!

Could you use WGLMakie for Pluto?

This is exactly what I ended up doing Simon. It is <chef’s kiss> soooo nice. And super fast.

function viz(panels, values; vectors=panels.n, colormap=:viridis)
    fig = Figure()
    ax = Axis3(fig[1, 1], aspect=:data)

    # Normalize and map to color
    vmin, vmax = extrema(values)
    norm_vals = (values .- vmin) ./ (vmax - vmin + eps())
    colors = cgrad(colormap)[norm_vals]

    # Mesh geometry (triangle list) and colors
    triangles = mapreduce(vcat, panels) do panel
        p = panel.corners
        [p[1], p[2], p[3], p[4], p[3], p[2]]
    end
    tri_colors = mapreduce(c -> fill(c, 6), vcat, colors)
    mesh!(ax, triangles; color=tri_colors)

    # Normals & color bar
    components(data) = ntuple(i -> getindex.(data, i), 3)
    arrows!(ax, components(panels.x)..., components(vectors)...; color=colors)
    Colorbar(fig[1, 2], limits=(vmin, vmax); colormap)
    fig
end
3 Likes

@sdanisch I have a follow-up (maybe belongs in the new question). One feature of this boundary element method is that the panels aren’t really planar, and using two triangles might give the wrong impression. Is there a way to “fake” a smoother surface?

I have the corner points, the center point, and the normal at the center. I tried making four triangles between the corners and center, but this looks even more “pointy”. Can I apply my panel-center normal to the shader for all four of those triangle so the light is more uniform on them?

I’m not 100% sure if I understand you correctly, but I think calculating a normal for each point should do the trick.
Best, by averaging over neighboring normals.

This is certainly another question now… :wink: I’ll ask on slack.