如何将任意线条投影到屏幕边缘
How can I project an arbitrary line to the edges of the screen?
我想做的是给任意两个点(在典型的屏幕坐标系中,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=%dn",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对这条线来说是正确的,但第二个点差了很多。
有一种概念上更简单的方法。调用点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)的一个坐标是显而易见的。要找到另一个,请代入相关的原始参数方程。
相关文章:
- UE4-如何在给定4个屏幕坐标的情况下缩放纹理或材质
- 如何在GTK程序运行时禁用屏幕保护程序/电源管理/屏幕消隐
- 使用 SFML 和 C++ 将 Pixel 打印到屏幕上
- 在 Windows 8/10 技术中完全实时的屏幕捕获,没有延迟
- Winapi:屏幕截图未显示在窗口中
- 如何获取边缘窗口句柄 (HWND)?
- 如何在快板的屏幕中显示子位图的绘制?
- 提升如何在图形可视化中写入边缘的权重?
- 在 c++ 中使用 Tensorflow Lite 在边缘 TPU 上运行"mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite"时出现问题
- 分数背包边缘箱
- 按回车键后输出屏幕关闭
- 要在屏幕上绘制一些小瓷砖,我应该使用 QQuickItem 还是 QQuickPaintedItem?
- 应用程序无法找到铬边缘浏览器
- SFML 向下移动时如何围绕屏幕中心旋转?
- 截取屏幕截图后程序卡住
- C++鼠标单击时的屏幕截图不起作用
- 屏幕插入运算符<<的运算符过载问题
- 难以使球从屏幕边缘反弹
- 我的精灵使用名为 ASGE 的C++框架卡在屏幕边缘
- 如何将任意线条投影到屏幕边缘