From 87849132d1006d0b21563a7823ecd9a67ad0cb6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Wed, 19 May 2021 22:57:45 +0300 Subject: [PATCH] more self-crossing and documentation --- notes.txt | 45 +++++++++++++++++++++++++++++++++++++-------- tests.sql | 2 +- wm.sql | 27 ++++++++++++++------------- 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/notes.txt b/notes.txt index 90f5a39..c7655c9 100644 --- a/notes.txt +++ b/notes.txt @@ -1,14 +1,22 @@ -Definition of a bend: ends of the line should always be bends, otherwise not +Definition of a bend +-------------------- + +Ends of the line should always be bends, otherwise not all line vertices are covered by bends (definition elsewhere). -Gentle inflection at the end of the bend: the article does not specify how many -vertices should be included when calculating the end-of-bend inflection. We -chose the iterative approach -- as long as the angle is "right" and the -distance is (greedily) decreasing, keep going. +Gentle inflection at the end of the bend +---------------------------------------- -Self-line crossing when cutting a bend: the self-line-crossing may happen -after a few bends have been skipped. E.g. ends of A<->B cross the line, but -"swallow" a few more in between: +The article does not specify how many vertices should be included when +calculating the end-of-bend inflection. We chose the iterative approach -- as +long as the angle is "right" and the distance is (greedily) decreasing, keep +going. + +Self-line crossing when cutting a bend +-------------------------------------- + +The self-line-crossing may happen after a few bends have been skipped. E.g. +ends of A<->B cross the line, but "swallow" a few more in between: ,______ / \ @@ -36,3 +44,24 @@ 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 intersects with AB. Some intersections may be missed (see the last example), but they will be eliminated by joining A and B anyway. + +Also, there is another way to remove self-crossing, without removing most of +the bend. E.g. from: + + +\ \ +B\ | __ + | | / \ + | |____/A | + \__________| + +To: + +\ \_ +B\ `-,_.__ + | A' \ + | | + \__________| + +But perhaps it doesn't look quite as natural. I will trust the original +article to do the right thing here. diff --git a/tests.sql b/tests.sql index 228e2fc..c9b4c92 100644 --- a/tests.sql +++ b/tests.sql @@ -18,7 +18,7 @@ insert into figures (name, way) values ('fig3',ST_GeomFromText('LINESTRING(0 0,1 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)')); insert into figures (name, way) values ('fig6',ST_GeomFromText('LINESTRING(84 47,91 59,114 64,122 80,116 92,110 93,106 106,117 118,136 107,135 76,120 45,125 39,141 39,147 32)')); -insert into figures (name, way) values ('fig6-rev',st_reverse(st_translate((select way from figures where name='fig6'), 80, 0))); +insert into figures (name, way) values ('fig6-rev',ST_Reverse(ST_Translate((select way from figures where name='fig6'), 80, 0))); 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)')); -- DETECT BENDS diff --git a/wm.sql b/wm.sql index b115070..52a257e 100644 --- a/wm.sql +++ b/wm.sql @@ -191,28 +191,29 @@ begin p2 = p1; p1 = p0; continue when p3 is null; - angle = angle + abs(pi - st_angle(p1, p2, p3)); end loop; continue when abs(angle) <= pi; - -- sum of inflection angles for this bend is >180, so it may be self-crossing. - -- now try to find another bend in this line that crosses this one. + -- sum of inflection angles for this bend is >180, so it may be + -- self-crossing. now try to find another bend in this line that + -- crosses an imaginary line of end-vertices p0 = st_pointn(bends[i], 1); p1 = st_pointn(bends[i], -1); - -- go through each bend in this line, and see if has a potential to cross bends[i]. - -- optimization: we care only about bends which beginning and end start at different - -- sides of the plane, separated by endpoints p0 and p1. + -- go through each bend in the given line, and see if has a potential to + -- cross bends[i]. optimization: we care only about bends which beginning + -- and end start at different sides of the plane, separated by endpoints + -- p0 and p1. for j in 1..array_length(bends, 1) loop continue when i = j; p2 = st_pointn(bends[j], 1); p3 = st_pointn(bends[j], -1); - -- are p2 and p3 on the same side of (p0,p1)? vector multiplication - -- https://stackoverflow.com/questions/1560492/ + -- are p2 and p3 on the different sides of line(p0,p1)? vector + -- multiplication; https://stackoverflow.com/questions/1560492/ s2 = (st_x(p0)-st_x(p1)*(st_y(p2)-st_y(p1))-(st_y(p0)-st_y(p1))*(st_x(p2)-st_x(p1))); s3 = (st_x(p0)-st_x(p1)*(st_y(p3)-st_y(p1))-(st_y(p0)-st_y(p1))*(st_x(p3)-st_x(p1))); continue when sign(s2) = sign(s3); @@ -222,16 +223,16 @@ begin multi = st_split(bends[j], this); continue when st_numgeometries(multi) = 1; - -- self-crossing detected! + -- real self-crossing detected! Remove it. -- if j < i: -- bends[j] = multi[1][1...n-1]; that will have all the vertices of bends[j], - -- except the crossing itself. + -- except the crossing and what comes after it. -- bends[j] = append(bends[j], bends[i][-1]) -- remove bends from bends[j+1] to bends[i] inclusive. -- elif j > i: - -- remove bends from bends[i+1] to bends[j-1] inclusive. - -- bends[j] = multi[2][2..n] - -- bends[i] + -- bends[i] = bends[i][1] + -- bends[i] = append(bends[i], multi[2][2..n]) + -- remove bends from bends[i+1] to bends[j] inclusive. end loop;