Merge pull request #649 from gavin-ts/fix-arrowhead-rendering

dagre: fix arrowhead rendering
This commit is contained in:
gavin-ts 2023-01-12 11:28:32 -08:00 committed by GitHub
commit 85d25a46a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 998 additions and 99 deletions

View file

@ -8,3 +8,5 @@
- Code snippets of unrecognized languages will render (just without syntax highlighting). [#650](https://github.com/terrastruct/d2/pull/650)
#### Bugfixes ⛑️
- Fixes arrowheads sometimes appearing broken in dagre layouts. [#649](https://github.com/terrastruct/d2/pull/649)

View file

@ -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)
@ -263,18 +306,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 != "" {

View file

@ -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
}
`,
},
}

View file

@ -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,
"y": 287.5
},
{
"x": 120,
"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": 287.5
},
{
"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": 465,
"y": 287.5
},
{
"x": 465,
"y": 359.5
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
}
]
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 794 KiB

View file

@ -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
}
]
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 795 KiB

View file

@ -822,20 +822,11 @@
"x": 925,
"y": 745.597137014315
},
{
"x": 847.4,
"y": 758.3971370143149
},
{
"x": 905.6,
"y": 748.797137014315
},
{
"x": 828,
"y": 761.597137014315
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
@ -978,20 +969,11 @@
"x": 912,
"y": 522
},
{
"x": 845,
"y": 533.8777110844337
},
{
"x": 895.25,
"y": 524.9694277711085
},
{
"x": 828.25,
"y": 536.8471388555422
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 812 KiB

After

Width:  |  Height:  |  Size: 812 KiB

View file

@ -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,

View file

@ -39,7 +39,7 @@ width="698" height="630" viewBox="-102 -102 698 630"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16);
}
});
]]></script><g id="a"><g class="shape" ><rect x="0" y="0" width="494" height="426" style="fill:#E3E9FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="247.000000" y="33.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">a</text></g><g id="a.b"><g class="shape" ><rect x="40" y="50" width="414" height="326" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="247.000000" y="79.000000" style="text-anchor:middle;font-size:24px;fill:#0A0F25">b</text></g><g id="a.b.c"><g class="shape" ><rect x="80" y="100" width="334" height="226" style="fill:#F7F8FE;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="247.000000" y="125.000000" style="text-anchor:middle;font-size:20px;fill:#0A0F25">c</text></g><g id="a.b.c.d"><g class="shape" ><rect x="130" y="150" width="114" height="126" style="fill:#FFFFFF;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text-bold" x="187.000000" y="216.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">d</text></g><g id="(a.b -&gt; a)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 245.640452 172.103153 C 270.666667 154.649446 279.000000 150.000000 281.500000 150.000000 C 284.000000 150.000000 287.333333 162.600000 289.833333 181.500000 C 292.333333 200.400000 292.333333 225.600000 289.833333 244.500000 C 287.333333 263.400000 270.666667 271.350554 247.280904 255.040926" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3168013246)"/></g><g id="a.(b -&gt; b.c)[0]"><path d="M 245.760942 181.359493 C 292.000000 156.461538 307.000000 150.000000 311.500000 150.000000 C 316.000000 150.000000 322.000000 162.600000 326.500000 181.500000 C 331.000000 200.400000 331.000000 225.600000 326.500000 244.500000 C 322.000000 263.400000 292.000000 269.538462 247.521884 245.588707" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3168013246)"/></g><g id="a.(b.c.d -&gt; b)[0]"><path d="M 245.666473 237.972160 C 243.933333 237.996288 243.733333 237.999072 240.000388 238.051039" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3168013246)"/></g><mask id="3168013246" maskUnits="userSpaceOnUse" x="-100" y="-100" width="698" height="630">
]]></script><g id="a"><g class="shape" ><rect x="0" y="0" width="494" height="426" style="fill:#E3E9FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="247.000000" y="33.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">a</text></g><g id="a.b"><g class="shape" ><rect x="40" y="50" width="414" height="326" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="247.000000" y="79.000000" style="text-anchor:middle;font-size:24px;fill:#0A0F25">b</text></g><g id="a.b.c"><g class="shape" ><rect x="80" y="100" width="334" height="226" style="fill:#F7F8FE;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="247.000000" y="125.000000" style="text-anchor:middle;font-size:20px;fill:#0A0F25">c</text></g><g id="a.b.c.d"><g class="shape" ><rect x="130" y="150" width="114" height="126" style="fill:#FFFFFF;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text-bold" x="187.000000" y="216.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">d</text></g><g id="(a.b -&gt; a)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 245.640452 172.103153 C 270.666667 154.649446 279.000000 150.000000 281.500000 150.000000 C 284.000000 150.000000 287.333333 162.600000 289.833333 181.500000 C 292.333333 200.400000 292.333333 225.600000 289.833333 244.500000 C 287.333333 263.400000 270.666667 271.350554 247.280904 255.040926" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#4293364358)"/></g><g id="a.(b -&gt; b.c)[0]"><path d="M 245.760942 181.359493 C 292.000000 156.461538 307.000000 150.000000 311.500000 150.000000 C 316.000000 150.000000 322.000000 162.600000 326.500000 181.500000 C 331.000000 200.400000 331.000000 225.600000 326.500000 244.500000 C 322.000000 263.400000 292.000000 269.538462 247.521884 245.588707" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#4293364358)"/></g><g id="a.(b.c.d -&gt; b)[0]"><path d="M 245.666473 237.972160 L 240.000388 238.051039" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#4293364358)"/></g><mask id="4293364358" maskUnits="userSpaceOnUse" x="-100" y="-100" width="698" height="630">
<rect x="-100" y="-100" width="698" height="630" fill="white"></rect>
</mask><style type="text/css"><![CDATA[

Before

Width:  |  Height:  |  Size: 650 KiB

After

Width:  |  Height:  |  Size: 650 KiB

View file

@ -605,20 +605,11 @@
"x": 332.5,
"y": 598
},
{
"x": 268.5,
"y": 621.2
},
{
"x": 316.5,
"y": 603.8
},
{
"x": 252.5,
"y": 627
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,

View file

@ -39,7 +39,7 @@ width="790" height="1534" viewBox="-102 -102 790 1534"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16);
}
});
]]></script><g id="a"><g class="shape" ><rect x="416" y="0" width="113" height="126" style="fill:#F7F8FE;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text-bold" x="472.500000" y="66.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="g"><g class="shape" ><rect x="333" y="226" width="253" height="878" style="fill:#E3E9FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="459.500000" y="259.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">g</text></g><g id="d"><g class="shape" ><rect x="0" y="502" width="293" height="326" style="fill:#E3E9FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="146.500000" y="535.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">d</text></g><g id="f"><g class="shape" ><rect x="404" y="1204" width="111" height="126" style="fill:#F7F8FE;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text-bold" x="459.500000" y="1270.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">f</text></g><g id="g.b"><g class="shape" ><rect x="416" y="276" width="113" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text-bold" x="472.500000" y="342.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="d.h"><g class="shape" ><rect x="40" y="552" width="213" height="226" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="146.500000" y="581.000000" style="text-anchor:middle;font-size:24px;fill:#0A0F25">h</text></g><g id="g.e"><g class="shape" ><rect x="383" y="928" width="113" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text-bold" x="439.500000" y="994.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">e</text></g><g id="d.h.c"><g class="shape" ><rect x="90" y="602" width="113" height="126" style="fill:#F7F8FE;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text-bold" x="146.500000" y="668.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">c</text></g><g id="(a -&gt; g.b)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 472.750000 128.000000 C 472.750000 166.000000 472.750000 236.000000 472.750000 272.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3377918310)"/></g><g id="(g.b -&gt; d.h.c)[0]"><path d="M 434.660405 403.723672 C 412.134956 442.000000 406.250000 462.000000 406.250000 477.000000 C 406.250000 492.000000 365.650000 569.600000 206.920003 638.409063" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3377918310)"/></g><g id="(d -&gt; g.e)[0]"><path d="M 148.471500 828.336433 C 380.900000 868.000000 439.500000 888.000000 439.500000 924.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3377918310)"/></g><g id="(g.e -&gt; f)[0]"><path d="M 439.500000 1056.000000 C 439.500000 1094.000000 441.300000 1164.000000 447.791388 1200.063267" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3377918310)"/></g><g id="(f -&gt; g)[0]"><path d="M 508.941346 1202.411883 C 538.345133 1164.000000 546.000000 1144.000000 546.000000 1108.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3377918310)"/></g><g id="(g -&gt; d.h)[0]"><path d="M 330.619728 598.681599 C 268.500000 621.200000 316.500000 603.800000 256.260544 625.636803" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3377918310)"/></g><mask id="3377918310" maskUnits="userSpaceOnUse" x="-100" y="-100" width="790" height="1534">
]]></script><g id="a"><g class="shape" ><rect x="416" y="0" width="113" height="126" style="fill:#F7F8FE;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text-bold" x="472.500000" y="66.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="g"><g class="shape" ><rect x="333" y="226" width="253" height="878" style="fill:#E3E9FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="459.500000" y="259.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">g</text></g><g id="d"><g class="shape" ><rect x="0" y="502" width="293" height="326" style="fill:#E3E9FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="146.500000" y="535.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">d</text></g><g id="f"><g class="shape" ><rect x="404" y="1204" width="111" height="126" style="fill:#F7F8FE;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text-bold" x="459.500000" y="1270.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">f</text></g><g id="g.b"><g class="shape" ><rect x="416" y="276" width="113" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text-bold" x="472.500000" y="342.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="d.h"><g class="shape" ><rect x="40" y="552" width="213" height="226" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="146.500000" y="581.000000" style="text-anchor:middle;font-size:24px;fill:#0A0F25">h</text></g><g id="g.e"><g class="shape" ><rect x="383" y="928" width="113" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text-bold" x="439.500000" y="994.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">e</text></g><g id="d.h.c"><g class="shape" ><rect x="90" y="602" width="113" height="126" style="fill:#F7F8FE;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text-bold" x="146.500000" y="668.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">c</text></g><g id="(a -&gt; g.b)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 472.750000 128.000000 C 472.750000 166.000000 472.750000 236.000000 472.750000 272.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3062149661)"/></g><g id="(g.b -&gt; d.h.c)[0]"><path d="M 434.660405 403.723672 C 412.134956 442.000000 406.250000 462.000000 406.250000 477.000000 C 406.250000 492.000000 365.650000 569.600000 206.920003 638.409063" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3062149661)"/></g><g id="(d -&gt; g.e)[0]"><path d="M 148.471500 828.336433 C 380.900000 868.000000 439.500000 888.000000 439.500000 924.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3062149661)"/></g><g id="(g.e -&gt; f)[0]"><path d="M 439.500000 1056.000000 C 439.500000 1094.000000 441.300000 1164.000000 447.791388 1200.063267" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3062149661)"/></g><g id="(f -&gt; g)[0]"><path d="M 508.941346 1202.411883 C 538.345133 1164.000000 546.000000 1144.000000 546.000000 1108.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3062149661)"/></g><g id="(g -&gt; d.h)[0]"><path d="M 330.619728 598.681599 L 256.260544 625.636803" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3062149661)"/></g><mask id="3062149661" maskUnits="userSpaceOnUse" x="-100" y="-100" width="790" height="1534">
<rect x="-100" y="-100" width="790" height="1534" fill="white"></rect>
</mask><style type="text/css"><![CDATA[

Before

Width:  |  Height:  |  Size: 652 KiB

After

Width:  |  Height:  |  Size: 652 KiB

View file

@ -1393,20 +1393,11 @@
"x": 213,
"y": 488
},
{
"x": 173,
"y": 511.2
},
{
"x": 203,
"y": 493.8
},
{
"x": 163,
"y": 517
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
@ -1537,20 +1528,11 @@
"x": 679,
"y": 511
},
{
"x": 887,
"y": 544.6
},
{
"x": 731,
"y": 519.4
},
{
"x": 939,
"y": 553
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 659 KiB

After

Width:  |  Height:  |  Size: 659 KiB

View file

@ -633,20 +633,11 @@
"x": 113,
"y": 139.60208333333333
},
{
"x": 153,
"y": 158.80208333333331
},
{
"x": 123,
"y": 144.40208333333334
},
{
"x": 163,
"y": 163.60208333333333
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
@ -681,20 +672,11 @@
"x": 657,
"y": 583
},
{
"x": 697.6,
"y": 594.9524382097528
},
{
"x": 667.15,
"y": 585.9881095524382
},
{
"x": 707.75,
"y": 597.940547762191
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
@ -873,20 +855,11 @@
"x": 443,
"y": 555
},
{
"x": 483.6,
"y": 577.4938826466916
},
{
"x": 453.15,
"y": 560.6234706616729
},
{
"x": 493.75,
"y": 583.1173533083645
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 655 KiB

After

Width:  |  Height:  |  Size: 655 KiB

View file

@ -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}
}

View file

@ -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)

View file

@ -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)
}