commit 7a7c0ad72b7ecebd316959dd652a5a6349c627a7 (tree)
parent 192a19ba280355934756fec54f7e8c116f83dd52
Author: Motiejus Jakštys <motiejus@uber.com>
Date: Thu, 15 Apr 2021 14:12:18 +0300
self-crossing bugfix
Diffstat:
3 files changed, 57 insertions(+), 35 deletions(-)
diff --git a/IV/notes.txt b/IV/notes.txt
@@ -52,6 +52,20 @@ To:
But perhaps it doesn't look quite as natural. I will trust the original
article to do the right thing here and remove the bend altogether.
+ALSO: the bends should be iterated from different directions:
+
+for i := 0; i < len(bends); i++ {
+ for j := 0; j < i; j++ {
+ ...
+ }
+ for j := len(bends); j > i; j-- {
+ ...
+ }
+}
+
+So if there are multiple bends between the baseline, they will be cut
+correctly.
+
The Context of a Bend
---------------------
diff --git a/IV/tests.sql b/IV/tests.sql
@@ -53,7 +53,9 @@ insert into wm_figures (name, way) values ('inflection-1',ST_GeomFromText('LINES
insert into wm_figures (name, way) values ('multi-island',ST_GeomFromText('MULTILINESTRING((-15 10,-10 10,-5 11,0 11,5 11,10 10,11 9,13 10,15 9),(-5 11,-2 15,0 16,2 15,5 11))'));
-- TODO: there is a bug and it does not go through `self_crossing` function.
---insert into wm_figures (name, way) values ('selfcrossing-1',ST_GeomFromText('LINESTRING(-27 180,-20 166,-21 142,-18 136,55 136,55 136,71 145,44 165,37 146,22 145,14 164,11 164,3 146,-12 146,-13 176,-18 184)'));
+insert into wm_figures (name, way) values ('selfcrossing-1',ST_GeomFromText('LINESTRING(-27 180,-20 166,-21 142,-18 136,55 136,55 136,71 145,44 165,37 146,22 145,14 164,11 164,3 146,-12 146,-13 176,-18 184)'));
+insert into wm_figures (name, way) values ('selfcrossing-1-rev',ST_Reverse(ST_Translate((select way from wm_figures where name='selfcrossing-1'), 60, 0)));
+
-- Run ST_SimplifyWM in debug mode, so `wm_debug` is populated. That table
-- is used for geometric assertions later in the file.
diff --git a/IV/wm.sql b/IV/wm.sql
@@ -236,12 +236,37 @@ begin
-- go through each bend in the given line, and see if has a potential to
-- cross bends[i].
- j = 0;
- while j < array_length(bends, 1) loop
- j = j + 1;
- continue when i = j;
+ for j in 1..i-1 loop
+ a = st_pointn(bends[i], 1);
+ b = st_pointn(bends[i], -1);
+ multi = st_split(bends[j], st_makeline(a, b));
+ continue when st_numgeometries(multi) = 1;
+ continue when st_numgeometries(multi) = 2 and
+ (st_contains(bends[j], a) or st_contains(bends[j], b));
+
+ -- vertices, segments and stars are aligned, we are changing the bend
+ mutated = true;
+
+ -- To understand the block below, I suggest you take a pencil and paper,
+ -- draw a self-crossing bend (fig6 from the article works well), and
+ -- figure out what happens here, by hand. I know it's hard to follow.
+ -- Apologies.
+ prev_length = array_length(bends, 1);
- -- do end vertices of bend[i] cross bend[j]?
+ -- remove first vertex of the following bend, because the last
+ -- segment is always duplicated with the i'th bend.
+ bends[i+1] = st_removepoint(bends[i+1], 0);
+ bends[j] = st_geometryn(multi, 1);
+ bends[j] = st_setpoint(
+ bends[j],
+ st_npoints(bends[j])-1,
+ st_pointn(bends[i], st_npoints(bends[i]))
+ );
+ bends = bends[1:j] || bends[i+1:prev_length];
+ exit;
+ end loop;
+
+ for j in reverse array_length(bends, 1)..i+1 loop
a = st_pointn(bends[i], 1);
b = st_pointn(bends[i], -1);
multi = st_split(bends[j], st_makeline(a, b));
@@ -257,35 +282,16 @@ begin
-- figure out what happens here, by hand. I know it's hard to follow.
-- Apologies.
prev_length = array_length(bends, 1);
- if j < i then
- -- remove first vertex of the following bend, because the last
- -- segment is always duplicated with the i'th bend.
- bends[i+1] = st_removepoint(bends[i+1], 0);
- bends[j] = st_geometryn(multi, 1);
- bends[j] = st_setpoint(
- bends[j],
- st_npoints(bends[j])-1,
- st_pointn(bends[i], st_npoints(bends[i]))
- );
- bends = bends[1:j] || bends[i+1:prev_length];
- j = i;
- else
- -- remove last vertex of the previous bend, because the last
- -- segment is duplicated with the i'th bend.
- bends[i-1] = st_removepoint(bends[i-1], st_npoints(bends[i-1])-1);
- -- continue debugging the selfcrossing-1 here.
- --raise notice 'previous bend: %', st_astext(bends[i-1]);
- --raise notice 'multi: %', st_astext(multi);
- --raise notice '2: removing first point from %', st_astext(st_geometryn(multi, st_numgeometries(multi)));
- --mutated = false;
- --return;
- bends[i] = st_makeline(
- st_pointn(bends[i], 1),
- st_removepoint(st_geometryn(multi, st_numgeometries(multi)), 0)
- );
- bends = bends[1:i] || bends[j+1:prev_length];
- end if;
- j = j - prev_length + array_length(bends, 1);
+ -- remove last vertex of the previous bend, because the last
+ -- segment is duplicated with the i'th bend.
+ bends[i-1] = st_removepoint(bends[i-1], st_npoints(bends[i-1])-1);
+ -- continue debugging the selfcrossing-1 here.
+ bends[i] = st_makeline(
+ st_pointn(bends[i], 1),
+ st_removepoint(st_geometryn(multi, st_numgeometries(multi)), 0)
+ );
+ bends = bends[1:i] || bends[j+1:prev_length];
+ exit;
end loop;
end loop;
end