fix bezier cross bugs

This commit is contained in:
mkwiser
2014-09-04 00:24:42 +08:00
parent d08f45f175
commit b99a79af89
7 changed files with 211 additions and 109 deletions

View File

@@ -10,8 +10,8 @@ define(
function(require) {
var computeBoundingBox = require('render/util/computeBoundingBox');
var isLineCross = require('render/util/isLineCross');
var isBezierCross = require('render/util/isBezierCross');
var isLineCross = require('render/util/isLineRayCross');
var isBezierRayCross = require('render/util/isBezierRayCross');
var entry = {
@@ -24,18 +24,62 @@ define(
var width = canvas.offsetWidth;
var height = canvas.offsetHeight;
var points = [];
[0, 1, 2, 3].forEach(function(i) {
var p = {
x: Math.floor(Math.random() * (width - 100) + 50),
y: Math.floor(Math.random() * (height - 100) + 50)
// var points = [];
// [0, 1, 2, 3].forEach(function(i) {
// var p = {
// x: Math.floor(Math.random() * (width - 100) + 50),
// y: Math.floor(Math.random() * (height - 100) + 50)
// }
// points[i] = p;
// $($('.point').get(i)).css({
// left: p.x,
// top: p.y
// });
// });
var points = [
{
x: 130,
y: 77
},
{
x: 130,
y: 148
},
{
x: 65,
y: 148
},
{
x: 9,
y: 133
}
points[i] = p;
$($('.point').get(i)).css({
left: p.x,
top: p.y
});
});
];
// var points = [
// {
// x: 65,
// y: 148
// },
// {
// x: 20,
// y: 148
// },
// {
// x: 5,
// y: 115
// },
// {
// x: 9,
// y: 133
// }
// ];
$('[data-index="3"]').css({
left: points[3].x,
top: points[3].y
})
var point;
@@ -97,8 +141,10 @@ define(
ctx.lineTo(max[0], min[1]);
ctx.lineTo(min[0], min[1]);
ctx.stroke();
console.log(isBezierCross(points[0], points[1], points[2], points[3]));
//console.time('bezier');
var r = isBezierRayCross(points[0], points[1], points[2], points[3]);
//console.timeEnd('bezier');
console.log(r);
}
draw();

View File

@@ -30,8 +30,9 @@ define(
render.camera.ratio = 1;
});
render.capture.on('dragstart', function(e) {
render.capture.on('down', function(e) {
var shape = render.painter.getShapeIn(e);
if(shape) {
render.selectedShape = shape;
}

View File

@@ -22,8 +22,8 @@ define(
*/
getRect: function(shape) {
return {
x: shape.x,
y: shape.y,
x: shape.x - shape.width / 2 ,
y: shape.y - shape.height / 2,
width: shape.width,
height: shape.height
};
@@ -38,10 +38,12 @@ define(
* @param {boolean} 是否
*/
isIn: function(shape, x, y) {
return x <= shape.x + shape.width
&& x >= shape.x
&& y <= shape.y + shape.height
&& y >= shape.y;
var w = shape.width / 2;
var h = shape.height / 2;
return x <= shape.x + w
&& x >= shape.x - w
&& y <= shape.y + h
&& y >= shape.y - h;
},
/**
@@ -51,13 +53,13 @@ define(
* @param {Object} shape shape数据
*/
draw: function(ctx, shape) {
var w = shape.width;
var h = shape.height;
ctx.moveTo(shape.x, shape.y);
ctx.lineTo(shape.x + w, shape.y);
var w = shape.width / 2;
var h = shape.height / 2;
ctx.moveTo(shape.x - w, shape.y - h);
ctx.lineTo(shape.x + w, shape.y - h);
ctx.lineTo(shape.x + w, shape.y + h);
ctx.lineTo(shape.x, shape.y + h);
ctx.lineTo(shape.x, shape.y);
ctx.lineTo(shape.x - w, shape.y + h);
ctx.lineTo(shape.x - w, shape.y - h);
}
};

View File

@@ -3,91 +3,20 @@
* @author mengke01
* @date
* @description
* 判断x轴射线是否与贝塞尔曲线相交
* 求两个bezier曲线的交点
*/
define(
function(require) {
var computeBoundingBox = require('./computeBoundingBox');
/**
* 判断x轴射线是否与贝塞尔曲线相交
*
* @return {boolean} 是否
* 求两个bezier曲线的交点
*/
function isBezierCross(p0, p1, p2, p) {
// 3点都在同一侧
if(!((p0.y > p.y) + (p1.y > p.y) + (p2.y > p.y)) % 3) {
return false;
}
var bound = computeBoundingBox.quadraticBezier(p0, p1, p2);
// 在包围盒内部
if(
p.x < bound.x + bound.width
& p.y > bound.y && p.y < bound.y + bound.height
) {
var a = p0.y + p2.y - 2 * p1.y;
var b = 2 * (p1.y - p0.y);
var c = p0.y - p.y;
// 求解二次方程
var b4ac = Math.pow(b, 2) - 4 * a *c;
// 有解
if(b4ac >= 0) {
var t1 = (-b + Math.sqrt(b4ac, 2)) / 2 / a;
var t2 = (-b - Math.sqrt(b4ac, 2)) / 2 / a;
var t = 0;
var x1, x2;
// 两个交点
if(t1 >= 0 && t1 <= 1) {
t = t1;
x1 = Math.pow(1 - t, 2) * p0.x
+ 2 * t * (1-t) * p1.x
+ Math.pow(t, 2) * p2.x;
}
if(t2 >= 0 && t2 <= 1) {
t = t2;
x2 = Math.pow(1 - t, 2) * p0.x
+ 2 * t * (1-t) * p1.x
+ Math.pow(t, 2) * p2.x;
}
if (x1 != undefined && x2 != undefined) {
// 点在两个交点中间
if(! (p.x > x1) ^ (p.x < x2) ) {
return true;
}
}
else if(x1 != undefined) {
if(p.x < x1) {
return {
x: x1,
y: p.y
}
}
}
else if(x2 != undefined) {
if(p.x < x2) {
return {
x: x2,
y: p.y
}
}
}
}
}
return false;
function(p0, p1, p2, t0, t1. t2) {
// a = p0 + p2 - 2p1
// b = 2(p1 - p0)
// c = p0
}

View File

@@ -0,0 +1,121 @@
/**
* @file isBezierCross.js
* @author mengke01
* @date
* @description
* 判断x轴射线是否与贝塞尔曲线相交
*/
define(
function(require) {
var computeBoundingBox = require('./computeBoundingBox');
/**
* 判断x轴射线是否与贝塞尔曲线相交
*
* @return {boolean} 是否
*/
function isBezierCross(p0, p1, p2, p) {
// 3点都在同一侧
if(!((p0.y > p.y) + (p1.y > p.y) + (p2.y > p.y)) % 3) {
return false;
}
var bound = computeBoundingBox.quadraticBezier(p0, p1, p2);
// 退化成线段
if(bound.width == 0) {
return ! (p.y > p0.y) ^ (p.y < p2.y)
? {
x: p0.x,
y: p.y
}
: false;
}
// 判断是否在曲线上
else if (bound.height == 0) {
return p.y == p0.y && (p.x < p0.x || p.x < p2.x)
? p
: false;
}
// 在包围盒内部
if(
p.x < bound.x + bound.width
& p.y > bound.y && p.y < bound.y + bound.height
) {
var a = p0.y + p2.y - 2 * p1.y;
var b = 2 * (p1.y - p0.y);
var c = p0.y - p.y;
var t1;
var t2;
// 只有一个解
if(a == 0) {
t1 = -c / b;
t2 = -1;
}
else {
var b4ac = Math.pow(b, 2) - 4 * a *c;
// 求解二次方程
if(b4ac >= 0) {
t1 = (-b + Math.sqrt(b4ac, 2)) / 2 / a;
t2 = (-b - Math.sqrt(b4ac, 2)) / 2 / a;
}
}
var t = 0;
var x1, x2;
// 两个交点
if(t1 >= 0 && t1 <= 1) {
t = t1;
x1 = Math.pow(1 - t, 2) * p0.x
+ 2 * t * (1-t) * p1.x
+ Math.pow(t, 2) * p2.x;
}
if(t2 >= 0 && t2 <= 1) {
t = t2;
x2 = Math.pow(1 - t, 2) * p0.x
+ 2 * t * (1-t) * p1.x
+ Math.pow(t, 2) * p2.x;
}
if (x1 != undefined && x2 != undefined) {
// 点在两个交点中间
if(! (p.x > x1) ^ (p.x < x2) ) {
return p.x > x1
? {x: x2, y: p.y}
: {x: x1, y: p.y};
}
}
else if(x1 != undefined) {
if(p.x < x1) {
return {
x: x1,
y: p.y
}
}
}
else if(x2 != undefined) {
if(p.x < x2) {
return {
x: x2,
y: p.y
}
}
}
}
return false;
}
return isBezierCross;
}
);

View File

@@ -11,8 +11,8 @@
define(
function(require) {
var isBezierCross = require('./isBezierCross');
var isLineCross = require('./isLineCross');
var isBezierCross = require('./isBezierRayCross');
var isLineCross = require('./isLineRayCross');
/**
* 判断点是否在path内部

View File

@@ -38,7 +38,10 @@ define(
var xcross = (p.y - p0.y) / (p1.y - p0.y) * (p1.x - p0.x) + p0.x;
if (xcross > p.x) {
return true;
return {
x: xcross,
y: p.y
};
}
}