1 | import { findIndex } from "lodash/fp";
|
2 | import { getStartSideByOrientation } from "../geom-utils";
|
3 | import { DEFAULT_STUB_LENGTH } from "./edge";
|
4 | import { getOrientationOfHyperedgeStartPoint, getOrientationOfHyperedgeEndPoint, validateOrientation } from "./orientation";
|
5 | const INDEX_TO_DIMENSION = ["x", "y"];
|
6 | function getActiveOrientationIndexAndDimension(orientation) {
|
7 | const activeOrientationIndex = findIndex((orientationScalar) => orientationScalar !== 0, orientation);
|
8 | const activeOrientationDimension = INDEX_TO_DIMENSION[activeOrientationIndex];
|
9 | const otherOrientationDimension = activeOrientationDimension === "x"
|
10 | ? "y"
|
11 | : "x";
|
12 | return {
|
13 | activeOrientationIndex,
|
14 | activeOrientationDimension,
|
15 | otherOrientationDimension
|
16 | };
|
17 | }
|
18 | /**
|
19 | * calculateAllPoints for edges of type Elbow and Curved
|
20 | *
|
21 | * PathVisio-Java does not always specify all the points needed to draw edges
|
22 | * of type Elbow and Curved. Unless the user drags one or more of the
|
23 | * waypoints, PathVisio-Java will only specify the first and last points,
|
24 | * leaving implicit one or more additional points that are required to draw
|
25 | * the edge.
|
26 | *
|
27 | * Kaavio requires that a PvjsonEdge specifies ALL the points required for
|
28 | * drawing the edge, so this function calculates any implicit points required
|
29 | * to unambiguously specify an edge and returns the full set of points
|
30 | * (implicit points are made explicit).
|
31 | *
|
32 | * @param explicitPoints {Array}
|
33 | * @param [sourceEntity] {Object} entity from which the EDGE emanates
|
34 | * (never an Anchor)
|
35 | * @param [targetEntity] {Object} entity into which the EDGE terminates
|
36 | * (never an Anchor)
|
37 | * @return {Array} Full set of points required to render the edge
|
38 | */
|
39 | export function calculateAllPoints(explicitPoints, sourceEntity, targetEntity) {
|
40 | let firstPoint = explicitPoints[0];
|
41 | let lastPoint = explicitPoints[explicitPoints.length - 1];
|
42 | // NOTE: we need at least one of the first point or the last point to have a
|
43 | // valid orientation. If that's not the case already, we try setting it here,
|
44 | // based on other information available to us.
|
45 | if (!validateOrientation(firstPoint.orientation)) {
|
46 | if (firstPoint.hasOwnProperty("isAttachedTo")) {
|
47 | // It is correct to specify <PvjsonEdge> as the type for
|
48 | // sourceEntity/targetEntity when calculating the orientation of a point
|
49 | // attached to another edge below, because we get into there if neither
|
50 | // the first nor last point have a valid orientation. If a point is
|
51 | // attached to a SingleFreeNode, a Group or a GPML State, it would already
|
52 | // have a valid orientation calculated by this point, so the point must
|
53 | // be either attached to nothing or else attached to an edge.
|
54 | firstPoint.orientation = getOrientationOfHyperedgeStartPoint(sourceEntity, firstPoint, lastPoint);
|
55 | }
|
56 | else {
|
57 | firstPoint.orientation = [-1, 0];
|
58 | }
|
59 | }
|
60 | if (!validateOrientation(lastPoint.orientation)) {
|
61 | if (lastPoint.hasOwnProperty("isAttachedTo")) {
|
62 | // It is correct to specify <PvjsonEdge> as the type for
|
63 | // sourceEntity/targetEntity when calculating the orientation of a point
|
64 | // attached to another edge below, because we get into there if neither
|
65 | // the first nor last point have a valid orientation. If a point is
|
66 | // attached to a SingleFreeNode, a Group or a GPML State, it would already
|
67 | // have a valid orientation calculated by this point, so the point must
|
68 | // be either attached to nothing or else attached to an edge.
|
69 | lastPoint.orientation = getOrientationOfHyperedgeEndPoint(targetEntity, lastPoint, firstPoint);
|
70 | }
|
71 | else {
|
72 | const { x: x0, y: y0 } = firstPoint;
|
73 | const { x: x1, y: y1 } = lastPoint;
|
74 | const firstSide = getStartSideByOrientation(firstPoint.orientation);
|
75 | if (firstSide === "left") {
|
76 | if (x0 >= x1 && x0 < x1 + DEFAULT_STUB_LENGTH) {
|
77 | lastPoint.orientation = [1, 0];
|
78 | }
|
79 | else {
|
80 | lastPoint.orientation = [-1, 0];
|
81 | }
|
82 | }
|
83 | else if (firstSide === "right") {
|
84 | if (x0 + DEFAULT_STUB_LENGTH <= x1) {
|
85 | lastPoint.orientation = [1, 0];
|
86 | }
|
87 | else {
|
88 | lastPoint.orientation = [-1, 0];
|
89 | }
|
90 | }
|
91 | else {
|
92 | lastPoint.orientation = [-1, 0];
|
93 | }
|
94 | }
|
95 | }
|
96 | if (explicitPoints.length > 2) {
|
97 | return explicitPoints;
|
98 | }
|
99 | let startPoint;
|
100 | let endPoint;
|
101 | let endEntity;
|
102 | let pointOrderReversed;
|
103 | if (validateOrientation(firstPoint.orientation)) {
|
104 | pointOrderReversed = false;
|
105 | startPoint = firstPoint;
|
106 | endPoint = lastPoint;
|
107 | endEntity = targetEntity;
|
108 | }
|
109 | else if (validateOrientation(lastPoint.orientation)) {
|
110 | pointOrderReversed = true;
|
111 | startPoint = lastPoint;
|
112 | endPoint = firstPoint;
|
113 | endEntity = sourceEntity;
|
114 | }
|
115 | else {
|
116 | throw new Error(`Either first or last point (or both) should have a valid
|
117 | orientation by now in
|
118 | calculateAllPoints(
|
119 | ${JSON.stringify(explicitPoints)},
|
120 | ${JSON.stringify(sourceEntity)},
|
121 | ${JSON.stringify(targetEntity)}
|
122 | )`);
|
123 | }
|
124 | const startOrientation = startPoint.orientation;
|
125 | const endOrientation = endPoint.orientation;
|
126 | const vectorSumOrientation = [
|
127 | Math.sign(endPoint.x - startPoint.x),
|
128 | Math.sign(endPoint.y - startPoint.y)
|
129 | ];
|
130 | const { activeOrientationIndex: activeStartOrientationIndex, activeOrientationDimension: activeStartOrientationDimension, otherOrientationDimension: otherStartOrientationDimension } = getActiveOrientationIndexAndDimension(startOrientation);
|
131 | const { activeOrientationIndex: activeEndOrientationIndex, activeOrientationDimension: activeEndOrientationDimension, otherOrientationDimension: otherEndOrientationDimension } = getActiveOrientationIndexAndDimension(endOrientation);
|
132 | const pvjsonPoints = [];
|
133 | pvjsonPoints.push(startPoint);
|
134 | // Calculate intermediate data points, which are implicit.
|
135 | // Remember that this refers to the minimum number of points required to
|
136 | // define the path, so 3 points could mean this:
|
137 | //
|
138 | // -------------------*-------------------
|
139 | // | |
|
140 | // | |
|
141 | // * *
|
142 | //
|
143 | // or this:
|
144 | // *
|
145 | // |
|
146 | // |
|
147 | // -------------------*-------------------
|
148 | // |
|
149 | // |
|
150 | // *
|
151 | //
|
152 | // or several other possible configurations
|
153 | // NOTE: when an edge is connected to a SingleFreeNode or a Group (how about a State?),
|
154 | // PathVisio-Java will route the edge around the side from which the edge
|
155 | // emanates, if needed.
|
156 | // But when an edge is connected to another edge, PathVisio-Java
|
157 | // does not do any special re-routing for that connection.
|
158 | if (activeStartOrientationIndex === activeEndOrientationIndex) {
|
159 | // Start and end orientations are parallel, e.g.,
|
160 | // starts at right and ends on either right or left side, or
|
161 | // starts on top and ends on either top or bottom side.
|
162 | const activeOrientationIndex = activeStartOrientationIndex;
|
163 | const activeOrientationDimension = activeStartOrientationDimension;
|
164 | const otherOrientationDimension = otherStartOrientationDimension;
|
165 | const otherOrientationDimensionDisplacement = endPoint[otherOrientationDimension] -
|
166 | startPoint[otherOrientationDimension];
|
167 | if (startOrientation[activeOrientationIndex] ===
|
168 | vectorSumOrientation[activeOrientationIndex]) {
|
169 | // we don't have to avoid the start side
|
170 | pvjsonPoints[1] = {};
|
171 | pvjsonPoints[1][otherOrientationDimension] =
|
172 | startPoint[otherOrientationDimension] +
|
173 | otherOrientationDimensionDisplacement / 2;
|
174 | if (startOrientation[activeOrientationIndex] ===
|
175 | endOrientation[activeOrientationIndex]) {
|
176 | // *---
|
177 | // |
|
178 | // |
|
179 | // *
|
180 | // |
|
181 | // |
|
182 | // ---------------------*
|
183 | pvjsonPoints[1][activeOrientationDimension] =
|
184 | startPoint[activeOrientationDimension] +
|
185 | startOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH;
|
186 | }
|
187 | else {
|
188 | // *-------------------------
|
189 | // |
|
190 | // |
|
191 | // *
|
192 | // |
|
193 | // |
|
194 | // *---
|
195 | pvjsonPoints[1][activeOrientationDimension] =
|
196 | endPoint[activeOrientationDimension] -
|
197 | endOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH;
|
198 | }
|
199 | }
|
200 | else {
|
201 | // must initially route around start side
|
202 | if (startOrientation[activeOrientationIndex] ===
|
203 | endOrientation[activeOrientationIndex]) {
|
204 | // *---
|
205 | // |
|
206 | // |
|
207 | // *
|
208 | // |
|
209 | // |
|
210 | // -----------*-----------
|
211 | // |
|
212 | // |
|
213 | // *
|
214 | // |
|
215 | // |
|
216 | // ---*
|
217 | pvjsonPoints[1] = {};
|
218 | pvjsonPoints[1][activeOrientationDimension] =
|
219 | startPoint[activeOrientationDimension] +
|
220 | startOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH;
|
221 | pvjsonPoints[1][otherOrientationDimension] =
|
222 | startPoint[otherOrientationDimension] +
|
223 | otherOrientationDimensionDisplacement / 4;
|
224 | pvjsonPoints[2] = {};
|
225 | pvjsonPoints[2][activeOrientationDimension] =
|
226 | (startPoint[activeOrientationDimension] +
|
227 | endPoint[activeOrientationDimension]) /
|
228 | 2;
|
229 | pvjsonPoints[2][otherOrientationDimension] =
|
230 | startPoint[otherOrientationDimension] +
|
231 | otherOrientationDimensionDisplacement / 2;
|
232 | pvjsonPoints[3] = {};
|
233 | pvjsonPoints[3][activeOrientationDimension] =
|
234 | endPoint[activeOrientationDimension] -
|
235 | endOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH;
|
236 | pvjsonPoints[3][otherOrientationDimension] =
|
237 | startPoint[otherOrientationDimension] +
|
238 | 3 * otherOrientationDimensionDisplacement / 4;
|
239 | }
|
240 | else {
|
241 | // *---
|
242 | // |
|
243 | // |
|
244 | // *
|
245 | // |
|
246 | // |
|
247 | // *---------------------
|
248 | pvjsonPoints[1] = {};
|
249 | pvjsonPoints[1][activeOrientationDimension] =
|
250 | startPoint[activeOrientationDimension] +
|
251 | startOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH;
|
252 | pvjsonPoints[1][otherOrientationDimension] =
|
253 | startPoint[otherOrientationDimension] +
|
254 | otherOrientationDimensionDisplacement / 2;
|
255 | }
|
256 | }
|
257 | }
|
258 | else {
|
259 | // Start and end orientations are perpendicular
|
260 | if (startOrientation[activeStartOrientationIndex] ===
|
261 | vectorSumOrientation[activeStartOrientationIndex] &&
|
262 | endOrientation[activeEndOrientationIndex] ===
|
263 | vectorSumOrientation[activeEndOrientationIndex]) {
|
264 | // *
|
265 | // |
|
266 | // |
|
267 | // |
|
268 | // |
|
269 | // |
|
270 | // ---------------------*
|
271 | //
|
272 | // Do nothing.
|
273 | }
|
274 | else {
|
275 | // ---*
|
276 | // |
|
277 | // |
|
278 | // |
|
279 | // *
|
280 | // * |
|
281 | // | |
|
282 | // | |
|
283 | // --------*--------
|
284 | //
|
285 | // or *---
|
286 | // |
|
287 | // |
|
288 | // |
|
289 | // *
|
290 | // * |
|
291 | // | |
|
292 | // | |
|
293 | // --------*--------
|
294 | //
|
295 | // or
|
296 | //
|
297 | // ----*
|
298 | // |
|
299 | // |
|
300 | // *
|
301 | // |
|
302 | // |
|
303 | // ---*---
|
304 | // |
|
305 | // |
|
306 | // *
|
307 | const otherStartOrientationDimensionDisplacement = endPoint[otherStartOrientationDimension] -
|
308 | endOrientation[activeEndOrientationIndex] * DEFAULT_STUB_LENGTH -
|
309 | startPoint[otherStartOrientationDimension];
|
310 | pvjsonPoints[1] = {};
|
311 | pvjsonPoints[1][activeStartOrientationDimension] =
|
312 | startPoint[activeStartOrientationDimension] +
|
313 | startOrientation[activeStartOrientationIndex] * DEFAULT_STUB_LENGTH;
|
314 | pvjsonPoints[1][otherStartOrientationDimension] =
|
315 | startPoint[otherStartOrientationDimension] +
|
316 | otherStartOrientationDimensionDisplacement / 2;
|
317 | pvjsonPoints[2] = {};
|
318 | pvjsonPoints[2][activeEndOrientationDimension] =
|
319 | endPoint[activeEndOrientationDimension] -
|
320 | endOrientation[activeEndOrientationIndex] * DEFAULT_STUB_LENGTH;
|
321 | pvjsonPoints[2][otherEndOrientationDimension] =
|
322 | (pvjsonPoints[1][otherEndOrientationDimension] +
|
323 | endPoint[otherEndOrientationDimension]) /
|
324 | 2;
|
325 | }
|
326 | }
|
327 | pvjsonPoints.push(endPoint);
|
328 | return pointOrderReversed ? pvjsonPoints.reverse() : pvjsonPoints;
|
329 | }
|
330 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FsY3VsYXRlQWxsUG9pbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2VkZ2UvY2FsY3VsYXRlQWxsUG9pbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBUSxTQUFTLEVBQTRCLE1BQU0sV0FBVyxDQUFDO0FBQ3RFLE9BQU8sRUFNTCx5QkFBeUIsRUFJMUIsTUFBTSxlQUFlLENBQUM7QUFHdkIsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQzdDLE9BQU8sRUFDTCxtQ0FBbUMsRUFDbkMsaUNBQWlDLEVBQ2pDLG1CQUFtQixFQUNwQixNQUFNLGVBQWUsQ0FBQztBQUV2QixNQUFNLGtCQUFrQixHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBRXRDLCtDQUErQyxXQUE2QjtJQUMxRSxNQUFNLHNCQUFzQixHQUFHLFNBQVMsQ0FDdEMsQ0FBQyxpQkFBeUIsRUFBRSxFQUFFLENBQUMsaUJBQWlCLEtBQUssQ0FBQyxFQUN0RCxXQUFXLENBQ1osQ0FBQztJQUNGLE1BQU0sMEJBQTBCLEdBQUcsa0JBQWtCLENBQUMsc0JBQXNCLENBQUMsQ0FBQztJQUM5RSxNQUFNLHlCQUF5QixHQUFHLDBCQUEwQixLQUFLLEdBQUc7UUFDbEUsQ0FBQyxDQUFDLEdBQUc7UUFDTCxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ1IsTUFBTSxDQUFDO1FBQ0wsc0JBQXNCO1FBQ3RCLDBCQUEwQjtRQUMxQix5QkFBeUI7S0FDMUIsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FvQkc7QUFDSCxNQUFNLDZCQUNKLGNBQXNDLEVBQ3RDLFlBQXNDLEVBQ3RDLFlBQXNDO0lBRXRDLElBQUksVUFBVSxHQUFHLGNBQWMsQ0FBQyxDQUFDLENBQWlDLENBQUM7SUFDbkUsSUFBSSxTQUFTLEdBQUcsY0FBYyxDQUFDLGNBQWMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUM1QyxD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 |
\ | No newline at end of file |