Rev 4786 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Copyright (C) 2012.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 or
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
package uk.me.parabola.mkgmap.filters;
import java.util.ArrayList;
import java.util.List;
import uk.me.parabola.imgfmt.Utils;
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.log.Logger;
import uk.me.parabola.mkgmap.general.MapElement;
import uk.me.parabola.mkgmap.general.MapLine;
import uk.me.parabola.mkgmap.general.MapShape;
/**
* Filter for lines and shapes. Remove obsolete points on straight lines and spikes.
* @author GerdP
*
*/
public class RemoveObsoletePointsFilter
implements MapFilter
{
private static final Logger log =
Logger.
getLogger(RemoveObsoletePointsFilter.
class);
private boolean checkPreserved
;
@
Override
public void init
(FilterConfig config
) {
checkPreserved = config.
getLevel() ==
0 && config.
hasNet();
}
/**
* @param element A map element that will be a line or a polygon.
* @param next This is used to pass the possibly transformed element onward.
*/
@
Override
public void doFilter
(MapElement element, MapFilterChain next
) {
MapLine line =
(MapLine
) element
;
List<Coord
> points = line.
getPoints();
int numPoints = points.
size();
if (numPoints
<=
1) {
return;
}
int requiredPoints =
(line
instanceof MapShape
) ? 4:
2;
List<Coord
> newPoints =
new ArrayList<>(numPoints
);
while (true){
boolean removedSpike =
false;
numPoints = points.
size();
Coord lastP = points.
get(0);
newPoints.
add(lastP
);
for (int i =
1; i
< numPoints
; i++
) {
Coord newP = points.
get(i
);
int last = newPoints.
size()-
1;
lastP = newPoints.
get(last
);
if (lastP.
equals(newP
)){
// only add the new point if it has different
// coordinates to the last point or is preserved
if (checkPreserved
&& line.
isRoad()) {
if (!newP.
preserved()) {
continue;
} else if (!lastP.
preserved()) {
newPoints.
set(last, newP
); // replace last
continue;
}
} else {
continue;
}
}
if (newPoints.
size() > 1) {
switch (Utils.
isStraight(newPoints.
get(last-
1), lastP, newP
)){
case Utils.
STRICTLY_STRAIGHT:
if (checkPreserved
&& lastP.
preserved() && line.
isRoad()){
// keep it
} else {
log.
debug("found three consecutive points on strictly straight line");
newPoints.
set(last, newP
);
continue;
}
break;
case Utils.
STRAIGHT_SPIKE:
if (line
instanceof MapShape
){
log.
debug("removing spike");
newPoints.
remove(last
);
removedSpike =
true;
if (newPoints.
get(last-
1).
equals(newP
))
continue;
}
break;
default:
break;
}
}
newPoints.
add(newP
);
}
if (!removedSpike || newPoints.
size() < requiredPoints
)
break;
points = newPoints
;
newPoints =
new ArrayList<>(points.
size());
}
if (line
instanceof MapShape
){
// Check special cases caused by the fact that the first and last point
// in a shape are identical.
while (newPoints.
size() > 3){
int nPoints = newPoints.
size();
switch(Utils.
isStraight(newPoints.
get(newPoints.
size()-
2), newPoints.
get(0), newPoints.
get(1))){
case Utils.
STRAIGHT_SPIKE:
log.
debug("removing closing spike");
newPoints.
remove(0);
newPoints.
set(newPoints.
size()-
1, newPoints.
get(0));
if (newPoints.
get(newPoints.
size()-
2).
equals(newPoints.
get(newPoints.
size()-
1)))
newPoints.
remove(newPoints.
size()-
2);
break;
case Utils.
STRICTLY_STRAIGHT:
log.
debug("removing straight line across closing");
newPoints.
remove(newPoints.
size()-
1);
newPoints.
set(0, newPoints.
get(newPoints.
size()-
1));
break;
}
if (nPoints == newPoints.
size())
break;
}
} else if (!checkPreserved
&& newPoints.
size() > 2) {
// check for special case that line goes a-b-a or a-b-c-b-a or ... and cut in the middle
// typical for dual-carriage ways at low resolutions
int lenDup =
0;
while (newPoints.
get(lenDup
).
equals(newPoints.
get(newPoints.
size() -
1 - lenDup
))) {
lenDup++
;
if (lenDup
> newPoints.
size() -
1 - lenDup
)
break;
}
if (lenDup
> 1 ) {
// line starts and ends with the same sequence of points, remove one sequence
newPoints = newPoints.
subList(0, newPoints.
size() +
1 - lenDup
);
}
}
if (newPoints.
size() != line.
getPoints().
size()){
if (line
instanceof MapShape
&& newPoints.
size() <=
3 || newPoints.
size() <=
1)
return;
MapLine newLine = line.
copy();
newLine.
setPoints(newPoints
);
next.
doFilter(newLine
);
} else {
// no need to create new object
next.
doFilter(line
);
}
}
}