/**
* @private
* Adds hit testing and path intersection points methods to the Ext.draw.Path.
* Included by the Ext.draw.PathUtil.
*/
Ext.define('Ext.draw.overrides.hittest.Path', {
override: 'Ext.draw.Path',
// An arbitrary point outside the path used for hit testing with ray casting method.
rayOrigin: {
x: -10000,
y: -10000
},
/**
* Tests whether the given point is inside the path.
* @param {Number} x
* @param {Number} y
* @return {Boolean}
* @member Ext.draw.Path
*/
isPointInPath: function(x, y) {
var me = this,
commands = me.commands,
solver = Ext.draw.PathUtil,
origin = me.rayOrigin,
params = me.params,
ln = commands.length,
firstX = null,
firstY = null,
lastX = 0,
lastY = 0,
count = 0,
i, j;
for (i = 0, j = 0; i < ln; i++) {
switch (commands[i]) {
case 'M':
if (firstX !== null) {
// eslint-disable-next-line max-len
if (solver.linesIntersection(firstX, firstY, lastX, lastY, origin.x, origin.y, x, y)) {
count += 1;
}
}
firstX = lastX = params[j];
firstY = lastY = params[j + 1];
j += 2;
break;
case 'L':
// eslint-disable-next-line max-len
if (solver.linesIntersection(lastX, lastY, params[j], params[j + 1], origin.x, origin.y, x, y)) {
count += 1;
}
lastX = params[j];
lastY = params[j + 1];
j += 2;
break;
case 'C':
count += solver.cubicLineIntersections(
lastX, params[j], params[j + 2], params[j + 4],
lastY, params[j + 1], params[j + 3], params[j + 5],
origin.x, origin.y, x, y
).length;
lastX = params[j + 4];
lastY = params[j + 5];
j += 6;
break;
case 'Z':
if (firstX !== null) {
// eslint-disable-next-line max-len
if (solver.linesIntersection(firstX, firstY, lastX, lastY, origin.x, origin.y, x, y)) {
count += 1;
}
}
break;
}
}
return count % 2 === 1;
},
/**
* Tests whether the given point is on the path.
* @param {Number} x
* @param {Number} y
* @return {Boolean}
* @member Ext.draw.Path
*/
isPointOnPath: function(x, y) {
var me = this,
commands = me.commands,
solver = Ext.draw.PathUtil,
params = me.params,
ln = commands.length,
firstX = null,
firstY = null,
lastX = 0,
lastY = 0,
i, j;
for (i = 0, j = 0; i < ln; i++) {
switch (commands[i]) {
case 'M':
if (firstX !== null) {
if (solver.pointOnLine(firstX, firstY, lastX, lastY, x, y)) {
return true;
}
}
firstX = lastX = params[j];
firstY = lastY = params[j + 1];
j += 2;
break;
case 'L':
if (solver.pointOnLine(lastX, lastY, params[j], params[j + 1], x, y)) {
return true;
}
lastX = params[j];
lastY = params[j + 1];
j += 2;
break;
case 'C':
if (solver.pointOnCubic(
lastX, params[j], params[j + 2], params[j + 4],
lastY, params[j + 1], params[j + 3], params[j + 5], x, y)) {
return true;
}
lastX = params[j + 4];
lastY = params[j + 5];
j += 6;
break;
case 'Z':
if (firstX !== null) {
if (solver.pointOnLine(firstX, firstY, lastX, lastY, x, y)) {
return true;
}
}
break;
}
}
return false;
},
/**
* Calculates the points where the given segment intersects the path.
* If four parameters are given then the segment is considered to be a line segment,
* where given parameters are the coordinates of the start and end points.
* If eight parameters are given then the segment is considered to be
* a cubic Bezier curve segment, where given parameters are the
* coordinates of its edge points and control points.
* @param x1
* @param y1
* @param x2
* @param y2
* @param x3
* @param y3
* @param x4
* @param y4
* @return {Array}
* @member Ext.draw.Path
*/
getSegmentIntersections: function(x1, y1, x2, y2, x3, y3, x4, y4) {
var me = this,
count = arguments.length,
solver = Ext.draw.PathUtil,
commands = me.commands,
params = me.params,
ln = commands.length,
firstX = null,
firstY = null,
lastX = 0,
lastY = 0,
intersections = [],
i, j, points;
for (i = 0, j = 0; i < ln; i++) {
switch (commands[i]) {
case 'M':
if (firstX !== null) {
switch (count) {
case 4:
points = solver.linesIntersection(firstX, firstY, lastX, lastY,
x1, y1, x2, y2);
if (points) {
intersections.push(points);
}
break;
case 8:
points = solver.cubicLineIntersections(x1, x2, x3, x4, y1, y2, y3,
y4, firstX, firstY, lastX,
lastY);
intersections.push.apply(intersections, points);
break;
}
}
firstX = lastX = params[j];
firstY = lastY = params[j + 1];
j += 2;
break;
case 'L':
switch (count) {
case 4:
points = solver.linesIntersection(lastX, lastY, params[j],
params[j + 1], x1, y1, x2, y2);
if (points) {
intersections.push(points);
}
break;
case 8:
points = solver.cubicLineIntersections(x1, x2, x3, x4, y1, y2, y3, y4,
lastX, lastY, params[j],
params[j + 1]);
intersections.push.apply(intersections, points);
break;
}
lastX = params[j];
lastY = params[j + 1];
j += 2;
break;
case 'C':
switch (count) {
case 4:
points = solver.cubicLineIntersections(
lastX, params[j], params[j + 2], params[j + 4],
lastY, params[j + 1], params[j + 3], params[j + 5],
x1, y1, x2, y2);
intersections.push.apply(intersections, points);
break;
case 8:
points = solver.cubicsIntersections(
lastX, params[j], params[j + 2], params[j + 4],
lastY, params[j + 1], params[j + 3], params[j + 5],
x1, x2, x3, x4, y1, y2, y3, y4);
intersections.push.apply(intersections, points);
break;
}
lastX = params[j + 4];
lastY = params[j + 5];
j += 6;
break;
case 'Z':
if (firstX !== null) {
switch (count) {
case 4:
points = solver.linesIntersection(firstX, firstY, lastX, lastY, x1,
y1, x2, y2);
if (points) {
intersections.push(points);
}
break;
case 8:
points = solver.cubicLineIntersections(x1, x2, x3, x4, y1, y2, y3,
y4, firstX, firstY, lastX,
lastY);
intersections.push.apply(intersections, points);
break;
}
}
break;
}
}
return intersections;
},
getIntersections: function(path) {
var me = this,
commands = me.commands,
params = me.params,
ln = commands.length,
firstX = null,
firstY = null,
lastX = 0,
lastY = 0,
intersections = [],
i, j, points;
for (i = 0, j = 0; i < ln; i++) {
switch (commands[i]) {
case 'M':
if (firstX !== null) {
points = path.getSegmentIntersections.call(path, firstX, firstY, lastX,
lastY);
intersections.push.apply(intersections, points);
}
firstX = lastX = params[j];
firstY = lastY = params[j + 1];
j += 2;
break;
case 'L':
points = path.getSegmentIntersections.call(path, lastX, lastY, params[j],
params[j + 1]);
intersections.push.apply(intersections, points);
lastX = params[j];
lastY = params[j + 1];
j += 2;
break;
case 'C':
points = path.getSegmentIntersections.call(path, lastX, lastY, params[j],
params[j + 1], params[j + 2],
params[j + 3], params[j + 4],
params[j + 5]);
intersections.push.apply(intersections, points);
lastX = params[j + 4];
lastY = params[j + 5];
j += 6;
break;
case 'Z':
if (firstX !== null) {
points = path.getSegmentIntersections.call(path, firstX, firstY, lastX,
lastY);
intersections.push.apply(intersections, points);
}
break;
}
}
return intersections;
}
});