【问题标题】:Create area that cell tower covers创建手机信号塔覆盖的区域
【发布时间】:2021-01-09 12:33:51
【问题描述】:

我有一个包含手机信号塔信息的数据集,如下所示。 lat 和 lon 字段是塔的位置。

目标是获取蜂窝塔覆盖的扇区的面积(几何形状),从 start_angle 到 end_angle。如下图所示,以数据集的第一行为例,我可以从 start_angle 275 和 end_angle 35 获取行,但我希望缓冲区的其余部分消失。

使用的查询:

第一个查询用于创建和旋转从 start_angle 和 end_angle 开始的线以及 0 度的线。

WITH vertices AS
(SELECT 
      id,
 start_angle,
 end_angle,
      (ST_DumpPoints(geom)).path[1] AS v_id, 
      (ST_DumpPoints(geom)).geom AS vertex
FROM celulas
), teste as
(SELECT
    id,
    v_id,
    ST_SetSRID(ST_Translate(ST_Rotate(ST_MakeLine(ST_MakePoint( 1.0,0.0), 
                                                  ST_MakePoint(-1.0,0.0)),
                                      radians(start_angle * -1)), ST_X(vertex), ST_Y(Vertex)),
                                      ST_SRID(vertex)) AS startline,
    ST_SetSRID(ST_Translate(ST_Rotate(ST_MakeLine(ST_MakePoint( 1.0,0.0), 
                                                  ST_MakePoint(-1.0,0.0)),
                                      radians(end_angle * -1)), ST_X(vertex), ST_Y(Vertex)),
                                      ST_SRID(vertex)) AS endline,
    ST_SetSRID(ST_Translate(ST_Rotate(ST_MakeLine(ST_MakePoint( 1.0,0.0), 
                                                  ST_MakePoint(-1.0,0.0)),
                                      radians(0)), ST_X(vertex), ST_Y(Vertex)),
                                      ST_SRID(vertex)) AS midline
    
FROM vertices
)

我还使用下一个查询来合并所有几何图形:半径缓冲区和线条

select St_intersection(st_split(buffer, midline), st_split(buffer, angulo))
from angulo

【问题讨论】:

  • 你好。 “我希望缓冲区的其余部分消失”到底是什么意思?
  • 你好。正如您在图像中看到的那样,我拥有手机信号塔的整个半径。但我只想显示从 start_angle 到 end_angle 的扇区,即从 275 度到 35 度。圆的其余部分无关紧要。
  • 好的。您能否将用于创建此几何/缓冲区的查询添加到您的问题中?

标签: postgresql postgis spatial-query


【解决方案1】:

让我们专门为您的关系创建一个方便的inline function on the composite type

此外,首先,让我们为这种上下文中的各种用例创建两个同样方便的支持函数;获得 顺时针 (CW) (以及,因为我们在它,还有 逆时针 (CW))两个方位角之间的角度差异:

CREATE OR REPLACE FUNCTION CWAngle(
  IN    sdeg FLOAT,
  IN    edeg FLOAT,
  OUT   ddeg  FLOAT
) LANGUAGE SQL AS
  $$
    SELECT CASE (sdeg <= edeg)
             WHEN TRUE THEN
               edeg - sdeg
             ELSE
               360.0 - sdeg + edeg
           END;
  $$
;

CREATE OR REPLACE FUNCTION CCWAngle(
  IN    sdeg FLOAT,
  IN    edeg FLOAT,
  OUT   ddeg  FLOAT
) LANGUAGE SQL AS
  $$
    SELECT 360.0 - CWAngle(sdeg, edeg);
  $$
;

可能有也可能没有更有效的方法,或者更惯用的代码;这很好用。

现在,以下函数的概念是通过将中心点沿start_angleend_angle 之间的圆弧投影到给定的"radius" 处来创建一个圆的“楔形”,即您的扇区;我们将投影&lt;degrees_between_angles&gt;/FLOOR(&lt;degrees_between_angles&gt;) 点,因此每个1 &lt;= step &lt; 2stepdegrees(很多;ST_Buffer 默认为每四分之一圆有 8 个顶点的圆):

CREATE OR REPLACE FUNCTION sector(
    rec spatial.celulas
) RETURNS GEOMETRY(POLYGON, 4236) AS
  $$
    DECLARE
      delta FLOAT := CWAngle(rec.start_angle, rec.end_angle);
      step  FLOAT := delta / FLOOR(delta);
      
      wedge GEOMETRY(POINT)[];
      
    BEGIN
      wedge := wedge || ST_SetSRID(ST_MakePoint(rec.lon, rec.lat), 4326);
  
      FOR n IN 0..FLOOR(delta)
        LOOP
          wedge := wedge || ST_Project(wedge[1]::GEOGRAPHY, rec."radius", RADIANS(MOD(rec.start_angle+(n*step)::NUMERIC, 360.0::NUMERIC)))::GEOMETRY;
        END LOOP
      ;
  
      wedge := wedge || wedge[1];
      
      RETURN ST_MakePolygon(ST_SetSRID(ST_MakeLine(wedge), 4326));
    END;
  $$
LANGUAGE 'plpgsql';

假设

  • CWAngle 函数存在;如果需要,请在此函数中更改为 CCWAngle
  • start_angle -> end_angle顺时针方向
  • "radius"
  • 您的示例的确切关系和列名,即celulas.lat, celulas.lon, celulas."radius", celulas.start_angle, celulas.end_angle;如果它们实际上不同,则需要相应地更改函数中这些标识符的所有出现

因此,此函数特定于您示例中的关系,您可以将其称为关系限定列

SELECT [*,] celulas.sector AS geom
FROM   celulas
;

或者,here is a more general function 基于相同的概念,还允许设置每四分之一圆的最大顶点数和可选的内半径。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多