Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/418.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 将贝塞尔曲线分成两等分_Javascript_Svg_Linear Algebra_Bezier - Fatal编程技术网

Javascript 将贝塞尔曲线分成两等分

Javascript 将贝塞尔曲线分成两等分,javascript,svg,linear-algebra,bezier,Javascript,Svg,Linear Algebra,Bezier,我有两个点之间的贝塞尔曲线。我想把所有曲线切成两等分。 我的一个想法是,如果我能控制't'值,我将通过t=[0,0.5]和t=[0.5,1]绘制两条曲线,但我不知道如何绘制。下面是我的代码。我不介意任何其他想法或建议 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmln

我有两个点之间的贝塞尔曲线。我想把所有曲线切成两等分。 我的一个想法是,如果我能控制't'值,我将通过t=[0,0.5]和t=[0.5,1]绘制两条曲线,但我不知道如何绘制。下面是我的代码。我不介意任何其他想法或建议

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>D3 test</title>
    <script src="http://d3js.org/d3.v3.min.js"></script>

    <script>
    var Over = function(){
        d3.select(this)
        .style("stroke-opacity", 0.25);
    }
    var Out = function(){
        d3.select(this)
        .transition().duration(200)
        .style("stroke-opacity", 0);
    }

    function curve(n,x1,y1,x2,y2){

        var xr = (x1+x2)/2,
            yr = (y1+y2)/2,
            euDist = Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2)),
            x3 = -y1+xr+yr, x4 = -y2+xr+yr,
            y3 =  x1+yr-xr, y4 =  x2+yr-xr,
            ctrl , curveDescription;

        svg.append('path')
            .attr("stroke", 'blue')
            .attr('fill','none')
            .style("stroke-opacity",0.25)
            .attr('d', 'M'+x3+','+y3+'L'+x4+','+y4)
            .attr('stroke-width',strokeWidth);

        for(var j=0;j<=n;j++){
            ctrl = [(x4-x3)*j/n+x3 , (y4-y3)*j/n+y3] ,                  
            curveDescription=   
                    'M' +x1+','     +y1+ 
                    'Q' +ctrl[0]+','+ctrl[1]+','
                        +x2+','     +y2;

            svg.append('path')
                .attr("stroke", 'blue')
                .attr('fill','none')
                .style("stroke-opacity",0.25)
                .attr('d', curveDescription)
                .attr('stroke-width',strokeWidth);  

            svg.append('path')
                .attr("stroke", 'blue')
                .attr('fill','none')
                .style("stroke-opacity",0)
                .on("mouseover", Over)
                .on("mouseout", Out)
                .attr('d', curveDescription)
                .attr('stroke-width',strokeWidth*25);

        }

    }
    </script>

</head>

<body>
    <script>
    var w = 1268 , h = 680 , strokeWidth = 2;

    var svg = d3.select("body")
                .append("svg")
                .attr("width", w)
                .attr("height", h)

    curve(5, 100,100, 400,500);


    </script>
</body>
</html>

D3试验
var Over=函数(){
d3.选择(本)
.样式(“笔划不透明度”,0.25);
}
var Out=函数(){
d3.选择(本)
.transition().持续时间(200)
.style(“笔划不透明度”,0);
}
函数曲线(n,x1,y1,x2,y2){
变量xr=(x1+x2)/2,
年=(y1+y2)/2,
euDist=Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2)),
x3=-y1+xr+yr,x4=-y2+xr+yr,
y3=x1+yr xr,y4=x2+yr xr,
ctrl,曲线描述;
append('path')
.attr(“笔划”,“蓝色”)
.attr('fill','none')
.style(“笔划不透明度”,0.25)
.attr('d','M'+x3+','+y3+'L'+x4+','+y4)
.attr(“笔划宽度”,笔划宽度);

对于(var j=0;j来说,将贝塞尔曲线拆分为两条曲线相当简单。请查阅De Casteljau的算法

更新

De Casteljau比看起来更简单。对于非数学学家来说,WP的文章可能更清晰。所以我将更简单地解释

假设您有一个由点a、B、C和D定义的贝塞尔曲线,其中a和D是端点,B和C是控制点

假设你想在曲线上的点“t”处找到曲线的值(其中t在0..1范围内)。你可以通过几何体这样做:

  • 沿直线AB找到位于“t”的点E
  • 沿直线BC找到位于“t”的点F
  • 沿直线CD找到位于“t”处的点G

  • 沿直线EF找到位于“t”处的点H

  • 沿直线FG找到位于“t”处的点J

  • 最后,沿直线HJ找到位于“t”的点K

  • K也等于沿贝塞尔曲线的点“t”。这是德卡斯特卢的算法

    但有用的是,它还为我们提供了两条贝塞尔曲线的控制点,如果曲线在点K处分割,则会产生这两条贝塞尔曲线。这两条贝塞尔曲线是:A、E、H、K和K、J、G、D

    在你的例子中,t=0.5,所以找到这两条曲线只是一系列的加法和除以2

      E = (A+B)/2
      F = (B+C)/2
      G = (C+D)/2
      H = (E+F)/2
      J = (F+G)/2
      K = (H+J)/2
    
    显然,这些计算都必须针对x和y进行


    希望这能有所帮助。

    这里有一个将贝塞尔曲线拆分为两条曲线的公式

    var w = 800, h = 560;
    
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    
    var pts = [{x:20, y:20},
               {x:20, y:100},
               {x:200, y:100},
               {x:200,  y:20}];
    var t = 0.5;
    
    function lerp(a, b, t)
    {
        var s = 1 - t;
        return {x:a.x*s + b.x*t,
                y:a.y*s + b.y*t};
    }
    
    
    function splitcurve()
    {
        var p0 = pts[0], p1 = pts[1], p2 = pts[2], p3 = pts[3];
        var p4 = lerp(p0, p1, t);
        var p5 = lerp(p1, p2, t);
        var p6 = lerp(p2, p3, t);
        var p7 = lerp(p4, p5, t);
        var p8 = lerp(p5, p6, t);
        var p9 = lerp(p7, p8, t);
    
        var firsthalf = [p0, p4, p7, p9];
        var secondhalf =  [p9, p8, p6, p3];
    
        console.log(firsthalf);
        console.log(secondhalf);
    
        ctx.beginPath();
        ctx.moveTo(20,20);
        ctx.lineWidth=5;
        ctx.bezierCurveTo(20,100,200,100,200,20);
        ctx.strokeStyle="black";
        ctx.stroke(); 
    
        ctx.beginPath();
        ctx.moveTo(p0.x,p0.y);
        ctx.lineWidth=5;
        ctx.bezierCurveTo(p4.x,p4.y,p7.x,p7.y,p9.x,p9.y);
        ctx.strokeStyle="blue";
        ctx.stroke(); 
    
        ctx.beginPath();
        ctx.moveTo(p9.x,p9.y);
        ctx.lineWidth=5;
        ctx.bezierCurveTo(p8.x,p8.y,p6.x,p6.y,p3.x,p3.y);
        ctx.strokeStyle="red";
        ctx.stroke(); 
    }
    
    splitcurve();
    
    这对我很有帮助。我认为,如果有一个视觉上的答案,其他人会受益更多,我在下面提供

    下图说明了Paul LeBeau的答案中描述的要点。有关相关解释,请参见该答案。实际图表显示了t=0.5的特例,但对于0和1之间的任何t值,一般原则是相同的。黑色粗线表示“控制线”对于原始曲线,而对于第一条“半曲线”,红线显示它们


    我不能直接包括它,所以我上传了它。这对我来说很难理解,但我正在尝试:你的解释让我理解,非常感谢你^ ^非常有用的回答!谢谢。在另一个回答中,我添加了一个图表,说明了你描述的要点。谢谢安德鲁。如果我们有三次曲线,但在不同的位置呢t形?我在一条不同的三次曲线上尝试了这种方法,它形成了一个类似(x立方体)的形状,这种方法无法找到中心。@hmali,不太可能是这样,因为De Casteljau的公式严格地遵循了(递归)的公式Bézier曲线的定义。过去它甚至是绘制Bézier曲线的常用算法。