self-crossing bugfix

main
Motiejus Jakštys 2021-05-19 22:57:47 +03:00 committed by Motiejus Jakštys
parent 9f717f1e3a
commit d390d373a9
3 changed files with 58 additions and 36 deletions

View File

@ -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
---------------------

View File

@ -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.

76
wm.sql
View File

@ -236,12 +236,7 @@ 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;
-- do end vertices of bend[i] cross bend[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));
@ -257,35 +252,46 @@ 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 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));
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);
-- 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