Merge pull request #1033 from alixander/elk-shim

Shim elk: remove bends
This commit is contained in:
Alexander Wang 2023-03-14 19:17:07 -07:00 committed by GitHub
commit 5e5d502fd6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
55 changed files with 4520 additions and 2694 deletions

View file

@ -96,6 +96,7 @@ var DefaultOpts = ConfigurableOpts{
}
var port_spacing = 40.
var edge_node_spacing = 40
type elkOpts struct {
EdgeNode int `json:"elk.spacing.edgeNode,omitempty"`
@ -143,7 +144,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
LayoutOptions: &elkOpts{
Thoroughness: 8,
EdgeEdgeBetweenLayersSpacing: 50,
EdgeNode: 40,
EdgeNode: edge_node_spacing,
HierarchyHandling: "INCLUDE_CHILDREN",
FixedAlignment: "BALANCED",
ConsiderModelOrder: "NODES_AND_EDGES",
@ -224,7 +225,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
EdgeEdgeBetweenLayersSpacing: 50,
HierarchyHandling: "INCLUDE_CHILDREN",
FixedAlignment: "BALANCED",
EdgeNode: 40,
EdgeNode: edge_node_spacing,
ConsiderModelOrder: "NODES_AND_EDGES",
// Why is it (height, width)? I have no clue, but it works.
NodeSizeMinimum: fmt.Sprintf("(%d, %d)", int(math.Ceil(height)), int(math.Ceil(width))),
@ -442,5 +443,270 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
edge.Route = points
}
deleteBends(g)
return nil
}
// deleteBends is a shim for ELK to delete unnecessary bends
// see https://github.com/terrastruct/d2/issues/1030
func deleteBends(g *d2graph.Graph) {
// Get rid of S-shapes at the source and the target
// TODO there might be value in repeating this. removal of an S shape introducing another S shape that can still be removed
for _, isSource := range []bool{true, false} {
for ei, e := range g.Edges {
if len(e.Route) < 4 {
continue
}
if e.Src == e.Dst {
continue
}
var endpoint *d2graph.Object
var start *geo.Point
var corner *geo.Point
var end *geo.Point
if isSource {
start = e.Route[0]
corner = e.Route[1]
end = e.Route[2]
endpoint = e.Src
} else {
start = e.Route[len(e.Route)-1]
corner = e.Route[len(e.Route)-2]
end = e.Route[len(e.Route)-3]
endpoint = e.Dst
}
isHorizontal := math.Ceil(start.Y) == math.Ceil(corner.Y)
// Make sure it's still attached
if isHorizontal {
if end.Y <= endpoint.TopLeft.Y+10 {
continue
}
if end.Y >= endpoint.TopLeft.Y+endpoint.Height-10 {
continue
}
} else {
if end.X <= endpoint.TopLeft.X+10 {
continue
}
if end.X >= endpoint.TopLeft.X+endpoint.Width-10 {
continue
}
}
var newStart *geo.Point
if isHorizontal {
newStart = geo.NewPoint(start.X, end.Y)
} else {
newStart = geo.NewPoint(end.X, start.Y)
}
endpointShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(endpoint.Attributes.Shape.Value)], endpoint.Box)
newStart = shape.TraceToShapeBorder(endpointShape, newStart, end)
// Check that the new segment doesn't collide with anything new
oldSegment := geo.NewSegment(start, corner)
newSegment := geo.NewSegment(newStart, end)
oldIntersects := countObjectIntersects(g, e.Src, e.Dst, *oldSegment)
newIntersects := countObjectIntersects(g, e.Src, e.Dst, *newSegment)
if newIntersects > oldIntersects {
continue
}
oldCrossingsCount, oldOverlapsCount, oldCloseOverlapsCount, oldTouchingCount := countEdgeIntersects(g, g.Edges[ei], *oldSegment)
newCrossingsCount, newOverlapsCount, newCloseOverlapsCount, newTouchingCount := countEdgeIntersects(g, g.Edges[ei], *newSegment)
if newCrossingsCount > oldCrossingsCount {
continue
}
if newOverlapsCount > oldOverlapsCount {
continue
}
if newCloseOverlapsCount > oldCloseOverlapsCount {
continue
}
if newTouchingCount > oldTouchingCount {
continue
}
// commit
if isSource {
g.Edges[ei].Route = append(
[]*geo.Point{newStart},
e.Route[3:]...,
)
} else {
g.Edges[ei].Route = append(
e.Route[:len(e.Route)-3],
newStart,
)
}
}
}
// Get rid of ladders
// ELK likes to do these for some reason
// . ┌─
// . ┌─┘
// . │
// We want to transform these into L-shapes
for ei, e := range g.Edges {
if len(e.Route) < 6 {
continue
}
if e.Src == e.Dst {
continue
}
for i := 1; i < len(e.Route)-3; i++ {
before := e.Route[i-1]
start := e.Route[i]
corner := e.Route[i+1]
end := e.Route[i+2]
after := e.Route[i+3]
// S-shape on sources only concerned one segment, since the other was just along the bound of endpoint
// These concern two segments
var newCorner *geo.Point
if math.Ceil(start.X) == math.Ceil(corner.X) {
newCorner = geo.NewPoint(end.X, start.Y)
// not ladder
if (end.X > start.X) != (start.X > before.X) {
continue
}
if (end.Y > start.Y) != (after.Y > end.Y) {
continue
}
} else {
newCorner = geo.NewPoint(start.X, end.Y)
if (end.Y > start.Y) != (start.Y > before.Y) {
continue
}
if (end.X > start.X) != (after.X > end.X) {
continue
}
}
oldS1 := geo.NewSegment(start, corner)
oldS2 := geo.NewSegment(corner, end)
newS1 := geo.NewSegment(start, newCorner)
newS2 := geo.NewSegment(newCorner, end)
// Check that the new segments doesn't collide with anything new
oldIntersects := countObjectIntersects(g, e.Src, e.Dst, *oldS1) + countObjectIntersects(g, e.Src, e.Dst, *oldS2)
newIntersects := countObjectIntersects(g, e.Src, e.Dst, *newS1) + countObjectIntersects(g, e.Src, e.Dst, *newS2)
if newIntersects > oldIntersects {
continue
}
oldCrossingsCount1, oldOverlapsCount1, oldCloseOverlapsCount1, oldTouchingCount1 := countEdgeIntersects(g, g.Edges[ei], *oldS1)
oldCrossingsCount2, oldOverlapsCount2, oldCloseOverlapsCount2, oldTouchingCount2 := countEdgeIntersects(g, g.Edges[ei], *oldS2)
oldCrossingsCount := oldCrossingsCount1 + oldCrossingsCount2
oldOverlapsCount := oldOverlapsCount1 + oldOverlapsCount2
oldCloseOverlapsCount := oldCloseOverlapsCount1 + oldCloseOverlapsCount2
oldTouchingCount := oldTouchingCount1 + oldTouchingCount2
newCrossingsCount1, newOverlapsCount1, newCloseOverlapsCount1, newTouchingCount1 := countEdgeIntersects(g, g.Edges[ei], *newS1)
newCrossingsCount2, newOverlapsCount2, newCloseOverlapsCount2, newTouchingCount2 := countEdgeIntersects(g, g.Edges[ei], *newS2)
newCrossingsCount := newCrossingsCount1 + newCrossingsCount2
newOverlapsCount := newOverlapsCount1 + newOverlapsCount2
newCloseOverlapsCount := newCloseOverlapsCount1 + newCloseOverlapsCount2
newTouchingCount := newTouchingCount1 + newTouchingCount2
if newCrossingsCount > oldCrossingsCount {
continue
}
if newOverlapsCount > oldOverlapsCount {
continue
}
if newCloseOverlapsCount > oldCloseOverlapsCount {
continue
}
if newTouchingCount > oldTouchingCount {
continue
}
// commit
g.Edges[ei].Route = append(append(
e.Route[:i],
newCorner,
),
e.Route[i+3:]...,
)
break
}
}
}
func countObjectIntersects(g *d2graph.Graph, src, dst *d2graph.Object, s geo.Segment) int {
count := 0
for i, o := range g.Objects {
if g.Objects[i] == src || g.Objects[i] == dst {
continue
}
if o.Intersects(s, float64(edge_node_spacing)-1) {
count++
}
}
return count
}
// countEdgeIntersects counts both crossings AND getting too close to a parallel segment
func countEdgeIntersects(g *d2graph.Graph, sEdge *d2graph.Edge, s geo.Segment) (int, int, int, int) {
isHorizontal := math.Ceil(s.Start.Y) == math.Ceil(s.End.Y)
crossingsCount := 0
overlapsCount := 0
closeOverlapsCount := 0
touchingCount := 0
for i, e := range g.Edges {
if g.Edges[i] == sEdge {
continue
}
for i := 0; i < len(e.Route)-1; i++ {
otherS := geo.NewSegment(e.Route[i], e.Route[i+1])
otherIsHorizontal := math.Ceil(otherS.Start.Y) == math.Ceil(otherS.End.Y)
if isHorizontal == otherIsHorizontal {
if s.Overlaps(*otherS, !isHorizontal, 0.) {
if isHorizontal {
if math.Abs(s.Start.Y-otherS.Start.Y) < float64(edge_node_spacing)/2. {
overlapsCount++
if math.Abs(s.Start.Y-otherS.Start.Y) < float64(edge_node_spacing)/4. {
closeOverlapsCount++
if math.Abs(s.Start.Y-otherS.Start.Y) < 1. {
touchingCount++
}
}
}
} else {
if math.Abs(s.Start.X-otherS.Start.X) < float64(edge_node_spacing)/2. {
overlapsCount++
if math.Abs(s.Start.X-otherS.Start.X) < float64(edge_node_spacing)/4. {
closeOverlapsCount++
if math.Abs(s.Start.Y-otherS.Start.Y) < 1. {
touchingCount++
}
}
}
}
}
} else {
if s.Intersects(*otherS) {
crossingsCount++
}
}
}
}
return crossingsCount, overlapsCount, closeOverlapsCount, touchingCount
}

View file

@ -81,6 +81,59 @@ func testStable(t *testing.T) {
}
`,
},
{
name: "elk_shim",
script: `network: {
cell tower: {
satellites: {
shape: stored_data
style.multiple: true
width: 140
}
transmitter: {
width: 140
}
satellites -> transmitter: send {
}
satellites -> transmitter: send {
}
satellites -> transmitter: send {
}
}
online portal: {
ui: { shape: hexagon }
}
data processor: {
storage: {
shape: cylinder
style.multiple: true
}
}
cell tower.transmitter -> data processor.storage: phone logs
}
user: {
shape: person
width: 130
}
user -> network.cell tower: make call
user -> network.online portal.ui: access {
style.stroke-dash: 3
}
api server -> network.online portal.ui: display
api server -> logs: persist
logs: { shape: page; style.multiple: true }
network.data processor -> api server
`,
},
{
name: "mono-font",
script: `satellites: SATELLITES {

View file

@ -1343,14 +1343,6 @@
},
{
"x": 596.5,
"y": 1356
},
{
"x": 585.75,
"y": 1356
},
{
"x": 585.75,
"y": 1506
}
],

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 806 KiB

After

Width:  |  Height:  |  Size: 806 KiB

View file

@ -283,14 +283,6 @@
},
{
"x": 88.5,
"y": 307
},
{
"x": 115,
"y": 307
},
{
"x": 115,
"y": 347
}
],

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 799 KiB

After

Width:  |  Height:  |  Size: 799 KiB

View file

@ -598,17 +598,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 501.75,
"y": 60
},
{
"x": 501.75,
"y": 100
},
{
"x": 520.5,
"y": 100
"y": 60
},
{
"x": 520.5,
@ -646,17 +638,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 636.75,
"y": 60
},
{
"x": 636.75,
"y": 100
},
{
"x": 605.5,
"y": 100
"y": 60
},
{
"x": 605.5,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 668 KiB

After

Width:  |  Height:  |  Size: 668 KiB

View file

@ -441,17 +441,9 @@
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 211,
"y": 178
},
{
"x": 211,
"y": 218
},
{
"x": 274,
"y": 218
"y": 178
},
{
"x": 274,
@ -497,17 +489,9 @@
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 410,
"y": 178
},
{
"x": 410,
"y": 319
},
{
"x": 482.3,
"y": 319
"y": 178
},
{
"x": 482.3,
@ -545,17 +529,9 @@
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 609,
"y": 178
},
{
"x": 609,
"y": 319
},
{
"x": 536.7,
"y": 319
"y": 178
},
{
"x": 536.7,
@ -593,17 +569,9 @@
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 808,
"y": 178
},
{
"x": 808,
"y": 218
},
{
"x": 735.7,
"y": 218
"y": 178
},
{
"x": 735.7,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 801 KiB

After

Width:  |  Height:  |  Size: 800 KiB

View file

@ -1180,17 +1180,9 @@
"x": 243,
"y": 300
},
{
"x": 283,
"y": 300
},
{
"x": 283,
"y": 252
},
{
"x": 468,
"y": 252
"y": 300
},
{
"x": 468,
@ -1292,17 +1284,9 @@
"x": 333,
"y": 262
},
{
"x": 468,
"y": 262
},
{
"x": 468,
"y": 281
},
{
"x": 563,
"y": 281
"y": 262
}
],
"animated": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 663 KiB

After

Width:  |  Height:  |  Size: 663 KiB

View file

@ -671,17 +671,9 @@
"x": 278,
"y": 288.1875
},
{
"x": 612,
"y": 288.1875
},
{
"x": 612,
"y": 299.625
},
{
"x": 652,
"y": 299.625
"y": 288.1875
}
],
"animated": false,
@ -719,17 +711,9 @@
"x": 840,
"y": 127.5
},
{
"x": 880,
"y": 127.5
},
{
"x": 880,
"y": 102
},
{
"x": 970,
"y": 102
"y": 127.5
}
],
"animated": false,
@ -917,14 +901,6 @@
"route": [
{
"x": 1290,
"y": 169.66666666666669
},
{
"x": 1330,
"y": 169.66666666666669
},
{
"x": 1330,
"y": 164.66666666666669
},
{

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 671 KiB

After

Width:  |  Height:  |  Size: 671 KiB

View file

@ -564,17 +564,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 83.83333333333337,
"y": 78
},
{
"x": 83.83333333333337,
"y": 118
},
{
"x": 56.5,
"y": 118
"y": 78
},
{
"x": 56.5,
@ -612,17 +604,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 146.16666666666663,
"y": 78
},
{
"x": 146.16666666666663,
"y": 118
},
{
"x": 186,
"y": 118
"y": 78
},
{
"x": 186,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 480 KiB

After

Width:  |  Height:  |  Size: 480 KiB

View file

@ -395,16 +395,8 @@
"labelPercentage": 0,
"route": [
{
"x": 103,
"y": 258
},
{
"x": 103,
"y": 298
},
{
"x": 134.66666666666669,
"y": 298
"x": 135,
"y": 247
},
{
"x": 135,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 477 KiB

After

Width:  |  Height:  |  Size: 477 KiB

View file

@ -793,14 +793,6 @@
},
{
"x": 443.75,
"y": 567
},
{
"x": 413.5,
"y": 567
},
{
"x": 413.5,
"y": 612
}
],
@ -937,14 +929,6 @@
},
{
"x": 351.75,
"y": 270
},
{
"x": 295.25,
"y": 270
},
{
"x": 295.25,
"y": 612
}
],
@ -985,14 +969,6 @@
},
{
"x": 507.25,
"y": 466
},
{
"x": 494.25,
"y": 466
},
{
"x": 494.25,
"y": 567
},
{
@ -1049,14 +1025,6 @@
},
{
"x": 319.75,
"y": 220
},
{
"x": 221.25,
"y": 220
},
{
"x": 221.25,
"y": 567
},
{

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 817 KiB

After

Width:  |  Height:  |  Size: 816 KiB

View file

@ -154,17 +154,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 43.16666666666667,
"y": 78
},
{
"x": 43.16666666666667,
"y": 168
},
{
"x": 38.66666666666667,
"y": 168
"y": 78
},
{
"x": 38.66666666666667,
@ -208,14 +200,6 @@
},
{
"x": 38.66666666666667,
"y": 364
},
{
"x": 43.16666666666667,
"y": 364
},
{
"x": 43.16666666666667,
"y": 404
}
],
@ -250,17 +234,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 60.833333333333336,
"y": 404
},
{
"x": 60.833333333333336,
"y": 314
},
{
"x": 65.33333333333334,
"y": 314
"y": 404
},
{
"x": 65.33333333333334,
@ -298,17 +274,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 65.33333333333334,
"y": 208
},
{
"x": 65.33333333333334,
"y": 118
},
{
"x": 60.833333333333336,
"y": 118
"y": 208
},
{
"x": 60.833333333333336,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 331 KiB

After

Width:  |  Height:  |  Size: 331 KiB

View file

@ -599,17 +599,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 157.25,
"y": 379
},
{
"x": 157.25,
"y": 424
},
{
"x": 148.5,
"y": 424
"y": 379
},
{
"x": 148.5,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 657 KiB

After

Width:  |  Height:  |  Size: 657 KiB

View file

@ -728,17 +728,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 181.5,
"y": 224
},
{
"x": 181.5,
"y": 264
},
{
"x": 180,
"y": 264
"y": 224
},
{
"x": 180,
@ -776,17 +768,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 108.5,
"y": 224
},
{
"x": 108.5,
"y": 264
},
{
"x": 110,
"y": 264
"y": 224
},
{
"x": 110,
@ -824,17 +808,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 422.75,
"y": 566
},
{
"x": 422.75,
"y": 606
},
{
"x": 421,
"y": 606
"y": 566
},
{
"x": 421,
@ -928,17 +904,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 160,
"y": 370
},
{
"x": 160,
"y": 410
},
{
"x": 146,
"y": 410
"y": 370
},
{
"x": 146,
@ -984,17 +952,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 200,
"y": 370
},
{
"x": 200,
"y": 410
},
{
"x": 214,
"y": 410
"y": 370
},
{
"x": 214,
@ -1654,14 +1614,6 @@
},
{
"x": 392.75,
"y": 606
},
{
"x": 353.41666666666663,
"y": 606
},
{
"x": 353.41666666666663,
"y": 902
},
{
@ -1800,17 +1752,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 603.25,
"y": 566
},
{
"x": 603.25,
"y": 606
},
{
"x": 601.5,
"y": 606
"y": 566
},
{
"x": 601.5,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 342 KiB

After

Width:  |  Height:  |  Size: 341 KiB

1109
e2etests/testdata/stable/elk_shim/dagre/board.exp.json generated vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 806 KiB

892
e2etests/testdata/stable/elk_shim/elk/board.exp.json generated vendored Normal file
View file

@ -0,0 +1,892 @@
{
"name": "",
"isFolderOnly": false,
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "network",
"type": "rectangle",
"pos": {
"x": 12,
"y": 311
},
"width": 540,
"height": 892,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "network",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 96,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "network.cell tower",
"type": "rectangle",
"pos": {
"x": 62,
"y": 361
},
"width": 240,
"height": 403,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "cell tower",
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 99,
"labelHeight": 31,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "network.cell tower.satellites",
"type": "stored_data",
"pos": {
"x": 112,
"y": 411
},
"width": 140,
"height": 61,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "AA5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": true,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "satellites",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 65,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 3
},
{
"id": "network.cell tower.transmitter",
"type": "rectangle",
"pos": {
"x": 112,
"y": 653
},
"width": 140,
"height": 61,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "transmitter",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 83,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 3
},
{
"id": "network.online portal",
"type": "rectangle",
"pos": {
"x": 322,
"y": 366
},
"width": 180,
"height": 169,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "online portal",
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 128,
"labelHeight": 31,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "network.online portal.ui",
"type": "hexagon",
"pos": {
"x": 372,
"y": 416
},
"width": 80,
"height": 69,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "N5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "ui",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 14,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 3
},
{
"id": "network.data processor",
"type": "rectangle",
"pos": {
"x": 82,
"y": 935
},
"width": 199,
"height": 218,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "data processor",
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 150,
"labelHeight": 31,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "network.data processor.storage",
"type": "cylinder",
"pos": {
"x": 132,
"y": 985
},
"width": 99,
"height": 118,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "AA5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": true,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "storage",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 54,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 3
},
{
"id": "user",
"type": "person",
"pos": {
"x": 286,
"y": 12
},
"width": 130,
"height": 87,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B3",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "user",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 32,
"labelHeight": 21,
"labelPosition": "OUTSIDE_BOTTOM_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "api server",
"type": "rectangle",
"pos": {
"x": 534,
"y": 59
},
"width": 116,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "api server",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 71,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "logs",
"type": "page",
"pos": {
"x": 632,
"y": 311
},
"width": 73,
"height": 87,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "AB4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": true,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "logs",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 28,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 1
}
],
"connections": [
{
"id": "network.cell tower.(satellites -> transmitter)[0]",
"src": "network.cell tower.satellites",
"srcArrow": "none",
"srcLabel": "",
"dst": "network.cell tower.transmitter",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "send",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 33,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 138,
"y": 472
},
{
"x": 138,
"y": 653
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "network.cell tower.(satellites -> transmitter)[1]",
"src": "network.cell tower.satellites",
"srcArrow": "none",
"srcLabel": "",
"dst": "network.cell tower.transmitter",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "send",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 33,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 182,
"y": 472
},
{
"x": 182,
"y": 653
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "network.cell tower.(satellites -> transmitter)[2]",
"src": "network.cell tower.satellites",
"srcArrow": "none",
"srcLabel": "",
"dst": "network.cell tower.transmitter",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "send",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 33,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 226,
"y": 472
},
{
"x": 226,
"y": 653
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "network.(cell tower.transmitter -> data processor.storage)[0]",
"src": "network.cell tower.transmitter",
"srcArrow": "none",
"srcLabel": "",
"dst": "network.data processor.storage",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "phone logs",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 74,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 182,
"y": 714
},
{
"x": 182,
"y": 985
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(user -> network.cell tower)[0]",
"src": "user",
"srcArrow": "none",
"srcLabel": "",
"dst": "network.cell tower",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "make call",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 64,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 329,
"y": 99
},
{
"x": 329.33333333333337,
"y": 165
},
{
"x": 222.83333333333334,
"y": 165
},
{
"x": 222.83333333333334,
"y": 361
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(user -> network.online portal.ui)[0]",
"src": "user",
"srcArrow": "none",
"srcLabel": "",
"dst": "network.online portal.ui",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 3,
"strokeWidth": 2,
"stroke": "B2",
"borderRadius": 10,
"label": "access",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 44,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 399,
"y": 99
},
{
"x": 399,
"y": 416
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(api server -> network.online portal.ui)[0]",
"src": "api server",
"srcArrow": "none",
"srcLabel": "",
"dst": "network.online portal.ui",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "display",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 48,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 563,
"y": 125
},
{
"x": 563,
"y": 266
},
{
"x": 425.33333333333337,
"y": 266
},
{
"x": 425,
"y": 416
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(api server -> logs)[0]",
"src": "api server",
"srcArrow": "none",
"srcLabel": "",
"dst": "logs",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "persist",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 46,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 621,
"y": 125
},
{
"x": 621,
"y": 165
},
{
"x": 668.5,
"y": 165
},
{
"x": 669,
"y": 311
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(network.data processor -> api server)[0]",
"src": "network.data processor",
"srcArrow": "none",
"srcLabel": "",
"dst": "api server",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 132.5,
"y": 1153
},
{
"x": 132.5,
"y": 1248
},
{
"x": 592,
"y": 1248
},
{
"x": 592,
"y": 125
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
}
],
"root": {
"id": "",
"type": "",
"pos": {
"x": 0,
"y": 0
},
"width": 0,
"height": 0,
"opacity": 0,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "N7",
"stroke": "",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "",
"fontSize": 0,
"fontFamily": "",
"language": "",
"color": "",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"zIndex": 0,
"level": 0
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 805 KiB

View file

@ -1331,15 +1331,7 @@
"y": 111
},
{
"x": 263.08333333333337,
"y": 153
},
{
"x": 297.16666666666663,
"y": 153
},
{
"x": 297,
"x": 263,
"y": 193
}
],
@ -1566,17 +1558,9 @@
"x": 150.66666666666669,
"y": 873
},
{
"x": 198.16666666666669,
"y": 873
},
{
"x": 198.16666666666666,
"y": 1008
},
{
"x": 235,
"y": 1008
"y": 873
},
{
"x": 235,
@ -1707,16 +1691,8 @@
"y": 1646
},
{
"x": 442.58333333333337,
"y": 1844
},
{
"x": 463.66666666666663,
"y": 1844
},
{
"x": 464,
"y": 1945
"x": 443,
"y": 1950
}
],
"animated": false,
@ -1759,28 +1735,12 @@
"y": 2121
},
{
"x": 361.66666666666663,
"x": 351.66666666666663,
"y": 2121
},
{
"x": 361.66666666666663,
"y": 2322
},
{
"x": 351.66666666666663,
"y": 2322
},
{
"x": 351.66666666666663,
"y": 2423
},
{
"x": 341.66666666666663,
"y": 2423
},
{
"x": 342,
"y": 2518
"x": 352,
"y": 2519
}
],
"animated": false,
@ -2006,17 +1966,9 @@
"x": 235.66666666666669,
"y": 823
},
{
"x": 188.16666666666669,
"y": 823
},
{
"x": 188.16666666666666,
"y": 1008
},
{
"x": 93.49999999999999,
"y": 1008
"y": 823
},
{
"x": 93.5,
@ -2099,15 +2051,7 @@
"y": 1567.6666666666667
},
{
"x": 221.66666666666669,
"y": 1646
},
{
"x": 202.66666666666669,
"y": 1646
},
{
"x": 203,
"x": 222,
"y": 1686
}
],
@ -2236,14 +2180,6 @@
},
{
"x": 139.66666666666666,
"y": 2930
},
{
"x": 148.33333333333334,
"y": 2930
},
{
"x": 148.33333333333334,
"y": 3374
},
{
@ -2286,17 +2222,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 434.16666666666663,
"y": 2735
},
{
"x": 434.16666666666663,
"y": 2830
},
{
"x": 451.8333333333333,
"y": 2830
"y": 2735
},
{
"x": 452,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 815 KiB

After

Width:  |  Height:  |  Size: 814 KiB

View file

@ -1768,17 +1768,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 586.4166666666665,
"y": 1443.625
},
{
"x": 586.4166666666665,
"y": 1578
},
{
"x": 589.9166666666666,
"y": 1578
"y": 1443.625
},
{
"x": 589.9166666666666,
@ -2078,14 +2070,6 @@
},
{
"x": 528,
"y": 966
},
{
"x": 503.08333333333326,
"y": 966
},
{
"x": 503.08333333333326,
"y": 1377.625
}
],
@ -2120,17 +2104,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 225,
"y": 617
},
{
"x": 225,
"y": 966
},
{
"x": 197.5,
"y": 966
"y": 617
},
{
"x": 197.4999999999999,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 668 KiB

After

Width:  |  Height:  |  Size: 667 KiB

View file

@ -280,14 +280,6 @@
},
{
"x": 294.9166666666667,
"y": 103
},
{
"x": 203,
"y": 103
},
{
"x": 203,
"y": 143
}
],

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 511 KiB

After

Width:  |  Height:  |  Size: 511 KiB

View file

@ -114,27 +114,11 @@
"labelPercentage": 0,
"route": [
{
"x": 52,
"x": 44,
"y": 78
},
{
"x": 52.25,
"y": 118
},
{
"x": 44.5,
"y": 118
},
{
"x": 44.5,
"y": 219
},
{
"x": 54.75,
"y": 219
},
{
"x": 54.75,
"y": 259
}
],
@ -210,27 +194,11 @@
"labelPercentage": 0,
"route": [
{
"x": 133,
"x": 140,
"y": 78
},
{
"x": 132.75,
"y": 118
},
{
"x": 140.5,
"y": 118
},
{
"x": 140.5,
"y": 219
},
{
"x": 130.25,
"y": 219
},
{
"x": 130.25,
"y": 259
}
],

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 266 KiB

After

Width:  |  Height:  |  Size: 265 KiB

View file

@ -1628,17 +1628,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 55.33333333333337,
"y": 752
},
{
"x": 55.33333333333337,
"y": 792
},
{
"x": 38.66666666666663,
"y": 792
"y": 752
},
{
"x": 38.66666666666663,
@ -1676,17 +1668,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 88.66666666666663,
"y": 752
},
{
"x": 88.66666666666663,
"y": 842
},
{
"x": 65.33333333333337,
"y": 842
"y": 752
},
{
"x": 65.33333333333337,
@ -1738,14 +1722,6 @@
},
{
"x": 132,
"y": 1134
},
{
"x": 135.33333333333326,
"y": 1134
},
{
"x": 135.33333333333326,
"y": 1174
}
],
@ -1828,17 +1804,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 236.33333333333326,
"y": 948
},
{
"x": 236.33333333333326,
"y": 988
},
{
"x": 233,
"y": 988
"y": 948
},
{
"x": 233,
@ -1924,17 +1892,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 155.33333333333326,
"y": 752
},
{
"x": 155.33333333333326,
"y": 792
},
{
"x": 150.83333333333326,
"y": 792
"y": 752
},
{
"x": 150.83333333333326,
@ -2170,14 +2130,6 @@
},
{
"x": 368.49999999999994,
"y": 646
},
{
"x": 397.33333333333326,
"y": 646
},
{
"x": 397.33333333333326,
"y": 686
}
],

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 346 KiB

After

Width:  |  Height:  |  Size: 345 KiB

View file

@ -359,17 +359,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 88.5,
"y": 128
},
{
"x": 88.5,
"y": 223
},
{
"x": 78.25,
"y": 223
"y": 128
},
{
"x": 78.25,
@ -415,17 +407,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 148.75,
"y": 651
},
{
"x": 148.75,
"y": 691
},
{
"x": 142.5,
"y": 691
"y": 651
},
{
"x": 142.5,
@ -551,17 +535,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 171.5,
"y": 178
},
{
"x": 171.5,
"y": 223
},
{
"x": 220.75,
"y": 223
"y": 178
},
{
"x": 220.75,
@ -645,14 +621,6 @@
},
{
"x": 161.5,
"y": 273
},
{
"x": 148.75,
"y": 273
},
{
"x": 148.75,
"y": 313
}
],

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 657 KiB

After

Width:  |  Height:  |  Size: 657 KiB

View file

@ -3784,17 +3784,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 1513,
"y": 1396
},
{
"x": 1513,
"y": 1491
},
{
"x": 1791.5,
"y": 1491
"y": 1396
},
{
"x": 1791.5,
@ -3846,14 +3838,6 @@
},
{
"x": 2080,
"y": 1491
},
{
"x": 1801.5,
"y": 1491
},
{
"x": 1802,
"y": 1536
}
],

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 830 KiB

After

Width:  |  Height:  |  Size: 829 KiB

View file

@ -1182,14 +1182,6 @@
},
{
"x": 277.25,
"y": 309
},
{
"x": 235.75,
"y": 309
},
{
"x": 235.75,
"y": 494
},
{
@ -1294,14 +1286,6 @@
},
{
"x": 245.75,
"y": 494
},
{
"x": 261.5,
"y": 494
},
{
"x": 261.5,
"y": 589
}
],

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 663 KiB

After

Width:  |  Height:  |  Size: 663 KiB

View file

@ -2297,17 +2297,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 1743.3333333333333,
"y": 1298
},
{
"x": 1743.3333333333333,
"y": 1338
},
{
"x": 1736.6666666666665,
"y": 1338
"y": 1298
},
{
"x": 1736.6666666666665,
@ -2577,17 +2569,9 @@
"x": 1185.7619047619048,
"y": 1338
},
{
"x": 774.8333333333334,
"y": 1338
},
{
"x": 774.8333333333334,
"y": 2080
},
{
"x": 752.5000000000001,
"y": 2080
"y": 1338
},
{
"x": 752.5000000000001,
@ -2721,17 +2705,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 1770,
"y": 1298
},
{
"x": 1770,
"y": 1338
},
{
"x": 1776.6666666666665,
"y": 1338
"y": 1298
},
{
"x": 1776.6666666666665,
@ -2769,17 +2745,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 1720.6666666666665,
"y": 1694
},
{
"x": 1720.6666666666665,
"y": 1734
},
{
"x": 1722.6666666666665,
"y": 1734
"y": 1694
},
{
"x": 1722.6666666666665,
@ -3049,17 +3017,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 1562.4166666666667,
"y": 3182
},
{
"x": 1562.4166666666667,
"y": 3222
},
{
"x": 1559.1666666666667,
"y": 3222
"y": 3182
},
{
"x": 1559.1666666666667,
@ -3186,27 +3146,11 @@
"labelPercentage": 0,
"route": [
{
"x": 117.5,
"x": 116.5,
"y": 2586
},
{
"x": 117.5,
"y": 2626
},
{
"x": 116.5,
"y": 2626
},
{
"x": 116.5,
"y": 3222
},
{
"x": 117.5,
"y": 3222
},
{
"x": 117.5,
"y": 3362
}
],
@ -4055,14 +3999,6 @@
},
{
"x": 1301.1666666666667,
"y": 2280
},
{
"x": 1313.4166666666667,
"y": 2280
},
{
"x": 1313.4166666666667,
"y": 2520
}
],
@ -4103,14 +4039,6 @@
},
{
"x": 1104.3690476190477,
"y": 254
},
{
"x": 1057.702380952381,
"y": 254
},
{
"x": 1057.702380952381,
"y": 294
}
],
@ -4255,14 +4183,6 @@
},
{
"x": 1479,
"y": 550
},
{
"x": 1465.3333333333333,
"y": 550
},
{
"x": 1465.3333333333333,
"y": 836
}
],
@ -4599,14 +4519,6 @@
},
{
"x": 797,
"y": 2130
},
{
"x": 785.8333333333334,
"y": 2130
},
{
"x": 785.8333333333334,
"y": 2520
}
],
@ -4889,17 +4801,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 471.83333333333326,
"y": 656
},
{
"x": 471.83333333333326,
"y": 696
},
{
"x": 485.1666666666665,
"y": 696
"y": 656
},
{
"x": 485.1666666666665,
@ -4938,27 +4842,11 @@
"labelPercentage": 0,
"route": [
{
"x": 437.1666666666665,
"x": 430.5,
"y": 902
},
{
"x": 437.1666666666665,
"y": 942
},
{
"x": 430.5,
"y": 942
},
{
"x": 430.5,
"y": 3222
},
{
"x": 419.3690476190475,
"y": 3222
},
{
"x": 419.3690476190475,
"y": 3362
}
],
@ -5281,17 +5169,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 149.5,
"y": 2586
},
{
"x": 149.5,
"y": 3222
},
{
"x": 147.5,
"y": 3222
"y": 2586
},
{
"x": 147.5,
@ -5329,17 +5209,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 127.5,
"y": 3428
},
{
"x": 127.5,
"y": 3468
},
{
"x": 102,
"y": 3468
"y": 3428
},
{
"x": 102,
@ -5543,14 +5415,6 @@
},
{
"x": 1585.5833333333333,
"y": 1388
},
{
"x": 1558.9166666666667,
"y": 1388
},
{
"x": 1558.9166666666667,
"y": 1628
}
],
@ -5585,17 +5449,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 1508.9166666666667,
"y": 1694
},
{
"x": 1508.9166666666667,
"y": 1884
},
{
"x": 1505.5833333333333,
"y": 1884
"y": 1694
},
{
"x": 1505.5833333333333,
@ -5879,14 +5735,6 @@
},
{
"x": 1492.25,
"y": 1388
},
{
"x": 1518.9166666666667,
"y": 1388
},
{
"x": 1518.9166666666667,
"y": 1628
}
],
@ -6121,17 +5969,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 1784.6666666666665,
"y": 1694
},
{
"x": 1784.6666666666665,
"y": 1734
},
{
"x": 1782.6666666666665,
"y": 1734
"y": 1694
},
{
"x": 1782.6666666666665,
@ -6423,14 +6263,6 @@
},
{
"x": 452,
"y": 3272
},
{
"x": 451.3690476190475,
"y": 3272
},
{
"x": 451.3690476190475,
"y": 3362
}
],
@ -6561,17 +6393,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 167.5,
"y": 3428
},
{
"x": 167.5,
"y": 3518
},
{
"x": 132,
"y": 3518
"y": 3428
},
{
"x": 132,
@ -6697,17 +6521,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 692.3690476190477,
"y": 3182
},
{
"x": 692.3690476190477,
"y": 3222
},
{
"x": 716.3690476190476,
"y": 3222
"y": 3182
},
{
"x": 716.3690476190476,
@ -6745,17 +6561,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 1568.9166666666667,
"y": 1694
},
{
"x": 1568.9166666666667,
"y": 1884
},
{
"x": 1572.25,
"y": 1884
"y": 1694
},
{
"x": 1572.25,
@ -6807,14 +6615,6 @@
},
{
"x": 368.1666666666665,
"y": 2676
},
{
"x": 357.1666666666665,
"y": 2676
},
{
"x": 357.1666666666665,
"y": 3116
}
],
@ -6945,17 +6745,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 1782.6666666666665,
"y": 2040
},
{
"x": 1782.6666666666665,
"y": 2080
},
{
"x": 1777.8333333333333,
"y": 2080
"y": 2040
},
{
"x": 1777.8333333333333,
@ -6993,17 +6785,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 310.5,
"y": 3182
},
{
"x": 310.5,
"y": 3222
},
{
"x": 307.16666666666674,
"y": 3222
"y": 3182
},
{
"x": 307.16666666666674,
@ -7145,17 +6929,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 1602.4166666666667,
"y": 3182
},
{
"x": 1602.4166666666667,
"y": 3468
},
{
"x": 1618,
"y": 3468
"y": 3182
},
{
"x": 1618,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 376 KiB

After

Width:  |  Height:  |  Size: 372 KiB

View file

@ -364,17 +364,9 @@
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 222.75,
"y": 264
},
{
"x": 222.75,
"y": 304
},
{
"x": 223,
"y": 304
"y": 264
},
{
"x": 223,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 668 KiB

After

Width:  |  Height:  |  Size: 668 KiB

View file

@ -159,14 +159,6 @@
},
{
"x": 409.66666666666674,
"y": 150
},
{
"x": 236,
"y": 150
},
{
"x": 236,
"y": 190
}
],
@ -207,14 +199,6 @@
},
{
"x": 552.3333333333334,
"y": 150
},
{
"x": 726,
"y": 150
},
{
"x": 726,
"y": 190
}
],

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 666 KiB

After

Width:  |  Height:  |  Size: 665 KiB

View file

@ -27,6 +27,28 @@ func (b *Box) Center() *Point {
return NewPoint(b.TopLeft.X+b.Width/2, b.TopLeft.Y+b.Height/2)
}
// Intersects returns true if the segment comes within buffer of the box
func (b *Box) Intersects(s Segment, buffer float64) bool {
tl := NewPoint(b.TopLeft.X-buffer, b.TopLeft.Y-buffer)
tr := NewPoint(tl.X+b.Width+buffer*2, tl.Y)
br := NewPoint(tr.X, tr.Y+b.Height+buffer*2)
bl := NewPoint(tl.X, br.Y)
if p := IntersectionPoint(s.Start, s.End, tl, tr); p != nil {
return true
}
if p := IntersectionPoint(s.Start, s.End, tr, br); p != nil {
return true
}
if p := IntersectionPoint(s.Start, s.End, br, bl); p != nil {
return true
}
if p := IntersectionPoint(s.Start, s.End, bl, tl); p != nil {
return true
}
return false
}
func (b *Box) Intersections(s Segment) []*Point {
pts := []*Point{}

View file

@ -20,24 +20,28 @@ func NewSegment(from, to *Point) *Segment {
func (s Segment) Overlaps(otherS Segment, isHorizontal bool, buffer float64) bool {
if isHorizontal {
if s.Start.Y-otherS.End.Y >= buffer {
if math.Min(s.Start.Y, s.End.Y)-math.Max(otherS.Start.Y, otherS.End.Y) >= buffer {
return false
}
if otherS.Start.Y-s.End.Y >= buffer {
if math.Min(otherS.Start.Y, otherS.End.Y)-math.Max(s.Start.Y, s.End.Y) >= buffer {
return false
}
return true
} else {
if s.Start.X-otherS.End.X >= buffer {
if math.Min(s.Start.X, s.End.X)-math.Max(otherS.Start.X, otherS.End.X) >= buffer {
return false
}
if otherS.Start.X-s.End.X >= buffer {
if math.Min(otherS.Start.X, otherS.End.X)-math.Max(s.Start.X, s.End.X) >= buffer {
return false
}
return true
}
}
func (segment Segment) Intersects(otherSegment Segment) bool {
return IntersectionPoint(segment.Start, segment.End, otherSegment.Start, otherSegment.End) != nil
}
//nolint:unused
func (s Segment) ToString() string {
return fmt.Sprintf("%v -> %v", s.Start.ToString(), s.End.ToString())