1 | import { flow, isFinite, last, map } from "lodash/fp";
|
2 | import { START_SEGMENT_DETAILS_MAPS, flipOrientation, sameSide, SmartPath } from "../geom-utils";
|
3 | import { distance } from "../spinoffs/Angle";
|
4 | import { DEFAULT_STUB_LENGTH } from "./edge";
|
5 | /**
|
6 | * getOrientationOfHyperedgeStartPoint
|
7 | *
|
8 | * Get orientation of the start point of an edge that is attached to another
|
9 | * edge.
|
10 | *
|
11 | * @param referencedEdge {PvjsonEdge}
|
12 | * @param startPoint {Point}
|
13 | * @param otherPoint {Point}
|
14 | * @return {Orientation}
|
15 | */
|
16 | export function getOrientationOfHyperedgeStartPoint(referencedEdge, startPoint, endPoint) {
|
17 | if (!referencedEdge) {
|
18 | throw new Error("Missing referencedEdge when calculating orientation of point attached to other edge.");
|
19 | }
|
20 | const currentPath = new SmartPath([startPoint, endPoint]);
|
21 | const angleOfCurrentVectorSum = currentPath.sum.angle;
|
22 | const referencedPath = new SmartPath(referencedEdge.points, referencedEdge);
|
23 | // This is the angle of the line tangent to the referenced edge at
|
24 | // startPoint.
|
25 | const angleOfReferencedEdgeAtPointOnEdge = referencedPath.position(startPoint.attachmentDisplay.position[0]).angle;
|
26 | const firstSegmentCalculations = START_SEGMENT_DETAILS_MAPS.map(function (startSegmentDetailsMap) {
|
27 | /*
|
28 | * referenced edge
|
29 | * /
|
30 | * /
|
31 | * /.
|
32 | * / angle (rad)
|
33 | * / .
|
34 | * /--------------
|
35 | * / ^ | --------------
|
36 | * / | | | |
|
37 | * | ------------| |
|
38 | * | | |
|
39 | * firstSegment --------------
|
40 | * (of current edge)
|
41 | *
|
42 | */
|
43 | const { orientation } = startSegmentDetailsMap;
|
44 | const [orientationX, orientationY] = orientation;
|
45 | const firstSegmentEndPoint = {
|
46 | x: startPoint.x + DEFAULT_STUB_LENGTH * orientationX,
|
47 | y: startPoint.y + DEFAULT_STUB_LENGTH * orientationY
|
48 | };
|
49 | return {
|
50 | firstSegmentEndPoint,
|
51 | endPoint,
|
52 | emanationAngle: startSegmentDetailsMap.angle,
|
53 | orientation: orientation
|
54 | };
|
55 | })
|
56 | .map(function ({ firstSegmentEndPoint, endPoint, emanationAngle: emanationAngle, orientation }) {
|
57 | const isSameSide = sameSide(referencedEdge.points[0], last(referencedEdge.points), firstSegmentEndPoint, endPoint);
|
58 | const angleBetweenOrientationVectorAndCurrentEdge = distance(emanationAngle, angleOfCurrentVectorSum);
|
59 | const angleBetweenOrientationVectorAndReferencedEdge = distance(angleOfReferencedEdgeAtPointOnEdge, emanationAngle);
|
60 | return {
|
61 | isSameSide,
|
62 | angleBetweenOrientationVectorAndCurrentEdge,
|
63 | angleBetweenOrientationVectorAndVectorPerpendicularToReferencedEdge: Math.abs(angleBetweenOrientationVectorAndReferencedEdge - Math.PI / 2),
|
64 | orientation
|
65 | };
|
66 | })
|
67 | .sort(function (a, b) {
|
68 | if (a.isSameSide && !b.isSameSide) {
|
69 | return -1;
|
70 | }
|
71 | else if (!a.isSameSide && b.isSameSide) {
|
72 | return 1;
|
73 | }
|
74 | else {
|
75 | if (a.angleBetweenOrientationVectorAndVectorPerpendicularToReferencedEdge <
|
76 | b.angleBetweenOrientationVectorAndVectorPerpendicularToReferencedEdge) {
|
77 | return -1;
|
78 | }
|
79 | else if (a.angleBetweenOrientationVectorAndVectorPerpendicularToReferencedEdge >
|
80 | b.angleBetweenOrientationVectorAndVectorPerpendicularToReferencedEdge) {
|
81 | return 1;
|
82 | }
|
83 | else {
|
84 | if (a.angleBetweenOrientationVectorAndCurrentEdge <
|
85 | b.angleBetweenOrientationVectorAndCurrentEdge) {
|
86 | return -1;
|
87 | }
|
88 | else if (a.angleBetweenOrientationVectorAndCurrentEdge >
|
89 | b.angleBetweenOrientationVectorAndCurrentEdge) {
|
90 | return 1;
|
91 | }
|
92 | else {
|
93 | return 0;
|
94 | }
|
95 | }
|
96 | }
|
97 | });
|
98 | const formatted = map(function (firstSegmentCalculation) {
|
99 | const { angleBetweenOrientationVectorAndVectorPerpendicularToReferencedEdge, angleBetweenOrientationVectorAndCurrentEdge, isSameSide } = firstSegmentCalculation;
|
100 | return {
|
101 | angleBetweenOrientationVectorAndVectorPerpendicularToReferencedEdge: String(angleBetweenOrientationVectorAndVectorPerpendicularToReferencedEdge /
|
102 | Math.PI) + " * PI",
|
103 | angleBetweenOrientationVectorAndCurrentEdge: String(angleBetweenOrientationVectorAndCurrentEdge / Math.PI) + " * PI",
|
104 | isSameSide
|
105 | };
|
106 | }, firstSegmentCalculations);
|
107 | return firstSegmentCalculations[0].orientation;
|
108 | }
|
109 | // Uses the same sorting criteria as getOrientationOfHyperedgeStartPoint,
|
110 | // except with the obvious changes in direction to account for being the
|
111 | // endPoint instead of the startPoint.
|
112 | export const getOrientationOfHyperedgeEndPoint = flow(getOrientationOfHyperedgeStartPoint, flipOrientation);
|
113 | // Validate orientation of attachment display.
|
114 | //
|
115 | // When attached to a normal Node, we can calculate the orientation immediately
|
116 | // so this will return true right away.
|
117 | // When attached to an Edge or Group, we need to do more processing,
|
118 | // so this will at least initially return false.
|
119 | // TODO: Not sure whether the orientation of a point attached to an Edge or a
|
120 | // Group is ever set.
|
121 | export function validateOrientation(orientation) {
|
122 | return !!orientation && isFinite(orientation[0]) && isFinite(orientation[1]);
|
123 | }
|
124 | /*
|
125 | // NOTE: PathVisio-Java appears to try to avoid making an edge
|
126 | // terminate into another edge at an approach angle of anything
|
127 | // less than about 30 deg.
|
128 | if (endPoint.hasOwnProperty("isAttachedTo")) {
|
129 | const referencedEndPath = new SmartPath(endEntity.points, endEntity);
|
130 | const angleOfReferencedEdgeAtPointOnEdge = referencedEndPath.position(
|
131 | startPoint.attachmentDisplay.position[0]
|
132 | ).angle;
|
133 | if (
|
134 | Math.abs(
|
135 | START_SIDE_TO_EMANATION_ANGLE_MAPPINGS[endSide] -
|
136 | angleOfReferencedEdgeAtPointOnEdge
|
137 | ) <
|
138 | 30 * (Math.PI / 180)
|
139 | ) {
|
140 | // edge1 is almost parallel with edge2, making it hard to read, so we need to recalculate.
|
141 | endPoint.orientation = getOrientationOfHyperedgeEndPoint(
|
142 | endEntity,
|
143 | endPoint,
|
144 | startPoint
|
145 | );
|
146 | return getAndCompareSides(startPoint, endPoint, endEntity);
|
147 | }
|
148 | }
|
149 | //*/
|
150 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JpZW50YXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZWRnZS9vcmllbnRhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3RELE9BQU8sRUFDTCwwQkFBMEIsRUFDMUIsZUFBZSxFQUNmLFFBQVEsRUFFUixTQUFTLEVBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBUTdDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUU3Qzs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBTSw4Q0FDSixjQUEwQixFQUMxQixVQUF3QyxFQUN4QyxRQUFzQztJQUV0QyxFQUFFLENBQUMsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUM7UUFDcEIsTUFBTSxJQUFJLEtBQUssQ0FDYixzRkFBc0YsQ0FDdkYsQ0FBQztJQUNKLENBQUM7SUFFRCxNQUFNLFdBQVcsR0FBRyxJQUFJLFNBQVMsQ0FBQyxDQUFDLFVBQVUsRUFBRSxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQzFELE1BQU0sdUJBQXVCLEdBQUcsV0FBVyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUM7SUFDdEQsTUFBTSxjQUFjLEdBQUcsSUFBSSxTQUFTLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSxjQUFjLENBQUMsQ0FBQztJQUU1RSxrRUFBa0U7SUFDbEUsY0FBYztJQUNkLE1BQU0sa0NBQWtDLEdBQUcsY0FBYyxDQUFDLFFBQVEsQ0FDaEUsVUFBVSxDQUFDLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FDekMsQ0FBQyxLQUFLLENBQUM7SUFFUixNQUFNLHdCQUF3QixHQUFHLDBCQUEwQixDQUFDLEdBQUcsQ0FBQyxVQUM5RCxzQkFBc0I7UUFF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 |
\ | No newline at end of file |