9.11. Геометрические функции и операторы

Для геометрических типов point, box, lseg, line, path, polygon и circle разработан большой набор встроенных функций и операторов, представленный в Таблице 9.33, Таблице 9.34 и Таблице 9.35.

Внимание

Заметьте, что оператор «идентичности», ~=, представляет обычное сравнение на равенство значений point, box, polygon и circle. Для некоторых из этих типов определён также оператор =, но = проверяет только равенство площадей. Другие скалярные операторы сравнения (<= и т. д.) так же сравнивают площади значений этих типов.

Таблица 9.33. Геометрические операторы

ОператорОписаниеПример
+Сдвиг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)'
#Точка или прямоугольник в пересеченииbox '((1,-1),(-1,1))' # box '((1,1),(-2,-2))'
#Число точек в пути или вершин в многоугольнике# path '((1,0),(0,1),(-1,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))'
<^Ниже (может касаться)?circle '((0,0),1)' <^ circle '((0,5),1)'
>^Выше (может касаться)?circle '((0,5),1)' >^ circle '((0,0),1)'
?#Пересекает?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))'

Примечание

До PostgreSQL 8.2 операторы включения @> и <@ назывались соответственно ~ и @. Эти имена по-прежнему доступны, но считаются устаревшими и в конце концов будут удалены.

Таблица 9.34. Геометрические функции

ФункцияТип результатаОписаниеПример
area(объект)double precisionплощадьarea(box '((0,0),(1,1))')
center(объект)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(объект)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))')

Таблица 9.35. Функции преобразования геометрических типов

ФункцияТип результатаОписаниеПример
box(circle)boxокружность в прямоугольникbox(circle '((0,0),2.0)')
box(point)boxточка в пустой прямоугольникbox(point '(0,0)')
box(point, point)boxточки в прямоугольникbox(point '(0,0)', point '(1,1)')
box(polygon)boxмногоугольник в прямоугольникbox(polygon '((0,0),(1,1),(2,0))')
bound_box(box, box)boxпрямоугольники в окружающий прямоугольникbound_box(box '((0,0),(1,1))', box '((3,3),(4,4))')
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))')
line(point, point)lineточки в прямуюline(point '(-1,0)', point '(1,0)')
lseg(box)lsegдиагональ прямоугольника в отрезокlseg(box '((-1,0),(1,0))')
lseg(point, point)lsegточки в отрезокlseg(point '(-1,0)', point '(1,0)')
path(polygon)pathмногоугольник в путь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(число_точек, circle)polygonокружность с заданным числом_точек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. При этом для типа path заданный путь не должен быть самопересекающимся. Например, эта функция не примет значение типа path '((0,0),(0,1),(2,1),(2,2),(1,2),(1,0),(0,0))'::PATH, но примет визуально идентичный путь '((0,0),(0,1),(1,1),(1,2),(2,2),(2,1),(1,1),(1,0),(0,0))'::PATH. Если вы не вполне поняли, что здесь подразумевается под самопересечением пути, нарисуйте на бумаге две фигуры по приведённым координатам.

9.11. Geometric Functions and Operators

The geometric types point, box, lseg, line, path, polygon, and circle have a large set of native support functions and operators, shown in Table 9.33, Table 9.34, and Table 9.35.

Caution

Note that the same as operator, ~=, represents the usual notion of equality for the point, box, polygon, and circle types. Some of these types also have an = operator, but = compares for equal areas only. The other scalar comparison operators (<= and so on) likewise compare areas for these types.

Table 9.33. Geometric Operators

OperatorDescriptionExample
+Translationbox '((0,0),(1,1))' + point '(2.0,0)'
-Translationbox '((0,0),(1,1))' - point '(2.0,0)'
*Scaling/rotationbox '((0,0),(1,1))' * point '(2.0,0)'
/Scaling/rotationbox '((0,0),(2,2))' / point '(2.0,0)'
#Point or box of intersectionbox '((1,-1),(-1,1))' # box '((1,1),(-2,-2))'
#Number of points in path or polygon# path '((1,0),(0,1),(-1,0))'
@-@Length or circumference@-@ path '((0,0),(1,0))'
@@Center@@ circle '((0,0),10)'
##Closest point to first operand on second operandpoint '(0,0)' ## lseg '((2,0),(0,2))'
<->Distance betweencircle '((0,0),1)' <-> circle '((5,0),1)'
&&Overlaps? (One point in common makes this true.)box '((0,0),(1,1))' && box '((0,0),(2,2))'
<<Is strictly left of?circle '((0,0),1)' << circle '((5,0),1)'
>>Is strictly right of?circle '((5,0),1)' >> circle '((0,0),1)'
&<Does not extend to the right of?box '((0,0),(1,1))' &< box '((0,0),(2,2))'
&>Does not extend to the left of?box '((0,0),(3,3))' &> box '((0,0),(2,2))'
<<|Is strictly below?box '((0,0),(3,3))' <<| box '((3,4),(5,5))'
|>>Is strictly above?box '((3,4),(5,5))' |>> box '((0,0),(3,3))'
&<|Does not extend above?box '((0,0),(1,1))' &<| box '((0,0),(2,2))'
|&>Does not extend below?box '((0,0),(3,3))' |&> box '((0,0),(2,2))'
<^Is below (allows touching)?circle '((0,0),1)' <^ circle '((0,5),1)'
>^Is above (allows touching)?circle '((0,5),1)' >^ circle '((0,0),1)'
?#Intersects?lseg '((-1,0),(1,0))' ?# box '((-2,-2),(2,2))'
?-Is horizontal??- lseg '((-1,0),(1,0))'
?-Are horizontally aligned?point '(1,0)' ?- point '(0,0)'
?|Is vertical??| lseg '((-1,0),(1,0))'
?|Are vertically aligned?point '(0,1)' ?| point '(0,0)'
?-|Is perpendicular?lseg '((0,0),(0,1))' ?-| lseg '((0,0),(1,0))'
?||Are parallel?lseg '((-1,0),(1,0))' ?|| lseg '((-1,2),(1,2))'
@>Contains?circle '((0,0),2)' @> point '(1,1)'
<@Contained in or on?point '(1,1)' <@ circle '((0,0),2)'
~=Same as?polygon '((0,0),(1,1))' ~= polygon '((1,1),(0,0))'

Note

Before PostgreSQL 8.2, the containment operators @> and <@ were respectively called ~ and @. These names are still available, but are deprecated and will eventually be removed.

Table 9.34. Geometric Functions

FunctionReturn TypeDescriptionExample
area(object)double precisionareaarea(box '((0,0),(1,1))')
center(object)pointcentercenter(box '((0,0),(1,2))')
diameter(circle)double precisiondiameter of circlediameter(circle '((0,0),2.0)')
height(box)double precisionvertical size of boxheight(box '((0,0),(1,1))')
isclosed(path)booleana closed path?isclosed(path '((0,0),(1,1),(2,0))')
isopen(path)booleanan open path?isopen(path '[(0,0),(1,1),(2,0)]')
length(object)double precisionlengthlength(path '((-1,0),(1,0))')
npoints(path)intnumber of pointsnpoints(path '[(0,0),(1,1),(2,0)]')
npoints(polygon)intnumber of pointsnpoints(polygon '((1,1),(0,0))')
pclose(path)pathconvert path to closedpclose(path '[(0,0),(1,1),(2,0)]')
popen(path)pathconvert path to openpopen(path '((0,0),(1,1),(2,0))')
radius(circle)double precisionradius of circleradius(circle '((0,0),2.0)')
width(box)double precisionhorizontal size of boxwidth(box '((0,0),(1,1))')

Table 9.35. Geometric Type Conversion Functions

FunctionReturn TypeDescriptionExample
box(circle)boxcircle to boxbox(circle '((0,0),2.0)')
box(point)boxpoint to empty boxbox(point '(0,0)')
box(point, point)boxpoints to boxbox(point '(0,0)', point '(1,1)')
box(polygon)boxpolygon to boxbox(polygon '((0,0),(1,1),(2,0))')
bound_box(box, box)boxboxes to bounding boxbound_box(box '((0,0),(1,1))', box '((3,3),(4,4))')
circle(box)circlebox to circlecircle(box '((0,0),(1,1))')
circle(point, double precision)circlecenter and radius to circlecircle(point '(0,0)', 2.0)
circle(polygon)circlepolygon to circlecircle(polygon '((0,0),(1,1),(2,0))')
line(point, point)linepoints to lineline(point '(-1,0)', point '(1,0)')
lseg(box)lsegbox diagonal to line segmentlseg(box '((-1,0),(1,0))')
lseg(point, point)lsegpoints to line segmentlseg(point '(-1,0)', point '(1,0)')
path(polygon)pathpolygon to pathpath(polygon '((0,0),(1,1),(2,0))')
point(double precision, double precision)pointconstruct pointpoint(23.4, -44.5)
point(box)pointcenter of boxpoint(box '((-1,0),(1,0))')
point(circle)pointcenter of circlepoint(circle '((0,0),2.0)')
point(lseg)pointcenter of line segmentpoint(lseg '((-1,0),(1,0))')
point(polygon)pointcenter of polygonpoint(polygon '((0,0),(1,1),(2,0))')
polygon(box)polygonbox to 4-point polygonpolygon(box '((0,0),(1,1))')
polygon(circle)polygoncircle to 12-point polygonpolygon(circle '((0,0),2.0)')
polygon(npts, circle)polygoncircle to npts-point polygonpolygon(12, circle '((0,0),2.0)')
polygon(path)polygonpath to polygonpolygon(path '((0,0),(1,1),(2,0))')

It is possible to access the two component numbers of a point as though the point were an array with indexes 0 and 1. For example, if t.p is a point column then SELECT p[0] FROM t retrieves the X coordinate and UPDATE t SET p[1] = ... changes the Y coordinate. In the same way, a value of type box or lseg can be treated as an array of two point values.

The area function works for the types box, circle, and path. The area function only works on the path data type if the points in the path are non-intersecting. For example, the path '((0,0),(0,1),(2,1),(2,2),(1,2),(1,0),(0,0))'::PATH will not work; however, the following visually identical path '((0,0),(0,1),(1,1),(1,2),(2,2),(2,1),(1,1),(1,0),(0,0))'::PATH will work. If the concept of an intersecting versus non-intersecting path is confusing, draw both of the above paths side by side on a piece of graph paper.

FAQ