mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-28 17:02:24 -05:00
Simplify CurveLocation data structures.
Directly creating and linking intersections simplifies things a lot.
This commit is contained in:
parent
78e0bae6aa
commit
04452730dd
5 changed files with 74 additions and 90 deletions
|
@ -269,7 +269,7 @@
|
|||
// // annotatePath(pathB)
|
||||
// // pathB.translate([ 300, 0 ]);
|
||||
// // pathB.segments.filter(function(a) { return a._ixPair; }).map(
|
||||
// // function(a) { a._ixPair.getIntersection()._segment.selected = true; });
|
||||
// // function(a) { a._ixPair.intersection._segment.selected = true; });
|
||||
|
||||
// console.time('unite');
|
||||
// var nup = unite(pathA, pathB);
|
||||
|
|
|
@ -1000,8 +1000,7 @@ statics: {
|
|||
step /= 2;
|
||||
}
|
||||
var pt = Curve.getPoint(values, minT);
|
||||
return new CurveLocation(this, minT, pt, null, null, null,
|
||||
point.getDistance(pt));
|
||||
return new CurveLocation(this, minT, pt, point.getDistance(pt));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1317,7 +1316,8 @@ new function() { // Scope for methods that require private functions
|
|||
},
|
||||
new function() { // Scope for intersection using bezier fat-line clipping
|
||||
|
||||
function addLocation(locations, param, v1, c1, t1, p1, v2, c2, t2, p2) {
|
||||
function addLocation(locations, param, v1, c1, t1, p1, v2, c2, t2, p2,
|
||||
overlap) {
|
||||
var loc = null,
|
||||
tMin = /*#=*/Numerical.TOLERANCE,
|
||||
tMax = 1 - tMin;
|
||||
|
@ -1327,11 +1327,16 @@ new function() { // Scope for intersection using bezier fat-line clipping
|
|||
&& t1 <= (param.endConnected ? tMax : 1)) {
|
||||
if (t2 == null)
|
||||
t2 = Curve.getParameterOf(v2, p2.x, p2.y);
|
||||
loc = new CurveLocation(
|
||||
c1, t1, p1 || Curve.getPoint(v1, t1),
|
||||
c2, t2, p2 || Curve.getPoint(v2, t2));
|
||||
if (param.adjust)
|
||||
param.adjust(loc);
|
||||
var reparametrize = param.reparametrize;
|
||||
if (reparametrize) {
|
||||
var res = reparametrize(t1, t2);
|
||||
t1 = res.t1;
|
||||
t2 = res.t2;
|
||||
}
|
||||
loc = new CurveLocation(c1, t1, p1 || Curve.getPoint(v1, t1),
|
||||
null, overlap,
|
||||
new CurveLocation(c2, t2, p2 || Curve.getPoint(v2, t2),
|
||||
null, overlap));
|
||||
locations.push(loc);
|
||||
}
|
||||
return loc;
|
||||
|
@ -1662,18 +1667,10 @@ new function() { // Scope for intersection using bezier fat-line clipping
|
|||
abs(p2[4] - p1[4]) < epsilon &&
|
||||
abs(p2[5] - p1[5]) < epsilon) {
|
||||
// Overlapping parts are identical
|
||||
var t11 = pairs[0][0],
|
||||
t12 = pairs[0][1],
|
||||
t21 = pairs[1][0],
|
||||
t22 = pairs[1][1],
|
||||
loc1 = addLocation(locations, param, v1, c1, t11, null,
|
||||
v2, c2, t12, null),
|
||||
loc2 = addLocation(locations, param, v1, c1, t21, null,
|
||||
v2, c2, t22, null);
|
||||
if (loc1)
|
||||
loc1._overlap = true;
|
||||
if (loc2)
|
||||
loc2._overlap = true;
|
||||
addLocation(locations, param, v1, c1, pairs[0][0], null,
|
||||
v2, c2, pairs[0][1], null, true),
|
||||
addLocation(locations, param, v1, c1, pairs[1][0], null,
|
||||
v2, c2, pairs[1][1], null, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1736,37 +1733,22 @@ new function() { // Scope for intersection using bezier fat-line clipping
|
|||
},
|
||||
|
||||
_filterIntersections: function(locations, expand) {
|
||||
var last = locations.length - 1,
|
||||
tMax = 1 - /*#=*/Numerical.TOLERANCE;
|
||||
// Merge intersections very close to the end of a curve to the
|
||||
// beginning of the next curve, so we can compare them.
|
||||
for (var i = last; i >= 0; i--) {
|
||||
var loc = locations[i],
|
||||
next;
|
||||
if (loc._parameter >= tMax && (next = loc._curve.getNext())) {
|
||||
loc._parameter = 0;
|
||||
loc._curve = next;
|
||||
}
|
||||
if (loc._parameter2 >= tMax && (next = loc._curve2.getNext())) {
|
||||
loc._parameter2 = 0;
|
||||
loc._curve2 = next;
|
||||
}
|
||||
}
|
||||
|
||||
var last = locations.length - 1;
|
||||
if (last > 0) {
|
||||
CurveLocation.sort(locations);
|
||||
// Filter out duplicate locations, but preserve _overlap setting
|
||||
// among all duplicated (only one of them will have it defined).
|
||||
// Filter out duplicate locations, but preserve _overlap among
|
||||
// all duplicated (only one of them will have it defined).
|
||||
var i = last,
|
||||
loc = locations[i];
|
||||
while(--i >= 0) {
|
||||
var prev = locations[i];
|
||||
if (prev.equals(loc)) {
|
||||
locations.splice(i + 1, 1); // Remove loc.
|
||||
// Preserve overlap setting.
|
||||
var overlap = loc._overlap;
|
||||
if (overlap)
|
||||
prev._overlap = overlap;
|
||||
locations.splice(i + 1, 1); // Remove location.
|
||||
// Preserve _overlap for both linked intersections.
|
||||
var over = loc._overlap;
|
||||
if (over) {
|
||||
prev._overlap = prev._intersection._overlap = over;
|
||||
}
|
||||
last--;
|
||||
}
|
||||
loc = prev;
|
||||
|
@ -1774,7 +1756,7 @@ new function() { // Scope for intersection using bezier fat-line clipping
|
|||
}
|
||||
if (expand) {
|
||||
for (var i = last; i >= 0; i--)
|
||||
locations.push(locations[i].getIntersection());
|
||||
locations.push(locations[i]._intersection);
|
||||
CurveLocation.sort(locations);
|
||||
}
|
||||
return locations;
|
||||
|
|
|
@ -41,8 +41,17 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
* @param {Number} parameter
|
||||
* @param {Point} [point]
|
||||
*/
|
||||
initialize: function CurveLocation(curve, parameter, point, _curve2,
|
||||
_parameter2, _point2, _distance) {
|
||||
initialize: function CurveLocation(curve, parameter, point,
|
||||
_distance, _overlap, _intersection) {
|
||||
// Merge intersections very close to the end of a curve to the
|
||||
// beginning of the next curve.
|
||||
if (parameter >= 1 - /*#=*/Numerical.TOLERANCE) {
|
||||
var next = curve.getNext();
|
||||
if (next) {
|
||||
parameter = 0;
|
||||
curve = next;
|
||||
}
|
||||
}
|
||||
// Define this CurveLocation's unique id.
|
||||
// NOTE: We do not use the same pool as the rest of the library here,
|
||||
// since this is only required to be unique at runtime among other
|
||||
|
@ -53,10 +62,14 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
this._curve = curve;
|
||||
this._parameter = parameter;
|
||||
this._point = point || curve.getPointAt(parameter, true);
|
||||
this._curve2 = _curve2;
|
||||
this._parameter2 = _parameter2;
|
||||
this._point2 = _point2;
|
||||
this._distance = _distance;
|
||||
this._overlap = _overlap;
|
||||
this._intersection = _intersection;
|
||||
this._other = false;
|
||||
if (_intersection) {
|
||||
_intersection._intersection = this;
|
||||
_intersection._other = true;
|
||||
}
|
||||
// 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)
|
||||
|
@ -209,17 +222,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
* @bean
|
||||
*/
|
||||
getIntersection: function() {
|
||||
var intersection = this._intersection;
|
||||
if (!intersection && this._curve2) {
|
||||
// If we have the parameter on the other curve use that for
|
||||
// intersection rather than the point.
|
||||
this._intersection = intersection = new CurveLocation(this._curve2,
|
||||
this._parameter2, this._point2 || this._point);
|
||||
intersection._overlap = this._overlap;
|
||||
intersection._intersection = this;
|
||||
intersection._other = true;
|
||||
}
|
||||
return intersection;
|
||||
return this._intersection;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -275,23 +278,20 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
* @param {CurveLocation} location
|
||||
* @return {Boolean} {@true if the locations are equal}
|
||||
*/
|
||||
equals: function(loc) {
|
||||
var abs = Math.abs,
|
||||
// Use the same tolerance for curve time parameter comparisons as
|
||||
// in Curve.js when considering two locations the same.
|
||||
tolerance = /*#=*/Numerical.TOLERANCE;
|
||||
equals: function(loc, _ignoreIntersection) {
|
||||
return this === loc
|
||||
|| loc instanceof CurveLocation
|
||||
// Call getCurve() and getParameter() to keep in sync
|
||||
&& this.getCurve() === loc.getCurve()
|
||||
&& abs(this.getParameter() - loc.getParameter()) < tolerance
|
||||
// _curve2/_parameter2 are only used for Boolean operations
|
||||
// and don't need syncing there.
|
||||
// TODO: That's not quite true though... Rework this!
|
||||
&& this._curve2 === loc._curve2
|
||||
&& abs((this._parameter2 || 0) - (loc._parameter2 || 0))
|
||||
< tolerance
|
||||
|| false;
|
||||
|| loc instanceof CurveLocation
|
||||
// Call getCurve() and getParameter() to keep in sync
|
||||
&& this.getCurve() === loc.getCurve()
|
||||
// Use the same tolerance for curve time parameter
|
||||
// comparisons as in Curve.js
|
||||
&& Math.abs(this.getParameter() - loc.getParameter())
|
||||
< /*#=*/Numerical.TOLERANCE
|
||||
&& (_ignoreIntersection
|
||||
|| (!this._intersection && !loc._intersection
|
||||
|| this._intersection && this._intersection.equals(
|
||||
loc._intersection, true)))
|
||||
|| false;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -329,10 +329,12 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
if (curve1 === curve2) {
|
||||
var diff = l1._parameter - l2._parameter;
|
||||
if (Math.abs(diff) < tolerance) {
|
||||
var curve21 = l1._curve2,
|
||||
curve22 = l2._curve2;
|
||||
var i1 = l1._intersection,
|
||||
i2 = l2._intersection,
|
||||
curve21 = i1 && i1._curve,
|
||||
curve22 = i2 && l2._curve;
|
||||
res = curve21 === curve22 // equal or both null
|
||||
? l1._parameter2 - l2._parameter2
|
||||
? (i1 ? i1._parameter : 0) - (i2 ? i2._parameter : 0)
|
||||
: curve21 && curve22
|
||||
? curve21.getIndex() - curve22.getIndex()
|
||||
: curve21 ? 1 : -1;
|
||||
|
|
|
@ -225,14 +225,12 @@ PathItem.inject(new function() {
|
|||
intersections.forEach(function(inter) {
|
||||
var log = ['CurveLocation', inter._id, 'p', inter.getPath()._id,
|
||||
'i', inter.getIndex(), 't', inter._parameter,
|
||||
'i2', inter._curve2 ? inter._curve2.getIndex() : null,
|
||||
't2', inter._parameter2, 'o', !!inter._overlap];
|
||||
'o', !!inter._overlap];
|
||||
if (inter._other) {
|
||||
inter = inter.getIntersection();
|
||||
inter = inter._intersection;
|
||||
log.push('Other', inter._id, 'p', inter.getPath()._id,
|
||||
'i', inter.getIndex(), 't', inter._parameter,
|
||||
'i2', inter._curve2 ? inter._curve2.getIndex() : null,
|
||||
't2', inter._parameter2, 'o', !!inter._overlap);
|
||||
'o', !!inter._overlap);
|
||||
}
|
||||
console.log(log.map(function(v) {
|
||||
return v == null ? '-' : v
|
||||
|
@ -275,7 +273,7 @@ PathItem.inject(new function() {
|
|||
clearSegments.push(segment);
|
||||
}
|
||||
// Link the new segment with the intersection on the other curve
|
||||
segment._intersection = loc.getIntersection();
|
||||
segment._intersection = loc._intersection;
|
||||
loc._segment = segment;
|
||||
prev = loc;
|
||||
}
|
||||
|
|
|
@ -110,11 +110,13 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
|||
startConnected: length1 === 1,
|
||||
// After splitting, the end is always connected:
|
||||
endConnected: true,
|
||||
adjust: function(loc) {
|
||||
reparametrize: function(t1, t2) {
|
||||
// Since the curve was split above, we need to
|
||||
// adjust the parameters for both locations.
|
||||
loc._parameter /= 2;
|
||||
loc._parameter2 = 0.5 + loc._parameter2 / 2;
|
||||
return {
|
||||
t1: t1 / 2,
|
||||
t2: (1 + t2) / 2
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue