From 87c8be598a07493fe7839a4ddc161fe2aecc9ab2 Mon Sep 17 00:00:00 2001 From: hdavid16 Date: Tue, 24 Jan 2023 11:21:26 -0500 Subject: [PATCH 01/10] Fix #105 --- src/beziercurves.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/beziercurves.jl b/src/beziercurves.jl index 631e4f69..2a3cbf5b 100644 --- a/src/beziercurves.jl +++ b/src/beziercurves.jl @@ -197,7 +197,7 @@ function Path(P::Vararg{PT, N}; tangents=nothing, tfactor=.5) where {PT<:Abstrac # first command, recalculate WP if tangent is given first_wp = WP[1] if tangents !== nothing - p1, p2, t = P[1], P[2], normalize(tangents[1]) + p1, p2, t = P[1], P[2], normalize(Pointf(tangents[1])) dir = p2 - p1 d = tfactor * norm(dir ⋅ t) first_wp = PT(p1+d*t) @@ -214,7 +214,7 @@ function Path(P::Vararg{PT, N}; tangents=nothing, tfactor=.5) where {PT<:Abstrac # last command, recalculate last WP if tangent is given last_wp = (P[N] + WP[N-1])/2 if tangents !== nothing - p1, p2, t = P[N-1], P[N], normalize(tangents[2]) + p1, p2, t = P[N-1], P[N], normalize(Pointf(tangents[2])) dir = p2 - p1 d = tfactor * norm(dir ⋅ t) last_wp = PT(p2-d*t) From ff33b9b031a3ce96e154ca8e6d53d5327b432c71 Mon Sep 17 00:00:00 2001 From: hdavid16 Date: Tue, 24 Jan 2023 11:21:41 -0500 Subject: [PATCH 02/10] Allow selfloop to have waypoints. Update docstring --- src/recipes.jl | 114 ++++++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 54 deletions(-) diff --git a/src/recipes.jl b/src/recipes.jl index 09f35988..5cb8351b 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -72,11 +72,12 @@ the edge. - `edge_plottype=Makie.automatic()`: Either `automatic`, `:linesegments` or `:beziersegments`. `:beziersegments` are much slower for big graphs! -Self edges / loops: +Self edges / loops: -- `selfedge_size=Makie.automatic()`: Size of self-edge-loop (dict/vector possible). -- `selfedge_direction=Makie.automatic()`: Direction of self-edge-loop as `Point2` (dict/vector possible). +- `selfedge_size=Makie.automatic()`: Size of selfloop (dict/vector possible). +- `selfedge_direction=Makie.automatic()`: Direction of center of the selfloop as `Point2` (dict/vector possible). - `selfedge_width=Makie.automatic()`: Opening of selfloop in rad (dict/vector possible). +- Note: If valid waypoints are provided for selfloops, the selfedge attributes above will be ignored. High level interface for curvy edges: @@ -104,6 +105,8 @@ Tangents interface for curvy edges: Higher factor means bigger radius. Can be tuple per edge to specify different factor for src and dst. +- Note: Tangents are ignored on selfloops if no waypoints are provided. + Waypoints along edges: - `waypoints=nothing` @@ -111,7 +114,12 @@ Waypoints along edges: dict. Waypoints will be crossed using natural cubic splines. The waypoints may or may not include the src/dst positions. -- `waypoint_radius=nothing`: If number (dict/vector possible) bent lines within radius of waypoints. +- `waypoint_radius=nothing` + + If the attribute `waypoint_radius` is `nothing` or `:spline` the waypoints will + be crossed using natural cubic spline interpolation. If number (dict/vector + possible), the waypoints won't be reached, instead they will be connected with + straight lines which bend in the given radius around the waypoints. """ @recipe(GraphPlot, graph) do scene # TODO: figure out this whole theme business @@ -356,61 +364,59 @@ function find_edge_paths(g, attr, pos::AbstractVector{PT}) where {PT} paths = Vector{AbstractPath{PT}}(undef, ne(g)) for (i, e) in enumerate(edges(g)) - if src(e) == dst(e) # selfedge - size = getattr(attr.selfedge_size, i) - direction = getattr(attr.selfedge_direction, i) - width = getattr(attr.selfedge_width, i) - paths[i] = selfedge_path(g, pos, src(e), size, direction, width) - else # no selfedge - p1, p2 = pos[src(e)], pos[dst(e)] - tangents = getattr(attr.tangents, i) - tfactor = getattr(attr.tfactor, i) - waypoints::Vector{PT} = getattr(attr.waypoints, i, PT[]) - - cdu = getattr(attr.curve_distance_usage, i) - if cdu === true + p1, p2 = pos[src(e)], pos[dst(e)] + size = getattr(attr.selfedge_size, i) + direction = getattr(attr.selfedge_direction, i) + width = getattr(attr.selfedge_width, i) + tangents = getattr(attr.tangents, i) + tfactor = getattr(attr.tfactor, i) + waypoints::Vector{PT} = getattr(attr.waypoints, i, PT[]) + radius = getattr(attr.waypoint_radius, i, nothing) + + cdu = getattr(attr.curve_distance_usage, i) + if cdu === true + curve_distance = getattr(attr.curve_distance, i, 0.0) + elseif cdu === false + curve_distance = 0.0 + elseif cdu === automatic + if is_directed(g) && has_edge(g, dst(e), src(e)) curve_distance = getattr(attr.curve_distance, i, 0.0) - elseif cdu === false + else curve_distance = 0.0 - elseif cdu === automatic - if is_directed(g) && has_edge(g, dst(e), src(e)) - curve_distance = getattr(attr.curve_distance, i, 0.0) - else - curve_distance = 0.0 - end end + end - if !isnothing(waypoints) && !isempty(waypoints) #there are waypoints - # the waypoints may already include the endpoints - waypoints[begin] == p1 && popfirst!(waypoints) - waypoints[end] == p2 && pop!(waypoints) - - radius = getattr(attr.waypoint_radius, i, nothing) - - if isempty(waypoints) || radius === nothing || radius === :spline - paths[i] = Path(p1, waypoints..., p2; tangents, tfactor) - elseif radius isa Real - paths[i] = Path(radius, p1, waypoints..., p2) - else - throw(ArgumentError("Invalid radius $radius for edge $i!")) - end - elseif !isnothing(tangents) - paths[i] = Path(p1, p2; tangents, tfactor) - elseif PT<:Point2 && !iszero(curve_distance) - d = curve_distance - s = norm(p2 - p1) - γ = 2*atan(2 * d/s) - a = (p2 - p1)/s * (4*d^2 + s^2)/(3s) - - m = @SMatrix[cos(γ) -sin(γ); sin(γ) cos(γ)] - c1 = PT(p1 + m*a) - c2 = PT(p2 - transpose(m)*a) - - commands = [MoveTo(p1), CurveTo(c1, c2, p2)] - paths[i] = BezierPath(commands) - else # straight line - paths[i] = Path(p1, p2) + if !isnothing(waypoints) && !isempty(waypoints)#there are waypoints + # the waypoints may already include the endpoints (remove them if so) + waypoints[begin] == p1 && popfirst!(waypoints) + waypoints[end] == p2 && pop!(waypoints) + if p1 == p2 && isempty(waypoints) + paths[i] = selfedge_path(g, pos, src(e), size, direction, width) + elseif isempty(waypoints) || radius === nothing || radius === :spline + paths[i] = Path(p1, waypoints..., p2; tangents, tfactor) + elseif radius isa Real + paths[i] = Path(radius, p1, waypoints..., p2) + else + throw(ArgumentError("Invalid radius $radius for edge $i!")) end + elseif p1 == p2 # selfedge + paths[i] = selfedge_path(g, pos, src(e), size, direction, width) + elseif !isnothing(tangents) + paths[i] = Path(p1, p2; tangents, tfactor) + elseif PT<:Point2 && !iszero(curve_distance) + d = curve_distance + s = norm(p2 - p1) + γ = 2*atan(2 * d/s) + a = (p2 - p1)/s * (4*d^2 + s^2)/(3s) + + m = @SMatrix[cos(γ) -sin(γ); sin(γ) cos(γ)] + c1 = PT(p1 + m*a) + c2 = PT(p2 - transpose(m)*a) + + commands = [MoveTo(p1), CurveTo(c1, c2, p2)] + paths[i] = BezierPath(commands) + else # straight line + paths[i] = Path(p1, p2) end end From 10e759ad821279d743926bc2ab395f5cc20f156d Mon Sep 17 00:00:00 2001 From: hdavid16 Date: Tue, 24 Jan 2023 12:15:36 -0500 Subject: [PATCH 03/10] add simple example of a self loop with waypoints --- docs/examples/reftests.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/examples/reftests.jl b/docs/examples/reftests.jl index 8064d7e1..0d5195a2 100644 --- a/docs/examples/reftests.jl +++ b/docs/examples/reftests.jl @@ -126,3 +126,9 @@ graphplot(fig[2,1], edge_plottype = :beziersegments, ) @save_reference fig + +# ##self loop with waypoints +g1 = SimpleDiGraph(1) +add_edge!(g1, 1, 1) #add self loop +fig, ax, p = graphplot(g1, layout = _ -> [(0,0)], waypoints = [[(1,-1),(1,1),(-1,1),(-1,-1)]]) +@save_reference fig From e34e5216bba80de744cf40b51e6d638dc590438e Mon Sep 17 00:00:00 2001 From: hdavid16 Date: Tue, 24 Jan 2023 12:16:09 -0500 Subject: [PATCH 04/10] fix check on self loop; improve control flow --- src/recipes.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/recipes.jl b/src/recipes.jl index 5cb8351b..13bd4bb8 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -373,6 +373,11 @@ function find_edge_paths(g, attr, pos::AbstractVector{PT}) where {PT} waypoints::Vector{PT} = getattr(attr.waypoints, i, PT[]) radius = getattr(attr.waypoint_radius, i, nothing) + if !isnothing(waypoints) && !isempty(waypoints) #remove p1 and p2 from waypoints if these are given + waypoints[begin] == p1 && popfirst!(waypoints) + waypoints[end] == p2 && pop!(waypoints) + end + cdu = getattr(attr.curve_distance_usage, i) if cdu === true curve_distance = getattr(attr.curve_distance, i, 0.0) @@ -386,20 +391,15 @@ function find_edge_paths(g, attr, pos::AbstractVector{PT}) where {PT} end end - if !isnothing(waypoints) && !isempty(waypoints)#there are waypoints - # the waypoints may already include the endpoints (remove them if so) - waypoints[begin] == p1 && popfirst!(waypoints) - waypoints[end] == p2 && pop!(waypoints) - if p1 == p2 && isempty(waypoints) - paths[i] = selfedge_path(g, pos, src(e), size, direction, width) - elseif isempty(waypoints) || radius === nothing || radius === :spline + if !isnothing(waypoints) && !isempty(waypoints) #there are waypoints + if isempty(waypoints) || radius === nothing || radius === :spline paths[i] = Path(p1, waypoints..., p2; tangents, tfactor) elseif radius isa Real paths[i] = Path(radius, p1, waypoints..., p2) else throw(ArgumentError("Invalid radius $radius for edge $i!")) end - elseif p1 == p2 # selfedge + elseif src(e) == dst(e) # selfedge paths[i] = selfedge_path(g, pos, src(e), size, direction, width) elseif !isnothing(tangents) paths[i] = Path(p1, p2; tangents, tfactor) From ede8d71841f53566fbf4715f3eb987be81d58b42 Mon Sep 17 00:00:00 2001 From: hdavid16 Date: Tue, 24 Jan 2023 12:21:30 -0500 Subject: [PATCH 05/10] fix control flow --- src/recipes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/recipes.jl b/src/recipes.jl index 13bd4bb8..c7dafbf8 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -392,7 +392,7 @@ function find_edge_paths(g, attr, pos::AbstractVector{PT}) where {PT} end if !isnothing(waypoints) && !isempty(waypoints) #there are waypoints - if isempty(waypoints) || radius === nothing || radius === :spline + if radius === nothing || radius === :spline paths[i] = Path(p1, waypoints..., p2; tangents, tfactor) elseif radius isa Real paths[i] = Path(radius, p1, waypoints..., p2) From 1933dd4032d9354dbfa13de102cb46ee5c188681 Mon Sep 17 00:00:00 2001 From: hdavid16 Date: Tue, 24 Jan 2023 12:52:51 -0500 Subject: [PATCH 06/10] add reftest image --- assets/reftests.jl-13.png | Bin 0 -> 17469 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/reftests.jl-13.png diff --git a/assets/reftests.jl-13.png b/assets/reftests.jl-13.png new file mode 100644 index 0000000000000000000000000000000000000000..87e2914e6f90d3ea3b1b90131d77ab611d3c442d GIT binary patch literal 17469 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 Date: Tue, 24 Jan 2023 13:13:57 -0500 Subject: [PATCH 07/10] update ref img --- assets/reftests.jl-13.png | Bin 17469 -> 17474 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/reftests.jl-13.png b/assets/reftests.jl-13.png index 87e2914e6f90d3ea3b1b90131d77ab611d3c442d..a54ae1e62c965977a409ff2c3f9836d66f6bfa30 100644 GIT binary patch literal 17474 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 R{4ox~!TpB1g*x_O{|lG^vn2ok literal 17469 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 Date: Tue, 24 Jan 2023 13:58:46 -0500 Subject: [PATCH 08/10] move attr into each section --- src/recipes.jl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/recipes.jl b/src/recipes.jl index c7dafbf8..34ecf2a1 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -365,14 +365,9 @@ function find_edge_paths(g, attr, pos::AbstractVector{PT}) where {PT} for (i, e) in enumerate(edges(g)) p1, p2 = pos[src(e)], pos[dst(e)] - size = getattr(attr.selfedge_size, i) - direction = getattr(attr.selfedge_direction, i) - width = getattr(attr.selfedge_width, i) tangents = getattr(attr.tangents, i) tfactor = getattr(attr.tfactor, i) waypoints::Vector{PT} = getattr(attr.waypoints, i, PT[]) - radius = getattr(attr.waypoint_radius, i, nothing) - if !isnothing(waypoints) && !isempty(waypoints) #remove p1 and p2 from waypoints if these are given waypoints[begin] == p1 && popfirst!(waypoints) waypoints[end] == p2 && pop!(waypoints) @@ -392,6 +387,7 @@ function find_edge_paths(g, attr, pos::AbstractVector{PT}) where {PT} end if !isnothing(waypoints) && !isempty(waypoints) #there are waypoints + radius = getattr(attr.waypoint_radius, i, nothing) if radius === nothing || radius === :spline paths[i] = Path(p1, waypoints..., p2; tangents, tfactor) elseif radius isa Real @@ -400,6 +396,9 @@ function find_edge_paths(g, attr, pos::AbstractVector{PT}) where {PT} throw(ArgumentError("Invalid radius $radius for edge $i!")) end elseif src(e) == dst(e) # selfedge + size = getattr(attr.selfedge_size, i) + direction = getattr(attr.selfedge_direction, i) + width = getattr(attr.selfedge_width, i) paths[i] = selfedge_path(g, pos, src(e), size, direction, width) elseif !isnothing(tangents) paths[i] = Path(p1, p2; tangents, tfactor) From 47898191c4a4e894fe353fdfd8d7e4582cb54159 Mon Sep 17 00:00:00 2001 From: hdavid16 Date: Tue, 24 Jan 2023 14:08:02 -0500 Subject: [PATCH 09/10] wrap cuved_distance code into new func curved_path --- src/recipes.jl | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/recipes.jl b/src/recipes.jl index 34ecf2a1..bc9cfca1 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -403,17 +403,7 @@ function find_edge_paths(g, attr, pos::AbstractVector{PT}) where {PT} elseif !isnothing(tangents) paths[i] = Path(p1, p2; tangents, tfactor) elseif PT<:Point2 && !iszero(curve_distance) - d = curve_distance - s = norm(p2 - p1) - γ = 2*atan(2 * d/s) - a = (p2 - p1)/s * (4*d^2 + s^2)/(3s) - - m = @SMatrix[cos(γ) -sin(γ); sin(γ) cos(γ)] - c1 = PT(p1 + m*a) - c2 = PT(p2 - transpose(m)*a) - - commands = [MoveTo(p1), CurveTo(c1, c2, p2)] - paths[i] = BezierPath(commands) + paths[i] = curved_path(p1, p2, curve_distance) else # straight line paths[i] = Path(p1, p2) end @@ -467,7 +457,7 @@ end """ selfedge_path(g, pos, v, size, direction, width) -Return a Path for the +Return a BezierPath for a selfedge. """ function selfedge_path(g, pos::AbstractVector{<:Point2}, v, size, direction, width) vp = pos[v] @@ -524,6 +514,24 @@ function selfedge_path(g, pos::AbstractVector{<:Point3}, v, size, direction, wid error("Self edges in 3D not yet supported") end +""" + curved_path(p1, p2, curve_distance) + +Return a BezierPath for a curved edge (not selfedge). +""" +function curved_path(p1, p2, curve_distance) + d = curve_distance + s = norm(p2 - p1) + γ = 2*atan(2 * d/s) + a = (p2 - p1)/s * (4*d^2 + s^2)/(3s) + + m = @SMatrix[cos(γ) -sin(γ); sin(γ) cos(γ)] + c1 = PT(p1 + m*a) + c2 = PT(p2 - transpose(m)*a) + + return BezierPath([MoveTo(p1), CurveTo(c1, c2, p2)]) +end + """ edgeplot(paths::Vector{AbstractPath}) edgeplot!(sc, paths::Vector{AbstractPath}) From 7520d5f3565f04206bb48d00925f414d839a386c Mon Sep 17 00:00:00 2001 From: hdavid16 Date: Tue, 24 Jan 2023 14:25:31 -0500 Subject: [PATCH 10/10] fix bug in curved_path --- src/recipes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/recipes.jl b/src/recipes.jl index bc9cfca1..29a54dce 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -519,7 +519,7 @@ end Return a BezierPath for a curved edge (not selfedge). """ -function curved_path(p1, p2, curve_distance) +function curved_path(p1::PT, p2::PT, curve_distance) where {PT} d = curve_distance s = norm(p2 - p1) γ = 2*atan(2 * d/s)