Some code refactoring for #1740

This commit is contained in:
Jürg Lehni 2019-12-13 16:47:49 +01:00
parent a183dc0c0d
commit 46f1aaeca1
3 changed files with 104 additions and 114 deletions

View file

@ -2103,9 +2103,9 @@ new function() { // Scope for bezier intersection using fat-line clipping
}
function getIntersections(curves1, curves2, include, matrix1, matrix2,
_returnFirst) {
var epsilon = Numerical.GEOMETRIC_EPSILON;
var self = !curves2;
_returnFirst) {
var epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON,
self = !curves2;
if (self)
curves2 = curves1;
var length1 = curves1.length,
@ -2115,23 +2115,21 @@ new function() { // Scope for bezier intersection using fat-line clipping
locations = [];
for (var i = 0; i < length1; i++) {
var v = curves1[i].getValues(matrix1);
values1[i] = v;
values1[i] = curves1[i].getValues(matrix1);
}
if (!self) {
for (var i = 0; i < length2; i++) {
var v = curves2[i].getValues(matrix2);
values2[i] = v;
values2[i] = curves2[i].getValues(matrix2);
}
}
var boundsCollisions = CollisionDetection.findCurveBoundsCollisions(
values1, self ? null : values2, epsilon);
values1, self ? null : values2, epsilon);
for (var index1 = 0; index1 < length1; index1++) {
var curve1 = curves1[index1],
v1 = values1[index1];
if (self) {
// First check for self-intersections within the same curve.
getSelfIntersection(v1, curve1, locations, include);
getSelfIntersection(v1, curve1, locations, include);
}
// Check for intersections with potentially intersecting curves.
var collisions1 = boundsCollisions[index1];
@ -2146,12 +2144,11 @@ new function() { // Scope for bezier intersection using fat-line clipping
var curve2 = curves2[index2],
v2 = values2[index2];
getCurveIntersections(
v1, v2, curve1, curve2, locations, include
);
v1, v2, curve1, curve2, locations, include);
}
}
}
}
}
return locations;
}

View file

@ -23,9 +23,8 @@
* - Boolean operations on self-intersecting Paths items
*
* @author Harikrishnan Gopalakrishnan <hari.exeption@gmail.com>
* @author Jan Boesenberg <development@iconexperience.com>
* @author Jan Boesenberg <jan.boesenberg@gmail.com>
* @author Juerg Lehni <juerg@scratchdisk.com>
* https://hkrish.com/playground/paperjs/booleanStudy.html
*/
PathItem.inject(new function() {
var min = Math.min,
@ -179,22 +178,22 @@ PathItem.inject(new function() {
horCurvesMap[pathId][curve.getIndex()] = collidingCurves;
}
var vertCurveCollisions =
var verCurveCollisions =
CollisionDetection.findCurveBoundsCollisions(
curvesValues, curvesValues, 0, true, true);
var vertCurvesMap = {};
var verCurvesMap = {};
for (var i = 0; i < curves.length; i++) {
var curve = curves[i],
collidingCurves = [],
collisionIndices = vertCurveCollisions[i];
collisionIndices = verCurveCollisions[i];
if (collisionIndices) {
for (var j = 0; j < collisionIndices.length; j++) {
collidingCurves.push(curves[collisionIndices[j]]);
}
}
var pathId = curve.getPath().getId();
vertCurvesMap[pathId] = vertCurvesMap[pathId] || {};
vertCurvesMap[pathId][curve.getIndex()] = collidingCurves;
verCurvesMap[pathId] = verCurvesMap[pathId] || {};
verCurvesMap[pathId][curve.getIndex()] = collidingCurves;
}
// Propagate the winding contribution. Winding contribution of
@ -203,14 +202,14 @@ PathItem.inject(new function() {
// in all crossings:
for (var i = 0, l = crossings.length; i < l; i++) {
propagateWinding(crossings[i]._segment, _path1, _path2,
horCurvesMap, vertCurvesMap, operator);
horCurvesMap, verCurvesMap, operator);
}
for (var i = 0, l = segments.length; i < l; i++) {
var segment = segments[i],
inter = segment._intersection;
if (!segment._winding) {
propagateWinding(segment, _path1, _path2,
horCurvesMap, vertCurvesMap, operator);
horCurvesMap, verCurvesMap, operator);
}
// See if all encountered segments in a path are overlaps.
if (!(inter && inter._overlap))
@ -349,28 +348,28 @@ PathItem.inject(new function() {
// Now determine the winding for each path, from large to small.
for (var i = 0; i < length; i++) {
var path1 = sorted[i],
indicesI = collisions[i],
entry1 = lookup[path1._id],
containerWinding = 0;
if (indicesI) {
var point = null; // interior point, only get it if required
for (var j = indicesI.length - 1; j >= 0; j--) {
if (indicesI[j] < i) {
containerWinding = 0,
indices = collisions[i];
if (indices) {
var point = null; // interior point, only get it if required.
for (var j = indices.length - 1; j >= 0; j--) {
if (indices[j] < i) {
point = point || path1.getInteriorPoint();
var path2 = sorted[indicesI[j]];
var path2 = sorted[indices[j]];
// As we run through the paths from largest to
// smallest, for any current path, all potentially
// containing paths have already been processed and
// their orientation fixed. To achieve correct
// orientation of contained paths based on winding,
// we have to find one containing path with
// different "insideness" and set opposite orientation.
// find one containing path with different
// "insideness" and set opposite orientation.
if (path2.contains(point)) {
var entry2 = lookup[path2._id];
containerWinding = entry2.winding;
entry1.winding += containerWinding;
entry1.container = entry2.exclude ?
entry2.container : path2;
entry1.container = entry2.exclude
? entry2.container : path2;
break;
}
}
@ -388,8 +387,8 @@ PathItem.inject(new function() {
// If the containing path is not excluded, we're done
// searching for the orientation defining path.
var container = entry1.container;
path1.setClockwise(container ? !container.isClockwise()
: clockwise);
path1.setClockwise(
container ? !container.isClockwise() : clockwise);
}
}
}
@ -793,8 +792,8 @@ PathItem.inject(new function() {
};
}
function propagateWinding(segment, path1, path2, horCurveCollisionsMap,
vertCurveCollisionsMap, operator) {
function propagateWinding(segment, path1, path2, horCurvesMap, verCurvesMap,
operator) {
// Here we try to determine the most likely winding number contribution
// for the curve-chain starting with this segment. Once we have enough
// confidence in the winding contribution, we can propagate it until the
@ -845,9 +844,8 @@ PathItem.inject(new function() {
var wind = null;
if (operator.subtract && path2) {
// Calculate path winding at point depending on operand.
var pathWinding = operand === path1
? path2._getWinding(pt, dir, true)
: path1._getWinding(pt, dir, true);
var otherPath = operand === path1 ? path2 : path1,
pathWinding = otherPath._getWinding(pt, dir, true);
// Check if curve should be omitted.
if (operand === path1 && pathWinding.winding ||
operand === path2 && !pathWinding.winding) {
@ -861,12 +859,13 @@ PathItem.inject(new function() {
}
}
}
var pathId = path.getId();
var curveIndex = curve.getIndex();
var hCollisions = horCurveCollisionsMap[pathId][curveIndex];
var vCollisions = vertCurveCollisionsMap[pathId][curveIndex];
wind = wind ||
getWinding(pt, hCollisions, vCollisions, dir, true);
if (!wind) {
var pathId = path.getId(),
curveIndex = curve.getIndex(),
curvesH = horCurvesMap[pathId][curveIndex],
curvesV = verCurvesMap[pathId][curveIndex];
wind = getWinding(pt, curvesH, curvesV, dir, true);
}
if (wind.quality > winding.quality)
winding = wind;
break;

View file

@ -14,54 +14,51 @@
* @name CollisionDetection
* @namespace
* @private
* @author Jan Boesenberg <jan.boesenberg@gmail.com>
*/
var CollisionDetection = /** @lends CollisionDetection */{
var CollisionDetection = /** @lends CollisionDetection */{
/**
* Finds collisions between axis aligned bounding boxes of items.
*
* This function takes the bounds of all items in the items1 and items2
* arrays and calls findBoundsCollisions().
*
* @param {Array} itemsA Array of curve values for which collisions should
* be found.
* @param {Array} [itemsA] Array of curve values that the first array should
* be compared with. If not provided, collisions between items within
* the first arrray will be returned.
* @param {Array} items1 Array of items for which collisions should be
* found.
* @param {Array} [items2] Array of items that the first array should be
* compared with. If not provided, collisions between items within
* the first array will be returned.
* @param {Number} [tolerance] If provided, the tolerance will be added to
* all sides of each bounds when checking for collisions.
* @param {Boolean} [sweepVertical] If set to true, the sweep is done
* along the y axis.
* @param {Boolean} [onlySweepAxisCollisionss] If set to true, no collision
* checks will be done on the secondary axis.
* @returns {Array} Array containing for the bounds at thes same index in
* itemsA an array of the indexes of colliding bounds in itemsB
*
* @author Jan Boesenberg <jan.boesenberg@gmail.com>
* @param {Boolean} [sweepVertical] If true, the sweep is performed along
* the y-axis.
* @param {Boolean} [onlySweepAxisCollisions] If true, no collision checks
* will be done on the secondary axis.
* @returns {Array} Array containing for the bounds at the same index in
* items1 an array of the indexes of colliding bounds in items2
*/
findItemBoundsCollisions: function(itemsA, itemsB, tolerance,
sweepVertical, onlySweepAxisCollisions) {
var boundsArr1 = new Array(itemsA.length),
boundsArr2;
for (var i = 0; i < boundsArr1.length; i++) {
var bounds = itemsA[i].bounds;
boundsArr1[i] = [bounds.left, bounds.top, bounds.right,
bounds.bottom];
findItemBoundsCollisions: function(items1, items2, tolerance,
sweepVertical, onlySweepAxisCollisions) {
var bounds1 = new Array(items1.length),
bounds2;
for (var i = 0; i < items1.length; i++) {
var bounds = items1[i].bounds;
bounds1[i] = [bounds.left, bounds.top, bounds.right, bounds.bottom];
}
if (itemsB) {
if (itemsB === itemsA) {
boundsArr2 = boundsArr1;
if (items2) {
if (items2 === items1) {
bounds2 = bounds1;
} else {
boundsArr2 = new Array(itemsB.length);
for (var i = 0; i < boundsArr2.length; i++) {
var bounds = itemsB[i].bounds;
boundsArr2[i] = [bounds.left, bounds.top, bounds.right,
bounds2 = new Array(items2.length);
for (var i = 0; i < items2.length; i++) {
var bounds = items2[i].bounds;
bounds2[i] = [bounds.left, bounds.top, bounds.right,
bounds.bottom];
}
}
}
return this.findBoundsCollisions(boundsArr1, boundsArr2, tolerance || 0,
sweepVertical, onlySweepAxisCollisions);
return this.findBoundsCollisions(bounds1, bounds2, tolerance || 0,
sweepVertical, onlySweepAxisCollisions);
},
/**
@ -80,25 +77,23 @@ var CollisionDetection = /** @lends CollisionDetection */{
* curve bounds within the first arrray will be returned.
* @param {Number} [tolerance] If provided, the tolerance will be added to
* all sides of each bounds when checking for collisions.
* @param {Boolean} [sweepVertical] If set to true, the sweep is done
* along the y axis.
* @param {Boolean} [onlySweepAxisCollisionss] If set to true, no collision
* checks will be done on the secondary axis.
* @returns {Array} Array containing for the bounds at thes same index in
* curveValuesA an array of the indexes of colliding bounds in
* curveValuesB
*
* @author Jan Boesenberg <jan.boesenberg@gmail.com>
* @param {Boolean} [sweepVertical] If true, the sweep is performed along
* the y-axis.
* @param {Boolean} [onlySweepAxisCollisions] If true, no collision checks
* will be done on the secondary axis.
* @returns {Array} Array containing for the bounds at the same index in
* curveValues1 an array of the indexes of colliding bounds in
* curveValues2
*/
findCurveBoundsCollisions: function(curvesValues1, curvesValues2,
tolerance, sweepVertical, onlySweepAxisCollisions) {
tolerance, sweepVertical, onlySweepAxisCollisions) {
var min = Math.min,
max = Math.max,
boundsArr1 = new Array(curvesValues1.length),
boundsArr2;
for (var i = 0; i < boundsArr1.length; i++) {
bounds1 = new Array(curvesValues1.length),
bounds2;
for (var i = 0; i < bounds1.length; i++) {
var v1 = curvesValues1[i];
boundsArr1[i] = [
bounds1[i] = [
min(v1[0], v1[2], v1[4], v1[6]),
min(v1[1], v1[3], v1[5], v1[7]),
max(v1[0], v1[2], v1[4], v1[6]),
@ -107,12 +102,12 @@ var CollisionDetection = /** @lends CollisionDetection */{
}
if (curvesValues2) {
if (curvesValues2 === curvesValues1) {
boundsArr2 = boundsArr1;
bounds2 = bounds1;
} else {
boundsArr2 = new Array(curvesValues2.length);
for (var i = 0; i < boundsArr2.length; i++) {
bounds2 = new Array(curvesValues2.length);
for (var i = 0; i < bounds2.length; i++) {
var v2 = curvesValues2[i];
boundsArr2[i] = [
bounds2[i] = [
min(v2[0], v2[2], v2[4], v2[6]),
min(v2[1], v2[3], v2[5], v2[7]),
max(v2[0], v2[2], v2[4], v2[6]),
@ -121,8 +116,8 @@ var CollisionDetection = /** @lends CollisionDetection */{
}
}
}
return this.findBoundsCollisions(boundsArr1, boundsArr2,
tolerance || 0, sweepVertical, onlySweepAxisCollisions);
return this.findBoundsCollisions(bounds1, bounds2,
tolerance || 0, sweepVertical, onlySweepAxisCollisions);
},
/**
@ -135,9 +130,9 @@ var CollisionDetection = /** @lends CollisionDetection */{
* Each entry in the bounds arrays must be an array of length 4 with
* x0, y0, x1, and y1 as the array elements.
*
* The returned array has the same length as boundsArr1. Each entry
* The returned array has the same length as bounds1. Each entry
* contains an array with all indices of overlapping bounds of
* boundsArr2 (or boundsArr1 if boundsArr2 is not provided) sorted
* bounds2 (or bounds1 if bounds2 is not provided) sorted
* in ascending order.
*
* If the second bounds array parameter is null, collisions between bounds
@ -145,21 +140,19 @@ var CollisionDetection = /** @lends CollisionDetection */{
* returned for each bounds will not contain the bounds' own index.
*
*
* @param {Array} boundsArr1 Array of bounds objects for which collisions
* @param {Array} boundsA Array of bounds objects for which collisions
* should be found.
* @param {Array} [boundsArr2] Array of bounds that the first array should
* @param {Array} [boundsB] Array of bounds that the first array should
* be compared with. If not provided, collisions between bounds within
* the first arrray will be returned.
* @param {Number} [tolerance] If provided, the tolerance will be added to
* all sides of each bounds when checking for collisions.
* @param {Boolean} [sweepVertical] If set to true, the sweep is done
* along the y axis.
* @param {Boolean} [onlySweepAxisCollisionss] If set to true, no collision
* checks will be done on the secondary axis.
* @returns {Array} Array containing for the bounds at thes same index in
* boundsA an array of the indexes of colliding bounds in boundsB
*
* @author Jan Boesenberg <jan.boesenberg@gmail.com>
* @param {Boolean} [sweepVertical] If true, the sweep is performed along
* the y-axis.
* @param {Boolean} [onlySweepAxisCollisions] If true, no collision checks
* will be done on the secondary axis.
* @returns {Array} Array containing for the bounds at the same index in
* boundsA an array of the indexes of colliding bounds in boundsB
*/
findBoundsCollisions: function(boundsA, boundsB, tolerance,
sweepVertical, onlySweepAxisCollisions) {
@ -176,7 +169,7 @@ var CollisionDetection = /** @lends CollisionDetection */{
lo = 0;
hi = indices.length;
while (lo < hi) {
var mid = (hi + lo) >>> 1; // same as Math.floor((hi+lo)/2)
var mid = (hi + lo) >>> 1; // Same as Math.floor((hi + lo) / 2)
if (allBounds[indices[mid]][coordinate] < coordinateValue) {
lo = mid + 1;
} else {
@ -209,8 +202,9 @@ var CollisionDetection = /** @lends CollisionDetection */{
for (var i = 0; i < countAll; i++) {
var currentIndex = allIndicesByP0[i],
currentBounds = allBounds[currentIndex],
currentOriginalIndex = self ? currentIndex
: currentIndex - countA, // index in boundsA or boundsB array
currentOriginalIndex = self // index in boundsA or boundsB
? currentIndex
: currentIndex - countA,
isCurrentA = currentIndex < countA,
isCurrentB = self || currentIndex >= countA,
currentCollisions = isCurrentA ? [] : null;
@ -273,13 +267,13 @@ var CollisionDetection = /** @lends CollisionDetection */{
if (activeIndicesByP1.length) {
var currentP1 = currentBounds[coordP1],
insertIndex =
binarySearch(activeIndicesByP1, currentP1, coordP1) + 1;
binarySearch(activeIndicesByP1, currentP1, coordP1) + 1;
activeIndicesByP1.splice(insertIndex, 0, currentIndex);
} else {
activeIndicesByP1.push(currentIndex);
}
}
// Sort collision indices in ascending order
// Sort collision indices in ascending order.
for (var i = 0; i < allCollisions.length; i++) {
if (allCollisions[i]) {
allCollisions[i].sort(function(i1, i2) {