【问题标题】:Find rightmost/leftmost point of SVG path查找 SVG 路径的最右/最左点
【发布时间】:2017-04-13 08:51:41
【问题描述】:

如何找到 SVG C(贝塞尔曲线)路径段的最左/最右 ?我知道有 getBoundingClientRect()getBBox() 但它们都不适用,因为它们只返回点的单个坐标。


只是为了避免 XY 问题 - 我想将由贝塞尔曲线组成的单个路径拆分为多个路径,每个路径都单调地从左到右(或从右到左)。这意味着在任何一条路径上都不应有两个 X 坐标相等的点。我知道所需的分割点可能段的边界框内,因此不是最左/最右,但我几乎可以肯定找到这样的点的方法应该使用与找到水平极端相同的技术点。

【问题讨论】:

  • getBBpox(0 返回“单点”是什么意思? getBBox() 返回路径的边界框。最左边的点应该是bbox.x,最右边的应该是bbox.x + bbox.width。这是你想要的吗?
  • getBBox 可以让我知道x 目标点的坐标,但不能告诉我y。这就是我所说的仅单一坐标的意思。

标签: svg bounding-box bezier


【解决方案1】:

您需要使用.getPointAtLength(i) 方法遍历路径长度,然后找到限制。看起来很有趣,所以我做了一个快速而肮脏的实现,这是重要的部分:

function findLimits(path) {

  var boundingPoints = {
    minX: {x: dimensions.width, y: dimensions.height},
    minY: {x: dimensions.width, y: dimensions.height},
    maxX: {x: 0, y: 0},
    maxY: {x: 0, y: 0}
  }
  var l = path.getTotalLength();
  for (var p = 0; p < l; p++) {
    var coords = path.getPointAtLength(p);
    if (coords.x < boundingPoints.minX.x) boundingPoints.minX = coords;
    if (coords.y < boundingPoints.minY.y) boundingPoints.minY = coords;
    if (coords.x > boundingPoints.maxX.x) boundingPoints.maxX = coords;
    if (coords.y > boundingPoints.maxY.y) boundingPoints.maxY = coords;
  }
  return boundingPoints
}

你可以在这里找到实现:https://jsfiddle.net/4gus3hks/1/

【讨论】:

  • 这具有线性 O(length) 性能。有什么方法可以更快地做到这一点,或者一些开箱即用的例行程序?
  • 查看这个问题以获得数学解决方案而不是迭代解决方案。 stackoverflow.com/questions/24809978/…
【解决方案2】:

Paul LeBeau 在the wiki 上的评论和精美的动画启发了我的解决方案。它主要基于以下术语:

  • 来自[0, 1] 的参数t 的值可以与曲线匹配 分。

  • 对于曲线上的任意参数值点都可以构造 通过线性组合相邻控制点对逐步进行 进入更高“深度”的中间控制点。这个操作 可以重复直到只剩下一个点 - 曲线上的点 自己。

  • 中间点的坐标可以定义为 t-度数多项式等于点“深度”。和系数 这些多项式最终仅取决于初始坐标 控制点。

  • 构造的倒数第二步给出了定义切线的 2 个点 到最后一点的曲线,这些点的坐标是 由二次多项式控制。

  • 有问题的切线方向作为 vector 允许 针对需要曲线的t 构造二次方程 切线。

所以,其实找到需要的点可以在常量O(1)时间进行:

  tangentPoints: function(tx, ty){
    var ends = this.getPolynoms(2);
    var tangent = [ends[1][0].subtractPoly(ends[0][0]),
                   ends[1][1].subtractPoly(ends[0][1])];
    var eq = tangent[0].multiplyScalar(ty).subtractPoly(tangent[1].multiplyScalar(tx));
    return solveQuadratic(...eq.values).filter(t => t >= 0 && t <= 1);
  }

带有辅助Polynom 类和可视演示的完整代码我放入this repofiddle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多