【问题标题】:Get a point inside bezier curve在贝塞尔曲线内获取一个点
【发布时间】:2013-09-01 05:19:25
【问题描述】:

我用 KineticJS 画一个 logo,上下两条线都是 bezierCurveTo。

我需要在它们之间画线,所以我需要找到两条曲线内的点。

我想使用的是获取 X 坐标并获取 Y 坐标。 使用方法 bezierCurveTo 我可以找到位置。 问题是 bezierCurveTo 使用第一个参数作为百分比,我的两个 berzier 不相等,所以不是我的解决方案。

有没有给定树点和 X 返回 Y 的函数?

已编辑

我将尝试通过下一个示例更好地解释它 我有 C 点。我需要 A 点和 B 点,它们是 C 点给出的垂直线与贝塞尔曲线的交点,但贝塞尔曲线不是函数。

【问题讨论】:

  • 你的问题令人困惑——至少对我来说是这样:) 你能张贴一张你想要做什么的图片吗?或者重新提出你的问题。
  • 添加相关代码,这样很难理解你在说什么。

标签: kineticjs bezier


【解决方案1】:

给定一个 X 坐标:如何获得 2 条垂直堆叠的贝塞尔曲线的 Y 坐标。

我能想到两种方法,都使用“蛮力”。

第一种方法:检查像素:

  • 在单独的画布上绘制两个贝塞尔曲线。
  • 使用 context.getImageData 获取画布上坐标 X 处所有垂直像素的数组。
  • 在所需的 X 坐标处遍历每个垂直 Y 像素
  • 如果您发现一个不透明的像素,则说明您遇到了贝塞尔曲线(并且是 Y)
  • 从上到下迭代,直到找到顶部的贝塞尔 Y。
  • 从下到上迭代,直到找到底部的 Bezier Y。

这是第一种方法的代码和小提琴:http://jsfiddle.net/m1erickson/uRDYf/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    #canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    // draw a top bezier
    ctx.beginPath();
    ctx.moveTo(50,50);
    ctx.bezierCurveTo(125,0,150,100,250,75);
    ctx.lineWidth=3;
    ctx.strokeStyle="black";
    ctx.stroke();

    // draw a bottom bezier
    ctx.beginPath();
    ctx.moveTo(50,150);
    ctx.bezierCurveTo(125,0,150,100,250,175);
    ctx.lineWidth=3;
    ctx.strokeStyle="blue";
    ctx.stroke();

    // get an array of all the pixels in the canvas
    var x=100;  // put your X coordinate value here
    var iData = ctx.getImageData(x,0,1,canvas.height);
    var data = iData.data;
    var w=canvas.width;
    var h=canvas.height;
    var theY1=-999;  // your top result
    var theY2=-999;  // your bottom result


    // iterate through each Y at your vertical X coordinate
    // Examine the opacity value at the XY
    // if the pixel is not transparent, you have found your Y
    for(var y=0; y<h; y++) {
        if(data[y*4+3]>10){
            theY1=y;
            break;
      }
    }

    // now iterate backwards to get the Y of the bottom curve
    for(var y=0; y<h; y++) {
        if(data[(h-y)*4+3]>10){
            theY2=(h-y);
            break;
      }
    }


    // testing -- display the results

    ctx.beginPath();
    ctx.moveTo(x,0);
    ctx.lineTo(x,h);
    ctx.strokeStyle="lightgray";
    ctx.stroke();

    ctx.beginPath();
    ctx.arc(x,theY1,4,Math.PI*2,false);
    ctx.closePath();
    ctx.arc(x,theY2,4,Math.PI*2,false);
    ctx.closePath();
    ctx.fillStyle="red";
    ctx.fill();

}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

第二种方法:使用贝塞尔曲线公式反复“猜”Y坐标。

仅供参考,三次贝塞尔曲线实际上确实有一个公式

// where ABCD are the control points and T is an interval along that curve

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;
}

您可以像这样按照该公式计算 XY 点:

// cubic bezier T is 0-1
// When T==0.00, you are at the beginning of the Curve
// When T==1.00, you are at the ending of the Curve
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});
}

所以第二种方法是使用 getCubicBezierXYatT 沿曲线反复“猜测”T 值。

当返回的 X 是你想要的 X 时,你也有你想要的 Y。

我还没有尝试过,但是这篇 SO 帖子使用了一种称为 Newton-Raphson 改进的方法来比随机猜测更好:

Getting y from x co-ord for cubic bezier curve, fast Newton-Raphson method

【讨论】:

  • 感谢您的回答,我结束了您所说的类似方法(我的优势在于我知道贝塞尔曲线可能是刻板印象)。出色的 Newton-Raphson 方法,我会牢记这一点
猜你喜欢
  • 2018-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-25
  • 2017-12-12
  • 2011-12-06
  • 2016-02-28
  • 2011-03-10
相关资源
最近更新 更多