问题
I'm using PostgresSQL 9.5 to generate a rectangle (geometric type BOX). That works fine
SELECT Box(Point(-50, -100), Point(50, 100)) ; -- this works
Then I try to rotate that box around the origin (its center point). The rotation function is both
* Scaling/rotation box '((0,0),(1,1))' * point '(2.0,0)'
/ Scaling/rotation box '((0,0),(2,2))' / point '(2.0,0)'
where the x-point is the scaling factor (2.0 in this example) and the y-point is the rotation radians (0 in this example).
To check that the rotation is correct, I calculate the height, width and area of the box for each angle.
SELECT
xx.deg, -- angle in degrees
xx.geom, -- geometry of box
Area(xx.geom),
Center(xx.geom),
Height(xx.geom),
Width(xx.geom)
FROM
(SELECT deg,
Box(Point(-5, -10), Point(5, 10)) / Point(1, Radians(deg)) -- scale box by factor 1 and rotate by radians(degrees)
AS geom
FROM Generate_series(0, 360, 90) AS deg -- generate list of degrees from 0 to 360 by 90
) xx;
The results, which don't change between using *
or /
functions,
deg;geom;area;center;height;width
0;"(5,10),(-5,-10)";200;"(0,0)";20;10
90;"(5.97218570021291,0.618912639168559),(-5.97218570021291,-0.618912639168559)";14.785044853294;"(0,0)";1.23782527833712;11.9443714004258
180;"(3.35025316397424,0.525130727607429),(-3.35025316397424,-0.525130727607429)";7.03728352666753;"(0,0)";1.05026145521486;6.70050632794848
270;"(2.24607945852279,0.584400089411209),(-2.24607945852279,-0.584400089411209)";5.25043614554159;"(0,0)";1.16880017882242;4.49215891704558
360;"(1.67575357650576,0.529070250354662),(-1.67575357650576,-0.529070250354662)";3.5463654570185;"(0,0)";1.05814050070932;3.35150715301153
show that the box is being rotated but also scaled - the height, width and area are all not constant. I read somewhere that a rotation needs to take into account scaling, but I don't understand what scaling factor should be used to compsenate for the rotation. The documentation doesn't give any examples, and most of the resources online are for PostGIS (i.e. ST_Rotate).
UPDATE
I have a working solution that is not the fastest but gives correct results. See here
https://stackoverflow.com/a/39680955/2327328
回答1:
TL/DR: You cannot rotate boxes
The two operators *
and /
can be confusing. The idea is that they treat the two dimensional points as complex numbers and perform multiply (or divide) them as complex numbers. So for example point '(2,3)' * point '(1,-1)'
returns (5,1)
because (2+3i)*(1-i)=5+i
or point '(0,1)' * point '(0,1)'
returns (-1,0)
because i*i=-1
.
So if you want to use *
to rotate by an angle say φ
, you have to multiply by the complex number exp(i*φ)
which is equal to cos(φ)+i*sin(φ)
. For example:
SELECT point '(1,0)' * point(cos(radians(45)),sin(radians(45)));
=> (0.707106781186548,0.707106781186547)
rotates the point (1,0)
by 45 degrees counter clockwise.
Unfortunately, this doesn't work very well with boxes. If you do
SELECT box '((0,0),(1,1))' * point(cos(radians(45)),sin(radians(45)));
=> (1.11022302462516e-16,1.41421356237309),(0,0)
which means that postgres rotated the two points as individual points and not the whole box. The problem is that a box is a rectangle with sides parallel to the x and y axes. By that definition, if you rotate a box by 45 degrees, what you get is not a box. So you cannot rotate boxes.
In theory, it should be possible to rotate polygons. Unfortunatelly, it seems that this has not been implemented (yet?) in postgresql:
$ SELECT polygon(box '((0,0),(1,1))') * point(1,0);
ERROR: operator does not exist: polygon * point
LINE 1: SELECT polygon(box '((0,0),(1,1))') * point(1,0);
来源:https://stackoverflow.com/questions/39668459/postgresql-rotate-geometric-type-giving-unexpected-results