mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-04 03:45:58 -05:00
Boolean: More refactoring and code simplifications.
This commit is contained in:
parent
a1666a9b82
commit
7acb5bee45
1 changed files with 25 additions and 27 deletions
|
@ -28,18 +28,21 @@
|
||||||
* http://hkrish.com/playground/paperjs/booleanStudy.html
|
* http://hkrish.com/playground/paperjs/booleanStudy.html
|
||||||
*/
|
*/
|
||||||
PathItem.inject(new function() {
|
PathItem.inject(new function() {
|
||||||
// Set up lookup tables for each operator, to decide if a given segment is
|
var min = Math.min,
|
||||||
// to be considered a part of the solution, or to be discarded, based on its
|
max = Math.max,
|
||||||
// winding contribution, as calculated by propagateWinding().
|
abs = Math.abs,
|
||||||
// Boolean operators return true if a segment with the given winding
|
// Set up lookup tables for each operator, to decide if a given segment
|
||||||
// contribution contributes to the final result or not. They are applied to
|
// is to be considered a part of the solution, or to be discarded, based
|
||||||
// for each segment after the paths are split at crossings.
|
// on its winding contribution, as calculated by propagateWinding().
|
||||||
var operators = {
|
// Boolean operators return true if a segment with the given winding
|
||||||
unite: { 1: true },
|
// contribution contributes to the final result or not. They are applied
|
||||||
intersect: { 2: true },
|
// to for each segment after the paths are split at crossings.
|
||||||
subtract: { 1: true },
|
operators = {
|
||||||
exclude: { 1: true }
|
unite: { 1: true },
|
||||||
};
|
intersect: { 2: true },
|
||||||
|
subtract: { 1: true },
|
||||||
|
exclude: { 1: true }
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates a clone of the path that we can modify freely, with its matrix
|
* Creates a clone of the path that we can modify freely, with its matrix
|
||||||
|
@ -324,7 +327,6 @@ PathItem.inject(new function() {
|
||||||
*/
|
*/
|
||||||
function getWinding(point, curves, dir) {
|
function getWinding(point, curves, dir) {
|
||||||
var epsilon = /*#=*/Numerical.WINDING_EPSILON,
|
var epsilon = /*#=*/Numerical.WINDING_EPSILON,
|
||||||
abs = Math.abs,
|
|
||||||
// Determine the index of the abscissa and ordinate values in the
|
// Determine the index of the abscissa and ordinate values in the
|
||||||
// curve values arrays, based on the direction:
|
// curve values arrays, based on the direction:
|
||||||
ia = dir ? 1 : 0, // the abscissa index
|
ia = dir ? 1 : 0, // the abscissa index
|
||||||
|
@ -346,8 +348,7 @@ PathItem.inject(new function() {
|
||||||
function addWinding(v) {
|
function addWinding(v) {
|
||||||
var o0 = v[io],
|
var o0 = v[io],
|
||||||
o3 = v[io + 6];
|
o3 = v[io + 6];
|
||||||
if (o0 > po && o3 > po ||
|
if (o0 > po && o3 > po || o0 < po && o3 < po) {
|
||||||
o0 < po && o3 < po) {
|
|
||||||
// If curve is outside the ordinates' range, no intersection
|
// If curve is outside the ordinates' range, no intersection
|
||||||
// with the ray is possible.
|
// with the ray is possible.
|
||||||
return v;
|
return v;
|
||||||
|
@ -373,8 +374,7 @@ PathItem.inject(new function() {
|
||||||
var roots = [],
|
var roots = [],
|
||||||
a = po === o0 ? a0
|
a = po === o0 ? a0
|
||||||
: po === o3 ? a3
|
: po === o3 ? a3
|
||||||
: (a0 < paL && a1 < paL && a2 < paL && a3 < paL) ||
|
: paL > max(a0, a1, a2, a3) || paR < min(a0, a1, a2, a3)
|
||||||
(a0 > paR && a1 > paR && a2 > paR && a3 > paR)
|
|
||||||
? (a0 + a3) / 2
|
? (a0 + a3) / 2
|
||||||
: Curve.solveCubic(v, io, po, roots, 0, 1) === 1
|
: Curve.solveCubic(v, io, po, roots, 0, 1) === 1
|
||||||
? Curve.getPoint(v, roots[0])[dir ? 'y' : 'x']
|
? Curve.getPoint(v, roots[0])[dir ? 'y' : 'x']
|
||||||
|
@ -402,8 +402,7 @@ PathItem.inject(new function() {
|
||||||
if (a3Prev > paL) {
|
if (a3Prev > paL) {
|
||||||
pathWindingR += winding;
|
pathWindingR += winding;
|
||||||
}
|
}
|
||||||
} else if (a3Prev < paL && a > paL
|
} else if (a3Prev < paL && a > paL || a3Prev > paR && a < paR) {
|
||||||
|| a3Prev > paR && a < paR) {
|
|
||||||
// Point is on a horizontal curve between the previous non-
|
// Point is on a horizontal curve between the previous non-
|
||||||
// horizontal and the current curve.
|
// horizontal and the current curve.
|
||||||
isOnPath = true;
|
isOnPath = true;
|
||||||
|
@ -425,8 +424,7 @@ PathItem.inject(new function() {
|
||||||
o2 = v[io + 4],
|
o2 = v[io + 4],
|
||||||
o3 = v[io + 6];
|
o3 = v[io + 6];
|
||||||
// Only handle curves that can cross the point's ordinate.
|
// Only handle curves that can cross the point's ordinate.
|
||||||
if ((o0 >= po || o1 >= po || o2 >= po || o3 >= po) &&
|
if (po <= max(o0, o1, o2, o3) && po >= min(o0, o1, o2, o3)) {
|
||||||
(o0 <= po || o1 <= po || o2 <= po || o3 <= po)) {
|
|
||||||
// Get the abscissas:
|
// Get the abscissas:
|
||||||
var a0 = v[ia],
|
var a0 = v[ia],
|
||||||
a1 = v[ia + 2],
|
a1 = v[ia + 2],
|
||||||
|
@ -434,8 +432,8 @@ PathItem.inject(new function() {
|
||||||
a3 = v[ia + 6],
|
a3 = v[ia + 6],
|
||||||
// Get monotone curves. If the curve is outside the point's
|
// Get monotone curves. If the curve is outside the point's
|
||||||
// abscissa, it can be treated as a monotone curve:
|
// abscissa, it can be treated as a monotone curve:
|
||||||
monoCurves = (a0 < paL && a1 < paL && a2 < paL && a3 < paL)
|
monoCurves = paL > max(a0, a1, a2, a3) ||
|
||||||
|| (a0 > paR && a1 > paR && a2 > paR && a3 > paR)
|
paR < min(a0, a1, a2, a3)
|
||||||
? [v] : Curve.getMonoCurves(v, dir);
|
? [v] : Curve.getMonoCurves(v, dir);
|
||||||
for (var i = 0, l = monoCurves.length; i < l; i++) {
|
for (var i = 0, l = monoCurves.length; i < l; i++) {
|
||||||
vPrev = addWinding(monoCurves[i]);
|
vPrev = addWinding(monoCurves[i]);
|
||||||
|
@ -518,7 +516,7 @@ PathItem.inject(new function() {
|
||||||
// This is required when handling unite operations, where a winding
|
// This is required when handling unite operations, where a winding
|
||||||
// contribution of 2 is not part of the result unless it's the contour:
|
// contribution of 2 is not part of the result unless it's the contour:
|
||||||
return {
|
return {
|
||||||
winding: Math.max(windingL, windingR),
|
winding: max(windingL, windingR),
|
||||||
contour: !windingL ^ !windingR
|
contour: !windingL ^ !windingR
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -553,8 +551,8 @@ PathItem.inject(new function() {
|
||||||
// Determine the direction in which to check the winding
|
// Determine the direction in which to check the winding
|
||||||
// from the point (horizontal or vertical), based on the
|
// from the point (horizontal or vertical), based on the
|
||||||
// curve's direction at that point.
|
// curve's direction at that point.
|
||||||
dir = Math.abs(curve.getTangentAtTime(t).normalize().y)
|
dir = abs(curve.getTangentAtTime(t).normalize().y) < 0.5
|
||||||
< 0.5 ? 1 : 0;
|
? 1 : 0;
|
||||||
if (parent instanceof CompoundPath)
|
if (parent instanceof CompoundPath)
|
||||||
path = parent;
|
path = parent;
|
||||||
// While subtracting, we need to omit this curve if it is
|
// While subtracting, we need to omit this curve if it is
|
||||||
|
@ -757,7 +755,7 @@ PathItem.inject(new function() {
|
||||||
// location, but the winding calculation still produces a valid
|
// location, but the winding calculation still produces a valid
|
||||||
// number due to their slight differences producing a tiny area.
|
// number due to their slight differences producing a tiny area.
|
||||||
var area = path.getArea(true);
|
var area = path.getArea(true);
|
||||||
if (Math.abs(area) >= /*#=*/Numerical.GEOMETRIC_EPSILON) {
|
if (abs(area) >= /*#=*/Numerical.GEOMETRIC_EPSILON) {
|
||||||
// This path wasn't finished and is hence invalid.
|
// This path wasn't finished and is hence invalid.
|
||||||
// Report the error to the console for the time being.
|
// Report the error to the console for the time being.
|
||||||
console.error('Boolean operation resulted in open path',
|
console.error('Boolean operation resulted in open path',
|
||||||
|
|
Loading…
Reference in a new issue