绘制通过3分2条Bezier曲线以模拟圆弧(Draw 2 bezier curves through

2019-10-21 17:36发布

我有三个点不在同一直线上,本来我想通过这三点,我做到了画一个圆弧。 而Chrome实际上没有真正拉圈,但使用一些贝塞尔曲线来假装它是圆的,因为贝塞尔曲线很便宜。 如果Chrome正在做,作为一个中间人,为什么不是我画的圆样贝塞尔自己(二贝塞尔,从点1到中间点,中间点至3点)? 这将是更清洁,而且价格便宜(2相比,数量不明的贝塞尔曲线浏览器决定的)。 这就是我在哪里卡住了,怎么样? 应该在哪里了“控制点”是什么?

这是在JavaScript中我的老画弧功能

drawArc = function(startPoint, thirdPoint, endPoint){
var ctx = this.ctx;
ctx.lineWidth = this.strokeWidth;
ctx.strokeStyle = this.strokeColor;

var centerObject = circleCenter( new Point(startPoint.x, startPoint.y), 
                                 new Point(thirdPoint.x, thirdPoint.y), 
                                 new Point(endPoint.x, endPoint.y) );
var centerX = centerObject.x;
var centerY = centerObject.y;
var r = centerObject.r

var angle = Math.atan2(centerX-startPoint.x, centerY-startPoint.y);
// console.log(centerObject);
if (!angle){
    ctx.beginPath();
    ctx.moveTo(startPoint.x, startPoint.y);
    ctx.lineTo(endPoint.x, endPoint.y);
} else {
    if( angle > Math.PI/2) {
        ctx.beginPath();
        ctx.arc(centerX, centerY, r, Math.PI * 1.5-angle, Math.PI * 1.5 + angle, true);
    } else {
        ctx.beginPath();
        ctx.arc(centerX, centerY, r, Math.PI * 1.5-angle, Math.PI * 1.5 + angle, false);
    }
}
ctx.globalCompositeOperation = "source-over";
ctx.stroke();

}
var circleCenter = function(startPoint, thirdPoint, endPoint){
var dy1 = thirdPoint.y - startPoint.y;
var dx1 = thirdPoint.x - startPoint.x;
var dy2 = endPoint.y - thirdPoint.y;
var dx2 = endPoint.x - thirdPoint.x;

var aSlope = dy1/dx1;
var bSlope = dy2/dx2;  


var centerX = (aSlope*bSlope*(startPoint.y - endPoint.y) + bSlope*(startPoint.x + thirdPoint.x)
    - aSlope*(thirdPoint.x+endPoint.x) )/( 2* (bSlope-aSlope) );
var centerY = -1*(centerX - (startPoint.x+thirdPoint.x)/2)/aSlope +  (startPoint.y+thirdPoint.y)/2;
var r = dist(centerX, centerY, startPoint.x, startPoint.y)

return {
    x: centerX,
    y: centerY,
    r: r
};
}

谁能帮我改写drawArc功能使用画布bezierCurveTo()方法,而不是ARC()?

我的代码例子是在这里: http://codepen.io/wentin/pen/VYegqq

Answer 1:

您可以使用接近4条三次Bezier曲线的圈子......但它不是一个完美的圆;-)

示例代码和一个演示:

您可以使用半径常数之间的关系c的起点,终点和控制点来计算自己所需的控制点。 这贝塞尔近似绘制圆围绕原点[0,0],所以你当然会,转化为特定圆的中心点。

 var canvas=document.getElementById("canvas"); var ctx=canvas.getContext("2d"); var cw=canvas.width; var ch=canvas.height; ctx.lineWidth=3; // refined from 0.551915024494 thanks to Pomax var c=0.5522847498307933984022516322796 ; var cx=150; // center x var cy=150; // center y var r=100; // radius drawBezierCircle(cx,cy,r); function drawBezierCircle(cx,cy,r){ ctx.translate(cx,cy); // translate to centerpoint ctx.beginPath(); ctx.moveTo(0,-r); ctx.bezierCurveTo( c*r,-r, r,-c*r, r,0 ); ctx.strokeStyle='red'; ctx.stroke(); ctx.beginPath(); ctx.moveTo(r,0); ctx.bezierCurveTo( r,c*r, c*r,r, 0,r ); ctx.strokeStyle='green'; ctx.stroke(); ctx.beginPath(); ctx.moveTo(0,r); ctx.bezierCurveTo( -c*r,r, -r,c*r, -r,0 ); ctx.strokeStyle='blue'; ctx.stroke(); ctx.beginPath(); ctx.moveTo(-r,0); ctx.bezierCurveTo( -r,-c*r, -c*r,-r, 0,-r ); ctx.strokeStyle='gold'; ctx.stroke(); } 
 body{ background-color: ivory; padding:10px; } #canvas{border:1px solid red;} 
 <canvas id="canvas" width=300 height=300></canvas> 



Answer 2:

可以使用以下方式找到一个三次Bezier曲线的控制点为约计与结束点P0,P1,半径R和角跨度甲圆弧:

表示的控制点为Q0,Q1,Q2和Q3,接着

Q0 = P0,
Q3 = P1,
Q1 = P0 + L * T0
Q2 = P1 - L * T1

其中T0和T1是在P0和P1和L =(4/3)黄褐色(A / 4)的圆弧*的单位切向量。

请注意,逼近误差会成长为角跨度一变大。 因此,如果由3点定义你的圆弧具有相对小的角度范围,你甚至可以用一个三次Bezier曲线具有良好的精度接近它。 同样,如果你总是使用两个贝塞尔曲线(每两个点之间的一条曲线)来近似圆弧,那么你可能会最终有一个不那么好的近似。 如果Chrome使用几个Bezier曲线绘制圆弧,精度可能是贝塞尔曲线的数目不是固定值的原因。



文章来源: Draw 2 bezier curves through 3 points to mimic a circle arc