ea 0.6.10 → 0.6.12

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: eed940fe5d30af46cc24f8945771cfa2ae1b4ccafaf5574a343b0b361241c7fb
4
- data.tar.gz: f072e8063bfd37d5f1547bec70e72fcc3cac33a2ae0fdfff5a85e035885a4ab2
3
+ metadata.gz: 9ab8e167be62620122df9b9f06f67164d94f5843811f2e3d41069095b7225d1d
4
+ data.tar.gz: 512ab6826980ce4625c31816a4efa7d55bee0f37a12a4e74cd2fa0ba430f0cdf
5
5
  SHA512:
6
- metadata.gz: a202d8da9feef0a2f2908780873dab759090e74fc6c5bd9c313e443f3e33659a871b2492122fd9b39b37528e4f5f05f30e4439b88e72646c370a0045a66b2ecc
7
- data.tar.gz: 56d7264d3167c6367a753254a4815e42e3ed029cc1a39ae0d1d85f2baebf1fde14a0cf2a1b0008981a1196474632eafcc1c763cfac72ff8913e10dcb5096154f
6
+ metadata.gz: 52b93143d5900ecd0ffa27abb452b1b2ce3ac1005e97cc7e7cea20d0ed98f0000e458b18453dd3dc89a02dd0e8cdf3e1de806c917b239de558bcf4e2a46b9021
7
+ data.tar.gz: 13b265e34b8d6e0358f0116f0a0a41878231ea7f0aba212553038f14e936fd41a646d4b56145ebc6058b07da90c97e66dabab2ad9b1e256aa2f7c2e184843867
@@ -377,7 +377,10 @@ module Ea
377
377
  element_edge_point(target_placement, :target, edge_out)
378
378
 
379
379
  intermediate = intermediate_waypoints(link_row)
380
- if intermediate.any?
380
+ if tree_route?(edge_out, intermediate)
381
+ points = tree_waypoints(source_placement, target_placement,
382
+ intermediate.first)
383
+ elsif intermediate.any?
381
384
  points = [source_point, *intermediate, target_point]
382
385
  elsif source_port || target_port
383
386
  # Exact ports are known — the SX/SY bend heuristics in
@@ -392,6 +395,26 @@ module Ea
392
395
  end
393
396
  end
394
397
 
398
+ # EA's tree-style routing (Geometry EDGE=2 with a single Path
399
+ # bend): the visible line leaves the SOURCE's right edge at
400
+ # the bend's y, runs horizontally to the bend x, then
401
+ # vertically to the target's facing edge — replacing the
402
+ # ray-cast ports entirely. Verified against the
403
+ # CityObjectGroup reference (parent + groupMember lines).
404
+ def tree_route?(edge_out, intermediate)
405
+ edge_out == 2 && intermediate.size == 1
406
+ end
407
+
408
+ def tree_waypoints(source_placement, target_placement, bend)
409
+ src = bounds_from_rect(source_placement)
410
+ tgt = bounds_from_rect(target_placement)
411
+ bend_x = bend[0]
412
+ source_point = [src.x + src.width, bend[1]]
413
+ going_up = tgt.y + tgt.height <= src.y
414
+ target_y = going_up ? tgt.y + tgt.height : tgt.y
415
+ [source_point, [bend_x, bend[1]], [bend_x, target_y]]
416
+ end
417
+
395
418
  # Absolute connection point EA docks the connector's visible
396
419
  # endpoint at, derived from the Geometry SX/SY (source) and
397
420
  # EX/EY (target) offsets. The offsets are measured inward from
@@ -41,7 +41,8 @@ module Ea
41
41
  # anchor - [x, y] of the connector endpoint
42
42
  # connector - the DiagramConnector (for relationship lookup)
43
43
  # end_kind - :source or :target
44
- def texts(text_box:, mult_box:, anchor:, connector:, end_kind:)
44
+ def texts(text_box:, mult_box:, anchor:, connector:, end_kind:,
45
+ tree: false)
45
46
  from_property, role, mult = role_and_multiplicity(connector, end_kind)
46
47
  if role_empty?(role) && mult_empty?(mult)
47
48
  other_from_prop, other_role, other_mult = role_and_multiplicity(connector,
@@ -56,6 +57,10 @@ module Ea
56
57
 
57
58
  text_pos = position_at(text_box, anchor)
58
59
  mult_pos = position_at(mult_box, anchor) || text_pos
60
+ if tree && zero_offset?(text_box, mult_box)
61
+ text_pos, mult_pos = tree_positions(end_kind, anchor, role,
62
+ text_pos, mult_pos)
63
+ end
59
64
  show_property = property_label?(connector)
60
65
 
61
66
  build_texts(role:, mult:, standalone:,
@@ -64,6 +69,30 @@ module Ea
64
69
 
65
70
  private
66
71
 
72
+ # EA's tree-route label clusters (verified against
73
+ # EA-published reference SVGs): source-end pairs stack at
74
+ # the exit point (role +3/-23, mult +3/0); target-end pairs
75
+ # sit astride the trunk — the mult starts at trunk+8 and
76
+ # the role's right edge meets it (role_x = trunk+8-width).
77
+ def zero_offset?(text_box, mult_box)
78
+ [text_box, mult_box].compact.all? do |b|
79
+ b["ox"].to_i.zero? && b["oy"].to_i.zero?
80
+ end
81
+ end
82
+
83
+ def tree_positions(end_kind, anchor, role, text_pos, mult_pos)
84
+ if end_kind == :source
85
+ [[anchor[0] + 3, anchor[1] - 23],
86
+ [anchor[0] + 3, anchor[1]]]
87
+ else
88
+ width = Ea::Fonts::Metrics.text_length(
89
+ role.to_s, font_size, family: font_family
90
+ ) || role.to_s.length * 6
91
+ [[anchor[0] + 8 - width, text_pos ? text_pos[1] : anchor[1]],
92
+ [anchor[0] + 8, mult_pos ? mult_pos[1] : anchor[1]]]
93
+ end
94
+ end
95
+
67
96
  def build_texts(role:, mult:, standalone:, text_pos:, mult_pos:,
68
97
  show_property:)
69
98
  if role && !role.empty? && text_pos
@@ -72,6 +72,7 @@ module Ea
72
72
  source_pt = points.first
73
73
  target_pt = points.last
74
74
  boxes = connector.label_boxes || {}
75
+ tree = tree_shaped?(points)
75
76
 
76
77
  src_tb, src_mb = end_boxes(boxes, :llt, :llb) ||
77
78
  default_label_boxes(points, :source)
@@ -81,13 +82,25 @@ module Ea
81
82
  texts = []
82
83
  end_renderer.texts(text_box: src_tb, mult_box: src_mb,
83
84
  anchor: source_pt, connector: connector,
84
- end_kind: :source).each { |t| texts << t }
85
- end_renderer.texts(text_box: tgt_tb, mult_box: tgt_mb,
85
+ end_kind: :source, tree: tree && tree[:source]).each { |t| texts << t }
86
+ end_renderer.texts(text_box: tgt_tb,
87
+ mult_box: tgt_mb,
86
88
  anchor: target_pt, connector: connector,
87
- end_kind: :target).each { |t| texts << t }
89
+ end_kind: :target, tree: tree && tree[:target]).each { |t| texts << t }
88
90
  texts
89
91
  end
90
92
 
93
+ # EA tree routes are a perfect L: source-exit horizontal into
94
+ # the corner, vertical trunk into the target dock. Returns
95
+ # per-end flags when the connector matches, else nil.
96
+ def tree_shaped?(points)
97
+ return nil unless points.size == 3
98
+ return nil unless points[0][1] == points[1][1] &&
99
+ points[1][0] == points[2][0]
100
+
101
+ { source: true, target: true }
102
+ end
103
+
91
104
  def end_boxes(boxes, text_key, mult_key)
92
105
  return nil if boxes[text_key].nil? && boxes[mult_key].nil?
93
106
 
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.10"
7
+ VERSION = "0.6.12"
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.10
4
+ version: 0.6.12
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-09-29 00:00:00.000000000 Z
11
+ date: 2026-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model