diff --git a/IV/mj-msc.tex b/IV/mj-msc.tex index f1822be..f16cc06 100644 --- a/IV/mj-msc.tex +++ b/IV/mj-msc.tex @@ -589,7 +589,7 @@ table~\ref{table:scale-halfcirlce-diameter}. Sometimes, when working with {\WM}, it is useful to convert between half-circle's diameter $D$ and adjusted size $A_{adj}$. These easily derive -from circle's area formula $A = 2\pi r^2$. Diameter: +from circle's area formula $A = 2\pi \frac{D}{2}^2$: \[ D = 2\sqrt{\frac{2 A_{adj}}{\pi}} @@ -868,7 +868,7 @@ The smaller the distance $d$, the more similar the bends are. \subsection{Elimination Operator} -NOTE: not implemented. +NOTE: implemented, explain. \subsection{Combination Operator} @@ -876,7 +876,7 @@ NOTE: not implemented. \subsection{Exaggeration Operator} -NOTE: not implemented. +NOTE: implemented, explain. Also {\texttt intersection\_tolerance} parameter. \section{Program Implementation} diff --git a/IV/test-rivers.sql b/IV/test-rivers.sql index eba4a73..86c2da8 100644 --- a/IV/test-rivers.sql +++ b/IV/test-rivers.sql @@ -109,4 +109,4 @@ end $$ language plpgsql; delete from wm_debug where name in (select distinct name from wm_rivers); delete from wm_demo where name in (select distinct name from wm_rivers); -insert into wm_demo (name, way) select name, ST_SimplifyWM(way, 37.5, name) from wm_rivers; +insert into wm_demo (name, way) select name, ST_SimplifyWM(way, 37.5, null, name) from wm_rivers; diff --git a/IV/test.sql b/IV/test.sql index 9566f7e..f106780 100644 --- a/IV/test.sql +++ b/IV/test.sql @@ -56,8 +56,8 @@ insert into wm_figures (name, way) values ('isolated-2', 'LINESTRING(250 100,246 delete from wm_debug where name in (select distinct name from wm_figures); delete from wm_demo where name in (select distinct name from wm_figures); -insert into wm_demo (name, way) select name, ST_SimplifyWM(way, .1, name) from wm_figures where name not in ('fig8', 'isolated-1'); -insert into wm_demo (name, way) select name, ST_SimplifyWM(way, 14, name) from wm_figures where name in ('fig8', 'isolated-1', 'isolated-2'); +insert into wm_demo (name, way) select name, ST_SimplifyWM(way, .1, null, name) from wm_figures where name not in ('fig8', 'isolated-1'); +insert into wm_demo (name, way) select name, ST_SimplifyWM(way, 14, null, name) from wm_figures where name in ('fig8', 'isolated-1', 'isolated-2'); drop function if exists wm_debug_get; create function wm_debug_get( diff --git a/IV/wm.sql b/IV/wm.sql index e705084..b7f1445 100644 --- a/IV/wm.sql +++ b/IV/wm.sql @@ -481,6 +481,7 @@ $$ language plpgsql; create function wm_exaggeration( INOUT bendattrs wm_t_bend_attrs[], dhalfcircle float, + intersect_patience integer, dbgname text default null, dbggen integer default null, OUT mutated boolean @@ -489,19 +490,56 @@ declare desired_size constant float default pi()*(dhalfcircle^2)/8; tmpbendattr wm_t_bend_attrs; i integer; + n integer; last_id integer; begin mutated = false; + <> for i in 1..array_length(bendattrs, 1) loop if bendattrs[i].isolated and bendattrs[i].adjsize < desired_size then - mutated = true; tmpbendattr.bend = wm_exaggerate_bend( bendattrs[i].bend, bendattrs[i].adjsize, desired_size ); + + -- does tmpbendattrs.bend intersect with the previous or next + -- intersect_patience bends? If they do, abort exaggeration for this one. + bendattrs[i] = tmpbendattr; + -- Do close-by bends intersect with this one? Special + -- handling first, because 2 vertices need to be removed before checking. + n = st_npoints(bendattrs[i-1].bend); + if n > 3 then + continue when st_overlaps(tmpbendattr.bend, + st_removepoint(st_removepoint(bendattrs[i-1].bend, n-1), n-2)); + end if; + + n = st_npoints(bendattrs[i+1].bend); + if n > 3 then + continue when st_intersects(tmpbendattr.bend, + st_removepoint(st_removepoint(bendattrs[i+1].bend, 0), 0)); + end if; + + -- now loop over the next intersect_patience + for n in -intersect_patience+1..intersect_patience-1 loop + continue when n in (-1, 0, 1); + continue when i+n < 1; + continue when i+n > array_length(bendattrs, 1); + + if st_overlaps(tmpbendattr.bend, bendattrs[i+n].bend) then + insert into wm_manual(name, way) values + ('intersecter', tmpbendattr.bend), + ('intersectee', bendattrs[i+n].bend); + raise notice '[%] % intersects with %', dbggen, i, i+n; + continue bendloop; + end if; + end loop; + + -- no intersections within intersect_patience. Mutate bend. + mutated = true; + -- remove last vertex of the previous bend and -- first vertex of the next bend, because bends always -- share a line segment together @@ -690,6 +728,7 @@ drop function if exists ST_SimplifyWM; create function ST_SimplifyWM( geom geometry, dhalfcircle float, + intersect_patience integer default 10, dbgname text default null ) returns geometry as $$ declare @@ -703,6 +742,9 @@ declare mutated boolean; l_type text; begin + if intersect_patience is null then + intersect_patience = 10; + end if; l_type = st_geometrytype(geom); if l_type = 'ST_LineString' then lines = array[geom]; @@ -736,7 +778,8 @@ begin bendattrs = wm_isolated_bends(bendattrs, dbgname, gen); select * from wm_exaggeration( - bendattrs, dhalfcircle, dbgname, gen) into bendattrs, mutated; + bendattrs, dhalfcircle, intersect_patience, dbgname, gen + ) into bendattrs, mutated; -- TODO: wm_combination @@ -750,6 +793,18 @@ begin bends[j] = bendattrs[j].bend; end loop; lines[i] = st_linemerge(st_union(bends)); + if st_geometrytype(lines[i]) != 'ST_LineString' then + raise 'Got % instead of ST_LineString. ' + 'Does the exaggerated bend intersect? ' + 'If so, try increasing intersect_patience.', + st_geometrytype(lines[i]); + + insert into wm_manual(name, way) + select 'non-linestring-' || a.path[1], a.geom + from st_dump(lines[i]) a + order by a.path[1]; + exit; + end if; gen = gen + 1; continue; end if;