UNPKG

makerjs

Version:

Maker.js, a Microsoft Garage project, is a JavaScript library for creating and sharing modular line drawings for CNC and laser cutters.

1,375 lines (1,300 loc) 448 kB
/* __________________________________________________________________________________________________________________________________________ __________________________________________________________________________________________________________________________________________ ________/\\\\____________/\\\\_____/\\\\\\\\\_____/\\\________/\\\__/\\\\\\\\\\\\\\\__/\\\\\\\\\\\________________________________________ _______\/\\\\\\________/\\\\\\___/\\\\/////\\\\__\/\\\_____/\\\//__\/\\\///////////__\/\\\///////\\\_______________/\\\___________________ _______\/\\\//\\\____/\\\//\\\__/\\\/____\///\\\_\/\\\__/\\\//_____\/\\\_____________\/\\\_____\/\\\______________\///____________________ _______\/\\\\///\\\/\\\/_\/\\\_\/\\\_______\/\\\_\/\\\\\\//\\\_____\/\\\\\\\\\\\_____\/\\\\\\\\\\\/________________/\\\__/\\\\\\\\\\______ _______\/\\\__\///\\\/___\/\\\_\/\\\\\\\\\\\\\\\_\/\\\//_\//\\\____\/\\\///////______\/\\\//////\\\_______________\/\\\_\/\\\//////_______ _______\/\\\____\///_____\/\\\_\/\\\/////////\\\_\/\\\____\//\\\___\/\\\_____________\/\\\____\//\\\______________\/\\\_\/\\\\\\\\\\______ _______\/\\\_____________\/\\\_\/\\\_______\/\\\_\/\\\_____\//\\\__\/\\\_____________\/\\\_____\//\\\_________/\\_\/\\\_\////////\\\______ _______\/\\\_____________\/\\\_\/\\\_______\/\\\_\/\\\______\//\\\_\/\\\\\\\\\\\\\\\_\/\\\______\//\\\__/\\\_\//\\\\\\___/\\\\\\\\\\______ _______\///______________\///__\///________\///__\///________\///__\///////////////__\///________\///__\///___\//////___\//////////_______ __________________________________________________________________________________________________________________________________________ __________________________________________________________________________________________________________________________________________ Maker.js https://github.com/Microsoft/maker.js Copyright (c) Microsoft Corporation. All rights reserved. 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 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. */ /** * Modules in this bundle * @license * * makerjs: * license: Apache-2.0 (http://opensource.org/licenses/Apache-2.0) * author: Dan Marshall / Microsoft Corporation * maintainers: Dan Marshall <danmar@microsoft.com> * homepage: https://maker.js.org * version: 0.12.1 * * browserify: * license: MIT (http://opensource.org/licenses/MIT) * author: James Halliday <mail@substack.net> * homepage: https://github.com/browserify/browserify#readme * version: 16.2.2 * * clone: * license: MIT (http://opensource.org/licenses/MIT) * author: Paul Vorbach <paul@vorba.ch> * contributors: Blake Miner <miner.blake@gmail.com>, Tian You <axqd001@gmail.com>, George Stagas <gstagas@gmail.com>, Tobiasz Cudnik <tobiasz.cudnik@gmail.com>, Pavel Lang <langpavel@phpskelet.org>, Dan MacTough, w1nk, Hugh Kennedy, Dustin Diaz, Ilya Shaisultanov, Nathan MacInnes <nathan@macinn.es>, Benjamin E. Coe <ben@npmjs.com>, Nathan Zadoks, Róbert Oroszi <robert+gh@oroszi.net>, Aurélio A. Heckert, Guy Ellis * homepage: https://github.com/pvorb/node-clone#readme * version: 1.0.4 * * graham_scan: * license: MIT (http://opensource.org/licenses/MIT) * author: Brian Barnett <brian@3kb.co.uk> * homepage: http://brian3kb.github.io/graham_scan_js * version: 1.0.4 * * kdbush: * license: ISC (http://opensource.org/licenses/ISC) * author: Vladimir Agafonkin * homepage: https://github.com/mourner/kdbush#readme * version: 2.0.1 * * This header is generated by licensify (https://github.com/twada/licensify) */ require=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ },{}],2:[function(require,module,exports){ (function (Buffer){ var clone = (function() { 'use strict'; /** * Clones (copies) an Object using deep copying. * * This function supports circular references by default, but if you are certain * there are no circular references in your object, you can save some CPU time * by calling clone(obj, false). * * Caution: if `circular` is false and `parent` contains circular references, * your program may enter an infinite loop and crash. * * @param `parent` - the object to be cloned * @param `circular` - set to true if the object to be cloned may contain * circular references. (optional - true by default) * @param `depth` - set to a number if the object is only to be cloned to * a particular depth. (optional - defaults to Infinity) * @param `prototype` - sets the prototype to be used when cloning an object. * (optional - defaults to parent prototype). */ function clone(parent, circular, depth, prototype) { var filter; if (typeof circular === 'object') { depth = circular.depth; prototype = circular.prototype; filter = circular.filter; circular = circular.circular } // maintain two arrays for circular references, where corresponding parents // and children have the same index var allParents = []; var allChildren = []; var useBuffer = typeof Buffer != 'undefined'; if (typeof circular == 'undefined') circular = true; if (typeof depth == 'undefined') depth = Infinity; // recurse this function so we don't reset allParents and allChildren function _clone(parent, depth) { // cloning null always returns null if (parent === null) return null; if (depth == 0) return parent; var child; var proto; if (typeof parent != 'object') { return parent; } if (clone.__isArray(parent)) { child = []; } else if (clone.__isRegExp(parent)) { child = new RegExp(parent.source, __getRegExpFlags(parent)); if (parent.lastIndex) child.lastIndex = parent.lastIndex; } else if (clone.__isDate(parent)) { child = new Date(parent.getTime()); } else if (useBuffer && Buffer.isBuffer(parent)) { if (Buffer.allocUnsafe) { // Node.js >= 4.5.0 child = Buffer.allocUnsafe(parent.length); } else { // Older Node.js versions child = new Buffer(parent.length); } parent.copy(child); return child; } else { if (typeof prototype == 'undefined') { proto = Object.getPrototypeOf(parent); child = Object.create(proto); } else { child = Object.create(prototype); proto = prototype; } } if (circular) { var index = allParents.indexOf(parent); if (index != -1) { return allChildren[index]; } allParents.push(parent); allChildren.push(child); } for (var i in parent) { var attrs; if (proto) { attrs = Object.getOwnPropertyDescriptor(proto, i); } if (attrs && attrs.set == null) { continue; } child[i] = _clone(parent[i], depth - 1); } return child; } return _clone(parent, depth); } /** * Simple flat clone using prototype, accepts only objects, usefull for property * override on FLAT configuration object (no nested props). * * USE WITH CAUTION! This may not behave as you wish if you do not know how this * works. */ clone.clonePrototype = function clonePrototype(parent) { if (parent === null) return null; var c = function () {}; c.prototype = parent; return new c(); }; // private utility functions function __objToStr(o) { return Object.prototype.toString.call(o); }; clone.__objToStr = __objToStr; function __isDate(o) { return typeof o === 'object' && __objToStr(o) === '[object Date]'; }; clone.__isDate = __isDate; function __isArray(o) { return typeof o === 'object' && __objToStr(o) === '[object Array]'; }; clone.__isArray = __isArray; function __isRegExp(o) { return typeof o === 'object' && __objToStr(o) === '[object RegExp]'; }; clone.__isRegExp = __isRegExp; function __getRegExpFlags(re) { var flags = ''; if (re.global) flags += 'g'; if (re.ignoreCase) flags += 'i'; if (re.multiline) flags += 'm'; return flags; }; clone.__getRegExpFlags = __getRegExpFlags; return clone; })(); if (typeof module === 'object' && module.exports) { module.exports = clone; } }).call(this,require("buffer").Buffer) },{"buffer":1}],3:[function(require,module,exports){ /** * Graham's Scan Convex Hull Algorithm * @desc An implementation of the Graham's Scan Convex Hull algorithm in JavaScript. * @author Brian Barnett, brian@3kb.co.uk, http://brianbar.net/ || http://3kb.co.uk/ * @version 1.0.4 */ function ConvexHullGrahamScan(){this.anchorPoint=void 0,this.reverse=!1,this.points=[]}ConvexHullGrahamScan.prototype={constructor:ConvexHullGrahamScan,Point:function(n,t){this.x=n,this.y=t},_findPolarAngle:function(n,t){var i,o,h=57.295779513082;if(!n||!t)return 0;if(i=t.x-n.x,o=t.y-n.y,0==i&&0==o)return 0;var r=Math.atan2(o,i)*h;return this.reverse?0>=r&&(r+=360):r>=0&&(r+=360),r},addPoint:function(n,t){return void 0===this.anchorPoint?void(this.anchorPoint=new this.Point(n,t)):this.anchorPoint.y>t&&this.anchorPoint.x>n||this.anchorPoint.y===t&&this.anchorPoint.x>n||this.anchorPoint.y>t&&this.anchorPoint.x===n?(this.points.push(new this.Point(this.anchorPoint.x,this.anchorPoint.y)),void(this.anchorPoint=new this.Point(n,t))):void this.points.push(new this.Point(n,t))},_sortPoints:function(){var n=this;return this.points.sort(function(t,i){var o=n._findPolarAngle(n.anchorPoint,t),h=n._findPolarAngle(n.anchorPoint,i);return h>o?-1:o>h?1:0})},_checkPoints:function(n,t,i){var o,h=this._findPolarAngle(n,t),r=this._findPolarAngle(n,i);return h>r?(o=h-r,!(o>180)):r>h?(o=r-h,o>180):!0},getHull:function(){var n,t,i=[];if(this.reverse=this.points.every(function(n){return n.x<0&&n.y<0}),n=this._sortPoints(),t=n.length,3>t)return n.unshift(this.anchorPoint),n;for(i.push(n.shift(),n.shift());;){var o,h,r;if(i.push(n.shift()),o=i[i.length-3],h=i[i.length-2],r=i[i.length-1],this._checkPoints(o,h,r)&&i.splice(i.length-2,1),0==n.length){if(t==i.length){var e=this.anchorPoint;return i=i.filter(function(n){return!!n}),i.some(function(n){return n.x==e.x&&n.y==e.y})||i.unshift(this.anchorPoint),i}n=i,t=n.length,i=[],i.push(n.shift(),n.shift())}}}},"function"==typeof define&&define.amd&&define(function(){return ConvexHullGrahamScan}),"undefined"!=typeof module&&(module.exports=ConvexHullGrahamScan); },{}],4:[function(require,module,exports){ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.kdbush = factory()); }(this, (function () { 'use strict'; function sortKD(ids, coords, nodeSize, left, right, depth) { if (right - left <= nodeSize) return; var m = Math.floor((left + right) / 2); select(ids, coords, m, left, right, depth % 2); sortKD(ids, coords, nodeSize, left, m - 1, depth + 1); sortKD(ids, coords, nodeSize, m + 1, right, depth + 1); } function select(ids, coords, k, left, right, inc) { while (right > left) { if (right - left > 600) { var n = right - left + 1; var m = k - left + 1; var z = Math.log(n); var s = 0.5 * Math.exp(2 * z / 3); var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1); var newLeft = Math.max(left, Math.floor(k - m * s / n + sd)); var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd)); select(ids, coords, k, newLeft, newRight, inc); } var t = coords[2 * k + inc]; var i = left; var j = right; swapItem(ids, coords, left, k); if (coords[2 * right + inc] > t) swapItem(ids, coords, left, right); while (i < j) { swapItem(ids, coords, i, j); i++; j--; while (coords[2 * i + inc] < t) i++; while (coords[2 * j + inc] > t) j--; } if (coords[2 * left + inc] === t) swapItem(ids, coords, left, j); else { j++; swapItem(ids, coords, j, right); } if (j <= k) left = j + 1; if (k <= j) right = j - 1; } } function swapItem(ids, coords, i, j) { swap(ids, i, j); swap(coords, 2 * i, 2 * j); swap(coords, 2 * i + 1, 2 * j + 1); } function swap(arr, i, j) { var tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } function range(ids, coords, minX, minY, maxX, maxY, nodeSize) { var stack = [0, ids.length - 1, 0]; var result = []; var x, y; while (stack.length) { var axis = stack.pop(); var right = stack.pop(); var left = stack.pop(); if (right - left <= nodeSize) { for (var i = left; i <= right; i++) { x = coords[2 * i]; y = coords[2 * i + 1]; if (x >= minX && x <= maxX && y >= minY && y <= maxY) result.push(ids[i]); } continue; } var m = Math.floor((left + right) / 2); x = coords[2 * m]; y = coords[2 * m + 1]; if (x >= minX && x <= maxX && y >= minY && y <= maxY) result.push(ids[m]); var nextAxis = (axis + 1) % 2; if (axis === 0 ? minX <= x : minY <= y) { stack.push(left); stack.push(m - 1); stack.push(nextAxis); } if (axis === 0 ? maxX >= x : maxY >= y) { stack.push(m + 1); stack.push(right); stack.push(nextAxis); } } return result; } function within(ids, coords, qx, qy, r, nodeSize) { var stack = [0, ids.length - 1, 0]; var result = []; var r2 = r * r; while (stack.length) { var axis = stack.pop(); var right = stack.pop(); var left = stack.pop(); if (right - left <= nodeSize) { for (var i = left; i <= right; i++) { if (sqDist(coords[2 * i], coords[2 * i + 1], qx, qy) <= r2) result.push(ids[i]); } continue; } var m = Math.floor((left + right) / 2); var x = coords[2 * m]; var y = coords[2 * m + 1]; if (sqDist(x, y, qx, qy) <= r2) result.push(ids[m]); var nextAxis = (axis + 1) % 2; if (axis === 0 ? qx - r <= x : qy - r <= y) { stack.push(left); stack.push(m - 1); stack.push(nextAxis); } if (axis === 0 ? qx + r >= x : qy + r >= y) { stack.push(m + 1); stack.push(right); stack.push(nextAxis); } } return result; } function sqDist(ax, ay, bx, by) { var dx = ax - bx; var dy = ay - by; return dx * dx + dy * dy; } function kdbush(points, getX, getY, nodeSize, ArrayType) { return new KDBush(points, getX, getY, nodeSize, ArrayType); } function KDBush(points, getX, getY, nodeSize, ArrayType) { getX = getX || defaultGetX; getY = getY || defaultGetY; ArrayType = ArrayType || Array; this.nodeSize = nodeSize || 64; this.points = points; this.ids = new ArrayType(points.length); this.coords = new ArrayType(points.length * 2); for (var i = 0; i < points.length; i++) { this.ids[i] = i; this.coords[2 * i] = getX(points[i]); this.coords[2 * i + 1] = getY(points[i]); } sortKD(this.ids, this.coords, this.nodeSize, 0, this.ids.length - 1, 0); } KDBush.prototype = { range: function (minX, minY, maxX, maxY) { return range(this.ids, this.coords, minX, minY, maxX, maxY, this.nodeSize); }, within: function (x, y, r) { return within(this.ids, this.coords, x, y, r, this.nodeSize); } }; function defaultGetX(p) { return p[0]; } function defaultGetY(p) { return p[1]; } return kdbush; }))); },{}],"makerjs":[function(require,module,exports){ /** * Root module for Maker.js. * * Example: get a reference to Maker.js * ``` * var makerjs = require('makerjs'); * ``` * */ var MakerJs; (function (MakerJs) { /** * Version info */ MakerJs.version = 'debug'; /** * Enumeration of environment types. */ MakerJs.environmentTypes = { BrowserUI: 'browser', NodeJs: 'node', WebWorker: 'worker', Unknown: 'unknown' }; /** * @private */ function tryEval(name) { try { var value = eval(name); return value; } catch (e) { } return; } /** * @private */ function detectEnvironment() { if (tryEval('WorkerGlobalScope') && tryEval('self')) { return MakerJs.environmentTypes.WebWorker; } if (tryEval('window') && tryEval('document')) { return MakerJs.environmentTypes.BrowserUI; } //put node last since packagers usually add shims for it if (tryEval('global') && tryEval('process')) { return MakerJs.environmentTypes.NodeJs; } return MakerJs.environmentTypes.Unknown; } /** * Current execution environment type, should be one of environmentTypes. */ MakerJs.environment = detectEnvironment(); //units /** * String-based enumeration of unit types: imperial, metric or otherwise. * A model may specify the unit system it is using, if any. When importing a model, it may have different units. * Unit conversion function is makerjs.units.conversionScale(). * Important: If you add to this, you must also add a corresponding conversion ratio in the unit.ts file! */ MakerJs.unitType = { Centimeter: 'cm', Foot: 'foot', Inch: 'inch', Meter: 'm', Millimeter: 'mm' }; /** * @private */ function split(s, char) { var p = s.indexOf(char); if (p < 0) { return [s]; } else if (p > 0) { return [s.substr(0, p), s.substr(p + 1)]; } else { return ['', s]; } } /** * Split a decimal into its whole and fractional parts as strings. * * Example: get whole and fractional parts of 42.056 * ``` * makerjs.splitDecimal(42.056); //returns ["42", "056"] * ``` * * @param n The number to split. * @returns Array of 2 strings when n contains a decimal point, or an array of one string when n is an integer. */ function splitDecimal(n) { var s = n.toString(); if (s.indexOf('e') > 0) { //max digits is 20 - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed s = n.toFixed(20).match(/.*[^(0+$)]/)[0]; //regex trims trailing zeros } return split(s, '.'); } MakerJs.splitDecimal = splitDecimal; /** * Numeric rounding * * Example: round to 3 decimal places * ``` * makerjs.round(3.14159, .001); //returns 3.142 * ``` * * @param n The number to round off. * @param accuracy Optional exemplar of number of decimal places. * @returns Rounded number. */ function round(n, accuracy) { if (accuracy === void 0) { accuracy = .0000001; } //optimize for early exit for integers if (n % 1 === 0) return n; var exp = 1 - String(Math.ceil(1 / accuracy)).length; //Adapted from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round // If the exp is undefined or zero... if (typeof exp === 'undefined' || +exp === 0) { return Math.round(n); } n = +n; exp = +exp; // If the value is not a number or the exp is not an integer... if (isNaN(n) || !(typeof exp === 'number' && exp % 1 === 0)) { return NaN; } // If the value is negative... if (n < 0) { return -round(-n, accuracy); } // Shift var a = split(n.toString(), 'e'); n = Math.round(+(a[0] + 'e' + (a[1] ? (+a[1] - exp) : -exp))); // Shift back a = split(n.toString(), 'e'); return +(a[0] + 'e' + (a[1] ? (+a[1] + exp) : exp)); } MakerJs.round = round; /** * Create a string representation of a route array. * * @param route Array of strings which are segments of a route. * @returns String of the flattened array. */ function createRouteKey(route) { var converted = []; for (var i = 0; i < route.length; i++) { var element = route[i]; var newElement; if (i % 2 === 0) { newElement = (i > 0 ? '.' : '') + element; } else { newElement = JSON.stringify([element]); } converted.push(newElement); } return converted.join(''); } MakerJs.createRouteKey = createRouteKey; /** * Travel along a route inside of a model to extract a specific node in its tree. * * @param modelContext Model to travel within. * @param route String of a flattened route, or a string array of route segments. * @returns Model or Path object within the modelContext tree. */ function travel(modelContext, route) { if (!modelContext || !route) return null; var routeArray; if (Array.isArray(route)) { routeArray = route; } else { routeArray = JSON.parse(route); } var props = routeArray.slice(); var ref = modelContext; var origin = modelContext.origin || [0, 0]; while (props.length) { var prop = props.shift(); ref = ref[prop]; if (!ref) return null; if (ref.origin && props.length) { origin = MakerJs.point.add(origin, ref.origin); } } return { result: ref, offset: origin }; } MakerJs.travel = travel; /** * @private */ var clone = require('clone'); /** * Clone an object. * * @param objectToClone The object to clone. * @returns A new clone of the original object. */ function cloneObject(objectToClone) { return clone(objectToClone); } MakerJs.cloneObject = cloneObject; /** * Copy the properties from one object to another object. * * Example: * ``` * makerjs.extendObject({ abc: 123 }, { xyz: 789 }); //returns { abc: 123, xyz: 789 } * ``` * * @param target The object to extend. It will receive the new properties. * @param other An object containing properties to merge in. * @returns The original object after merging. */ function extendObject(target, other) { if (target && other) { for (var key in other) { if (typeof other[key] !== 'undefined') { target[key] = other[key]; } } } return target; } MakerJs.extendObject = extendObject; /** * Test to see if a variable is a function. * * @param value The object to test. * @returns True if the object is a function type. */ function isFunction(value) { return typeof value === 'function'; } MakerJs.isFunction = isFunction; /** * Test to see if a variable is a number. * * @param value The object to test. * @returns True if the object is a number type. */ function isNumber(value) { return typeof value === 'number'; } MakerJs.isNumber = isNumber; /** * Test to see if a variable is an object. * * @param value The object to test. * @returns True if the object is an object type. */ function isObject(value) { return typeof value === 'object'; } MakerJs.isObject = isObject; //points /** * Test to see if an object implements the required properties of a point. * * @param item The item to test. */ function isPoint(item) { return item && Array.isArray(item) && item.length == 2 && isNumber(item[0]) && isNumber(item[1]); } MakerJs.isPoint = isPoint; /** * Test to see if an object implements the required properties of a path. * * @param item The item to test. */ function isPath(item) { return item && item.type && isPoint(item.origin); } MakerJs.isPath = isPath; /** * Test to see if an object implements the required properties of a line. * * @param item The item to test. */ function isPathLine(item) { return isPath(item) && item.type == MakerJs.pathType.Line && isPoint(item.end); } MakerJs.isPathLine = isPathLine; /** * Test to see if an object implements the required properties of a circle. * * @param item The item to test. */ function isPathCircle(item) { return isPath(item) && item.type == MakerJs.pathType.Circle && isNumber(item.radius); } MakerJs.isPathCircle = isPathCircle; /** * Test to see if an object implements the required properties of an arc. * * @param item The item to test. */ function isPathArc(item) { return isPath(item) && item.type == MakerJs.pathType.Arc && isNumber(item.radius) && isNumber(item.startAngle) && isNumber(item.endAngle); } MakerJs.isPathArc = isPathArc; /** * Test to see if an object implements the required properties of an arc in a bezier curve. * * @param item The item to test. */ function isPathArcInBezierCurve(item) { return isPathArc(item) && isObject(item.bezierData) && isNumber(item.bezierData.startT) && isNumber(item.bezierData.endT); } MakerJs.isPathArcInBezierCurve = isPathArcInBezierCurve; /** * String-based enumeration of all paths types. * * Examples: use pathType instead of string literal when creating a circle. * ``` * var circle: IPathCircle = { type: pathType.Circle, origin: [0, 0], radius: 7 }; //typescript * var circle = { type: pathType.Circle, origin: [0, 0], radius: 7 }; //javascript * ``` */ MakerJs.pathType = { Line: "line", Circle: "circle", Arc: "arc", BezierSeed: "bezier-seed" }; /** * Test to see if an object implements the required properties of a model. */ function isModel(item) { return item && (item.paths || item.models); } MakerJs.isModel = isModel; /** * Test to see if an object implements the required properties of a chain. * * @param item The item to test. */ function isChain(item) { var x = item; return x && x.links && Array.isArray(x.links) && isNumber(x.pathLength); } MakerJs.isChain = isChain; /** * @private */ var Cascade = /** @class */ (function () { function Cascade(_module, $initial) { this._module = _module; this.$initial = $initial; for (var methodName in this._module) this._shadow(methodName); this.$result = $initial; } Cascade.prototype._shadow = function (methodName) { var _this = this; this[methodName] = function () { return _this._apply(_this._module[methodName], arguments); }; }; Cascade.prototype._apply = function (fn, carriedArguments) { var args = [].slice.call(carriedArguments); args.unshift(this.$result); this.$result = fn.apply(undefined, args); return this; }; Cascade.prototype.$reset = function () { this.$result = this.$initial; return this; }; return Cascade; }()); function $(context) { if (isModel(context)) { return new Cascade(MakerJs.model, context); } else if (isPath(context)) { return new Cascade(MakerJs.path, context); } else if (isPoint(context)) { return new Cascade(MakerJs.point, context); } } MakerJs.$ = $; })(MakerJs || (MakerJs = {})); //CommonJs module.exports = MakerJs; //This file is generated by ./target/cascadable.js var MakerJs; (function (MakerJs) { var angle; (function (angle) { /** * @private */ function getFractionalPart(n) { return MakerJs.splitDecimal(n)[1]; } /** * @private */ function setFractionalPart(n, fractionalPart) { if (fractionalPart) { return +(MakerJs.splitDecimal(n)[0] + '.' + fractionalPart); } else { return n; } } /** * @private */ function copyFractionalPart(src, dest) { if ((src < 0 && dest < 0) || (src > 0 && dest > 0)) { return setFractionalPart(dest, getFractionalPart(src)); } return dest; } /** * Ensures an angle is not greater than 360 * * @param angleInDegrees Angle in degrees. * @returns Same polar angle but not greater than 360 degrees. */ function noRevolutions(angleInDegrees) { var revolutions = Math.floor(angleInDegrees / 360); if (revolutions === 0) return angleInDegrees; var a = angleInDegrees - (360 * revolutions); return copyFractionalPart(angleInDegrees, a); } angle.noRevolutions = noRevolutions; /** * Convert an angle from degrees to radians. * * @param angleInDegrees Angle in degrees. * @returns Angle in radians. */ function toRadians(angleInDegrees) { return noRevolutions(angleInDegrees) * Math.PI / 180.0; } angle.toRadians = toRadians; /** * Convert an angle from radians to degrees. * * @param angleInRadians Angle in radians. * @returns Angle in degrees. */ function toDegrees(angleInRadians) { return angleInRadians * 180.0 / Math.PI; } angle.toDegrees = toDegrees; /** * Get an arc's end angle, ensured to be greater than its start angle. * * @param arc An arc path object. * @returns End angle of arc. */ function ofArcEnd(arc) { //compensate for values past zero. This allows easy compute of total angle size. //for example 0 = 360 if (arc.endAngle < arc.startAngle) { var revolutions = Math.ceil((arc.startAngle - arc.endAngle) / 360); var a = revolutions * 360 + arc.endAngle; return copyFractionalPart(arc.endAngle, a); } return arc.endAngle; } angle.ofArcEnd = ofArcEnd; /** * Get the angle in the middle of an arc's start and end angles. * * @param arc An arc path object. * @param ratio Optional number between 0 and 1 specifying percentage between start and end angles. Default is .5 * @returns Middle angle of arc. */ function ofArcMiddle(arc, ratio) { if (ratio === void 0) { ratio = .5; } return arc.startAngle + ofArcSpan(arc) * ratio; } angle.ofArcMiddle = ofArcMiddle; /** * Total angle of an arc between its start and end angles. * * @param arc The arc to measure. * @returns Angle of arc. */ function ofArcSpan(arc) { var endAngle = angle.ofArcEnd(arc); var a = endAngle - arc.startAngle; if (MakerJs.round(a) > 360) { return noRevolutions(a); } else { return a; } } angle.ofArcSpan = ofArcSpan; /** * Angle of a line path. * * @param line The line path to find the angle of. * @returns Angle of the line path, in degrees. */ function ofLineInDegrees(line) { return noRevolutions(toDegrees(ofPointInRadians(line.origin, line.end))); } angle.ofLineInDegrees = ofLineInDegrees; /** * Angle of a line through a point, in degrees. * * @param pointToFindAngle The point to find the angle. * @param origin Point of origin of the angle. * @returns Angle of the line throught the point, in degrees. */ function ofPointInDegrees(origin, pointToFindAngle) { return toDegrees(ofPointInRadians(origin, pointToFindAngle)); } angle.ofPointInDegrees = ofPointInDegrees; /** * Angle of a line through a point, in radians. * * @param pointToFindAngle The point to find the angle. * @param origin Point of origin of the angle. * @returns Angle of the line throught the point, in radians. */ function ofPointInRadians(origin, pointToFindAngle) { var d = MakerJs.point.subtract(pointToFindAngle, origin); var x = d[0]; var y = d[1]; return Math.atan2(-y, -x) + Math.PI; } angle.ofPointInRadians = ofPointInRadians; /** * Mirror an angle on either or both x and y axes. * * @param angleInDegrees The angle to mirror. * @param mirrorX Boolean to mirror on the x axis. * @param mirrorY Boolean to mirror on the y axis. * @returns Mirrored angle. */ function mirror(angleInDegrees, mirrorX, mirrorY) { if (mirrorY) { angleInDegrees = 360 - angleInDegrees; } if (mirrorX) { angleInDegrees = (angleInDegrees < 180 ? 180 : 540) - angleInDegrees; } return angleInDegrees; } angle.mirror = mirror; /** * @private */ var linkLineMap = {}; linkLineMap[MakerJs.pathType.Arc] = function (arc, first, reversed) { var fromEnd = first != reversed; var angleToRotate = fromEnd ? arc.endAngle - 90 : arc.startAngle + 90; var origin = MakerJs.point.fromArc(arc)[fromEnd ? 1 : 0]; var end = MakerJs.point.rotate(MakerJs.point.add(origin, [arc.radius, 0]), angleToRotate, origin); return new MakerJs.paths.Line(first ? [end, origin] : [origin, end]); }; linkLineMap[MakerJs.pathType.Line] = function (line, first, reversed) { return reversed ? new MakerJs.paths.Line(line.end, line.origin) : line; }; /** * @private */ function getLinkLine(chainLink, first) { if (chainLink) { var p = chainLink.walkedPath.pathContext; var fn = linkLineMap[p.type]; if (fn) { return fn(p, first, chainLink.reversed); } } } /** * Get the angle of a joint between 2 chain links. * * @param linkA First chain link. * @param linkB Second chain link. * @returns Angle between chain links. */ function ofChainLinkJoint(linkA, linkB) { if (arguments.length < 2) return null; var linkLines = [linkA, linkB].map(function (link, i) { return getLinkLine(link, i === 0); }); var result = noRevolutions(ofLineInDegrees(linkLines[1]) - ofLineInDegrees(linkLines[0])); if (result > 180) result -= 360; return result; } angle.ofChainLinkJoint = ofChainLinkJoint; })(angle = MakerJs.angle || (MakerJs.angle = {})); })(MakerJs || (MakerJs = {})); var MakerJs; (function (MakerJs) { var point; (function (point) { /** * Add two points together and return the result as a new point object. * * @param a First point. * @param b Second point. * @param subtract Optional boolean to subtract instead of add. * @returns A new point object. */ function add(a, b, subtract) { var newPoint = clone(a); if (!b) return newPoint; for (var i = 2; i--;) { if (subtract) { newPoint[i] -= b[i]; } else { newPoint[i] += b[i]; } } return newPoint; } point.add = add; /** * Get the average of two points. * * @param a First point. * @param b Second point. * @returns New point object which is the average of a and b. */ function average(a, b) { function avg(i) { return (a[i] + b[i]) / 2; } return [avg(0), avg(1)]; } point.average = average; /** * Clone a point into a new point. * * @param pointToClone The point to clone. * @returns A new point with same values as the original. */ function clone(pointToClone) { if (!pointToClone) return point.zero(); return [pointToClone[0], pointToClone[1]]; } point.clone = clone; /** * From an array of points, find the closest point to a given reference point. * * @param referencePoint The reference point. * @param pointOptions Array of points to choose from. * @returns The first closest point from the pointOptions. */ function closest(referencePoint, pointOptions) { var smallest = { index: 0, distance: -1 }; for (var i = 0; i < pointOptions.length; i++) { var distance = MakerJs.measure.pointDistance(referencePoint, pointOptions[i]); if (smallest.distance == -1 || distance < smallest.distance) { smallest.distance = distance; smallest.index = i; } } return pointOptions[smallest.index]; } point.closest = closest; /** * @private */ var zero_cos = {}; zero_cos[Math.PI / 2] = true; zero_cos[3 * Math.PI / 2] = true; /** * @private */ var zero_sin = {}; zero_sin[Math.PI] = true; zero_sin[2 * Math.PI] = true; /** * Get a point from its polar coordinates. * * @param angleInRadians The angle of the polar coordinate, in radians. * @param radius The radius of the polar coordinate. * @returns A new point object. */ function fromPolar(angleInRadians, radius) { return [ (angleInRadians in zero_cos) ? 0 : MakerJs.round(radius * Math.cos(angleInRadians)), (angleInRadians in zero_sin) ? 0 : MakerJs.round(radius * Math.sin(angleInRadians)) ]; } point.fromPolar = fromPolar; /** * Get a point on a circle or arc path, at a given angle. * @param angleInDegrees The angle at which you want to find the point, in degrees. * @param circle A circle or arc. * @returns A new point object. */ function fromAngleOnCircle(angleInDegrees, circle) { return add(circle.origin, fromPolar(MakerJs.angle.toRadians(angleInDegrees), circle.radius)); } point.fromAngleOnCircle = fromAngleOnCircle; /** * Get the two end points of an arc path. * * @param arc The arc path object. * @returns Array with 2 elements: [0] is the point object corresponding to the start angle, [1] is the point object corresponding to the end angle. */ function fromArc(arc) { return [fromAngleOnCircle(arc.startAngle, arc), fromAngleOnCircle(arc.endAngle, arc)]; } point.fromArc = fromArc; /** * @private */ var pathEndsMap = {}; pathEndsMap[MakerJs.pathType.Arc] = function (arc) { return point.fromArc(arc); }; pathEndsMap[MakerJs.pathType.Line] = function (line) { return [line.origin, line.end]; }; pathEndsMap[MakerJs.pathType.BezierSeed] = pathEndsMap[MakerJs.pathType.Line]; /** * Get the two end points of a path. * * @param pathContext The path object. * @returns Array with 2 elements: [0] is the point object corresponding to the origin, [1] is the point object corresponding to the end. */ function fromPathEnds(pathContext, pathOffset) { var result = null; var fn = pathEndsMap[pathContext.type]; if (fn) { result = fn(pathContext); if (pathOffset) { result = result.map(function (p) { return add(p, pathOffset); }); } } return result; } point.fromPathEnds = fromPathEnds; /** * @private */ function verticalIntersectionPoint(verticalLine, nonVerticalSlope) { var x = verticalLine.origin[0]; var y = nonVerticalSlope.slope * x + nonVerticalSlope.yIntercept; return [x, y]; } /** * Calculates the intersection of slopes of two lines. * * @param lineA First line to use for slope. * @param lineB Second line to use for slope. * @param options Optional IPathIntersectionOptions. * @returns point of intersection of the two slopes, or null if the slopes did not intersect. */ function fromSlopeIntersection(lineA, lineB, options) { if (options === void 0) { options = {}; } var slopeA = MakerJs.measure.lineSlope(lineA); var slopeB = MakerJs.measure.lineSlope(lineB); //see if slope are parallel if (MakerJs.measure.isSlopeParallel(slopeA, slopeB)) { if (MakerJs.measure.isSlopeEqual(slopeA, slopeB)) { //check for overlap options.out_AreOverlapped = MakerJs.measure.isLineOverlapping(lineA, lineB, options.excludeTangents); } return null; } var pointOfIntersection; if (!slopeA.hasSlope) { pointOfIntersection = verticalIntersectionPoint(lineA, slopeB); } else if (!slopeB.hasSlope) { pointOfIntersection = verticalIntersectionPoint(lineB, slopeA); } else { // find intersection by line equation var x = (slopeB.yIntercept - slopeA.yIntercept) / (slopeA.slope - slopeB.slope); var y = slopeA.slope * x + slopeA.yIntercept; pointOfIntersection = [x, y]; } return pointOfIntersection; } point.fromSlopeIntersection = fromSlopeIntersection; /** * @private */ function midCircle(circle, midAngle) { return point.add(circle.origin, point.fromPolar(MakerJs.angle.toRadians(midAngle), circle.radius)); } /** * @private */ var middleMap = {}; middleMap[MakerJs.pathType.Arc] = function (arc, ratio) { var midAngle = MakerJs.angle.ofArcMiddle(arc, ratio); return midCircle(arc, midAngle); }; middleMap[MakerJs.pathType.Circle] = function (circle, ratio) { return midCircle(circle, 360 * ratio); }; middleMap[MakerJs.pathType.Line] = function (line, ratio) { function ration(a, b) { return a + (b - a) * ratio; } ; return [ ration(line.origin[0], line.end[0]), ration(line.origin[1], line.end[1]) ]; }; middleMap[MakerJs.pathType.BezierSeed] = function (seed, ratio) { return MakerJs.models.BezierCurve.computePoint(seed, ratio); }; /** * Get the middle point of a path. * * @param pathContext The path object. * @param ratio Optional ratio (between 0 and 1) of point along the path. Default is .5 for middle. * @returns Point on the path, in the middle of the path. */ function middle(pathContext, ratio) { if (ratio === void 0) { ratio = .5; } var midPoint = null; var fn = middleMap[pathContext.type]; if (fn) { midPoint = fn(pathContext, ratio); } return midPoint; } point.middle = middle; /** * Create a clone of a point, mirrored on either or both x and y axes. * * @param pointToMirror The point to mirror. * @param mirrorX Boolean to mirror on the x axis. * @param mirrorY Boolean to mirror on the y axis. * @returns Mirrored point. */ function mirror(pointToMirror, mirrorX, mirrorY) { var p = clone(pointToMirror); if (mirrorX) { p[0] = -p[0]; } if (mirrorY) { p[1] = -p[1]; } return p; } point.mirror = mirror; /** * Round the values of a point. * * @param pointContext The point to serialize. * @param accuracy Optional exemplar number of decimal places. * @returns A new point with the values rounded. */ function rounded(pointContext, accuracy) { return [MakerJs.round(pointContext[0], accuracy), MakerJs.round(pointContext[1], accuracy)]; } point.rounded = rounded; /** * Rotate a point. * * @param pointToRotate The point to rotate. * @param angleInDegrees The amount of rotation, in degrees. * @param rotationOrigin The center point of rotation. * @returns A new point. */ function rotate(pointToRotate, angleInDegrees, rotationOrigin) { if (rotationOrigin === void 0) { rotationOrigin = [0, 0]; } var pointAngleInRadians = MakerJs.angle.ofPointInRadians(rotationOrigin, pointToRotate); var d = MakerJs.measure.pointDistance(rotationOrigin, pointToRotate); var rotatedPoint = fromPolar(pointAngleInRadians + MakerJs.angle.toRadians(angleInDegrees), d); return add(rotationOrigin, rotatedPoint); } point.rotate = rotate; /** * Scale a point's coordinates. * * @param pointToScale The point to scale. * @param scaleValue The amount of scaling. * @returns A new point. */ function scale(pointToScale, scaleValue) { var p = clone(pointToScale); for (var i = 2; i--;) { p[i] *= scaleValue; } return p; } point.scale = scale; /** * Distort a point's coordinates. * * @param pointToDistort The point to distort. * @param scaleX The amount of x scaling. * @param scaleY The amount of y scaling. * @returns A new point. */ function distort(pointToDistort, scaleX, scaleY) { return [pointToDistort[0] * scaleX, pointToDistort[1] * scaleY]; } point.distort