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
JavaScript
/*
__________________________________________________________________________________________________________________________________________
__________________________________________________________________________________________________________________________________________
________/\\\\____________/\\\\_____/\\\\\\\\\_____/\\\________/\\\__/\\\\\\\\\\\\\\\__/\\\\\\\\\\\________________________________________
_______\/\\\\\\________/\\\\\\___/\\\\/////\\\\__\/\\\_____/\\\//__\/\\\///////////__\/\\\///////\\\_______________/\\\___________________
_______\/\\\//\\\____/\\\//\\\__/\\\/____\///\\\_\/\\\__/\\\//_____\/\\\_____________\/\\\_____\/\\\______________\///____________________
_______\/\\\\///\\\/\\\/_\/\\\_\/\\\_______\/\\\_\/\\\\\\//\\\_____\/\\\\\\\\\\\_____\/\\\\\\\\\\\/________________/\\\__/\\\\\\\\\\______
_______\/\\\__\///\\\/___\/\\\_\/\\\\\\\\\\\\\\\_\/\\\//_\//\\\____\/\\\///////______\/\\\//////\\\_______________\/\\\_\/\\\//////_______
_______\/\\\____\///_____\/\\\_\/\\\/////////\\\_\/\\\____\//\\\___\/\\\_____________\/\\\____\//\\\______________\/\\\_\/\\\\\\\\\\______
_______\/\\\_____________\/\\\_\/\\\_______\/\\\_\/\\\_____\//\\\__\/\\\_____________\/\\\_____\//\\\_________/\\_\/\\\_\////////\\\______
_______\/\\\_____________\/\\\_\/\\\_______\/\\\_\/\\\______\//\\\_\/\\\\\\\\\\\\\\\_\/\\\______\//\\\__/\\\_\//\\\\\\___/\\\\\\\\\\______
_______\///______________\///__\///________\///__\///________\///__\///////////////__\///________\///__\///___\//////___\//////////_______
__________________________________________________________________________________________________________________________________________
__________________________________________________________________________________________________________________________________________
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