Fix issues with wrong sorting of CurveLocation in Curve.filterIntersections()

This commit is contained in:
Jürg Lehni 2015-08-26 16:56:28 +02:00
parent 815991d556
commit d85b4f0c80
4 changed files with 55 additions and 24 deletions

View file

@ -1623,34 +1623,19 @@ new function() { // Scope for methods that require private functions
// Merge intersections very close to the end of a curve to the
// beginning of the next curve.
for (var i = last; i >= 0; i--) {
var loc = locations[i],
next = loc._curve.getNext(),
next2 = loc._curve2.getNext();
if (next && loc._parameter >= tMax) {
var loc = locations[i];
if (loc._parameter >= tMax && (next = loc._curve.getNext())) {
loc._parameter = 0;
loc._curve = next;
}
if (next2 && loc._parameter2 >= tMax) {
if (loc._parameter2 >= tMax && (next = loc._curve2.getNext())) {
loc._parameter2 = 0;
loc._curve2 = next2;
loc._curve2 = next;
}
}
// Compare helper to filter locations
function compare(loc1, loc2) {
var path1 = loc1.getPath(),
path2 = loc2.getPath();
return path1 === path2
// We can add parameter (0 <= t <= 1) to index
// (a integer) to compare both at the same time.
? (loc1.getIndex() + loc1.getParameter())
- (loc2.getIndex() + loc2.getParameter())
// Sort by path id to group all locs on the same path.
: path1._id - path2._id;
}
if (last > 0) {
locations.sort(compare);
CurveLocation.sort(locations);
// Filter out duplicate locations, but preserve _overlap setting
// among all duplicated (only one of them will have it defined).
var i = last,
@ -1671,7 +1656,7 @@ new function() { // Scope for methods that require private functions
if (expand) {
for (var i = last; i >= 0; i--)
locations.push(locations[i].getIntersection());
locations.sort(compare);
CurveLocation.sort(locations);
}
return locations;
}

View file

@ -217,6 +217,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
this._parameter2, this._point2 || this._point);
intersection._overlap = this._overlap;
intersection._intersection = this;
intersection._other = true;
}
return intersection;
},
@ -286,6 +287,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
&& 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
@ -310,6 +312,30 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
if (this._distance != null)
parts.push('distance: ' + f.number(this._distance));
return '{ ' + parts.join(', ') + ' }';
},
statics: {
sort: function(locations) {
var tolerance = 1 - /*#=*/Numerical.TOLERANCE;
locations.sort(function compare(l1, l2) {
var curve1 = l1._curve,
curve2 = l2._curve,
path1 = curve1._path,
path2 = curve2._path;
// Sort by path-id, curve, parameter, curve2, parameter2 so we
// can easily remove duplicates with calls to equals() after.
return path1 === path2
? curve1 === curve2
? Math.abs(l1._parameter - l2._parameter) < tolerance
? l1._curve2 === l2._curve2
? l1._parameter2 - l2._parameter2
: l1._curve2.getIndex() - l2._curve2.getIndex()
: l1._parameter - l2._parameter
: curve1.getIndex() - curve2.getIndex()
// Sort by path id to group all locs on the same path.
: path1._id - path2._id;
});
}
}
}, Base.each(Curve.evaluateMethods, function(name) {
// Produce getters for #getTangent() / #getNormal() / #getCurvature()

View file

@ -1191,8 +1191,9 @@ var Path = PathItem.extend(/** @lends Path# */{
index = arg.index;
parameter = arg.parameter;
}
var tolerance = /*#=*/Numerical.TOLERANCE;
if (parameter >= 1 - tolerance) {
var tMin = /*#=*/Numerical.TOLERANCE,
tMax = 1 - tMin;
if (parameter >= tMax) {
// t == 1 is the same as t == 0 and index ++
index++;
parameter--;
@ -1200,7 +1201,7 @@ var Path = PathItem.extend(/** @lends Path# */{
var curves = this.getCurves();
if (index >= 0 && index < curves.length) {
// Only divide curves if we're not on an existing segment already.
if (parameter >= tolerance) {
if (parameter >= tMin) {
// Divide the curve with the index at given parameter.
// Increase because dividing adds more segments to the path.
curves[index++].divide(parameter, true);

View file

@ -220,6 +220,24 @@ PathItem.inject(new function() {
* @param {CurveLocation[]} intersections Array of CurveLocation objects
*/
function splitPath(intersections) {
console.log('splitting', intersections.length);
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];
if (inter._other) {
inter = inter.getIntersection();
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);
}
console.log(log.map(function(v) {
return v == null ? '-' : v
}).join(' '));
});
// TODO: Make public in API, since useful!
var tMin = /*#=*/Numerical.TOLERANCE,
tMax = 1 - tMin,
@ -466,6 +484,7 @@ PathItem.inject(new function() {
inter = seg._intersection;
labelSegment(seg, i
+ ' i: ' + !!inter
+ ' p: ' + seg._path._id
+ ' o: ' + (inter && inter._overlap || 0)
+ ' w: ' + seg._winding
, 'green');