将行转换为 "rectangle snake"。 Canvas。 JavaScript
Convert line to "rectangle snake". Canvas. JavaScript
可能有人知道 JavaScript 库或 canvas 绘图框架。
我有以下问题:
1)徒手画一些线(比如Paint/Photoshop铅笔)
2)需要将线转换成"rectangle snake"(使用固定宽度的矩形构建线)
看截图
这个问题用什么库比较好?
可能是某种库已经具有此功能?
我的意思是需要以下功能:
线性近似
样条分离
将行转换为polygons/shapes/objects
如果有人能帮助我就太好了。谢谢!
正如您在问题中所说,您的分数可以 turned into a spline consisting of a set of cubic Bezier curves. Hint: you might simplify the point-set 在计算剩余(更少)分数的样条之前。
下面是如何计算一组沿三次贝塞尔曲线的矩形多边形。
旁注:多边形必须是矩形的,因为不可能沿着曲线路径创建一组边连接的矩形。
- 沿曲线计算一组点。
- 使用#1 中的点,计算每个点的切线角度。
- 使用点和角度,计算从每个点向两个方向向外延伸的垂直线。
- 使用垂直线的端点构建一组多边形。每个新的多边形都是根据先前和当前的垂直端点构建的。
这里是带注释的代码和一个Demo:
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// variables defining a cubic bezier curve
var PI=Math.PI;
var PI2=PI*2;
var s={x:20,y:30};
var c1={x:300,y:40};
var c2={x:40,y:150};
var e={x:370,y:170};
// an array of points plotted along the bezier curve
var points=[];
// an array of polygons along the bezier curve
var polys=[];
// plot some points & tangent angles along the curve
for(var t=0;t<=100;t+=4){
var T=t/100;
// plot a point on the curve
var pos=getCubicBezierXYatT(s,c1,c2,e,T);
// calculate the tangent angle of the curve at that point
var tx = bezierTangent(s.x,c1.x,c2.x,e.x,T);
var ty = bezierTangent(s.y,c1.y,c2.y,e.y,T);
var a = Math.atan2(ty, tx)-PI/2;
// save the x/y position of the point and the tangent angle
points.push({
x:pos.x,
y:pos.y,
angle:a
});
}
// create polygons that extend on either side of the
// original points set
for(var i=1;i<points.length;i++){
var p0=points[i-1];
var p1=points[i];
polys.push({
x0:p0.x+20*Math.cos(p0.angle),
y0:p0.y+20*Math.sin(p0.angle),
x1:p1.x+20*Math.cos(p1.angle),
y1:p1.y+20*Math.sin(p1.angle),
x2:p1.x+20*Math.cos(p1.angle-PI),
y2:p1.y+20*Math.sin(p1.angle-PI),
x3:p0.x+20*Math.cos(p0.angle-PI),
y3:p0.y+20*Math.sin(p0.angle-PI),
});
}
// draw the polygons
for(var i=0;i<polys.length;i++){
var r=polys[i];
ctx.beginPath();
ctx.moveTo(r.x0,r.y0);
ctx.lineTo(r.x1,r.y1);
ctx.lineTo(r.x2,r.y2);
ctx.lineTo(r.x3,r.y3);
ctx.closePath();
ctx.fillStyle=randomColor();
ctx.fill();
ctx.stroke();
}
// draw the bezier curve points
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
for(var i=0;i<points.length;i++){
ctx.lineTo(points[i].x,points[i].y);
}
ctx.lineWidth=3;
ctx.strokeStyle='red';
ctx.stroke();
function randomColor(){
return('#'+Math.floor(Math.random()*16777215).toString(16));
}
//////////////////////////////////////////
// helper functions
//////////////////////////////////////////
// calculate one XY point along Cubic Bezier at interval T
// (where T==0.00 at the start of the curve and T==1.00 at the end)
function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
return({x:x,y:y});
}
// cubic helper formula at T distance
function CubicN(T, a,b,c,d) {
var t2 = T * T;
var t3 = t2 * T;
return a + (-a * 3 + T * (3 * a - a * T)) * T
+ (3 * b + T * (-6 * b + b * 3 * T)) * T
+ (c * 3 - c * 3 * T) * t2
+ d * t3;
}
// calculate the tangent angle at interval T on the curve
function bezierTangent(a, b, c, d, t) {
return (3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b));
};
body{ background-color:white; padding:10px; }
#canvas{border:1px solid red; margin:0 auto; }
<h4>"Rectangular-ish" polygons along the red cubic bezier curve.</h4>
<canvas id="canvas" width=400 height=300></canvas>
等宽多边形:
同样,因为它们是 rectangular-ish 多边形,您将无法获得精确均匀的宽度。要获得半均匀宽度:
- 沿曲线计算许多点(可能超过 1000 个)。
- 使用距离公式将 1000+ 点集简化为沿曲线具有均匀距离的点集:
var distance=Math.sqrt( (pt1.x-pt0.x)*(pt1.x-pt0.x) + (pt1.y-pt0.y)*(pt1.y-pt0.y) )
可能有人知道 JavaScript 库或 canvas 绘图框架。
我有以下问题:
1)徒手画一些线(比如Paint/Photoshop铅笔)
2)需要将线转换成"rectangle snake"(使用固定宽度的矩形构建线)
看截图
这个问题用什么库比较好? 可能是某种库已经具有此功能?
我的意思是需要以下功能:
线性近似
样条分离
将行转换为polygons/shapes/objects
如果有人能帮助我就太好了。谢谢!
正如您在问题中所说,您的分数可以 turned into a spline consisting of a set of cubic Bezier curves. Hint: you might simplify the point-set 在计算剩余(更少)分数的样条之前。
下面是如何计算一组沿三次贝塞尔曲线的矩形多边形。
旁注:多边形必须是矩形的,因为不可能沿着曲线路径创建一组边连接的矩形。
- 沿曲线计算一组点。
- 使用#1 中的点,计算每个点的切线角度。
- 使用点和角度,计算从每个点向两个方向向外延伸的垂直线。
- 使用垂直线的端点构建一组多边形。每个新的多边形都是根据先前和当前的垂直端点构建的。
这里是带注释的代码和一个Demo:
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// variables defining a cubic bezier curve
var PI=Math.PI;
var PI2=PI*2;
var s={x:20,y:30};
var c1={x:300,y:40};
var c2={x:40,y:150};
var e={x:370,y:170};
// an array of points plotted along the bezier curve
var points=[];
// an array of polygons along the bezier curve
var polys=[];
// plot some points & tangent angles along the curve
for(var t=0;t<=100;t+=4){
var T=t/100;
// plot a point on the curve
var pos=getCubicBezierXYatT(s,c1,c2,e,T);
// calculate the tangent angle of the curve at that point
var tx = bezierTangent(s.x,c1.x,c2.x,e.x,T);
var ty = bezierTangent(s.y,c1.y,c2.y,e.y,T);
var a = Math.atan2(ty, tx)-PI/2;
// save the x/y position of the point and the tangent angle
points.push({
x:pos.x,
y:pos.y,
angle:a
});
}
// create polygons that extend on either side of the
// original points set
for(var i=1;i<points.length;i++){
var p0=points[i-1];
var p1=points[i];
polys.push({
x0:p0.x+20*Math.cos(p0.angle),
y0:p0.y+20*Math.sin(p0.angle),
x1:p1.x+20*Math.cos(p1.angle),
y1:p1.y+20*Math.sin(p1.angle),
x2:p1.x+20*Math.cos(p1.angle-PI),
y2:p1.y+20*Math.sin(p1.angle-PI),
x3:p0.x+20*Math.cos(p0.angle-PI),
y3:p0.y+20*Math.sin(p0.angle-PI),
});
}
// draw the polygons
for(var i=0;i<polys.length;i++){
var r=polys[i];
ctx.beginPath();
ctx.moveTo(r.x0,r.y0);
ctx.lineTo(r.x1,r.y1);
ctx.lineTo(r.x2,r.y2);
ctx.lineTo(r.x3,r.y3);
ctx.closePath();
ctx.fillStyle=randomColor();
ctx.fill();
ctx.stroke();
}
// draw the bezier curve points
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
for(var i=0;i<points.length;i++){
ctx.lineTo(points[i].x,points[i].y);
}
ctx.lineWidth=3;
ctx.strokeStyle='red';
ctx.stroke();
function randomColor(){
return('#'+Math.floor(Math.random()*16777215).toString(16));
}
//////////////////////////////////////////
// helper functions
//////////////////////////////////////////
// calculate one XY point along Cubic Bezier at interval T
// (where T==0.00 at the start of the curve and T==1.00 at the end)
function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
return({x:x,y:y});
}
// cubic helper formula at T distance
function CubicN(T, a,b,c,d) {
var t2 = T * T;
var t3 = t2 * T;
return a + (-a * 3 + T * (3 * a - a * T)) * T
+ (3 * b + T * (-6 * b + b * 3 * T)) * T
+ (c * 3 - c * 3 * T) * t2
+ d * t3;
}
// calculate the tangent angle at interval T on the curve
function bezierTangent(a, b, c, d, t) {
return (3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b));
};
body{ background-color:white; padding:10px; }
#canvas{border:1px solid red; margin:0 auto; }
<h4>"Rectangular-ish" polygons along the red cubic bezier curve.</h4>
<canvas id="canvas" width=400 height=300></canvas>
等宽多边形:
同样,因为它们是 rectangular-ish 多边形,您将无法获得精确均匀的宽度。要获得半均匀宽度:
- 沿曲线计算许多点(可能超过 1000 个)。
- 使用距离公式将 1000+ 点集简化为沿曲线具有均匀距离的点集:
var distance=Math.sqrt( (pt1.x-pt0.x)*(pt1.x-pt0.x) + (pt1.y-pt0.y)*(pt1.y-pt0.y) )