Douglas-Peucker transfer-node elimination on pre-processor level

This commit is contained in:
Arndt Brenschede 2019-07-30 11:36:45 +02:00
parent 0a6ead24a1
commit aa7bb37a99
2 changed files with 81 additions and 19 deletions

View file

@ -0,0 +1,66 @@
/**
* Filter to eliminate some transfer nodes (Douglas-Peucker algorithm)
*
* @author ab
*/
package btools.mapcreator;
import java.util.ArrayList;
import btools.util.CheapRuler;
public class DPFilter
{
private static double dp_sql_threshold = 0.4 * 0.4;
/*
* for each node (except first+last), eventually set the DP_SURVIVOR_BIT
*/
public static void doDPFilter( ArrayList<OsmNodeP> nodes, int first, int last )
{
double maxSqDist = -1.;
int index = -1;
OsmNodeP p1 = nodes.get( first );
OsmNodeP p2 = nodes.get( last );
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( (p1.ilat+p2.ilat) >> 1 );
double dlon2m = lonlat2m[0];
double dlat2m = lonlat2m[1];
double dx = (p2.ilon - p1.ilon) * dlon2m;
double dy = (p2.ilat - p1.ilat) * dlat2m;
double d2 = dx * dx + dy * dy;
for ( int i = first + 1; i < last; i++ )
{
OsmNodeP p = nodes.get( i );
double t = 0.;
if ( d2 != 0f )
{
t = ( ( p.ilon - p1.ilon ) * dlon2m * dx + ( p.ilat - p1.ilat ) * dlat2m * dy ) / d2;
t = t > 1. ? 1. : ( t < 0. ? 0. : t );
}
double dx2 = (p.ilon - ( p1.ilon + t*( p2.ilon - p1.ilon ) ) ) * dlon2m;
double dy2 = (p.ilat - ( p1.ilat + t*( p2.ilat - p1.ilat ) ) ) * dlat2m;
double sqDist = dx2 * dx2 + dy2 * dy2;
if ( sqDist > maxSqDist )
{
index = i;
maxSqDist = sqDist;
}
}
if ( index >= 0 )
{
if ( index - first > 1 )
{
doDPFilter( nodes, first, index );
}
if ( maxSqDist >= dp_sql_threshold )
{
nodes.get( index ).bits |= OsmNodeP.DP_SURVIVOR_BIT;
}
if ( last - index > 1 )
{
doDPFilter( nodes, index, last );
}
}
}
}

View file

@ -35,6 +35,7 @@ public class OsmNodeP extends OsmLinkP
public final static int TRAFFIC_BIT = 8; public final static int TRAFFIC_BIT = 8;
public final static int ANY_WAY_BIT = 16; public final static int ANY_WAY_BIT = 16;
public final static int MULTI_WAY_BIT = 32; public final static int MULTI_WAY_BIT = 32;
public final static int DP_SURVIVOR_BIT = 64;
public byte bits = 0; public byte bits = 0;
@ -200,10 +201,15 @@ public class OsmNodeP extends OsmLinkP
OsmNodeP origin = this; OsmNodeP origin = this;
OsmNodeP target = null; OsmNodeP target = null;
ArrayList<OsmNodeP> linkNodes = new ArrayList<OsmNodeP>();
linkNodes.add( this );
// first pass just to see if that link is consistent // first pass just to see if that link is consistent
while (link != null) while (link != null)
{ {
target = link.getTarget( origin ); target = link.getTarget( origin );
linkNodes.add( target );
if ( !target.isTransferNode() ) if ( !target.isTransferNode() )
{ {
break; break;
@ -244,30 +250,20 @@ public class OsmNodeP extends OsmLinkP
mc.writeVarLengthSigned( target.ilon - ilon ); mc.writeVarLengthSigned( target.ilon - ilon );
mc.writeVarLengthSigned( target.ilat - ilat ); mc.writeVarLengthSigned( target.ilat - ilat );
mc.writeModeAndDesc( isReverse, link0.descriptionBitmap ); mc.writeModeAndDesc( isReverse, link0.descriptionBitmap );
if ( !isReverse ) // write geometry for forward links only if ( !isReverse && linkNodes.size() > 2 ) // write geometry for forward links only
{ {
link = link0; DPFilter.doDPFilter( linkNodes, 0, linkNodes.size()-1 );
origin = this; origin = this;
while (link != null) for( int i=1; i<linkNodes.size()-1; i++ )
{ {
OsmNodeP tranferNode = link.getTarget( origin ); OsmNodeP tranferNode = linkNodes.get(i);
if ( !tranferNode.isTransferNode() ) if ( ( tranferNode.bits & OsmNodeP.DP_SURVIVOR_BIT ) != 0 )
{ {
break; mc.writeVarLengthSigned( tranferNode.ilon - origin.ilon );
mc.writeVarLengthSigned( tranferNode.ilat - origin.ilat );
mc.writeVarLengthSigned( tranferNode.getSElev() - origin.getSElev() );
origin = tranferNode;
} }
mc.writeVarLengthSigned( tranferNode.ilon - origin.ilon );
mc.writeVarLengthSigned( tranferNode.ilat - origin.ilat );
mc.writeVarLengthSigned( tranferNode.getSElev() - origin.getSElev() );
// next link is the one (of two), does does'nt point back
for ( link = tranferNode.getFirstLink(); link != null; link = link.getNext( tranferNode ) )
{
if ( link.getTarget( tranferNode ) != origin )
break;
}
if ( link == null )
throw new RuntimeException( "follow-up link not found for transfer-node!" );
origin = tranferNode;
} }
} }
mc.injectSize( sizeoffset ); mc.injectSize( sizeoffset );