From e9bc363be474a0d79eb315db83f0694585c99edb Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Wed, 28 Dec 2022 12:10:11 -0800 Subject: [PATCH 1/6] add dagre_broken_arrowhead regression test --- e2etests/regression_test.go | 20 + .../dagre/board.exp.json | 392 ++++++++++++++++++ .../dagre/sketch.exp.svg | 66 +++ .../dagre_broken_arrowhead/elk/board.exp.json | 381 +++++++++++++++++ .../dagre_broken_arrowhead/elk/sketch.exp.svg | 66 +++ 5 files changed, 925 insertions(+) create mode 100644 e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json create mode 100644 e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg create mode 100644 e2etests/testdata/regression/dagre_broken_arrowhead/elk/board.exp.json create mode 100644 e2etests/testdata/regression/dagre_broken_arrowhead/elk/sketch.exp.svg diff --git a/e2etests/regression_test.go b/e2etests/regression_test.go index 90d250fa4..2943852d9 100644 --- a/e2etests/regression_test.go +++ b/e2etests/regression_test.go @@ -309,6 +309,26 @@ k8s -> osvc: vault script: `x: |d2 x -> y | +`, + }, + { + name: "dagre_broken_arrowhead", + script: ` +a.b -> a.c: "line 1\nline 2\nline 3\nline 4" { + style: { + font-color: red + stroke: red + } + target-arrowhead: { + shape: diamond + } +} +a.1 -> a.c +a.2 <-> a.c +a.c { + style.stroke: white + d +} `, }, } diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json new file mode 100644 index 000000000..f6d941eba --- /dev/null +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json @@ -0,0 +1,392 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 571, + "height": 648, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#E3E9FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 17, + "labelHeight": 41, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "a.c", + "type": "", + "pos": { + "x": 40, + "y": 359 + }, + "width": 478, + "height": 235, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "white", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "c", + "fontSize": 24, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 15, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.c.d", + "type": "", + "pos": { + "x": 236, + "y": 413 + }, + "width": 114, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "d", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 14, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "a.b", + "type": "", + "pos": { + "x": 64, + "y": 55 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.1", + "type": "", + "pos": { + "x": 237, + "y": 55 + }, + "width": 112, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "1", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 12, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.2", + "type": "", + "pos": { + "x": 409, + "y": 55 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "2", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + } + ], + "connections": [ + { + "id": "a.(b -> c)[0]", + "src": "a.b", + "srcArrow": "none", + "srcLabel": "", + "dst": "a.c", + "dstArrow": "diamond", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "red", + "label": "line 1\nline 2\nline 3\nline 4", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "red", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 36, + "labelHeight": 69, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 120, + "y": 181.5 + }, + { + "x": 120, + "y": 251.9 + }, + { + "x": 120.2, + "y": 358.7 + }, + { + "x": 121, + "y": 359.5 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "a.(1 -> c)[0]", + "src": "a.1", + "srcArrow": "none", + "srcLabel": "", + "dst": "a.c", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 292.5, + "y": 181.5 + }, + { + "x": 292.5, + "y": 251.9 + }, + { + "x": 292.5, + "y": 358.7 + }, + { + "x": 292.5, + "y": 359.5 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "a.(2 <-> c)[0]", + "src": "a.2", + "srcArrow": "triangle", + "srcLabel": "", + "dst": "a.c", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 465, + "y": 181.5 + }, + { + "x": 465, + "y": 251.9 + }, + { + "x": 464.8, + "y": 358.7 + }, + { + "x": 464, + "y": 359.5 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg new file mode 100644 index 000000000..5cc5284f5 --- /dev/null +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg @@ -0,0 +1,66 @@ + +acb12d line 1line 2line 3line 4 + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/elk/board.exp.json b/e2etests/testdata/regression/dagre_broken_arrowhead/elk/board.exp.json new file mode 100644 index 000000000..7c00e2724 --- /dev/null +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/elk/board.exp.json @@ -0,0 +1,381 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "", + "pos": { + "x": 12, + "y": 12 + }, + "width": 490, + "height": 878, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#E3E9FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 17, + "labelHeight": 41, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "a.c", + "type": "", + "pos": { + "x": 106, + "y": 539 + }, + "width": 264, + "height": 276, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "white", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "c", + "fontSize": 24, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 15, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.c.d", + "type": "", + "pos": { + "x": 181, + "y": 614 + }, + "width": 114, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "d", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 14, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "a.b", + "type": "", + "pos": { + "x": 87, + "y": 87 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.1", + "type": "", + "pos": { + "x": 182, + "y": 313 + }, + "width": 112, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "1", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 12, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.2", + "type": "", + "pos": { + "x": 314, + "y": 313 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "2", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + } + ], + "connections": [ + { + "id": "a.(b -> c)[0]", + "src": "a.b", + "srcArrow": "none", + "srcLabel": "", + "dst": "a.c", + "dstArrow": "diamond", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "red", + "label": "line 1\nline 2\nline 3\nline 4", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "red", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 36, + "labelHeight": 69, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 143.5, + "y": 213 + }, + { + "x": 143.5, + "y": 489 + }, + { + "x": 172.5, + "y": 489 + }, + { + "x": 172.5, + "y": 539 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "a.(1 -> c)[0]", + "src": "a.1", + "srcArrow": "none", + "srcLabel": "", + "dst": "a.c", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 238.5, + "y": 439 + }, + { + "x": 238.5, + "y": 539 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "a.(2 <-> c)[0]", + "src": "a.2", + "srcArrow": "triangle", + "srcLabel": "", + "dst": "a.c", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 371, + "y": 439 + }, + { + "x": 371, + "y": 489 + }, + { + "x": 304.5, + "y": 489 + }, + { + "x": 304.5, + "y": 539 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/elk/sketch.exp.svg b/e2etests/testdata/regression/dagre_broken_arrowhead/elk/sketch.exp.svg new file mode 100644 index 000000000..1160dee24 --- /dev/null +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/elk/sketch.exp.svg @@ -0,0 +1,66 @@ + +acb12d line 1line 2line 3line 4 + + + \ No newline at end of file From 25e37fd0c4803102b2e7cc982c463f7203356fcb Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Wed, 11 Jan 2023 15:31:27 -0800 Subject: [PATCH 2/6] handle straight line --- d2layouts/d2dagrelayout/layout.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go index 0d5c5d569..34b87fcd6 100644 --- a/d2layouts/d2dagrelayout/layout.go +++ b/d2layouts/d2dagrelayout/layout.go @@ -263,18 +263,20 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err path := make([]*geo.Point, 0) path = append(path, points[0]) - path = append(path, points[0].AddVector(vectors[0].Multiply(.8))) - for i := 1; i < len(vectors)-2; i++ { - p := points[i] - v := vectors[i] - path = append(path, p.AddVector(v.Multiply(.2))) - path = append(path, p.AddVector(v.Multiply(.5))) - path = append(path, p.AddVector(v.Multiply(.8))) + if len(vectors) > 1 { + path = append(path, points[0].AddVector(vectors[0].Multiply(.8))) + for i := 1; i < len(vectors)-2; i++ { + p := points[i] + v := vectors[i] + path = append(path, p.AddVector(v.Multiply(.2))) + path = append(path, p.AddVector(v.Multiply(.5))) + path = append(path, p.AddVector(v.Multiply(.8))) + } + path = append(path, points[len(points)-2].AddVector(vectors[len(vectors)-1].Multiply(.2))) + edge.IsCurve = true } - path = append(path, points[len(points)-2].AddVector(vectors[len(vectors)-1].Multiply(.2))) path = append(path, points[len(points)-1]) - edge.IsCurve = true edge.Route = path // compile needs to assign edge label positions if edge.Attributes.Label.Value != "" { From 54f34d72ad92a4f8c7a4d9772536eb61660b1af8 Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Wed, 11 Jan 2023 20:21:47 -0800 Subject: [PATCH 3/6] extend previous segment to target if last segment is very short --- d2layouts/d2dagrelayout/layout.go | 43 +++++++++++++++++++++++++++++++ lib/geo/point.go | 6 ++--- lib/geo/point_test.go | 2 +- lib/geo/segment.go | 8 ++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go index 34b87fcd6..7ac2a44e4 100644 --- a/d2layouts/d2dagrelayout/layout.go +++ b/d2layouts/d2dagrelayout/layout.go @@ -30,6 +30,8 @@ var setupJS string //go:embed dagre.js var dagreJS string +const MIN_SEGMENT_LEN = 10 + type ConfigurableOpts struct { NodeSep int `json:"nodesep"` EdgeSep int `json:"edgesep"` @@ -247,6 +249,47 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err } } + // arrowheads can appear broken if segments are very short from dagre routing a point just outside the shape + // to fix this, we try extending the previous segment into the shape instead of having a very short segment + if !start.Equals(points[0]) && startIndex+2 < len(points) { + newStartingSegment := *geo.NewSegment(start, points[startIndex+1]) + if newStartingSegment.Length() < MIN_SEGMENT_LEN { + // we don't want a very short segment right next to the source because it will mess up the arrowhead + // instead we want to extend the next segment into the shape border if possible + nextStart := points[startIndex+1] + nextEnd := points[startIndex+2] + + // Note: in other direction to extend towards source + nextSegment := *geo.NewSegment(nextStart, nextEnd) + v := nextSegment.ToVector() + extendedStart := nextEnd.ToVector().Add(v.AddLength(MIN_SEGMENT_LEN)).ToPoint() + extended := *geo.NewSegment(nextEnd, extendedStart) + + if intersections := edge.Src.Box.Intersections(extended); len(intersections) > 0 { + start = intersections[0] + startIndex += 1 + } + } + } + if !end.Equals(points[len(points)-1]) && endIndex-2 >= 0 { + newEndingSegment := *geo.NewSegment(end, points[endIndex-1]) + if newEndingSegment.Length() < MIN_SEGMENT_LEN { + // extend the prev segment into the shape border if possible + prevStart := points[endIndex-2] + prevEnd := points[endIndex-1] + + prevSegment := *geo.NewSegment(prevStart, prevEnd) + v := prevSegment.ToVector() + extendedEnd := prevStart.ToVector().Add(v.AddLength(MIN_SEGMENT_LEN)).ToPoint() + extended := *geo.NewSegment(prevStart, extendedEnd) + + if intersections := edge.Dst.Box.Intersections(extended); len(intersections) > 0 { + end = intersections[0] + endIndex -= 1 + } + } + } + srcShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Src.Attributes.Shape.Value)], edge.Src.Box) dstShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Dst.Attributes.Shape.Value)], edge.Dst.Box) diff --git a/lib/geo/point.go b/lib/geo/point.go index 13275db79..0acc5021b 100644 --- a/lib/geo/point.go +++ b/lib/geo/point.go @@ -187,12 +187,12 @@ func (p *Point) DistanceToLine(p1, p2 *Point) float64 { // Moves the given point by Vector func (start *Point) AddVector(v Vector) *Point { - return start.toVector().Add(v).ToPoint() + return start.ToVector().Add(v).ToPoint() } // Creates a Vector of the size between start and endpoint, pointing to endpoint func (start *Point) VectorTo(endpoint *Point) Vector { - return endpoint.toVector().Minus(start.toVector()) + return endpoint.ToVector().Minus(start.ToVector()) } func (p *Point) FormattedCoordinates() string { @@ -205,7 +205,7 @@ func (q *Point) OnSegment(p, r *Point) bool { } // Creates a Vector pointing to point -func (endpoint *Point) toVector() Vector { +func (endpoint *Point) ToVector() Vector { return []float64{endpoint.X, endpoint.Y} } diff --git a/lib/geo/point_test.go b/lib/geo/point_test.go index 259975897..343f8bb30 100644 --- a/lib/geo/point_test.go +++ b/lib/geo/point_test.go @@ -29,7 +29,7 @@ func TestAddVector(t *testing.T) { func TestToVector(t *testing.T) { p := &Point{3.5, 6.7} - v := p.toVector() + v := p.ToVector() if v[0] != p.X || v[1] != p.Y { t.Fatalf("Expected Vector (%v) coordinates to match the point (%v)", p, v) diff --git a/lib/geo/segment.go b/lib/geo/segment.go index 473cb12e8..df6f64a5c 100644 --- a/lib/geo/segment.go +++ b/lib/geo/segment.go @@ -114,3 +114,11 @@ func (segment *Segment) GetBounds(segments []*Segment, buffer float64) (float64, } return floor, ceil } + +func (segment Segment) Length() float64 { + return EuclideanDistance(segment.Start.X, segment.Start.Y, segment.End.X, segment.End.Y) +} + +func (segment Segment) ToVector() Vector { + return NewVector(segment.End.X-segment.Start.X, segment.End.Y-segment.Start.Y) +} From d59fa7fd0b68ed3c370ea38c6806ef8f479b7f4a Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Wed, 11 Jan 2023 20:26:50 -0800 Subject: [PATCH 4/6] update test --- .../dagre_broken_arrowhead/dagre/board.exp.json | 14 +++++++------- .../dagre_broken_arrowhead/dagre/sketch.exp.svg | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json index f6d941eba..5a05fac5f 100644 --- a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json @@ -278,11 +278,11 @@ "y": 251.9 }, { - "x": 120.2, - "y": 358.7 + "x": 120, + "y": 287.5 }, { - "x": 121, + "x": 120, "y": 359.5 } ], @@ -327,7 +327,7 @@ }, { "x": 292.5, - "y": 358.7 + "y": 287.5 }, { "x": 292.5, @@ -374,11 +374,11 @@ "y": 251.9 }, { - "x": 464.8, - "y": 358.7 + "x": 465, + "y": 287.5 }, { - "x": 464, + "x": 465, "y": 359.5 } ], diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg index 5cc5284f5..657dbb9f6 100644 --- a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg @@ -39,7 +39,7 @@ width="775" height="852" viewBox="-102 -102 775 852">aabbllmmnnoocciikkddgghhjjeeff1122 334455667788 +aabbllmmnnoocciikkddgghhjjeeff1122 334455667788 diff --git a/e2etests/testdata/stable/child_parent_edges/dagre/board.exp.json b/e2etests/testdata/stable/child_parent_edges/dagre/board.exp.json index d64f023cc..29604db23 100644 --- a/e2etests/testdata/stable/child_parent_edges/dagre/board.exp.json +++ b/e2etests/testdata/stable/child_parent_edges/dagre/board.exp.json @@ -361,20 +361,11 @@ "x": 243.66666666666669, "y": 238 }, - { - "x": 243.93333333333334, - "y": 237.99628770301624 - }, - { - "x": 243.73333333333335, - "y": 237.99907192575407 - }, { "x": 244, "y": 237.9953596287703 } ], - "isCurve": true, "animated": false, "tooltip": "", "icon": null, diff --git a/e2etests/testdata/stable/child_parent_edges/dagre/sketch.exp.svg b/e2etests/testdata/stable/child_parent_edges/dagre/sketch.exp.svg index c157addac..f8a893097 100644 --- a/e2etests/testdata/stable/child_parent_edges/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/child_parent_edges/dagre/sketch.exp.svg @@ -39,7 +39,7 @@ width="698" height="630" viewBox="-102 -102 698 630">