Reputation: 483
I have simple table:
create table boxes2(id serial, rect polygon);
insert into boxes2(rect) values(polygon'((0,0),(10,0),(10,10),(0,10))');
And I want to get concrete point of this polygon, I made this
select rect[0] from boxes2 where id = 1;
But there is error: "Type polygon is not array, impossible appoint index of element"
How can I do this?
Version - "PostgreSQL 9.5.4, compiled by Visual C++ build 1800, 32-bit"
Upvotes: 0
Views: 893
Reputation: 6328
This is a rather complicated way of getting the 'nth' point of a polygon, based on assuming that PostgreSQL keeps the vertices in the same order they were entered, converting polygons to text, then parsing the text using regular expressions, taking out the part you're interested in, and casting it back to a point type. It's rather complicated:
WITH boxes2(id, rect) AS
(
VALUES
(1, polygon'((0,0),(10,0),(10,10),(0,10))')
)
SELECT
p
FROM
(
SELECT
row_number() over () AS rn, p
FROM
(
SELECT
(
(regexp_matches(rect::text,
'\([^()]+\)', 'g')
)[1]
)::point AS p
FROM
boxes2
WHERE
id = 1
) AS pol_to_table_of_points
) AS numbered_table_of_points
WHERE
rn = 2 /* This is if you want to get then 2nd point */ ;
I must admit this looks rather awful, but, AFAIK, there is no published way to get the 'nth' point of a polygon (nor a path). I'm quite sure you can do it using PostGIS, but have not found a way to do it without it.
There is a function to get the number of points (npoints(polygon '((1,1),(0,0))')
), but not a specific point. And converting a polygon to an array of points (a cast a_polygon::point[]) doesn't work either.
Caveat:
From a geometric point of view, if A, B, C and D are points (vertices or corners), then the polygons described by (A, B, C, D), (B, C, D, A), (C, D, A, B), (D, A, B, C) and the same (ordered) quadruplets but reversed: (D, C, B, A), ... are absolutely equivalent.
So, you cannot really say which is the "second" vertex of a polygon. At this point, and just having checked a few samples with very few points, it seems that PostgreSQL represents polygons as an ordered list of vertices, keeping the original order. But it actually could change it if this new representation helps it in some way.
For instance, all the polygons in the following query are equivalent:
WITH some_polygons (p1, p2, p3, p4, p5, p6, p7, p8) AS
(
VALUES
('(0,0), (1,0), (2,2), (0,3)' :: polygon,
'(1,0), (2,2), (0,3), (0,0)' :: polygon,
'(2,2), (0,3), (0,0), (1,0)' :: polygon,
'(0,3), (0,0), (1,0), (2,2)' :: polygon,
'(0,3), (2,2), (1,0), (0,0)' :: polygon,
'(0,0), (0,3), (2,2), (1,0)' :: polygon,
'(1,0), (0,0), (0,3), (2,2)' :: polygon,
'(2,2), (1,0), (0,0), (0,3)' :: polygon
)
)
SELECT
p1 ~= p2 AS eq2, -- ~= stands for "same as"
p1 ~= p3 AS eq3,
p1 ~= p4 AS eq4,
p1 ~= p5 AS eq5,
p1 ~= p6 AS eq6,
p1 ~= p7 AS eq7,
p1 ~= p8 AS eq8
FROM
some_polygons ;
I think this is the reason why PostgreSQL decided not to let you take the "nth" vertex
of a polygon: it is something not theoretically defined.
So, if you want to keep on the safe side, and not risk that a later implementation change breaks your code, as an alternative, you could store an array of points (point[]
). An array is guaranteed to keep values in the same order they were supplied. If you need both a polygon and the original list of vertices, I think I would have the two pieces of data (even if this is a not-normalized form). If you only work with rectangles, I'd use the type box
; it better represents your needs.
Upvotes: 1
Reputation: 121889
There is a function ST_DumpPoints(geometry geom) in the PostGIS extention to extract points from a geometric object.
If rect
values are just boxes then you can convert polygons to boxes:
select (box(rect))[0] right_top, (box(rect))[1] left_bottom
from boxes2
where id = 1;
right_top | left_bottom
-----------+-------------
(10,10) | (0,0)
(1 row)
In this case however you can simply store the values as type box
.
Upvotes: 2