But sometime having read, researched, experimented, and not found the right solution one can be forced to roll one’s own so to speak to get the job done.
For the problem below, if someone can point out a way to create what is needed using standard PostGIS API calls, then let me know.
The problem is this.
The customer wants to create transects along 20m segments chopped from a set of river centrelines.
For each 20m segment, a centroid must be created (at 10m), and an average bearing for the segment calculated from the first and last point.
A transect (straight line) must then be formed at the centroid with a direction at right angles to the segment bearing.
The transect must then be fitted inside a floodplain polygon so that it starts and ends by touching the boundary of the local part of the floodplain polygon.
The length of the created transect is compared to the intersection of the transect with a river polygon to compute a ratio of river width to floodplain width.
The floodplain polygon is very convoluted and extensive.
To be clear, what is not required is a set of homogeneous transects create from an envelope that covers the whole floodplain (whole to the part solution).
The required solution creates transects that are specific to river linestring segments that vary from segment to segment.
And for each of these, the transect must fit perfectly within that part of the floodplain polygon within which it resides, so that the transect line has its starting point touch one boundary, and its ending point to touch another.
So, the length of the transect varies for each and ever transect and its local area.
Techniques that guess a transect length using a width greater than the polygon are problematic as they can cross different parts of the polygon than the local area.
A solution therefore is needed that can compute/create a transect perfectly inside the local area.
While I tried many approaches (hoping not to write code), in the end I wrote a function called ST_InsideLine whose signature looks like this:
CREATEORREPLACEFUNCTION spdba.ST_InsideLine(
p_point IN geometry,
p_direction_start INNUMERIC,
p_direction_end INNUMERIC,
p_polygon IN geometry,
p_dIncrement INNUMERICDEFAULT5.0
)
RETURNS GEOMETRY
...
The function’s parameters are:
p_point (geometry) — Starting point which must fall inside p_polygon
p_direction_start (numeric) — Whole circle bearing in degrees defining direction of line from p_point to the start of the line
p_direction_end (numeric) — Whole circle bearing in degrees defining direction of line from p_point to the end of the line
p_polygon (geometry) — Polygon for which the inside line must be fitted.
p_dIncrement (numeric) — Line increment (distance) for incrementally extending a line, and testing line to find its boundary intersection point.
The function works as follows:
This function creates a line that lies inside p_polygon but whose start and end points touch p_polygon’s boundary.
Line is generated from a starting point and two bearings.
The algorithm first generates a line from the supplied point to the line’s start point by extending and testing the line by p_dIncrement until it finds a p_polygon boundary.
After finding point for first half of line, the second line is generated using p_direction_end.
If p_direction_end is null or the same as p_direction_start, a default direction of p_direction_start – 180.0 is used.
The algorithm uses a stepping approach: it first creates a line at p_direction_start for p_dIncrement distance. If the line does not touch a p_polygon boundary point it increases the line length by p_dIncrement and tests again.
The stepping process continues until the line touches or crosses the boundary.
Once the two halves are created, they are unioned together and the resulting line returned.
Here is an picture of the solution for a test polygon.
The following example shows how, by varying the bearings so they are different from each other, the function can create “bent” linestrings. Here is an example:
Comment