I need an algorithm where I can check if a point falls within a polygon within a small tolerance (meaning the point is completely within the polygon or sufficiently close to the border). To implement this, I was planning on using the st_scale
function to expand the polygon by a factor, then check the point with st_within
. Note that I can't use st_buffer
because st_buffer
expects an absolute radius of the buffer but I need a relative radius (ex. Determine if the point is within the polygon or within the polygon that has been scaled up by 5%).
To accomplish this, I've written the following tester code. I take a polygon, scale it up by 5%, and then test to see if the original polygon's centroid falls within the scaled-up polygon:
SELECT ST_within(
st_centroid(polygon),
st_scale(
polygon,
'POINT(1.05 1.05)'::geometry,
st_centroid(polygon)
));
However, sometimes this function fails for no apparent reason (meaning it says the polygon's centroid is not within the scaled-up polygon) and I have no idea why. This feels like it's buggy, but I can't imagine I've found a bug in postGIS.
Passing testcases:
-- drawing a 1x1 box at the origin of the x-y plane
SELECT ST_Within(
st_centroid('MULTIPOLYGON(((0 0, 1 0, 1 1, 0 1, 0 0)))'::geometry),
st_scale(
'MULTIPOLYGON(((0 0, 1 0, 1 1, 0 1, 0 0)))'::geometry,
'POINT(1.05 1.05)'::geometry,
st_centroid('MULTIPOLYGON(((0 0, 1 0, 1 1, 0 1, 0 0)))'::geometry))
);
-- box in the first quadrant at an origin of (10, 10)
SELECT ST_Within(
st_centroid('MULTIPOLYGON(((10 10, 11 10, 11 11, 10 11, 10 10)))'::geometry),
st_scale(
'MULTIPOLYGON(((10 10, 11 10, 11 11, 10 11, 10 10)))'::geometry,
'POINT(1.05 1.05)'::geometry,
st_centroid('MULTIPOLYGON(((10 10, 11 10, 11 11, 10 11, 10 10)))'::geometry))
);
Failing testcase:
-- 1x1 box with the bottom left corner at (98, 28)
SELECT ST_within(
st_centroid('MULTIPOLYGON(((98 28,99 28,99 29,98 29,98 28)))'::geometry),
st_scale(
'MULTIPOLYGON(((98 28,99 28,99 29,98 29,98 28)))'::geometry,
'POINT(1.05 1.05)'::geometry,
st_centroid('MULTIPOLYGON(((98 28,99 28,99 29,98 29,98 28)))'::geometry))
);
Interestingly, though, casting the scaled shape to WKT and then back to a geometry DOES work.
-- 1x1 box with the bottom left corner at (98, 28)
SELECT ST_within(
st_centroid('MULTIPOLYGON(((98 28,99 28,99 29,98 29,98 28)))'::geometry),
st_geomfromewkt(st_asewkt(st_scale(
'MULTIPOLYGON(((98 28,99 28,99 29,98 29,98 28)))'::geometry,
'POINT(1.05 1.05)'::geometry,
st_centroid('MULTIPOLYGON(((98 28,99 28,99 29,98 29,98 28)))'::geometry))))
);
So, yeah, what is going on here???? Have I found a bug in PostGIS?