diff --git a/article.js b/article.js index 87419f00..7851d6e5 100644 --- a/article.js +++ b/article.js @@ -1,21763 +1,20 @@ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["BezierArticle"] = factory(); - else - root["BezierArticle"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.l = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; - -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; - -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; - -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 116); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var React = __webpack_require__(1); -var Locale = __webpack_require__(3); -var locale = new Locale(); - -module.exports = function generateBase(page, handler) { - - // the basic class just has a title and basic content. - var componentClass = { - getDefaultProps: function getDefaultProps() { - return { - title: locale.getTitle(page) - }; - }, - - render: function render() { - return locale.getContent(page, this); - } - }; - - // if the content requires code bindings, ensure those exist: - if (handler) { - Object.keys(handler).forEach(function (key) { - componentClass[key] = handler[key]; - }); - } - - // then build the actual React class - return React.createClass(componentClass); -}; - -/***/ }), -/* 1 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) {Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_proptypes__ = __webpack_require__(114); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_proptypes___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_proptypes__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_preact__ = __webpack_require__(112); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_preact___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_preact__); -/* harmony reexport (default from non-hamory) */ __webpack_require__.d(__webpack_exports__, "PropTypes", function() { return __WEBPACK_IMPORTED_MODULE_0_proptypes___default.a; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "version", function() { return version; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DOM", function() { return DOM; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Children", function() { return Children; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "render", function() { return render$1; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createClass", function() { return createClass; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createFactory", function() { return createFactory; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createElement", function() { return createElement; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "cloneElement", function() { return cloneElement$1; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isValidElement", function() { return isValidElement; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "findDOMNode", function() { return findDOMNode; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "unmountComponentAtNode", function() { return unmountComponentAtNode; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Component", function() { return Component$1; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PureComponent", function() { return PureComponent; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "unstable_renderSubtreeIntoContainer", function() { return renderSubtreeIntoContainer; }); - - - -var version = '15.1.0'; // trick libraries to think we are react - -var ELEMENTS = 'a abbr address area article aside audio b base bdi bdo big blockquote body br button canvas caption cite code col colgroup data datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins kbd keygen label legend li link main map mark menu menuitem meta meter nav noscript object ol optgroup option output p param picture pre progress q rp rt ruby s samp script section select small source span strong style sub summary sup table tbody td textarea tfoot th thead time title tr track u ul var video wbr circle clipPath defs ellipse g image line linearGradient mask path pattern polygon polyline radialGradient rect stop svg text tspan'.split(' '); - -var REACT_ELEMENT_TYPE = (typeof Symbol!=='undefined' && Symbol.for && Symbol.for('react.element')) || 0xeac7; - -var COMPONENT_WRAPPER_KEY = typeof Symbol!=='undefined' ? Symbol.for('__preactCompatWrapper') : '__preactCompatWrapper'; - -// don't autobind these methods since they already have guaranteed context. -var AUTOBIND_BLACKLIST = { - constructor: 1, - render: 1, - shouldComponentUpdate: 1, - componentWillReceiveProps: 1, - componentWillUpdate: 1, - componentDidUpdate: 1, - componentWillMount: 1, - componentDidMount: 1, - componentWillUnmount: 1, - componentDidUnmount: 1 -}; - - -var CAMEL_PROPS = /^(?:accent|alignment|arabic|baseline|cap|clip|color|fill|flood|font|glyph|horiz|marker|overline|paint|stop|strikethrough|stroke|text|underline|unicode|units|v|vert|word|writing|x)[A-Z]/; - - -var BYPASS_HOOK = {}; - -/*global process*/ -var DEV = typeof process==='undefined' || !process.env || process.env.NODE_ENV!=='production'; - -// a component that renders nothing. Used to replace components for unmountComponentAtNode. -function EmptyComponent() { return null; } - - - -// make react think we're react. -var VNode = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1_preact__["h"])('a', null).constructor; -VNode.prototype.$$typeof = REACT_ELEMENT_TYPE; -VNode.prototype.preactCompatUpgraded = false; -VNode.prototype.preactCompatNormalized = false; - -Object.defineProperty(VNode.prototype, 'type', { - get: function() { return this.nodeName; }, - set: function(v) { this.nodeName = v; }, - configurable:true -}); - -Object.defineProperty(VNode.prototype, 'props', { - get: function() { return this.attributes; }, - set: function(v) { this.attributes = v; }, - configurable:true -}); - - - -var oldEventHook = __WEBPACK_IMPORTED_MODULE_1_preact__["options"].event; -__WEBPACK_IMPORTED_MODULE_1_preact__["options"].event = function (e) { - if (oldEventHook) { e = oldEventHook(e); } - e.persist = Object; - e.nativeEvent = e; - return e; -}; - - -var oldVnodeHook = __WEBPACK_IMPORTED_MODULE_1_preact__["options"].vnode; -__WEBPACK_IMPORTED_MODULE_1_preact__["options"].vnode = function (vnode) { - if (!vnode.preactCompatUpgraded) { - vnode.preactCompatUpgraded = true; - - var tag = vnode.nodeName, - attrs = vnode.attributes = extend({}, vnode.attributes); - - if (typeof tag==='function') { - if (tag[COMPONENT_WRAPPER_KEY]===true || (tag.prototype && 'isReactComponent' in tag.prototype)) { - if (vnode.children && !vnode.children.length) { vnode.children = undefined; } - if (vnode.children) { attrs.children = vnode.children; } - - if (!vnode.preactCompatNormalized) { - normalizeVNode(vnode); - } - handleComponentVNode(vnode); - } - } - else { - if (vnode.children && !vnode.children.length) { vnode.children = undefined; } - if (vnode.children) { attrs.children = vnode.children; } - - if (attrs.defaultValue) { - if (!attrs.value && attrs.value!==0) { - attrs.value = attrs.defaultValue; - } - delete attrs.defaultValue; - } - - handleElementVNode(vnode, attrs); - } - } - - if (oldVnodeHook) { oldVnodeHook(vnode); } -}; - -function handleComponentVNode(vnode) { - var tag = vnode.nodeName, - a = vnode.attributes; - - vnode.attributes = {}; - if (tag.defaultProps) { extend(vnode.attributes, tag.defaultProps); } - if (a) { extend(vnode.attributes, a); } -} - -function handleElementVNode(vnode, a) { - var shouldSanitize, attrs, i; - if (a) { - for (i in a) { if ((shouldSanitize = CAMEL_PROPS.test(i))) { break; } } - if (shouldSanitize) { - attrs = vnode.attributes = {}; - for (i in a) { - if (a.hasOwnProperty(i)) { - attrs[ CAMEL_PROPS.test(i) ? i.replace(/([A-Z0-9])/, '-$1').toLowerCase() : i ] = a[i]; - } - } - } - } -} - - - -// proxy render() since React returns a Component reference. -function render$1(vnode, parent, callback) { - var prev = parent && parent._preactCompatRendered && parent._preactCompatRendered.base; - - // ignore impossible previous renders - if (prev && prev.parentNode!==parent) { prev = null; } - - // default to first Element child - if (!prev) { prev = parent.children[0]; } - - // remove unaffected siblings - for (var i=parent.childNodes.length; i--; ) { - if (parent.childNodes[i]!==prev) { - parent.removeChild(parent.childNodes[i]); - } - } - - var out = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1_preact__["render"])(vnode, parent, prev); - if (parent) { parent._preactCompatRendered = out && (out._component || { base: out }); } - if (typeof callback==='function') { callback(); } - return out && out._component || out; -} - - -var ContextProvider = function () {}; - -ContextProvider.prototype.getChildContext = function () { - return this.props.context; -}; -ContextProvider.prototype.render = function (props) { - return props.children[0]; -}; - -function renderSubtreeIntoContainer(parentComponent, vnode, container, callback) { - var wrap = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1_preact__["h"])(ContextProvider, { context: parentComponent.context }, vnode); - var c = render$1(wrap, container); - if (callback) { callback(c); } - return c._component || c.base; -} - - -function unmountComponentAtNode(container) { - var existing = container._preactCompatRendered && container._preactCompatRendered.base; - if (existing && existing.parentNode===container) { - __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1_preact__["render"])(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1_preact__["h"])(EmptyComponent), container, existing); - return true; - } - return false; -} - - - -var ARR = []; - -// This API is completely unnecessary for Preact, so it's basically passthrough. -var Children = { - map: function(children, fn, ctx) { - if (children == null) { return null; } - children = Children.toArray(children); - if (ctx && ctx!==children) { fn = fn.bind(ctx); } - return children.map(fn); - }, - forEach: function(children, fn, ctx) { - if (children == null) { return null; } - children = Children.toArray(children); - if (ctx && ctx!==children) { fn = fn.bind(ctx); } - children.forEach(fn); - }, - count: function(children) { - return children && children.length || 0; - }, - only: function(children) { - children = Children.toArray(children); - if (children.length!==1) { throw new Error('Children.only() expects only one child.'); } - return children[0]; - }, - toArray: function(children) { - return Array.isArray && Array.isArray(children) ? children : ARR.concat(children); - } -}; - - -/** Track current render() component for ref assignment */ -var currentComponent; - - -function createFactory(type) { - return createElement.bind(null, type); -} - - -var DOM = {}; -for (var i=ELEMENTS.length; i--; ) { - DOM[ELEMENTS[i]] = createFactory(ELEMENTS[i]); -} - -function upgradeToVNodes(arr, offset) { - for (var i=offset || 0; i 0 ) children[ len ] = arguments[ len + 2 ]; - - if (!isValidElement(element)) { return element; } - var elementProps = element.attributes || element.props; - var node = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1_preact__["h"])( - element.nodeName || element.type, - elementProps, - element.children || elementProps && elementProps.children - ); - // Only provide the 3rd argument if needed. - // Arguments 3+ overwrite element.children in preactCloneElement - var cloneArgs = [node, props]; - if (children && children.length) { - cloneArgs.push(children); - } - else if (props && props.children) { - cloneArgs.push(props.children); - } - return normalizeVNode(__WEBPACK_IMPORTED_MODULE_1_preact__["cloneElement"].apply(void 0, cloneArgs)); -} - - -function isValidElement(element) { - return element && ((element instanceof VNode) || element.$$typeof===REACT_ELEMENT_TYPE); -} - - -function createStringRefProxy(name, component) { - return component._refProxies[name] || (component._refProxies[name] = function (resolved) { - if (component && component.refs) { - component.refs[name] = resolved; - if (resolved===null) { - delete component._refProxies[name]; - component = null; - } - } - }); -} - - -function applyEventNormalization(ref) { - var nodeName = ref.nodeName; - var attributes = ref.attributes; - - if (!attributes || typeof nodeName!=='string') { return; } - var props = {}; - for (var i in attributes) { - props[i.toLowerCase()] = i; - } - if (props.ondoubleclick) { - attributes.ondblclick = attributes[props.ondoubleclick]; - delete attributes[props.ondoubleclick]; - } - // for *textual inputs* (incl textarea), normalize `onChange` -> `onInput`: - if (props.onchange && (nodeName==='textarea' || (nodeName.toLowerCase()==='input' && !/^fil|che|rad/i.test(attributes.type)))) { - var normalized = props.oninput || 'oninput'; - if (!attributes[normalized]) { - attributes[normalized] = multihook([attributes[normalized], attributes[props.onchange]]); - delete attributes[props.onchange]; - } - } -} - - -function applyClassName(ref) { - var attributes = ref.attributes; - - if (!attributes) { return; } - var cl = attributes.className || attributes.class; - if (cl) { attributes.className = cl; } -} - - -function extend(base, props) { - for (var key in props) { - if (props.hasOwnProperty(key)) { - base[key] = props[key]; - } - } - return base; -} - - -function shallowDiffers(a, b) { - for (var i in a) { if (!(i in b)) { return true; } } - for (var i$1 in b) { if (a[i$1]!==b[i$1]) { return true; } } - return false; -} - - -function findDOMNode(component) { - return component && component.base || component; -} - - -function F(){} - -function createClass(obj) { - function cl(props, context) { - bindAll(this); - Component$1.call(this, props, context, BYPASS_HOOK); - newComponentHook.call(this, props, context); - } - - obj = extend({ constructor: cl }, obj); - - // We need to apply mixins here so that getDefaultProps is correctly mixed - if (obj.mixins) { - applyMixins(obj, collateMixins(obj.mixins)); - } - if (obj.statics) { - extend(cl, obj.statics); - } - if (obj.propTypes) { - cl.propTypes = obj.propTypes; - } - if (obj.defaultProps) { - cl.defaultProps = obj.defaultProps; - } - if (obj.getDefaultProps) { - cl.defaultProps = obj.getDefaultProps(); - } - - F.prototype = Component$1.prototype; - cl.prototype = extend(new F(), obj); - - cl.displayName = obj.displayName || 'Component'; - - return cl; -} - - -// Flatten an Array of mixins to a map of method name to mixin implementations -function collateMixins(mixins) { - var keyed = {}; - for (var i=0; i4) { - if (arguments.length !== 1) { - throw new Error("Only new Bezier(point[]) is accepted for 4th and higher order curves"); - } - higher = true; - } - } else { - if(len!==6 && len!==8 && len!==9 && len!==12) { - if (arguments.length !== 1) { - throw new Error("Only new Bezier(point[]) is accepted for 4th and higher order curves"); - } - } - } - var _3d = (!higher && (len === 9 || len === 12)) || (coords && coords[0] && typeof coords[0].z !== "undefined"); - this._3d = _3d; - var points = []; - for(var idx=0, step=(_3d ? 3 : 2); idx 0.0001) { - curve._linear = false; - return; - } - } - curve._linear = true; - }(this)); - - this._t1 = 0; - this._t2 = 1; - this.update(); - }; - - Bezier.fromSVG = function(svgString) { - var list = svgString.match(/[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?/g).map(parseFloat); - var relative = /[cq]/.test(svgString); - if(!relative) return new Bezier(list); - list = list.map(function(v,i) { - return i < 2 ? v : v + list[i % 2]; - }); - return new Bezier(list); - }; - - function getABC(n,S,B,E,t) { - if(typeof t === "undefined") { t = 0.5; } - var u = utils.projectionratio(t,n), - um = 1-u, - C = { - x: u*S.x + um*E.x, - y: u*S.y + um*E.y - }, - s = utils.abcratio(t,n), - A = { - x: B.x + (B.x-C.x)/s, - y: B.y + (B.y-C.y)/s - }; - return { A:A, B:B, C:C }; - } - - Bezier.quadraticFromPoints = function(p1,p2,p3, t) { - if(typeof t === "undefined") { t = 0.5; } - // shortcuts, although they're really dumb - if(t===0) { return new Bezier(p2,p2,p3); } - if(t===1) { return new Bezier(p1,p2,p2); } - // real fitting. - var abc = getABC(2,p1,p2,p3,t); - return new Bezier(p1, abc.A, p3); - }; - - Bezier.cubicFromPoints = function(S,B,E, t,d1) { - if(typeof t === "undefined") { t = 0.5; } - var abc = getABC(3,S,B,E,t); - if(typeof d1 === "undefined") { d1 = utils.dist(B,abc.C); } - var d2 = d1 * (1-t)/t; - - var selen = utils.dist(S,E), - lx = (E.x-S.x)/selen, - ly = (E.y-S.y)/selen, - bx1 = d1 * lx, - by1 = d1 * ly, - bx2 = d2 * lx, - by2 = d2 * ly; - // derivation of new hull coordinates - var e1 = { x: B.x - bx1, y: B.y - by1 }, - e2 = { x: B.x + bx2, y: B.y + by2 }, - A = abc.A, - v1 = { x: A.x + (e1.x-A.x)/(1-t), y: A.y + (e1.y-A.y)/(1-t) }, - v2 = { x: A.x + (e2.x-A.x)/(t), y: A.y + (e2.y-A.y)/(t) }, - nc1 = { x: S.x + (v1.x-S.x)/(t), y: S.y + (v1.y-S.y)/(t) }, - nc2 = { x: E.x + (v2.x-E.x)/(1-t), y: E.y + (v2.y-E.y)/(1-t) }; - // ...done - return new Bezier(S,nc1,nc2,E); - }; - - var getUtils = function() { - return utils; - }; - - Bezier.getUtils = getUtils; - - Bezier.prototype = { - getUtils: getUtils, - valueOf: function() { - return this.toString(); - }, - toString: function() { - return utils.pointsToString(this.points); - }, - toSVG: function(relative) { - if(this._3d) return false; - var p = this.points, - x = p[0].x, - y = p[0].y, - s = ["M", x, y, (this.order===2 ? "Q":"C")]; - for(var i=1, last=p.length; i1; d--, c--) { - var list = []; - for(var j=0, dpt; j 0; - }, - length: function() { - return utils.length(this.derivative.bind(this)); - }, - _lut: [], - getLUT: function(steps) { - steps = steps || 100; - if (this._lut.length === steps) { return this._lut; } - this._lut = []; - for(var t=0; t<=steps; t++) { - this._lut.push(this.compute(t/steps)); - } - return this._lut; - }, - on: function(point, error) { - error = error || 5; - var lut = this.getLUT(), hits = [], c, t=0; - for(var i=0; i 1) { - for (var i=0; i1) { - _p = []; - for(i=0, l=p.length-1; i=0 && t<=1); }); - roots = roots.concat(result[dim].sort()); - }.bind(this)); - roots = roots.sort().filter(function(v,idx) { return (roots.indexOf(v) === idx); }); - result.values = roots; - return result; - }, - bbox: function() { - var extrema = this.extrema(), result = {}; - this.dims.forEach(function(d) { - result[d] = utils.getminmax(this, d, extrema[d]); - }.bind(this)); - return result; - }, - overlaps: function(curve) { - var lbbox = this.bbox(), - tbbox = curve.bbox(); - return utils.bboxoverlap(lbbox,tbbox); - }, - offset: function(t, d) { - if(typeof d !== "undefined") { - var c = this.get(t); - var n = this.normal(t); - var ret = { - c: c, - n: n, - x: c.x + n.x * d, - y: c.y + n.y * d - }; - if(this._3d) { - ret.z = c.z + n.z * d; - }; - return ret; - } - if(this._linear) { - var nv = this.normal(0); - var coords = this.points.map(function(p) { - var ret = { - x: p.x + t * nv.x, - y: p.y + t * nv.y - }; - if(p.z && n.z) { ret.z = p.z + t * nv.z; } - return ret; - }); - return [new Bezier(coords)]; - } - var reduced = this.reduce(); - return reduced.map(function(s) { - return s.scale(t); - }); - }, - simple: function() { - if(this.order===3) { - var a1 = utils.angle(this.points[0], this.points[3], this.points[1]); - var a2 = utils.angle(this.points[0], this.points[3], this.points[2]); - if(a1>0 && a2<0 || a1<0 && a2>0) return false; - } - var n1 = this.normal(0); - var n2 = this.normal(1); - var s = n1.x*n2.x + n1.y*n2.y; - if(this._3d) { s += n1.z*n2.z; } - var angle = abs(acos(s)); - return angle < pi/3; - }, - reduce: function() { - var i, t1=0, t2=0, step=0.01, segment, pass1=[], pass2=[]; - // first pass: split on extrema - var extrema = this.extrema().values; - if(extrema.indexOf(0)===-1) { extrema = [0].concat(extrema); } - if(extrema.indexOf(1)===-1) { extrema.push(1); } - - for(t1=extrema[0], i=1; i 1); - shape.endcap.virtual = (i < len/2-1); - shapes.push(shape); - } - return shapes; - }, - intersects: function(curve, curveIntersectionThreshold) { - if(!curve) return this.selfintersects(curveIntersectionThreshold); - if(curve.p1 && curve.p2) { - return this.lineIntersects(curve); - } - if(curve instanceof Bezier) { curve = curve.reduce(); } - return this.curveintersects(this.reduce(), curve, curveIntersectionThreshold); - }, - lineIntersects: function(line) { - var mx = min(line.p1.x, line.p2.x), - my = min(line.p1.y, line.p2.y), - MX = max(line.p1.x, line.p2.x), - MY = max(line.p1.y, line.p2.y), - self=this; - return utils.roots(this.points, line).filter(function(t) { - var p = self.get(t); - return utils.between(p.x, mx, MX) && utils.between(p.y, my, MY); - }); - }, - selfintersects: function(curveIntersectionThreshold) { - var reduced = this.reduce(); - // "simple" curves cannot intersect with their direct - // neighbour, so for each segment X we check whether - // it intersects [0:x-2][x+2:last]. - var i,len=reduced.length-2,results=[],result,left,right; - for(i=0; i 0) { - intersections = intersections.concat(result); - } - }); - return intersections; - }, - arcs: function(errorThreshold) { - errorThreshold = errorThreshold || 0.5; - var circles = []; - return this._iterate(errorThreshold, circles); - }, - _error: function(pc, np1, s, e) { - var q = (e - s) / 4, - c1 = this.get(s + q), - c2 = this.get(e - q), - ref = utils.dist(pc, np1), - d1 = utils.dist(pc, c1), - d2 = utils.dist(pc, c2); - return abs(d1-ref) + abs(d2-ref); - }, - _iterate: function(errorThreshold, circles) { - var s = 0, e = 1, safety; - // we do a binary search to find the "good `t` closest to no-longer-good" - do { - safety=0; - - // step 1: start with the maximum possible arc - e = 1; - - // points: - var np1 = this.get(s), np2, np3, arc, prev_arc; - - // booleans: - var curr_good = false, prev_good = false, done; - - // numbers: - var m = e, prev_e = 1, step = 0; - - // step 2: find the best possible arc - do { - prev_good = curr_good; - prev_arc = arc; - m = (s + e)/2; - step++; - - np2 = this.get(m); - np3 = this.get(e); - - arc = utils.getccenter(np1, np2, np3); - - //also save the t values - arc.interval = { - start: s, - end: e - }; - - var error = this._error(arc, np1, s, e); - curr_good = (error <= errorThreshold); - - done = prev_good && !curr_good; - if(!done) prev_e = e; - - // this arc is fine: we can move 'e' up to see if we can find a wider arc - if(curr_good) { - // if e is already at max, then we're done for this arc. - if (e >= 1) { - prev_e = 1; - prev_arc = arc; - break; - } - // if not, move it up by half the iteration distance - e = e + (e-s)/2; - } - - // this is a bad arc: we need to move 'e' down to find a good arc - else { - e = m; - } - } - while(!done && safety++<100); - - if(safety>=100) { - console.error("arc abstraction somehow failed..."); - break; - } - - // console.log("[F] arc found", s, prev_e, prev_arc.x, prev_arc.y, prev_arc.s, prev_arc.e); - - prev_arc = (prev_arc ? prev_arc : arc); - circles.push(prev_arc); - s = prev_e; - } - while(e < 1); - return circles; - } - }; - - module.exports = Bezier; - -}()); - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -(function() { - "use strict"; - - // math-inlining. - var abs = Math.abs, - cos = Math.cos, - sin = Math.sin, - acos = Math.acos, - atan2 = Math.atan2, - sqrt = Math.sqrt, - pow = Math.pow, - // cube root function yielding real roots - crt = function(v) { return (v<0) ? -pow(-v,1/3) : pow(v,1/3); }, - // trig constants - pi = Math.PI, - tau = 2*pi, - quart = pi/2, - // float precision significant decimal - epsilon = 0.000001; - - // Bezier utility functions - var utils = { - // Legendre-Gauss abscissae with n=24 (x_i values, defined at i=n as the roots of the nth order Legendre polynomial Pn(x)) - Tvalues: [ - -0.0640568928626056260850430826247450385909, - 0.0640568928626056260850430826247450385909, - -0.1911188674736163091586398207570696318404, - 0.1911188674736163091586398207570696318404, - -0.3150426796961633743867932913198102407864, - 0.3150426796961633743867932913198102407864, - -0.4337935076260451384870842319133497124524, - 0.4337935076260451384870842319133497124524, - -0.5454214713888395356583756172183723700107, - 0.5454214713888395356583756172183723700107, - -0.6480936519369755692524957869107476266696, - 0.6480936519369755692524957869107476266696, - -0.7401241915785543642438281030999784255232, - 0.7401241915785543642438281030999784255232, - -0.8200019859739029219539498726697452080761, - 0.8200019859739029219539498726697452080761, - -0.8864155270044010342131543419821967550873, - 0.8864155270044010342131543419821967550873, - -0.9382745520027327585236490017087214496548, - 0.9382745520027327585236490017087214496548, - -0.9747285559713094981983919930081690617411, - 0.9747285559713094981983919930081690617411, - -0.9951872199970213601799974097007368118745, - 0.9951872199970213601799974097007368118745 - ], - - // Legendre-Gauss weights with n=24 (w_i values, defined by a function linked to in the Bezier primer article) - Cvalues: [ - 0.1279381953467521569740561652246953718517, - 0.1279381953467521569740561652246953718517, - 0.1258374563468282961213753825111836887264, - 0.1258374563468282961213753825111836887264, - 0.1216704729278033912044631534762624256070, - 0.1216704729278033912044631534762624256070, - 0.1155056680537256013533444839067835598622, - 0.1155056680537256013533444839067835598622, - 0.1074442701159656347825773424466062227946, - 0.1074442701159656347825773424466062227946, - 0.0976186521041138882698806644642471544279, - 0.0976186521041138882698806644642471544279, - 0.0861901615319532759171852029837426671850, - 0.0861901615319532759171852029837426671850, - 0.0733464814110803057340336152531165181193, - 0.0733464814110803057340336152531165181193, - 0.0592985849154367807463677585001085845412, - 0.0592985849154367807463677585001085845412, - 0.0442774388174198061686027482113382288593, - 0.0442774388174198061686027482113382288593, - 0.0285313886289336631813078159518782864491, - 0.0285313886289336631813078159518782864491, - 0.0123412297999871995468056670700372915759, - 0.0123412297999871995468056670700372915759 - ], - - arcfn: function(t, derivativeFn) { - var d = derivativeFn(t); - var l = d.x*d.x + d.y*d.y; - if(typeof d.z !== "undefined") { - l += d.z*d.z; - } - return sqrt(l); - }, - - between: function(v, m, M) { - return (m <= v && v <= M) || utils.approximately(v, m) || utils.approximately(v, M); - }, - - approximately: function(a,b,precision) { - return abs(a-b) <= (precision || epsilon); - }, - - length: function(derivativeFn) { - var z=0.5,sum=0,len=utils.Tvalues.length,i,t; - for(i=0; i bbox.x.min) mx = bbox.x.min; - if(my > bbox.y.min) my = bbox.y.min; - if(MX < bbox.x.max) MX = bbox.x.max; - if(MY < bbox.y.max) MY = bbox.y.max; - }); - return { - x: { min: mx, mid:(mx+MX)/2, max: MX, size:MX-mx }, - y: { min: my, mid:(my+MY)/2, max: MY, size:MY-my } - } - }, - - shapeintersections: function(s1, bbox1, s2, bbox2, curveIntersectionThreshold) { - if(!utils.bboxoverlap(bbox1, bbox2)) return []; - var intersections = []; - var a1 = [s1.startcap, s1.forward, s1.back, s1.endcap]; - var a2 = [s2.startcap, s2.forward, s2.back, s2.endcap]; - a1.forEach(function(l1) { - if(l1.virtual) return; - a2.forEach(function(l2) { - if(l2.virtual) return; - var iss = l1.intersects(l2, curveIntersectionThreshold); - if(iss.length>0) { - iss.c1 = l1; - iss.c2 = l2; - iss.s1 = s1; - iss.s2 = s2; - intersections.push(iss); - } - }); - }); - return intersections; - }, - - makeshape: function(forward, back, curveIntersectionThreshold) { - var bpl = back.points.length; - var fpl = forward.points.length; - var start = utils.makeline(back.points[bpl-1], forward.points[0]); - var end = utils.makeline(forward.points[fpl-1], back.points[0]); - var shape = { - startcap: start, - forward: forward, - back: back, - endcap: end, - bbox: utils.findbbox([start, forward, back, end]) - }; - var self = utils; - shape.intersections = function(s2) { - return self.shapeintersections(shape,shape.bbox,s2,s2.bbox, curveIntersectionThreshold); - }; - return shape; - }, - - getminmax: function(curve, d, list) { - if(!list) return { min:0, max:0 }; - var min=0xFFFFFFFFFFFFFFFF, max=-min,t,c; - if(list.indexOf(0)===-1) { list = [0].concat(list); } - if(list.indexOf(1)===-1) { list.push(1); } - for(var i=0,len=list.length; i max) { max = c[d]; } - } - return { min:min, mid:(min+max)/2, max:max, size:max-min }; - }, - - align: function(points, line) { - var tx = line.p1.x, - ty = line.p1.y, - a = -atan2(line.p2.y-ty, line.p2.x-tx), - d = function(v) { - return { - x: (v.x-tx)*cos(a) - (v.y-ty)*sin(a), - y: (v.x-tx)*sin(a) + (v.y-ty)*cos(a) - }; - }; - return points.map(d); - }, - - roots: function(points, line) { - line = line || {p1:{x:0,y:0},p2:{x:1,y:0}}; - var order = points.length - 1; - var p = utils.align(points, line); - var reduce = function(t) { return 0<=t && t <=1; }; - - if (order === 2) { - var a = p[0].y, - b = p[1].y, - c = p[2].y, - d = a - 2*b + c; - if(d!==0) { - var m1 = -sqrt(b*b-a*c), - m2 = -a+b, - v1 = -( m1+m2)/d, - v2 = -(-m1+m2)/d; - return [v1, v2].filter(reduce); - } - else if(b!==c && d===0) { - return [ (2*b-c)/2*(b-c) ].filter(reduce); - } - return []; - } - - // see http://www.trans4mind.com/personal_development/mathematics/polynomials/cubicAlgebra.htm - var pa = p[0].y, - pb = p[1].y, - pc = p[2].y, - pd = p[3].y, - d = (-pa + 3*pb - 3*pc + pd), - a = (3*pa - 6*pb + 3*pc) / d, - b = (-3*pa + 3*pb) / d, - c = pa / d, - p = (3*b - a*a)/3, - p3 = p/3, - q = (2*a*a*a - 9*a*b + 27*c)/27, - q2 = q/2, - discriminant = q2*q2 + p3*p3*p3, - u1,v1,x1,x2,x3; - if (discriminant < 0) { - var mp3 = -p/3, - mp33 = mp3*mp3*mp3, - r = sqrt( mp33 ), - t = -q/(2*r), - cosphi = t<-1 ? -1 : t>1 ? 1 : t, - phi = acos(cosphi), - crtr = crt(r), - t1 = 2*crtr; - x1 = t1 * cos(phi/3) - a/3; - x2 = t1 * cos((phi+tau)/3) - a/3; - x3 = t1 * cos((phi+2*tau)/3) - a/3; - return [x1, x2, x3].filter(reduce); - } else if(discriminant === 0) { - u1 = q2 < 0 ? crt(-q2) : -crt(q2); - x1 = 2*u1-a/3; - x2 = -u1 - a/3; - return [x1,x2].filter(reduce); - } else { - var sd = sqrt(discriminant); - u1 = crt(-q2+sd); - v1 = crt(q2+sd); - return [u1-v1-a/3].filter(reduce);; - } - }, - - droots: function(p) { - // quadratic roots are easy - if(p.length === 3) { - var a = p[0], - b = p[1], - c = p[2], - d = a - 2*b + c; - if(d!==0) { - var m1 = -sqrt(b*b-a*c), - m2 = -a+b, - v1 = -( m1+m2)/d, - v2 = -(-m1+m2)/d; - return [v1, v2]; - } - else if(b!==c && d===0) { - return [(2*b-c)/(2*(b-c))]; - } - return []; - } - - // linear roots are even easier - if(p.length === 2) { - var a = p[0], b = p[1]; - if(a!==b) { - return [a/(a-b)]; - } - return []; - } - }, - - inflections: function(points) { - if (points.length<4) return []; - - // FIXME: TODO: add in inflection abstraction for quartic+ curves? - - var p = utils.align(points, { p1: points[0], p2: points.slice(-1)[0] }), - a = p[2].x * p[1].y, - b = p[3].x * p[1].y, - c = p[1].x * p[2].y, - d = p[3].x * p[2].y, - v1 = 18 * (-3*a + 2*b + 3*c - d), - v2 = 18 * (3*a - b - 3*c), - v3 = 18 * (c - a); - - if (utils.approximately(v1,0)) return []; - - var trm = v2*v2 - 4*v1*v3, - sq = Math.sqrt(trm), - d = 2 * v1; - - if (utils.approximately(d,0)) return []; - - return [(sq-v2)/d, -(v2+sq)/d].filter(function(r) { - return (0 <= r && r <= 1); - }); - }, - - bboxoverlap: function(b1,b2) { - var dims=['x','y'],len=dims.length,i,dim,l,t,d - for(i=0; i= d) return false; - } - return true; - }, - - expandbox: function(bbox, _bbox) { - if(_bbox.x.min < bbox.x.min) { bbox.x.min = _bbox.x.min; } - if(_bbox.y.min < bbox.y.min) { bbox.y.min = _bbox.y.min; } - if(_bbox.z && _bbox.z.min < bbox.z.min) { bbox.z.min = _bbox.z.min; } - if(_bbox.x.max > bbox.x.max) { bbox.x.max = _bbox.x.max; } - if(_bbox.y.max > bbox.y.max) { bbox.y.max = _bbox.y.max; } - if(_bbox.z && _bbox.z.max > bbox.z.max) { bbox.z.max = _bbox.z.max; } - bbox.x.mid = (bbox.x.min + bbox.x.max)/2; - bbox.y.mid = (bbox.y.min + bbox.y.max)/2; - if(bbox.z) { bbox.z.mid = (bbox.z.min + bbox.z.max)/2; } - bbox.x.size = bbox.x.max - bbox.x.min; - bbox.y.size = bbox.y.max - bbox.y.min; - if(bbox.z) { bbox.z.size = bbox.z.max - bbox.z.min; } - }, - - pairiteration: function(c1, c2, curveIntersectionThreshold) { - var c1b = c1.bbox(), - c2b = c2.bbox(), - r = 100000, - threshold = curveIntersectionThreshold || 0.5; - if(c1b.x.size + c1b.y.size < threshold && c2b.x.size + c2b.y.size < threshold) { - return [ ((r * (c1._t1+c1._t2)/2)|0)/r + "/" + ((r * (c2._t1+c2._t2)/2)|0)/r ]; - } - var cc1 = c1.split(0.5), - cc2 = c2.split(0.5), - pairs = [ - {left: cc1.left, right: cc2.left }, - {left: cc1.left, right: cc2.right }, - {left: cc1.right, right: cc2.right }, - {left: cc1.right, right: cc2.left }]; - pairs = pairs.filter(function(pair) { - return utils.bboxoverlap(pair.left.bbox(),pair.right.bbox()); - }); - var results = []; - if(pairs.length === 0) return results; - pairs.forEach(function(pair) { - results = results.concat( - utils.pairiteration(pair.left, pair.right, threshold) - ); - }) - results = results.filter(function(v,i) { - return results.indexOf(v) === i; - }); - return results; - }, - - getccenter: function(p1,p2,p3) { - var dx1 = (p2.x - p1.x), - dy1 = (p2.y - p1.y), - dx2 = (p3.x - p2.x), - dy2 = (p3.y - p2.y); - var dx1p = dx1 * cos(quart) - dy1 * sin(quart), - dy1p = dx1 * sin(quart) + dy1 * cos(quart), - dx2p = dx2 * cos(quart) - dy2 * sin(quart), - dy2p = dx2 * sin(quart) + dy2 * cos(quart); - // chord midpoints - var mx1 = (p1.x + p2.x)/2, - my1 = (p1.y + p2.y)/2, - mx2 = (p2.x + p3.x)/2, - my2 = (p2.y + p3.y)/2; - // midpoint offsets - var mx1n = mx1 + dx1p, - my1n = my1 + dy1p, - mx2n = mx2 + dx2p, - my2n = my2 + dy2p; - // intersection of these lines: - var arc = utils.lli8(mx1,my1,mx1n,my1n, mx2,my2,mx2n,my2n), - r = utils.dist(arc,p1), - // arc start/end values, over mid point: - s = atan2(p1.y - arc.y, p1.x - arc.x), - m = atan2(p2.y - arc.y, p2.x - arc.x), - e = atan2(p3.y - arc.y, p3.x - arc.x), - _; - // determine arc direction (cw/ccw correction) - if (sm || m>e) { s += tau; } - if (s>e) { _=e; e=s; s=_; } - } else { - // if e (n-1)) throw new Error('degree must be less than or equal to point count - 1'); - - if(!weights) { - // build weight vector of length [n] - weights = []; - for(i=0; i high) throw new Error('out of bounds'); - - // find s (the spline segment) for the [t] value provided - for(s=domain[0]; s= knots[s] && t <= knots[s+1]) { - break; - } - } - - // convert points to homogeneous coordinates - var v = []; - for(i=0; is-degree-1+l; i--) { - alpha = (t - knots[i]) / (knots[i+degree+1-l] - knots[i]); - - // interpolate each component - for(j=0; j