Rift.IO OSM R1 Initial Submission
[osm/UI.git] / skyquake / plugins / composer / src / src / libraries / graph / math.js
diff --git a/skyquake/plugins/composer/src/src/libraries/graph/math.js b/skyquake/plugins/composer/src/src/libraries/graph/math.js
new file mode 100644 (file)
index 0000000..2968cfa
--- /dev/null
@@ -0,0 +1,147 @@
+
+/*
+ * 
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+/**
+ * Created by onvelocity on 9/1/15.
+ */
+
+import Position from './Position'
+
+const angleOfLine = function (x1, y1, x2, y2) {
+
+       const y = y2 - y1;
+       const x = x2 - x1;
+
+       const rad = Math.atan2(y, x);
+       const deg = Math.abs(rad * 180 / Math.PI);
+
+       let addDeg = 0;
+
+       if (rad <= 0) {
+               addDeg = 360;
+       }
+
+       // - addDeg bc atan2 returns -π to π where -π is the upper side of rectangle
+       // - 360 bc our ui grid system has zero in upper left corner not lower left
+       return Math.abs(Math.abs(deg - addDeg) - 360);
+
+};
+
+const angleBetweenPositions = function (src, dst) {
+       if (!src instanceof Position) {
+               throw new ReferenceError('require a position instance');
+       }
+       if (!dst instanceof Position) {
+               throw new ReferenceError('require a position instance');
+       }
+       const srcCenter = src.centerPoint();
+       const dstCenter = dst.centerPoint();
+       return angleOfLine(srcCenter.x, srcCenter.y, dstCenter.x, dstCenter.y);
+};
+
+const distanceBetweenPositions = function (src, dst) {
+       if (!src instanceof Position) {
+               throw new ReferenceError('require a position instance');
+       }
+       if (!dst instanceof Position) {
+               throw new ReferenceError('require a position instance');
+       }
+       const srcCenter = src.centerPoint();
+       const dstCenter = dst.centerPoint();
+       const x = Math.pow(dstCenter.x - srcCenter.x, 2);
+       const y = Math.pow(dstCenter.y - srcCenter.y, 2);
+       const distance = Math.sqrt((x) + (y));
+       if (isNaN(distance)) {
+               console.log('nan distance', srcCenter, dstCenter);
+       }
+       return distance;
+};
+
+const rectangleAnglesFromCenter = function (position) {
+       /* given a rectangle defined by a Position, determine the angle of each corner from center.
+        // note: 0˚ is on x-axis; angles are given counterclockwise from x-axis
+        // for example:
+        // the line AB(0, 0, 5, 0) would have angle 0˚
+        // the line AC(0, 0, 0, 5) would have angle 90˚
+        // the line BC(5, 0, 0, 5) would have angle 135˚
+        // the line BA(5, 0, 0, 0) would have angle 180˚
+        */
+       if (!position instanceof Position) {
+               throw new ReferenceError('require a Position instance');
+       }
+       const center = position.centerPoint();
+       return [
+               angleOfLine(center.x, center.y, position.right, position.top),
+               angleOfLine(center.x, center.y, position.left, position.top),
+               angleOfLine(center.x, center.y, position.left, position.bottom),
+               angleOfLine(center.x, center.y, position.right, position.bottom)
+       ];
+};
+
+const edgeLocation = function (rectangleInclinations) {
+       /* given the angle of a line, determine which edge of the rectangle the line should attach. */
+       let inclinations = rectangleInclinations;
+       if (rectangleInclinations instanceof Position) {
+               inclinations = rectangleAnglesFromCenter(rectangleInclinations);
+       }
+       return angle => {
+               angle = parseFloat(angle);
+               if (angle >= inclinations[3]) {
+                       return 'right';
+               }
+               if (angle >= 270) {
+                       return 'bottom-right';
+               }
+               if (angle >= inclinations[2]) {
+                       return 'bottom-left';
+               }
+               if (angle >= inclinations[1]) {
+                       return 'left';
+               }
+               if (angle >= 90) {
+                       return 'top-left';
+               }
+               if (angle >= inclinations[0]) {
+                       return 'top-right';
+               }
+               return 'right';
+       };
+};
+
+const upperLowerEdgeLocation = function (angle) {
+       angle = parseFloat(angle);
+       if (angle > 270) {
+               return 'bottom-right';
+       }
+       if (angle > 180) {
+               return 'bottom-left';
+       }
+       if (angle > 90) {
+               return 'top-left';
+       }
+       return 'top-right';
+};
+
+export default {
+       angleOfLine: angleOfLine,
+       angleBetweenPositions: angleBetweenPositions,
+       distanceBetweenPositions: distanceBetweenPositions,
+       anglesFromCenter: rectangleAnglesFromCenter,
+       edgeLocation: edgeLocation,
+       upperLowerEdgeLocation: upperLowerEdgeLocation
+}