flatten-js
Version:
Javascript library for 2d geometry
1 lines • 33.3 kB
JSON
{"dependencies":[{"name":"C:\\Users\\alexbol\\WebstormProjects\\flatten-js\\package.json","includedInParent":true,"mtime":1520238055570}],"generated":{"js":"/**\r\n * Created by Alex Bol on 3/17/2017.\r\n */\n\n\"use strict\";\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nmodule.exports = function (Flatten) {\n var Point = Flatten.Point,\n Segment = Flatten.Segment,\n Arc = Flatten.Arc,\n Box = Flatten.Box,\n Edge = Flatten.Edge;\n /**\r\n * Class representing a face (closed loop) in a [polygon]{@link Flatten.Polygon} object.\r\n * Face is a circular bidirectional linked list of [edges]{@link Flatten.Edge}.\r\n * Face object cannot be instantiated with a constructor.\r\n * Instead, use [polygon.addFace()]{@link Flatten.Polygon#addFace} method.\r\n * <br/>\r\n * Note, that face only set entry point to the linked list of edges but does not contain edges by itself.\r\n * Container of edges is a property of the polygon object. <br/>\r\n *\r\n * @example\r\n * // Face implements \"next\" iterator which enables to iterate edges in for loop:\r\n * for (let edge of face) {\r\n * console.log(edge.shape.length) // do something\r\n * }\r\n *\r\n * // Instead, it is possible to iterate edges as linked list, starting from face.first:\r\n * let edge = face.first;\r\n * do {\r\n * console.log(edge.shape.length); // do something\r\n * edge = edge.next;\r\n * } while (edge != face.first)\r\n */\n\n Flatten.Face = function () {\n function Face(polygon) {\n _classCallCheck(this, Face);\n\n /**\r\n * Reference to the first edge in face\r\n */\n this.first;\n /**\r\n * Reference to the last edge in face\r\n */\n this.last;\n\n this._box = undefined; // new Box();\n this._orientation = undefined;\n\n if ((arguments.length <= 1 ? 0 : arguments.length - 1) == 0) {\n return;\n }\n\n /* If passed an array it supposed to be:\r\n 1) array of shapes that performs close loop or\r\n 2) array of points that performs set of vertices\r\n */\n if ((arguments.length <= 1 ? 0 : arguments.length - 1) == 1) {\n if ((arguments.length <= 1 ? undefined : arguments[1]) instanceof Array) {\n // let argsArray = args[0];\n var shapes = arguments.length <= 1 ? undefined : arguments[1]; // argsArray[0];\n if (shapes.length == 0) return;\n\n if (shapes.every(function (shape) {\n return shape instanceof Point;\n })) {\n var segments = Face.points2segments(shapes);\n this.shapes2face(polygon.edges, segments);\n } else if (shapes.every(function (shape) {\n return shape instanceof Segment || shape instanceof Arc;\n })) {\n this.shapes2face(polygon.edges, shapes);\n }\n // this is from JSON.parse object\n else if (shapes.every(function (shape) {\n return shape.name === \"Segment\" || shape.name === \"Arc\";\n })) {\n var flattenShapes = [];\n var _iteratorNormalCompletion = true;\n var _didIteratorError = false;\n var _iteratorError = undefined;\n\n try {\n for (var _iterator = shapes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {\n var shape = _step.value;\n\n var flattenShape = void 0;\n if (shape.name === \"Segment\") {\n flattenShape = new Segment(shape.ps.x, shape.ps.y, shape.pe.x, shape.pe.y);\n } else {\n flattenShape = new Arc(new Point(shape.pc.x, shape.pc.y), shape.r, shape.startAngle, shape.endAngle, shape.counterClockwise);\n }\n flattenShapes.push(flattenShape);\n }\n } catch (err) {\n _didIteratorError = true;\n _iteratorError = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion && _iterator.return) {\n _iterator.return();\n }\n } finally {\n if (_didIteratorError) {\n throw _iteratorError;\n }\n }\n }\n\n this.shapes2face(polygon.edges, flattenShapes);\n }\n }\n /* Create new face and copy edges into polygon.edges set */\n else if ((arguments.length <= 1 ? undefined : arguments[1]) instanceof Face) {\n var face = arguments.length <= 1 ? undefined : arguments[1];\n this.first = face.first;\n this.last = face.last;\n var _iteratorNormalCompletion2 = true;\n var _didIteratorError2 = false;\n var _iteratorError2 = undefined;\n\n try {\n for (var _iterator2 = face[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {\n var _edge = _step2.value;\n\n polygon.edges.add(_edge);\n }\n } catch (err) {\n _didIteratorError2 = true;\n _iteratorError2 = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion2 && _iterator2.return) {\n _iterator2.return();\n }\n } finally {\n if (_didIteratorError2) {\n throw _iteratorError2;\n }\n }\n }\n }\n }\n /* If passed two edges, consider them as start and end of the face loop */\n /* THIS METHOD WILL BE USED BY BOOLEAN OPERATIONS */\n /* Assume that edges already copied to polygon.edges set in the clip algorithm !!! */\n if ((arguments.length <= 1 ? 0 : arguments.length - 1) == 2 && (arguments.length <= 1 ? undefined : arguments[1]) instanceof Edge && (arguments.length <= 2 ? undefined : arguments[2]) instanceof Edge) {\n this.first = arguments.length <= 1 ? undefined : arguments[1]; // first edge in face or undefined\n this.last = arguments.length <= 2 ? undefined : arguments[2]; // last edge in face or undefined\n this.last.next = this.first;\n this.first.prev = this.last;\n\n // set arc length\n this.setArcLength();\n /*\r\n let edge = this.first;\r\n edge.arc_length = 0;\r\n edge = edge.next;\r\n while (edge !== this.first) {\r\n edge.arc_length = edge.prev.arc_length + edge.prev.length;\r\n edge = edge.next;\r\n }\r\n */\n\n // this.box = this.getBox();\n // this.orientation = this.getOrientation(); // face direction cw or ccw\n }\n }\n\n _createClass(Face, [{\n key: Symbol.iterator,\n value: function value() {\n var _this = this;\n\n var edge = undefined;\n return {\n next: function next() {\n var value = edge ? edge : _this.first;\n var done = _this.first ? edge ? edge === _this.first : false : true;\n edge = value ? value.next : undefined;\n return { value: value, done: done };\n }\n };\n }\n }, {\n key: \"shapes2face\",\n value: function shapes2face(edges, shapes) {\n var _iteratorNormalCompletion3 = true;\n var _didIteratorError3 = false;\n var _iteratorError3 = undefined;\n\n try {\n for (var _iterator3 = shapes[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {\n var shape = _step3.value;\n\n var _edge2 = new Edge(shape);\n this.append(edges, _edge2);\n // this.box = this.box.merge(shape.box);\n // edges.add(edge);\n }\n // this.orientation = this.getOrientation(); // face direction cw or ccw\n } catch (err) {\n _didIteratorError3 = true;\n _iteratorError3 = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion3 && _iterator3.return) {\n _iterator3.return();\n }\n } finally {\n if (_didIteratorError3) {\n throw _iteratorError3;\n }\n }\n }\n }\n\n /**\r\n * Returns true if face is empty, false otherwise\r\n * @returns {boolean}\r\n */\n\n }, {\n key: \"isEmpty\",\n value: function isEmpty() {\n return this.first === undefined && this.last === undefined;\n }\n\n /**\r\n * Append given edge after the last edge (and before the first edge). <br/>\r\n * This method mutates current object and does not return any value\r\n * @param {PlanarSet} edges - Container of edges\r\n * @param {Edge} edge - Edge to be appended to the linked list\r\n */\n\n }, {\n key: \"append\",\n value: function append(edges, edge) {\n if (this.first === undefined) {\n edge.prev = edge;\n edge.next = edge;\n this.first = edge;\n this.last = edge;\n edge.arc_length = 0;\n } else {\n // append to end\n edge.prev = this.last;\n this.last.next = edge;\n\n // update edge to be last\n this.last = edge;\n\n // restore circular links\n this.last.next = this.first;\n this.first.prev = this.last;\n\n // set arc length\n edge.arc_length = edge.prev.arc_length + edge.prev.length;\n }\n edge.face = this;\n\n edges.add(edge); // Add new edges into edges container\n }\n\n /**\r\n * Insert edge newEdge into the linked list after the edge edgeBefore <br/>\r\n * This method mutates current object and does not return any value\r\n * @param {PlanarSet} edges - Container of edges\r\n * @param {Edge} newEdge - Edge to be inserted into linked list\r\n * @param {Edge} edgeBefore - Edge to insert newEdge after it\r\n */\n\n }, {\n key: \"insert\",\n value: function insert(edges, newEdge, edgeBefore) {\n if (this.first === undefined) {\n edge.prev = newEdge;\n edge.next = newEdge;\n this.first = newEdge;\n this.last = newEdge;\n } else {\n /* set links to new edge */\n var edgeAfter = edgeBefore.next;\n edgeBefore.next = newEdge;\n edgeAfter.prev = newEdge;\n\n /* set links from new edge */\n newEdge.prev = edgeBefore;\n newEdge.next = edgeAfter;\n\n /* extend chain if new edge added after last edge */\n if (this.last === edgeBefore) this.first = newEdge;\n }\n newEdge.face = this;\n\n edges.add(newEdge); // Add new edges into edges container\n }\n\n /**\r\n * Remove the given edge from the linked list of the face <br/>\r\n * This method mutates current object and does not return any value\r\n * @param {PlanarSet} edges - Container of edges\r\n * @param {Edge} edge - Edge to be removed\r\n */\n\n }, {\n key: \"remove\",\n value: function remove(edges, edge) {\n // special case if last edge removed\n if (edge === this.first && edge === this.last) {\n this.first = undefined;\n this.last = undefined;\n } else {\n // update linked list\n edge.prev.next = edge.next;\n edge.next.prev = edge.prev;\n // update first if need\n if (edge === this.first) {\n this.first = edge.next;\n }\n // update last if need\n if (edge === this.last) {\n this.last = edge.prev;\n }\n }\n edges.delete(edge); // delete from PlanarSet of edges and update index\n }\n\n /**\r\n * Reverse orientation of the face: first edge become last and vice a verse,\r\n * all edges starts and ends swapped, direction of arcs inverted.\r\n */\n\n }, {\n key: \"reverse\",\n value: function reverse() {\n // collect edges in revert order with reverted shapes\n var edges = [];\n var edge_tmp = this.last;\n do {\n // reverse shape\n edge_tmp.shape = edge_tmp.shape.reverse();\n edges.push(edge_tmp);\n edge_tmp = edge_tmp.prev;\n } while (edge_tmp !== this.last);\n\n // restore linked list\n this.first = undefined;\n this.last = undefined;\n var _iteratorNormalCompletion4 = true;\n var _didIteratorError4 = false;\n var _iteratorError4 = undefined;\n\n try {\n for (var _iterator4 = edges[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {\n var _edge3 = _step4.value;\n\n if (this.first === undefined) {\n _edge3.prev = _edge3;\n _edge3.next = _edge3;\n this.first = _edge3;\n this.last = _edge3;\n _edge3.arc_length = 0;\n } else {\n // append to end\n _edge3.prev = this.last;\n this.last.next = _edge3;\n\n // update edge to be last\n this.last = _edge3;\n\n // restore circular links\n this.last.next = this.first;\n this.first.prev = this.last;\n\n // set arc length\n _edge3.arc_length = _edge3.prev.arc_length + _edge3.prev.length;\n }\n }\n\n // Recalculate orientation, if set\n } catch (err) {\n _didIteratorError4 = true;\n _iteratorError4 = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion4 && _iterator4.return) {\n _iterator4.return();\n }\n } finally {\n if (_didIteratorError4) {\n throw _iteratorError4;\n }\n }\n }\n\n if (this._orientation !== undefined) {\n this._orientation = undefined;\n this._orientation = this.orientation();\n }\n }\n\n /**\r\n * Set arc_length property for each of the edges in the face.\r\n * Arc_length of the edge it the arc length from the first edge of the face\r\n */\n\n }, {\n key: \"setArcLength\",\n value: function setArcLength() {\n var _iteratorNormalCompletion5 = true;\n var _didIteratorError5 = false;\n var _iteratorError5 = undefined;\n\n try {\n for (var _iterator5 = this[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {\n var _edge4 = _step5.value;\n\n if (_edge4 === this.first) {\n _edge4.arc_length = 0.0;\n } else {\n _edge4.arc_length = _edge4.prev.arc_length + _edge4.prev.length;\n }\n _edge4.face = this;\n }\n } catch (err) {\n _didIteratorError5 = true;\n _iteratorError5 = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion5 && _iterator5.return) {\n _iterator5.return();\n }\n } finally {\n if (_didIteratorError5) {\n throw _iteratorError5;\n }\n }\n }\n }\n\n /**\r\n * Returns the absolute value of the area of the face\r\n * @returns {number}\r\n */\n\n }, {\n key: \"area\",\n value: function area() {\n return Math.abs(this.signedArea());\n }\n\n /**\r\n * Returns signed area of the simple face.\r\n * Face is simple if it has no self intersections that change its orientation.\r\n * Then the area will be positive if the orientation of the face is clockwise,\r\n * and negative if orientation is counterclockwise.\r\n * It may be zero if polygon is degenerated.\r\n * @returns {number}\r\n */\n\n }, {\n key: \"signedArea\",\n value: function signedArea() {\n var sArea = 0;\n var _iteratorNormalCompletion6 = true;\n var _didIteratorError6 = false;\n var _iteratorError6 = undefined;\n\n try {\n for (var _iterator6 = this[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {\n var _edge5 = _step6.value;\n\n sArea += _edge5.shape.definiteIntegral(this.box.ymin);\n }\n } catch (err) {\n _didIteratorError6 = true;\n _iteratorError6 = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion6 && _iterator6.return) {\n _iterator6.return();\n }\n } finally {\n if (_didIteratorError6) {\n throw _iteratorError6;\n }\n }\n }\n\n return sArea;\n }\n\n /**\r\n * Return face orientation: one of Flatten.ORIENTATION.CCW, Flatten.ORIENTATION.CW, Flatten.ORIENTATION.NOT_ORIENTABLE <br/>\r\n * According to Green theorem the area of a closed curve may be calculated as double integral,\r\n * and the sign of the integral will be defined by the direction of the curve.\r\n * When the integral (\"signed area\") will be negative, direction is counter clockwise,\r\n * when positive - clockwise and when it is zero, polygon is not orientable.\r\n * See {@link https://mathinsight.org/greens_theorem_find_area}\r\n * @returns {number}\r\n */\n\n }, {\n key: \"orientation\",\n value: function orientation() {\n if (this._orientation === undefined) {\n var area = this.signedArea();\n if (Flatten.Utils.EQ_0(area)) {\n this._orientation = Flatten.ORIENTATION.NOT_ORIENTABLE;\n } else if (Flatten.Utils.LT(area, 0)) {\n this._orientation = Flatten.ORIENTATION.CCW;\n } else {\n this._orientation = Flatten.ORIENTATION.CW;\n }\n }\n return this._orientation;\n }\n\n /**\r\n * Return bounding box of the face\r\n * @returns {Box}\r\n */\n\n }, {\n key: \"getRelation\",\n\n\n /**\r\n * Check relation between face and other polygon\r\n * on strong assumption that they are NOT INTERSECTED <br/>\r\n * Then there are 4 options: <br/>\r\n * face disjoint to polygon - Flatten.OUTSIDE <br/>\r\n * face inside polygon - Flatten.INSIDE <br/>\r\n * face contains polygon - Flatten.CONTAIN <br/>\r\n * face interlaced with polygon: inside some face and contains other face - Flatten.INTERLACE <br/>\r\n * @param {Polygon} polygon - Polygon to check relation\r\n */\n value: function getRelation(polygon) {\n this.first.bv = this.first.bvStart = this.first.bvEnd = undefined;\n var bvThisInOther = this.first.setInclusion(polygon);\n var resp = polygon.faces.search(this.box);\n if (resp.length === 0) {\n return bvThisInOther; // OUTSIDE or INSIDE\n } else {\n // possible INTERLACE\n var polyTmp = new Flatten.Polygon();\n polyTmp.addFace(this);\n\n var numInsideThis = 0;\n var _iteratorNormalCompletion7 = true;\n var _didIteratorError7 = false;\n var _iteratorError7 = undefined;\n\n try {\n for (var _iterator7 = resp[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {\n var face = _step7.value;\n\n face.first.bv = face.first.bvStart = face.first.bvEnd = undefined;\n var bvOtherInThis = face.first.setInclusion(polyTmp);\n if (bvOtherInThis === Flatten.INSIDE) {\n numInsideThis++;\n }\n }\n } catch (err) {\n _didIteratorError7 = true;\n _iteratorError7 = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion7 && _iterator7.return) {\n _iterator7.return();\n }\n } finally {\n if (_didIteratorError7) {\n throw _iteratorError7;\n }\n }\n }\n\n if (bvThisInOther === Flatten.OUTSIDE) {\n if (numInsideThis === 0) {\n // none inside this - outside\n return Flatten.OUTSIDE;\n } else if (numInsideThis === resp.length) {\n // all from resp inside this - contains or interlace\n if (resp.length === polygon.faces.size) {\n return Flatten.CONTAINS; // all faces from polygon are in response - contains\n } else {\n return Flatten.INTERLACE; // some faces inside - interlace\n }\n } else {\n return Flatten.INTERLACE; // some faces inside - interlace\n }\n } else if (bvThisInOther === Flatten.INSIDE) {\n return numInsideThis === 0 ? Flatten.INSIDE : Flatten.INTERLACE;\n }\n }\n }\n }, {\n key: \"toJSON\",\n value: function toJSON() {\n return this.edges.map(function (edge) {\n return edge.toJSON();\n });\n }\n }, {\n key: \"svg\",\n value: function svg() {\n var svgStr = \"\\nM\" + this.first.start.x + \",\" + this.first.start.y;\n\n var _iteratorNormalCompletion8 = true;\n var _didIteratorError8 = false;\n var _iteratorError8 = undefined;\n\n try {\n for (var _iterator8 = this[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {\n var _edge6 = _step8.value;\n\n svgStr += _edge6.svg();\n }\n } catch (err) {\n _didIteratorError8 = true;\n _iteratorError8 = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion8 && _iterator8.return) {\n _iterator8.return();\n }\n } finally {\n if (_didIteratorError8) {\n throw _iteratorError8;\n }\n }\n }\n\n svgStr += \" z\";\n return svgStr;\n }\n }, {\n key: \"edges\",\n\n\n /**\r\n * Return array of edges from first to last\r\n * @returns {Array}\r\n */\n get: function get() {\n var face_edges = [];\n var _iteratorNormalCompletion9 = true;\n var _didIteratorError9 = false;\n var _iteratorError9 = undefined;\n\n try {\n for (var _iterator9 = this[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {\n var _edge7 = _step9.value;\n\n face_edges.push(_edge7);\n }\n } catch (err) {\n _didIteratorError9 = true;\n _iteratorError9 = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion9 && _iterator9.return) {\n _iterator9.return();\n }\n } finally {\n if (_didIteratorError9) {\n throw _iteratorError9;\n }\n }\n }\n\n return face_edges;\n }\n\n /**\r\n * Return number of edges in the face\r\n * @returns {number}\r\n */\n\n }, {\n key: \"size\",\n get: function get() {\n var counter = 0;\n var _iteratorNormalCompletion10 = true;\n var _didIteratorError10 = false;\n var _iteratorError10 = undefined;\n\n try {\n for (var _iterator10 = this[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {\n var _edge8 = _step10.value;\n\n counter++;\n }\n } catch (err) {\n _didIteratorError10 = true;\n _iteratorError10 = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion10 && _iterator10.return) {\n _iterator10.return();\n }\n } finally {\n if (_didIteratorError10) {\n throw _iteratorError10;\n }\n }\n }\n\n return counter;\n }\n }, {\n key: \"box\",\n get: function get() {\n if (this._box === undefined) {\n var box = new Flatten.Box();\n var _iteratorNormalCompletion11 = true;\n var _didIteratorError11 = false;\n var _iteratorError11 = undefined;\n\n try {\n for (var _iterator11 = this[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {\n var _edge9 = _step11.value;\n\n box = box.merge(_edge9.box);\n }\n } catch (err) {\n _didIteratorError11 = true;\n _iteratorError11 = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion11 && _iterator11.return) {\n _iterator11.return();\n }\n } finally {\n if (_didIteratorError11) {\n throw _iteratorError11;\n }\n }\n }\n\n this._box = box;\n }\n return this._box;\n }\n }], [{\n key: \"points2segments\",\n value: function points2segments(points) {\n var segments = [];\n for (var i = 0; i < points.length; i++) {\n segments.push(new Segment(points[i], points[(i + 1) % points.length]));\n }\n return segments;\n }\n }]);\n\n return Face;\n }();\n};"},"hash":"db7a0ab22ef5ee8bb7981be21ee4a78d","cacheData":{"env":{}}}