Compare commits

...

22 commits

Author SHA1 Message Date
Arndt Brenschede
c7b5f2b5de suspect-manager: uups-fix 2018-10-02 09:49:46 +02:00
Arndt Brenschede
be1ef91a0c suspect-manager: some fixes 2018-09-22 21:00:11 +02:00
Arndt Brenschede
3d81c7938f search circles: bugfix + effective coverage 2018-09-16 09:32:08 +02:00
Arndt Brenschede
b81ebca103 minor performance patch 2018-09-16 09:30:45 +02:00
Arndt Brenschede
2c6617f99a suspect-manager: dynamic polygons 2018-09-16 09:30:17 +02:00
Arndt Brenschede
8ee4f57375 Merge branch 'master' into suspectscanner 2018-09-15 15:52:44 +02:00
Arndt Brenschede
448b1db2a2 merge master->suspectscanner 2018-09-15 15:50:57 +02:00
Arndt Brenschede
761feb4ac7 suspectscanner: search-circlees 2018-09-15 09:58:35 +02:00
Arndt Brenschede
ff31300a6a performance fix 2018-09-14 13:49:10 +02:00
Arndt Brenschede
0fe6773536 performance fix 2018-09-13 13:07:16 +02:00
Arndt Brenschede
02520733cc Issue archive: more selective 2018-09-01 12:27:08 +02:00
Arndt Brenschede
aecb3f3707 inverse mode, fixed false-positive bug 2018-08-21 20:17:28 +02:00
Arndt Brenschede
10931da3a7 destination access logic 2018-06-02 13:22:44 +02:00
ProBackup-nl
7881952682 Create vm-forum-liegerad-schnell.brf 2018-06-02 13:22:01 +02:00
Arndt Brenschede
313def7f7c fixed bug for TR near start/end 2018-06-02 13:21:37 +02:00
Arndt Brenschede
17aba8d04d 1.4.11 preps 2018-06-02 13:14:47 +02:00
Arndt Brenschede
bacc956ac2 1.4.11 preps 2018-06-02 13:14:27 +02:00
Arndt Brenschede
971a5e904b automatically ignore islands 2018-06-02 13:14:06 +02:00
Arndt Brenschede
230765106e breaking speeds from cost model + cost tuning 2018-06-02 13:13:40 +02:00
Arndt Brenschede
1f358b3d48 energy along the track 2018-06-02 13:13:19 +02:00
Arndt Brenschede
e5d8bd9bf4 initail commit suspect detection 2018-03-10 10:41:11 +01:00
Arndt Brenschede
e6601b9a61 extraParams in addition to routing-profile 2018-03-10 10:33:54 +01:00
11 changed files with 605 additions and 89 deletions

View file

@ -286,10 +286,25 @@ abstract class OsmPath implements OsmLinkHolder
tr = tr.next; tr = tr.next;
} }
if ( !hasPositive && ( hasAnyPositive || hasNegative ) ) if ( !hasPositive && ( hasAnyPositive || hasNegative ) )
{
if ( rc.considerTurnRestrictions && !detailMode )
{ {
cost = -1; cost = -1;
return; return;
} }
if ( !rc.considerTurnRestrictions && detailMode ) // detect effective (=suspect) TRs
{
if ( rc.suspectTRs != null && priorityclassifier > 20 && cost > 2000 && cost < rc.maxcost - 2000 )
{
Long id = Long.valueOf( sourceNode.getIdFromPos() );
if ( rc.suspectTRs.get( id ) == null )
{
System.out.println( "bad TR candidate: " + id );
rc.suspectTRs.put( id, Integer.valueOf( priorityclassifier ) );
}
}
}
}
} }
// if recording, new MessageData for each section (needed for turn-instructions) // if recording, new MessageData for each section (needed for turn-instructions)
@ -372,8 +387,12 @@ abstract class OsmPath implements OsmLinkHolder
double elevation = ele2 == Short.MIN_VALUE ? 100. : ele2/4.; double elevation = ele2 == Short.MIN_VALUE ? 100. : ele2/4.;
double sectionCost = processWaySection( rc, dist, delta_h, elevation, angle, cosangle, isStartpoint, nsection, lastpriorityclassifier ); double sectionCost = processWaySection( rc, dist, delta_h, elevation, angle, cosangle, isStartpoint, nsection, lastpriorityclassifier );
if ( ( sectionCost < 0. || costfactor > 9998. && !detailMode ) || sectionCost + cost >= 2000000000. ) if ( ( sectionCost < 0. || costfactor > 9996. && !detailMode ) || sectionCost + cost >= 2000000000. )
{ {
if ( ( costfactor == 9998. && priorityclassifier == lastpriorityclassifier ) || costfactor == 9997. )
{
rc.foundWayBlock = Math.max( rc.foundWayBlock, priorityclassifier );
}
cost = -1; cost = -1;
return; return;
} }
@ -462,6 +481,17 @@ abstract class OsmPath implements OsmLinkHolder
double targetCost = processTargetNode( rc ); double targetCost = processTargetNode( rc );
if ( targetCost < 0. || targetCost + cost >= 2000000000. ) if ( targetCost < 0. || targetCost + cost >= 2000000000. )
{ {
if ( rc.suspectNodes != null && priorityclassifier > 20 && rc.inverseDirection == rc.inverseRouting )
{
rc.foundNodeBlock = true;
Long id = Long.valueOf( targetNode.getIdFromPos() );
Integer val = rc.suspectNodes.get( id );
if ( val == null || priorityclassifier > val.intValue() )
{
rc.suspectNodes.put( id, Integer.valueOf( priorityclassifier ) );
}
}
cost = -1; cost = -1;
return; return;
} }

View file

@ -8,6 +8,7 @@ package btools.router;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -35,6 +36,13 @@ public final class RoutingContext
public String rawTrackPath; public String rawTrackPath;
public Map<Long,Integer> suspectNodes;
public Map<Long,Integer> suspectTRs;
public boolean foundNodeBlock;
public int foundWayBlock;
public int maxcost;
public String getProfileName() public String getProfileName()
{ {
String name = localFunction == null ? "unknown" : localFunction; String name = localFunction == null ? "unknown" : localFunction;
@ -57,7 +65,7 @@ public final class RoutingContext
public int uphillcutoff; public int uphillcutoff;
public boolean carMode; public boolean carMode;
public boolean bikeMode; public boolean bikeMode;
public boolean considerTurnRestrictions; public boolean considerTurnRestrictions = true;
public boolean processUnusedTags; public boolean processUnusedTags;
public boolean forceSecondaryData; public boolean forceSecondaryData;
public double pass1coefficient; public double pass1coefficient;
@ -131,7 +139,7 @@ public final class RoutingContext
bikeMode = 0.f != expctxGlobal.getVariableValue( "validForBikes", 0.f ); bikeMode = 0.f != expctxGlobal.getVariableValue( "validForBikes", 0.f );
// turn-restrictions used per default for car profiles // turn-restrictions used per default for car profiles
considerTurnRestrictions = 0.f != expctxGlobal.getVariableValue( "considerTurnRestrictions", carMode ? 1.f : 0.f ); considerTurnRestrictions = 0.f != expctxGlobal.getVariableValue( "considerTurnRestrictions", carMode && considerTurnRestrictions ? 1.f : 0.f );
// process tags not used in the profile (to have them in the data-tab) // process tags not used in the profile (to have them in the data-tab)
processUnusedTags = 0.f != expctxGlobal.getVariableValue( "processUnusedTags", 0.f ); processUnusedTags = 0.f != expctxGlobal.getVariableValue( "processUnusedTags", 0.f );
@ -161,7 +169,7 @@ public final class RoutingContext
trafficSourceMinDist = expctxGlobal.getVariableValue( "trafficSourceMinDist", 3000.f ); trafficSourceMinDist = expctxGlobal.getVariableValue( "trafficSourceMinDist", 3000.f );
showspeed = 0.f != expctxGlobal.getVariableValue( "showspeed", 0.f ); showspeed = 0.f != expctxGlobal.getVariableValue( "showspeed", 0.f );
inverseRouting = 0.f != expctxGlobal.getVariableValue( "inverseRouting", 0.f ); inverseRouting = 0.f != expctxGlobal.getVariableValue( "inverseRouting", inverseRouting ? 1.f : 0.f );
int tiMode = (int)expctxGlobal.getVariableValue( "turnInstructionMode", 0.f ); int tiMode = (int)expctxGlobal.getVariableValue( "turnInstructionMode", 0.f );
if ( tiMode != 1 ) // automatic selection from coordinate source if ( tiMode != 1 ) // automatic selection from coordinate source

View file

@ -9,6 +9,7 @@ import java.io.Writer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
import btools.mapaccess.NodesCache; import btools.mapaccess.NodesCache;
import btools.mapaccess.OsmLink; import btools.mapaccess.OsmLink;
@ -279,16 +280,43 @@ public class RoutingEngine extends Thread
public void doSearch() public void doSearch()
{
doSearch(0);
}
public void doSearch( int radius )
{ {
try try
{
List<MatchedWaypoint> wpList = new ArrayList<MatchedWaypoint>();
for( OsmNodeNamed wp : waypoints )
{ {
MatchedWaypoint seedPoint = new MatchedWaypoint(); MatchedWaypoint seedPoint = new MatchedWaypoint();
seedPoint.waypoint = waypoints.get(0); seedPoint.waypoint = wp;
List<MatchedWaypoint> listOne = new ArrayList<MatchedWaypoint>(); wpList.add( seedPoint );
listOne.add( seedPoint ); }
matchWaypointsToNodes( listOne );
findTrack( "seededSearch", seedPoint, null, null, null, false ); resetCache( false );
nodesCache.waypointMatcher = new WaypointMatcherImpl( wpList, 250., islandNodePairs );
for( MatchedWaypoint mwp : wpList )
{
preloadPosition( mwp.waypoint );
}
for( MatchedWaypoint mwp : wpList )
{
if ( mwp.crosspoint != null )
{
if ( radius > 0 )
{
boundary = new SearchBoundary( mwp.waypoint, radius, 0 );
routingContext.inverseRouting = !routingContext.inverseRouting; // hack
routingContext.inverseDirection = routingContext.inverseRouting;
}
MAXNODES_ISLAND_CHECK = -1;
findTrack( "seededSearch", mwp, null, null, null, false );
}
}
} }
catch( IllegalArgumentException e) catch( IllegalArgumentException e)
{ {
@ -978,6 +1006,7 @@ public class RoutingEngine extends Thread
} }
routingContext.firstPrePath = null; routingContext.firstPrePath = null;
routingContext.maxcost = maxTotalCost;
for( OsmLink link = currentNode.firstlink; link != null; link = link.getNext( currentNode) ) for( OsmLink link = currentNode.firstlink; link != null; link = link.getNext( currentNode) )
{ {
@ -1004,28 +1033,35 @@ public class RoutingEngine extends Thread
} }
} }
int nPathPossible = 0;
routingContext.foundNodeBlock = false;
routingContext.foundWayBlock = 0;
for( OsmLink link = currentNode.firstlink; link != null; link = link.getNext( currentNode) ) for( OsmLink link = currentNode.firstlink; link != null; link = link.getNext( currentNode) )
{ {
OsmNode nextNode = link.getTarget( currentNode ); OsmNode nextNode = link.getTarget( currentNode );
if ( ! nodesCache.obtainNonHollowNode( nextNode ) ) if ( ! nodesCache.obtainNonHollowNode( nextNode ) )
{ {
nPathPossible++;
continue; // border node? continue; // border node?
} }
if ( nextNode.firstlink == null )
{
continue; // don't care about dead ends
}
if ( nextNode == sourceNode ) if ( nextNode == sourceNode )
{ {
continue; // border node? continue; // border node?
} }
if ( nextNode.firstlink == null )
{
nPathPossible++;
continue; // don't care about dead ends
}
if ( guideTrack != null ) if ( guideTrack != null )
{ {
int gidx = path.treedepth + 1; int gidx = path.treedepth + 1;
if ( gidx >= guideTrack.nodes.size() ) if ( gidx >= guideTrack.nodes.size() )
{ {
nPathPossible++;
continue; continue;
} }
OsmPathElement guideNode = guideTrack.nodes.get( routingContext.inverseRouting ? guideTrack.nodes.size() - 1 - gidx : gidx ); OsmPathElement guideNode = guideTrack.nodes.get( routingContext.inverseRouting ? guideTrack.nodes.size() - 1 - gidx : gidx );
@ -1035,11 +1071,14 @@ public class RoutingEngine extends Thread
// not along the guide-track, discard, but register for voice-hint processing // not along the guide-track, discard, but register for voice-hint processing
if ( routingContext.turnInstructionMode > 0 ) if ( routingContext.turnInstructionMode > 0 )
{ {
Map<Long,Integer> trSuspects = routingContext.suspectTRs;
routingContext.suspectTRs = null;
OsmPath detour = routingContext.createPath( path, link, refTrack, true ); OsmPath detour = routingContext.createPath( path, link, refTrack, true );
if ( detour.cost >= 0. && nextId != startNodeId1 && nextId != startNodeId2 ) if ( detour.cost >= 0. && nextId != startNodeId1 && nextId != startNodeId2 )
{ {
guideTrack.registerDetourForId( currentNode.getIdFromPos(), OsmPathElement.create( detour, false ) ); guideTrack.registerDetourForId( currentNode.getIdFromPos(), OsmPathElement.create( detour, false ) );
} }
routingContext.suspectTRs = trSuspects;
} }
continue; continue;
} }
@ -1080,6 +1119,8 @@ public class RoutingEngine extends Thread
} }
if ( bestPath != null ) if ( bestPath != null )
{ {
nPathPossible++;
boolean trafficSim = endPos == null; boolean trafficSim = endPos == null;
bestPath.airdistance = trafficSim ? keepPathAirdistance : ( isFinalLink ? 0 : nextNode.calcDistance( endPos ) ); bestPath.airdistance = trafficSim ? keepPathAirdistance : ( isFinalLink ? 0 : nextNode.calcDistance( endPos ) );
@ -1116,6 +1157,29 @@ public class RoutingEngine extends Thread
} }
} }
// report oneway dead-ends as suspects
if ( routingContext.suspectNodes != null && path.priorityclassifier > 20 && currentNode.virgin && path.cost > 2000 && routingContext.inverseDirection == routingContext.inverseRouting && guideTrack == null )
{
int suspectPrio = 0;
if ( nPathPossible == 0 && (!routingContext.foundNodeBlock) )
{
suspectPrio = path.priorityclassifier;
}
else if ( routingContext.foundWayBlock != 0 )
{
suspectPrio = routingContext.foundWayBlock;
}
if ( suspectPrio > 20 )
{
Long id = Long.valueOf( currentNode.getIdFromPos() );
Integer val = routingContext.suspectNodes.get( id );
if ( val == null || suspectPrio > val.intValue() )
{
routingContext.suspectNodes.put( id, Integer.valueOf( suspectPrio ) );
}
}
}
path.unregisterUpTree( routingContext ); path.unregisterUpTree( routingContext );
} }
@ -1214,7 +1278,7 @@ public class RoutingEngine extends Thread
track.buildMap(); track.buildMap();
// for final track.. // for final track..
if ( guideTrack != null ) if ( guideTrack != null && routingContext.turnInstructionMode > 0 )
{ {
track.copyDetours( guideTrack ); track.copyDetours( guideTrack );
track.processVoiceHints( routingContext ); track.processVoiceHints( routingContext );

View file

@ -40,6 +40,8 @@ public class OsmNode extends OsmLink implements OsmPos
*/ */
public OsmLink firstlink = null; public OsmLink firstlink = null;
public boolean virgin = true;
public OsmNode() public OsmNode()
{ {
} }
@ -107,9 +109,9 @@ public class OsmNode extends OsmLink implements OsmPos
double l4 = l2 * l2; double l4 = l2 * l2;
double coslat = 1. - l2 + l4 / 6.; double coslat = 1. - l2 + l4 / 6.;
double dlat = ( ilat - p.getILat() ) / 1000000.; double dlat = ( ilat - p.getILat() );
double dlon = ( ilon - p.getILon() ) / 1000000. * coslat; double dlon = ( ilon - p.getILon() ) * coslat;
double d = Math.sqrt( dlat * dlat + dlon * dlon ) * 110984.; // 6378000. / 57.3; double d = Math.sqrt( dlat * dlat + dlon * dlon ) * 0.110984; // 6378000. / 57.3;
return (int) ( d + 1.0 ); return (int) ( d + 1.0 );
} }
@ -232,6 +234,8 @@ public class OsmNode extends OsmLink implements OsmPos
public final void unlinkLink( OsmLink link ) public final void unlinkLink( OsmLink link )
{ {
virgin = false;
OsmLink n = link.clear( this ); OsmLink n = link.clear( this );
if ( link == firstlink ) if ( link == firstlink )

View file

@ -51,7 +51,7 @@ public class Area
{ {
for( int j=0; j<neglist.size(); j++) for( int j=0; j<neglist.size(); j++)
{ {
if ( neglist.get(i).isInPolygon( id ) ) if ( neglist.get(j).isInPolygon( id ) )
{ {
return false; return false;
} }

View file

@ -136,7 +136,7 @@ public class BRouter
} }
private static OsmNodeNamed readPosition( String[] args, int idx, String name ) public static OsmNodeNamed readPosition( String[] args, int idx, String name )
{ {
OsmNodeNamed n = new OsmNodeNamed(); OsmNodeNamed n = new OsmNodeNamed();
n.name = name; n.name = name;

View file

@ -0,0 +1,90 @@
package btools.server;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import btools.mapaccess.OsmNode;
import btools.router.OsmNodeNamed;
import btools.router.RoutingContext;
import btools.router.RoutingEngine;
import btools.router.SearchBoundary;
public class BadTRDetector
{
public static void main(String[] args) throws Exception
{
System.out.println("BadTRDetector / 12092018 / abrensch");
if ( args.length < 7 )
{
System.out.println("Find bad TR candidates in OSM");
System.out.println("usage: java BadTRDetector <segmentdir> <lon-from> <lat-from> <lon-to> <lat-to> <profile> <nshots>");
return;
}
int x0 = Integer.parseInt( args[1]);
int y0 = Integer.parseInt( args[2]);
int x1 = Integer.parseInt( args[3]);
int y1 = Integer.parseInt( args[4]);
String profile = args[5];
int radius = Integer.parseInt( args[6] );
double overlap = Double.parseDouble( args[7] );
Random rand = new Random();
Map<Long,Integer> suspectTRs = new HashMap<Long,Integer>();
for( int y = y0; y < y1; y++ )
{
for( int x = x0; x < x1; x++ )
{
// calculate n-circles for this latitude
int lon0 = 1000000 * ( x + 180 );
int lat0 = 1000000 * ( y + 90 );
OsmNode n0 = new OsmNode( lon0, lat0 );
double arect = n0.calcDistance( new OsmNode( lon0, lat0 + 1000000 ) );
arect *= n0.calcDistance( new OsmNode( lon0 + 1000000, lat0 ) );
double adisc = ( Math.PI * radius ) * radius;
int shots = (int)(1. + overlap * arect / adisc);
System.out.println( "shots for y=" + y + " x=" + x + " -> " + shots );
List<OsmNodeNamed> wplist = new ArrayList<OsmNodeNamed>();
for( int shot=0; shot<shots; shot++ )
{
OsmNodeNamed n = new OsmNodeNamed();
n.name = "from";
n.ilon = lon0 + rand.nextInt( 1000000 );
n.ilat = lat0 + rand.nextInt( 1000000 );
wplist.add( n );
}
RoutingContext rc = new RoutingContext();
rc.localFunction = profile;
rc.memoryclass = (int) ( Runtime.getRuntime().maxMemory() / 1024 / 1024 );
rc.suspectNodes = suspectTRs;
rc.inverseRouting = rand.nextBoolean();
RoutingEngine re = new RoutingEngine( "mytrack", "mylog", args[0], wplist, rc );
re.doSearch( radius );
if ( re.getErrorMessage() != null )
{
System.out.println( re.getErrorMessage() );
}
}
}
// write tr-suspects to file
String suspectsFile = "deadend.suspects";
BufferedWriter bw = new BufferedWriter( new FileWriter( new File( suspectsFile ) ) );
for( Long suspect : suspectTRs.keySet() )
{
bw.write( suspect + " " + suspectTRs.get( suspect ) + "\r\n" );
}
bw.close();
}
}

View file

@ -0,0 +1,71 @@
package btools.server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
public class IssueArchiver
{
public static void main(String[] args) throws Exception
{
if ( args.length < 3 )
{
System.out.println( "usage : IssueArchiver <new-suspect-dir> <old-suspect-dir> <suspect-archive>" );
System.exit(1);
}
File newSuspectDir = new File( args[0] );
if ( !newSuspectDir.isDirectory() )
{
throw new IllegalArgumentException( "not a directory: " + newSuspectDir );
}
File oldSuspectDir = new File( args[1] );
if ( !oldSuspectDir.isDirectory() )
{
throw new IllegalArgumentException( "not a directory: " + oldSuspectDir );
}
File suspectArchive = new File( args[2] );
if ( !suspectArchive.isDirectory() )
{
throw new IllegalArgumentException( "not a directory: " + suspectArchive );
}
File[] newFiles = newSuspectDir.listFiles();
for ( File newFile : newFiles )
{
String name = newFile.getName();
if ( name.startsWith( "suspects_" ) && name.endsWith( ".txt" ) )
{
File oldFile = new File( oldSuspectDir, name );
if ( !oldFile.exists() ) continue;
System.out.println( "archiving " + oldFile );
BufferedReader br = new BufferedReader( new FileReader( oldFile ) );
for(;;)
{
String line = br.readLine();
if ( line == null ) break;
StringTokenizer tk = new StringTokenizer( line );
long id = Long.parseLong( tk.nextToken() );
int prio = Integer.parseInt( tk.nextToken() );
File archiveEntry = new File( suspectArchive, "" + id );
if ( !archiveEntry.exists() )
{
archiveEntry.createNewFile();
}
}
br.close();
}
}
}
}

View file

@ -0,0 +1,40 @@
package btools.server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
public class IssueFilter
{
public static void main(String[] args) throws Exception
{
if ( args.length != 2 )
{
System.out.println( "usage : IssueFilter <in-file> <out-file> " );
System.exit(1);
}
BufferedReader br = new BufferedReader( new FileReader( new File( args[0] ) ) );
BufferedWriter bw = new BufferedWriter( new FileWriter( new File( args[1] ) ) );
for(;;)
{
String line = br.readLine();
if ( line == null ) break;
if ( line.startsWith( "bad TR candidate: " ) )
{
bw.write( line.substring( "bad TR candidate: ".length() ) );
bw.write( "\r\n" );
}
}
br.close();
bw.close();
}
}

View file

@ -0,0 +1,121 @@
package btools.server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
public class IssueSorter
{
public static void main(String[] args) throws Exception
{
if ( args.length < 2 )
{
System.out.println( "usage : IssueSorter <in-file> <out-file> [<osm-filter>]" );
System.exit(1);
}
File osmFilter = args.length > 2 ? new File( args[2] ) : null;
Set<Long> filterSet = null;
// if the osm-filter exists, read it
if ( osmFilter != null && osmFilter.exists() )
{
filterSet = new HashSet<Long>();
BufferedReader r = new BufferedReader( new FileReader( osmFilter ) );
for(;;)
{
String line = r.readLine();
if ( line == null ) break;
int idx0 = line.indexOf( "<node id=\"" );
if ( idx0 < 0 ) continue;
idx0 += 10;
int idx1 = line.indexOf( '"', idx0 );
long nodeId = Long.parseLong( line.substring( idx0, idx1 ) );
filterSet.add( Long.valueOf( nodeId ) );
}
r.close();
}
TreeMap<String,TreeMap<Long,Integer>> keys = new TreeMap<String,TreeMap<Long,Integer>>();
BufferedReader br = new BufferedReader( new FileReader( new File( args[0] ) ) );
for(;;)
{
String line = br.readLine();
if ( line == null ) break;
StringTokenizer tk = new StringTokenizer( line );
long id = Long.parseLong( tk.nextToken() );
int prio = Integer.parseInt( tk.nextToken() );
if ( filterSet != null && !filterSet.contains( Long.valueOf( id ) ) )
{
continue;
}
int ilon = (int) ( id >> 32 );
int ilat = (int) ( id & 0xffffffff );
String key = getKey( ilon, ilat );
TreeMap<Long,Integer> map = keys.get( key );
if ( map == null )
{
map = new TreeMap<Long,Integer>();
keys.put( key, map );
}
map.put( Long.valueOf( id ), Integer.valueOf( prio ) );
}
br.close();
// write suspects to file
BufferedWriter bw = new BufferedWriter( new FileWriter( new File( args[1] ) ) );
for( String key : keys.keySet() )
{
TreeMap<Long,Integer> map = keys.get( key );
for( Long suspect : map.keySet() )
{
bw.write( suspect + " " + map.get( suspect ) + "\r\n" );
}
}
bw.close();
// if the osm-filter does not exist, write it
if ( osmFilter != null && !osmFilter.exists() )
{
bw = new BufferedWriter( new FileWriter( osmFilter ) );
bw.write( "<?xml version='1.0' encoding='UTF-8'?>\n" );
bw.write( "<osm version=\"0.6\">\n" );
for( String key : keys.keySet() )
{
TreeMap<Long,Integer> map = keys.get( key );
for( Long suspect : map.keySet() )
{
long id = suspect.longValue();
int ilon = (int) ( id >> 32 );
int ilat = (int) ( id & 0xffffffff );
double dlon = (ilon-180000000)/1000000.;
double dlat = (ilat-90000000)/1000000.;
bw.write( "<node id=\"" + id + "\" version=\"1\" timestamp=\"2017-01-10T12:00:00Z\" uid=\"1\" user=\"me\" changeset=\"1\" lat=\"" + dlat + "\" lon=\"" + dlon + "\"/>\n" );
}
}
bw.write( "</osm>\n" );
bw.close();
}
}
public static String getKey( int ilon, int ilat )
{
int lon = (ilon / 1000000 );
int lat = (ilat / 1000000 );
return "" + (100000 + lon*360 + lat);
}
}

View file

@ -24,7 +24,11 @@ public class SuspectManager extends Thread
private static String formatAge( File f ) private static String formatAge( File f )
{ {
long age = System.currentTimeMillis() - f.lastModified(); return formatAge( System.currentTimeMillis() - f.lastModified() );
}
private static String formatAge( long age )
{
long minutes = age / 60000; long minutes = age / 60000;
if ( minutes < 60 ) if ( minutes < 60 )
{ {
@ -67,7 +71,7 @@ public class SuspectManager extends Thread
while ( tk.hasMoreTokens() ) while ( tk.hasMoreTokens() )
{ {
String c = tk.nextToken(); String c = tk.nextToken();
if ( "all".equals( c ) || "new".equals( c ) ) if ( "all".equals( c ) || "new".equals( c ) || "confirmed".equals( c ) )
{ {
filter = c; filter = c;
break; break;
@ -93,6 +97,7 @@ public class SuspectManager extends Thread
{ {
String url2 = "/brouter/suspects" + country + "/" + c; String url2 = "/brouter/suspects" + country + "/" + c;
String linkNew = "<td>&nbsp;<a href=\"" + url2 + "/new\">new</a>&nbsp;</td>"; String linkNew = "<td>&nbsp;<a href=\"" + url2 + "/new\">new</a>&nbsp;</td>";
String linkCnf = "<td>&nbsp;<a href=\"" + url2 + "/confirmed\">confirmed</a>&nbsp;</td>";
String linkAll = "<td>&nbsp;<a href=\"" + url2 + "/all\">all</a>&nbsp;</td>"; String linkAll = "<td>&nbsp;<a href=\"" + url2 + "/all\">all</a>&nbsp;</td>";
String linkSub = ""; String linkSub = "";
@ -100,7 +105,7 @@ public class SuspectManager extends Thread
{ {
linkSub = "<td>&nbsp;<a href=\"" + url2 + "\">sub-regions</a>&nbsp;</td>"; linkSub = "<td>&nbsp;<a href=\"" + url2 + "\">sub-regions</a>&nbsp;</td>";
} }
bw.write( "<tr><td>" + c + "</td>" + linkNew + linkAll + linkSub + "\n" ); bw.write( "<tr><td>" + c + "</td>" + linkNew + linkCnf + linkAll + linkSub + "\n" );
} }
bw.write( "</table>\n" ); bw.write( "</table>\n" );
bw.write( "</body></html>\n" ); bw.write( "</body></html>\n" );
@ -127,6 +132,7 @@ public class SuspectManager extends Thread
bw.flush(); bw.flush();
return; return;
} }
SuspectList suspects = getAllSuspects( suspectFile );
boolean showWatchList = false; boolean showWatchList = false;
if ( tk.hasMoreTokens() ) if ( tk.hasMoreTokens() )
@ -146,35 +152,48 @@ public class SuspectManager extends Thread
{ {
bw.write( "watchlist for " + country + "\n" ); bw.write( "watchlist for " + country + "\n" );
bw.write( "<br><a href=\"/brouter/suspects\">back to country list</a><br><br>\n" ); bw.write( "<br><a href=\"/brouter/suspects\">back to country list</a><br><br>\n" );
BufferedReader r = new BufferedReader( new FileReader( suspectFile ) );
for ( ;; )
{
String line = r.readLine();
if ( line == null )
break;
StringTokenizer tk2 = new StringTokenizer( line );
id = Long.parseLong( tk2.nextToken() );
String countryId = country + "/" + filter + "/" + id;
long timeNow = System.currentTimeMillis();
for( int isuspect = 0; isuspect<suspects.cnt; isuspect++ )
{
id = suspects.ids[isuspect];
if ( !polygon.isInBoundingBox( id ) )
{
continue; // not in selected polygon (pre-check)
}
if ( new File( "falsepositives/" + id ).exists() ) if ( new File( "falsepositives/" + id ).exists() )
{ {
continue; // known false positive continue; // known false positive
} }
File confirmedEntry = new File( "confirmednegatives/" + id ); File fixedEntry = new File( "fixedsuspects/" + id );
if ( !( isFixed( id, suspectFile ) && confirmedEntry.exists() ) ) if ( !fixedEntry.exists() )
{ {
continue; continue;
} }
long age = System.currentTimeMillis() - confirmedEntry.lastModified(); long fixedTs = fixedEntry.lastModified();
if ( age / 1000 < 3600 * 24 * 8 ) if ( fixedTs < suspects.timestamp )
{ {
continue; continue; // that would be under current suspects
}
long hideTime = fixedTs - timeNow;
if ( hideTime < 0 )
{
File confirmedEntry = new File( "confirmednegatives/" + id );
if ( confirmedEntry.exists() && confirmedEntry.lastModified() > suspects.timestamp )
{
continue; // that would be under current suspects
}
} }
if ( !polygon.isInArea( id ) ) if ( !polygon.isInArea( id ) )
{ {
continue; // not in selected polygon continue; // not in selected polygon
} }
String hint = "&nbsp;&nbsp;&nbsp;confirmed " + formatAge( confirmedEntry ) + " ago";
String countryId = country + "/" + filter + "/" + id;
String dueTime = hideTime < 0 ? "(asap)" : formatAge( hideTime + 43200000 );
String hint = "&nbsp;&nbsp;&nbsp;due in " + dueTime;
int ilon = (int) ( id >> 32 ); int ilon = (int) ( id >> 32 );
int ilat = (int) ( id & 0xffffffff ); int ilat = (int) ( id & 0xffffffff );
double dlon = ( ilon - 180000000 ) / 1000000.; double dlon = ( ilon - 180000000 ) / 1000000.;
@ -182,7 +201,6 @@ public class SuspectManager extends Thread
String url2 = "/brouter/suspects" + countryId; String url2 = "/brouter/suspects" + countryId;
bw.write( "<a href=\"" + url2 + "\">" + dlon + "," + dlat + "</a>" + hint + "<br>\n" ); bw.write( "<a href=\"" + url2 + "\">" + dlon + "," + dlat + "</a>" + hint + "<br>\n" );
} }
r.close();
bw.write( "</body></html>\n" ); bw.write( "</body></html>\n" );
bw.flush(); bw.flush();
return; return;
@ -230,8 +248,15 @@ public class SuspectManager extends Thread
if ( tk.hasMoreTokens() ) if ( tk.hasMoreTokens() )
{ {
String param = tk.nextToken(); String param = tk.nextToken();
hideDays = Integer.parseInt( param ); hideDays = Integer.parseInt( param ); // hiding, not fixing
fixedMarker.setLastModified( System.currentTimeMillis() + hideDays*86400000L ); }
else // touch the confirmed entry when marking fixed
{
File confirmedEntry = new File( "confirmednegatives/" + id );
if ( confirmedEntry.exists() )
{
confirmedEntry.setLastModified( System.currentTimeMillis() );
}
} }
fixedMarker.setLastModified( System.currentTimeMillis() + hideDays*86400000L ); fixedMarker.setLastModified( System.currentTimeMillis() + hideDays*86400000L );
} }
@ -246,7 +271,7 @@ public class SuspectManager extends Thread
double dlat = ( ilat - 90000000 ) / 1000000.; double dlat = ( ilat - 90000000 ) / 1000000.;
String profile = "car-eco"; String profile = "car-eco";
File configFile = new File( "configs/" + country + ".cfg" ); File configFile = new File( "configs/profile.cfg" );
if ( configFile.exists() ) if ( configFile.exists() )
{ {
BufferedReader br = new BufferedReader( new FileReader( configFile ) ); BufferedReader br = new BufferedReader( new FileReader( configFile ) );
@ -271,7 +296,7 @@ public class SuspectManager extends Thread
String url4a = "https://overpass-turbo.eu/?Q=[date:&quot;" + formatZ( weekAgo ) + "Z&quot;];way[highway]({{bbox}});out meta geom;&C=" String url4a = "https://overpass-turbo.eu/?Q=[date:&quot;" + formatZ( weekAgo ) + "Z&quot;];way[highway]({{bbox}});out meta geom;&C="
+ dlat + ";" + dlon + ";18&R"; + dlat + ";" + dlon + ";18&R";
String url4b = "https://overpass-turbo.eu/?Q=(node(around%3A1%2C%7B%7Bcenter%7D%7D)-%3E.n%3Bway(bn.n)%3Brel(bn.n%3A%22via%22)%5Btype%3Drestriction%5D%3B)%3Bout%20meta%3B%3E%3Bout%20skel%20qt%3B&C=" String url4b = "https://overpass-turbo.eu/?Q=(node(around%3A1%2C%7B%7Bcenter%7D%7D)-%3E.n%3Bway(bn.n)%5Bhighway%5D%3Brel(bn.n%3A%22via%22)%5Btype%3Drestriction%5D%3B)%3Bout%20meta%3B%3E%3Bout%20skel%20qt%3B&C="
+ dlat + ";" + dlon + ";18&R"; + dlat + ";" + dlon + ";18&R";
String url5 = "https://tyrasd.github.io/latest-changes/#16/" + dlat + "/" + dlon; String url5 = "https://tyrasd.github.io/latest-changes/#16/" + dlat + "/" + dlon;
@ -286,7 +311,7 @@ public class SuspectManager extends Thread
bw.write( "Overpass: <a href=\"" + url4a + "\">minus one week</a> &nbsp;&nbsp; <a href=\"" + url4b + "\">node context</a><br><br>\n" ); bw.write( "Overpass: <a href=\"" + url4a + "\">minus one week</a> &nbsp;&nbsp; <a href=\"" + url4b + "\">node context</a><br><br>\n" );
bw.write( "<a href=\"" + url5 + "\">Open in Latest-Changes / last week</a><br><br>\n" ); bw.write( "<a href=\"" + url5 + "\">Open in Latest-Changes / last week</a><br><br>\n" );
bw.write( "<br>\n" ); bw.write( "<br>\n" );
if ( isFixed( id, suspectFile ) ) if ( isFixed( id, suspects.timestamp ) )
{ {
bw.write( "<br><br><a href=\"/brouter/suspects/" + country + "/" + filter + "/watchlist\">back to watchlist</a><br><br>\n" ); bw.write( "<br><br><a href=\"/brouter/suspects/" + country + "/" + filter + "/watchlist\">back to watchlist</a><br><br>\n" );
} }
@ -299,11 +324,17 @@ public class SuspectManager extends Thread
String prefix = "<a href=\"/brouter/suspects" + countryId + "/fixed"; String prefix = "<a href=\"/brouter/suspects" + countryId + "/fixed";
String prefix2 = " &nbsp;&nbsp;" + prefix; String prefix2 = " &nbsp;&nbsp;" + prefix;
bw.write( prefix + "\">mark as fixed</a><br><br>\n" ); bw.write( prefix + "\">mark as fixed</a><br><br>\n" );
bw.write( "hide for " ); bw.write( "hide for: weeks:" );
bw.write( prefix2 + "/7\">1 week</a>" ); bw.write( prefix2 + "/7\">1w</a>" );
bw.write( prefix2 + "/30\">1 month</a>" ); bw.write( prefix2 + "/14\">2w</a>" );
bw.write( prefix2 + "/91\">3 months</a>" ); bw.write( prefix2 + "/21\">3w</a>" );
bw.write( prefix2 + "/182\">6 months</a><br><br>\n" ); bw.write( " &nbsp;&nbsp;&nbsp; months:" );
bw.write( prefix2 + "/30\">1m</a>" );
bw.write( prefix2 + "/61\">2m</a>" );
bw.write( prefix2 + "/91\">3m</a>" );
bw.write( prefix2 + "/122\">4m</a>" );
bw.write( prefix2 + "/152\">5m</a>" );
bw.write( prefix2 + "/183\">6m</a><br><br>\n" );
} }
else else
{ {
@ -318,38 +349,20 @@ public class SuspectManager extends Thread
bw.write( "<br><a href=\"/brouter/suspects" + country + "/" + filter + "/watchlist\">see watchlist</a>\n" ); bw.write( "<br><a href=\"/brouter/suspects" + country + "/" + filter + "/watchlist\">see watchlist</a>\n" );
bw.write( "<br><a href=\"/brouter/suspects\">back to country list</a><br><br>\n" ); bw.write( "<br><a href=\"/brouter/suspects\">back to country list</a><br><br>\n" );
int maxprio = 0; int maxprio = 0;
for ( int pass = 1; pass <= 2; pass++ )
{ {
if ( pass == 2 ) for( int isuspect = 0; isuspect<suspects.cnt; isuspect++ )
{
id = suspects.ids[isuspect];
int prio = suspects.prios[isuspect];
int nprio = ( ( prio + 1 ) / 2 ) * 2; // normalize (no link prios)
if ( nprio < maxprio )
{
if ( maxprio == 0 )
{ {
bw.write( "current level: " + getLevelDecsription( maxprio ) + "<br><br>\n" ); bw.write( "current level: " + getLevelDecsription( maxprio ) + "<br><br>\n" );
} }
BufferedReader r = new BufferedReader( new FileReader( suspectFile ) );
for ( ;; )
{
String line = r.readLine();
if ( line == null )
break; break;
StringTokenizer tk2 = new StringTokenizer( line );
String idString = tk2.nextToken();
int prio = Integer.parseInt( tk2.nextToken() );
prio = ( ( prio + 1 ) / 2 ) * 2; // normalize (no link prios)
if ( pass == 1 )
{
if ( prio <= maxprio )
continue;
} }
else
{
if ( prio < maxprio )
continue;
}
id = Long.parseLong( idString );
if ( !polygon.isInBoundingBox( id ) ) if ( !polygon.isInBoundingBox( id ) )
{ {
continue; // not in selected polygon (pre-check) continue; // not in selected polygon (pre-check)
@ -358,22 +371,26 @@ public class SuspectManager extends Thread
{ {
continue; // known false positive continue; // known false positive
} }
if ( isFixed( id, suspectFile ) ) if ( isFixed( id, suspects.timestamp ) )
{ {
continue; // known fixed continue; // known fixed
} }
if ( "new".equals( filter ) && new File( "suspectarchive/" + id ).exists() ) if ( "new".equals( filter ) && new File( "suspectarchive/" + id ).exists() )
{ {
continue; // known fixed continue; // known archived
}
if ( "confirmed".equals( filter ) && !new File( "confirmednegatives/" + id ).exists() )
{
continue; // showing confirmed suspects only
} }
if ( !polygon.isInArea( id ) ) if ( !polygon.isInArea( id ) )
{ {
continue; // not in selected polygon continue; // not in selected polygon
} }
if ( pass == 1 ) if ( maxprio == 0 )
{ {
maxprio = prio; maxprio = nprio;
continue; bw.write( "current level: " + getLevelDecsription( maxprio ) + "<br><br>\n" );
} }
String countryId = country + "/" + filter + "/" + id; String countryId = country + "/" + filter + "/" + id;
File confirmedEntry = new File( "confirmednegatives/" + id ); File confirmedEntry = new File( "confirmednegatives/" + id );
@ -389,7 +406,6 @@ public class SuspectManager extends Thread
String url2 = "/brouter/suspects" + countryId; String url2 = "/brouter/suspects" + countryId;
bw.write( "<a href=\"" + url2 + "\">" + dlon + "," + dlat + "</a>" + hint + "<br>\n" ); bw.write( "<a href=\"" + url2 + "\">" + dlon + "," + dlat + "</a>" + hint + "<br>\n" );
} }
r.close();
} }
} }
bw.write( "</body></html>\n" ); bw.write( "</body></html>\n" );
@ -398,10 +414,82 @@ public class SuspectManager extends Thread
} }
private static boolean isFixed( long id, File suspectFile ) private static boolean isFixed( long id, long timestamp )
{ {
File fixedEntry = new File( "fixedsuspects/" + id ); File fixedEntry = new File( "fixedsuspects/" + id );
return fixedEntry.exists() && fixedEntry.lastModified() > suspectFile.lastModified(); return fixedEntry.exists() && fixedEntry.lastModified() > timestamp;
} }
private static final class SuspectList
{
int cnt;
long[] ids;
int[] prios;
long timestamp;
SuspectList( int count, long time )
{
cnt = count;
ids = new long[cnt];
prios = new int[cnt];
timestamp = time;
}
}
private static SuspectList allSuspects;
private static Object allSuspectsSync = new Object();
private static SuspectList getAllSuspects( File suspectFile ) throws IOException
{
synchronized( allSuspectsSync )
{
if ( allSuspects != null && suspectFile.lastModified() == allSuspects.timestamp )
{
return allSuspects;
}
// count prios
int[] prioCount = new int[100];
BufferedReader r = new BufferedReader( new FileReader( suspectFile ) );
for ( ;; )
{
String line = r.readLine();
if ( line == null ) break;
StringTokenizer tk2 = new StringTokenizer( line );
tk2.nextToken();
int prio = Integer.parseInt( tk2.nextToken() );
int nprio = ( ( prio + 1 ) / 2 ) * 2; // normalize (no link prios)
prioCount[nprio]++;
}
r.close();
// sum up
int pointer = 0;
for( int i=99; i>=0; i-- )
{
int cnt = prioCount[i];
prioCount[i] = pointer;
pointer += cnt;
}
// sort into suspect list
allSuspects = new SuspectList( pointer, suspectFile.lastModified() );
r = new BufferedReader( new FileReader( suspectFile ) );
for ( ;; )
{
String line = r.readLine();
if ( line == null ) break;
StringTokenizer tk2 = new StringTokenizer( line );
long id = Long.parseLong( tk2.nextToken() );
int prio = Integer.parseInt( tk2.nextToken() );
int nprio = ( ( prio + 1 ) / 2 ) * 2; // normalize (no link prios)
pointer = prioCount[nprio]++;
allSuspects.ids[pointer] = id;
allSuspects.prios[pointer] = prio;
}
r.close();
return allSuspects;
}
}
} }