PostgreSQL 三角函数的用法举例 - 已知3点求夹角(旋转门续)

背景

前几天写了一篇关于旋转门的数据压缩算法在PostgreSQL中的实现,里面用到了PostGIS里面的ST_Azimuth函数用来计算夹角,其实在PostgreSQL 中,我们还可以使用三角函数,以及三边来求夹角。

文中用到的计算夹角的方法如下

      SELECT 180-ST_Azimuth(
                              ST_MakePoint(o_x, o_val+i_radius),    -- 门上点
                              ST_MakePoint(v_x, v_val)              -- next point
                           )/(2pi())360 as degAz,                 -- 上夹角
                 ST_Azimuth(
                              ST_MakePoint(o_x, o_val-i_radius),    -- 门下点
                              ST_MakePoint(v_x, v_val)              -- next point
                           )/(2pi())360 As degAzrev               -- 下夹角
      INTO v_angle1, v_angle2;

余弦定理

cosA=(b²+c²-a²)/(2bc)

定点为A、B、C; 对的边分别为a、b、c;

PostgreSQL 支持的三角函数

https://www.postgresql.org/docs/9.6/static/functions-math.html

Function (radians) Function (degrees) Description
acos(x) acosd(x) inverse cosine
asin(x) asind(x) inverse sine
atan(x) atand(x) inverse tangent
atan2(y, x) atan2d(y, x) inverse tangent of y/x
cos(x) cosd(x) cosine
cot(x) cotd(x) cotangent
sin(x) sind(x) sine
tan(x) tand(x) tangent

例子

已知三个点A(3,2),B(1,2.5),C(1,1)。 求夹角B, C。

套用余弦公式

cosB=(a²+c²-b²)/(2ac)   

cosC=(b²+a²-c²)/(2ba)

首先求三条边长

postgres=# select point_distance(point(3,2), point(1,2.5)) as c , point_distance(point(3,2), point(1,1)) as b , point_distance(point(1,1), point(1,2.5)) as a;
        c         |        b         |  a
------------------+------------------+-----
 2.06155281280883 | 2.23606797749979 | 1.5
(1 row)

运算如下

cosB=(a²+c²-b²)/(2ac)
=(1.5^2 + 2.06155281280883^2 - 2.23606797749979^2) / (21.52.06155281280883)
=0.24253562503633260164  

cosC=(b²+a²-c²)/(2ba)
=(1.5^2 + 2.23606797749979^2 - 2.06155281280883^2) / (22.236067977499791.5)
=0.44721359549995825124

求夹角 1 度数

postgres=# select acosd(0.24253562503633260164);
      acosd
------------------
 75.9637565320735
(1 row)

求夹角 2 度数

postgres=# select acosd(0.44721359549995825124);
      acosd
-----------------
 63.434948822922
(1 row)

比对使用PostGIS计算的结果一致

test=>  SELECT 180-ST_Azimuth(
                              ST_MakePoint(1,2.5),    -- 门上点
                              ST_MakePoint(3,2)              -- next point
                           )/(2pi())360 as degAz,                 -- 上夹角
                 ST_Azimuth(
                              ST_MakePoint(1,1),    -- 门下点
                              ST_MakePoint(3,2)              -- next point
                           )/(2pi())360 As degAzrev ;
      degaz       |    degazrev
------------------+-----------------
 75.9637565320735 | 63.434948822922
(1 row)

源码

三角函数属于浮点运算中的函数

src/backend/utils/adt/float.c

/*
 *              acosd_q1                - returns the inverse cosine of x in degrees, for x in
 *                                                the range [0, 1].  The result is an angle in the
 *                                                first quadrant --- [0, 90] degrees.
 *
 *                                                For the 3 special case inputs (0, 0.5 and 1), this
 *                                                function will return exact values (0, 60 and 90
 *                                                degrees respectively).
 */
static double
acosd_q1(double x)
{
        /*
         * Stitch together inverse sine and cosine functions for the ranges [0,
         * 0.5] and (0.5, 1].  Each expression below is guaranteed to return
         * exactly 60 for x=0.5, so the result is a continuous monotonic function
         * over the full range.
         */
        if (x <= 0.5)
        {
                volatile float8 asin_x = asin(x);

                return 90.0 - (asin_x / asin_0_5) * 30.0;
        }
        else
        {
                volatile float8 acos_x = acos(x);

                return (acos_x / acos_0_5) * 60.0;
        }
}

/*
 *              dacosd                  - returns the arccos of arg1 (degrees)
 */
Datum
dacosd(PG_FUNCTION_ARGS)
{
        float8          arg1 = PG_GETARG_FLOAT8(0);
        float8          result;

        / Per the POSIX spec, return NaN if the input is NaN /
        if (isnan(arg1))
                PG_RETURN_FLOAT8(get_float8_nan());

        INIT_DEGREE_CONSTANTS();

        /*
         * The principal branch of the inverse cosine function maps values in the
         * range [-1, 1] to values in the range [0, 180], so we should reject any
         * inputs outside that range and the result will always be finite.
         */
        if (arg1 < -1.0 || arg1 > 1.0)
                ereport(ERROR,
                                (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                 errmsg("input is out of range")));

        if (arg1 >= 0.0)
                result = acosd_q1(arg1);
        else
                result = 90.0 + asind_q1(-arg1);

        CHECKFLOATVAL(result, false, true);
        PG_RETURN_FLOAT8(result);
}
man asin
NAME
       asin, asinf, asinl - arc sine function

SYNOPSIS
       #include <math.h>

       double asin(double x);
       float asinf(float x);
       long double asinl(long double x);

///

CONFORMING TO
       C99, POSIX.1-2001.  The variant returning double also conforms to SVr4, 4.3BSD, C89.

SEE ALSO
       acos(3), atan(3), atan2(3), casin(3), cos(3), sin(3), tan(3)

祝大家玩得开心,欢迎随时来 阿里云促膝长谈业务需求 ,恭候光临

阿里云的小伙伴们加油,努力 做好内核与服务,打造最贴地气的云数据库

时间: 2024-08-08 07:23:56

PostgreSQL 三角函数的用法举例 - 已知3点求夹角(旋转门续)的相关文章

反算经纬度-已知A、B点经纬度jA、wA、jB、wB和分别到C点的距离弧长AC、BC,求C点经纬度jC、wC

问题描述 已知A.B点经纬度jA.wA.jB.wB和分别到C点的距离弧长AC.BC,求C点经纬度jC.wC 已知A.B点经纬度jA.wA.jB.wB和分别到C点的距离弧长AC.BC,求C点经纬度jC.wC(二个解).方程式一:弧长AC=Rarccos(coswA*coswC*cos(jA-jC)+sinwA*sinwC)方程式二:弧长BC=Rarccos(coswB*coswC*cos(jB-jC)+sinwB*sinwC) 解决方案 有四种可能,0个解.1个解.2个解.无数多个解.0个解的情况

给定已知100个地址的经纬度 如何求出每个地址对应最近的三个地址?

问题描述 已知100个地址的经纬度:地址1地址2地址3...地址100根据经纬度求出地址1对应最近的三个地址? 解决方案 解决方案二:存到数据库里面..用SQL语句选择经纬度差值最小的3条记录即可.自己遍历计算也可以,就是麻烦解决方案三:求两点间的距离.再求个最值解决方案四:引用1楼xzhui的回复: 存到数据库里面..用SQL语句选择经纬度差值最小的3条记录即可.自己遍历计算也可以,就是麻烦 经纬度差值最小的这个是如何算呢?解决方案五:先把经纬度转换成投影坐标系再直接做加减运算解决方案六:引用

美国政府拟立法改进物联网安全:禁止硬编码密码、已知漏洞必须修复

本文讲的是美国政府拟立法改进物联网安全:禁止硬编码密码.已知漏洞必须修复,美国参议院四位参议员Warner.Gardner.Wyden和Daines最近提交一项名为<物联网安全改进法案>(the Internet of Things Cybersecurity Improvement Act of 2017,简称IoT-CIA)的草拟法案,旨在加强物联网厂商对设备安全性的投入. 这项法案不是针对所有物联网设备,只是适用于美国政府内部使用的设备,因此不大可能会有大的反对意见,通过立法几率很大.而

译文:身未动,心已知

译者注:本人兴趣于交互设计上对人类认知模式的借鉴,先前撰文<人的"模式识别"与设计的认知效率>探讨了模式识别的本能及其在设计中的运用.此次翻译Charles Hannon教授一篇关于模式识别在大脑中更本质的机能原理阐述的文章,共飨. 原文:You Already Know How To Use It --------------------------------------- 在iPad最早的电视广告中有这么一句旁诉:"绝对给力,魔幻十足!身未动,心已知(You

c++ stl容器set成员函数介绍及set集合插入,遍历等用法举例

c++ stl集合set介绍    c++ stl集合(Set)是一种包含已排序对象的关联容器.set/multiset会根据待定的排序准则,自动将元素排序.两者不同在于前者不允许元素重复,而后者允许. 1) 不能直接改变元素值,因为那样会打乱原本正确的顺序,要改变元素值必须先删除旧元素,则插入新元素 2) 不提供直接存取元素的任何操作函数,只能通过迭代器进行间接存取,而且从迭代器角度来看,元素值是常数 3) 元素比较动作只能用于型别相同的容器(即元素和排序准则必须相同) set模板原型://K

如何用SQL语句来判断已知表是否存在

如何判断库中已知表是否存在今日受人之托,帮他解决这个问题,代码为通常的引用Dao做的一模块: Function fExistTable(strTableName As String) As IntegerDim db As DatabaseDim i As Integer Set db = DBEngine.Workspaces(0).Databases(0) fExistTable = False db.TableDefs.Refresh For i = 0 To db.TableDefs.C

百度地图 js 通过IP定位城市后,已知一个坐标集合,根据每个坐标添加标注点,求大神help me

问题描述 百度地图 js 通过IP定位城市后,已知一个坐标集合,根据每个坐标添加标注点,求大神help me var myCity = new BMap.LocalCity(); // 以当前IP定位到城市 myCity.get(myFun); // 根据IP对当前城市进行定位 function myFun(result){ var center = result.center; // 城市坐标中心点 var point = new BMap.Point(center.lng,center.la

NokiaS40和S60开发平台1.0已知问题(翻译)

问题 NokiaS40和S60开发平台1.0已知问题(翻译) 作者:陈跃峰 出自:http://blog.csdn.net/mailbomb   1.  Nokia3300不支MMA(声音处理)类库. 2.  Image.getGraphics()方法在不同的软件版本中工作不同,该方法无法在新版本的7650.3650和N-Gage中正常工作.即这些机器中无法实现双缓冲技术. 3.  Nokia7650.3650和N-Gage,无法控制背景灯和震动. 4.  同时播放声音在S60模拟器上可以运行,

WCF技术剖析之十三:序列化过程中的已知类型(Known Type)

DataContractSerializer承载着所有数据契约对象的序列化和反序列化操作.在上面一篇文章(<数据契约(Data Contract)和数据契约序列化器(DataContractSerializer)>)中,我们谈到DataContractSerializer基本的序列化规则:如何控制DataContractSerializer序列化或者反序列化对象的数量:以及如何在序列化后的XML中保存被序列化对象的对象引用结构.在这篇文章中,我们会详细讨论WCF序列化中一个重要的话题:已知类型