mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
More refactoring for #1740
This commit is contained in:
parent
46f1aaeca1
commit
d63647eb06
1 changed files with 114 additions and 138 deletions
|
@ -30,35 +30,24 @@ var CollisionDetection = /** @lends CollisionDetection */{
|
||||||
* the first array will be returned.
|
* the first array will be returned.
|
||||||
* @param {Number} [tolerance] If provided, the tolerance will be added to
|
* @param {Number} [tolerance] If provided, the tolerance will be added to
|
||||||
* all sides of each bounds when checking for collisions.
|
* all sides of each bounds when checking for collisions.
|
||||||
* @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
|
* @returns {Array} Array containing for the bounds at the same index in
|
||||||
* items1 an array of the indexes of colliding bounds in items2
|
* items1 an array of the indexes of colliding bounds in items2
|
||||||
*/
|
*/
|
||||||
findItemBoundsCollisions: function(items1, items2, tolerance,
|
findItemBoundsCollisions: function(items1, items2, tolerance) {
|
||||||
sweepVertical, onlySweepAxisCollisions) {
|
function getBounds(items) {
|
||||||
var bounds1 = new Array(items1.length),
|
var bounds = new Array(items.length);
|
||||||
bounds2;
|
for (var i = 0; i < items.length; i++) {
|
||||||
for (var i = 0; i < items1.length; i++) {
|
var rect = items[i].getBounds();
|
||||||
var bounds = items1[i].bounds;
|
bounds[i] = [rect.left, rect.top, rect.right, rect.bottom];
|
||||||
bounds1[i] = [bounds.left, bounds.top, bounds.right, bounds.bottom];
|
|
||||||
}
|
}
|
||||||
if (items2) {
|
return bounds;
|
||||||
if (items2 === items1) {
|
|
||||||
bounds2 = bounds1;
|
|
||||||
} else {
|
|
||||||
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];
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
var bounds1 = getBounds(items1),
|
||||||
return this.findBoundsCollisions(bounds1, bounds2, tolerance || 0,
|
bounds2 = !items2 || items2 === items1
|
||||||
sweepVertical, onlySweepAxisCollisions);
|
? bounds1
|
||||||
|
: getBounds(items2);
|
||||||
|
return this.findBoundsCollisions(bounds1, bounds2, tolerance || 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,14 +56,14 @@ var CollisionDetection = /** @lends CollisionDetection */{
|
||||||
* the actual bounds. Broad bounds guarantee to contain the full curve,
|
* the actual bounds. Broad bounds guarantee to contain the full curve,
|
||||||
* but they are usually larger than the actual bounds of a curve.
|
* but they are usually larger than the actual bounds of a curve.
|
||||||
*
|
*
|
||||||
* This function takes the broad bounds of all curve values in the
|
* This function takes the broad bounds of all curve values in the curves1
|
||||||
* curveValues1 and curveValues2 arrays and calls findBoundsCollisions().
|
* and curves2 arrays and calls findBoundsCollisions().
|
||||||
*
|
*
|
||||||
* @param {Array} curvesValues1 Array of curve values for which collisions
|
* @param {Array} curves1 Array of curve values for which collisions should
|
||||||
* should be found.
|
* be found.
|
||||||
* @param {Array} [curvesValues2] Array of curve values that the first
|
* @param {Array} [curves2] Array of curve values that the first array
|
||||||
* array should be compared with. If not provided, collisions between
|
* should be compared with. If not provided, collisions between curve
|
||||||
* curve bounds within the first arrray will be returned.
|
* bounds within the first arrray will be returned.
|
||||||
* @param {Number} [tolerance] If provided, the tolerance will be added to
|
* @param {Number} [tolerance] If provided, the tolerance will be added to
|
||||||
* all sides of each bounds when checking for collisions.
|
* all sides of each bounds when checking for collisions.
|
||||||
* @param {Boolean} [sweepVertical] If true, the sweep is performed along
|
* @param {Boolean} [sweepVertical] If true, the sweep is performed along
|
||||||
|
@ -82,40 +71,30 @@ var CollisionDetection = /** @lends CollisionDetection */{
|
||||||
* @param {Boolean} [onlySweepAxisCollisions] If true, no collision checks
|
* @param {Boolean} [onlySweepAxisCollisions] If true, no collision checks
|
||||||
* will be done on the secondary axis.
|
* will be done on the secondary axis.
|
||||||
* @returns {Array} Array containing for the bounds at the same index in
|
* @returns {Array} Array containing for the bounds at the same index in
|
||||||
* curveValues1 an array of the indexes of colliding bounds in
|
* curves1 an array of the indexes of colliding bounds in curves2
|
||||||
* curveValues2
|
|
||||||
*/
|
*/
|
||||||
findCurveBoundsCollisions: function(curvesValues1, curvesValues2,
|
findCurveBoundsCollisions: function(curves1, curves2,
|
||||||
tolerance, sweepVertical, onlySweepAxisCollisions) {
|
tolerance, sweepVertical, onlySweepAxisCollisions) {
|
||||||
|
function getBounds(curves) {
|
||||||
var min = Math.min,
|
var min = Math.min,
|
||||||
max = Math.max,
|
max = Math.max,
|
||||||
bounds1 = new Array(curvesValues1.length),
|
bounds = new Array(curves.length);
|
||||||
bounds2;
|
for (var i = 0; i < curves.length; i++) {
|
||||||
for (var i = 0; i < bounds1.length; i++) {
|
var v = curves[i];
|
||||||
var v1 = curvesValues1[i];
|
bounds[i] = [
|
||||||
bounds1[i] = [
|
min(v[0], v[2], v[4], v[6]),
|
||||||
min(v1[0], v1[2], v1[4], v1[6]),
|
min(v[1], v[3], v[5], v[7]),
|
||||||
min(v1[1], v1[3], v1[5], v1[7]),
|
max(v[0], v[2], v[4], v[6]),
|
||||||
max(v1[0], v1[2], v1[4], v1[6]),
|
max(v[1], v[3], v[5], v[7])
|
||||||
max(v1[1], v1[3], v1[5], v1[7])
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
if (curvesValues2) {
|
return bounds;
|
||||||
if (curvesValues2 === curvesValues1) {
|
|
||||||
bounds2 = bounds1;
|
|
||||||
} else {
|
|
||||||
bounds2 = new Array(curvesValues2.length);
|
|
||||||
for (var i = 0; i < bounds2.length; i++) {
|
|
||||||
var v2 = curvesValues2[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]),
|
|
||||||
max(v2[1], v2[3], v2[5], v2[7])
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bounds1 = getBounds(curves1),
|
||||||
|
bounds2 = !curves2 || curves2 === curves1
|
||||||
|
? bounds1
|
||||||
|
: getBounds(curves2);
|
||||||
return this.findBoundsCollisions(bounds1, bounds2,
|
return this.findBoundsCollisions(bounds1, bounds2,
|
||||||
tolerance || 0, sweepVertical, onlySweepAxisCollisions);
|
tolerance || 0, sweepVertical, onlySweepAxisCollisions);
|
||||||
},
|
},
|
||||||
|
@ -156,21 +135,20 @@ var CollisionDetection = /** @lends CollisionDetection */{
|
||||||
*/
|
*/
|
||||||
findBoundsCollisions: function(boundsA, boundsB, tolerance,
|
findBoundsCollisions: function(boundsA, boundsB, tolerance,
|
||||||
sweepVertical, onlySweepAxisCollisions) {
|
sweepVertical, onlySweepAxisCollisions) {
|
||||||
|
var self = !boundsB || boundsA === boundsB,
|
||||||
|
allBounds = self ? boundsA : boundsA.concat(boundsB),
|
||||||
|
lengthA = boundsA.length,
|
||||||
|
lengthAll = allBounds.length;
|
||||||
|
|
||||||
// Binary search utility function.
|
// Binary search utility function.
|
||||||
// For multiple same entries, this returns the rightmost entry.
|
// For multiple same entries, this returns the rightmost entry.
|
||||||
// https://en.wikipedia.org/wiki/Binary_search_algorithm#Procedure_for_finding_the_rightmost_element
|
// https://en.wikipedia.org/wiki/Binary_search_algorithm#Procedure_for_finding_the_rightmost_element
|
||||||
var self = !boundsB || boundsA === boundsB,
|
function binarySearch(indices, coord, value) {
|
||||||
allBounds = self ? boundsA : boundsA.concat(boundsB),
|
var lo = 0,
|
||||||
countA = boundsA.length,
|
|
||||||
countAll = allBounds.length,
|
|
||||||
lo, hi;
|
|
||||||
|
|
||||||
function binarySearch(indices, coordinateValue, coordinate) {
|
|
||||||
lo = 0;
|
|
||||||
hi = indices.length;
|
hi = indices.length;
|
||||||
while (lo < hi) {
|
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) {
|
if (allBounds[indices[mid]][coord] < value) {
|
||||||
lo = mid + 1;
|
lo = mid + 1;
|
||||||
} else {
|
} else {
|
||||||
hi = mid;
|
hi = mid;
|
||||||
|
@ -182,73 +160,73 @@ var CollisionDetection = /** @lends CollisionDetection */{
|
||||||
// Set coordinates for primary and secondary axis depending on sweep
|
// Set coordinates for primary and secondary axis depending on sweep
|
||||||
// direction. By default we sweep in horizontal direction, which
|
// direction. By default we sweep in horizontal direction, which
|
||||||
// means x is the primary axis.
|
// means x is the primary axis.
|
||||||
var coordP0 = sweepVertical ? 1 : 0,
|
var pri0 = sweepVertical ? 1 : 0,
|
||||||
coordP1 = coordP0 + 2,
|
pri1 = pri0 + 2,
|
||||||
coordS0 = sweepVertical ? 0 : 1,
|
sec0 = sweepVertical ? 0 : 1,
|
||||||
coordS1 = coordS0 + 2;
|
sec1 = sec0 + 2;
|
||||||
// Create array with all indices sorted by lower boundary on primary
|
// Create array with all indices sorted by lower boundary on primary
|
||||||
// axis.
|
// axis.
|
||||||
var allIndicesByP0 = new Array(countAll);
|
var allIndicesByPri0 = new Array(lengthAll);
|
||||||
for (var i = 0; i < countAll; i++) {
|
for (var i = 0; i < lengthAll; i++) {
|
||||||
allIndicesByP0[i] = i;
|
allIndicesByPri0[i] = i;
|
||||||
}
|
}
|
||||||
allIndicesByP0.sort(function(i1, i2) {
|
allIndicesByPri0.sort(function(i1, i2) {
|
||||||
return allBounds[i1][coordP0] - allBounds[i2][coordP0];
|
return allBounds[i1][pri0] - allBounds[i2][pri0];
|
||||||
});
|
});
|
||||||
// Sweep along primary axis. Indices of active bounds are kept in an
|
// Sweep along primary axis. Indices of active bounds are kept in an
|
||||||
// array sorted by higher boundary on primary axis.
|
// array sorted by higher boundary on primary axis.
|
||||||
var activeIndicesByP1 = [],
|
var activeIndicesByPri1 = [],
|
||||||
allCollisions = new Array(countA);
|
allCollisions = new Array(lengthA);
|
||||||
for (var i = 0; i < countAll; i++) {
|
for (var i = 0; i < lengthAll; i++) {
|
||||||
var currentIndex = allIndicesByP0[i],
|
var curIndex = allIndicesByPri0[i],
|
||||||
currentBounds = allBounds[currentIndex],
|
curBounds = allBounds[curIndex],
|
||||||
currentOriginalIndex = self // index in boundsA or boundsB
|
// The original index in boundsA or boundsB:
|
||||||
? currentIndex
|
origIndex = self ? curIndex : curIndex - lengthA,
|
||||||
: currentIndex - countA,
|
isCurrentA = curIndex < lengthA,
|
||||||
isCurrentA = currentIndex < countA,
|
isCurrentB = self || !isCurrentA,
|
||||||
isCurrentB = self || currentIndex >= countA,
|
curCollisions = isCurrentA ? [] : null;
|
||||||
currentCollisions = isCurrentA ? [] : null;
|
if (activeIndicesByPri1.length) {
|
||||||
if (activeIndicesByP1.length) {
|
// remove (prune) indices that are no longer active.
|
||||||
// remove (prune) indices that are no longer active
|
var pruneCount = binarySearch(activeIndicesByPri1, pri1,
|
||||||
var pruneCount = binarySearch(activeIndicesByP1,
|
curBounds[pri0] - tolerance) + 1;
|
||||||
currentBounds[coordP0] - tolerance, coordP1) + 1;
|
activeIndicesByPri1.splice(0, pruneCount);
|
||||||
activeIndicesByP1.splice(0, pruneCount);
|
// Add collisions for current index.
|
||||||
// add collisions for current index
|
|
||||||
if (self && onlySweepAxisCollisions) {
|
if (self && onlySweepAxisCollisions) {
|
||||||
// All active indexes can be added, no further checks needed
|
// All active indexes can be added, no further checks needed
|
||||||
currentCollisions = currentCollisions.concat(
|
curCollisions = curCollisions.concat(activeIndicesByPri1);
|
||||||
activeIndicesByP1.slice());
|
|
||||||
// Add current index to collisions of all active indexes
|
// Add current index to collisions of all active indexes
|
||||||
for (var j = 0; j < activeIndicesByP1.length; j++) {
|
for (var j = 0; j < activeIndicesByPri1.length; j++) {
|
||||||
var activeIndex = activeIndicesByP1[j];
|
var activeIndex = activeIndicesByPri1[j];
|
||||||
allCollisions[activeIndex].push(currentOriginalIndex);
|
allCollisions[activeIndex].push(origIndex);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var currentS1 = currentBounds[coordS1],
|
var curSec1 = curBounds[sec1],
|
||||||
currentS0 = currentBounds[coordS0];
|
curSec0 = curBounds[sec0];
|
||||||
for (var j = 0; j < activeIndicesByP1.length; j++) {
|
for (var j = 0; j < activeIndicesByPri1.length; j++) {
|
||||||
var activeIndex = activeIndicesByP1[j],
|
var activeIndex = activeIndicesByPri1[j],
|
||||||
isActiveA = activeIndex < countA,
|
activeBounds = allBounds[activeIndex],
|
||||||
isActiveB = self || activeIndex >= countA;
|
isActiveA = activeIndex < lengthA,
|
||||||
// Check secondary axis bounds if necessary
|
isActiveB = self || activeIndex >= lengthA;
|
||||||
if (onlySweepAxisCollisions ||
|
|
||||||
(((isCurrentA && isActiveB) ||
|
// Check secondary axis bounds if necessary.
|
||||||
(isCurrentB && isActiveA)) &&
|
if (
|
||||||
currentS1 >=
|
onlySweepAxisCollisions ||
|
||||||
allBounds[activeIndex][coordS0] -
|
(
|
||||||
tolerance &&
|
isCurrentA && isActiveB ||
|
||||||
currentS0 <=
|
isCurrentB && isActiveA
|
||||||
allBounds[activeIndex][coordS1] +
|
) && (
|
||||||
tolerance)) {
|
curSec1 >= activeBounds[sec0] - tolerance &&
|
||||||
|
curSec0 <= activeBounds[sec1] + tolerance
|
||||||
|
)
|
||||||
|
) {
|
||||||
// Add current index to collisions of active
|
// Add current index to collisions of active
|
||||||
// indices and vice versa.
|
// indices and vice versa.
|
||||||
if (isCurrentA && isActiveB) {
|
if (isCurrentA && isActiveB) {
|
||||||
currentCollisions.push(
|
curCollisions.push(
|
||||||
self ? activeIndex : activeIndex - countA);
|
self ? activeIndex : activeIndex - lengthA);
|
||||||
}
|
}
|
||||||
if (isCurrentB && isActiveA) {
|
if (isCurrentB && isActiveA) {
|
||||||
allCollisions[activeIndex].push(
|
allCollisions[activeIndex].push(origIndex);
|
||||||
currentOriginalIndex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,29 +234,27 @@ var CollisionDetection = /** @lends CollisionDetection */{
|
||||||
}
|
}
|
||||||
if (isCurrentA) {
|
if (isCurrentA) {
|
||||||
if (boundsA === boundsB) {
|
if (boundsA === boundsB) {
|
||||||
// if both arrays are the same, add self collision
|
// If both arrays are the same, add self collision.
|
||||||
currentCollisions.push(currentIndex);
|
curCollisions.push(curIndex);
|
||||||
}
|
}
|
||||||
// add collisions for current index
|
// Add collisions for current index.
|
||||||
allCollisions[currentIndex] = currentCollisions;
|
allCollisions[curIndex] = curCollisions;
|
||||||
}
|
}
|
||||||
// add current index to active indices. Keep array sorted by
|
// Add current index to active indices. Keep array sorted by
|
||||||
// their higher boundary on the primary axis
|
// their higher boundary on the primary axis.s
|
||||||
if (activeIndicesByP1.length) {
|
if (activeIndicesByPri1.length) {
|
||||||
var currentP1 = currentBounds[coordP1],
|
var curPri1 = curBounds[pri1],
|
||||||
insertIndex =
|
index = binarySearch(activeIndicesByPri1, pri1, curPri1);
|
||||||
binarySearch(activeIndicesByP1, currentP1, coordP1) + 1;
|
activeIndicesByPri1.splice(index + 1, 0, curIndex);
|
||||||
activeIndicesByP1.splice(insertIndex, 0, currentIndex);
|
|
||||||
} else {
|
} else {
|
||||||
activeIndicesByP1.push(currentIndex);
|
activeIndicesByPri1.push(curIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Sort collision indices in ascending order.
|
// Sort collision indices in ascending order.
|
||||||
for (var i = 0; i < allCollisions.length; i++) {
|
for (var i = 0; i < allCollisions.length; i++) {
|
||||||
if (allCollisions[i]) {
|
var collisions = allCollisions[i];
|
||||||
allCollisions[i].sort(function(i1, i2) {
|
if (collisions) {
|
||||||
return i1 - i2;
|
collisions.sort(function(i1, i2) { return i1 - i2; });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return allCollisions;
|
return allCollisions;
|
||||||
|
|
Loading…
Reference in a new issue