commit eaedce39761f40acc377488dd1392bc5d658cd70 (tree)
parent e76efda4367c117cc302b20ecb1bb88740d1ca2a
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date: Wed, 19 May 2021 22:57:45 +0300
docs and inflections
Diffstat:
| M | tests.sql | | | 31 | +++++++++++++++++++++---------- |
| M | wm.sql | | | 61 | ++++++++++++++++++++++++++++++++++--------------------------- |
2 files changed, 55 insertions(+), 37 deletions(-)
diff --git a/tests.sql b/tests.sql
@@ -16,8 +16,9 @@ create table figures (name text, way geometry);
insert into figures (name, way) values ('fig3',ST_GeomFromText('LINESTRING(0 0,12 0,13 4,20 2,20 0,32 0,33 10,38 16,43 15,44 10,44 0,60 0)'));
insert into figures (name, way) values ('fig3-1',ST_GeomFromText('LINESTRING(0 0,12 0,13 4,20 2,20 0,32 0,33 10,38 16,43 15,44 10,44 0)'));
insert into figures (name, way) values ('fig5',ST_GeomFromText('LINESTRING(0 39,19 52,27 77,26 104,41 115,49 115,65 103,65 75,53 45,63 15,91 0,91 0)'));
-insert into figures (name, way) values ('inflection-1',ST_GeomFromText('LINESTRING(100 14,114 20,133 20,145 15,145 0,136 5,123 7,114 7,111 2)'));
+insert into figures (name, way) values ('inflection-1',ST_GeomFromText('LINESTRING(110 24,114 20,133 20,145 15,145 0,136 5,123 7,114 7,111 2)'));
+-- `bends` is for manual inspection using, say, qgis
drop table if exists bends;
create table bends (way geometry);
insert into bends select unnest(detect_bends((select way from figures where name='fig3')));
@@ -26,17 +27,27 @@ insert into bends select unnest(detect_bends((select way from figures where name
do $$
declare
- bends geometry[];
+ vbends geometry[];
begin
- select detect_bends((select way from figures where name='fig3')) into bends;
- perform assert_equals(5, array_length(bends, 1));
- perform assert_equals('LINESTRING(0 0,12 0,13 4)', st_astext(bends[1]));
- perform assert_equals('LINESTRING(12 0,13 4,20 2,20 0)', st_astext(bends[2]));
- perform assert_equals('LINESTRING(20 2,20 0,32 0,33 10)', st_astext(bends[3]));
- perform assert_equals('LINESTRING(32 0,33 10,38 16,43 15,44 10,44 0)', st_astext(bends[4]));
+ -- DETECT BENDS
+ select detect_bends((select way from figures where name='fig3')) into vbends;
+ perform assert_equals(5, array_length(vbends, 1));
+ perform assert_equals('LINESTRING(0 0,12 0,13 4)', st_astext(vbends[1]));
+ perform assert_equals('LINESTRING(12 0,13 4,20 2,20 0)', st_astext(vbends[2]));
+ perform assert_equals('LINESTRING(20 2,20 0,32 0,33 10)', st_astext(vbends[3]));
+ perform assert_equals('LINESTRING(32 0,33 10,38 16,43 15,44 10,44 0)', st_astext(vbends[4]));
perform assert_equals(4, array_length(detect_bends((select way from figures where name='fig3-1')), 1));
- select detect_bends((select way from figures where name='fig5')) into bends;
- perform assert_equals(3, array_length(bends, 1));
+ select detect_bends((select way from figures where name='fig5')) into vbends;
+ perform assert_equals(3, array_length(vbends, 1));
+
+ -- FIX BEND INFLECTIONS
+ select detect_bends((select way from figures where name='inflection-1')) into vbends;
+
+ drop table if exists inflections;
+ create table inflections (way geometry);
+ --insert into inflections select unnest(fix_gentle_inflections(vbends));
+ select fix_gentle_inflections(vbends);
+
end $$ language plpgsql;
diff --git a/wm.sql b/wm.sql
@@ -73,19 +73,21 @@ $$ language plpgsql;
--
-- The text does not specify how many vertices can be "adjusted"; it can
-- equally be one or many. This function is adjusting many, as long as the
--- commulative inflection angle is less than pi/6 (30 deg).
+-- commulative inflection angle small (see variable below).
create or replace function fix_gentle_inflections(INOUT bends geometry[]) as $$
declare
- prev_bend geometry;
- bend geometry;
- p geometry;
- p1 geometry;
- p2 geometry;
- p3 geometry;
+ small_angle real;
+ phead geometry; -- head point of head bend
+ ptail geometry[]; -- 3 head points of tail bend
+ i int4; -- bends[i] is the current head
begin
- foreach bend in array bends loop
- if prev_bend is null then
- prev_bend = bend;
+ -- the threshold when the angle is still "small", so gentle inflections can
+ -- be joined
+ small_angle := radians(30);
+
+ <<bend_loop>>
+ for i in select generate_subscripts(bends, 1) loop
+ if i = 1 then
continue;
end if;
@@ -101,31 +103,36 @@ begin
--
-- Assume this curve (figure `inflection-1`):
--
- -- A______B
- -- ---' `-------. C
- -- |
- -- G___ F |
- -- / `-----.____+ D
- -- E
+ -- \______B
+ -- A `-------. C
+ -- |
+ -- G___ F |
+ -- / `-----.____+ D
+ -- E
--
-- After processing the curve following the definition of a bend, the bend
-- [A-E] would be detected. Assuming inflection point E and F are "small",
-- the bend needs to be extended by two edges to [A,G].
- --
- -- Assuming the direction in this example is clock-wise, the first set of
- -- `p` variables will be: p1=C, p2=B, p3=A.
- for p in (select geom from st_dumppoints(prev_bend) order by path[1] desc) loop
- p3 = p2;
- p2 = p1;
- p1 = p;
- if p3 is null then
- continue;
+ select geom from st_dumppoints(bends[i]) order by path[1] desc limit 1 into phead;
+ while true loop
+ -- copy last 3 points of bends[i-1] (tail) to ptail
+ select array_agg(geom) from st_dumppoints(bends[i-1]) order by path[1] desc limit 3 into ptail;
+
+ -- if inflection angle between ptail[1:3] "large", stop processing this bend
+ if abs(st_angle(ptail[1], ptail[2], ptail[2], ptail[3]) - pi) > small_angle then
+ exit bend_loop;
+ end if;
+
+ -- distance from last vertex should be larger than second-last vertex
+ if st_distance(phead, ptail[2]) < st_distance(phead, ptail[3]) then
+ exit bend_loop;
end if;
- -- (p2, p1) is shared with the current bend.
+ -- detected a gentle inflection. Move head of the tail to the tail of head
+ bends[i] = st_addpoint(bends[i], ptail[3]);
+ bends[i-1] = st_removepoint(bends[i-1], st_npoints(bends[i-1])-1);
end loop;
- prev_bend = bend;
end loop;
end
$$ language plpgsql;