PostgreSQL - 旋转几何类型,给出意想不到的结果

时间:2016-09-23 19:45:01

标签: postgresql rotation geometry

我使用PostgresSQL 9.5生成一个矩形(geometric type BOX)。 这很好用

SELECT Box(Point(-50, -100), Point(50, 100)) ; -- this works

然后我尝试围绕原点(其中心点)旋转该框。 rotation function都是

*   Scaling/rotation    box '((0,0),(1,1))' * point '(2.0,0)'
/   Scaling/rotation    box '((0,0),(2,2))' / point '(2.0,0)'

其中x点是比例因子(本例中为2.0),y点是旋转弧度(本例中为0)。

为了检查旋转是否正确,我计算每个角度的盒子的高度,宽度和面积。

 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;  

使用*/函数之间不会发生变化的结果

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

显示盒子正在旋转但也缩放 - 高度,宽度和面积都不是恒定的。我在某处读到旋转需要考虑缩放,但我不明白应该使用什么缩放因子来计算旋转。文档没有给出任何示例,大多数在线资源都是针对PostGIS(即ST_Rotate)。

更新

我有一个不是最快的工作解决方案,但会给出正确的结果。见这里

https://stackoverflow.com/a/39680955/2327328

1 个答案:

答案 0 :(得分:1)

TL / DR:你不能旋转方框

两个运营商*/可能令人困惑。他们的想法是,他们将二维点视为复数,并将它们作为复数进行乘法(或除)。因此,例如point '(2,3)' * point '(1,-1)'会返回(5,1),因为(2+3i)*(1-i)=5+ipoint '(0,1)' * point '(0,1)'会返回(-1,0),因为i*i=-1

因此,如果您想使用*φ的角度旋转,则必须乘以等于exp(i*φ)的复数cos(φ)+i*sin(φ)。例如:

SELECT point '(1,0)' * point(cos(radians(45)),sin(radians(45)));
=> (0.707106781186548,0.707106781186547)

将点(1,0)逆时针旋转45度。

不幸的是,这对盒子来说效果不佳。如果你这样做

SELECT box '((0,0),(1,1))' * point(cos(radians(45)),sin(radians(45)));
=> (1.11022302462516e-16,1.41421356237309),(0,0)

这意味着postgres将两个点旋转为单个点而不是整个框。问题是盒子是一个边长平行于x和y轴的矩形。按照这个定义,如果你将一个盒子旋转45度,你得到的不是盒子。所以你不能旋转盒子。

理论上,应该可以旋转多边形。不幸的是,似乎在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);