Monday, 6 July 2015

buffer - What is the width of the beach of a little island polygon?


This is a "classic" problem, that have no practical utility (see note-1 for applications), but illustrate another GIS problems...


little island figure


We can do some approximations to modeling the situation,




  • the real center (coconut) is not at the ST_Centroid point, but can be approximated to;

  • the real shape (a island) is not a circle, neither a square, they are optional references.


So, translating the question to an equation, and using OGC standard functions... "What is the value of w?" at the equation


ST_Area(ST_Buffer(ST_Centroid(littleIsland), w, quad_segs)) = ST_Area(littleIsland)

When quad_segs=1, the reference is a square, when quad_segs>=8 the reference is near to a circle (see examples of generated polygons).




NOTE-1: For understand this problem into a context of applications, see "Is there a st_buffer inverse function, that returns a width estimation?" and see "How to fit a polygon to a “best buffer” about a reference geometry in it?".



NOTE-2: the "inverse function" is so general and complex, because can operates with point, line and polygon inputs. Here we can discuss the simplest case, when the input is like a point, with no area or length.



Answer



I am using this function to solve the problem, but not have any source/reference (do you have? please inform posting a comment)... So, I posted also demonstrations and tests.


CREATE FUNCTION pointbuffer_width(g geometry, N integer DEFAULT 8) RETURNS float AS $$
-- Returns the value of W in the approximation "g ~ ST_Buffer(ST_Centroid(g),W,'quad_segs=N')"
-- where N>0 indicates the reference-shape, 1=square, 2=heptagon, ... circle.
--
SELECT sqrt( area/(0.5*n*sin(2*pi()/n)) )
FROM ( SELECT ST_Area($1) as area,
(CASE WHEN $2<=1 THEN 4 ELSE 4*$2 END)::float as n

) as t;
$$ LANGUAGE SQL immutable;



DEMONSTRATING


The main shapes, circle and square, have areas


A = pi*w^2   # circle with radius w
A = 2*w^2 # square circumscribed into a circle of radius w

The intermediary shapes are the regular polygons of n sides. The square have n=4, the octagon n=8, etc. So, we can substitute the factor of w^2 by a function f(n) that supply the adequate value for the n sides. The formula of the area of a regular polygon of n sides with a circumradius w, is:



 A = 0.5*n*sin(2*pi/n)*w^2

Where we can check: for n=4 the factor 0.5*n*sin(2*pi/n) is 2; for n=400 (infinite) is 3.14 (~pi).


For the standard ST_Buffer(g,'quad_segs=N') polygon generator we can check that this N is 4*n.


different buffers


Confirmation of N=4*n with PostGIS:


SELECT ST_AsEWKT((p_geom).geom) As geom_ewkt
FROM (SELECT ST_DumpPoints(
ST_Buffer(ST_GeomFromText('POINT(100 90)'),50,'quad_segs=5')
) AS p_geom ) AS t;


It returns 4+1 rows when N=1, 20+1 rows when N=5, etc. The dumped last row repeat the first, to close the polygon.


TESTING


Tests simulating buffers (need more tests with irregular ones)


-- FORMULA TESTER FOR POINTS AND ITS BUFFERS:
SELECT w,
(array['square','octagon','','','','','','~circle'])[shape] as shape,
round(pointbuffer_width(circle8,shape),1) as circle8,
round(pointbuffer_width(octagon,shape),1) as octagon,
round(pointbuffer_width(square,shape),1) as square

FROM (
SELECT
w, shape, -- 1, 2, 3 or 10
ST_Buffer(g, w) as circle8, -- default 8, use 20 for perfect circle
ST_Buffer(g, w, 'quad_segs=2') as octagon,
ST_Buffer(g, w, 'quad_segs=1') as square
FROM ( SELECT ST_GeomFromText('POINT(100 90)') as g,
unnest(array[1.0,150.0]) as w,
unnest(array[1,2,8]) as shape
) as t

) as t2;

RESULTS:


   w   |  shape  | circle8 | octagon | square 
-------+---------+---------+---------+--------
1.0 | square | 1.2 | 1.2 | *1
150.0 | octagon | 157.6 | *150 | 126.1
1.0 | ~circle | *1 | 1 | 0.8
150.0 | square | 187.4 | 178.4 | *150
1.0 | octagon | 1.1 | *1 | 0.8

150.0 | ~circle | *150 | 142.8 | 120.1

Conclusion: it is stable for any w value (!); it is exact when the modeled shape fits the geometry shape (*).


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...