找到 SVG 路径的 rightmost/leftmost 点
Find rightmost/leftmost point of SVG path
如何找到SVG C(贝塞尔曲线)路径段的leftmost/rightmost点?我知道有 getBoundingClientRect()
和 getBBox()
但其中 none 适用,因为它们 return 只有点的单个坐标。
只是为了避免 XY 问题 - 我想将由贝塞尔曲线组成的单个路径分成几条路径,每条路径单调地从左到右(或从右到左)。这意味着在任何一条路径上都不应该有两个 X 坐标相等的点。我知道所需的分割点可能在 内部 段的边界框因此不是 leftmost/rightmost,但我几乎可以肯定找到这样的点的方法应该使用相同的寻找水平极值点的技术。
您需要使用 .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/
Paul LeBeau 在 the wiki 上的评论和精美的动画启发了我的解决方案。它主要基于以下术语:
来自[0, 1]
的参数t
的值可以匹配到曲线
点.
对于曲线上的任意参数值点都可以构造
通过线性组合成对的相邻控制点逐步
进入更高 "depth" 的中间控制点。这个操作
可以重复直到只剩下一个点 - 曲线上的点
本身。
中间点的坐标可以定义为
t
-次数等于点 "depth" 的多项式。和系数
这些多项式最终仅取决于初始坐标
控制点.
构造的倒数第二步给出了定义切线的 2 个点
到曲线的终点,这些点的坐标是
由二次多项式控制。
将所讨论的切线方向设为 向量 允许
根据 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);
}
如何找到SVG C(贝塞尔曲线)路径段的leftmost/rightmost点?我知道有 getBoundingClientRect()
和 getBBox()
但其中 none 适用,因为它们 return 只有点的单个坐标。
只是为了避免 XY 问题 - 我想将由贝塞尔曲线组成的单个路径分成几条路径,每条路径单调地从左到右(或从右到左)。这意味着在任何一条路径上都不应该有两个 X 坐标相等的点。我知道所需的分割点可能在 内部 段的边界框因此不是 leftmost/rightmost,但我几乎可以肯定找到这样的点的方法应该使用相同的寻找水平极值点的技术。
您需要使用 .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/
Paul LeBeau 在 the wiki 上的评论和精美的动画启发了我的解决方案。它主要基于以下术语:
来自
[0, 1]
的参数t
的值可以匹配到曲线 点.对于曲线上的任意参数值点都可以构造 通过线性组合成对的相邻控制点逐步 进入更高 "depth" 的中间控制点。这个操作 可以重复直到只剩下一个点 - 曲线上的点 本身。
中间点的坐标可以定义为
t
-次数等于点 "depth" 的多项式。和系数 这些多项式最终仅取决于初始坐标 控制点.构造的倒数第二步给出了定义切线的 2 个点 到曲线的终点,这些点的坐标是 由二次多项式控制。
将所讨论的切线方向设为 向量 允许 根据
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);
}