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. Геометрические функции
| Функция | Тип результата | Описание | Пример |
|---|---|---|---|
| double precision | площадь | area(box '((0,0),(1,1))') |
| point | центр | center(box '((0,0),(1,2))') |
| double precision | диаметр круга | diameter(circle '((0,0),2.0)') |
| double precision | вертикальный размер прямоугольника | height(box '((0,0),(1,1))') |
| boolean | замкнутый путь? | isclosed(path '((0,0),(1,1),(2,0))') |
| boolean | открытый путь? | isopen(path '[(0,0),(1,1),(2,0)]') |
| double precision | длина | length(path '((-1,0),(1,0))') |
| int | число точек | npoints(path '[(0,0),(1,1),(2,0)]') |
| int | число точек | npoints(polygon '((1,1),(0,0))') |
| path | преобразует путь в замкнутый | pclose(path '[(0,0),(1,1),(2,0)]') |
| path | преобразует путь в открытый | popen(path '((0,0),(1,1),(2,0))') |
| double precision | радиус окружности | radius(circle '((0,0),2.0)') |
| double precision | горизонтальный размер прямоугольника | width(box '((0,0),(1,1))') |
Таблица 9.35. Функции преобразования геометрических типов
К двум компонентам типа 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
| Operator | Description | Example |
|---|---|---|
+ | Translation | box '((0,0),(1,1))' + point '(2.0,0)' |
- | Translation | box '((0,0),(1,1))' - point '(2.0,0)' |
* | Scaling/rotation | box '((0,0),(1,1))' * point '(2.0,0)' |
/ | Scaling/rotation | box '((0,0),(2,2))' / point '(2.0,0)' |
# | Point or box of intersection | box '((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 operand | point '(0,0)' ## lseg '((2,0),(0,2))' |
<-> | Distance between | circle '((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
| Function | Return Type | Description | Example |
|---|---|---|---|
| double precision | area | area(box '((0,0),(1,1))') |
| point | center | center(box '((0,0),(1,2))') |
| double precision | diameter of circle | diameter(circle '((0,0),2.0)') |
| double precision | vertical size of box | height(box '((0,0),(1,1))') |
| boolean | a closed path? | isclosed(path '((0,0),(1,1),(2,0))') |
| boolean | an open path? | isopen(path '[(0,0),(1,1),(2,0)]') |
| double precision | length | length(path '((-1,0),(1,0))') |
| int | number of points | npoints(path '[(0,0),(1,1),(2,0)]') |
| int | number of points | npoints(polygon '((1,1),(0,0))') |
| path | convert path to closed | pclose(path '[(0,0),(1,1),(2,0)]') |
| path | convert path to open | popen(path '((0,0),(1,1),(2,0))') |
| double precision | radius of circle | radius(circle '((0,0),2.0)') |
| double precision | horizontal size of box | width(box '((0,0),(1,1))') |
Table 9.35. Geometric Type Conversion Functions
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.