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

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

本文介绍了PostgreSQL - 旋转几何类型给出意想不到的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用PostgresSQL 9.5生成一个矩形( BOX)。
工作正常

  SELECT BOX(点(-50,-100),点(50,100)) ; - 这个工程

然后我尝试围绕原点(它的中心点)旋转那个盒子。 既是

  *缩放/旋转框'((0,0),(1,1))'* point'(2.0,0)'
/(缩放/旋转框)'((0,0),(2,2))'/ point'(2.0,0)'

其中x点是比例因子(本例中为2.0),y点是旋转弧度(本例中为0)。
$ b $为了检查旋转是否正确,我计算了每个角度的高度,宽度和框的面积。

 选择
xx.deg, - 以度为单位的角度
xx.geom, - 框的几何形状
区域(xx.geom),
中心(xx.geom),
Height(xx.geom),
Width(xx.geom)
FROM
(SELECT deg,
Box(Point(-5,-10),Point (5,10))/ Point(1,Radians(deg)) - 按比例1放大比例框并旋转弧度(度)
AS geom
FROM Generate_series(0,360,90)AS deg - 根据90
)xx生成从0到360的度数列表;

结果在使用 * / 函数,

  deg; geom; area; (5,10),( -  5,-10); 200;(0,0); 20; 10 
90;(5.97218570021291, ( - 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)。




更新



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



解决方案
TL / DR:你不能旋转盒子

两个运算符 * / 可能会造成混淆。这个想法是,他们将二维点视为复数,并将它们乘以(或划分)为复数。因此,例如点'(2,3)'*点'(1,-1)'返回(5,1)(2 + 3i)*(1-i)= 5 + i 点'(0,1)'* (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) code>逆时针45度。



不幸的是,这对盒子来说效果不佳。 ((0,0),(1,1))'*点(cos(弧度) (45)),SIN(弧度(45)));
=> (1.11022302462516e-16,1.41421356237309),(0,0)

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



理论上,应该可以旋转多边形。不幸的是,这似乎还没有在postgresql中实现(还没有?):

  $ SELECT多边形(box'((0 ,0),(1,1))')* point(1,0); 
ERROR:运算符不存在:polygon * point
LINE 1:SELECT polygon(box'((0,0),(1,1))')* point(1,0);


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

解决方案

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);

这篇关于PostgreSQL - 旋转几何类型给出意想不到的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-01 22:23