几何函数和操作符
=================


几何类型point, box, lseg, line, path, polygon, circle 有许多内置函数和操作符支持,在 **表.几何操作符** , **表.几何函数** 和 **表.几何类型转换函数** 中展示。

.. caution:: 请注意"相同"操作符~=表示point,box, polygon,circle类型在一般意义上相同。 这些类型有些还有一个=操作符,不过它只是比较相同的 **面积** 。 其它的标量比较操作符(<=等)也是为这些类型比较面积。

**表.几何操作符**


.. list-table::
    :widths: auto
    :header-rows: 1

    * - 操作符
      - 描述
      - 例子
    * - \+
      - 平移
      - box '((0,0),(1,1))' + point '(2.0,0)'
    * - \-
      - 平移
      - box '((0,0),(1,1))' - point '(2.0,0)'
    * - \*
      - 伸缩/旋转
      - box '((0,0),(1,1))' * point '(2.0,0)'
    * - \/
      - 伸缩/旋转
      - box '((0,0),(2,2))' / point '(2.0,0)'
    * - \@-@
      - 长度或者周长
      - @-@ path '((0,0),(1,0))'
    * - \@@
      - 中心
      - @@ circle '((0,0),10)'
    * - \##
      - 第一个操作数相对第二个操作数的最近点
      - point '(0,0)' ## lseg '((2,0),(0,2))'
    * - \<->
      - 间距
      - circle '((0,0),1)' <-> circle '((5,0),1)'
    * - \&&
      - 重叠?
      - box '((0,0),(1,1))' && box '((0,0),(2,2))'
    * - \<<
      - 是否严格在左?
      - circle '((0,0),1)' << circle '((5,0),1)'
    * - \>>
      - 是否严格在右?
      - circle '((5,0),1)' >> circle '((0,0),1)'
    * - \&<
      - 是否没有延伸到右边?
      - box '((0,0),(1,1))' &< box '((0,0),(2,2))'
    * - \&>
      - 是否没有延伸到左边?
      - box '((0,0),(3,3))' &> box '((0,0),(2,2))'
    * - \<<|
      - 是否严格在下?
      - box '((0,0),(3,3))' <<| box '((3,4),(5,5))'
    * - \|>>
      - 是否严格在上?
      - box '((3,4),(5,5))' \|>> box '((0,0),(3,3))'
    * - \&<|
      - 是否延伸到上面?
      - box '((0,0),(1,1))' &<| box '((0,0),(2,2))'
    * - \|&>
      - 是否延伸到下面?
      - box '((0,0),(3,3))' \|&> box '((0,0),(2,2))'
    * - \?#
      - 相交?
      - lseg '((-1,0),(1,0))' ?# box '((-2,-2),(2,2))'
    * - \?-
      - 水平?
      - ?- lseg '((-1,0),(1,0))'
    * - \?-
      - 水平对齐?
      - point '(1,0)' ?- point '(0,0)'
    * - \?|
      - 竖直?
      - ?| lseg '((-1,0),(1,0))'
    * - \?|
      - 竖直对齐?
      - point '(0,1)' ?| point '(0,0)'
    * - \?-|
      - 垂直?
      - lseg '((0,0),(0,1))' ?-| lseg '((0,0),(1,0))'
    * - \?||
      - 平行?
      - lseg '((-1,0),(1,0))' ?|| lseg '((-1,2),(1,2))'
    * - \@>
      - 包含?
      - circle '((0,0),2)' @> point '(1,1)'
    * - \<@
      - 包含或在...上?
      - point '(1,1)' <@ circle '((0,0),2)'
    * - \~=
      - 与...相同?
      - polygon '((0,0),(1,1))' ~= polygon '((1,1),(0,0))'

**表.几何函数**


.. list-table::
    :widths: auto
    :header-rows: 1

    * - 函数
      - 返回类型
      - 描述
      - 例子
    * - area(object)	
      - double precision	
      - 面积	
      - area(box '((0,0),(1,1))')
    * - center(object)	
      - point	
      - 中心
      - center(box '((0,0),(1,2))')
    * - diameter(circle)	
      - double precision	
      - 圆直径
      - diameter(circle '((0,0),2.0)')
    * - height(box)	
      - double precision	
      - 矩形的竖直高度	
      - height(box '((0,0),(1,1))')
    * - isclosed(path)	
      - boolean	
      - 闭合路径?	
      - isclosed(path '((0,0),(1,1),(2,0))')
    * - isopen(path)	
      - boolean	
      - 开路径?	
      - isopen(path '[(0,0),(1,1),(2,0)]')
    * - length(object)	
      - double precision	
      - 长度	
      - length(path '((-1,0),(1,0))')
    * - npoints(path)	
      - int	
      - 点数
      - npoints(path '[(0,0),(1,1),(2,0)]')
    * - npoints(polygon)	
      - int	
      - 点数
      - npoints(polygon '((1,1),(0,0))')
    * - pclose(path)	
      - path	
      - 把路径转换为闭合
      - pclose(path '[(0,0),(1,1),(2,0)]')
    * - popen(path)	
      - path	
      - 把路径转换为开放		
      - popen(path '((0,0),(1,1),(2,0))')
    * - radius(circle)	
      - double precision	
      - 圆半径	
      - radius(circle '((0,0),2.0)')
    * - width(box) 
      - double precision	
      - 矩形的水平尺寸	
      - width(box '((0,0),(1,1))')

**表.几何类型转换函数**


.. list-table::
    :widths: auto
    :header-rows: 1

    * - 函数
      - 返回类型
      - 描述
      - 例子
    * - box(circle)	
      - box	
      - 将圆转换成矩形	
      - box(circle '((0,0),2.0)')
    * - box(point, point)	
      - box	
      - 将点转换成矩形
      - box(point '(0,0)', point '(1,1)')
    * - box(polygon)	
      - box	
      - 将多边形转换成矩形
      - box(polygon '((0,0),(1,1),(2,0))')
    * - circle(box)	
      - circle	
      - 矩形转换成圆
      - circle(box '((0,0),(1,1))')
    * - circle(point, double precision)	
      - circle	
      - 将圆心和半径转换成圆
      - circle(point '(0,0)', 2.0)
    * - circle(polygon)	
      - circle	
      - 将多边形转换成圆	
      - circle(polygon '((0,0),(1,1),(2,0))')
    * - lseg(box)	lseg	
      - box 
      - 矩形对角线转化成线段
      - lseg(box '((-1,0),(1,0))')
    * - lseg(point, point)	
      - lseg	
      - 点转换成线段
      - lseg(point '(-1,0)', point '(1,0)')
    * - path(polygon)	
      - point	
      - 多边形转换成路径
      - path(polygon '((0,0),(1,1),(2,0))')
    * - point(double precision, double precision)	
      - point	
      - 构造点	
      - point(23.4, -44.5)
    * - point(box)	
      - point
      - 矩形的中心
      - point(box '((-1,0),(1,0))')
    * - point(circle)	
      - point
      - 圆心
      - point(circle '((0,0),2.0)')
    * - point(lseg)	
      - point	
      - 线段的中心
      - point(lseg '((-1,0),(1,0))')
    * - point(polygon)	
      - point	
      - 多边形的中心
      - point(polygon '((0,0),(1,1),(2,0))')
    * - polygon(box)
      - polygon  
      - 矩形转换成 4 点多边形	
      - polygon(box '((0,0),(1,1))')
    * - polygon(circle)	
      - polygon	
      - 圆转换成 12 点多边形
      - polygon(circle '((0,0),2.0)')
    * - polygon(npts, circle)
      - polygon
      - 圆转换成 12 点多边形	
      - polygon(12, circle '((0,0),2.0)')
    * - polygon(path)	
      - polygon	
      - 路径转换成多边形
      - polygon(path '((0,0),(1,1),(2,0))')

我们可以把一个point的两个组成部分当作索引分别为 0 和 1 的数组元素进行访问。比如,如果t.p是一个point字段,那么SELECT p[0] FROM t 检索 X 座标而UPDATE t SET p[1] = ...改变 Y 座标。同样, box或lseg的值可以当作两个point的数组值看待。

area函数可以用于box, circle, path类型。area函数操作path数据类型的时候, 只有在path的点没有交叉的情况下才可用。比如,path '((0,0),(0,1),(2,1),(2,2),(1,2),(1,0),(0,0))'::PATH是不行的, 而下面的视觉等效path '((0,0),(0,1),(1,1),(1,2),(2,2),(2,1),(1,1),(1,0),(0,0))'::PATH 就可以。如果交叉和不交叉的path概念让你糊涂,那么把上面两个path 都画在纸上,你就明白了。