【问题标题】:Perpendicular line from bezier curve to point从贝塞尔曲线到点的垂直线
【发布时间】:2020-04-27 00:12:10
【问题描述】:

问题

我需要得到 三次 (2d) 贝塞尔曲线的 Q B(t) 从点 B(t) em>Q 到另一个给定点 P 与贝塞尔曲线垂直相交

  • 我知道:P, B(t)
  • 我在寻找:Q(基本上我想得到 g 的斜率,但是当我知道 Q 时,我可以很容易地计算出来,但是g的斜率就足够了)


到目前为止我做了什么(你可以跳过这个)

请注意,我认为这个 ansatz 是错误的。这只是为了完整性。

我试图用我的(基本)数学知识来解决这个问题,但我无法完成它。这是我现在的(请不要对符号太严格,我不太擅长):

以下公式将表示为 y(x) 以获得一个结果,这必须为 y(x) 计算x(y)。点P是控制点,QQg(x)线的点P 垂直于贝塞尔曲线 B(t) = (x, y)Tg(x) 行的表达式可以通过

检索

其中 B(x) 是笛卡尔坐标中的贝塞尔曲线,B'(x) 是导数(笛卡尔坐标中),k 是与 y 轴的交点。要得到 g(x) 的斜率,必须解决

要计算 B(x),必须为 t 求解 B(t),然后插入回到B(t)。所以在贝塞尔曲线上的每个点都有关系

这也适用于导数B'(t)

B(t)的导数是(根据wikipedia

为 t (with wolfram alpha) 求解这个结果

其中 a0 = (P1 - P0)x, a1 = (P2 - P 1)xa2 = (P3子> - P2)x。将 *ti*s 插回 B(t) 会导致 (wolfram alpha for t1, wolfram alpha for t2, wolfram alpha for t3)

现在接下来是使用 y = B'(x) 和第二个等式并消除 x 但我不知道怎么做,我不知道甚至知道这是否可能。

【问题讨论】:

  • 非常重要的技术说明:没有“重点”。事实上,可能有 许多 个点与 P 形成一条垂直于曲线的直线。以你试图找到一个点的想法为基础的数学会导致错误的公式。
  • @Mike'Pomax'Kamermans 哦,是的,你是对的。我什至没有想到这一点。谢谢

标签: geometry computational-geometry intersection bezier cubic-bezier


【解决方案1】:

您已经知道贝塞尔曲线的导数 - 它描述了曲线的切线。此切线应垂直于QP 向量。所以此时你需要写向量PQ和切向量T的两个分量

PQx = (1-t)^3 * P0.x + 3*t*(1-t)^2*P1.x  ... - P.x
PQy = (1-t)^3 * P0.y + ... - P.y
Tx = 3*(1-t)^2 * (P1.x - P0.x).... and so on
Ty = ....

并为向量T和QP的点积建立方程(垂直向量的点积为零):

 PQx * Tx + PQy * Ty = 0

现在打开括号并得到未知t5次度方程。

此类多项式方程没有封闭形式的解,因此您需要某种数值 root-finding algorithm(使用那些用于多项式根的数值)

【讨论】:

    【解决方案2】:

    我找到了一个由mbostock on Github 提出的近似问题的实现,他实现了this online book which was acutally created by @Mike'Pomax'Kamermans 关于贝塞尔曲线的想法。如果您必须处理贝塞尔曲线,请检查一下。这解释了我在使用贝塞尔曲线时遇到的大部分问题。

    算法的思路如下:

    1. 做一个粗略的近似:
      1. 通过插入不同的tQapprox, i >is in B(t)(mbostock 使用 t1 = 0, t2 = 1/8, t3 = 2/8, ...)。
      2. 计算Q约,i 之间的二次(保存一个平方根计算)距离>P.
      3. 保存 Qapprox, iti 是最近的(距离最短)。
    2. 进行更精确的近似:
      1. 选择一个精度q
      2. 计算tbefore = ti - q
      3. 检查Q之前之间的距离是否=B (tbefore)和P之间的距离小于Q大约,iP,如果是,则设置 Q大约,i = Q大约,之前并从 2 开始(精确近似),如果没有继续。
      4. 计算tafter = ti + q
      5. 检查Q约后之间的距离是否=B (tafter)和P之间的距离小于Q大约,iP,如果是,则设置 Q大约,i = Qafter 并开始在 2(精确近似),如果没有继续。
      6. Q近似,i 是最接近的。如果精度足够好,请在此处停止。如果不降低精度 q(mbostock 除以 2)并从 2 重新开始(精确近似)。

    如前所述,有mbostock on Github 的实现。一世 将代码粘贴到此处,以防链接断开。这不是我自己的代码。

    var points = [[474,276],[586,393],[378,388],[338,323],[341,138],[547,252],[589,148],[346,227],[365,108],[562,62]];
    var width = 960,
        height = 500;
    var line = d3.svg.line()
        .interpolate("cardinal");
    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height);
    var path = svg.append("path")
        .datum(points)
        .attr("d", line);
    var line = svg.append("line");
    var circle = svg.append("circle")
        .attr("cx", -10)
        .attr("cy", -10)
        .attr("r", 3.5);
    svg.append("rect")
        .attr("width", width)
        .attr("height", height)
        .on("mousemove", mousemoved);
    // adding coordinates display
    var coords = svg.append("text");
    function mousemoved() {
      var m = d3.mouse(this),
          p = closestPoint(path.node(), m);
      line.attr("x1", p[0]).attr("y1", p[1]).attr("x2", m[0]).attr("y2", m[1]);
      circle.attr("cx", p[0]).attr("cy", p[1]);
      coords.attr("x", (p[0] + m[0]) / 2).attr("y", (p[1] + m[1]) / 2).html("Q(" + Math.round(p[0]) + ", " + Math.round(p[1]) + ")");
    }
    function closestPoint(pathNode, point) {
      var pathLength = pathNode.getTotalLength(),
          precision = 8,
          best,
          bestLength,
          bestDistance = Infinity;
      // linear scan for coarse approximation
      for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) {
        if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) {
          best = scan, bestLength = scanLength, bestDistance = scanDistance;
        }
      }
      // binary search for precise estimate
      precision /= 2;
      while (precision > 0.5) {
        var before,
            after,
            beforeLength,
            afterLength,
            beforeDistance,
            afterDistance;
        if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) {
          best = before, bestLength = beforeLength, bestDistance = beforeDistance;
        } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) {
          best = after, bestLength = afterLength, bestDistance = afterDistance;
        } else {
          precision /= 2;
        }
      }
      best = [best.x, best.y];
      best.distance = Math.sqrt(bestDistance);
      return best;
      function distance2(p) {
        var dx = p.x - point[0],
            dy = p.y - point[1];
        return dx * dx + dy * dy;
      }
    }
    .disclaimer{
      padding: 10px;
      border-left: 3px solid #ffcc00;
      background: #fffddd;
    }
    path {
      fill: none;
      stroke: #000;
      stroke-width: 1.5px;
    }
    line {
      fill: none;
      stroke: red;
      stroke-width: 1.5px;
    }
    circle {
      fill: red;
    }
    rect {
      fill: none;
      cursor: crosshair;
      pointer-events: all;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
    <div class="disclaimer">
      This is not my own code. This is made by <a href="https://gist.github.com/mbostock/8027637">mbostock on Github</a> based on Mike Kamermans <a href="https://pomax.github.io/bezierinfo/#projections">Primer on Bézier Curves online book</a>.
    </div>

    【讨论】:

    • 感谢您的链接,感谢@Mike'Pomax'Kamermans 提供这本很棒的在线图书。我很高兴我现在偶然发现了它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-11
    • 1970-01-01
    • 2018-03-10
    • 1970-01-01
    • 2014-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多