Skip to content
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

Rework line shaders for WGLMakie compatability #3558

Merged
merged 115 commits into from
Feb 27, 2024
Merged

Conversation

ffreyer
Copy link
Collaborator

@ffreyer ffreyer commented Jan 16, 2024

Description

The last (GLMakie) line rework (#2666 + some fixes) modified the generated geometry to cleanly join lines. This resulted in a pretty complex geometry shader that is hard to translate to WGLMakie. With this pr I want to try a different approach - generating a simple (enlarged) rect and cutting it into shape with multiple signed distance fields. This should then be portable to WGLMakie.

Goals:

Approach

Basic line segment

Let's start with the simple base case for a (connected) line segment. Using the 4 points from the previous, current and next line segment, we can calculate 3 line vectors ($v_0, v_1, v_2$) and normals ($n_0, n_1, n_2$). Using these we can calculate miter vectors $miter.{v_i} = normalize(v_{i-1} + v_i)$ and normals $miter.n_i = normalize(n_{i-1} + n_i)$. With those and the linewidth we can calculate the corner points of the segment as c_i = p_i +- 0.5 * linewidth / dot(n1, miter_n_i) * miter_n_i. (Or 0.5 * linewidth + AA_THICKNESS to add padding for anti-aliasing.)

Screenshot from 2024-02-10 14-43-23

Truncated joints

Miter joints have some problems. One is that he more the line bends (i.e. $\langle v_{i-1}, v_i \rangle \to -1$), the further out the corner goes ($1.0 / \langle n_1, miter.n_i \rangle \to \infty$). To avoid this we want to truncate the joint, i.e. make a cut parallel to the miter_v_i direction.

Doing this by adjusting the geometry is rather complicated. We need one extra vertex per joint to add the flat end of the joint, i.e. the truncated part (green). The vertex that overlaps the other line segment needs to move to avoid the line drawing over each other (green). If we also consider padding for AA we will need to push these vertices further outside to guarantee we always have enough space to do AA in the orange section.

image

We take a different approach here and do the joint using signed distance fields (SDF). Let's assume the joint applies to p2, with the current line segment being the left one. First we adjust the geometry to include the full joint with AA padding by extruding the line past p2 in v1 direction. Additionally we keep track of a bunch of variables:

  • the distance from p2 along v1 direction (current segment)
  • the distance from p2 along v2 direction (next segment)
  • the truncation distance from p2 along sign(dot(miter_n2, v1)) * miter_n2 direction

To cap the line we add an anti-aliasing border when the truncation distance reaches a certain linewidth dependent value (cutoff marked in green). The two other distances tell us how close a pixel is to each line segment. Based on that we can discard pixels belonging to the other line (discarded marker in blue for the left line segment). To avoid cutting off a large section of our line (e.g. the other end) we can stop discarding once the distance inside our line reaches some threshold (darker/less intense color). We can also add an anti-aliasing border just after we stop discarding to do this smoothly.

image

Linestyles/Patterns

To draw a patterned line we need to know how far from the start of the line we are. For this each lien point needs to know how far it is from the start of the line and each fragment drawn needs to know how far it is from p1, in line direction v1. The latter is given by the distances used for truncated joints, and the former needs to be calculated on the CPU beforehand. With perspective projection this requires a full transformation to pixel space.

The difficulty with patterns lies in handling joints. If we just sample the distance from p1 at an extruded corner we will get different values between incoming and outgoing line segment. This would fragment the pattern. To avoid this we sample the pattern at (start, center, end) of the joint and make the following adjustments: (with - being drawn and + not)

  • (+++), (---): The pattern wants to draw or discard the whole joint. To avoid AA within the joint we overwrite sampling for the joint, pushing AA outside
  • (-+-): Both sides of the joint draw, center does not. We overwrite the joint to push AA outside.
  • (++-), (+--), (+-+): The pattern does not draw on the left edge and may draw inside the joint to the right. We elongate the right line segment so that it includes the left edge (+ AA padding) and shorten the other, removing the joint.
  • (-++), (--+): The pattern does not draw on the right, and may to the left. Extend the left line segment to include the right edge and shorten the other.

Colors

Colors don't interpolate cleanly when being passed per vertex. Consider for example this line alternating between blue and red: (Note the first segment being dominantly red and the broken purple section in the second)

image

Instead of defaulting to vertex interpolation on a triangle like this, we interpolate between the colors of each point manually in the fragment shader. For this we reuse the distance from p1 used for truncated joints alongside the line start offset and length (which vary along the normal direction due to joints).

Short Segments

Short line segments can cause some issues which we need to deal with. The first issue is with miter joints, which can partially invert in this case:

image

To avoid this we scale the distance points 2 and 4 are from p1 and p2 by a common factor, such that they fall on top of each other. This effectively reduces the line quad to a triangle, which is the only part of the line that is not overlapping the previous and next segment. This generally works well, but makes a random clusters of line points a bit more chaotic.

There is another problem with short segments and the pattern adjustments above. For long-enough segments we can can check pattern values at max(0.5 * linewidth, dot(extrusion, +-v1)) which would allow dots to never be bend around a joint. If segments are short though, this will result in artifacting.

Old Explanation

To explain how lines are drawn in this pr I will first explain the case of solid lines. For reference we will use this debug image:

Screenshot from 2024-01-25 14-22-25

1. Generating Geometry

To start we generate a rectangle large enough to draw a line segment for every pair of consecutive points. There are 4 rectangles in the reference, each with a darker outline and some colored bits. When generating these rectangles we need to make sure that we have enough space for joints and for anti-aliasing, the latter of which simply requires adding a few extra pixels of space.

Joints come in two forms: an extrusion into a sharp point (miter) and a truncated version thereof. You can see sharp miter joints at point 2 and 3 (going clockwise from the left) and a truncated one at point 4. The shader decides between the two by checking the angle between consecutive line vectors with

bool[2] is_truncated = bool[2](
    dot(v0.xy, v1.xy) < MITER_LIMIT,
    dot(v1.xy, v2.xy) < MITER_LIMIT
);

and calculates the change in line length on one side of the line to extrusion. The extruded corners are the points where the edge of two line segments intersect at the end of the blue/red colored sections in the reference.

Our rectangle needs to be large enough to include these points, so it is elongated by abs(extrusion) plus some padding for AA along the line direction. Along the linewidth directions, the rectangle expands by 0.5 * linewidth + AA.

2. Main rectangle SDF

The next step is to generate a a signed distance field (SDF) which describes what's inside of the line segments and what is not. For a rectangle this would be given by

function rect_sdf(p, center, widths)
    d = abs(p - center)
    return max(d[1] - widths[1], d[2] - widths[2])
end

The shader splits this up into 3 components and computes it for each vertex in the geometry shader as f_quad_sdf1. The components are

vertex.quad_sdf1.x = dot(vertex_pos - p1, -v1.xy); // distance from p1 in reverse line direction (prev outside)
vertex.quad_sdf1.y = dot(vertex_pos - p2,  v1.xy); // distance from p2 in line direction (next outside)
vertex.quad_sdf1.z = dot(vertex_pos - p1, n1); // distance from p1 in normal direction
...
f_linewidth = 0.5 * g_thickness[1];

which the fragment shader combines as sdf_x = max(f_quad_sdf1.x, f_quad_sdf.y) to get the first component of the rect sdf and sdf_y = abs(f_quad_sdf.z) - f_linewidth for the second. The reference shows every point with positive max(sdf_x, sdf_y) in a darker shade, resulting in the outline around the rectangle.

3. Miter Joints

Drawing just the above would result in miter joints overlapping each other. To avoid this we also compute the signed distance field of the previous line segment along its line vector v0 and the sdf of the next line segment along v1:

vertex.quad_sdf0 = isvalid[0] ? dot(VP1, v0.xy) : 2 * AA_THICKNESS;
vertex.quad_sdf2 = isvalid[3] ? dot(VP2, -v2.xy) : 2 * AA_THICKNESS;

In the fragment shader we then check for each pixel/fragment whether it is "more inside" the previous, current or next line segment. If it is "most inside" the current line segment it is drawn, otherwise it is discarded for the other segment to draw. This makes sure that each pixel of a joint is only drawn once.

if (f_quad_sdf0 < f_quad_sdf1.x || f_quad_sdf2 <= f_quad_sdf1.y)
    discard;

The parts cut off by this process are visible in red and blue depending on which line segment they cut from.

Caveats/Notes:

  • If the previous or next line segment does not exist, its line vector is undefined. To avoid issues with this we explicitly set the sdf to a positive value, marking everything as outside
  • In the form given above this produces gaps at certain angles. For some reason this can be avoided entirely(?) by adding + 0.5 to each line-length sdf and rounding rect_vertex_pos = line_pos + round(offset). The rounding introduces a slight jitter. In GLMakie it seems to be fine to do round(128 * offset) / 128 to reduce/remove it, in WGLMakie that reintroduces over/underdraw.
  • In order for the main SDF to not discard points of the joint that are outside the original line segment rectangle, we need to shift f_quad_sdf1.xy by the abs(extrusion).
  • You could also handle these joints by adjusting the rendered geometry in normal cases. For that one vertex would move in -v1 direction and the other in +v1 direction. However if that shift becomes larger than the length of the segment, vertices from different ends of the segment would pass each other. In this case the geometry no longer describes the segment.

4. Truncated Miter Joints

To truncate a miter joint we need introduce an extra edge which does the truncation. The parts cut off by this edge are visible in green in the reference. Each segment has two signed distance fields describing the truncation given by

vertex.truncation.x = !is_truncated[0] ? -1.0 :
    dot(VP1, sign(dot(miter_n1, -v1.xy)) * miter_n1) - halfwidth * abs(miter_offset1);
vertex.truncation.y = !is_truncated[1] ? -1.0 :
    dot(VP2, sign(dot(miter_n2, +v1.xy)) * miter_n2) - halfwidth * abs(miter_offset2);

If the edge is not truncated they default to a constant -1 meaning no truncation. Otherwise they calculate the distance from the line vertex p1/p2 in the direction of far miter corner +- miter_n and then move the edge a certain amount in that direction.

Caveats

  • As long as a line segment draws over the previous/next line segment it will trigger the discard condition. E.g. if v0 = -v1 no overlap between the two segments will be shown, and if 1 is shorter than 0 parts of the line will disappear entirely. To fix this we introduce vec2 f_linelength as the maximum value for the previous and next line segments.

Linestyles

Linestyles make things more complicated. Let's start off with a new reference image an the basic idea.

Screenshot from 2024-01-25 16-56-09

Pattern sampling

Linestyles are represented with a signed distance field (pattern) that indicates which parts of the line should be hidden based on the cumulative length of the line. The cumulative length is calculated on the CPU but still needs to be corrected in the geometry shader to fit the rectangle we generated. This basically just involves some offsetting based on the extrusion and AA padding

vertex.uv = vec2((g_lastlen[index] + extrusion_with_AA) / pattern_length, 0.0);

where index differentiates the start and end of a line segment and pattern_length maps pixel scale values to a range appropriate to the pattern.

Joints

Joints are a big problem for patterns. If we just do the above patterns get fragmented if they switch between an on and off section in a joint. Consider for example a square from a :dot linestyle starting at point 2 in the reference. Most of the red section belonging to the right segment will read "no draw", with the little triangle at the bottom right reading "draw". Most of the blue section belonging to the left segment will read "draw" with the little triangle at the bottom left reading "no draw`. These little triangles as well as some uncolored parts will make the pattern discontinuous.

The solution used here gives patterns two main options:

  1. Fill the entire joint with either "draw" or "no draw"
  2. Remove the joint, extend one line segment and shorten the other

These options are controlled by process_pattern which returns a value each for the line start and end, describing whether it be adjusted (+-1) or not (0). It also sets f_pattern_overwrite which tells the fragment shader when to freeze the pattern in a "draw" or "no draw" state and which of the two it should be.

For each joint three values of the pattern are sampled: The center, i.e. the value at shared point and left (right) = - (+) max(extrusion, 0.5 * linewidth) which is the minimum distance needed for segments to not overlap. We then choose between option (1) and (2) based on the signs of (left, center, right):

  • (+++), (---): The pattern wants to draw or discard the whole joint. Use option (1) to ensure AA happens outside the joint
  • (-+-): Both sides of the joint draw, center does not. Use option (1) to extend the center across the joint, shrinking the drawn regions a bit.
  • (++-), (+--), (+-+): The pattern does not draw on the left edge and may draw inside the joint to the right. Elongate the line on the right side of the joint to include the left edge (+ AA padding) and shorten the other. (2)
  • (-++), (--+): The pattern does not draw on the right, and may to the left. Extend the left line to include the right edge and shorten the other. (2)

You can see option (1) taking effect at point 2 and option (2) at point 3 and 4.

For option (2) we need to make a bunch of adjustments to the geometry and SDF's we have set up:

  • f_quad_sdf1.xy needs to extrude to at least 0.5 * linewidth to not discard patterns on elongated line segments
  • vertices need to be offset as accordingly
  • The discards for joints need to be disabled as the segments are explicitly resized to avoid overlap. This can be done by setting f_quad_sdf0/1 to a large constant value if the respective side is elongated or shortened.
  • Similarly truncation for truncated joints needs to disabled. This can be done in the same way.

Colors

Since the vertex position of our line geometry do not match the positions where two line segments actually connect we cannot just pass colors as a vertex attribute. Specifically on the short side of a joint we would still render a color mixture rather than the color assigned to the respective line point. Extrapolating the color of the vertex in the geometry shader also doesn't work due to how colors gets interpolated on a triangle.

Screenshot from 2024-01-27 15-22-11

using GLMakie, LinearAlgebra
begin
    fig = Figure(size = (1200, 800))

    ax = Axis(fig[1, 1], title = "simple mesh")
    xlims!(ax, -0.5, 1.5)
    ylims!(ax, -0.5, 1.5)

    ps = Point2f[(-0.2,0), (-0.2,1), (1.2,0), (1.2,1)]
    fs = [1 2 3; 2 3 4]
    mesh!(ax, ps, fs, color = [:red, :red, :blue, :blue], shading = NoShading)
    mesh!(ax, Point2f[(0.2,0), (-0.2,1), (-0.2,0), (0.8,0), (1.2,1), (1.2,0)], [1 2 3; 4 5 6], color = (:white, 0.5), shading = NoShading)
    lines!(ax, Point2f[(0.2,0), (-0.2,1), (0.8,0), (1.2,1)][[1, 2, 4, 3, 1]], color = :black)



    ax = Axis(fig[1, 2], title = "distorted mesh")
    xlims!(ax, -0.5, 1.5)
    ylims!(ax, -0.5, 1.5)

    ps = Point2f[(0.2,0), (-0.2,1), (0.8,0), (1.2,1)]
    fs = [1 2 3; 2 3 4]
    mesh!(ax, ps, fs, color = [:red, :red, :blue, :blue], shading = NoShading)
    lines!(ax, Point2f[(0.2,0), (-0.2,1), (0.8,0), (1.2,1)][[1, 2, 4, 3, 1]], color = :black)



    ax = Axis(fig[1, 3], title = "extrapolated mesh")
    xlims!(ax, -0.5, 1.5)
    ylims!(ax, -0.5, 1.5)

    ps = Point2f[(-0.2,0), (-0.2,1), (1.2,0), (1.2,1)]
    fs = [1 2 3; 2 3 4]
    # bot: want red @ 0.2 and blue @ 0.8
    a = 0.4 / (0.8 - 0.2)
    cs = [RGBf(1+a, 0, -a), RGBf(1, 0, 0), RGBf(-a, 0, 1+a), RGBf(0, 0, 1)]
    mesh!(ax, ps, fs, color = cs, shading = NoShading)
    mesh!(ax, Point2f[(0.2,0), (-0.2,1), (-0.2,0), (0.8,0), (1.2,1), (1.2,0)], [1 2 3; 4 5 6], color = (:white, 0.5), shading = NoShading)
    lines!(ax, Point2f[(0.2,0), (-0.2,1), (0.8,0), (1.2,1)][[1, 2, 4, 3, 1]], color = :black)



    ax = Axis(fig[2, 1], title = "SDF - geometric normalization")
    xlims!(ax, -0.5, 1.5)
    ylims!(ax, -0.5, 1.5)

    ps = Point2f[(-0.2,0), (-0.2,1), (1.2,0), (1.2,1)]
    c11, c12, c21, c22 = ps

    img = let
        img = Matrix{RGBf}(undef, 101, 101)

        for (i, a) in enumerate(range(0, 1, length = size(img, 1)))
            for (j, b) in enumerate(range(0, 1, length = size(img, 2)))
                img[i, j] = RGBf(1-a, 0, a)
            end
        end

        img
    end
    heatmap!(ax, -0.2..1.2, 0..1, img)
    mesh!(ax, Point2f[(0.2,0), (-0.2,1), (-0.2,0), (0.8,0), (1.2,1), (1.2,0)], [1 2 3; 4 5 6], color = (:white, 0.5), shading = NoShading)
    lines!(ax, Point2f[(0.2,0), (-0.2,1), (0.8,0), (1.2,1)][[1, 2, 4, 3, 1]], color = :black)



    ax = Axis(fig[2, 2], title = "SDF: edge to edge normalized (per fragment)")
    xlims!(ax, -0.5, 1.5)
    ylims!(ax, -0.5, 1.5)

    # ps = Point2f[(0,0), (0,1), (1,0), (1,1)]
    ps = Point2f[(-0.2,0), (-0.2,1), (1.2,0), (1.2,1)]
    c11, c12, c21, c22 = ps
    v = Vec2f(1, 0)

    img = let
        img = Matrix{RGBf}(undef, 101, 101)

        for (i, a) in enumerate(range(0, 1, length = size(img, 1)))
            for (j, b) in enumerate(range(0, 1, length = size(img, 2)))
                l = ((1-b) * c11 + b * c12)
                r = ((1-b) * c21 + b * c22)
                p = (1-a) * l + a * r
                x0 = 0.2 + (-0.2 - 0.2) * b
                w = 0.6 + (1.4 - 0.6) * b
                x = (p[1] - x0) / w
                img[i, j] = RGBf(1-x, 0, x)
            end
        end

        img
    end
    heatmap!(ax, -0.2..1.2, 0..1, img)
    mesh!(ax, Point2f[(0.2,0), (-0.2,1), (-0.2,0), (0.8,0), (1.2,1), (1.2,0)], [1 2 3; 4 5 6], color = (:white, 0.5), shading = NoShading)
    lines!(ax, Point2f[(0.2,0), (-0.2,1), (0.8,0), (1.2,1)][[1, 2, 4, 3, 1]], color = :black)




    ax = Axis(fig[2, 3], title = "SDF: edge to egde normalized (per vertex)")
    xlims!(ax, -0.5, 1.5)
    ylims!(ax, -0.5, 1.5)

    # (pos - start) / width
    x11 = (-0.2 -  0.2) / 0.6
    x12 = (-0.2 - -0.2) / 1.4
    x21 = ( 1.2 -  0.2) / 0.6
    x22 = ( 1.2 - -0.2) / 1.4

    img = let
        img = Matrix{RGBf}(undef, 101, 101)

        for (i, a) in enumerate(range(0, 1, length = size(img, 1)))
            for (j, b) in enumerate(range(0, 1, length = size(img, 2)))
                l = ((1-b) * x11 + b * x12)
                r = ((1-b) * x21 + b * x22)
                x = (1 - a) * l + a * r
                img[i, j] = RGBf(1-x, 0, x)
            end
        end

        img
    end
    heatmap!(ax, -0.2..1.2, 0..1, img)
    mesh!(ax, Point2f[(0.2,0), (-0.2,1), (-0.2,0), (0.8,0), (1.2,1), (1.2,0)], [1 2 3; 4 5 6], color = (:white, 0.5), shading = NoShading)
    lines!(ax, Point2f[(0.2,0), (-0.2,1), (0.8,0), (1.2,1)][[1, 2, 4, 3, 1]], color = :black)


    fig
end

So instead we do the interpolation manually, by considering the distance from the left edge in line direction normalized to the distance between the left and right edge. To avoid problems with the short side of the line segment becoming <= 0 we do this calculation in the fragment shader.

// vert - get distance from left line point and length (both using vertex interpolation)
f_linestart = (1 - 2 * y) * extrusion[0];
f_linelength = segment_length1 - (1 - 2 * y) * (extrusion[0] + extrusion[1]);

// frag - interpolate
float factor = (-f_quad_sdf1.x - f_linestart) / f_linelength;
color = f_color1 + factor * (f_color2 - f_color1);
Testing Code
using Printf, GLMakie

begin
    fig = Figure(size = (1200, 800))


    marker_visible = Observable(true)
    on(Button(fig[1, 1], label = "Marker visible").clicks) do _
        marker_visible[] = !marker_visible[]
    end

    alpha = Slider(fig[1, 2], range = 0.0:0.01:1.0, startvalue = 0.5).value
    Label(fig[1, 3], map(x -> @sprintf("Line alpha = %0.2f", x), alpha), width = 100)

    # pattern_idx = Observable(1) # nothing, :dot, :dash
    # on(Button(fig[1, 4], label = "Switch Pattern").clicks) do _
    #     pattern_idx[] = mod1(pattern_idx[] + 1, 3)
    # end
    # linestyle = map(idx -> (:solid, :dot, :dash)[idx], pattern_idx)

    # ps = Observable([Point2f(x-20, 150) for x in 100:100:500])
    # ps = Observable(Point2f[(133.62674, 197.9638), (150, 200), (360, 230), (490, 130), (310, 90)])
    # ps = Observable(Point2f[(99.823944, 192.68478), (150, 200), (360, 230), (490, 130), (310, 90)])
    # ps = Observable(Point2f[(161.09152, 112.44344), (150, 200), (360, 230), (490, 130), (310, 90)])
    ps = Observable(Point2f[(151.05634, 131.97586), (150, 200), (360, 230), (490, 130), (310, 90)])
    lw = Observable([100.0, 100.0, 100.0, 100.0, 100.0])

    ax = Axis(fig[2, :], aspect = DataAspect())
    xlims!(ax, 0, 600)
    ylims!(ax, 0, 350)
    deactivate_interaction!(ax, :rectanglezoom)
    # scene.scene.backgroundcolor[] = RGBAf(1,0,0,1)
    # scene.scene.clear = true

    l = lines!(ax, ps, linewidth = lw, color = map(a -> RGBAf(0,0,0,a), alpha), transparency = true,
        linestyle = :solid, debug = true)
    p = scatter!(
        ax, ps, markersize = 20, color = :black, strokewidth = 2f0,
        strokecolor = :red, visible = marker_visible
    )
    translate!(p, Vec3f(0,0,1))

    selected = Ref(-1)

    on(events(ax).mousebutton, priority = 1000) do event
        if event.button == Mouse.left
            if event.action == Mouse.press
                plt, idx = pick(ax)
                if plt == p
                    selected[] = idx
                    return Consume(true)
                end
            elseif event.action == Mouse.release
                selected[] = -1
                return Consume(true)
            end
        end
        return Consume(false)
    end

    on(events(ax).mouseposition, priority = 1000) do mp
        if selected[] != -1
            ps[][selected[]] = mouseposition(ax)
            notify(ps)
            return Consume(true)
        end
        return Consume(false)
    end

    on(events(ax).scroll, priority = 1000) do (dx, dy)
        plt, idx = pick(ax)
        if plt == p
            lw[][idx] *= 0.9^dy
            notify(lw)
            return Consume(true)
        end
        return Consume(false)
    end

    on(events(ax).keyboardbutton, priority = 1000) do e
        if e.key == Keyboard.d && e.action == Keyboard.release
            # This requires the #ifdef DEBUG blocks in lines.frag to be 
            # replaced with a `if (debug)` and a `uniform bool debug`.
            # draw_lines/linesegments in glshaders/lines.jl also need to define `debug = false`
            # l.debug[] = !l.debug[] 
        end
    end

    display(fig, px_per_unit = 1.0)
end

TODO:

  • prototype with working joints
  • fix occasional overlap on hard edges (red)
  • reimplement patterns
    • basic pattern sampling
    • avoid slice sampling at start/end of line (optional)
    • avoid partial sampling of sharp joints
    • avoid partial sampling of truncated joints
    • avoid oversampling of truncated joints
  • test/implement variable line widths they create more problems than they're worth
    • fix disconnect cause by linewidth missmatch between start and end of a joint
    • fix overzealous cut-out with large linewidth_delta/linelength (caused by line rect becoming concave with a sharp joint)
    • find a better solution that removing joints
  • cleanup line overlap/cutoff for truncated joints (avoid cutting off too much of a line, avoid extrusion in linewidth direction)
    • maybe try adaptive method for solid lines
  • make sure there is always enough AA padding to actually do AA (calculate it)
  • switch back to old miter limit (~113.58° instead of 120°)
  • find & fix bugs related to joint orientation (line bending left vs right)
  • check pixel_per_unit
  • recombine with line_segments shader
  • test/compare performance (about the same)
  • smooth inner truncation for truncated miter joints
  • test:
    • fix linestyle for thin, dense lines (e.g. PolarAxis test)
    • fix/check darker lines in GLMakie/Connected Sphere.png (This is probably an AA change with super thin lines. Not sure if this requires fixing...)
    • fix disappearing line in GLMakie/Record Video.mp4
    • line visibility in GLMakie/colorscale (poly).png
    • coloring artifacts in GLMakie/colorscale (lines).png
    • gaps in GLMakie/Streamplot animation.mp4
    • bracket patterns
    • fix patterns/linestyles sometimes extruding too far
  • cleanup code, comments, document details here
    • Variable cleanup: drop segment_length0/2, remove number from f_extrusion12
    • maybe reverse direction of extrusion so linestart and linelength matches vertex definition
    • consider merging uv into f_quad_sdf1
    • equalize shader code between WGLMakie and GLMakie as much as possible
    • update explanation
  • WGLMakie...
    • move/implement joints (prev/next point, rect size adjustments, sdf generation & processing)
    • move/implement color handling (sample colormaps in vertex shader, use distance based color sampling)
    • move/implement linestyles (process patterns into GPU format, move pattern handling code)
    • implement normal rendering mode
    • implement linesegments
    • fix high density lines dissolving
    • fix error caused by using too many attributes (drop f_uv and avoid generating prev and next for every
      vertex attribute)
    • fix disappearing grid lines in Axis
    • fix artifacts from incomplete pattern discard for dense line sections
    • fix NaN handling
    • fix wrong color/alpha/line density in "streamplot 3d", "connected sphere", etc (partially transparency issue)
    • fix missing segments in "basic polygon shapes"
    • fix skipped pixels due to joint discard (lines number color, PolarAxis limits, PolarAxis radial shift and clip, Voronoiplot with a nonlinear transform, basic polygon shapes, Contour3d)
    • fix skipped pixels due to short segments (?) (contour labels 3D,
    • gap when looping line (i.e. first point = last point) (e.g. Tooltip)
    • cleanup offset calculation

For future prs see #3641.

Notes on tests

  • GLMakie/Animated surface and wireframe fails but I can't tell why
  • GLMakie/Depth Shift.png looks slightly different but that's due to volume

Issues

Type of change

  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
    • drops support for smoothly varying per-point linewidths
    • different rendering technique will likely cause at least some small visual differences
    • adjusted pattern scaling to dynamically change with linewidth. This avoids stretching and squashing of patterns when used with nan-separated lines of different linewidth (e.g. lines([1,1,1,1, NaN, 2,2,2,2], linewidth = [5,5,5,5,0,10,10,10,10], linestyle = :dot))
    • adjusted patterns to reset after NaN (i.e. after NaN start with a full dot/dash)

Checklist

  • Added an entry in NEWS.md (for new features and breaking changes)
  • Added or changed relevant sections in the documentation
  • Added unit tests for new algorithms, conversion methods, etc.
  • Added Enabled reference image tests for new plotting functions, recipes, visual options, etc.

@MakieBot
Copy link
Collaborator

MakieBot commented Jan 16, 2024

Compile Times benchmark

Note, that these numbers may fluctuate on the CI servers, so take them with a grain of salt. All benchmark results are based on the mean time and negative percent mean faster than the base branch. Note, that GLMakie + WGLMakie run on an emulated GPU, so the runtime benchmark is much slower. Results are from running:

using_time = @ctime using Backend
# Compile time
create_time = @ctime fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true)
display_time = @ctime Makie.colorbuffer(display(fig))
# Runtime
create_time = @benchmark fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true)
display_time = @benchmark Makie.colorbuffer(fig)
using create display create display
GLMakie 3.37s (3.32, 3.50) 0.06+- 401.91ms (396.23, 422.19) 9.07+- 527.69ms (519.30, 546.32) 8.62+- 7.23ms (7.10, 7.42) 0.10+- 25.61ms (25.37, 26.02) 0.27+-
master 3.36s (3.32, 3.39) 0.03+- 390.52ms (342.09, 404.05) 21.87+- 492.56ms (471.55, 570.64) 36.46+- 7.36ms (7.19, 7.63) 0.15+- 25.73ms (25.53, 26.12) 0.21+-
evaluation 1.00x invariant, 0.01s (0.20d, 0.71p, 0.04std) 0.97x invariant, 11.39ms (0.68d, 0.24p, 15.47std) 0.93x slower❌, 35.13ms (1.33d, 0.04p, 22.54std) 1.02x invariant, -0.13ms (-0.99d, 0.09p, 0.13std) 1.00x invariant, -0.12ms (-0.51d, 0.36p, 0.24std)
CairoMakie 3.08s (3.04, 3.14) 0.03+- 330.83ms (325.55, 339.08) 5.35+- 145.13ms (142.98, 148.43) 2.31+- 7.45ms (7.29, 7.77) 0.17+- 606.17μs (600.82, 614.54) 4.80+-
master 3.07s (3.03, 3.13) 0.04+- 328.11ms (322.89, 345.19) 7.65+- 143.08ms (139.55, 148.28) 2.90+- 7.28ms (7.07, 7.48) 0.17+- 605.39μs (596.77, 618.77) 7.88+-
evaluation 1.00x invariant, 0.01s (0.33d, 0.55p, 0.03std) 0.99x invariant, 2.72ms (0.41d, 0.46p, 6.50std) 0.99x invariant, 2.06ms (0.78d, 0.17p, 2.61std) 0.98x invariant, 0.16ms (0.96d, 0.10p, 0.17std) 1.00x invariant, 0.78μs (0.12d, 0.83p, 6.34std)
WGLMakie 3.52s (3.50, 3.57) 0.02+- 414.04ms (408.91, 424.45) 5.45+- 9.17s (9.09, 9.23) 0.05+- 9.58ms (9.27, 10.54) 0.44+- 69.37ms (68.86, 70.50) 0.56+-
master 3.53s (3.51, 3.55) 0.01+- 414.46ms (410.05, 421.15) 3.48+- 9.16s (9.09, 9.23) 0.05+- 9.30ms (9.19, 9.42) 0.07+- 68.24ms (67.60, 69.37) 0.71+-
evaluation 1.00x invariant, -0.01s (-0.32d, 0.56p, 0.02std) 1.00x invariant, -0.42ms (-0.09d, 0.87p, 4.47std) 1.00x invariant, 0.0s (0.07d, 0.89p, 0.05std) 0.97x invariant, 0.28ms (0.91d, 0.14p, 0.25std) 0.98x slower X, 1.13ms (1.76d, 0.01p, 0.64std)

@ffreyer
Copy link
Collaborator Author

ffreyer commented Jan 17, 2024

On master (GLMakie) truncated joints (i.e. joints that connect two segments with a flat cap rather than extruding them into a spike) generate some overlapping geometry which you can see in with transparent lines:

Screenshot from 2024-01-17 18-31-01

This is probably not something I can fix here. Cutting off the segments to cleanly join them can cause the entire segment to be cut off which looks bad if the next segment doesn't fill the full space:

Screenshot from 2024-01-17 18-28-40

The other option is to not cut, which leaves overlap (I can fix the corners here, but most of the overlap will remain):

Screenshot from 2024-01-17 18-28-06

It might be possible to do some in-between solution that does a clean cut for as long as it works out, and then adds overlap beyond that.

@ffreyer
Copy link
Collaborator Author

ffreyer commented Jan 23, 2024

This pr is currently removing/ignoring per-point linewidths, because they make everything annoyingly complicated. Without them the line rendering seems good to me now. The only small issue is that line joins occasionally end up skipping a few pixels: This has been mostly fixed (After 2b0ed24 this issue is reduced to a rare missing single pixel)

Screenshot from 2024-01-23 20-54-02

I think this is a float precision issues coming from the vertices of different segments being different.

Self-overlap never happens for pointy joints, and early for truncated joints. Currently these overlap edges are not anti-aliased, but I could try to fix that.

Screenshot from 2024-01-23 21-00-38

Patterns/linestyles snap to/around joints to avoid them getting fragmented:

Screenshot from 2024-01-23 20-30-18 Screenshot from 2024-01-23 20-30-28 Screenshot from 2024-01-23 20-30-34
Screenshot from 2024-01-23 20-30-50 Screenshot from 2024-01-23 20-30-44

@ffreyer ffreyer changed the title Rework line shaders again Rework line shaders for WGLMakie compatability Jan 24, 2024
@ffreyer
Copy link
Collaborator Author

ffreyer commented Jan 24, 2024

I'm wondering if we should just truncate truncated joints immediately rather than extruding them a bit. That would give use a much nicer overlap (clean AA and no section without overlap):
Screenshot from 2024-01-24 17-02-09

@ffreyer ffreyer mentioned this pull request Feb 19, 2024
@SimonDanisch SimonDanisch changed the base branch from master to breaking-0.21 February 23, 2024 13:36
@SimonDanisch SimonDanisch mentioned this pull request Feb 23, 2024
12 tasks
@ffreyer
Copy link
Collaborator Author

ffreyer commented Feb 23, 2024

Found another issue where lines sometimes give up on drawing segments when they go in the (exact?) opposite direction or the previous/next

Screenshot from 2024-02-23 23-42-01

MWE: (move camera)

scatterlines([s * x * Vec2f(1, 1) for x in 1:3 for s in (-1, 1)])

The problem was that if a line reverses, i.e. v1 = -v2, then the same is true for the normals and thus miter_n2 = normalize(n1 + n2) = vec2(0). To avoid this I changed it to miter_n2 = normalize(n1 + n2 + v1 - v2). v1 - v2 is the same direction but cancels to vec2(0) at 0° rather than 180°. So together they always produce a valid result.
v1 - v2 is either in the same or opposite direction of n1+n2 so we can't just add them up. Switching between them should work smoothly though. is_truncated is a decent trigger for this as long as we don't make miter limit/joinstyle adjustable. (We need to switch before dot(v1, v2) = -1.0)

@SimonDanisch SimonDanisch reopened this Feb 27, 2024
@SimonDanisch SimonDanisch merged commit 3f885c3 into breaking-0.21 Feb 27, 2024
30 of 34 checks passed
@SimonDanisch SimonDanisch deleted the ff/lines branch February 27, 2024 18:33
SimonDanisch added a commit that referenced this pull request May 8, 2024
* run CI against this PR

* bump version

* fix circular reference

* remove GeoInterfaceMakie tests for good to avoid circular dependencies

* add poly1

* Rework line shaders for WGLMakie compatability (#3558)

* prototyping

* fix joint with non-uniform linewidths

* fix transform

* add patterns

* fix pattern sampling

* fix truncated join cutoff + some cleanup

* improve pattern overwrite threshhold

* reorganize code

* cleanup

* add function for line vec -> line normal

* don't try to cleanup joints if linewidth difference is critical

* rename some variables

* cleanup comments, restructure linewidth sdf generation

* minor cleanup + notes

* fix orientation problems with truncated joints

* minor performance tweaks + cleanup

* handle line joints in fragment shader & ditch variable linewidths

* improve truncation overlap/gap

* improve pattern adjustments for truncated joints

* cleanup

* reorganize code to reduce memory usage

* mostly fix gap in sharp joints

* explain pattern overwrite a bit more

* use new fragment shader for linesegments

* disable debug rendering

* fix incorrect line placement

* adjust line segments to pattern

* use const over define & fix dots

* tweak debug rendering

* make truncation overlap a bit nicer

* minor cleanup

* fix linestyle in linesegments

* skip rendering at 0 linewidth

* add slight bias to avoid missing pixels

* differentiate different segments in debug render

* make color interpolation continuous at joint

* fix dense line color artifacts

* remove unused

* allocate space for joints

* use sdf for AA + debug render

* add miter joints

* handle colors

* some cleanup + linesegments prep

* fix some errors [skip ci]

* add patterns

* clean up linesegments

* add normal rendering mode

* minor cleanup

* experiment with geometry adjustments

* use rounding to solve joint over/underdraw

* WebGL doesn't like scaling

* smooth out inner edge of truncated join

* remove derivative to reduce float accuracy issues

* improve thin lines

* fix lastlen error

* match buffer sizes to number of drawn segments

* avoid dissipation of lines at high point densities

* calculate uv from quad_sdf1

* reduce number of interleaved buffers

* fix disappearing grid lines

* fix missing preprocessors

* fix pattern artifacts in dense line sections

* cleanup some variables

* allow patterns to adjust to linewidth

* fix AA at line end

* fix nan handling

* discard fully transparent pixels

* fix patterns with nan, reset pattern on nan

* fix size issues

* extrude lines slightly to cleanly close them

* fix pixel skipping?

* cleanup patterns

* remove linewidth from pattern based line adjustments

* consider AA in shape factor

* reset shape_factor if pattern changes segment shape

* minor cleanup

* apply changes to WGLMakie + cleanup

* cleanup pattern overwrite

* use the same AA_RADIUS in fragment shader

* fix linelen transform

* disable debug

* fix line start/end AA

* fix px_per_unit?

* fix px_per_unit?

* reduce line start/end extrusion

* simplify extrusion and shape_factor

* summarize breaking changes

* move miter joint test

* update docstring

* minor cleanup

* enable more tests

* move gappy & friends to Makie

* note change to linestyle scaling

* cleanup

* fix line start/end AA

* remove global var

* disable GeoMakie tests for now

* improve transparency for WGLMakie

* fix problems with 180° change in line direction

* fix directionality

* interpolate colormap in fragment shader

* remove util.vert from line/segments

---------

Co-authored-by: SimonDanisch <sdanisch@protonmail.com>

* fix line inversion (#3651)

* fix lines shader

* cleanup debug code

* fix rebase error

* fix pattern connectivity

* some cleanup

* apply changes to WGLMakie

* add test

* fix CairoMakie too

* update changelog

* fix missing start/end segment

* Update CHANGELOG.md

* update comments

---------

Co-authored-by: Simon <sdanisch@protonmail.com>

* Documented / validated plot attributes (#3626)

* add second `@recipe` method

* rename function

* implement recipe and keyword validation

* fix some bugs

* rename for clarity

* change Scatter recipe

* use argument symbols correctly

* change Lines

* change linesegments

* do a bunch of plots more

* fix text bugs

* splice in internal attribute after mesh creation

* add allowlist

* fix text

* add attribute deprecation mechanism

* add explanation

* remove `text` for GLMakie

* fix contour volume attributes

* add rasterize to allowlist

* add `enable_depth` to volume

* add `matcap` to mesh

* set `fxaa = false` on scatter, lines, linesegments, text

* move fxaa after mixins

* fix keywords

* remove markersize attribute

* remove invalid markersize

* add depthsorting to attributes for scatter

* fix forwarded attributes

* add absorption to volume

* don't use `used_attributes` for datashader canvas convert

* fix positional args

* image

* add better printing and rudimentary tests

* make allowlist a tuple for fewer allocations

* attribute names tuple instead of set

* make deprecations also a tuple

* avoid intermediate vector to speed up attribute creation

* apply same optimization to blocks

* implement mechanism to augment user docstring

* delete manually written out attribute docs

* use funcsym in docstring

* incorporate attribute docs into docstring again

* use equal

* add changelog

* introduce `DocumentedAttributes` with macro

* add function to access `DocumentedAttributes` of a recipe

* fix module mutation problem for now

* move definition behind PlotType

* return Attributes instead of Dict

* convert wireframe recipe

* close over reference

* don't include prereleases in benchmark, failed with 1.11 alpha

* stringify default expr

* convert arrows

* add docs

* directly convert default exprs to strings

* convert ablines

* print wrong attribute in red

* convert annotations

* convert arc

* remove attributes in arrows docstring

* convert band

* fix escaping issue

* convert barplot

* convert bracket

* fix barplot usage in hist

* convert contourf

* typo

* convert contour

* fix waterfall

* comment out arrows test

* convert datashader

* convert errorbar and rangebar

* convert hvlines

* convert hvspan

* convert pie

* convert rainclouds

* convert scatterlines

* convert series

* convert spy

* convert stairs

* convert stem

* convert streamplot

* convert timeseries

* convert tooltip

* convert tricontourf

* add transformation to allowlist

* convert triplot

* convert volumeslices

* convert voronoiplot

* convert waterfall

* convert boxplot

* convert crossbar

* convert density

* convert qqplot and qqnorm

* convert ecdfplot

* convert hexbin

* convert hist

* convert violin

* improve error message printing

* add docstrings for mutating functions and plot types

* add missing docstrings

* reconnect lines docstring

* move functions out of macro

* fix arrows example and adjust docs

* put necessary functions back into macro

---------

Co-authored-by: Simon <sdanisch@protonmail.com>

* Add voxel plot type (#3527)

* create voxel rendering prototype

* enable lighting

* prototype voxel id generation & color handling

* add is_air attribute

* prototype texture mapping

* fix shader reloading

* fix texture mapping

* implement local updates

* optimize render order (depthsorting = false)

* add depthsorting = true

* render z planes first

* add lowclip and highclip

* add refimg tests + some fixes

* fix colorrange

* fix local chunk update

* handle colorrange more efficiently

* handle voxel id data more efficiently

* docstring & formatting

* switch back to lrbt order for uvmap

* add docs

* try fix tests

* fix show

* fix test?

* add missing dimensions

* add arguments for placement and scale

* allow Colon

* add Colon() to local_update

* minor cleanup

* prototype WGLMakie version

* add fallback in CairoMakie

* add RPRMakie fallback

* skip invisible voxels

* fix typo

* rename voxel -> voxels

* update docs, fix placement

* update news

* fix Colorbar for voxels

* enable tests

* fix texture rotation

* cleanup print

* cleanup comment

* generalize array access

* debug WGLMakie

* get voxels rendering in WGLMakie

* fix texture mapping

* activate tests

* fix moving planes, cleanup prints

* add unit tests

* add gap attribute

* tests & docs

* mention potential issues with picking

* fix WGLMakie picking

* fix depthsorting/gap handling

* switch to integer mod

* fix render order

* use RNG

* fix 1.6 3d array syntax

* fix refimage

* Update CHANGELOG.md

* fix julia 1.6

---------

Co-authored-by: Simon <sdanisch@protonmail.com>

* implement Float32 without losing Float64 precision (rebased) (#3681)

* implement float64 precision

* remove merge conflicts

* update CairoMakie

* move some code around

* simplify syntax

* add non-Observable apply_transform_and_f32_conversion

* clean up convert_arguments

* update WGLMakie

* fix tests

* patch model to act after f32convert

* fix function name

* update project and plot_to_screen

* fix patch_model

* add first test

* rename file

* fix type after patch_model

* fix ticks beyond limits

* fix image and heatmap conversion

* convert to float types

* update test

* Fix CairoMakie not precompiling

missed a `Makie.` in the image recipe

* update mesh converts

* fix poly convert type

* fix dict access

* fix first test in WGLMakie

* don't use triangle_mesh

* fix incorrect convert_arguments

* fix test

* fix DataInspector error

* add meshscatter + surface to tests, fix convert_arguments for poly

* Fix docs + Makie tests

* Fix 1.6!?

* fix picking test

* update DataInspector

* fix indicator rotation for meshscatter in DataInspector

* fix Vector{<: Integer}, Vector{Float32} -> Vector{Float32} [skip ci]

* fix stackoverflow on mixed tuple types [skip ci]

* fix tuples correctly [skip ci]

* fix geom -> points eltype [skip ci]

* fix geom -> PointBased output type

* fix Rect2 -> points output type [skip ci]

* fix PointBased mesh conversion

* fix PointBased multi-linestrings type [skip ci]

* update bezierpath

* split up conversions

* fix missing Points convert [skip ci]

* fix CellGridBased types [skip ci]

* always convert volumes to float32

* start adding type tests for every convert_arguments

* fix tests

* undo splitting conversions.jl

* test and cleanup mesh conversions

* fix docs

* update & test Annotations

* update & test arrows

* update and test band and bracket

* update & test errorbars and rangebars conversions

* test & update series converts

* make type stable on 1.6

* update & test remaining convert_arguments

* fix & test model application

* add tests for float32convert

* at floatmin/max refimg test

* fix typo

* update text bbox test & add backtrace

* avoid Float32 in data_limits

* fix Polygon -> Bezierpath conversion

* fix WGLMakie meshscatter model patching

* fix Float64 normals

* fix Float64 matrices in Voxels

* test normal and uv types

* fix for 1.6

* make new project method more complete

* clean up some TODOs

* restore text tests

* restore Polar transform tests

* avoid BBox for Axis limits

* fix rectangle zoom, deprecate to_world with matrix inputs

* fix 1.6

* fix Float64 latexstrings

* fix hvlines, hvspan, errorbars, rangebars

* fix & test ablines

* fix other usage of projview_to_2d_limits

* remove dublicated line

* update changelog + cleanup [skip ci]

* fix missing to_value

* consider markersize and offset for scatter data_limits

* fix tests

* revert BBox -> Rect2d changes

* get hist and barplot working

---------

Co-authored-by: ffreyer <frederic481994@hotmail.de>
Co-authored-by: Anshul Singhvi <anshulsinghvi@gmail.com>

* Document conversion pipeline (#3719)

* document conversion pipeline

* fix doc build

* fix block

---------

Co-authored-by: SimonDanisch <sdanisch@protonmail.com>

* Deprecate `rotations` for `rotation` for Scatter and MeshScatter (#3724)

* deprecate `rotations` for `rotation` for Scatter and MeshScatter

* one more rename

* remove double conversion

* fix cairomakie meshscatter

* fix usage in docs

* remove mat4 code again

* fix CairoMakie rror

* change one more rotations

* fix WGLMakie

* add changelog entry

---------

Co-authored-by: ffreyer <frederic481994@hotmail.de>

* fix merge

* update scatter boundingbox (#3716)

* implement scatter boundingbox with marker metrics

* add tests

* always consider marker rotations

* update changelog [skip ci]

* fix data_limits

* fix some more issues

* rotations -> rotation

* Update boundingboxes.jl

---------

Co-authored-by: Simon <sdanisch@protonmail.com>

* Change how boundingbox(::Text) is deprecated (#3723)

* change how boundingbox is deprecated

* update changelog

* fix test errors

* fix docs errors and cleanup error message

* fix type instability

* fix function name

* fix function name

* fix boundingbox overwrites

* update changelog

* add types to function args

maybe this allows boundingbox(::MyPlot, space) to work without ::Symbol...

* fix typing

* fully remove :world space

* fix test

* Various fixes for next release (#3731)

* fix error for 2d meshscatter data_limits

* avoid Rect3(::Rect2) constructor

* allow :inspector_label

* allow inspector_clear and inspector_hover too

* fix rect zoom & cleanup to_world

* move inspector attributes to default attributes

* fix NaN handling in limits & deprecate _update_rect

* Update CHANGELOG.md

* Fix some issues with voxels (#3748)

* fix single color

* update to new attribute docs and hide internal attributes

* fix missing voxel planes in Axis3

* use transformationmatrix

* should be normalized

* make view_direction optimization less error prone

* Fix rare missing/duplicate pixels in truncated joint (#3794)

* rework truncated joint discard

* update WGLMakie

* fix non-solid linestyle joints

* Add linecaps and jointstyles (#3771)

* add attributes

* prototype linecap & linestyle in GLMakie

* move code around, add comments

* add capstyle for linesegments

* update WGLMakie

* revert change in padding of uncapped lines

* make sure truncation can't trigger

* update CairoMakie

* add :bevel

* make miter_limit adjustable

* capstyle -> linecap

* update changelog

* add refimg tests

* add example

* fix rendering issue with bevel for continued lines

* use named constants

* add more space to test

* consider miter_limit in CairoMakie as well

* also enable refimg test

* switch to angle based miter_limit

* fix default

* tweak tests

* note change in default miter_limit

* add new attributes to recipes

* rename jointstyle -> joinstyle

* update a few more jointstyles

* Fix rare missing/duplicate pixels in truncated joint (#3794)

* rework truncated joint discard

* update WGLMakie

* fix non-solid linestyle joints

* improve truncated linecap a bit

* regenerate wglmakie bundled

* tweak shape_factor

* restore file

* try fix connected sphere

* add debug refimgs

* more testing

* more testing

* revert debugging

* fix test?

* Cleanup for breaking 0.21 (#3765)

* cleanup temp defitions

* finalize data_limits cleanup

* GeometryBasics should probably be breaking

* adjust other versions

* use newly tagged GeometryBasics

* use breaking gridlayoutbase

* try updating registry

* somehow this is needed?!

* add to missing CI

---------

Co-authored-by: SimonDanisch <sdanisch@protonmail.com>

* Unit support for Axes & Recipes, a.k.a axis converts (#3226)

* take over most of the work from #1347

* add typed argument conversion (#3565)

* add typed argument conversion

* fix volume

* add function to get available conversions

* make conversion apply more narrowly

* more cleanly separate recursion in convert_arguments

* clean up

* allow to get axis before creating a plot

* clean up

* fix tests

* bring back dim converts (axis_convert)

* update tests

* fix tests and work around conversion problems

* fix WGLMakie

* fix errors

* clean up conversion pipeline

* fix tests

* add changelog entry

* disable project run

* improve performance slightly

* might as well use array

* tmp

* wip

* implement axis convert recursion

* fix tests

* fix datashader

* fix datashader

* move unitful integration

* fix performance regression!?

* fix merge & new date time improvements

* fix scaling test

* remove test false

* clean up

* converts shouldnt be here

* move axis converts to scene

* further refactor [skip ci]

* finish refactor for AxisConversion type

* allow limit setting and ticks

* make tests less noisy

* cleanup

* clean up and fix unitful/date conversion

* make sure all tests work correctly

* remove rand

* rename, clean up and make axis spec work

* clean up and test new conversion pipeline

* undo feature deletion, don't reintroduce Rect2f

* be explicit about Volume Interval types

* minor docstring cleanup

* try to clarify new conversion docstrings

* remove convert_arguments_typed in favor of types_for_plot_arguments

* fix remaining bugs for conversion simplification

* fix ticks not updating

* fix specapi

* fix qqnorm

* clean up types_for_plot_arguments

* fix tuple conversion

* try to fix compile time regression

* try to fix compile time regression

* clean up and introduce expand_dimensions

* fix #3655 and clean up convert_arguments + add tests

* fix #3509 and add tests for

* clean up observables and more docs

* final rename

* fix docs

* cleanup

* small clean up

* small doc improvements

* improve docs

* fix docs

* try relative link

* try without .md

* take out link

* try fix

---------

Co-authored-by: ffreyer <frederic481994@hotmail.de>

* fix comment

* Add wrap recipe tutorial (#3816)

* [Docs] add wrap/redirect recipe tutorial

* fix sentence

* Update docs/tutorials/wrap-existing-recipe.md

Co-authored-by: Anshul Singhvi <anshulsinghvi@gmail.com>

* update

* fix doc build

* add changelog

* fix preview

---------

Co-authored-by: Moelf <proton@jling.dev>
Co-authored-by: Anshul Singhvi <anshulsinghvi@gmail.com>

* only forward attributes usable by recipe

* make sharing of attributes explicit

* ci

* fix RPRMakie material

* small fixes

* fix RPRMakie

* fix series with BezierPath

* fix series conversions

---------

Co-authored-by: Frederic Freyer <frederic481994@hotmail.de>
Co-authored-by: Julius Krumbiegel <22495855+jkrumbiegel@users.noreply.github.com>
Co-authored-by: Anshul Singhvi <anshulsinghvi@gmail.com>
Co-authored-by: Moelf <proton@jling.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants