ea 0.6.101 → 0.6.102
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c453170a8a782786ce0a1061623c8de93ed75536228bb99d9b6c1857163f58f3
|
|
4
|
+
data.tar.gz: 19c5dc1e01e47508e51dfc87add4cd24059b4035b83ed45c5aa98d46d4edcb8b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 26fbc91c4d39c834e0e9a19c443501953b487210ea88922be813bf167dfb56c6d2cc55cb3238441f58a08a6cd7511560e495f787a05a566466e9e7c5f45b06b0
|
|
7
|
+
data.tar.gz: 79f6d211068cf179e2fee6eea24e2e0ae60385be826db2254dcb6ce3d3aab345d68c743f529d430b242f8ea0cc3fdda7425e6cf880cf984abf1b7aeec145d74c
|
|
@@ -23,6 +23,16 @@ module Ea
|
|
|
23
23
|
set_stored_ray_origins(model, source, target, geom)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
def mark_default_square_ray(model, link_row, geom, context)
|
|
27
|
+
style = model.style.to_h
|
|
28
|
+
return model if context || !link_row.path.to_s.empty? || model.waypoints.size != 2
|
|
29
|
+
return model unless style[:mode] == "3" && style[:tree] == "OS" && style[:lwidth] == "2"
|
|
30
|
+
return model unless geom[:sx].nil? && geom[:sy].nil? && [geom[:ex], geom[:ey]] == [0, 0]
|
|
31
|
+
|
|
32
|
+
model.style = style.merge(default_square_ray: true)
|
|
33
|
+
model
|
|
34
|
+
end
|
|
35
|
+
|
|
26
36
|
# A Mode 2 Generalization whose stored Path is a horizontal jog
|
|
27
37
|
# between vertically separated boxes that overlap in x is EA's
|
|
28
38
|
# auto-route: one vertical ray at the overlap midpoint plus SX.
|
|
@@ -100,30 +110,39 @@ module Ea
|
|
|
100
110
|
return model unless stored_ray_candidate?(model, link_row, geom)
|
|
101
111
|
|
|
102
112
|
source, target = stored_ray_boxes(link_row, diagram_row)
|
|
103
|
-
|
|
113
|
+
allowed = if normalized_port_anchors?(model)
|
|
114
|
+
normalized_level_ray?(model, source, target, geom)
|
|
115
|
+
else
|
|
116
|
+
stored_ray_gap?(source, target, model.style[:mode], geom[:edge])
|
|
117
|
+
end
|
|
118
|
+
return model unless allowed
|
|
104
119
|
|
|
105
120
|
set_stored_ray_origins(model, source, target, geom)
|
|
106
121
|
end
|
|
107
122
|
|
|
108
|
-
# An empty-Path Mode 3 Association
|
|
109
|
-
#
|
|
110
|
-
#
|
|
123
|
+
# An empty-Path Mode 3 Association follows the line between its
|
|
124
|
+
# stored endpoint origins; an omitted offset defaults to the center.
|
|
125
|
+
# The target origin must lie inside its own stroked outline.
|
|
111
126
|
def association_stored_ray(model, link_row, diagram_row, geom, context)
|
|
112
127
|
return model if context
|
|
113
128
|
return model unless association_ray_candidate?(model, link_row)
|
|
114
129
|
|
|
115
130
|
source, target = stored_ray_boxes(link_row, diagram_row)
|
|
116
|
-
|
|
131
|
+
width = association_outline_width(model, link_row, diagram_row)
|
|
132
|
+
origins = association_ray_origins(source, target, geom, width)
|
|
117
133
|
return model unless origins
|
|
118
134
|
|
|
119
|
-
model.waypoints = port_waypoints(model)
|
|
135
|
+
model.waypoints = port_waypoints(model, origins)
|
|
120
136
|
model.source_anchor, model.target_anchor = origins
|
|
121
137
|
model.style = model.style.to_h.merge(stored_association_ray: true, association_ray_outline: true)
|
|
138
|
+
if geom[:edge] == 1 && !inside_box?(origins.first, grown_bounds(source, width == "2" ? 1 : 0))
|
|
139
|
+
model.style[:stored_top_dock] = true
|
|
140
|
+
end
|
|
122
141
|
model
|
|
123
142
|
end
|
|
124
143
|
|
|
125
|
-
def port_waypoints(model)
|
|
126
|
-
[model.source_port, model.target_port].map do |point|
|
|
144
|
+
def port_waypoints(model, origins)
|
|
145
|
+
[model.source_port || origins.first, model.target_port || origins.last].map do |point|
|
|
127
146
|
Ea::Model::Waypoint.new(position: point)
|
|
128
147
|
end
|
|
129
148
|
end
|
|
@@ -135,12 +154,41 @@ module Ea
|
|
|
135
154
|
origins = [stored_ray_origin(source, geom[:sx], geom[:sy]),
|
|
136
155
|
stored_ray_origin(target, geom[:ex], geom[:ey])]
|
|
137
156
|
boxes = [source, target].map { |box| grown_bounds(box, outline) }
|
|
138
|
-
|
|
139
|
-
return unless inside && origins.first != origins.last
|
|
157
|
+
return unless origins.first != origins.last && association_origin_pair?(origins, boxes, width, geom[:edge])
|
|
140
158
|
|
|
141
159
|
origins if width == "2" || sub_pixel_safe_origins?(origins, [source, target] + boxes)
|
|
142
160
|
end
|
|
143
161
|
|
|
162
|
+
# An external source origin is a virtual point on the saved ray.
|
|
163
|
+
# It is usable only when that segment actually crosses the source.
|
|
164
|
+
def association_origin_pair?(origins, boxes, width, edge)
|
|
165
|
+
return false unless inside_box?(origins.last, boxes.last)
|
|
166
|
+
return true if inside_box?(origins.first, boxes.first)
|
|
167
|
+
|
|
168
|
+
return segment_crosses_box?(origins.first, origins.last, boxes.first) if width == "2"
|
|
169
|
+
return false unless edge == 1
|
|
170
|
+
|
|
171
|
+
source = boxes.first
|
|
172
|
+
top = Ea::Model::Bounds.new(x: source.x, y: source.y, width: source.width, height: 0)
|
|
173
|
+
segment_crosses_box?(origins.first, origins.last, top)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def segment_crosses_box?(first, last, box)
|
|
177
|
+
interval = [0.0, 1.0]
|
|
178
|
+
axes = [[first.x, last.x, box.x, box.x + box.width],
|
|
179
|
+
[first.y, last.y, box.y, box.y + box.height]]
|
|
180
|
+
axes.all? do |origin, finish, low, high|
|
|
181
|
+
if origin == finish
|
|
182
|
+
origin.between?(low, high)
|
|
183
|
+
else
|
|
184
|
+
times = [(low - origin).to_f / (finish - origin),
|
|
185
|
+
(high - origin).to_f / (finish - origin)].minmax
|
|
186
|
+
interval = [[interval.first, times.first].max, [interval.last, times.last].min]
|
|
187
|
+
interval.first <= interval.last
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
144
192
|
def grown_bounds(bounds, amount)
|
|
145
193
|
Ea::Model::Bounds.new(x: bounds.x - amount, y: bounds.y - amount,
|
|
146
194
|
width: bounds.width + 2 * amount,
|
|
@@ -149,8 +197,21 @@ module Ea
|
|
|
149
197
|
|
|
150
198
|
def association_ray_candidate?(model, link_row)
|
|
151
199
|
model.connector_type == "Association" && link_row.path.to_s.empty? &&
|
|
152
|
-
model.
|
|
153
|
-
association_ray_style?(model.style.to_h)
|
|
200
|
+
model.source_anchor && model.target_anchor &&
|
|
201
|
+
(model.source_port || model.target_port) && association_ray_style?(model.style.to_h)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# A thin connector still meets the outer stroke of explicitly
|
|
205
|
+
# bordered elements. Ambiguous placements must agree on that border.
|
|
206
|
+
def association_outline_width(model, link_row, diagram_row)
|
|
207
|
+
width = model.style[:lwidth]
|
|
208
|
+
return width if width == "2"
|
|
209
|
+
|
|
210
|
+
connector = database.find_connector(link_row.connectorid)
|
|
211
|
+
ids = [connector.start_object_id, connector.end_object_id]
|
|
212
|
+
placements = database.diagram_objects_for(diagram_row.diagram_id)
|
|
213
|
+
borders = placements.select { |placement| ids.include?(placement.ea_object_id) }
|
|
214
|
+
borders.all? { |placement| DiagramStyleParser.parse(placement.objectstyle)[:lwth] == "2" } ? "2" : width
|
|
154
215
|
end
|
|
155
216
|
|
|
156
217
|
def association_ray_style?(style)
|
|
@@ -263,7 +324,21 @@ module Ea
|
|
|
263
324
|
def stored_ray_candidate?(model, link_row, geom)
|
|
264
325
|
%w[Generalization Aggregation].include?(model.connector_type) &&
|
|
265
326
|
model.waypoints.size == 2 && stored_ray_style?(model.style, link_row) &&
|
|
266
|
-
stored_ray_geometry?(model, geom)
|
|
327
|
+
stored_ray_geometry?(model, geom)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Boundary-port rounding can move a computed jog off a level saved
|
|
331
|
+
# ray. Equal stored origin rows specify the line before clipping.
|
|
332
|
+
def normalized_level_ray?(model, source, target, geom)
|
|
333
|
+
style = model.style.to_h
|
|
334
|
+
return false unless style[:mode] == "3" && style[:lwidth] == "2" &&
|
|
335
|
+
horizontal_ray_gap?(source, target)
|
|
336
|
+
|
|
337
|
+
origins = [stored_ray_origin(source, geom[:sx], geom[:sy]),
|
|
338
|
+
stored_ray_origin(target, geom[:ex], geom[:ey])]
|
|
339
|
+
boxes = [source, target].map { |box| grown_bounds(box, 1) }
|
|
340
|
+
origins.first.y == origins.last.y &&
|
|
341
|
+
origins.zip(boxes).all? { |origin, box| inside_box?(origin, box) }
|
|
267
342
|
end
|
|
268
343
|
|
|
269
344
|
def stored_ray_style?(style, link_row)
|
|
@@ -436,7 +436,8 @@ module Ea
|
|
|
436
436
|
model = mode2_overlap_ray(model, link_row, diagram_row, geom, context)
|
|
437
437
|
model = association_stored_ray(model, link_row, diagram_row, geom, context)
|
|
438
438
|
model = correct_stored_ray_origins(model, link_row, diagram_row, geom, context)
|
|
439
|
-
overlap_ray_origins(model, link_row, diagram_row, geom, context)
|
|
439
|
+
model = overlap_ray_origins(model, link_row, diagram_row, geom, context)
|
|
440
|
+
mark_default_square_ray(model, link_row, geom, context)
|
|
440
441
|
end
|
|
441
442
|
|
|
442
443
|
# Ray origin for one connector end: the element's center
|
|
@@ -46,7 +46,8 @@ module Ea
|
|
|
46
46
|
original = clipped_pairs(bounds, anchors)
|
|
47
47
|
unless stroke_outline?(connector, bounds) || overlap_ray?(connector) ||
|
|
48
48
|
bordered_outline?(connector, diagram, [source_ref, target_ref], bounds)
|
|
49
|
-
|
|
49
|
+
pairs = default_square_pairs(connector, points, source_bounds, target_bounds, original)
|
|
50
|
+
return stored_top_pairs(connector, source_bounds, pairs)
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
# EA docks these markers on the outer edge of the 2px box stroke.
|
|
@@ -55,9 +56,48 @@ module Ea
|
|
|
55
56
|
width: box.width + 2, height: box.height + 2)
|
|
56
57
|
end
|
|
57
58
|
candidate = clipped_pairs(outline, anchors)
|
|
58
|
-
forward_route?(original, candidate)
|
|
59
|
+
expanded = forward_route?(original, candidate)
|
|
60
|
+
pairs = expanded ? candidate : original
|
|
61
|
+
target = expanded ? outline.last : target_bounds
|
|
62
|
+
pairs = default_square_pairs(connector, points, source_bounds, target, pairs)
|
|
63
|
+
stored_top_pairs(connector, expanded ? outline.first : source_bounds, pairs)
|
|
59
64
|
end
|
|
60
65
|
|
|
66
|
+
# EDGE=1 explicitly seats an external source ray on the top edge;
|
|
67
|
+
# its first contact can instead be the bottom when its origin is below.
|
|
68
|
+
def stored_top_pairs(connector, source, pairs)
|
|
69
|
+
return pairs unless connector.connector_type == "Association" &&
|
|
70
|
+
connector.style.to_h[:stored_top_dock] == true
|
|
71
|
+
|
|
72
|
+
first = connector.source_anchor
|
|
73
|
+
last = connector.target_anchor
|
|
74
|
+
return pairs unless first && last && first.y != last.y
|
|
75
|
+
|
|
76
|
+
ratio = (source.y - first.y).to_f / (last.y - first.y)
|
|
77
|
+
x_position = first.x + ratio * (last.x - first.x)
|
|
78
|
+
return pairs unless ratio.between?(0, 1) &&
|
|
79
|
+
x_position.between?(source.x, source.x + source.width)
|
|
80
|
+
|
|
81
|
+
proposed = [[x_position.floor, source.y], pairs.last]
|
|
82
|
+
forward_route?(pairs, proposed) ? proposed : pairs
|
|
83
|
+
end
|
|
84
|
+
private_class_method :stored_top_pairs
|
|
85
|
+
|
|
86
|
+
# A square ray with an omitted source offset keeps its chosen side
|
|
87
|
+
# edge and projects that end to the clipped target's horizontal row.
|
|
88
|
+
def default_square_pairs(connector, points, source, target, pairs)
|
|
89
|
+
return pairs unless connector.style.to_h[:default_square_ray] == true
|
|
90
|
+
return pairs unless points.first[1] == points.last[1] &&
|
|
91
|
+
on_side_edge?(points.first, source) && on_side_edge?(pairs.last, target)
|
|
92
|
+
|
|
93
|
+
first = [points.first[0], pairs.last[1]]
|
|
94
|
+
return pairs unless on_side_edge?(first, source)
|
|
95
|
+
|
|
96
|
+
proposed = [first, pairs.last]
|
|
97
|
+
forward_route?(points, proposed) ? proposed : pairs
|
|
98
|
+
end
|
|
99
|
+
private_class_method :default_square_pairs
|
|
100
|
+
|
|
61
101
|
# A horizontal lateral tree the QEA builder derived as one level
|
|
62
102
|
# line (internal style flag) keeps it between the facing side edges.
|
|
63
103
|
def flush_lateral_line?(connector, points, source, target)
|
data/lib/ea/version.rb
CHANGED