增加贝塞尔曲线分割
This commit is contained in:
54
demo/bezierSplit.html
Normal file
54
demo/bezierSplit.html
Normal file
@@ -0,0 +1,54 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>贝塞尔分割</title>
|
||||
<script src="../dep/esl.js"></script>
|
||||
<script src="../dep/jquery.min.js"></script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.point {
|
||||
position: absolute;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
margin-left: -5px;
|
||||
margin-top: -5px;
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
#start-point {
|
||||
border-color: green;
|
||||
}
|
||||
|
||||
#end-point {
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
#control-point {
|
||||
border-color: blue;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="start-point" class="point" data-index="0"></div>
|
||||
<div id="end-point" class="point" data-index="1"></div>
|
||||
<div id="control-point" class="point" data-index="2"></div>
|
||||
<div class="point" data-index="3"></div>
|
||||
<canvas id="canvas" width="800" height="800"></canvas>
|
||||
<script>
|
||||
require.config({
|
||||
baseUrl: '../src',
|
||||
paths: {
|
||||
demo: '../demo/js',
|
||||
}
|
||||
});
|
||||
define('jquery', $);
|
||||
</script>
|
||||
|
||||
<script>require(['demo/bezierSplit'])</script>
|
||||
</body>
|
||||
</html>
|
||||
106
demo/js/bezierSplit.js
Normal file
106
demo/js/bezierSplit.js
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @file bezierSplit.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* bezier分割
|
||||
*/
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
var splitBezier = require('math/bezierQ2Split');
|
||||
|
||||
var entry = {
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
init: function () {
|
||||
var canvas = $('#canvas').get(0);
|
||||
var ctx = canvas.getContext('2d');
|
||||
var width = canvas.offsetWidth;
|
||||
var height = canvas.offsetHeight;
|
||||
|
||||
var points =[{"x":167,"y":449},{"x":233,"y":331},{"x":431,"y":332},{"x":481,"y":417}];
|
||||
|
||||
$(points).each(function(index, item) {
|
||||
$('[data-index="'+index+'"]').css({
|
||||
left: points[index].x,
|
||||
top: points[index].y
|
||||
})
|
||||
});
|
||||
|
||||
var point;
|
||||
|
||||
$('.point').on('mousedown', function(e) {
|
||||
point = $(this);
|
||||
});
|
||||
|
||||
$(document.body).on('mousemove', onMove);
|
||||
$(document.body).on('mouseup', function(e) {
|
||||
onMove.call(this, e);
|
||||
point = null;
|
||||
});
|
||||
|
||||
function onMove(e) {
|
||||
var px = e.pageX;
|
||||
var py = e.pageY;
|
||||
if(point) {
|
||||
point.css({
|
||||
left: px,
|
||||
top: py
|
||||
});
|
||||
var p = points[+point.attr('data-index')];
|
||||
p.x = px;
|
||||
p.y = py;
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
||||
function getPoint(p0, p1, p2, t) {
|
||||
return {
|
||||
x: p0.x * Math.pow(1 - t, 2) + 2 * p1.x * t * (1-t) + p2.x * Math.pow(t, 2),
|
||||
y: p0.y * Math.pow(1 - t, 2) + 2 * p1.y * t * (1-t) + p2.y * Math.pow(t, 2)
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
|
||||
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
//绘制2次贝塞尔曲线
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth=2;
|
||||
ctx.strokeStyle='gray';
|
||||
|
||||
ctx.moveTo(points[0].x, points[0].y);
|
||||
ctx.quadraticCurveTo(points[1].x,points[1].y,points[2].x,points[2].y);
|
||||
ctx.stroke();
|
||||
|
||||
|
||||
|
||||
var result = splitBezier(points[0], points[1], points[2], getPoint(points[0], points[1], points[2], 0.5));
|
||||
|
||||
result.forEach(function(bezier, i) {
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth=1;
|
||||
ctx.strokeStyle = i ? 'blue' : 'red';
|
||||
ctx.moveTo(bezier[0].x, bezier[0].y);
|
||||
ctx.quadraticCurveTo(bezier[1].x, bezier[1].y, bezier[2].x, bezier[2].y);
|
||||
ctx.stroke();
|
||||
});
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
draw();
|
||||
}
|
||||
};
|
||||
|
||||
entry.init();
|
||||
|
||||
return entry;
|
||||
}
|
||||
);
|
||||
88
src/math/bezierQ2Split.js
Normal file
88
src/math/bezierQ2Split.js
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* @file bezierQ2Split.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* 分割二次贝塞尔曲线
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
var bezierQ2Equation = require('math/bezierQ2Equation');
|
||||
|
||||
// 获取贝塞尔曲线上的点
|
||||
function getPoint(p0, p1, p2, t) {
|
||||
return {
|
||||
x: p0.x * Math.pow(1 - t, 2) + 2 * p1.x * t * (1-t) + p2.x * Math.pow(t, 2),
|
||||
y: p0.y * Math.pow(1 - t, 2) + 2 * p1.y * t * (1-t) + p2.y * Math.pow(t, 2)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 分割贝塞尔曲线
|
||||
*
|
||||
* @param {Object} p0 p0
|
||||
* @param {Object} p1 p1
|
||||
* @param {Object} p2 p2
|
||||
* @param {number|Object} point 分割点t或者坐标
|
||||
* @return {Array} 分割后的贝塞尔
|
||||
*/
|
||||
function bezierQ2Split(p0, p1, p2, point) {
|
||||
var t, p;
|
||||
|
||||
if (typeof(point) === 'number') {
|
||||
t = point;
|
||||
p = getPoint(p0, p1, p2, t);
|
||||
}
|
||||
else if (typeof(point) === 'object') {
|
||||
p = point;
|
||||
var result = bezierQ2Equation(
|
||||
p0.x + p2.x - 2 * p1.x + p0.y + p2.y - 2 * p1.y,
|
||||
2 * (p1.x - p0.x) + 2 * (p1.y - p0.y),
|
||||
p0.x + p0.y - p.x - p.y
|
||||
);
|
||||
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result.length === 1) {
|
||||
t = result[0];
|
||||
}
|
||||
else {
|
||||
var pt = getPoint(p0, p1, p2, result[0]);
|
||||
if (Math.abs(pt.x - p.x) < 0.01 && Math.abs(pt.y - p.y) < 0.01) {
|
||||
t = result[0];
|
||||
}
|
||||
else {
|
||||
t = result[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
[
|
||||
p0,
|
||||
{
|
||||
x: p0.x + (p1.x - p0.x) * t,
|
||||
y: p0.y + (p1.y - p0.y) * t,
|
||||
},
|
||||
p
|
||||
],
|
||||
[
|
||||
p,
|
||||
{
|
||||
x: p1.x + (p2.x - p1.x) * t,
|
||||
y: p1.y + (p2.y - p1.y) * t,
|
||||
},
|
||||
p2
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
return bezierQ2Split;
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user