beginnings of self-crossing

This commit is contained in:
Motiejus Jakštys 2021-03-02 14:54:44 +02:00
parent 28bad3583f
commit f26073151b
3 changed files with 40 additions and 8 deletions

View File

@ -27,13 +27,12 @@ after a few bends have been skipped. E.g. ends of A<->B cross the line, but
If a bend with 180+ deg inflection is found, its line between inflection angles If a bend with 180+ deg sum of inflection angles is found, its line between
(AB in our examples) must be crossed with all the other bends to detect a inflection angles (AB in our examples) must be crossed with all the other bends
possible line-crossing. This is O(N*M), where N is the total number of line to detect a possible line-crossing. This is O(N*M), where N is the total number
segments, and M is the number of qualifying bends. In other words, can be very of line segments, and M is the number of qualifying bends. It is expensive.
computationally expensive.
This may be simplified: if other bend's endpoints (A' and B') are in the same This may be simplified: if other bend's endpoints (A' and B') are in the same
sub-plane as divided by AB, then the bend can be skipped from checking if it sub-plane as divided by AB, then the bend can be skipped from checking if it
intersects with AB. Some intersections may be missed (see the example), but intersects with AB. Some intersections may be missed (see the last example),
they will be eliminated by just joining A and B. but they will be eliminated by joining A and B anyway.

View File

@ -47,7 +47,7 @@ drop table if exists inflections, demo_inflections;
create table inflections (name text, ways geometry[]); create table inflections (name text, ways geometry[]);
insert into inflections select name, fix_gentle_inflections(ways) from bends; insert into inflections select name, fix_gentle_inflections(ways) from bends;
create table demo_inflections (name text, i bigint, way geometry); create table demo_inflections (name text, i bigint, way geometry);
insert into demo_inflections select a.name, generate_subscripts(a.ways, 1), unnest(a.ways) from inflections a; insert into demo_inflections select name, generate_subscripts(ways, 1), unnest(ways) from inflections;
do $$ do $$
declare declare
@ -67,3 +67,10 @@ begin
perform assert_equals('LINESTRING(114 20,133 20,145 15,145 0,136 5,123 7,114 7)', st_astext(vinflections[2])); perform assert_equals('LINESTRING(114 20,133 20,145 15,145 0,136 5,123 7,114 7)', st_astext(vinflections[2]));
perform assert_equals('LINESTRING(123 7,114 7,111 2)', st_astext(vinflections[3])); perform assert_equals('LINESTRING(123 7,114 7,111 2)', st_astext(vinflections[3]));
end $$ language plpgsql; end $$ language plpgsql;
-- SELF-LINE CROSSING
drop table if exists selfcrossing, demo_selfcrossing;
create table selfcrossing (name text, ways geometry[]);
insert into selfcrossing select name, self_crossing(ways) from inflections;
create table demo_selfcrossing (name text, i bigint, way geometry);
insert into demo_selfcrossing select name, generate_subscripts(ways, 1), unnest(ways) from selfcrossing;

View File

@ -170,9 +170,35 @@ $$ language plpgsql;
create or replace function self_crossing(INOUT bends geometry[]) as $$ create or replace function self_crossing(INOUT bends geometry[]) as $$
declare declare
pi real; pi real;
angle real;
p geometry;
p1 geometry;
p2 geometry;
p3 geometry;
bend geometry;
begin begin
pi = radians(180);
-- go through the bends and find one where sum of inflection angle is >180
foreach bend in array bends loop
angle = 0;
p3 = null;
p2 = null;
p1 = null;
for p in (select geom from st_dumppoints(bend) order by path[1] asc) loop
p3 = p2;
p2 = p1;
p1 = p;
if p3 is null then
continue;
end if;
angle = angle + abs(pi - st_angle(p1, p2, p3));
end loop;
if abs(angle) > pi then
raise notice 'maybe self-crossing bend %: %', st_astext(bend), round(degrees(abs(angle)));
end if;
end loop;
end end
$$ language plpgsql; $$ language plpgsql;