给定两个点 (x1,y1) (x2,y2),我如何计算 N 个不同的点均匀地位于给定点之间的线上
Given two points (x1,y1) (x2,y2), how can I compute N different points evenly lying on the line between the given points
我有两个点,我想在给定线创建的线的顶部计算 n 个均匀分布的点。我如何在 C++ 中执行此操作?
您可以使用以下 give_uniform_points_between(M, N, num_points)
,它给出 M
和 N
之间的 #num_points
个点数。我在这里假设这条线不是垂直的(如果这条线可以垂直,请看下面)。
std::vector<Point> give_uniform_points_between(const Point& M, const Point& N, const unsigned num_points) {
std::vector<Point> result;
// get equation y = ax + b
float a = (N.y - M.y) / (N.x - M.x);
float b = N.y - a * N.x;
float step = std::fabs(M.x - N.x) / num_points;
for (float x = std::min(M.x, N.x); x < std::max(M.x, N.x); x += step) {
float y = a*x+b;
result.push_back(Point{x,y});
}
return result;
}
结果是:
(-3,9);(-2.3,7.6);(-1.6,6.2);(-0.9,4.8);(-0.2,3.4);(0.5,2);(1.2,0.6);(1.9,-0.8);(2.6,-2.2);(3.3,-3.6);
说明
从(x1,y1)
和(x2,y2)
两点可以猜出通过这两个点的直线方程。
这个等式采用 a*x + b*y + c = 0
的形式,如果不能有垂直线,则直接采用 y = a*x + b
的形式
其中 a = (y2 - y1) / (x2 - x1)
并且您推断 b 如代码所示。
然后你可以沿着你的线从具有最小值坐标的点开始改变 x
或 y
。
你找到的所有这些 (x,y)
点都在你的线上并且应该均匀分布(感谢固定的 step
)。
将直线视为 (x1,y1) + λ(x2-x1,y2-y1),即第一个点,加上它们之间向量的倍数。
当 λ=0 时你有第一个点,当 λ=1 时你有第二个点。
所以你只想取 0 到 1 之间的 n 个均匀分布的 λ 值。
如何做到这一点取决于您所说的介于两者之间的含义:是否包括端点?
例如,您可以取 λ=0/(n-1), λ=1/(n-1), λ=2/(n-1), ... λ=(n-1) /(n-1)。
这将给出 n 个均匀分布的点,包括端点。
或者您可以取 λ=1/(n+1), λ=2/(n+1), ... λ=n/(n+1)。
这将给出 n 个均匀分布的点,不包括端点。
Linear interpolation(图形社区亲切地称为 lerp)就是您想要的。给定端点,它可以使用参数 t
.
生成介于两者之间的点
设终点为A (Ax, Ay)
和B (Bx, By)
。从 A
到 B
的向量将由
给出
V = B − A = <Vx, Vy>
L(t) = A + tV
这本质上意味着从点A
开始,我们用标量t
缩放向量V
;点 A
被这个缩放向量取代,因此我们得到的点取决于参数 t
的值。当t = 0
时,我们返回A
,如果t = 1
,我们得到B
,如果是0.5
,我们得到A
和[之间的中间点=20=].
line A----|----|----|----B
t 0 ¼ ½ ¾ 1
它适用于任何线(斜率无关紧要)。现在解决 N
停止的问题。如果您需要 N
为 10,那么 t
会因 1/N
而异,因此 t = i/10
,其中 i
将是循环迭代器。
i = 0, t = 0
i = 1, t = 0.1
i = 2, t = 0.2
⋮
i = 9, t = 0.9
i = 10, t = 1.0
这是一种实现方法:
#include <iostream>
struct Point {
float x, y;
};
Point operator+ (Point const &pt1, Point const &pt2) {
return { pt1.x + pt2.x, pt1.y + pt2.y };
}
Point operator- (Point const &pt1, Point const &pt2) {
return { pt1.x - pt2.x, pt1.y - pt2.y };
}
Point scale(Point const &pt, float t) {
return { pt.x * t, pt.y * t };
}
std::ostream& operator<<(std::ostream &os, Point const &pt) {
return os << '(' << pt.x << ", " << pt.y << ')';
}
void lerp(Point const &pt1, Point const &pt2, float stops) {
Point const v = pt2 - pt1;
float t = 0.0f;
for (float i = 0.0f; i <= stops; ++i) {
t = i / stops;
Point const p = pt1 + scale(v, t);
std::cout << p << '\n';
}
}
int main() {
lerp({0.0, 0.0}, {5.0f, 5.0f}, 5.0f);
}
输出
(0, 0)
(1, 1)
(2, 2)
(3, 3)
(4, 4)
(5, 5)
放在一边
请注意,在每次迭代中 t
都会递增 Δt = 1 / N
。因此,另一种在循环中更新 t
的方法是
t₀ = 0
t₁ = t₀ + Δt
t₂ = t₁ + Δt
⋮
t₉ = t₈ + Δt
t₁₀ = t₉ + Δt
但是,这不是很可并行化,因为循环的每次迭代都取决于前一次迭代。
虽然没有那么多数学...
vector<Rect> Utils::createReactsOnLine(Point pt1, Point pt2, int numRects, int height, int width){
float x1 = pt1.x;
float y1 = pt1.y;
float x2 = pt2.x;
float y2 = pt2.y;
float x_range = std::abs(x2 - x1);
float y_range = std::abs(y2 - y1);
// Find center points of rects on the line
float x_step_size = x_range / (float)(numRects-1);
float y_step_size = y_range / (float)(numRects-1);
float x_min = std::min(x1,x2);
float y_min = std::min(x1,x2);
float x_max = std::max(x1,x2);
float y_max = std::max(x1,x2);
cout << numRects << endl;
float next_x = x1;
float next_y = y1;
cout << "Next x, y: "<< next_x << "," << next_y << endl;
for(int i = 0; i < numRects-1; i++){
if (x1 < x2)
next_x = next_x + x_step_size;
else
next_x = next_x - x_step_size;
if (y1 < y2)
next_y = next_y + y_step_size;
else
next_y = next_y - y_step_size;
cout << "Next x, y: "<< next_x << "," << next_y << endl;
}
return vector<Rect>();
}
我有两个点,我想在给定线创建的线的顶部计算 n 个均匀分布的点。我如何在 C++ 中执行此操作?
您可以使用以下 give_uniform_points_between(M, N, num_points)
,它给出 M
和 N
之间的 #num_points
个点数。我在这里假设这条线不是垂直的(如果这条线可以垂直,请看下面)。
std::vector<Point> give_uniform_points_between(const Point& M, const Point& N, const unsigned num_points) {
std::vector<Point> result;
// get equation y = ax + b
float a = (N.y - M.y) / (N.x - M.x);
float b = N.y - a * N.x;
float step = std::fabs(M.x - N.x) / num_points;
for (float x = std::min(M.x, N.x); x < std::max(M.x, N.x); x += step) {
float y = a*x+b;
result.push_back(Point{x,y});
}
return result;
}
结果是:
(-3,9);(-2.3,7.6);(-1.6,6.2);(-0.9,4.8);(-0.2,3.4);(0.5,2);(1.2,0.6);(1.9,-0.8);(2.6,-2.2);(3.3,-3.6);
说明
从(x1,y1)
和(x2,y2)
两点可以猜出通过这两个点的直线方程。
这个等式采用 a*x + b*y + c = 0
的形式,如果不能有垂直线,则直接采用 y = a*x + b
的形式
其中 a = (y2 - y1) / (x2 - x1)
并且您推断 b 如代码所示。
然后你可以沿着你的线从具有最小值坐标的点开始改变 x
或 y
。
你找到的所有这些 (x,y)
点都在你的线上并且应该均匀分布(感谢固定的 step
)。
将直线视为 (x1,y1) + λ(x2-x1,y2-y1),即第一个点,加上它们之间向量的倍数。
当 λ=0 时你有第一个点,当 λ=1 时你有第二个点。 所以你只想取 0 到 1 之间的 n 个均匀分布的 λ 值。
如何做到这一点取决于您所说的介于两者之间的含义:是否包括端点?
例如,您可以取 λ=0/(n-1), λ=1/(n-1), λ=2/(n-1), ... λ=(n-1) /(n-1)。 这将给出 n 个均匀分布的点,包括端点。
或者您可以取 λ=1/(n+1), λ=2/(n+1), ... λ=n/(n+1)。 这将给出 n 个均匀分布的点,不包括端点。
Linear interpolation(图形社区亲切地称为 lerp)就是您想要的。给定端点,它可以使用参数 t
.
设终点为A (Ax, Ay)
和B (Bx, By)
。从 A
到 B
的向量将由
V = B − A = <Vx, Vy>
L(t) = A + tV
这本质上意味着从点A
开始,我们用标量t
缩放向量V
;点 A
被这个缩放向量取代,因此我们得到的点取决于参数 t
的值。当t = 0
时,我们返回A
,如果t = 1
,我们得到B
,如果是0.5
,我们得到A
和[之间的中间点=20=].
line A----|----|----|----B
t 0 ¼ ½ ¾ 1
它适用于任何线(斜率无关紧要)。现在解决 N
停止的问题。如果您需要 N
为 10,那么 t
会因 1/N
而异,因此 t = i/10
,其中 i
将是循环迭代器。
i = 0, t = 0
i = 1, t = 0.1
i = 2, t = 0.2
⋮
i = 9, t = 0.9
i = 10, t = 1.0
这是一种实现方法:
#include <iostream>
struct Point {
float x, y;
};
Point operator+ (Point const &pt1, Point const &pt2) {
return { pt1.x + pt2.x, pt1.y + pt2.y };
}
Point operator- (Point const &pt1, Point const &pt2) {
return { pt1.x - pt2.x, pt1.y - pt2.y };
}
Point scale(Point const &pt, float t) {
return { pt.x * t, pt.y * t };
}
std::ostream& operator<<(std::ostream &os, Point const &pt) {
return os << '(' << pt.x << ", " << pt.y << ')';
}
void lerp(Point const &pt1, Point const &pt2, float stops) {
Point const v = pt2 - pt1;
float t = 0.0f;
for (float i = 0.0f; i <= stops; ++i) {
t = i / stops;
Point const p = pt1 + scale(v, t);
std::cout << p << '\n';
}
}
int main() {
lerp({0.0, 0.0}, {5.0f, 5.0f}, 5.0f);
}
输出
(0, 0)
(1, 1)
(2, 2)
(3, 3)
(4, 4)
(5, 5)
放在一边
请注意,在每次迭代中 t
都会递增 Δt = 1 / N
。因此,另一种在循环中更新 t
的方法是
t₀ = 0
t₁ = t₀ + Δt
t₂ = t₁ + Δt
⋮
t₉ = t₈ + Δt
t₁₀ = t₉ + Δt
但是,这不是很可并行化,因为循环的每次迭代都取决于前一次迭代。
虽然没有那么多数学...
vector<Rect> Utils::createReactsOnLine(Point pt1, Point pt2, int numRects, int height, int width){
float x1 = pt1.x;
float y1 = pt1.y;
float x2 = pt2.x;
float y2 = pt2.y;
float x_range = std::abs(x2 - x1);
float y_range = std::abs(y2 - y1);
// Find center points of rects on the line
float x_step_size = x_range / (float)(numRects-1);
float y_step_size = y_range / (float)(numRects-1);
float x_min = std::min(x1,x2);
float y_min = std::min(x1,x2);
float x_max = std::max(x1,x2);
float y_max = std::max(x1,x2);
cout << numRects << endl;
float next_x = x1;
float next_y = y1;
cout << "Next x, y: "<< next_x << "," << next_y << endl;
for(int i = 0; i < numRects-1; i++){
if (x1 < x2)
next_x = next_x + x_step_size;
else
next_x = next_x - x_step_size;
if (y1 < y2)
next_y = next_y + y_step_size;
else
next_y = next_y - y_step_size;
cout << "Next x, y: "<< next_x << "," << next_y << endl;
}
return vector<Rect>();
}