【问题标题】:Bezier curve with control points within the curve贝塞尔曲线与曲线内的控制点
【发布时间】:2018-03-10 00:41:17
【问题描述】:

请看下图。 此路径对象是使用每侧的 4 条贝塞尔曲线创建的。 目前,当我尝试获取使用三次火盆曲线创建的路径对象的边界时,我遇到了一个问题。如您所见,顶部和底部的控制点远离曲线,这使得边界完全不准确。

所以我的问题是,是否可以像在图像中那样创建一个拼图块,使所有控制点都在曲线上或曲线的水平面上。 (即创建一条曲线和它的完美镜像,曲线边界内的所有点)

【问题讨论】:

  • 您可以尝试Flatten 路径的副本并使用其边界。如果移动控制点,曲线会发生很大变化!
  • 问题不是计算界限。我已经通过展平来做到这一点。我正在使用 java/android 功能将此路径用作蒙版,然后将拼图图片覆盖在其上以生成拼图。该功能使用这些界限,因此我遇到了这个问题。最简单的方法是尽可能在边界内移动控制点。有什么解决方法吗?

标签: java c# math bezier curve


【解决方案1】:

Bezier 曲线的一个特性是,当您分割它们时,平滑曲线和 CV 之间的距离会缩小。

因此,在顶部和底部修复这些 CV 的一种方法是使用 De Casteljau 算法将相关的 Bezier 拆分为两个 Bezier。

你甚至可以通过算法来做到这一点:

  • 查找紧密边界框和基于 CV 的边界框。
  • 如果差异大于您的容差,请查找最大/最小 CV 及其相关的贝塞尔曲线
  • 将所有相关的贝塞尔曲线分成两条贝塞尔曲线
  • 重复

最终你会达到你的容忍度。如果你有一个非常严格的容差或棘手的数据,那么到那时你可能会有很多贝塞尔曲线。

【讨论】:

    【解决方案2】:

    您可以轻松地将 BEZIER 三次控制点转换为插值三次。只需将其反转:

    所以:

    /*                              bezier = interpol
    1  |                           (    x0)=X1;
    t  |                  (3.0*x1)-(3.0*x0)=(0.5*(X2-X0));
    tt |         (3.0*x2)-(6.0*x1)+(3.0*x0)=(3.0*(X2-X1))-(X2-X0)-(0.5*(X3-X1));
    ttt|(    x3)-(3.0*x2)+(3.0*x1)-(    x0)=(0.5*(X2-X0))+(0.5*(X3-X1))+(2.0*(-X2+X1));
    1  |                           (    y0)=Y1;
    t  |                  (3.0*y1)-(3.0*y0)=(0.5*(Y2-Y0));
    tt |         (3.0*y2)-(6.0*y1)+(3.0*y0)=(3.0*(Y2-Y1))-(Y2-Y0)-(0.5*(Y3-Y1));
    ttt|(    y3)-(3.0*y2)+(3.0*y1)-(    y0)=(0.5*(Y2-Y0))+(0.5*(Y3-Y1))+(2.0*(-Y2+Y1));
    */
    
    // input: x0,y0,..x3,y3 ... Bezier control points
    // output: X0,Y0,..X3,Y3  ... interpolation control points
        double x0,y0,x1,y1,x2,y2,x3,y3,m=1.0/9.0;
        X0=x0-(x1-x0)/m; Y0=y0-(y1-y0)/m;
        X1=x0;           Y1=y0;
        X2=x3;           Y2=y3;
        X3=x3+(x3-x2)/m; Y3=y3+(y3-y2)/m;
    

    希望我没有犯任何代数错误。这会将所有控制点直接移动到您的曲线中,而形状将保持不变。请注意,对于 BBOX 计算,您应该只使用 (X1,Y1)(X2,Y2),因为使用的参数 t=<0,1> 在它们之间进行插值!!!。

    但即使这样也可能会导致不准确,因为您可能会遇到一些没有控制点的极端情况。如果这是一个问题(BBOX 比应该的小一点),您可以通过一些步骤(0.1)重新对曲线上的点集(例如每立方 10 个)进行形状采样并执行 BBOX从那些点。这将更精确但较粗略...

    【讨论】:

      【解决方案3】:

      那么,不要使用控制点来计算边界。至少如果您需要严格的界限并且不想快速检查给定剪切矩形中的潜在可见性。 Thisawesome site 可以为常见的贝塞尔曲线计算提供很多帮助,包括 bounding box

      或者,切换到控制点位于曲线上的样条曲线,但最终可能会产生相反的效果,即曲线超出其控制点施加的边界。

      【讨论】:

      • 感谢您的回复。我已经实现了算法来估计实际界限。但我正在使用 java/android 功能将此路径用作蒙版,然后将拼图图片覆盖在其上以生成拼图。该功能使用这些界限,因此我遇到了这个问题。最简单的方法是尽可能在边界内移动控制点。有什么解决方法吗?
      • 用折线近似曲线。或者在每个方向的最外侧点上分割曲线,使控制点不再位于外侧。如果您可以近似曲线,那么找到该点应该不难。对于其他所有问题,该链接应提供答案。
      猜你喜欢
      • 2011-08-21
      • 1970-01-01
      • 2016-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-01
      • 1970-01-01
      相关资源
      最近更新 更多