bezier cross test
This commit is contained in:
parent
2152c4bf62
commit
16556d4494
@ -22,33 +22,14 @@ define(
|
|||||||
var width = canvas.offsetWidth;
|
var width = canvas.offsetWidth;
|
||||||
var height = canvas.offsetHeight;
|
var height = canvas.offsetHeight;
|
||||||
|
|
||||||
var points = [
|
var points = [{"x":132,"y":409},{"x":314,"y":227},{"x":39,"y":356},{"x":181,"y":276},{"x":202,"y":567},{"x":100,"y":122}];
|
||||||
{
|
|
||||||
x: 130,
|
|
||||||
y: 77
|
|
||||||
},
|
|
||||||
{
|
|
||||||
x: 130,
|
|
||||||
y: 148
|
|
||||||
},
|
|
||||||
{
|
|
||||||
x: 65,
|
|
||||||
y: 148
|
|
||||||
},
|
|
||||||
{
|
|
||||||
x: 330,
|
|
||||||
y: 77
|
|
||||||
},
|
|
||||||
{
|
|
||||||
x: 130,
|
|
||||||
y: 148
|
|
||||||
},
|
|
||||||
{
|
|
||||||
x: 165,
|
|
||||||
y: 148
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
|
// benchmark
|
||||||
|
console.time('bezier');
|
||||||
|
for (var i = 0; i < 1000; i++) {
|
||||||
|
isBezierCross.apply(null, points);
|
||||||
|
}
|
||||||
|
console.timeEnd('bezier');
|
||||||
|
|
||||||
points.forEach(function(p, index) {
|
points.forEach(function(p, index) {
|
||||||
$('[data-index="'+index+'"]').css({
|
$('[data-index="'+index+'"]').css({
|
||||||
@ -105,13 +86,14 @@ define(
|
|||||||
ctx.lineWidth = 1;
|
ctx.lineWidth = 1;
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
|
//console.log(JSON.stringify(points));
|
||||||
//console.time('bezier');
|
|
||||||
var r = isBezierCross.apply(null, points);
|
var r = isBezierCross.apply(null, points);
|
||||||
//console.timeEnd('bezier');
|
|
||||||
if(r) {
|
if(r) {
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
r.forEach(function(item) {
|
r.forEach(function(item) {
|
||||||
|
ctx.moveTo(item.x, item.y);
|
||||||
ctx.arc(item.x, item.y, 4, 0, Math.PI * 2, true);
|
ctx.arc(item.x, item.y, 4, 0, Math.PI * 2, true);
|
||||||
});
|
});
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
@ -121,8 +103,6 @@ define(
|
|||||||
|
|
||||||
draw();
|
draw();
|
||||||
|
|
||||||
//var points = [{"x":79,"y":156},{"x":314,"y":227},{"x":74,"y":287},{"x":159,"y":116},{"x":32,"y":256},{"x":303,"y":290}];
|
|
||||||
//console.log(isBezierCross.apply(null, points));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -124,18 +124,23 @@ define(
|
|||||||
tmatrix = minus(multi(xmatrix, ymatrix[4]), multi(ymatrix, xmatrix[4]));
|
tmatrix = minus(multi(xmatrix, ymatrix[4]), multi(ymatrix, xmatrix[4]));
|
||||||
tResult = bezierQ2Equation.apply(this, tmatrix);
|
tResult = bezierQ2Equation.apply(this, tmatrix);
|
||||||
}
|
}
|
||||||
// matrix[4] 系数为0, 曲线2退化成垂直线
|
// xmatrix[4] 系数为0, 曲线2退化成垂直线
|
||||||
else if(xmatrix[4] == 0) {
|
else if(xmatrix[4] == 0) {
|
||||||
tResult = bezierQ2Equation.apply(this, xmatrix);
|
tResult = bezierQ2Equation.apply(this, xmatrix);
|
||||||
}
|
}
|
||||||
else if(ymatrix[4] == 0) {
|
else if(ymatrix[4] == 0) {
|
||||||
tResult = bezierQ2Equation.apply(this, ymatrix);
|
tResult = bezierQ2Equation.apply(this, ymatrix);
|
||||||
|
|
||||||
|
// 保证ymatrix可解
|
||||||
|
tmatrix = xmatrix;
|
||||||
|
xmatrix = ymatrix;
|
||||||
|
ymatrix = tmatrix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 二次系数有一个为0
|
// 二次系数有一个为0
|
||||||
else {
|
else {
|
||||||
// 代入法
|
// 代入法
|
||||||
// 置换矩阵
|
// 置换矩阵, 保持xmatrix[3]为 0
|
||||||
if (ymatrix[3] == 0) {
|
if (ymatrix[3] == 0) {
|
||||||
tmatrix = xmatrix;
|
tmatrix = xmatrix;
|
||||||
xmatrix = ymatrix;
|
xmatrix = ymatrix;
|
||||||
@ -148,66 +153,79 @@ define(
|
|||||||
}
|
}
|
||||||
// 同高次方程1
|
// 同高次方程1
|
||||||
else {
|
else {
|
||||||
|
// 求t2的参数方程
|
||||||
tmatrix = multi(xmatrix, 1 / xmatrix[4]);
|
tmatrix = multi(xmatrix, 1 / xmatrix[4]);
|
||||||
// 代入法求四次方程系数
|
var t4 = multi([
|
||||||
tmatrix = [
|
Math.pow(tmatrix[0], 2),
|
||||||
ymatrix[3] * Math.pow(tmatrix[0], 2), // 4
|
2 * tmatrix[0] * tmatrix[1],
|
||||||
2 * ymatrix[3] * tmatrix[0] * tmatrix[1] + ymatrix[4] * tmatrix[0], // 3
|
2 * tmatrix[0] * tmatrix[2] + Math.pow(tmatrix[1], 2),
|
||||||
ymatrix[3] * (2 * tmatrix[0] * tmatrix[2] + Math.pow(tmatrix[1], 2)) + ymatrix[4] * tmatrix[2] - ymatrix[0], // 2
|
2 * tmatrix[1] * tmatrix[2],
|
||||||
ymatrix[3] * 2 * tmatrix[1] * tmatrix[2] + ymatrix[4] * tmatrix[2] - ymatrix[1], // 1
|
Math.pow(tmatrix[2], 2)
|
||||||
ymatrix[3] * tmatrix[2] * tmatrix[2] - ymatrix[2] // 0
|
], ymatrix[3]);
|
||||||
];
|
|
||||||
tResult = bezierQ4Equation.apply(this, tmatrix);
|
var t3 = multi([0, 0, tmatrix[0], tmatrix[1], tmatrix[2]], ymatrix[4]);
|
||||||
|
|
||||||
|
// 四次方程系数
|
||||||
|
var t5 = plus(t4, t3);
|
||||||
|
t5[2] = t5[2] - ymatrix[0];
|
||||||
|
t5[3] = t5[3] - ymatrix[1];
|
||||||
|
t5[4] = t5[4] - ymatrix[2];
|
||||||
|
|
||||||
|
tResult = bezierQ4Equation.apply(this, t5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// t1 有解
|
// t1 有解
|
||||||
if(tResult) {
|
if(tResult) {
|
||||||
|
|
||||||
var pair = [], t1, t2, t2Result = false;
|
var tr1, t2Result, tr2, px, tx;
|
||||||
|
for (var i = tResult.length - 1; i >= 0; i--) {
|
||||||
for (var i = 0, l = tResult.length; i < l; i++) {
|
tr1 = tResult[i];
|
||||||
t1 = tResult[i];
|
|
||||||
|
|
||||||
// 代入求t2
|
// 方程联和求解
|
||||||
t2Result = bezierQ2Equation(
|
t2Result = bezierQ2Equation(
|
||||||
xmatrix[3],
|
ymatrix[3] - xmatrix[3],
|
||||||
xmatrix[4],
|
ymatrix[4] - xmatrix[4],
|
||||||
-(xmatrix[0] * Math.pow(t1, 2) + xmatrix[1] * t1 + xmatrix[2])
|
(xmatrix[0] * Math.pow(tr1, 2) + xmatrix[1] * tr1 + xmatrix[2])
|
||||||
|
-(ymatrix[0] * Math.pow(tr1, 2) + ymatrix[1] * tr1 + ymatrix[2])
|
||||||
);
|
);
|
||||||
|
|
||||||
if(t2Result) {
|
if(!t2Result) {
|
||||||
|
tResult.splice(i, 1);
|
||||||
// 验证根是否成立
|
}
|
||||||
for (var j = 0, ll = t2Result.length; j < ll; j++) {
|
else {
|
||||||
t2 = t2Result[j];
|
for (var j = t2Result.length - 1; j >= 0; j--) {
|
||||||
// 控制舍入误差,非必需
|
|
||||||
// if(
|
tr2 = t2Result[j];
|
||||||
// true ||
|
|
||||||
// 0.0001 > Math.abs(
|
// 这里有些情况会出现4个解,需要舍去
|
||||||
// ymatrix[0] * Math.pow(t1, 2) + ymatrix[1] * t1 + ymatrix[2]
|
px = p0.x * Math.pow(1 - tr1, 2) + 2 * p1.x * tr1 * (1-tr1) + p2.x * Math.pow(tr1, 2);
|
||||||
// - (ymatrix[3] * Math.pow(t2, 2) + ymatrix[4] * t2)
|
tx = t0.x * Math.pow(1 - tr2, 2) + 2 * t1.x * tr2 * (1-tr2) + t2.x * Math.pow(tr2, 2);
|
||||||
// )
|
|
||||||
// ) {
|
if(0.001 < Math.abs(px - tx)){
|
||||||
pair.push([t1, t2]);
|
t2Result.splice(j, 1);
|
||||||
//}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!t2Result.length) {
|
||||||
|
tResult.splice(i, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 求解x,y坐标
|
// 求解x,y坐标
|
||||||
return pair.length
|
return tResult.length
|
||||||
? pair.map(function(item) {
|
? tResult.map(function(t) {
|
||||||
return {
|
return {
|
||||||
x: xmatrix[0] * Math.pow(t1, 2) + xmatrix[1] * t1 + p0.x,
|
x: p0.x * Math.pow(1 - t, 2) + 2 * p1.x * t * (1-t) + p2.x * Math.pow(t, 2),
|
||||||
y: ymatrix[0] * Math.pow(t1, 2) + ymatrix[1] * t1 + p0.y
|
y: p0.y * Math.pow(1 - t, 2) + 2 * p1.y * t * (1-t) + p2.y * Math.pow(t, 2)
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,22 +35,34 @@ define(
|
|||||||
var b1_lb = isPointInBounding(b2, {x: b1.x, y: b1.y + b1.height}); // 左下
|
var b1_lb = isPointInBounding(b2, {x: b1.x, y: b1.y + b1.height}); // 左下
|
||||||
var b1_rb = isPointInBounding(b2, {x: b1.x + b1.width, y: b1.y + b1.height}); //右下
|
var b1_rb = isPointInBounding(b2, {x: b1.x + b1.width, y: b1.y + b1.height}); //右下
|
||||||
|
|
||||||
|
// b2 包含 b1
|
||||||
|
if(b1_lt && b1_rt && b1_lb && b1_rb) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
var b2_lt = isPointInBounding(b1, b2); // 左上
|
var b2_lt = isPointInBounding(b1, b2); // 左上
|
||||||
var b2_rt = isPointInBounding(b1, {x: b2.x + b2.width, y: b2.y}); // 右上
|
var b2_rt = isPointInBounding(b1, {x: b2.x + b2.width, y: b2.y}); // 右上
|
||||||
var b2_lb = isPointInBounding(b1, {x: b2.x, y: b2.y + b2.height}); // 左下
|
var b2_lb = isPointInBounding(b1, {x: b2.x, y: b2.y + b2.height}); // 左下
|
||||||
var b2_rb = isPointInBounding(b1, {x: b2.x + b2.width, y: b2.y + b2.height}); //右下
|
var b2_rb = isPointInBounding(b1, {x: b2.x + b2.width, y: b2.y + b2.height}); //右下
|
||||||
|
|
||||||
|
// b1 包含 b2
|
||||||
|
if(b2_lt && b2_rt && b2_lb && b2_rb) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
// 无交点
|
// 无交点
|
||||||
if(false == (b1_lt || b1_rt || b1_lb || b1_rb || b2_lt || b2_rt || b2_lb || b2_rb)) {
|
if(false == (b1_lt || b1_rt || b1_lb || b1_rb || b2_lt || b2_rt || b2_lb || b2_rb)) {
|
||||||
return false;
|
// 判断十字架
|
||||||
}
|
if(
|
||||||
// b2 包含 b1
|
(b1.x >= b2.x && b1.x <= b2.x + b2.width)
|
||||||
else if (b1_lt && b1_rt && b1_lb && b1_rb) {
|
|| (b1.y >= b2.y && b1.y <= b2.y + b2.height)
|
||||||
return 2;
|
) {
|
||||||
}
|
return 1;
|
||||||
// b1 包含 b2
|
}
|
||||||
else if (b2_lt && b2_rt && b2_lb && b2_rb) {
|
else {
|
||||||
return 3;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// 有交点
|
// 有交点
|
||||||
else {
|
else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user