2011-04-11 19:27:11 +02:00
|
|
|
/*
|
2013-01-28 18:03:27 -08:00
|
|
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
2011-04-11 19:27:11 +02:00
|
|
|
* http://paperjs.org/
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2014-01-04 01:47:16 +01:00
|
|
|
* Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
|
|
|
|
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-07-01 12:17:45 +02:00
|
|
|
* Distributed under the MIT license. See LICENSE file for details.
|
|
|
|
*
|
2011-04-11 19:27:11 +02:00
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
2011-06-22 23:56:05 +01:00
|
|
|
/**
|
|
|
|
* @name CurveLocation
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-06-22 23:56:05 +01:00
|
|
|
* @class CurveLocation objects describe a location on {@link Curve}
|
|
|
|
* objects, as defined by the curve {@link #parameter}, a value between
|
|
|
|
* {@code 0} (beginning of the curve) and {@code 1} (end of the curve). If
|
|
|
|
* the curve is part of a {@link Path} item, its {@link #index} inside the
|
|
|
|
* {@link Path#curves} array is also provided.
|
2011-07-07 16:10:27 +02:00
|
|
|
*
|
|
|
|
* The class is in use in many places, such as
|
2013-01-28 16:30:28 -08:00
|
|
|
* {@link Path#getLocationAt(offset, isParameter)},
|
2012-12-27 21:08:03 +01:00
|
|
|
* {@link Path#getLocationOf(point)},
|
2012-12-30 19:43:35 +01:00
|
|
|
* {@link Path#getNearestLocation(point),
|
2012-12-27 21:08:03 +01:00
|
|
|
* {@link PathItem#getIntersections(path)},
|
|
|
|
* etc.
|
2011-06-22 23:56:05 +01:00
|
|
|
*/
|
2013-05-27 12:48:58 -07:00
|
|
|
var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
2013-06-23 20:18:32 -07:00
|
|
|
_class: 'CurveLocation',
|
2011-07-07 16:10:27 +02:00
|
|
|
// DOCS: CurveLocation class description: add these back when the mentioned
|
2012-12-27 19:23:03 +01:00
|
|
|
// functioned have been added: {@link Path#split(location)}
|
2011-05-23 17:39:26 +02:00
|
|
|
/**
|
|
|
|
* Creates a new CurveLocation object.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 17:39:26 +02:00
|
|
|
* @param {Curve} curve
|
2011-05-27 21:21:49 +02:00
|
|
|
* @param {Number} parameter
|
2011-05-23 17:39:26 +02:00
|
|
|
* @param {Point} point
|
|
|
|
*/
|
2013-06-13 15:53:28 -07:00
|
|
|
initialize: function CurveLocation(curve, parameter, point, _curve2,
|
|
|
|
_parameter2, _point2, _distance) {
|
2013-04-22 19:11:42 -07:00
|
|
|
// Define this CurveLocation's unique id.
|
|
|
|
this._id = CurveLocation._id = (CurveLocation._id || 0) + 1;
|
2011-04-11 19:27:11 +02:00
|
|
|
this._curve = curve;
|
2013-01-22 14:46:49 -08:00
|
|
|
// Also store references to segment1 and segment2, in case path
|
|
|
|
// splitting / dividing is going to happen, in which case the segments
|
|
|
|
// can be used to determine the new curves, see #getCurve(true)
|
|
|
|
this._segment1 = curve._segment1;
|
|
|
|
this._segment2 = curve._segment2;
|
2011-04-11 19:27:11 +02:00
|
|
|
this._parameter = parameter;
|
|
|
|
this._point = point;
|
2013-06-13 15:53:28 -07:00
|
|
|
this._curve2 = _curve2;
|
|
|
|
this._parameter2 = _parameter2;
|
|
|
|
this._point2 = _point2;
|
2013-04-30 18:41:26 -07:00
|
|
|
this._distance = _distance;
|
2011-04-11 19:27:11 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The segment of the curve which is closer to the described location.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 17:39:26 +02:00
|
|
|
* @type Segment
|
|
|
|
* @bean
|
2011-04-11 19:27:11 +02:00
|
|
|
*/
|
2014-01-05 17:40:54 +01:00
|
|
|
getSegment: function(_preferFirst) {
|
2011-04-11 19:27:11 +02:00
|
|
|
if (!this._segment) {
|
2013-01-22 14:46:49 -08:00
|
|
|
var curve = this.getCurve(),
|
2011-07-08 18:39:05 +02:00
|
|
|
parameter = this.getParameter();
|
2013-05-04 02:50:18 -07:00
|
|
|
if (parameter === 1) {
|
2011-04-27 20:48:41 +01:00
|
|
|
this._segment = curve._segment2;
|
2014-01-05 17:40:54 +01:00
|
|
|
} else if (parameter === 0 || _preferFirst) {
|
2013-05-04 02:50:18 -07:00
|
|
|
this._segment = curve._segment1;
|
2011-05-01 13:16:25 +01:00
|
|
|
} else if (parameter == null) {
|
2011-04-11 19:27:11 +02:00
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
// Determine the closest segment by comparing curve lengths
|
2011-04-27 20:52:24 +01:00
|
|
|
this._segment = curve.getLength(0, parameter)
|
|
|
|
< curve.getLength(parameter, 1)
|
|
|
|
? curve._segment1
|
|
|
|
: curve._segment2;
|
2011-04-11 19:27:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return this._segment;
|
|
|
|
},
|
|
|
|
|
2014-01-05 17:40:54 +01:00
|
|
|
setSegment: function(segment) {
|
|
|
|
// NOTE: We only include this setter so the above getter can declare
|
|
|
|
// the _preferFirst parameter without having to hide it.
|
|
|
|
// See Strap.js beans conventions.
|
|
|
|
this._segment = segment;
|
|
|
|
},
|
|
|
|
|
2011-04-11 19:27:11 +02:00
|
|
|
/**
|
|
|
|
* The curve by which the location is defined.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 17:39:26 +02:00
|
|
|
* @type Curve
|
|
|
|
* @bean
|
2011-04-11 19:27:11 +02:00
|
|
|
*/
|
2014-01-05 17:40:54 +01:00
|
|
|
getCurve: function(_uncached) {
|
|
|
|
if (!this._curve || _uncached) {
|
2013-01-22 14:46:49 -08:00
|
|
|
// If we're asked to get the curve uncached, access current curve
|
|
|
|
// objects through segment1 / segment2. Since path splitting or
|
|
|
|
// dividing might have happened in the meantime, try segment1's
|
|
|
|
// curve, and see if _point lies on it still, otherwise assume it's
|
|
|
|
// the curve before segment2.
|
|
|
|
this._curve = this._segment1.getCurve();
|
|
|
|
if (this._curve.getParameterOf(this._point) == null)
|
|
|
|
this._curve = this._segment2.getPrevious().getCurve();
|
|
|
|
}
|
2011-04-11 19:27:11 +02:00
|
|
|
return this._curve;
|
|
|
|
},
|
|
|
|
|
2014-01-05 17:40:54 +01:00
|
|
|
setCurve: function(curve) {
|
|
|
|
// See #setSegment()
|
|
|
|
this._curve = curve;
|
|
|
|
},
|
|
|
|
|
2013-04-30 18:41:26 -07:00
|
|
|
/**
|
|
|
|
* The curve location on the intersecting curve, if this location is the
|
|
|
|
* result of a call to {@link PathItem#getIntersections(path)} /
|
|
|
|
* {@link Curve#getIntersections(curve)}.
|
|
|
|
*
|
|
|
|
* @type CurveLocation
|
|
|
|
* @bean
|
|
|
|
*/
|
|
|
|
getIntersection: function() {
|
|
|
|
var intersection = this._intersection;
|
2013-06-13 15:53:28 -07:00
|
|
|
if (!intersection && this._curve2) {
|
|
|
|
var param = this._parameter2;
|
2013-06-09 18:37:08 -07:00
|
|
|
// If we have the parameter on the other curve use that for
|
|
|
|
// intersection rather than the point.
|
|
|
|
this._intersection = intersection = new CurveLocation(
|
2013-06-13 15:53:28 -07:00
|
|
|
this._curve2, param, this._point2 || this._point, this);
|
2013-04-30 18:41:26 -07:00
|
|
|
intersection._intersection = this;
|
|
|
|
}
|
|
|
|
return intersection;
|
|
|
|
},
|
|
|
|
|
2011-04-26 17:49:54 +01:00
|
|
|
/**
|
2011-07-08 22:25:42 +02:00
|
|
|
* The path this curve belongs to, if any.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 17:39:26 +02:00
|
|
|
* @type Item
|
|
|
|
* @bean
|
2011-04-26 17:49:54 +01:00
|
|
|
*/
|
2011-07-08 22:25:42 +02:00
|
|
|
getPath: function() {
|
2013-01-22 14:46:49 -08:00
|
|
|
var curve = this.getCurve();
|
|
|
|
return curve && curve._path;
|
2011-04-26 17:49:54 +01:00
|
|
|
},
|
|
|
|
|
2011-04-11 19:27:11 +02:00
|
|
|
/**
|
2011-05-27 20:06:57 +02:00
|
|
|
* The index of the curve within the {@link Path#curves} list, if the
|
2011-04-11 19:27:11 +02:00
|
|
|
* curve is part of a {@link Path} item.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 17:39:26 +02:00
|
|
|
* @type Index
|
|
|
|
* @bean
|
2011-04-11 19:27:11 +02:00
|
|
|
*/
|
|
|
|
getIndex: function() {
|
2013-01-22 14:46:49 -08:00
|
|
|
var curve = this.getCurve();
|
|
|
|
return curve && curve.getIndex();
|
2011-04-11 19:27:11 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The length of the path from its beginning up to the location described
|
|
|
|
* by this object.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-27 20:15:15 +02:00
|
|
|
* @type Number
|
2011-05-23 17:39:26 +02:00
|
|
|
* @bean
|
2011-04-11 19:27:11 +02:00
|
|
|
*/
|
2011-04-27 20:08:57 +01:00
|
|
|
getOffset: function() {
|
2013-01-22 14:46:49 -08:00
|
|
|
var path = this.getPath();
|
2011-04-27 20:08:57 +01:00
|
|
|
return path && path._getOffset(this);
|
2011-04-11 19:27:11 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The length of the curve from its beginning up to the location described
|
|
|
|
* by this object.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-27 20:15:15 +02:00
|
|
|
* @type Number
|
2011-05-23 17:39:26 +02:00
|
|
|
* @bean
|
2011-04-11 19:27:11 +02:00
|
|
|
*/
|
2011-04-27 20:08:57 +01:00
|
|
|
getCurveOffset: function() {
|
2013-01-22 14:46:49 -08:00
|
|
|
var curve = this.getCurve(),
|
|
|
|
parameter = this.getParameter();
|
|
|
|
return parameter != null && curve && curve.getLength(0, parameter);
|
2011-04-11 19:27:11 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The curve parameter, as used by various bezier curve calculations. It is
|
|
|
|
* value between {@code 0} (beginning of the curve) and {@code 1} (end of
|
|
|
|
* the curve).
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-27 20:15:15 +02:00
|
|
|
* @type Number
|
2011-05-23 17:39:26 +02:00
|
|
|
* @bean
|
2011-04-11 19:27:11 +02:00
|
|
|
*/
|
2014-01-05 17:40:54 +01:00
|
|
|
getParameter: function(_uncached) {
|
|
|
|
if ((this._parameter == null || _uncached) && this._point) {
|
|
|
|
var curve = this.getCurve(_uncached && this._point);
|
2013-01-22 14:46:49 -08:00
|
|
|
this._parameter = curve && curve.getParameterOf(this._point);
|
|
|
|
}
|
2011-04-26 17:49:54 +01:00
|
|
|
return this._parameter;
|
2011-04-11 19:27:11 +02:00
|
|
|
},
|
|
|
|
|
2014-01-05 17:40:54 +01:00
|
|
|
setParameter: function(parameter) {
|
|
|
|
// See #setSegment()
|
|
|
|
this._parameter = parameter;
|
|
|
|
},
|
|
|
|
|
2011-04-11 19:27:11 +02:00
|
|
|
/**
|
2011-05-23 17:39:26 +02:00
|
|
|
* The point which is defined by the {@link #curve} and
|
|
|
|
* {@link #parameter}.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 17:39:26 +02:00
|
|
|
* @type Point
|
|
|
|
* @bean
|
2011-04-11 19:27:11 +02:00
|
|
|
*/
|
2014-01-05 17:40:54 +01:00
|
|
|
getPoint: function(_uncached) {
|
|
|
|
if ((!this._point || _uncached) && this._parameter != null) {
|
2013-01-22 14:46:49 -08:00
|
|
|
var curve = this.getCurve();
|
2013-01-28 16:30:28 -08:00
|
|
|
this._point = curve && curve.getPointAt(this._parameter, true);
|
2013-01-22 14:46:49 -08:00
|
|
|
}
|
2011-04-11 19:27:11 +02:00
|
|
|
return this._point;
|
|
|
|
},
|
|
|
|
|
2014-01-05 17:40:54 +01:00
|
|
|
setPoint: function(point) {
|
|
|
|
// See #setSegment()
|
|
|
|
this._point = point;
|
|
|
|
},
|
|
|
|
|
2011-04-27 19:26:03 +01:00
|
|
|
/**
|
2011-05-23 17:39:26 +02:00
|
|
|
* The tangential vector to the {@link #curve} at the given location.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 17:39:26 +02:00
|
|
|
* @type Point
|
|
|
|
* @bean
|
2011-04-27 19:26:03 +01:00
|
|
|
*/
|
|
|
|
getTangent: function() {
|
2013-01-22 14:46:49 -08:00
|
|
|
var parameter = this.getParameter(),
|
|
|
|
curve = this.getCurve();
|
2013-01-28 16:30:28 -08:00
|
|
|
return parameter != null && curve && curve.getTangentAt(parameter, true);
|
2011-04-27 19:26:03 +01:00
|
|
|
},
|
2011-06-30 06:01:51 -04:00
|
|
|
|
2011-04-27 19:26:03 +01:00
|
|
|
/**
|
2011-05-23 17:39:26 +02:00
|
|
|
* The normal vector to the {@link #curve} at the given location.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 17:39:26 +02:00
|
|
|
* @type Point
|
|
|
|
* @bean
|
2011-04-27 19:26:03 +01:00
|
|
|
*/
|
|
|
|
getNormal: function() {
|
2013-01-22 14:46:49 -08:00
|
|
|
var parameter = this.getParameter(),
|
|
|
|
curve = this.getCurve();
|
2013-01-28 16:30:28 -08:00
|
|
|
return parameter != null && curve && curve.getNormalAt(parameter, true);
|
2011-04-27 19:26:03 +01:00
|
|
|
},
|
|
|
|
|
2011-07-06 22:19:01 +02:00
|
|
|
/**
|
|
|
|
* The distance from the queried point to the returned location.
|
|
|
|
*
|
|
|
|
* @type Number
|
|
|
|
* @bean
|
|
|
|
*/
|
|
|
|
getDistance: function() {
|
|
|
|
return this._distance;
|
|
|
|
},
|
|
|
|
|
2012-12-30 19:53:09 +01:00
|
|
|
divide: function() {
|
2013-03-01 20:26:03 -08:00
|
|
|
var curve = this.getCurve(true);
|
2013-07-04 19:39:55 -07:00
|
|
|
return curve && curve.divide(this.getParameter(true), true);
|
2012-12-31 21:42:55 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
split: function() {
|
2013-03-01 20:26:03 -08:00
|
|
|
var curve = this.getCurve(true);
|
2013-07-04 19:39:55 -07:00
|
|
|
return curve && curve.split(this.getParameter(true), true);
|
2012-12-30 19:53:09 +01:00
|
|
|
},
|
|
|
|
|
2014-02-20 15:37:49 +01:00
|
|
|
/**
|
|
|
|
* Checks whether tow CurveLocation objects are describing the same location
|
|
|
|
* on a path, by applying the same tolerances as elsewhere when dealing with
|
|
|
|
* curve time parameters.
|
|
|
|
*
|
|
|
|
* @param {CurveLocation} location
|
|
|
|
* @return {Boolean} {@true if the locations are equal}
|
|
|
|
*/
|
|
|
|
equals: function(loc) {
|
|
|
|
var isZero = Numerical.isZero;
|
|
|
|
return this === loc
|
|
|
|
|| loc
|
|
|
|
&& this._curve === loc._curve
|
|
|
|
&& this._curve2 === loc._curve2
|
|
|
|
&& isZero(this._parameter - loc._parameter)
|
|
|
|
&& isZero(this._parameter2 - loc._parameter2)
|
|
|
|
|| false;
|
|
|
|
},
|
|
|
|
|
2011-05-23 17:39:26 +02:00
|
|
|
/**
|
2013-08-23 19:45:28 -07:00
|
|
|
* @return {String} a string representation of the curve location
|
2011-05-23 17:39:26 +02:00
|
|
|
*/
|
2011-04-11 19:27:11 +02:00
|
|
|
toString: function() {
|
2011-05-04 19:42:50 +01:00
|
|
|
var parts = [],
|
2013-04-09 17:32:19 -07:00
|
|
|
point = this.getPoint(),
|
|
|
|
f = Formatter.instance;
|
2011-04-27 19:24:40 +01:00
|
|
|
if (point)
|
|
|
|
parts.push('point: ' + point);
|
2011-04-11 19:27:11 +02:00
|
|
|
var index = this.getIndex();
|
2011-05-01 13:18:36 +01:00
|
|
|
if (index != null)
|
2011-04-26 17:49:54 +01:00
|
|
|
parts.push('index: ' + index);
|
2011-04-11 19:27:11 +02:00
|
|
|
var parameter = this.getParameter();
|
2011-05-01 13:18:36 +01:00
|
|
|
if (parameter != null)
|
2013-04-09 17:32:19 -07:00
|
|
|
parts.push('parameter: ' + f.number(parameter));
|
2011-07-07 22:14:58 +02:00
|
|
|
if (this._distance != null)
|
2013-04-09 17:32:19 -07:00
|
|
|
parts.push('distance: ' + f.number(this._distance));
|
2011-05-02 12:23:42 +02:00
|
|
|
return '{ ' + parts.join(', ') + ' }';
|
2011-04-11 19:27:11 +02:00
|
|
|
}
|
2011-04-11 19:33:34 +02:00
|
|
|
});
|