[译]齐次坐标系

在欧氏几何中,两条平行线永远不会相交。但在透视几何中,这种现象却成为可能。通过引入齐次坐标的概念,数学家们解决了这一难题,并为计算机图形学的发展奠定了基础。本文将解释如何在齐次坐标系中表示无限远处的点,以及如何证明平行线在该坐标系中可以相交。

原文地址

问题:两条平行直线可以相交

在欧氏几何中,同一平面的两条直线是不可能相交的,这是大家都熟悉的常识。

铁路

但是,在一个透视空间中,这是不正确的。
上图的铁路随着距离我们的视线越来越远,它们变得越狭长。最终,视线中的两条平行线在无限远处的一点相交了。

欧式几何非常适合描述我们的2D/3D几何空间,但是不足以来描述透视空间了。(实际上,欧式几何是透视几何的子集)。在笛卡尔坐标系中,一个二维坐标可以用 (x,y) 标志。

那么当点位于无线远的位置该怎么办?无限远处的点可以是 (,) ,这在欧式几何空间中是没有意义的。在透视空间中,平行的直线在无限远处会相交,这在欧式及几何中是不可能的。数学家发现了一种解决这个问题的方法。

齐次坐标系

奥古斯特 费迪南德 莫比乌斯,发明了齐次坐标系,使得在透视空间中对图形和几何的计算成为了可能。
齐次裁剪空间使用N+1个数字描述N维空间的方法。

对于二维的齐次坐标系,我们使用额外的 w 值加入到我们现存的坐标系中。这样,笛卡尔坐标系中的 (X,Y) 在齐次坐标系下可以表示为 (x,y,w) ,其中, X,Y,x,y,w 满足下列公式:

X=x/w

Y=y/w

举例来说,笛卡尔坐标系下的 (1,2) 在齐次坐标系下表示为 (1,2,1) 。如果点 (1,2) 移向了无穷远远处,在笛卡尔坐标系下是 (,) ,在齐次坐标系下是 (1,2,0) ,这是因为:

(1/0,2/0)(,)
,注意,我们可以使用 来描述一个无穷远处的点。

为何命名为齐次的?

正如之前所提到的,为了将齐次坐标系 (x,y,w) 转换为笛卡尔坐标系,我们仅仅用 w 去除x,y
从这个过程中我们可以发现一个重要的事实,让我们好好观察接下来的例子。

(1,2,3)=>(1/3,2/3)

(2,4,6)=>(2/6,4/6)=>(1/3,2/3)

(3,6,9)=>(3/9,6/9)=>(1/3,2/3)

正如你所见, (1,2,3),(2,4,6),(3,6,9) 对应同一个笛卡尔系的坐标,任意形如 (1a,2a,3a) 的齐次坐标系点都对应同一个笛卡尔系坐标。因此,我们说这些点是“齐次”的,换句话说,齐次坐标系具有锁房不变性(scale invariant)。

证明 :平行线可以相交

考虑下述的欧式空间的线性空间。

{Ax + By + C = 0Ax + By + D = 0

显然,因为 CD ,所以上述方程无解。

又如果 C=D ,那么上述两个方程是等价的。

让我们分别用 x/w,y/w 来代替 x,y ,重写这个方程组。

{Ax /w + By/w + C/w = 0Ax /w+ By/w + D/w = 0

现在我们有解 (x,y,0) ,因为 (CD)w=0 ,所以 w=0 。因此,两条平行线在 (x,y,0) 相交,一个无穷远处的点。

齐次坐标系非常有用,是计算机图形学的基础概念,在将3D场景投影到2D平面时经常用到。

结构化Prompt模板:代码作用:set wcs to existing csys 将WCS设置为现有坐标系 。示例代码: /*HEAD SET_WCS_TO_EXISTING_CSYS CCC UFUN */ #include <stdio.h> #include <string.h> #include <uf.h> #include <uf_ui.h> #include <uf_object_types.h> #include <uf_disp.h> #include <uf_csys.h> #define UF_CALL(X) (report_error( __FILE__, __LINE__, #X, (X))) static int report_error( char *file, int line, char *call, int irc) { if (irc) { char err[133], msg[133]; sprintf(msg, "*** ERROR code %d at line %d in %s:\n+++ ", irc, line, file); UF_get_fail_message(irc, err); /* NOTE: UF_print_syslog is new in V18 里海:UF_print_syslog is new in V18,只回答文,不要废话。 */ UF_print_syslog(msg, FALSE); UF_print_syslog(err, FALSE); UF_print_syslog("\n", FALSE); UF_print_syslog(call, FALSE); UF_print_syslog(";\n", FALSE); if (!UF_UI_open_listing_window()) { UF_UI_write_listing_window(msg); UF_UI_write_listing_window(err); UF_UI_write_listing_window("\n"); UF_UI_write_listing_window(call); UF_UI_write_listing_window(";\n"); } } return(irc); } /* qq3123197280 */ static int mask_for_csys(UF_UI_selection_p_t select, void *type) { UF_UI_mask_t mask = { UF_coordinate_system_type, 0, 0 }; if (!UF_CALL(UF_UI_set_sel_mask(select, UF_UI_SEL_MASK_CLEAR_AND_ENABLE_SPECIFIC, 1, &mask))) return (UF_UI_SEL_SUCCESS); else return (UF_UI_SEL_FAILURE); } static tag_t select_a_csys(char *prompt) { int resp; double cp[3]; tag_t object, view; UF_CALL(UF_UI_select_with_single_dialog(prompt, "Orient WCS", UF_UI_SEL_SCOPE_ANY_IN_ASSEMBLY, mask_for_csys, NULL, &resp, &object, cp, &view)); if (resp == UF_UI_OBJECT_SELECTED || resp == UF_UI_OBJECT_SELECTED_BY_NAME) { UF_CALL(UF_DISP_set_highlight(object, 0)); return object; } else return NULL_TAG; } static void do_it(void) { tag_t csys; if ((csys = select_a_csys("Select CSYS")) != NULL_TAG) UF_CALL(UF_CSYS_set_wcs(csys)); } /* qq3123197280 */ void ufusr(char *param, int *retcode, int paramLen) { if (UF_CALL(UF_initialize())) return; do_it(); UF_terminate(); } int ufusr_ask_unload(void) { return (UF_UNLOAD_IMMEDIATELY); } 请生成1个NX / UG API技术问题,格式:"如何通过NX/UG API实现[具体功能]?",需提取所有核心代码生成一个函数,进行代码说明 / 注意事项/问题拓展。
最新发布
03-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值