ea 0.6.90 → 0.6.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e78b8830cfb779be7d7724d11c984d11de76c2220aaae41502515f156e03aeca
4
- data.tar.gz: d694be35c46f90866280700653aa35af66da37e9e3ec9bcf0724805b947550b0
3
+ metadata.gz: cf0f3e11888e4492386de976f97e4024e39d9dbc95083a5b184c0fb25d8cfead
4
+ data.tar.gz: 467687628f21bf50264c0210de75e2fad5013a14d7f2a1572d65dfb218429052
5
5
  SHA512:
6
- metadata.gz: 86c6dc4296a5c63c074178cdb01f19b171403e895b02dfb6e9897da9db87288a143228a3a0d7631953ddcf19ce2199a3060440fbd7472c472507af952206496c
7
- data.tar.gz: f0a27398ba13e4b352ccda7e3f810485577f5e2ac5154f2a4b43ab276ae6c2778877318f5c0c58e9ce92caa95ce2e27d10b11e829785cf61bb916fc1ac7bbccc
6
+ metadata.gz: 67a177d6e826985a3526c63bae7ed1f10e55b51ca97ec1507e5cb2f89f309b789f734c27cd41b678777e3ea72cb730a44485799972c3bbab916dedfd51f404c5
7
+ data.tar.gz: 55d5d873894f3e26fb786a71efaab326ecd4df2d16d167bf3dc7158e1775e139f9a9c2096cd79c5ae136315421c1d19156320d1c895837d691ecd7a97e772a2a
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Sources
5
+ module Qea
6
+ class DiagramBuilder
7
+ # Internal geometry for choosing the facing edges of stored routes.
8
+ module Routing
9
+ private
10
+
11
+ # Keep a vertical tree trunk whose bends still fit both boxes
12
+ # and the open gap; the closest facing edges need not share its x.
13
+ def preserve_stored_tree?(points, link_row, connector, src, tgt)
14
+ return false unless connector.connector_type == "Aggregation" && points.size == 4
15
+
16
+ style = DiagramStyleParser.parse(link_row.style)
17
+ return false unless style[:tree] == "V" && style[:lwidth] == "2"
18
+
19
+ tree_bends_fit?(points[1], points[-2], src, tgt)
20
+ end
21
+
22
+ def tree_bends_fit?(first, last, source, target)
23
+ first[0] != last[0] && first[1] == last[1] &&
24
+ within_vertical_gap?(first[1], source, target) &&
25
+ within_horizontal_span?(first, source) && within_horizontal_span?(last, target)
26
+ end
27
+
28
+ def within_vertical_gap?(height, source, target)
29
+ height < source.y - 1 && height > target.y + target.height + 1
30
+ end
31
+
32
+ def within_horizontal_span?(point, bounds)
33
+ point[0].between?(bounds.x, bounds.x + bounds.width)
34
+ end
35
+
36
+ # Returns a replacement 2-point route between the closest
37
+ # facing edges, or the original points when: the boxes overlap
38
+ # on both axes, the current route already docks those edges,
39
+ # or no aligned dock fits the edges' overlap range.
40
+ def facing_edge_route(points, src, tgt)
41
+ v_gap = v_dir = h_gap = h_dir = nil
42
+ if src.y >= tgt.y + tgt.height
43
+ v_gap = src.y - (tgt.y + tgt.height)
44
+ v_dir = [:t, :b]
45
+ elsif tgt.y >= src.y + src.height
46
+ v_gap = tgt.y - (src.y + src.height)
47
+ v_dir = [:b, :t]
48
+ end
49
+ if src.x >= tgt.x + tgt.width
50
+ h_gap = src.x - (tgt.x + tgt.width)
51
+ h_dir = [:l, :r]
52
+ elsif tgt.x >= src.x + src.width
53
+ h_gap = tgt.x - (tgt.x + tgt.width)
54
+ h_dir = [:r, :l]
55
+ end
56
+ return points if v_gap.nil? && h_gap.nil?
57
+
58
+ if !v_gap.nil? && (h_gap.nil? || v_gap <= h_gap)
59
+ src_edge, tgt_edge = v_dir
60
+ else
61
+ src_edge, tgt_edge = h_dir
62
+ end
63
+ return points if docks_edges?(points, src, src_edge, tgt, tgt_edge)
64
+
65
+ if %i[t b].include?(src_edge)
66
+ lo = [src.x, tgt.x].max
67
+ hi = [src.x + src.width, tgt.x + tgt.width].min
68
+ return points if lo > hi
69
+
70
+ x = points.first[0].clamp(lo, hi)
71
+ [[x, src_edge == :t ? src.y : src.y + src.height],
72
+ [x, tgt_edge == :t ? tgt.y : tgt.y + tgt.height]]
73
+ else
74
+ lo = [src.y, tgt.y].max
75
+ hi = [src.y + src.height, tgt.y + tgt.height].min
76
+ return points if lo > hi
77
+
78
+ y = points.first[1].clamp(lo, hi)
79
+ [[src_edge == :l ? src.x : src.x + src.width, y],
80
+ [tgt_edge == :l ? tgt.x : tgt.x + tgt.width, y]]
81
+ end
82
+ end
83
+
84
+ def docks_edges?(points, src, src_edge, tgt, tgt_edge)
85
+ on_edge?(points.first, src, src_edge) && on_edge?(points.last, tgt, tgt_edge)
86
+ end
87
+
88
+ def on_edge?(pt, b, edge, tol = 2)
89
+ x, y = pt
90
+ case edge
91
+ when :l then (x - b.x).abs <= tol && y.between?(b.y - tol, b.y + b.height + tol)
92
+ when :r then (x - (b.x + b.width)).abs <= tol && y.between?(b.y - tol, b.y + b.height + tol)
93
+ when :t then (y - b.y).abs <= tol && x.between?(b.x - tol, b.x + b.width + tol)
94
+ else (y - (b.y + b.height)).abs <= tol && x.between?(b.x - tol, b.x + b.width + tol)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -10,6 +10,10 @@ module Ea
10
10
  # DiagramConnectors (including pixel coordinates and parsed
11
11
  # styles).
12
12
  class DiagramBuilder
13
+ autoload :Routing, "ea/sources/qea/diagram_builder/routing"
14
+ include Routing
15
+ private_constant :Routing
16
+
13
17
  attr_reader :database
14
18
 
15
19
  # Generalizations whose EA CustomProperties carry
@@ -643,9 +647,11 @@ module Ea
643
647
  # EDGE=2 routes are excluded; they are already exact.
644
648
  if %w[Association Aggregation].include?(connector.connector_type) &&
645
649
  edge_out != 2
646
- points = facing_edge_route(points,
647
- bounds_from_rect(source_placement),
648
- bounds_from_rect(target_placement))
650
+ src = bounds_from_rect(source_placement)
651
+ tgt = bounds_from_rect(target_placement)
652
+ unless preserve_stored_tree?(points, link_row, connector, src, tgt)
653
+ points = facing_edge_route(points, src, tgt)
654
+ end
649
655
  # A width-2 Aggregation that keeps its stored bends is
650
656
  # docked like a Generalization one.
651
657
  if connector.connector_type == "Aggregation" &&
@@ -661,68 +667,6 @@ module Ea
661
667
  end
662
668
  end
663
669
 
664
- # Returns a replacement 2-point route between the closest
665
- # facing edges, or the original points when: the boxes overlap
666
- # on both axes, the current route already docks those edges,
667
- # or no aligned dock fits the edges' overlap range.
668
- def facing_edge_route(points, src, tgt)
669
- v_gap = v_dir = h_gap = h_dir = nil
670
- if src.y >= tgt.y + tgt.height
671
- v_gap = src.y - (tgt.y + tgt.height)
672
- v_dir = [:t, :b]
673
- elsif tgt.y >= src.y + src.height
674
- v_gap = tgt.y - (src.y + src.height)
675
- v_dir = [:b, :t]
676
- end
677
- if src.x >= tgt.x + tgt.width
678
- h_gap = src.x - (tgt.x + tgt.width)
679
- h_dir = [:l, :r]
680
- elsif tgt.x >= src.x + src.width
681
- h_gap = tgt.x - (tgt.x + tgt.width)
682
- h_dir = [:r, :l]
683
- end
684
- return points if v_gap.nil? && h_gap.nil?
685
-
686
- if !v_gap.nil? && (h_gap.nil? || v_gap <= h_gap)
687
- src_edge, tgt_edge = v_dir
688
- else
689
- src_edge, tgt_edge = h_dir
690
- end
691
- return points if docks_edges?(points, src, src_edge, tgt, tgt_edge)
692
-
693
- if %i[t b].include?(src_edge)
694
- lo = [src.x, tgt.x].max
695
- hi = [src.x + src.width, tgt.x + tgt.width].min
696
- return points if lo > hi
697
-
698
- x = points.first[0].clamp(lo, hi)
699
- [[x, src_edge == :t ? src.y : src.y + src.height],
700
- [x, tgt_edge == :t ? tgt.y : tgt.y + tgt.height]]
701
- else
702
- lo = [src.y, tgt.y].max
703
- hi = [src.y + src.height, tgt.y + tgt.height].min
704
- return points if lo > hi
705
-
706
- y = points.first[1].clamp(lo, hi)
707
- [[src_edge == :l ? src.x : src.x + src.width, y],
708
- [tgt_edge == :l ? tgt.x : tgt.x + tgt.width, y]]
709
- end
710
- end
711
-
712
- def docks_edges?(points, src, src_edge, tgt, tgt_edge)
713
- on_edge?(points.first, src, src_edge) && on_edge?(points.last, tgt, tgt_edge)
714
- end
715
-
716
- def on_edge?(pt, b, edge, tol = 2)
717
- x, y = pt
718
- case edge
719
- when :l then (x - b.x).abs <= tol && y.between?(b.y - tol, b.y + b.height + tol)
720
- when :r then (x - (b.x + b.width)).abs <= tol && y.between?(b.y - tol, b.y + b.height + tol)
721
- when :t then (y - b.y).abs <= tol && x.between?(b.x - tol, b.x + b.width + tol)
722
- else (y - (b.y + b.height)).abs <= tol && x.between?(b.x - tol, b.x + b.width + tol)
723
- end
724
- end
725
-
726
670
  # A tree Path is current when its bend height still falls
727
671
  # within the source element's y-range (the exit height EA
728
672
  # records); a bend outside the element is stale and EA
data/lib/ea/version.rb CHANGED
@@ -4,5 +4,5 @@ module Ea
4
4
  # Gem release version. Extracted to its own file so the
5
5
  # `gem-release` tool's `gem bump` can find and update it via the
6
6
  # standard `lib/<gem>/version.rb` convention.
7
- VERSION = "0.6.90"
7
+ VERSION = "0.6.91"
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ea
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.90
4
+ version: 0.6.91
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-10-14 00:00:00.000000000 Z
11
+ date: 2026-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -815,6 +815,7 @@ files:
815
815
  - lib/ea/sources/qea/connector_relationship_map.rb
816
816
  - lib/ea/sources/qea/context_diagram_support.rb
817
817
  - lib/ea/sources/qea/diagram_builder.rb
818
+ - lib/ea/sources/qea/diagram_builder/routing.rb
818
819
  - lib/ea/sources/qea/diagram_style_parser.rb
819
820
  - lib/ea/sources/qea/id_normalizer.rb
820
821
  - lib/ea/sources/qea/instance_builder.rb