| 1 | CREATE OR REPLACE FUNCTION public.build_sector_coverage(
|
|---|
| 2 | p_center geometry(Point, 4326),
|
|---|
| 3 | p_azimuth double precision,
|
|---|
| 4 | p_beamwidth double precision,
|
|---|
| 5 | p_radius_m double precision,
|
|---|
| 6 | p_arc_segments integer DEFAULT 16
|
|---|
| 7 | )
|
|---|
| 8 | RETURNS geometry(Polygon, 4326)
|
|---|
| 9 | LANGUAGE plpgsql
|
|---|
| 10 | IMMUTABLE
|
|---|
| 11 | STRICT
|
|---|
| 12 | AS $$
|
|---|
| 13 | DECLARE
|
|---|
| 14 | ring_points geometry[] := ARRAY[p_center];
|
|---|
| 15 | angle_degrees double precision;
|
|---|
| 16 | i integer;
|
|---|
| 17 | BEGIN
|
|---|
| 18 | IF p_azimuth < 0 OR p_azimuth >= 360 THEN
|
|---|
| 19 | RAISE EXCEPTION 'Azimuth must be between 0 and 359 degrees';
|
|---|
| 20 | END IF;
|
|---|
| 21 |
|
|---|
| 22 | IF p_beamwidth <= 0 OR p_beamwidth > 360 THEN
|
|---|
| 23 | RAISE EXCEPTION 'Beamwidth must be between 1 and 360 degrees';
|
|---|
| 24 | END IF;
|
|---|
| 25 |
|
|---|
| 26 | IF p_radius_m <= 0 THEN
|
|---|
| 27 | RAISE EXCEPTION 'Coverage radius must be positive';
|
|---|
| 28 | END IF;
|
|---|
| 29 |
|
|---|
| 30 | IF p_arc_segments < 4 OR p_arc_segments > 72 THEN
|
|---|
| 31 | RAISE EXCEPTION 'Arc segments must be between 4 and 72';
|
|---|
| 32 | END IF;
|
|---|
| 33 |
|
|---|
| 34 | IF p_beamwidth = 360 THEN
|
|---|
| 35 | RETURN ST_Buffer(p_center::geography, p_radius_m)::geometry;
|
|---|
| 36 | END IF;
|
|---|
| 37 |
|
|---|
| 38 | FOR i IN 0..p_arc_segments LOOP
|
|---|
| 39 | angle_degrees := p_azimuth - (p_beamwidth / 2.0)
|
|---|
| 40 | + (p_beamwidth * i / p_arc_segments);
|
|---|
| 41 | ring_points := array_append(
|
|---|
| 42 | ring_points,
|
|---|
| 43 | ST_Project(
|
|---|
| 44 | p_center::geography,
|
|---|
| 45 | p_radius_m,
|
|---|
| 46 | radians(angle_degrees)
|
|---|
| 47 | )::geometry
|
|---|
| 48 | );
|
|---|
| 49 | END LOOP;
|
|---|
| 50 |
|
|---|
| 51 | ring_points := array_append(ring_points, p_center);
|
|---|
| 52 | RETURN ST_ForcePolygonCCW(ST_MakePolygon(ST_MakeLine(ring_points)));
|
|---|
| 53 | END;
|
|---|
| 54 | $$;
|
|---|
| 55 |
|
|---|
| 56 | COMMENT ON FUNCTION public.build_sector_coverage IS
|
|---|
| 57 | 'Builds a directional coverage wedge from a site point and sector settings.';
|
|---|