bring back working wm.sql
This commit is contained in:
parent
e20781aa85
commit
b7a9d559e2
464
wm.sql
464
wm.sql
@ -81,14 +81,16 @@ begin
|
|||||||
dbgpolygon = null;
|
dbgpolygon = null;
|
||||||
if st_npoints(bends[i]) >= 3 then
|
if st_npoints(bends[i]) >= 3 then
|
||||||
dbgpolygon = st_makepolygon(
|
dbgpolygon = st_makepolygon(
|
||||||
st_addpoint(bends[i], st_startpoint(bends[i]))
|
st_addpoint(bends[i],
|
||||||
|
st_startpoint(bends[i]))
|
||||||
);
|
);
|
||||||
end if;
|
end if;
|
||||||
insert into wm_debug(stage, name, gen, nbend, way) values(
|
insert into wm_debug(stage, name, gen, nbend, way) values(
|
||||||
'bbends-polygon', dbgname, dbggen, i, dbgpolygon);
|
'bbends-polygon', dbgname, dbggen, i, dbgpolygon);
|
||||||
end loop;
|
end loop;
|
||||||
end if;
|
end if;
|
||||||
end $$ language plpgsql;
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
-- wm_fix_gentle_inflections moves bend endpoints following "Gentle Inflection
|
-- wm_fix_gentle_inflections moves bend endpoints following "Gentle Inflection
|
||||||
-- at End of a Bend" section.
|
-- at End of a Bend" section.
|
||||||
@ -139,7 +141,8 @@ begin
|
|||||||
'cinflections-polygon', dbgname, dbggen, i, dbgpolygon);
|
'cinflections-polygon', dbgname, dbggen, i, dbgpolygon);
|
||||||
end loop;
|
end loop;
|
||||||
end if;
|
end if;
|
||||||
end $$ language plpgsql;
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
-- wm_fix_gentle_inflections1 fixes gentle inflections of an array of lines in
|
-- wm_fix_gentle_inflections1 fixes gentle inflections of an array of lines in
|
||||||
-- one direction. An implementation detail of wm_fix_gentle_inflections.
|
-- one direction. An implementation detail of wm_fix_gentle_inflections.
|
||||||
@ -201,7 +204,8 @@ begin
|
|||||||
end loop;
|
end loop;
|
||||||
|
|
||||||
end loop;
|
end loop;
|
||||||
end $$ language plpgsql;
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
-- wm_if_selfcross returns whether baseline of bendi crosses bendj.
|
-- wm_if_selfcross returns whether baseline of bendi crosses bendj.
|
||||||
-- If it doesn't, returns a null geometry.
|
-- If it doesn't, returns a null geometry.
|
||||||
@ -231,7 +235,9 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
|
|
||||||
return multi;
|
return multi;
|
||||||
end $$ language plpgsql;
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
|
|
||||||
-- wm_self_crossing eliminates self-crossing from the bends, following the
|
-- wm_self_crossing eliminates self-crossing from the bends, following the
|
||||||
-- article's section "Self-line Crossing When Cutting a Bend".
|
-- article's section "Self-line Crossing When Cutting a Bend".
|
||||||
@ -299,7 +305,8 @@ begin
|
|||||||
unnest(bends)
|
unnest(bends)
|
||||||
);
|
);
|
||||||
end if;
|
end if;
|
||||||
end $$ language plpgsql;
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
drop function if exists wm_inflection_angle;
|
drop function if exists wm_inflection_angle;
|
||||||
create function wm_inflection_angle (IN bend geometry, OUT angle real) as $$
|
create function wm_inflection_angle (IN bend geometry, OUT angle real) as $$
|
||||||
@ -317,14 +324,17 @@ begin
|
|||||||
continue when p3 is null;
|
continue when p3 is null;
|
||||||
angle = angle + abs(pi() - st_angle(p1, p2, p3));
|
angle = angle + abs(pi() - st_angle(p1, p2, p3));
|
||||||
end loop;
|
end loop;
|
||||||
end $$ language plpgsql;
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
drop function if exists wm_bend_attrs;
|
drop function if exists wm_bend_attrs;
|
||||||
|
drop function if exists wm_isolated_bends;
|
||||||
drop function if exists wm_elimination;
|
drop function if exists wm_elimination;
|
||||||
drop function if exists wm_exaggeration;
|
drop function if exists wm_exaggeration;
|
||||||
drop function if exists wm_st_intersects_neighbors;
|
drop type if exists wm_t_bend_attrs;
|
||||||
drop type if exists wm_t_attrs;
|
create type wm_t_bend_attrs as (
|
||||||
create type wm_t_attrs as (
|
bend geometry,
|
||||||
|
area real,
|
||||||
adjsize real,
|
adjsize real,
|
||||||
baselinelength real,
|
baselinelength real,
|
||||||
curvature real,
|
curvature real,
|
||||||
@ -334,66 +344,40 @@ create function wm_bend_attrs(
|
|||||||
bends geometry[],
|
bends geometry[],
|
||||||
dbgname text default null,
|
dbgname text default null,
|
||||||
dbggen integer default null
|
dbggen integer default null
|
||||||
) returns wm_t_attrs[] as $$
|
) returns setof wm_t_bend_attrs as $$
|
||||||
declare
|
declare
|
||||||
isolation_threshold constant real default 0.5;
|
cmp float;
|
||||||
attrs wm_t_attrs[];
|
|
||||||
attr wm_t_attrs;
|
|
||||||
bend geometry;
|
|
||||||
i int4;
|
i int4;
|
||||||
needs_curvature real;
|
polygon geometry;
|
||||||
skip_next boolean;
|
bend geometry;
|
||||||
dbglastid integer;
|
res wm_t_bend_attrs;
|
||||||
begin
|
begin
|
||||||
for i in 1..array_length(bends, 1) loop
|
for i in 1..array_length(bends, 1) loop
|
||||||
bend = bends[i];
|
bend = bends[i];
|
||||||
attr.adjsize = 0;
|
res = null;
|
||||||
attr.baselinelength = st_distance(st_startpoint(bend), st_endpoint(bend));
|
res.bend = bend;
|
||||||
attr.curvature = wm_inflection_angle(bend) / st_length(bend);
|
res.adjsize = 0;
|
||||||
attr.isolated = false;
|
res.baselinelength = st_distance(st_startpoint(bend), st_endpoint(bend));
|
||||||
|
res.curvature = wm_inflection_angle(bend) / st_length(bend);
|
||||||
|
res.isolated = false;
|
||||||
if st_numpoints(bend) >= 3 then
|
if st_numpoints(bend) >= 3 then
|
||||||
attr.adjsize = wm_adjsize(bend);
|
res.adjsize = wm_adjsize(bend);
|
||||||
end if;
|
end if;
|
||||||
attrs[i] = attr;
|
|
||||||
end loop;
|
|
||||||
|
|
||||||
for i in 1..array_length(attrs, 1) loop
|
|
||||||
if dbgname is not null then
|
if dbgname is not null then
|
||||||
insert into wm_debug (stage, name, gen, nbend, way, props) values(
|
insert into wm_debug (stage, name, gen, nbend, way, props) values(
|
||||||
'ebendattrs', dbgname, dbggen, i, bend,
|
'ebendattrs', dbgname, dbggen, i, bend,
|
||||||
jsonb_build_object(
|
jsonb_build_object(
|
||||||
'adjsize', attrs[i].adjsize,
|
'adjsize', res.adjsize,
|
||||||
'baselinelength', attrs[i].baselinelength,
|
'baselinelength', res.baselinelength,
|
||||||
'curvature', attrs[i].curvature,
|
'curvature', res.curvature
|
||||||
'isolated', false
|
|
||||||
)
|
)
|
||||||
) returning id into dbglastid;
|
);
|
||||||
end if;
|
|
||||||
|
|
||||||
-- first and last bends can never be isolated by definition
|
|
||||||
if skip_next or i = 1 or i = array_length(attrs, 1) then
|
|
||||||
skip_next = false;
|
|
||||||
continue;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
needs_curvature = attrs[i].curvature * isolation_threshold;
|
|
||||||
if attrs[i-1].curvature < needs_curvature and
|
|
||||||
attrs[i+1].curvature < needs_curvature then
|
|
||||||
attr = attrs[i];
|
|
||||||
attr.isolated = true;
|
|
||||||
attrs[i] = attr;
|
|
||||||
skip_next = true;
|
|
||||||
|
|
||||||
if dbgname is not null then
|
|
||||||
update wm_debug
|
|
||||||
set props=props || jsonb_build_object('isolated', true)
|
|
||||||
where id=dbglastid;
|
|
||||||
end if;
|
|
||||||
end if;
|
end if;
|
||||||
|
return next res;
|
||||||
end loop;
|
end loop;
|
||||||
|
end;
|
||||||
return attrs;
|
$$ language plpgsql;
|
||||||
end $$ language plpgsql;
|
|
||||||
|
|
||||||
-- sm_st_split a line by a point in a more robust way than st_split.
|
-- sm_st_split a line by a point in a more robust way than st_split.
|
||||||
-- See https://trac.osgeo.org/postgis/ticket/2192
|
-- See https://trac.osgeo.org/postgis/ticket/2192
|
||||||
@ -417,44 +401,55 @@ end $$ language plpgsql;
|
|||||||
|
|
||||||
-- wm_exaggerate_bend exaggerates a given bend. Must be a simple linestring.
|
-- wm_exaggerate_bend exaggerates a given bend. Must be a simple linestring.
|
||||||
drop function if exists wm_exaggerate_bend;
|
drop function if exists wm_exaggerate_bend;
|
||||||
create function wm_exaggerate_bend(INOUT bend geometry) as $$
|
create function wm_exaggerate_bend(
|
||||||
|
INOUT bend geometry,
|
||||||
|
size float,
|
||||||
|
desired_size float
|
||||||
|
) as $$
|
||||||
declare
|
declare
|
||||||
scale constant float default 1.2; -- exaggeration enthusiasm
|
scale constant float default 2; -- per-step scaling factor
|
||||||
midpoint geometry; -- midpoint of the baseline
|
midpoint geometry; -- midpoint of the baseline
|
||||||
splitbend geometry; -- bend split across its half
|
splitbend geometry; -- bend split across its half
|
||||||
bendm geometry; -- bend with coefficients to prolong the lines
|
bendm geometry; -- bend with coefficients to prolong the lines
|
||||||
points geometry[];
|
points geometry[];
|
||||||
begin
|
begin
|
||||||
|
if size = 0 then
|
||||||
|
raise 'invalid input: zero-area bend';
|
||||||
|
end if;
|
||||||
midpoint = st_lineinterpolatepoint(st_makeline(
|
midpoint = st_lineinterpolatepoint(st_makeline(
|
||||||
st_pointn(bend, 1),
|
st_pointn(bend, 1),
|
||||||
st_pointn(bend, -1)
|
st_pointn(bend, -1)
|
||||||
), .5);
|
), .5);
|
||||||
|
|
||||||
splitbend = wm_st_split(bend, st_lineinterpolatepoint(bend, .5));
|
while size < desired_size loop
|
||||||
-- Convert bend to LINESTRINGM, where M is the fraction by how
|
splitbend = wm_st_split(bend, st_lineinterpolatepoint(bend, .5));
|
||||||
-- much the point will be prolonged:
|
-- Convert bend to LINESTRINGM, where M is the fraction by how
|
||||||
-- 1. draw a line between midpoint and the point on the bend.
|
-- much the point will be prolonged:
|
||||||
-- 2. multiply the line length by M. Midpoint stays intact.
|
-- 1. draw a line between midpoint and the point on the bend.
|
||||||
-- 3. the new set of lines form a new bend.
|
-- 2. multiply the line length by M. Midpoint stays intact.
|
||||||
-- Uses linear interpolation; can be updated to gaussian or similar;
|
-- 3. the new set of lines form a new bend.
|
||||||
-- then interpolate manually instead of relying on st_addmeasure.
|
-- Uses linear interpolation; can be updated to gaussian or similar;
|
||||||
bendm = st_collect(
|
-- then interpolate manually instead of relying on st_addmeasure.
|
||||||
st_addmeasure(st_geometryn(splitbend, 1), 1, scale),
|
bendm = st_collect(
|
||||||
st_addmeasure(st_geometryn(splitbend, 2), scale, 1)
|
st_addmeasure(st_geometryn(splitbend, 1), 1, scale),
|
||||||
);
|
st_addmeasure(st_geometryn(splitbend, 2), scale, 1)
|
||||||
|
);
|
||||||
|
|
||||||
points = array((
|
points = array((
|
||||||
select st_scale(
|
select st_scale(
|
||||||
st_makepoint(st_x(geom), st_y(geom)),
|
st_makepoint(st_x(geom), st_y(geom)),
|
||||||
st_makepoint(st_m(geom), st_m(geom)),
|
st_makepoint(st_m(geom), st_m(geom)),
|
||||||
midpoint
|
midpoint
|
||||||
)
|
)
|
||||||
from st_dumppoints(bendm)
|
from st_dumppoints(bendm)
|
||||||
order by path[1], path[2]
|
order by path[1], path[2]
|
||||||
));
|
));
|
||||||
|
|
||||||
bend = st_setsrid(st_makeline(points), st_srid(bend));
|
bend = st_setsrid(st_makeline(points), st_srid(bend));
|
||||||
end $$ language plpgsql;
|
size = wm_adjsize(bend);
|
||||||
|
end loop;
|
||||||
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
-- wm_adjsize calculates adjusted size for a polygon. Can return 0.
|
-- wm_adjsize calculates adjusted size for a polygon. Can return 0.
|
||||||
drop function if exists wm_adjsize;
|
drop function if exists wm_adjsize;
|
||||||
@ -479,62 +474,12 @@ begin
|
|||||||
if cmp > 0 then
|
if cmp > 0 then
|
||||||
adjsize = (area*(0.75/cmp));
|
adjsize = (area*(0.75/cmp));
|
||||||
end if;
|
end if;
|
||||||
end $$ language plpgsql;
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
drop function if exists wm_st_intersects_neighbors;
|
|
||||||
create function wm_st_intersects_neighbors(
|
|
||||||
bends geometry[],
|
|
||||||
bend geometry,
|
|
||||||
i integer,
|
|
||||||
intersect_patience integer
|
|
||||||
) returns boolean as $$
|
|
||||||
declare
|
|
||||||
n integer;
|
|
||||||
neighbor geometry;
|
|
||||||
begin
|
|
||||||
-- Do close-by bends intersect with this one? Special
|
|
||||||
-- handling first, because 2 vertices need to be removed before checking.
|
|
||||||
n = st_npoints(bends[i-1]);
|
|
||||||
if n > 3 and st_intersects(bend,
|
|
||||||
st_removepoint(st_removepoint(bends[i-1], n-1), n-2)) then
|
|
||||||
return true;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
n = st_npoints(bends[i+1]);
|
|
||||||
if n > 3 and st_intersects(bend,
|
|
||||||
st_removepoint(st_removepoint(bends[i+1], 0), 0)) then
|
|
||||||
return true;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- Go through all the neighbors and see if the enlarged bend intersects
|
|
||||||
-- with any of them. If yes -- abort enlargement.
|
|
||||||
for n in -intersect_patience+1..intersect_patience-1 loop
|
|
||||||
continue when i+n < 1 or n in (-1, 0, 1);
|
|
||||||
continue when i+n > array_length(bends, 1);
|
|
||||||
|
|
||||||
-- More special handling: if the neigbhoring bend has 3 vertices, the
|
|
||||||
-- neighbor's neighbor may just touch the bend; in this
|
|
||||||
-- case, the nearest vertex should be removed before comparing.
|
|
||||||
neighbor = bends[i+n];
|
|
||||||
if st_npoints(neighbor) > 2 then
|
|
||||||
if n = -2 and st_npoints(bends[i+n+1]) = 3 then
|
|
||||||
neighbor = st_removepoint(neighbor, st_npoints(neighbor)-1);
|
|
||||||
elsif n = 2 and st_npoints(bends[i+n-1]) = 3 then
|
|
||||||
neighbor = st_removepoint(neighbor, 0);
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
if st_intersects(bend, neighbor) then
|
|
||||||
return true;
|
|
||||||
end if;
|
|
||||||
end loop;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
end $$ language plpgsql;
|
|
||||||
|
|
||||||
-- wm_exaggeration is the Exaggeration Operator described in the WM paper.
|
-- wm_exaggeration is the Exaggeration Operator described in the WM paper.
|
||||||
create function wm_exaggeration(
|
create function wm_exaggeration(
|
||||||
INOUT bends geometry[],
|
INOUT bendattrs wm_t_bend_attrs[],
|
||||||
attrs wm_t_attrs[],
|
|
||||||
dhalfcircle float,
|
dhalfcircle float,
|
||||||
intersect_patience integer,
|
intersect_patience integer,
|
||||||
dbgname text default null,
|
dbgname text default null,
|
||||||
@ -543,58 +488,87 @@ create function wm_exaggeration(
|
|||||||
) as $$
|
) as $$
|
||||||
declare
|
declare
|
||||||
desired_size constant float default pi()*(dhalfcircle^2)/8;
|
desired_size constant float default pi()*(dhalfcircle^2)/8;
|
||||||
bend geometry;
|
tmpbendattr wm_t_bend_attrs;
|
||||||
neighbor geometry;
|
tmpint geometry;
|
||||||
size float;
|
|
||||||
i integer;
|
i integer;
|
||||||
this_mutated boolean;
|
n integer;
|
||||||
|
last_id integer;
|
||||||
begin
|
begin
|
||||||
mutated = false;
|
mutated = false;
|
||||||
i = 0;
|
<<bendloop>>
|
||||||
while i < array_length(attrs, 1) loop
|
for i in 1..array_length(bendattrs, 1) loop
|
||||||
i = i + 1;
|
if bendattrs[i].isolated and bendattrs[i].adjsize < desired_size then
|
||||||
|
tmpbendattr.bend = wm_exaggerate_bend(
|
||||||
|
bendattrs[i].bend,
|
||||||
|
bendattrs[i].adjsize,
|
||||||
|
desired_size
|
||||||
|
);
|
||||||
|
|
||||||
continue when not attrs[i].isolated;
|
-- does tmpbendattrs.bend intersect with the previous or next
|
||||||
this_mutated = false;
|
-- intersect_patience bends? If they do, abort exaggeration for this one.
|
||||||
|
|
||||||
-- keep increasing this bend until either size permits, or it hits a
|
|
||||||
-- neighboring bend (intersect_patience number of neighbors will be
|
|
||||||
-- checked). When the size is right, stick it to the line.
|
|
||||||
size = attrs[i].adjsize;
|
|
||||||
while size < desired_size loop
|
|
||||||
bend = wm_exaggerate_bend(bends[i]);
|
|
||||||
exit when wm_st_intersects_neighbors(bends, bend, i, intersect_patience);
|
|
||||||
|
|
||||||
this_mutated = true;
|
-- Do close-by bends intersect with this one? Special
|
||||||
bends[i] = bend;
|
-- handling first, because 2 vertices need to be removed before checking.
|
||||||
size = wm_adjsize(bend);
|
n = st_npoints(bendattrs[i-1].bend);
|
||||||
end loop;
|
if n > 3 then
|
||||||
continue when not this_mutated;
|
continue when st_intersects(tmpbendattr.bend,
|
||||||
|
st_removepoint(st_removepoint(bendattrs[i-1].bend, n-1), n-2));
|
||||||
|
end if;
|
||||||
|
|
||||||
mutated = true;
|
n = st_npoints(bendattrs[i+1].bend);
|
||||||
-- Stick the right-sized bend to the line
|
if n > 3 then
|
||||||
-----------------------------------------
|
continue when st_intersects(tmpbendattr.bend,
|
||||||
-- Remove last vertex of the previous bend and first vertex of the next
|
st_removepoint(st_removepoint(bendattrs[i+1].bend, 0), 0));
|
||||||
-- bend, because bends always share a line segment together.
|
end if;
|
||||||
bend = st_removepoint(bends[i-1], st_npoints(bends[i-1])-1);
|
|
||||||
bends[i-1] = bend;
|
|
||||||
bend = st_removepoint(bends[i+1], 0);
|
|
||||||
bends[i+1] = bend;
|
|
||||||
|
|
||||||
if dbgname is not null then
|
for n in -intersect_patience+1..intersect_patience-1 loop
|
||||||
insert into wm_debug (stage, name, gen, nbend, way) values(
|
continue when n in (-1, 0, 1);
|
||||||
'gexaggeration', dbgname, dbggen, i, bends[i]);
|
continue when i+n < 1;
|
||||||
|
continue when i+n > array_length(bendattrs, 1);
|
||||||
|
|
||||||
|
-- More special handling: if the neigbhoring bend has 3 vertices, the
|
||||||
|
-- neighbor's neighbor may just touch the tmpbendattr.bend; in this
|
||||||
|
-- case, the nearest vertex should be removed before comparing.
|
||||||
|
tmpint = bendattrs[i+n].bend;
|
||||||
|
if st_npoints(tmpint) > 2 then
|
||||||
|
if n = -2 and st_npoints(bendattrs[i+n+1].bend) = 3 then
|
||||||
|
tmpint = st_removepoint(tmpint, st_npoints(tmpint)-1);
|
||||||
|
elsif n = 2 and st_npoints(bendattrs[i+n-1].bend) = 3 then
|
||||||
|
tmpint = st_removepoint(tmpint, 0);
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
continue bendloop when st_intersects(tmpbendattr.bend, tmpint);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
-- No intersections within intersect_patience, mutate bend!
|
||||||
|
mutated = true;
|
||||||
|
bendattrs[i] = tmpbendattr;
|
||||||
|
|
||||||
|
-- remove last vertex of the previous bend and first vertex of the next
|
||||||
|
-- bend, because bends always share a line segment together this is
|
||||||
|
-- duplicated in a few places, because PostGIS does not allow (?)
|
||||||
|
-- mutating an array when passed to a function.
|
||||||
|
tmpbendattr.bend = st_removepoint(
|
||||||
|
bendattrs[i-1].bend,
|
||||||
|
st_npoints(bendattrs[i-1].bend)-1
|
||||||
|
);
|
||||||
|
bendattrs[i-1] = tmpbendattr;
|
||||||
|
tmpbendattr.bend = st_removepoint(bendattrs[i+1].bend, 0);
|
||||||
|
bendattrs[i+1] = tmpbendattr;
|
||||||
|
|
||||||
|
if dbgname is not null then
|
||||||
|
insert into wm_debug (stage, name, gen, nbend, way) values(
|
||||||
|
'gexaggeration', dbgname, dbggen, i, bendattrs[i].bend
|
||||||
|
);
|
||||||
|
end if;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
-- Next bend was modified, so `isolated` is not valid for neighbor's
|
|
||||||
-- neighbor. Skip over.
|
|
||||||
i = i + 2;
|
|
||||||
end loop;
|
end loop;
|
||||||
end $$ language plpgsql;
|
end $$ language plpgsql;
|
||||||
|
|
||||||
create function wm_elimination(
|
create function wm_elimination(
|
||||||
INOUT bends geometry[],
|
INOUT bendattrs wm_t_bend_attrs[],
|
||||||
attrs wm_t_attrs[],
|
|
||||||
dhalfcircle float,
|
dhalfcircle float,
|
||||||
dbgname text default null,
|
dbgname text default null,
|
||||||
dbggen integer default null,
|
dbggen integer default null,
|
||||||
@ -605,54 +579,119 @@ declare
|
|||||||
leftsize float;
|
leftsize float;
|
||||||
rightsize float;
|
rightsize float;
|
||||||
i int4;
|
i int4;
|
||||||
|
j int4;
|
||||||
|
tmpbendattr wm_t_bend_attrs;
|
||||||
|
dbgbends geometry[];
|
||||||
begin
|
begin
|
||||||
mutated = false;
|
mutated = false;
|
||||||
|
|
||||||
i = 1;
|
i = 1;
|
||||||
while i < array_length(attrs, 1)-1 loop
|
while i < array_length(bendattrs, 1)-1 loop
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
continue when attrs[i].adjsize = 0;
|
continue when bendattrs[i].adjsize = 0;
|
||||||
continue when attrs[i].adjsize > desired_size;
|
continue when bendattrs[i].adjsize > desired_size;
|
||||||
|
|
||||||
if i = 2 then
|
if i = 2 then
|
||||||
leftsize = attrs[i].adjsize + 1;
|
leftsize = bendattrs[i].adjsize + 1;
|
||||||
else
|
else
|
||||||
leftsize = attrs[i-1].adjsize;
|
leftsize = bendattrs[i-1].adjsize;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
if i = array_length(attrs, 1)-1 then
|
if i = array_length(bendattrs, 1)-1 then
|
||||||
rightsize = attrs[i].adjsize + 1;
|
rightsize = bendattrs[i].adjsize + 1;
|
||||||
else
|
else
|
||||||
rightsize = attrs[i+1].adjsize;
|
rightsize = bendattrs[i+1].adjsize;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
continue when attrs[i].adjsize >= leftsize;
|
continue when bendattrs[i].adjsize >= leftsize;
|
||||||
continue when attrs[i].adjsize >= rightsize;
|
continue when bendattrs[i].adjsize >= rightsize;
|
||||||
|
|
||||||
-- Local minimum. Elminate bend!
|
-- Local minimum. Elminate bend!
|
||||||
mutated = true;
|
mutated = true;
|
||||||
bends[i] = st_makeline(st_pointn(bends[i], 1), st_pointn(bends[i], -1));
|
tmpbendattr.bend = st_makeline(
|
||||||
|
st_pointn(bendattrs[i].bend, 1),
|
||||||
|
st_pointn(bendattrs[i].bend, -1)
|
||||||
|
);
|
||||||
|
bendattrs[i] = tmpbendattr;
|
||||||
-- remove last vertex of the previous bend and
|
-- remove last vertex of the previous bend and
|
||||||
-- first vertex of the next bend, because bends always
|
-- first vertex of the next bend, because bends always
|
||||||
-- share a line segment together
|
-- share a line segment together
|
||||||
bends[i-1] = st_removepoint(bends[i-1], st_npoints(bends[i-1])-1);
|
tmpbendattr.bend = st_removepoint(
|
||||||
bends[i+1] = st_removepoint(bends[i+1], 0);
|
bendattrs[i-1].bend,
|
||||||
|
st_npoints(bendattrs[i-1].bend)-1
|
||||||
|
);
|
||||||
|
bendattrs[i-1] = tmpbendattr;
|
||||||
|
tmpbendattr.bend = st_removepoint(bendattrs[i+1].bend, 0);
|
||||||
|
bendattrs[i+1] = tmpbendattr;
|
||||||
-- the next bend's adjsize is now messed up; it should not be taken
|
-- the next bend's adjsize is now messed up; it should not be taken
|
||||||
-- into consideration for other local minimas. Skip over 2.
|
-- into consideration for other local minimas. Skip over 2.
|
||||||
i = i + 2;
|
i = i + 2;
|
||||||
end loop;
|
end loop;
|
||||||
|
|
||||||
if dbgname is not null then
|
if dbgname is not null then
|
||||||
|
for j in 1..array_length(bendattrs, 1) loop
|
||||||
|
dbgbends[j] = bendattrs[j].bend;
|
||||||
|
end loop;
|
||||||
|
|
||||||
insert into wm_debug(stage, name, gen, nbend, way) values(
|
insert into wm_debug(stage, name, gen, nbend, way) values(
|
||||||
'helimination',
|
'helimination',
|
||||||
dbgname,
|
dbgname,
|
||||||
dbggen,
|
dbggen,
|
||||||
generate_subscripts(bends, 1),
|
generate_subscripts(dbgbends, 1),
|
||||||
unnest(bends)
|
unnest(dbgbends)
|
||||||
);
|
);
|
||||||
end if;
|
end if;
|
||||||
end $$ language plpgsql;
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
|
create function wm_isolated_bends(
|
||||||
|
INOUT bendattrs wm_t_bend_attrs[],
|
||||||
|
dbgname text default null,
|
||||||
|
dbggen integer default null
|
||||||
|
) as $$
|
||||||
|
declare
|
||||||
|
-- if neighbor's curvatures are within this fraction of the current bend
|
||||||
|
isolation_threshold constant real default 0.5;
|
||||||
|
this real;
|
||||||
|
skip_next bool;
|
||||||
|
res wm_t_bend_attrs;
|
||||||
|
i int4;
|
||||||
|
last_id integer;
|
||||||
|
begin
|
||||||
|
for i in 1..array_length(bendattrs, 1) loop
|
||||||
|
if dbgname is not null then
|
||||||
|
insert into wm_debug (stage, name, gen, nbend, way, props) values(
|
||||||
|
'fisolated_bends', dbgname, dbggen, i, bendattrs[i].bend,
|
||||||
|
jsonb_build_object('isolated', false)
|
||||||
|
) returning id into last_id;
|
||||||
|
end if;
|
||||||
|
-- first and last bends cannot be isolated
|
||||||
|
if i = 1 or i = array_length(bendattrs, 1) then
|
||||||
|
continue;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
res = bendattrs[i];
|
||||||
|
if skip_next then
|
||||||
|
skip_next = false;
|
||||||
|
else
|
||||||
|
this = bendattrs[i].curvature * isolation_threshold;
|
||||||
|
if bendattrs[i-1].curvature < this and
|
||||||
|
bendattrs[i+1].curvature < this then
|
||||||
|
res.isolated = true;
|
||||||
|
bendattrs[i] = res;
|
||||||
|
skip_next = true;
|
||||||
|
|
||||||
|
if dbgname is not null then
|
||||||
|
update wm_debug
|
||||||
|
set props=props || jsonb_build_object('isolated', true)
|
||||||
|
where id=last_id;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
drop function if exists ST_SimplifyWM_Estimate;
|
drop function if exists ST_SimplifyWM_Estimate;
|
||||||
create function ST_SimplifyWM_Estimate(
|
create function ST_SimplifyWM_Estimate(
|
||||||
@ -678,7 +717,8 @@ begin
|
|||||||
npoints = npoints + st_numpoints(lines[i]);
|
npoints = npoints + st_numpoints(lines[i]);
|
||||||
end loop;
|
end loop;
|
||||||
secs = npoints / 33;
|
secs = npoints / 33;
|
||||||
end $$ language plpgsql;
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
-- ST_SimplifyWM simplifies a given geometry using Wang & Müller's
|
-- ST_SimplifyWM simplifies a given geometry using Wang & Müller's
|
||||||
-- "Line Generalization Based on Analysis of Shape Characteristics" algorithm,
|
-- "Line Generalization Based on Analysis of Shape Characteristics" algorithm,
|
||||||
@ -702,7 +742,7 @@ declare
|
|||||||
line geometry;
|
line geometry;
|
||||||
lines geometry[];
|
lines geometry[];
|
||||||
bends geometry[];
|
bends geometry[];
|
||||||
attrs wm_t_attrs[];
|
bendattrs wm_t_bend_attrs[];
|
||||||
mutated boolean;
|
mutated boolean;
|
||||||
l_type text;
|
l_type text;
|
||||||
begin
|
begin
|
||||||
@ -733,37 +773,42 @@ begin
|
|||||||
|
|
||||||
select * from wm_self_crossing(bends, dbgname, gen) into bends, mutated;
|
select * from wm_self_crossing(bends, dbgname, gen) into bends, mutated;
|
||||||
|
|
||||||
if not mutated then
|
if mutated then
|
||||||
attrs = wm_bend_attrs(bends, dbgname, gen);
|
lines[i] = st_linemerge(st_union(bends));
|
||||||
|
gen = gen + 1;
|
||||||
select * from wm_exaggeration(
|
continue;
|
||||||
bends, attrs, dhalfcircle, intersect_patience, dbgname, gen
|
|
||||||
) into bends, mutated;
|
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
|
bendattrs = array((select wm_bend_attrs(bends, dbgname, gen)));
|
||||||
|
bendattrs = wm_isolated_bends(bendattrs, dbgname, gen);
|
||||||
|
|
||||||
|
select * from wm_exaggeration(
|
||||||
|
bendattrs, dhalfcircle, intersect_patience, dbgname, gen
|
||||||
|
) into bendattrs, mutated;
|
||||||
|
|
||||||
-- TODO: wm_combination
|
-- TODO: wm_combination
|
||||||
|
|
||||||
if not mutated then
|
if not mutated then
|
||||||
select * from wm_elimination(
|
select * from wm_elimination(
|
||||||
bends, attrs, dhalfcircle, dbgname, gen) into bends, mutated;
|
bendattrs, dhalfcircle, dbgname, gen) into bendattrs, mutated;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
if mutated then
|
if mutated then
|
||||||
|
for j in 1..array_length(bendattrs, 1) loop
|
||||||
|
bends[j] = bendattrs[j].bend;
|
||||||
|
end loop;
|
||||||
lines[i] = st_linemerge(st_union(bends));
|
lines[i] = st_linemerge(st_union(bends));
|
||||||
|
|
||||||
if st_geometrytype(lines[i]) != 'ST_LineString' then
|
if st_geometrytype(lines[i]) != 'ST_LineString' then
|
||||||
raise notice 'Got % (in %) instead of ST_LineString. '
|
-- For manual debugging:
|
||||||
|
--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];
|
||||||
|
raise 'Got % (in %) instead of ST_LineString. '
|
||||||
'Does the exaggerated bend intersect with the line? '
|
'Does the exaggerated bend intersect with the line? '
|
||||||
'If so, try increasing intersect_patience.',
|
'If so, try increasing intersect_patience.',
|
||||||
st_geometrytype(lines[i]), dbgname;
|
st_geometrytype(lines[i]), dbgname;
|
||||||
-- For manual debugging, usually when wm_exaggeration returns
|
--exit lineloop;
|
||||||
-- ST_MultiLineString. Uncomment the code below and change `raise`
|
|
||||||
-- to `raise notice` above.
|
|
||||||
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 lineloop;
|
|
||||||
end if;
|
end if;
|
||||||
gen = gen + 1;
|
gen = gen + 1;
|
||||||
continue;
|
continue;
|
||||||
@ -776,4 +821,5 @@ begin
|
|||||||
elseif l_type = 'ST_MultiLineString' then
|
elseif l_type = 'ST_MultiLineString' then
|
||||||
return st_union(lines);
|
return st_union(lines);
|
||||||
end if;
|
end if;
|
||||||
end $$ language plpgsql;
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
Loading…
Reference in New Issue
Block a user