diff --git a/changes/unreleased/drawio-unrouted-edges.fixed.md b/changes/unreleased/drawio-unrouted-edges.fixed.md new file mode 100644 index 0000000000..80bdcd7cb0 --- /dev/null +++ b/changes/unreleased/drawio-unrouted-edges.fixed.md @@ -0,0 +1 @@ +- The `drawio` rendering form no longer falls back silently when the router finds no path for an edge: the file carries a notice naming the edge and its cells, and an end at a port still leaves through the port's face. Two causes of such edges are gone: a flush pin at a quarter, half or three quarters of a side (a container's header pin above a centred member) coincided with one of libavoid's generic pins and attached to neither, in the diagram panel's router as well as in the export, and a member drawn outside its container was routed inside the container's bounds. Routed waypoints and anchors are written to a thousandth of a pixel instead of with float noise, while a stated `Route` keeps its exact points, and an edge that is a declaration of its own (a connection, flow, succession, transition, dependency and the like) carries its qualified name as `fqn` on its ``, as the nodes do. diff --git a/docs/project/view-rendering-forms.md b/docs/project/view-rendering-forms.md index b4ee12b0ab..1a90df2334 100644 --- a/docs/project/view-rendering-forms.md +++ b/docs/project/view-rendering-forms.md @@ -1419,9 +1419,10 @@ one model write byte-identical files. No draw.io is run to write it, and none is Every semantic cell — a node, a port, an edge — is wrapped in an `` carrying the element's handle beside draw.io's own `label`: `kind`, the node's keyword (`part def`, `state`, `initial`, …) or the edge's kind; `view`, the view rendered; `link`, the declaration's -`file:line` when the element has one; and, on a node or a port, `fqn`, the declaration's -qualified name. An edge carries no `fqn` — a relationship has no name of its own in most -models — and is matched by its `link` and the `source` and `target` cells it joins. +`file:line` when the element has one; and `fqn`, the declaration's qualified name, on a node, a +port, and an edge that is a declaration of its own (a connection, flow, succession, transition, +dependency and the like). An edge drawn from a member's declaration — a composition, a typing — +carries no `fqn` and is matched by its `link` and the `source` and `target` cells it joins. Compartment rows and edge end labels are plain `mxCell`s and carry none of these. The `fqn` is exact and the same for every cell of one element, so a tool reading an edited file back can match each cell to its declaration; a later round trip of positions edited in draw.io builds on @@ -1461,8 +1462,16 @@ of one container share stay inside that container, with its header and its other obstacles and the ancestors an end lies in reduced to their headers; an edge from a container to its own member leaves the header's underside above the member. Containers are padded by more than twice the clearance so a path fits between neighbours. A stated `Route` is never re-routed, and -an edge the router finds no path for (two boxes nearer than twice the clearance) is written -without waypoints under `edgeStyle=orthogonalEdgeStyle`, for draw.io to route as before. The `js` and `wasip1` builds of `sysml` +an edge the router finds no path for (two boxes nearer than twice the clearance plus their +port squares, as the default layout's 40 px between siblings can be) is written without +waypoints under `edgeStyle=orthogonalEdgeStyle`, for draw.io to route as before, under a notice +naming the edge and its cells; an end at a port keeps its face as the anchor, the inner face when +the edge leads into the port's owner. A member drawn outside its container is routed in the +nearest container holding both ends. Routed waypoints are written to a thousandth of a pixel; a +stated `Route` keeps its points. An edge that is a declaration of its own — a connection, flow, +succession, transition, dependency and the like — carries its qualified name as `fqn` on its +``, as the nodes do; an edge drawn from a member's declaration, such as a composition or a +typing, carries none. The `js` and `wasip1` builds of `sysml` carry no router (a WebAssembly runtime inside WebAssembly would route several times slower and add to the download): they write every unrouted edge that way, under a notice, and draw.io routes them when the file opens. diff --git a/editors/vscode/src/webview/avoid.test.ts b/editors/vscode/src/webview/avoid.test.ts index 3b79e1da9a..e9e6a07141 100644 --- a/editors/vscode/src/webview/avoid.test.ts +++ b/editors/vscode/src/webview/avoid.test.ts @@ -834,6 +834,14 @@ test("avoidRoutes keeps randomized port endpoints on their faces with perpendicu } }); +test("routingPinPositions drops a generic pin under a flush one so libavoid attaches to the pin", () => { + const box = { x: 0, y: 0, width: 200, height: 40 }; + const pins = routingPinPositions({ box, ports: [{ id: "hdr", side: "south", offset: 0.5, flush: true }] }); + assert.equal(pins.filter((pin) => pin.side === "south" && pin.y === 1 && pin.x === 0.5).length, 1); + assert.equal(pins.filter((pin) => pin.id === undefined).length, 11); + assert.equal(routingPinPositions({ box, ports: [{ id: "p", side: "south", offset: 0.5 }] }).filter((pin) => pin.id === undefined).length, 12); +}); + test("routingPinPositions pins a flush port on the border itself and grows the routing box for none", () => { const box = { x: 0, y: 0, width: 100, height: 50 }; const pins = routingPinPositions({ box, ports: [{ id: "a/3", side: "south", offset: 0.3, flush: true }] }); diff --git a/editors/vscode/src/webview/avoid.ts b/editors/vscode/src/webview/avoid.ts index c9c6fd692e..80f4ff4ca0 100644 --- a/editors/vscode/src/webview/avoid.ts +++ b/editors/vscode/src/webview/avoid.ts @@ -682,7 +682,12 @@ export function routingPinPositions(shapeData: AvoidShape): RoutingPinPosition[] return { id, side, x: 0, y: portion((y - routingBox.y) / routingBox.height) }; } }); - return [...genericPins, ...namedPins]; + // libavoid attaches to neither of two pins at one point: a generic pin + // under a named one (a flush pin at a quarter, half or three quarters) goes. + const uncovered = genericPins.filter( + (pin) => !namedPins.some((named) => named.side === pin.side && named.x === pin.x && named.y === pin.y), + ); + return [...uncovered, ...namedPins]; } // addShape is a box as a routing obstacle, with twelve proportional pins spread diff --git a/internal/ir/view/drawio.go b/internal/ir/view/drawio.go index b750191f11..81799f388e 100644 --- a/internal/ir/view/drawio.go +++ b/internal/ir/view/drawio.go @@ -7,6 +7,7 @@ import ( "github.com/Open-MBEE/OpenSysML/internal/ir/view/route" "math" "os" + "slices" "strconv" "strings" @@ -49,6 +50,8 @@ func (r *Rendering) DrawioWith(options Options) (string, error) { cells: map[string]bool{}, portBoxes: map[string]drawioBox{}, routed: map[int]bool{}, + inward: map[int]drawioEnds{}, + fqns: map[string]bool{}, } if r.Kind == KindAction { w.used = r.usedPorts(w.ports) @@ -71,21 +74,24 @@ func (r *Rendering) DrawioWith(options Options) (string, error) { // drawioWriter composes one draw.io file from a rendering. type drawioWriter struct { - fills familyFills - labels labeller - ports portView - used map[string]map[string]bool - links Links - view string - boxes map[string]drawioBox // node ID -> its box in canvas coordinates - unrouted bool // this build has no router; draw.io routes on opening - cells map[string]bool // the cell IDs written, the ends an edge may attach to - portBoxes map[string]drawioBox // port cell ID -> its box in canvas coordinates - routed map[int]bool // the edges (by index) the router gave their route - edgeIDs map[[2]string]string // edge ends -> its cell ID, the anchor an edge note joins - grid int // nodes and notes laid on the grid for want of a position - extent drawioBox // the bounds of everything placed - b strings.Builder + fills familyFills + labels labeller + ports portView + used map[string]map[string]bool + links Links + view string + boxes map[string]drawioBox // node ID -> its box in canvas coordinates + unrouted bool // this build has no router; draw.io routes on opening + cells map[string]bool // the cell IDs written, the ends an edge may attach to + portBoxes map[string]drawioBox // port cell ID -> its box in canvas coordinates + routed map[int]bool // the edges (by index) the router gave their route + unroutable []int // the edges (by index) the router found no path for + inward map[int]drawioEnds // per edge, the ends that lead into the port's owner + fqns map[string]bool // the qualified names written on cells so far + edgeIDs map[[2]string]string // edge ends -> its cell ID, the anchor an edge note joins + grid int // nodes and notes laid on the grid for want of a position + extent drawioBox // the bounds of everything placed + b strings.Builder } // drawioBox is an axis-aligned box in canvas coordinates: the top-left corner @@ -104,6 +110,11 @@ func (b drawioBox) relativeTo(parent drawioBox) drawioBox { func (b drawioBox) right() float64 { return b.X + b.Width } func (b drawioBox) bottom() float64 { return b.Y + b.Height } +// contains reports whether o lies within b. +func (b drawioBox) contains(o drawioBox) bool { + return o.X >= b.X && o.Y >= b.Y && o.right() <= b.right() && o.bottom() <= b.bottom() +} + // The spacing the grid lays unplaced nodes out with, and the padding a // container keeps about its nested children, in draw.io pixels. const ( @@ -449,6 +460,9 @@ func (w *drawioWriter) notices(r *Rendering, options Options) []string { if w.unrouted { notices = append(notices, "edges not routed: this build runs no router; draw.io routes them when the file opens") } + for _, i := range w.unroutable { + notices = append(notices, fmt.Sprintf("edge %s not routed: the router found no path at this layout; draw.io routes it when the file opens", w.edgeName(r.Edges[i]))) + } if options.Style != "" && options.Style != StylePilot { notices = append(notices, styleNotice(options.Style)) } @@ -494,6 +508,7 @@ func (w *drawioWriter) openObject(indent string, o drawioObject) { w.attr("label", o.label) if o.fqn != "" { w.attr("fqn", o.fqn) + w.fqns[o.fqn] = true } w.attr("kind", o.kind) w.attr("view", w.view) @@ -941,8 +956,11 @@ func (w *drawioWriter) writeEdge(i int, edge Edge) { if w.routed[i] && len(points) >= 2 { anchors = w.anchor("exit", source, points[0]) + w.anchor("entry", target, points[len(points)-1]) points = points[1 : len(points)-1] + } else if slices.Contains(w.unroutable, i) { + // No route, but an end at a port still leaves through the port's face. + anchors = w.faceAnchor("exit", source, w.inward[i]&drawioFrom != 0) + w.faceAnchor("entry", target, w.inward[i]&drawioTo != 0) } - w.openObject(" ", drawioObject{id: id, label: edge.Label, kind: edge.Kind.String(), link: w.link(edge.Origin)}) + w.openObject(" ", drawioObject{id: id, label: edge.Label, fqn: w.edgeFQN(edge), kind: edge.Kind.String(), link: w.link(edge.Origin)}) w.b.WriteString(" " + edge.To + if fqn := w.siteName(edge.Origin); fqn != "" { + return fqn + " (" + ends + ")" + } + if edge.Label != "" { + return edge.Label + " (" + ends + ")" + } + return ends +} + +// faceAnchor fixes an edge end at the middle of a port cell's outer face, or of its inner +// face when the edge leads into the port's owner; a node end is left to draw.io. +func (w *drawioWriter) faceAnchor(end, cell string, inward bool) string { + owner, _, isPort := strings.Cut(cell, ":") + port, ok := w.portBoxes[cell] + box, known := w.boxes[owner] + if !isPort || !ok || !known { + return "" + } + cx, cy := port.X+port.Width/2, port.Y+port.Height/2 + fx, fy, best := 0.5, 0.0, cy-box.Y + if d := box.right() - cx; d < best { + fx, fy, best = 1, 0.5, d + } + if d := box.bottom() - cy; d < best { + fx, fy, best = 0.5, 1, d + } + if d := cx - box.X; d < best { + fx, fy = 0, 0.5 + } + if inward { + fx, fy = 1-fx, 1-fy + } + return fmt.Sprintf("%sX=%s;%sY=%s;%sPerimeter=0;", end, formatCoord(fx), end, formatCoord(fy), end) +} + // anchor fixes an edge end at p on its cell, as the fraction of the cell's box // draw.io reads from exitX/exitY or entryX/entryY, taken exactly (no perimeter). func (w *drawioWriter) anchor(end, cell string, p Point) string { @@ -975,7 +1057,7 @@ func (w *drawioWriter) anchor(end, cell string, p Point) string { if size > 0 { f = min(1, max(0, (v-origin)/size)) } - return strconv.FormatFloat(f, 'f', -1, 64) + return strconv.FormatFloat(math.Round(f*10000)/10000, 'f', -1, 64) } return fmt.Sprintf("%sX=%s;%sY=%s;%sPerimeter=0;", end, fraction(p.X, box.X, box.Width), end, fraction(p.Y, box.Y, box.Height), end) } diff --git a/internal/ir/view/drawio_route.go b/internal/ir/view/drawio_route.go index b1f73a627f..d483980058 100644 --- a/internal/ir/view/drawio_route.go +++ b/internal/ir/view/drawio_route.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "maps" + "math" "slices" "sort" @@ -25,6 +26,10 @@ func (w *drawioWriter) routeEdges(r *Rendering) ([]Edge, error) { continue } key := tree.commonContainer(edge.From, edge.To) + // A member drawn outside its container is not held by it. + for key != "" && !(w.boxes[key].contains(w.boxes[edge.From]) && w.boxes[key].contains(w.boxes[edge.To])) { + key = tree.parents[key] + } groups[key] = append(groups[key], i) } keys := make([]string, 0, len(groups)) @@ -64,6 +69,11 @@ func (w *drawioWriter) routeEdges(r *Rendering) ([]Edge, error) { // leaves it through its inner face, into the container. if shape, ok := w.portShape(tree.nodes[key], w.boxes[key], port, true); ok { portShapes[shape.ID] = shape + if edges[i].From == key { + w.inward[i] |= drawioFrom + } else { + w.inward[i] |= drawioTo + } continue } pin := route.Port{ID: fmt.Sprintf("\x00member/%d", i), Side: route.South, Flush: true} @@ -123,11 +133,17 @@ func (w *drawioWriter) routeEdges(r *Rendering) ([]Edge, error) { } for _, found := range routes { i := group[found.Index] + // Routed points carry float noise a declared route never has. for _, p := range found.Points { - edges[i].Route = append(edges[i].Route, Point{X: p.X, Y: p.Y}) + edges[i].Route = append(edges[i].Route, Point{X: drawioRound(p.X), Y: drawioRound(p.Y)}) } w.routed[i] = true } + for _, i := range group { + if !w.routed[i] { + w.unroutable = append(w.unroutable, i) + } + } } return edges, nil } @@ -290,3 +306,6 @@ func (t drawioTree) commonContainer(a, b string) string { } return "" } + +// drawioRound trims a routed coordinate to a thousandth of a pixel. +func drawioRound(v float64) float64 { return math.Round(v*1000) / 1000 } diff --git a/internal/ir/view/drawio_test.go b/internal/ir/view/drawio_test.go index eb2c2425f9..9703f2bc3a 100644 --- a/internal/ir/view/drawio_test.go +++ b/internal/ir/view/drawio_test.go @@ -435,6 +435,7 @@ func TestDrawioSharesANoteAmongItsAnchors(t *testing.T) { func TestDrawioRoutesUnroutedEdges(t *testing.T) { for _, c := range []struct{ name, file, view string }{ {"interconnection-ports", "interconnection-ports.sysml", "ToasterViews::toasterView"}, + {"interconnection-header-ports", "interconnection-header-ports.sysml", "PumpStationViews::stationView"}, {"tree-edges", "tree-edges.sysml", "FleetViews::structure"}, {"layout", "layout.sysml", "PlantViews::placedView"}, } { @@ -479,7 +480,7 @@ func TestDrawioRoutesUnroutedEdges(t *testing.T) { path := append(append([]Point{exit}, cell.points...), entry) for j := 1; j < len(path); j++ { a, b := path[j-1], path[j] - if math.Abs(a.X-b.X) > 1e-6 && math.Abs(a.Y-b.Y) > 1e-6 { + if math.Abs(a.X-b.X) > 0.5 && math.Abs(a.Y-b.Y) > 0.5 { t.Errorf("%s: segment %v -> %v is not orthogonal", cell.id, a, b) } } diff --git a/internal/ir/view/route/route.go b/internal/ir/view/route/route.go index b935d35c8b..8f2f0dc761 100644 --- a/internal/ir/view/route/route.go +++ b/internal/ir/view/route/route.go @@ -6,6 +6,7 @@ package route import ( "errors" "math" + "slices" ) // Routes is the orthogonal route of each edge the router found a path for, @@ -232,6 +233,7 @@ func RoutingPinPositions(shape *Shape) []PinPosition { pins = append(pins, pin) } } + var named []PinPosition for _, port := range shape.Ports { point := portPoint(box, port) pin := PinPosition{ID: port.ID, Named: true, Side: port.Side} @@ -247,9 +249,17 @@ func RoutingPinPositions(shape *Shape) []PinPosition { case West: pin.Y = portion((point.Y - routingBox.Y) / routingBox.Height) } - pins = append(pins, pin) + named = append(named, pin) } - return pins + // libavoid attaches to neither of two pins at one point: a generic pin + // under a named one (a flush pin at a quarter, half or three quarters) goes. + kept := pins[:0] + for _, pin := range pins { + if !slices.ContainsFunc(named, func(n PinPosition) bool { return n.Side == pin.Side && n.X == pin.X && n.Y == pin.Y }) { + kept = append(kept, pin) + } + } + return append(kept, named...) } // snap rounds to the pixel grid the way JavaScript's Math.round does (halves go up). diff --git a/internal/ir/view/route/route_test.go b/internal/ir/view/route/route_test.go index e60687f488..30ecd18d61 100644 --- a/internal/ir/view/route/route_test.go +++ b/internal/ir/view/route/route_test.go @@ -141,3 +141,18 @@ func abs(v float64) float64 { } return v } + +func TestRoutesAFlushPinUnderAGenericOne(t *testing.T) { + owner := Shape{ID: "owner", Box: Box{X: 0, Y: 0, Width: 200, Height: 40}, Ports: []Port{{ID: "hdr", Side: South, Offset: 0.5, Flush: true}}} + member := Shape{ID: "member", Box: Box{X: 60, Y: 120, Width: 80, Height: 40}} + routes, err := Routes([]Shape{owner, member}, []Edge{{Index: 0, From: "owner", FromPort: "hdr", To: "member"}}, nil) + if err != nil { + t.Fatal(err) + } + if len(routes) != 1 { + t.Fatalf("routes = %v, want the flush pin at the middle of the header's underside routed", routes) + } + if first := routes[0].Points[0]; first != (Point{X: 100, Y: 40}) { + t.Errorf("route starts at %v, want the pin at (100, 40)", first) + } +} diff --git a/internal/ir/view/route/testdata/parity/ports.json b/internal/ir/view/route/testdata/parity/ports.json index 2b4f84695a..90bfb9f286 100644 --- a/internal/ir/view/route/testdata/parity/ports.json +++ b/internal/ir/view/route/testdata/parity/ports.json @@ -1 +1 @@ -{"scenes":[{"name":"same-side-edges-to-distinct-port-faces","shapes":[{"id":"a","box":{"x":100,"y":100,"width":120,"height":60},"ports":[{"id":"a.p1","side":"east","offset":0.25},{"id":"a.p2","side":"east","offset":0.75}]},{"id":"b","box":{"x":400,"y":60,"width":120,"height":60},"ports":[{"id":"b.in","side":"west","offset":0.5}]},{"id":"c","box":{"x":400,"y":220,"width":120,"height":60}}],"edges":[{"index":0,"from":"a","to":"b","fromPort":"a.p1","toPort":"b.in"},{"index":1,"from":"a","to":"c","fromPort":"a.p2"}],"routes":{"0":[{"x":225,"y":115},{"x":310,"y":115},{"x":310,"y":90},{"x":395,"y":90}],"1":[{"x":225,"y":145},{"x":430,"y":145},{"x":430,"y":220}]}},{"name":"three-shared-port-lanes-inside-bounds","shapes":[{"id":"hub","box":{"x":40,"y":40,"width":120,"height":60},"ports":[{"id":"hub.out","side":"south","offset":0.5}]},{"id":"x","box":{"x":40,"y":300,"width":100,"height":50},"ports":[{"id":"x.in","side":"north","offset":0.5}]},{"id":"y","box":{"x":260,"y":300,"width":100,"height":50},"ports":[{"id":"y.in","side":"north","offset":0.5}]},{"id":"z","box":{"x":480,"y":300,"width":100,"height":50},"ports":[{"id":"z.in","side":"west","offset":0.5}]}],"edges":[{"index":0,"from":"hub","to":"x","fromPort":"hub.out","toPort":"x.in"},{"index":1,"from":"hub","to":"y","fromPort":"hub.out","toPort":"y.in"},{"index":2,"from":"hub","to":"z","fromPort":"hub.out","toPort":"z.in"}],"bounds":{"x":0,"y":0,"width":640,"height":400},"routes":{"0":[{"x":100,"y":105},{"x":100,"y":200},{"x":90,"y":200},{"x":90,"y":295}],"1":[{"x":100,"y":105},{"x":100,"y":203.99999999999997},{"x":310,"y":203.99999999999997},{"x":310,"y":295}],"2":[{"x":100,"y":105},{"x":100,"y":195.99999999999997},{"x":417.50000000000006,"y":195.99999999999997},{"x":417.50000000000006,"y":325},{"x":475,"y":325}]}},{"name":"bounded-port-route-past-an-obstacle","shapes":[{"id":"left","box":{"x":20,"y":200,"width":100,"height":50},"ports":[{"id":"left.out","side":"south","offset":0.8}]},{"id":"wall","box":{"x":180,"y":120,"width":60,"height":220}},{"id":"right","box":{"x":320,"y":200,"width":100,"height":50},"ports":[{"id":"right.in","side":"south","offset":0.2}]}],"edges":[{"index":0,"from":"left","to":"right","fromPort":"left.out","toPort":"right.in"}],"bounds":{"x":0,"y":0,"width":440,"height":300},"routes":{"0":[{"x":100,"y":255},{"x":100,"y":271},{"x":150,"y":271},{"x":150,"y":104},{"x":280,"y":104},{"x":280,"y":271},{"x":340,"y":271},{"x":340,"y":255}]}},{"name":"generic-pin-beside-a-ported-side","shapes":[{"id":"a","box":{"x":60,"y":60,"width":100,"height":50},"ports":[{"id":"a.p","side":"south","offset":0.5}]},{"id":"b","box":{"x":300,"y":60,"width":100,"height":50}},{"id":"c","box":{"x":60,"y":260,"width":100,"height":50},"ports":[{"id":"c.p","side":"north","offset":0.5}]}],"edges":[{"index":0,"from":"a","to":"b"},{"index":1,"from":"a","to":"c","fromPort":"a.p","toPort":"c.p"}],"routes":{"0":[{"x":160,"y":85},{"x":300,"y":85}],"1":[{"x":110,"y":115},{"x":110,"y":255}]}},{"name":"unported-lanes-in-a-ported-batch","shapes":[{"id":"s","box":{"x":40,"y":150,"width":100,"height":50}},{"id":"t","box":{"x":400,"y":150,"width":100,"height":50}},{"id":"u","box":{"x":400,"y":20,"width":100,"height":50},"ports":[{"id":"u.in","side":"west","offset":0.5}]},{"id":"v","box":{"x":400,"y":300,"width":100,"height":50}}],"edges":[{"index":0,"from":"s","to":"t"},{"index":1,"from":"s","to":"t"},{"index":2,"from":"s","to":"u","toPort":"u.in"},{"index":3,"from":"s","to":"v"}],"routes":{"0":[{"x":140,"y":163},{"x":400,"y":163}],"1":[{"x":140,"y":175},{"x":400,"y":175}],"2":[{"x":90,"y":150},{"x":90,"y":45},{"x":395,"y":45}],"3":[{"x":90,"y":200},{"x":90,"y":313},{"x":400,"y":313}]}},{"name":"flush-header-pin-to-member-port","shapes":[{"id":"owner","box":{"x":40,"y":40,"width":300,"height":28},"ports":[{"id":"owner.header","side":"south","offset":0.5,"flush":true}]},{"id":"member","box":{"x":80,"y":160,"width":100,"height":50},"ports":[{"id":"member.in","side":"west","offset":0.5}]},{"id":"other","box":{"x":230,"y":160,"width":100,"height":50}}],"edges":[{"index":0,"from":"owner","to":"member","fromPort":"owner.header","toPort":"member.in"},{"index":1,"from":"owner","to":"other","fromPort":"owner.header"}],"bounds":{"x":0,"y":0,"width":1200,"height":600},"routes":{}},{"name":"fractional-west-port-box","shapes":[{"id":"a","box":{"x":10.5,"y":20.25,"width":90.5,"height":44.75},"ports":[{"id":"a.w","side":"west","offset":0.3},{"id":"a.e","side":"east","offset":0.6}]},{"id":"b","box":{"x":300.25,"y":200.5,"width":80,"height":40},"ports":[{"id":"b.n","side":"north","offset":0.5}]}],"edges":[{"index":0,"from":"a","to":"b","fromPort":"a.e","toPort":"b.n"},{"index":1,"from":"b","to":"a","toPort":"a.w"}],"routes":{"0":[{"x":106,"y":47.099999999999994},{"x":340.25,"y":47.099999999999994},{"x":340.25,"y":195.5}],"1":[{"x":300.25,"y":210.5},{"x":-10.5,"y":210.5},{"x":-10.5,"y":33.675},{"x":5.5,"y":33.675}]}}]} +{"scenes":[{"name":"same-side-edges-to-distinct-port-faces","shapes":[{"id":"a","box":{"x":100,"y":100,"width":120,"height":60},"ports":[{"id":"a.p1","side":"east","offset":0.25},{"id":"a.p2","side":"east","offset":0.75}]},{"id":"b","box":{"x":400,"y":60,"width":120,"height":60},"ports":[{"id":"b.in","side":"west","offset":0.5}]},{"id":"c","box":{"x":400,"y":220,"width":120,"height":60}}],"edges":[{"index":0,"from":"a","to":"b","fromPort":"a.p1","toPort":"b.in"},{"index":1,"from":"a","to":"c","fromPort":"a.p2"}],"routes":{"0":[{"x":225,"y":115},{"x":310,"y":115},{"x":310,"y":90},{"x":395,"y":90}],"1":[{"x":225,"y":145},{"x":430,"y":145},{"x":430,"y":220}]}},{"name":"three-shared-port-lanes-inside-bounds","shapes":[{"id":"hub","box":{"x":40,"y":40,"width":120,"height":60},"ports":[{"id":"hub.out","side":"south","offset":0.5}]},{"id":"x","box":{"x":40,"y":300,"width":100,"height":50},"ports":[{"id":"x.in","side":"north","offset":0.5}]},{"id":"y","box":{"x":260,"y":300,"width":100,"height":50},"ports":[{"id":"y.in","side":"north","offset":0.5}]},{"id":"z","box":{"x":480,"y":300,"width":100,"height":50},"ports":[{"id":"z.in","side":"west","offset":0.5}]}],"edges":[{"index":0,"from":"hub","to":"x","fromPort":"hub.out","toPort":"x.in"},{"index":1,"from":"hub","to":"y","fromPort":"hub.out","toPort":"y.in"},{"index":2,"from":"hub","to":"z","fromPort":"hub.out","toPort":"z.in"}],"bounds":{"x":0,"y":0,"width":640,"height":400},"routes":{"0":[{"x":100,"y":105},{"x":100,"y":200},{"x":90,"y":200},{"x":90,"y":295}],"1":[{"x":100,"y":105},{"x":100,"y":203.99999999999997},{"x":310,"y":203.99999999999997},{"x":310,"y":295}],"2":[{"x":100,"y":105},{"x":100,"y":195.99999999999997},{"x":417.50000000000006,"y":195.99999999999997},{"x":417.50000000000006,"y":325},{"x":475,"y":325}]}},{"name":"bounded-port-route-past-an-obstacle","shapes":[{"id":"left","box":{"x":20,"y":200,"width":100,"height":50},"ports":[{"id":"left.out","side":"south","offset":0.8}]},{"id":"wall","box":{"x":180,"y":120,"width":60,"height":220}},{"id":"right","box":{"x":320,"y":200,"width":100,"height":50},"ports":[{"id":"right.in","side":"south","offset":0.2}]}],"edges":[{"index":0,"from":"left","to":"right","fromPort":"left.out","toPort":"right.in"}],"bounds":{"x":0,"y":0,"width":440,"height":300},"routes":{"0":[{"x":100,"y":255},{"x":100,"y":271},{"x":150,"y":271},{"x":150,"y":104},{"x":280,"y":104},{"x":280,"y":271},{"x":340,"y":271},{"x":340,"y":255}]}},{"name":"generic-pin-beside-a-ported-side","shapes":[{"id":"a","box":{"x":60,"y":60,"width":100,"height":50},"ports":[{"id":"a.p","side":"south","offset":0.5}]},{"id":"b","box":{"x":300,"y":60,"width":100,"height":50}},{"id":"c","box":{"x":60,"y":260,"width":100,"height":50},"ports":[{"id":"c.p","side":"north","offset":0.5}]}],"edges":[{"index":0,"from":"a","to":"b"},{"index":1,"from":"a","to":"c","fromPort":"a.p","toPort":"c.p"}],"routes":{"0":[{"x":160,"y":85},{"x":300,"y":85}],"1":[{"x":110,"y":115},{"x":110,"y":255}]}},{"name":"unported-lanes-in-a-ported-batch","shapes":[{"id":"s","box":{"x":40,"y":150,"width":100,"height":50}},{"id":"t","box":{"x":400,"y":150,"width":100,"height":50}},{"id":"u","box":{"x":400,"y":20,"width":100,"height":50},"ports":[{"id":"u.in","side":"west","offset":0.5}]},{"id":"v","box":{"x":400,"y":300,"width":100,"height":50}}],"edges":[{"index":0,"from":"s","to":"t"},{"index":1,"from":"s","to":"t"},{"index":2,"from":"s","to":"u","toPort":"u.in"},{"index":3,"from":"s","to":"v"}],"routes":{"0":[{"x":140,"y":163},{"x":400,"y":163}],"1":[{"x":140,"y":175},{"x":400,"y":175}],"2":[{"x":90,"y":150},{"x":90,"y":45},{"x":395,"y":45}],"3":[{"x":90,"y":200},{"x":90,"y":313},{"x":400,"y":313}]}},{"name":"flush-header-pin-to-member-port","shapes":[{"id":"owner","box":{"x":40,"y":40,"width":300,"height":28},"ports":[{"id":"owner.header","side":"south","offset":0.5,"flush":true}]},{"id":"member","box":{"x":80,"y":160,"width":100,"height":50},"ports":[{"id":"member.in","side":"west","offset":0.5}]},{"id":"other","box":{"x":230,"y":160,"width":100,"height":50}}],"edges":[{"index":0,"from":"owner","to":"member","fromPort":"owner.header","toPort":"member.in"},{"index":1,"from":"owner","to":"other","fromPort":"owner.header"}],"bounds":{"x":0,"y":0,"width":1200,"height":600},"routes":{"0":[{"x":190,"y":68},{"x":190,"y":114.00000000000001},{"x":59,"y":114.00000000000001},{"x":59,"y":185},{"x":75,"y":185}],"1":[{"x":190,"y":68},{"x":190,"y":114.00000000000001},{"x":255,"y":114.00000000000001},{"x":255,"y":160}]}},{"name":"fractional-west-port-box","shapes":[{"id":"a","box":{"x":10.5,"y":20.25,"width":90.5,"height":44.75},"ports":[{"id":"a.w","side":"west","offset":0.3},{"id":"a.e","side":"east","offset":0.6}]},{"id":"b","box":{"x":300.25,"y":200.5,"width":80,"height":40},"ports":[{"id":"b.n","side":"north","offset":0.5}]}],"edges":[{"index":0,"from":"a","to":"b","fromPort":"a.e","toPort":"b.n"},{"index":1,"from":"b","to":"a","toPort":"a.w"}],"routes":{"0":[{"x":106,"y":47.099999999999994},{"x":340.25,"y":47.099999999999994},{"x":340.25,"y":195.5}],"1":[{"x":300.25,"y":210.5},{"x":-10.5,"y":210.5},{"x":-10.5,"y":33.675},{"x":5.5,"y":33.675}]}}]} diff --git a/internal/ir/view/testdata/abstract-interconnection.drawio.golden b/internal/ir/view/testdata/abstract-interconnection.drawio.golden index 00a00fa1cb..92af23a474 100644 --- a/internal/ir/view/testdata/abstract-interconnection.drawio.golden +++ b/internal/ir/view/testdata/abstract-interconnection.drawio.golden @@ -33,7 +33,7 @@ - + diff --git a/internal/ir/view/testdata/abstract-mixed.drawio.golden b/internal/ir/view/testdata/abstract-mixed.drawio.golden index 3935f42d27..53b6e2ec63 100644 --- a/internal/ir/view/testdata/abstract-mixed.drawio.golden +++ b/internal/ir/view/testdata/abstract-mixed.drawio.golden @@ -58,7 +58,7 @@ - + @@ -67,27 +67,32 @@ - + - - + + + + + + + - + - + - + @@ -98,25 +103,27 @@ - + - + - - + + - + - + + + diff --git a/internal/ir/view/testdata/abstract-tree.drawio.golden b/internal/ir/view/testdata/abstract-tree.drawio.golden index 406005d6d0..f7cb416f52 100644 --- a/internal/ir/view/testdata/abstract-tree.drawio.golden +++ b/internal/ir/view/testdata/abstract-tree.drawio.golden @@ -88,12 +88,12 @@ - + - + @@ -103,22 +103,22 @@ - + - + - + - + @@ -130,7 +130,7 @@ - + @@ -140,32 +140,32 @@ - + - + - + - + - + - + diff --git a/internal/ir/view/testdata/action.drawio.golden b/internal/ir/view/testdata/action.drawio.golden index 7c193e71f4..0ccdc09d31 100644 --- a/internal/ir/view/testdata/action.drawio.golden +++ b/internal/ir/view/testdata/action.drawio.golden @@ -1,6 +1,7 @@ + @@ -89,7 +90,7 @@ - + @@ -110,7 +111,7 @@ - + @@ -121,7 +122,7 @@ - + @@ -147,7 +148,7 @@ - + @@ -166,7 +167,7 @@ - + @@ -184,7 +185,7 @@ - + @@ -194,7 +195,7 @@ - + @@ -204,7 +205,7 @@ - + diff --git a/internal/ir/view/testdata/calc-parameters.drawio.golden b/internal/ir/view/testdata/calc-parameters.drawio.golden index b0bd168d47..3416418106 100644 --- a/internal/ir/view/testdata/calc-parameters.drawio.golden +++ b/internal/ir/view/testdata/calc-parameters.drawio.golden @@ -120,17 +120,17 @@ - + - + - + diff --git a/internal/ir/view/testdata/case.drawio.golden b/internal/ir/view/testdata/case.drawio.golden index 765ffbbb87..894753c1cb 100644 --- a/internal/ir/view/testdata/case.drawio.golden +++ b/internal/ir/view/testdata/case.drawio.golden @@ -104,12 +104,12 @@ - + - + @@ -120,7 +120,7 @@ - + @@ -132,7 +132,7 @@ - + @@ -142,7 +142,7 @@ - + @@ -151,8 +151,8 @@ - - + + @@ -162,7 +162,7 @@ - + @@ -173,12 +173,12 @@ - + - + @@ -189,7 +189,7 @@ - + @@ -201,12 +201,12 @@ - + - + @@ -217,12 +217,12 @@ - + - + @@ -232,7 +232,7 @@ - + diff --git a/internal/ir/view/testdata/feature-membership.drawio.golden b/internal/ir/view/testdata/feature-membership.drawio.golden index 4c262363fd..d3fc6b5f9d 100644 --- a/internal/ir/view/testdata/feature-membership.drawio.golden +++ b/internal/ir/view/testdata/feature-membership.drawio.golden @@ -43,12 +43,12 @@ - + - + @@ -57,7 +57,7 @@ - + @@ -67,12 +67,12 @@ - + - + @@ -82,7 +82,7 @@ - + diff --git a/internal/ir/view/testdata/general-definition.drawio.golden b/internal/ir/view/testdata/general-definition.drawio.golden index 56526ef625..de5ad07bb1 100644 --- a/internal/ir/view/testdata/general-definition.drawio.golden +++ b/internal/ir/view/testdata/general-definition.drawio.golden @@ -78,12 +78,12 @@ - + - + @@ -93,7 +93,7 @@ - + @@ -104,7 +104,7 @@ - + @@ -115,7 +115,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -136,7 +136,7 @@ - + @@ -149,7 +149,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -171,7 +171,7 @@ - + @@ -182,7 +182,7 @@ - + @@ -193,7 +193,7 @@ - + @@ -203,7 +203,7 @@ - + diff --git a/internal/ir/view/testdata/general-package.drawio.golden b/internal/ir/view/testdata/general-package.drawio.golden index 6e8b070bd7..c61283e0f5 100644 --- a/internal/ir/view/testdata/general-package.drawio.golden +++ b/internal/ir/view/testdata/general-package.drawio.golden @@ -33,7 +33,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -69,7 +69,7 @@ - + diff --git a/internal/ir/view/testdata/general-requirement.drawio.golden b/internal/ir/view/testdata/general-requirement.drawio.golden index 29fd609b8c..40324dc283 100644 --- a/internal/ir/view/testdata/general-requirement.drawio.golden +++ b/internal/ir/view/testdata/general-requirement.drawio.golden @@ -89,7 +89,7 @@ - + @@ -100,7 +100,7 @@ - + @@ -110,7 +110,7 @@ - + @@ -120,7 +120,7 @@ - + @@ -131,7 +131,7 @@ - + @@ -141,7 +141,7 @@ - + @@ -150,7 +150,7 @@ - + @@ -161,7 +161,7 @@ - + @@ -180,8 +180,8 @@ - - + + @@ -192,7 +192,7 @@ - + @@ -201,7 +201,7 @@ - + @@ -210,7 +210,7 @@ - + diff --git a/internal/ir/view/testdata/glyphs-action.drawio.golden b/internal/ir/view/testdata/glyphs-action.drawio.golden index ae9d2013f9..061105404a 100644 --- a/internal/ir/view/testdata/glyphs-action.drawio.golden +++ b/internal/ir/view/testdata/glyphs-action.drawio.golden @@ -37,7 +37,7 @@ - + diff --git a/internal/ir/view/testdata/glyphs-definition.drawio.golden b/internal/ir/view/testdata/glyphs-definition.drawio.golden index 32c4f4684f..bd276efcfd 100644 --- a/internal/ir/view/testdata/glyphs-definition.drawio.golden +++ b/internal/ir/view/testdata/glyphs-definition.drawio.golden @@ -73,17 +73,17 @@ - + - + - + @@ -93,7 +93,7 @@ - + @@ -108,7 +108,7 @@ - + @@ -117,8 +117,8 @@ - - + + @@ -127,8 +127,8 @@ - - + + @@ -138,12 +138,12 @@ - + - + @@ -154,7 +154,7 @@ - + diff --git a/internal/ir/view/testdata/glyphs-interconnection.drawio.golden b/internal/ir/view/testdata/glyphs-interconnection.drawio.golden index 0f97ef5b55..391ef5c3bb 100644 --- a/internal/ir/view/testdata/glyphs-interconnection.drawio.golden +++ b/internal/ir/view/testdata/glyphs-interconnection.drawio.golden @@ -33,7 +33,7 @@ - + diff --git a/internal/ir/view/testdata/glyphs-mixed.drawio.golden b/internal/ir/view/testdata/glyphs-mixed.drawio.golden index 23998196bb..3e277b8168 100644 --- a/internal/ir/view/testdata/glyphs-mixed.drawio.golden +++ b/internal/ir/view/testdata/glyphs-mixed.drawio.golden @@ -131,27 +131,27 @@ - + - + - + - + - + @@ -161,7 +161,7 @@ - + @@ -170,7 +170,7 @@ - + @@ -180,7 +180,7 @@ - + @@ -189,7 +189,7 @@ - + diff --git a/internal/ir/view/testdata/glyphs-package.drawio.golden b/internal/ir/view/testdata/glyphs-package.drawio.golden index 3f0bdda1a5..5b5344882a 100644 --- a/internal/ir/view/testdata/glyphs-package.drawio.golden +++ b/internal/ir/view/testdata/glyphs-package.drawio.golden @@ -23,12 +23,12 @@ - + - + @@ -38,7 +38,7 @@ - + diff --git a/internal/ir/view/testdata/glyphs-requirement.drawio.golden b/internal/ir/view/testdata/glyphs-requirement.drawio.golden index 2500b55acd..0ddb641726 100644 --- a/internal/ir/view/testdata/glyphs-requirement.drawio.golden +++ b/internal/ir/view/testdata/glyphs-requirement.drawio.golden @@ -27,7 +27,7 @@ - + @@ -38,12 +38,12 @@ - + - - + + diff --git a/internal/ir/view/testdata/glyphs-tree.drawio.golden b/internal/ir/view/testdata/glyphs-tree.drawio.golden index b304ac114e..ff48afaed4 100644 --- a/internal/ir/view/testdata/glyphs-tree.drawio.golden +++ b/internal/ir/view/testdata/glyphs-tree.drawio.golden @@ -68,22 +68,22 @@ - + - + - + - + @@ -96,7 +96,7 @@ - + @@ -106,19 +106,19 @@ - + - - + + - + @@ -128,12 +128,12 @@ - + - + @@ -142,12 +142,12 @@ - + - + @@ -156,7 +156,7 @@ - + diff --git a/internal/ir/view/testdata/interconnection-constraints-placed.drawio.golden b/internal/ir/view/testdata/interconnection-constraints-placed.drawio.golden index 697123af7b..0f3d19bb9b 100644 --- a/internal/ir/view/testdata/interconnection-constraints-placed.drawio.golden +++ b/internal/ir/view/testdata/interconnection-constraints-placed.drawio.golden @@ -66,7 +66,7 @@ - + @@ -76,7 +76,7 @@ - + @@ -86,7 +86,7 @@ - + @@ -96,7 +96,7 @@ - + @@ -106,7 +106,7 @@ - + diff --git a/internal/ir/view/testdata/interconnection-constraints.drawio.golden b/internal/ir/view/testdata/interconnection-constraints.drawio.golden index da547ec220..30661106f4 100644 --- a/internal/ir/view/testdata/interconnection-constraints.drawio.golden +++ b/internal/ir/view/testdata/interconnection-constraints.drawio.golden @@ -1,6 +1,7 @@ + @@ -84,38 +85,38 @@ - - + + - - + + - - + + - + - - + + - - + + - - + + diff --git a/internal/ir/view/testdata/interconnection-header-ports.sysml b/internal/ir/view/testdata/interconnection-header-ports.sysml new file mode 100644 index 0000000000..0136c7543a --- /dev/null +++ b/internal/ir/view/testdata/interconnection-header-ports.sysml @@ -0,0 +1,35 @@ +// Two parts whose ports sit on their top borders, under the header of the +// part that holds them: the connection between the ports has to leave each +// port upward, into the strip between the header and the parts. +package PumpStation { + port def FluidPort; + + part def Pump { + port outlet : FluidPort; + } + + part def Tank { + port inlet : ~FluidPort; + } + + part def Station { + part supply : Pump; + part reservoir : Tank; + connection fluid connect supply.outlet to reservoir.inlet; + } + + part station : Station; +} + +package PumpStationViews { + private import Views::*; + private import DiagramLayout::*; + + view stationView { + expose PumpStation::station; + render asInterconnectionDiagram; + metadata Layout about PumpStation::station { x = 40; y = 40; } + metadata Layout about PumpStation::station::supply { x = 80; y = 220; } + metadata Layout about PumpStation::station::reservoir { x = 300; y = 220; } + } +} diff --git a/internal/ir/view/testdata/interconnection-ports.drawio.golden b/internal/ir/view/testdata/interconnection-ports.drawio.golden index 1177dcb713..e089ad4345 100644 --- a/internal/ir/view/testdata/interconnection-ports.drawio.golden +++ b/internal/ir/view/testdata/interconnection-ports.drawio.golden @@ -41,8 +41,8 @@ - - + + @@ -52,11 +52,11 @@ - + - - + + diff --git a/internal/ir/view/testdata/interconnection.drawio.golden b/internal/ir/view/testdata/interconnection.drawio.golden index cad40ef74d..7c613ab400 100644 --- a/internal/ir/view/testdata/interconnection.drawio.golden +++ b/internal/ir/view/testdata/interconnection.drawio.golden @@ -56,8 +56,8 @@ - - + + @@ -67,7 +67,7 @@ - + diff --git a/internal/ir/view/testdata/layout.drawio.golden b/internal/ir/view/testdata/layout.drawio.golden index 86344d1a82..ac9d4eeb06 100644 --- a/internal/ir/view/testdata/layout.drawio.golden +++ b/internal/ir/view/testdata/layout.drawio.golden @@ -38,7 +38,7 @@ - + diff --git a/internal/ir/view/testdata/mixed-memberships.drawio.golden b/internal/ir/view/testdata/mixed-memberships.drawio.golden index 69dd7f07f7..8f0787943c 100644 --- a/internal/ir/view/testdata/mixed-memberships.drawio.golden +++ b/internal/ir/view/testdata/mixed-memberships.drawio.golden @@ -113,47 +113,47 @@ - + - + - + - + - + - + - + - + - + @@ -165,7 +165,7 @@ - + @@ -175,12 +175,12 @@ - + - + @@ -194,11 +194,11 @@ - + - - + + @@ -207,7 +207,7 @@ - + @@ -219,17 +219,17 @@ - + - + - + @@ -240,7 +240,7 @@ - + @@ -251,7 +251,7 @@ - + @@ -264,21 +264,21 @@ - + - - - - + + + + - + @@ -288,7 +288,7 @@ - + @@ -309,7 +309,7 @@ - + @@ -318,7 +318,7 @@ - + diff --git a/internal/ir/view/testdata/mixed.drawio.golden b/internal/ir/view/testdata/mixed.drawio.golden index d3ca2019fd..46f0895cad 100644 --- a/internal/ir/view/testdata/mixed.drawio.golden +++ b/internal/ir/view/testdata/mixed.drawio.golden @@ -182,7 +182,7 @@ - + @@ -191,7 +191,7 @@ - + @@ -201,7 +201,7 @@ - + @@ -210,7 +210,7 @@ - + @@ -222,7 +222,7 @@ - + @@ -232,7 +232,7 @@ - + @@ -243,7 +243,7 @@ - + @@ -251,8 +251,8 @@ - - + + @@ -262,37 +262,37 @@ - + - + - + - + - + - + - + @@ -302,51 +302,51 @@ - + - + - + - - - + + + - + - + - + - - - - + + + + - + @@ -358,54 +358,54 @@ - + - + - + - + - - - - - + + + + + - + - - - - + + + + - + - - - - + + + + @@ -415,7 +415,7 @@ - + @@ -426,7 +426,7 @@ - + @@ -438,7 +438,7 @@ - + @@ -448,7 +448,7 @@ - + @@ -458,7 +458,7 @@ - + @@ -468,7 +468,7 @@ - + @@ -478,7 +478,7 @@ - + @@ -487,7 +487,7 @@ - + @@ -497,7 +497,7 @@ - + @@ -507,7 +507,7 @@ - + @@ -517,7 +517,7 @@ - + @@ -528,7 +528,7 @@ - + diff --git a/internal/ir/view/testdata/state-entry.drawio.golden b/internal/ir/view/testdata/state-entry.drawio.golden index 44009624e6..7e3142a6b8 100644 --- a/internal/ir/view/testdata/state-entry.drawio.golden +++ b/internal/ir/view/testdata/state-entry.drawio.golden @@ -88,7 +88,7 @@ - + @@ -108,7 +108,7 @@ - + @@ -118,7 +118,7 @@ - + @@ -127,7 +127,7 @@ - + @@ -137,7 +137,7 @@ - + @@ -147,7 +147,7 @@ - + @@ -156,7 +156,7 @@ - + @@ -165,7 +165,7 @@ - + @@ -175,7 +175,7 @@ - + diff --git a/internal/ir/view/testdata/state.drawio.golden b/internal/ir/view/testdata/state.drawio.golden index 7e5bb125d5..dfb6726c0f 100644 --- a/internal/ir/view/testdata/state.drawio.golden +++ b/internal/ir/view/testdata/state.drawio.golden @@ -43,7 +43,7 @@ - + @@ -52,7 +52,7 @@ - + @@ -62,7 +62,7 @@ - + @@ -71,7 +71,7 @@ - + @@ -80,8 +80,8 @@ - - + + @@ -90,7 +90,7 @@ - + diff --git a/internal/ir/view/testdata/tree-edges.drawio.golden b/internal/ir/view/testdata/tree-edges.drawio.golden index 568e6536af..5c85511a87 100644 --- a/internal/ir/view/testdata/tree-edges.drawio.golden +++ b/internal/ir/view/testdata/tree-edges.drawio.golden @@ -188,54 +188,54 @@ - + - + - + - + - - + + - - + + - + - - + + - + - - - - + + + + @@ -243,12 +243,12 @@ - + - - + + @@ -257,7 +257,7 @@ - + @@ -267,7 +267,7 @@ - + @@ -294,7 +294,7 @@ - + @@ -304,36 +304,36 @@ - + - + - + - + - + - + - - + + @@ -342,36 +342,36 @@ - + - - + + - + - - + + - + - - + + @@ -381,25 +381,25 @@ - + - - - - + + + + - + - + @@ -410,12 +410,12 @@ - + - + @@ -428,7 +428,7 @@ - + @@ -438,12 +438,12 @@ - + - + @@ -454,7 +454,7 @@ - + @@ -465,12 +465,12 @@ - + - + @@ -479,7 +479,7 @@ - + @@ -490,47 +490,47 @@ - + - + - + - + - - + + - + - - + + - + @@ -540,12 +540,12 @@ - + - - + + diff --git a/internal/ir/view/testdata/tree.drawio.golden b/internal/ir/view/testdata/tree.drawio.golden index 259ea9dd4c..442ba659a0 100644 --- a/internal/ir/view/testdata/tree.drawio.golden +++ b/internal/ir/view/testdata/tree.drawio.golden @@ -58,37 +58,37 @@ - + - + - + - + - + - + - + diff --git a/internal/ir/view/testdata/typed-action.drawio.golden b/internal/ir/view/testdata/typed-action.drawio.golden index 6c7440fab5..5632d41340 100644 --- a/internal/ir/view/testdata/typed-action.drawio.golden +++ b/internal/ir/view/testdata/typed-action.drawio.golden @@ -28,7 +28,7 @@ - + @@ -38,7 +38,7 @@ - + diff --git a/internal/ir/view/testdata/typed-state.drawio.golden b/internal/ir/view/testdata/typed-state.drawio.golden index 5d0aa47c99..bffebdadbe 100644 --- a/internal/ir/view/testdata/typed-state.drawio.golden +++ b/internal/ir/view/testdata/typed-state.drawio.golden @@ -28,7 +28,7 @@ - + @@ -38,7 +38,7 @@ - + @@ -47,7 +47,7 @@ - + diff --git a/internal/ir/view/testdata/variation-interconnection.drawio.golden b/internal/ir/view/testdata/variation-interconnection.drawio.golden index 447704e67c..a14b35f59c 100644 --- a/internal/ir/view/testdata/variation-interconnection.drawio.golden +++ b/internal/ir/view/testdata/variation-interconnection.drawio.golden @@ -33,7 +33,7 @@ - + diff --git a/internal/ir/view/testdata/variation-mixed.drawio.golden b/internal/ir/view/testdata/variation-mixed.drawio.golden index f61e78609e..d5e6faaeeb 100644 --- a/internal/ir/view/testdata/variation-mixed.drawio.golden +++ b/internal/ir/view/testdata/variation-mixed.drawio.golden @@ -48,7 +48,7 @@ - + @@ -57,37 +57,37 @@ - + - + - + - + - + - + - + diff --git a/internal/ir/view/testdata/variation-tree.drawio.golden b/internal/ir/view/testdata/variation-tree.drawio.golden index 7ec012a79b..cf2fd64ebd 100644 --- a/internal/ir/view/testdata/variation-tree.drawio.golden +++ b/internal/ir/view/testdata/variation-tree.drawio.golden @@ -53,17 +53,17 @@ - + - + - + @@ -74,22 +74,22 @@ - + - + - + - +