我希望能够做到的任何两点(在典型的屏幕坐标系中,X向右增加,Y增加向下)并返回两点,如果该线延长它会碰到屏幕的边缘。我在这里尝试的方法是首先将点转换为象限1(其中Y向上增加),然后计算线的y截距。如果它在屏幕上,则使用0 X值。如果它不在屏幕上,那么该线必须首先穿过X轴...所以在这种情况下Y将是0而x是x截距。然后我将所有点转换为象限3并做同样的事情。然后,同样的程序应返回我的另一端的点。
代码似乎在象限1中起作用,但对象限3返回奇怪的结果。任何想法?
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
float _line_slope( int x1, int y1, int x2, int y2 )
{
return ((float)(y1-y2)) / ((float)(x1-x2));
}
float _y_intercept( float m, int x, int y )
{
// y = mx + b
float mx = m * x;
// we need to get b by itself, so if mx is positive we need to subtract it from y,
// if its negative we need to add it to y
return (mx > 0.0) ? (float)y - mx : (float)y + mx;
}
float _x_intercept( float m, float b )
{
return -b / m;
}
void _screen_to_quad1( uint32_t w, uint32_t h, int& x, int& y )
{
y = (h - y);
}
void _quad1_to_screen( uint32_t w, uint32_t h, int& x, int& y )
{
y = (h - y);
}
void _screen_to_quad3( uint32_t w, uint32_t h, int& x, int& y )
{
x = (x - w);
y = -y;
}
void _quad3_to_screen( uint32_t w, uint32_t h, int& x, int& y )
{
x = (x + w);
y = abs(y);
}
struct point { int x; int y; };
void _sort_points( int x1, int y1, int x2, int y2, struct point& a, struct point& b )
{
if( x1 < x2 )
{
a.x = x1; a.y = y1;
b.x = x2; b.y = y2;
}
else
{
a.x = x2; a.y = y2;
b.x = x1; b.y = y1;
}
}
void _project_line( uint32_t w, uint32_t h, int x1, int y1, int x2, int y2, int& ox1, int& oy1, int& ox2, int& oy2 )
{
struct point a, b;
_sort_points( x1, y1, x2, y2, a, b );
_screen_to_quad1( w, h, a.x, a.y );
_screen_to_quad1( w, h, b.x, b.y );
{
float slope = _line_slope( a.x, a.y, b.x, b.y );
float yint = _y_intercept( slope, a.x, a.y );
if( yint >= 0 && yint < h )
{
ox1 = 0;
oy1 = yint;
}
else
{
ox1 = _x_intercept( slope, yint );
oy1 = 0;
}
}
_quad1_to_screen( w, h, a.x, a.y );
_quad1_to_screen( w, h, b.x, b.y );
_quad1_to_screen( w, h, ox1, oy1 );
_screen_to_quad3( w, h, a.x, a.y );
_screen_to_quad3( w, h, b.x, b.y );
{
float slope = _line_slope( a.x, a.y, b.x, b.y );
float yint = _y_intercept( slope, a.x, a.y );
if( yint > -(int)h && yint < 0 )
{
ox2 = 0;
oy2 = yint;
}
else
{
ox2 = _x_intercept( slope, yint );
oy2 = 0;
}
}
_quad3_to_screen( w, h, a.x, a.y );
_quad3_to_screen( w, h, b.x, b.y );
_quad3_to_screen( w, h, ox2, oy2 );
printf("ox1=%d, oy1=%d, ox2=%d, oy2=%d\n",ox1,oy1,ox2,oy2);
}
int main( int argc, char* argv[] )
{
int ox1, oy1, ox2, oy2;
_project_line( 640, 480, 30, 50, 70, 20, ox1, oy1, ox2, oy2 );
return 0;
}
以下是ideone上的链接:http://ideone.com/LaejBy
输出如下:
ox1 = 0,oy1 = 73,ox2 = 1316,oy2 = 0
第一个点看起来没问题,第二个点的y对于这一行是正确的,但是第二个点X是偏离的。
答案 0 :(得分:1)
这是一种概念上更简单的方法。调用点A和B.使用参数形式:
x = xA + t(xB - xA)
y = yA + t(yB - yA)
现在通过求解x方程找到线条触及左右边界xL和xR的t值
tL = (xL - xA) / (xB - xA)
tR = (xR - xA) / (xB - xA)
如果线是垂直的,请跳过此计算。
然后使用y等式对顶部和底部执行相同的操作:
tB = (yB - yA) / (yB - yA)
tT = (yT - yA) / (yB - yA)
如果线条是水平线,请跳过此处。
现在从4个值tL,tR,tB,tT(如果输入是水平或垂直,则为2),一半的值将为负值,一半为正值(为什么?)。在每种情况下选择最小的绝对值。这将直接告诉您交叉点的边界:左,右,底,顶部基于相应的t值。由此,每个交叉点(x或y)的一个坐标是显而易见的。要找到另一个,请用相关的原始参数方程代替。