定义两个点的矩形背后的想法是什么?[关闭]


14

并不是说这没有道理,而是在99%的时间内效果都不好。

通常,在2D图形中,矩形是作为一对点进行初始化,存储和操作的。没有特别的语言,

class Rect:
   p1, p2: point

将矩形定义为两个x值和两个y值更有意义,如下所示:

class Rect
   xleft, xright: int
   ytop, ybottom: int

有两点,如果您想在源代码中的某个地方使用顶部的y值,则必须说rect.p1.y(hmmm,停下来想一想,是p1还是p2),但是使用四个值作为纯数据成员,就很清楚直接了:rect.ytop(无需思考!)使用两点意味着在处理垂直方向时,您必须纠结水平方向;独立元素之间存在无关紧要的关系。

两点想法是如何产生的,为什么会持续下去?它相对于裸露的x和y坐标有好处吗?

补充说明:此问题是在XY对齐矩形的背景下,例如在Windows管理器和GUI工具包中,而不是在绘图应用程序中的任意形状的背景下。


8
您是否使用Rects编写了大量代码?

6
矩形由两个点定义,因此将它们表示为两个点非常有意义。
亚当·克罗斯兰

2
矩形更自然地定义为x值范围和y值范围。
2010年

2
好问题!我本人从未考虑过,但是您提出了一个有趣的论点!FWIW,Windows也具有您所描述的RECT(上,左,下,右)
Dean Harding 2010年

3
如何定义具有两个点的矩形?是否假定没有旋转?
尼克·T

Answers:


8

您是否认为它不太容易出错?

如果使用(Point1,Point2),则清楚您指定的内容。如果提供2个点,则唯一可能的错误是,在构建点时,用户将x和y混合在一起,因为点的顺序无关紧要。

如果您提供4个整数,那么如果有人不注意,他们可能会在您需要(x1,y1,x2,y2)时提供(x1,x2,y1,y2),反之亦然。同样,某些API(例如WCF的Rect结构)将矩形定义为(x,y,width,height),这可能会导致(1、2、3、4)含义混乱。是(x,y,w,h)或(x1,y1,x2,y2)或(x1,x2,y1,y2)吗?

总而言之,(Point1,Point2)对我来说似乎更安全一些。


3
像Rect(xrange(x1,x2),yrange(y1,y2))这样的东西呢?这似乎是API使用安全性和优雅的终极选择。
DarenW,2010年

9

我一直喜欢将矩形定义为点+宽度和高度,其中该点是矩形的左上角。

class Rect {
  float x, y;
  float width, height;
}

然后添加获取其他指标所需的任何方法。像Java版本一样


4
是顶部y + height,y-height还是仅y?
卡梅隆·麦克法兰

2
@Cameron MacFarland:这取决于应用程序的坐标系,而这与低矩形无关。
乔恩·普迪

2
@Martin Wickman:使用2分有什么优势?
Kramii

@Kramii:一个优点是,如果要移动整个矩形,只需平移一个点。顺便说一句,您始终可以根据需要计算“缺失点”(cpu /内存权衡)。
马丁·威克曼

这也出现在现实生活中。我发现它很棘手,因为我对矩形所做的最常见操作之一就是测试是否包含点。绘图也很常见。在这两种情况下,都需要执行加法运算,这会困扰像我这样的高性能时钟周期计数器。
DarenW,2010年

7

实际上,重新定义不是由2点定义的。如果矩形与轴平行,则只能由两个点定义。

有几种表示平行于轴的矩形的方法:

  1. 两个对角相对的点
  2. 一个角点,高度和宽度
  3. 中心点,高度和宽度的一半(不常见,但有时很有用)。
  4. 作为两个X坐标和两个Y坐标

对于(1),许多库都使用约定来确定使用哪两个点-例如topLeft和bottomRight。

表示的选择可能是由矩形定义的原始目的决定的,但我认为它通常是任意的。这些表示形式在它们携带的信息中是等效的。但是,它们的区别在于计算矩形属性的难易程度和对矩形执行操作的便利性不同。

定义(1)相对于其他的好处包括:

  • API与其他多边形,线等的一致性
  • topLeft,bottomRight可以传递给任何接受点的方法
  • Point类的方法可以在topLeft,bottomRight上调用
  • 大多数属性可以很容易地导出,例如。bottomLeft,topRight,宽度,高度,中心,对角线长度等。

6

好吧p1: Point,无论如何他们p2: Point每个人都将拥有两个int坐标,所以您的课程不等于同一件事吗?

而且,如果您将这两点存储为一流的Point对象,难道您没有从它们那里得到更多的实用程序吗?在我所知道的大多数图形坐标系中,以这种方式将点子类化以创建对象的层次结构:point -> circle -> ellipse依此类推。

因此,如果创建的对象不使用Point该类,则该对象已与其他类层次结构分离。


1
我看到的OP表示法的优点是,如果您想知道矩形的y较低值,那么就知道它是“ ybottom”,其中与p1 / p2一样,您需要找出哪个值较低。除非您保证无论如何p1都将是较低的值。
杰森·维尔斯

1
的确,两种不同的结构都可以归结为四个坐标,而两点版本引入了一个无关的级别,该级别收集了一个x和一个y,而x与y的对应关系没有特别的理由。经过多年的图形编程,我认为这种额外的级别无法提供任何实用程序。
DarenW,2010年

1
@Jason:好点。但是,使用ytop/ ybottom方法,还需要在ybottom实际上低于的地方提供保证ytop
维利博士的学徒

或调用'em y1和y2,并使用min(y1,y2)和max(y1,y2)-当然,这比通过两个点p1,p2进行访问更麻烦。
DarenW,2010年

top / bottom的命名不会给您带来任何好处,因为除非您专门进行编码,否则什么都不会阻止bottomx <topx。我认为这只会增加混乱。
lkg

5

这就是为什么我喜欢Delphi's的原因TRect。它被定义为变体记录(C语言中的联合结构),可以解释为TopLeft和BottomRight点,或者解释Top,Left,Bottom和Right整数,以目前较为方便的形式解释。


1
是的,非常有用的功能。
2010年

4

当然,如果您将矩形定义为:

class Rect
{
    Point bottomLeft;
    Point topRight;
}

那么您马上就知道哪一点在哪。

更好的做法是添加额外的属性,使您可以使用应用程序所需的任何方式来操作矩形。这些将仅更新基础数据结构。

通过在形状上添加变换,您可以根据需要调整矩形的方向。您仍然需要轴对齐的边界框来进行快速接受/拒绝检查:)

但是,如果您的模型允许任何方向的矩形都无需应用变换,则“左下”和“右上”没有意义,这将导致“ p1”和“ p2”(或类似值)。


那么,将矩形旋转90度会发生什么?您是否正在跟踪与最初不同的两个点,或者您的“ topRight”现在位于“ bottomLeft”的左侧?
Inaimathi

@Inaimathi-如果添加变换矩阵,则可以使矩形与轴对齐。但是,它确实取决于您的应用程序。
克里斯·弗雷德(ChrisF)

2

我认为用x和y范围和一个点表示一个矩形更有意义;您甚至可以将位置点设为矩形的中心,因此它与旋转无关

但是将其编码为两点可能最简单!


两点编码怎么会更容易?
DarenW,2010年

@DaremW:典型的绘制矩形库函数将左上角和右下角点作为参数
Steven A. Lowe 2010年

但是,为什么要用这种方式设计这些API?除了不经意地模仿早期的库之外,就是这样。
2010年

@DarenW:我的猜测是图书馆使用Bresenham画线例程,该例程以两点作为输入并且非常有效
Steven A. Lowe 2010年

2

我不喜欢它,因为我们排除了潜在的自由度,这实际上允许任意旋转。普通的2D矩形具有五个未知数(自由度)。我们可以将它们指定为点的坐标,与该点形成顶点的两侧的长度以及与第一条线的水平线的角度(假定另一条线的角度大于90度)。也可以使用无数种其他可能性,但是必须指定五个独立的数量。有些选择会比其他选择更容易代数,这取决于对它们的选择。


5
重要的是要意识到“标准”矩形结构不是严格定义的数学矩形,而是始终与X轴和Y轴平行的简化版本,因为它被创建用于一个非常具体的事情:定义矩形区域对于窗口管理器,它们(几乎)始终平行于X和Y轴。
梅森惠勒2010年

1,左/右/顶/底结构被预分类,并因此具有较少的信息
哈维尔

好点,关于xy对齐的矩形。我想到了这一点,以及3D建模中使用的范围和其他一些东西,但所有xy(也许也为-z)都对齐了。
2010年

1

那与2分完全一样吗?尴尬如何...大多数绘图例程需要点,而不是单独的x / y组件。


1

将矩形定义为点对可让您将点重新用作其他形状的顶点。只是一个想法...


但是好像只玩了一半甲板,只保留两个点就可以定义一个四角形状。如果您碰巧需要左上角,那么酷,但是如果您需要右上角,则相对而言,您必须进行一些精美的数据获取。
2010年

如果有一个定义为AX点BY和BX点AY的访问器,它将使它在内存/磁盘上的重量减轻,我认为存储的顶点数量应为一半,并指向它们(取决于最大网格大小)。我以您的范围思想来了,但是您并没有花一半的时间,只是您没有在存储重复的数据……而其他需要说明的是内存限制是什么?所有互连代码中的重新实现意味着什么?
RobotHumans 2010年

而且由于不必进行任何“工作”即可将前两个顶点从内存中取出,因此速度可能会更快
RobotHumans 2010年

1

我相信主要是在所有形状图元之间建立统一性。

当然,您可以通过许多不同的方式定义矩形,但是如何以可以使用类似数据结构的方式定义三角形,星形或圆形?

所有多边形都可以由其点定义,只需很少的逻辑即可确定如何处理这些点。

图形库主要根据顶点和边缘在这些多边形上进行操作,因此,点和它们之间的线,所有计算都基于这两个要素(分别是面和面)进行,但其本身只是边的函数。


1

在二维中,将矩形存储为两个点比定义特定的角以及宽度和高度更清晰-考虑负宽度或高度,或者确定彼此之间的每个选项所需的计算。

在由点定义的矩形上执行旋转也比用点加上宽度和高度定义的矩形简单得多。

我希望封装使这种区分作为类的用户变得不重要。

矩形应定义为三个点,以便在3维中很好地定义。我不确定要定义4个或更多尺寸的矩形的要求。


1

这是完全任意的。您需要四项信息才能绘制一个矩形。库设计人员决定用两个点来表示它(每个点都有一个xy坐标),但是可以很容易地用x / y / w / h或top / bottom / left / right来表示它。

我认为OP的真正问题是:为什么要做出这个特定选择?


1

参数的选择仅对低级设计人员/编码人员重要。

高级用户只需要考虑以下几点:

  • IsPointInRect
  • 区域
  • 相交(或修剪)
  • HasOverlap(与Intersection.Area> 0相同)
  • 联合(成为矩形列表)
  • 减法(代表在矩形A中但不在矩形B中的相同点集的矩形列表)
  • 转变
    • X和Y的移位
    • 旋转(0、90、180、270)
    • X和Y缩放(请参阅注释)
  • 属性Xmin,Xmax,Ymin,Ymax,Width,Height的简单语法,因此用户不需要知道参数的确切选择。

注意:为了最大程度地减少缩放变换期间的精度损失,有时适合实施第二个使用浮点坐标的Rect类,以便可以将中间结果准确地存储在一系列变换中,并且仅在四舍五入时将其舍入为整数。最后一步。


0

正如@Steven所说,我认为应该以一个(x,y)点和一个(w,h)大小的向量表示。那是因为很容易陷入歧义。假设您有以下从(0,0)点开始的填充矩形。

  012
0 XXX
1 XXX
2 XXX

显然,它的宽度,高度是(3,3),但是第二点是什么呢?是(2,2)还是(3,3)?

这种歧义会引起各种问题。

我艰难地年前了解到,这是更好地认为图形坐标为各行之间的像素,而不是行的像素。这样就不会有歧义。


2
Mac上原始的QuickDraw例程(1980年代的例程)使用的数学模型中的点无限小。屏幕上的点位于像素之间。因此,从(3,5)到(10,5)绘制的线的长度为7,占据7个像素。在今天的坐标,这条线将有8的长度
巴里·布朗

@Barry:这是有道理的,因为它经常使用XOR,并且如果将线串在一起,则希望它们在连接时不会丢失像素。考虑到两个坐标系,我实际上发表了有关填充多边形的Siggraph论文。
Mike Dunlavey 2010年

0
Pa(x,y)*-----------------------------------*Pb(x,y)
       |                                   |
       |                                   |
       |                                   |
       |                                   |
       |                                   |
       |                                   |
Pc(x,y)*-----------------------------------*Pd(x,y)

我们可以同时定义Pb和Pc:

铅(Pd(x),Pa(y))

Pc(Pa(x),Pd(y))

因此,由于对称性,无需定义所有四个点

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.