I couldn't find correct answer and try to create function in PostGis which returned me polygon with geometry type. This function can be use for visualize cellular network topology on map. Below you can find this function for PostGis which is have next input parameters: lon , lat , azimuth , distance , width. distance - length of pie; width - width of pie.
create or replace function sector_3(lon float, lat float, azimuth float, distance integer, width integer)
returns geometry
language plpgsql
as
$$
declare
sector geometry;
begin
sector = ST_MakePolygon(ST_MakeLine(ARRAY[ST_SetSRID(ST_MakePoint(lon,lat),4326),
ST_Project(ST_SetSRID(ST_MakePoint(lon,lat),4326)::geography, distance, pi()*(azimuth-(width/2))/180.0)::geometry,
ST_Project(ST_SetSRID(ST_MakePoint(lon,lat),4326)::geography, distance, pi()*(azimuth-(width/2-1*(width/2/5)))/180.0)::geometry,
ST_Project(ST_SetSRID(ST_MakePoint(lon,lat),4326)::geography, distance, pi()*(azimuth-(width/2-2*(width/2/5)))/180.0)::geometry,
ST_Project(ST_SetSRID(ST_MakePoint(lon,lat),4326)::geography, distance, pi()*(azimuth-(width/2-3*(width/2/5)))/180.0)::geometry,
ST_Project(ST_SetSRID(ST_MakePoint(lon,lat),4326)::geography, distance, pi()*(azimuth-(width/2-4*(width/2/5)))/180.0)::geometry,
ST_Project(ST_SetSRID(ST_MakePoint(lon,lat),4326)::geography, distance, pi()*(azimuth)/180.0)::geometry,
ST_Project(ST_SetSRID(ST_MakePoint(lon,lat),4326)::geography, distance, pi()*(azimuth+(width/2-4*(width/2/5)))/180.0)::geometry,
ST_Project(ST_SetSRID(ST_MakePoint(lon,lat),4326)::geography, distance, pi()*(azimuth+(width/2-3*(width/2/5)))/180.0)::geometry,
ST_Project(ST_SetSRID(ST_MakePoint(lon,lat),4326)::geography, distance, pi()*(azimuth+(width/2-2*(width/2/5)))/180.0)::geometry,
ST_Project(ST_SetSRID(ST_MakePoint(lon,lat),4326)::geography, distance, pi()*(azimuth+(width/2-1*(width/2/5)))/180.0)::geometry,
ST_Project(ST_SetSRID(ST_MakePoint(lon,lat),4326)::geography, distance, pi()*(azimuth+(width/2))/180.0)::geometry,
ST_SetSRID(ST_MakePoint(lon,lat),4326)
]));
return sector;
end;
$$;
As a result you will see sector which starts from given point (lon, lat) and with given distance(length) and width.
You could simplify things a bit by first creating a buffer from the parameters distance
, lon
and lat
using ST_Buffer
, so that you already have the are you want covered. The second step would be to cut out the piece of the buffer you want, and you can do that using ST_Split
. The function ST_Split
expects a geometry and a blade to cut the geometry, and this blade can be created as a LineString based on the center point of the buffer (the reference coordinate pair), the azimuth
and the distance
, using ST_Project
. At this point you have two geometries - the area you want and the rest of the buffer - so you can use ST_GeometryN
to only return the area that interests you:
WITH j (geom,azimuth,distance,width) AS (
VALUES (ST_SetSRID(ST_MakePoint(38.94,45.05),4326),90,120,40)
)
SELECT
ST_GeometryN(
ST_Split(
ST_Buffer(geom::geography,distance)::geometry,
ST_MakeLine(ARRAY[
ST_Project(geom,distance+1,radians(azimuth-(width/2)))::geometry, geom,
ST_Project(geom,distance+1,radians(azimuth+(width/2)))::geometry]
)
),2)
FROM j;
Demo: db<>fiddle
To better illustrate the proposed solution the next query will depict the buffer, the projected points and the blade created based on them in three different CTEs.
WITH
original_values (geom,azimuth,distance,width) AS (
VALUES (ST_SetSRID(ST_MakePoint(38.94,45.05),4326),90,120,40)),
points (array_points) AS (
SELECT ARRAY[
ST_Project(geom,distance+1,radians(azimuth-(width/2)))::geometry, geom,
ST_Project(geom,distance+1,radians(azimuth+(width/2)))::geometry]
FROM original_values),
line (blade) AS (
SELECT ST_MakeLine(array_points)
FROM points),
area (buffer) AS (
SELECT ST_Buffer(geom::geography,distance)
FROM original_values
)
SELECT buffer FROM area
UNION
SELECT unnest(array_points) FROM points
UNION
SELECT blade FROM line;