mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-03 19:45:44 -05:00
parent
edfd8f53de
commit
d7e075d316
3 changed files with 71 additions and 31 deletions
|
@ -295,39 +295,62 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
var vals = this.getValues(),
|
var vals = this.getValues(),
|
||||||
count = Curve.solveCubic(vals, 1, point.y, roots),
|
count = Curve.solveCubic(vals, 1, point.y, roots),
|
||||||
crossings = 0,
|
crossings = 0,
|
||||||
tolerance = /*#=*/ Numerical.TOLERANCE;
|
tolerance = /*#=*/ Numerical.TOLERANCE,
|
||||||
|
abs = Math.abs;
|
||||||
|
|
||||||
|
// Checks the y-slope between the current curve and the previous for a
|
||||||
|
// change of orientation, when a solution is found at t == 0
|
||||||
|
function changesOrientation(curve, tangent) {
|
||||||
|
return Curve.evaluate(curve.getPrevious().getValues(), 1, true, 1).y
|
||||||
|
* tangent.y > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: See if this speeds up code, or slows it down:
|
||||||
|
// var bounds = this.getBounds();
|
||||||
|
// if (point.y < bounds.getTop() || point.y > bounds.getBottom()
|
||||||
|
// || point.x > bounds.getRight())
|
||||||
|
// return 0;
|
||||||
|
|
||||||
|
if (count === -1) {
|
||||||
|
// Infinite solutions, so we have a horizontal curve.
|
||||||
|
// Find parameter through getParameterOf()
|
||||||
|
roots[0] = Curve.getParameterOf(vals, point.x, point.y);
|
||||||
|
count = roots[0] !== null ? 1 : 0;
|
||||||
|
}
|
||||||
for (var i = 0; i < count; i++) {
|
for (var i = 0; i < count; i++) {
|
||||||
var t = roots[i];
|
var t = roots[i];
|
||||||
if (t >= -tolerance && t < 1 - tolerance) {
|
if (t > -tolerance && t < 1 - tolerance) {
|
||||||
var pt = Curve.evaluate(vals, t, true, 0);
|
var pt = Curve.evaluate(vals, t, true, 0);
|
||||||
/*#*/ if (options.debug) {
|
if (point.x < pt.x + tolerance) {
|
||||||
console.log(t, point + '', pt + '');
|
|
||||||
new Path.Circle({
|
|
||||||
center: Curve.evaluate(vals, t, true, 0),
|
|
||||||
radius: 2,
|
|
||||||
strokeColor: 'red',
|
|
||||||
strokeWidth: 0.25
|
|
||||||
});
|
|
||||||
/*#*/ }
|
|
||||||
if (pt.x >= point.x - tolerance) {
|
|
||||||
// Passing 1 for Curve.evaluate()'s type calculates tangents.
|
// Passing 1 for Curve.evaluate()'s type calculates tangents.
|
||||||
var tangent = Curve.evaluate(vals, t, true, 1);
|
var tan = Curve.evaluate(vals, t, true, 1),
|
||||||
if (
|
diff = abs(pt.x - point.x);
|
||||||
// Skip touching stationary points (tips), but if the
|
// Wee need to handle all kind of edge cases when points are
|
||||||
// actual point is on one, do not skip this solution!
|
// on contours, ore rays are touching countours, do termine
|
||||||
Math.abs(pt.x - point.x) > tolerance
|
// wether the corssings counts or not.
|
||||||
&& (
|
// Is the actual point is on the countour?
|
||||||
// Check derivate for stationary points
|
if (diff < tolerance) {
|
||||||
Math.abs(tangent.y) < tolerance
|
// Do not count the crossing if it is on the left
|
||||||
// If root is close to 0 and not changing vertical
|
// hand side of the shape (tangent pointing upwards)
|
||||||
// orientation from the previous curve, do not count
|
// since the ray will go out the other end and the
|
||||||
// this root, as it's touching a corner.
|
// point is on the contour, so inside.
|
||||||
|| t < tolerance
|
var angle = tan.getAngle();
|
||||||
// Check the y-slope for a change of orientation
|
if (angle > -180 && angle < 0
|
||||||
&& tangent.y * Curve.evaluate(
|
// Handle special case where point is on a corner,
|
||||||
this.getPrevious().getValues(), 1, true, 1).y
|
// in which case we only skip this crossing if both
|
||||||
< tolerance))
|
// tangents have the same orientation (see below)
|
||||||
continue;
|
&& (t > tolerance || changesOrientation(this, tan)))
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// Skip touching stationary points
|
||||||
|
if (abs(tan.y) < tolerance
|
||||||
|
// Check derivate for stationary points. If root is
|
||||||
|
// close to 0 and not changing vertical orientation
|
||||||
|
// from the previous curve, do not count this root,
|
||||||
|
// as it's touching a corner.
|
||||||
|
|| t < tolerance && !changesOrientation(this, tan))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
crossings++;
|
crossings++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1602,10 +1602,12 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
|
||||||
roots = new Array(3);
|
roots = new Array(3);
|
||||||
for (var i = 0, l = curves.length; i < l; i++)
|
for (var i = 0, l = curves.length; i < l; i++)
|
||||||
crossings += curves[i].getCrossings(point, roots);
|
crossings += curves[i].getCrossings(point, roots);
|
||||||
|
// TODO: Do not close open path for contains(), but create a straight
|
||||||
|
// closing lines instead, just like how filling open paths works.
|
||||||
if (!this._closed && hasFill)
|
if (!this._closed && hasFill)
|
||||||
crossings += Curve.create(this, segments[segments.length - 1],
|
crossings += Curve.create(this, segments[segments.length - 1],
|
||||||
segments[0]).getCrossings(point, roots);
|
segments[0]).getCrossings(point, roots);
|
||||||
return (crossings & 1) == 1;
|
return (crossings & 1) === 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
_hitTest: function(point, options) {
|
_hitTest: function(point, options) {
|
||||||
|
|
|
@ -106,6 +106,21 @@ test('Path#contains() (Rectangle Contours)', function() {
|
||||||
var path = new Path.Rectangle(new Point(100, 100), [200, 200]),
|
var path = new Path.Rectangle(new Point(100, 100), [200, 200]),
|
||||||
curves = path.getCurves();
|
curves = path.getCurves();
|
||||||
|
|
||||||
for (var i = 0; i < curves.length; i++)
|
for (var i = 0; i < curves.length; i++) {
|
||||||
|
testPoint(path, curves[i].getPoint(0), true);
|
||||||
testPoint(path, curves[i].getPoint(0.5), true);
|
testPoint(path, curves[i].getPoint(0.5), true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('Path#contains() (Rotated Rectangle Contours)', function() {
|
||||||
|
var path = new Path.Rectangle(new Point(100, 100), [200, 200]),
|
||||||
|
curves = path.getCurves();
|
||||||
|
|
||||||
|
path.rotate(45);
|
||||||
|
|
||||||
|
for (var i = 0; i < curves.length; i++) {
|
||||||
|
testPoint(path, curves[i].getPoint(0), true);
|
||||||
|
testPoint(path, curves[i].getPoint(0.5), true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue