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

@ -287,8 +287,23 @@ abstract class OsmPath implements OsmLinkHolder
}
if ( !hasPositive && ( hasAnyPositive || hasNegative ) )
{
cost = -1;
return;
if ( rc.considerTurnRestrictions && !detailMode )
{
cost = -1;
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 ) );
}
}
}
}
}
@ -372,8 +387,12 @@ abstract class OsmPath implements OsmLinkHolder
double elevation = ele2 == Short.MIN_VALUE ? 100. : ele2/4.;
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;
return;
}
@ -462,6 +481,17 @@ abstract class OsmPath implements OsmLinkHolder
double targetCost = processTargetNode( rc );
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;
return;
}

View file

@ -8,6 +8,7 @@ package btools.router;
import java.io.DataOutput;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -35,6 +36,13 @@ public final class RoutingContext
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()
{
String name = localFunction == null ? "unknown" : localFunction;
@ -57,7 +65,7 @@ public final class RoutingContext
public int uphillcutoff;
public boolean carMode;
public boolean bikeMode;
public boolean considerTurnRestrictions;
public boolean considerTurnRestrictions = true;
public boolean processUnusedTags;
public boolean forceSecondaryData;
public double pass1coefficient;
@ -131,7 +139,7 @@ public final class RoutingContext
bikeMode = 0.f != expctxGlobal.getVariableValue( "validForBikes", 0.f );
// 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)
processUnusedTags = 0.f != expctxGlobal.getVariableValue( "processUnusedTags", 0.f );
@ -161,7 +169,7 @@ public final class RoutingContext
trafficSourceMinDist = expctxGlobal.getVariableValue( "trafficSourceMinDist", 3000.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 );
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.Date;
import java.util.List;
import java.util.Map;
import btools.mapaccess.NodesCache;
import btools.mapaccess.OsmLink;
@ -279,16 +280,43 @@ public class RoutingEngine extends Thread
public void doSearch()
{
doSearch(0);
}
public void doSearch( int radius )
{
try
{
MatchedWaypoint seedPoint = new MatchedWaypoint();
seedPoint.waypoint = waypoints.get(0);
List<MatchedWaypoint> listOne = new ArrayList<MatchedWaypoint>();
listOne.add( seedPoint );
matchWaypointsToNodes( listOne );
List<MatchedWaypoint> wpList = new ArrayList<MatchedWaypoint>();
for( OsmNodeNamed wp : waypoints )
{
MatchedWaypoint seedPoint = new MatchedWaypoint();
seedPoint.waypoint = wp;
wpList.add( seedPoint );
}
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)
{
@ -978,6 +1006,7 @@ public class RoutingEngine extends Thread
}
routingContext.firstPrePath = null;
routingContext.maxcost = maxTotalCost;
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) )
{
OsmNode nextNode = link.getTarget( currentNode );
if ( ! nodesCache.obtainNonHollowNode( nextNode ) )
{
nPathPossible++;
continue; // border node?
}
if ( nextNode.firstlink == null )
{
continue; // don't care about dead ends
}
if ( nextNode == sourceNode )
{
continue; // border node?
}
if ( nextNode.firstlink == null )
{
nPathPossible++;
continue; // don't care about dead ends
}
if ( guideTrack != null )
{
int gidx = path.treedepth + 1;
if ( gidx >= guideTrack.nodes.size() )
{
nPathPossible++;
continue;
}
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
if ( routingContext.turnInstructionMode > 0 )
{
Map<Long,Integer> trSuspects = routingContext.suspectTRs;
routingContext.suspectTRs = null;
OsmPath detour = routingContext.createPath( path, link, refTrack, true );
if ( detour.cost >= 0. && nextId != startNodeId1 && nextId != startNodeId2 )
{
guideTrack.registerDetourForId( currentNode.getIdFromPos(), OsmPathElement.create( detour, false ) );
}
routingContext.suspectTRs = trSuspects;
}
continue;
}
@ -1080,6 +1119,8 @@ public class RoutingEngine extends Thread
}
if ( bestPath != null )
{
nPathPossible++;
boolean trafficSim = endPos == null;
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 );
}
@ -1214,7 +1278,7 @@ public class RoutingEngine extends Thread
track.buildMap();
// for final track..
if ( guideTrack != null )
if ( guideTrack != null && routingContext.turnInstructionMode > 0 )
{
track.copyDetours( guideTrack );
track.processVoiceHints( routingContext );

View file

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

View file

@ -51,7 +51,7 @@ public class Area
{
for( int j=0; j<neglist.size(); j++)
{
if ( neglist.get(i).isInPolygon( id ) )
if ( neglist.get(j).isInPolygon( id ) )
{
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();
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 )
{
long age = System.currentTimeMillis() - f.lastModified();
return formatAge( System.currentTimeMillis() - f.lastModified() );
}
private static String formatAge( long age )
{
long minutes = age / 60000;
if ( minutes < 60 )
{
@ -67,7 +71,7 @@ public class SuspectManager extends Thread
while ( tk.hasMoreTokens() )
{
String c = tk.nextToken();
if ( "all".equals( c ) || "new".equals( c ) )
if ( "all".equals( c ) || "new".equals( c ) || "confirmed".equals( c ) )
{
filter = c;
break;
@ -93,6 +97,7 @@ public class SuspectManager extends Thread
{
String url2 = "/brouter/suspects" + country + "/" + c;
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 linkSub = "";
@ -100,7 +105,7 @@ public class SuspectManager extends Thread
{
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( "</body></html>\n" );
@ -127,6 +132,7 @@ public class SuspectManager extends Thread
bw.flush();
return;
}
SuspectList suspects = getAllSuspects( suspectFile );
boolean showWatchList = false;
if ( tk.hasMoreTokens() )
@ -146,35 +152,48 @@ public class SuspectManager extends Thread
{
bw.write( "watchlist for " + country + "\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() )
{
continue; // known false positive
}
File confirmedEntry = new File( "confirmednegatives/" + id );
if ( !( isFixed( id, suspectFile ) && confirmedEntry.exists() ) )
File fixedEntry = new File( "fixedsuspects/" + id );
if ( !fixedEntry.exists() )
{
continue;
}
long age = System.currentTimeMillis() - confirmedEntry.lastModified();
if ( age / 1000 < 3600 * 24 * 8 )
long fixedTs = fixedEntry.lastModified();
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 ) )
{
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 ilat = (int) ( id & 0xffffffff );
double dlon = ( ilon - 180000000 ) / 1000000.;
@ -182,7 +201,6 @@ public class SuspectManager extends Thread
String url2 = "/brouter/suspects" + countryId;
bw.write( "<a href=\"" + url2 + "\">" + dlon + "," + dlat + "</a>" + hint + "<br>\n" );
}
r.close();
bw.write( "</body></html>\n" );
bw.flush();
return;
@ -230,8 +248,15 @@ public class SuspectManager extends Thread
if ( tk.hasMoreTokens() )
{
String param = tk.nextToken();
hideDays = Integer.parseInt( param );
fixedMarker.setLastModified( System.currentTimeMillis() + hideDays*86400000L );
hideDays = Integer.parseInt( param ); // hiding, not fixing
}
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 );
}
@ -246,7 +271,7 @@ public class SuspectManager extends Thread
double dlat = ( ilat - 90000000 ) / 1000000.;
String profile = "car-eco";
File configFile = new File( "configs/" + country + ".cfg" );
File configFile = new File( "configs/profile.cfg" );
if ( configFile.exists() )
{
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="
+ 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";
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( "<a href=\"" + url5 + "\">Open in Latest-Changes / last week</a><br><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" );
}
@ -299,11 +324,17 @@ public class SuspectManager extends Thread
String prefix = "<a href=\"/brouter/suspects" + countryId + "/fixed";
String prefix2 = " &nbsp;&nbsp;" + prefix;
bw.write( prefix + "\">mark as fixed</a><br><br>\n" );
bw.write( "hide for " );
bw.write( prefix2 + "/7\">1 week</a>" );
bw.write( prefix2 + "/30\">1 month</a>" );
bw.write( prefix2 + "/91\">3 months</a>" );
bw.write( prefix2 + "/182\">6 months</a><br><br>\n" );
bw.write( "hide for: weeks:" );
bw.write( prefix2 + "/7\">1w</a>" );
bw.write( prefix2 + "/14\">2w</a>" );
bw.write( prefix2 + "/21\">3w</a>" );
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
{
@ -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\">back to country list</a><br><br>\n" );
int maxprio = 0;
for ( int pass = 1; pass <= 2; pass++ )
{
if ( pass == 2 )
for( int isuspect = 0; isuspect<suspects.cnt; isuspect++ )
{
bw.write( "current level: " + getLevelDecsription( maxprio ) + "<br><br>\n" );
}
BufferedReader r = new BufferedReader( new FileReader( suspectFile ) );
for ( ;; )
{
String line = r.readLine();
if ( line == null )
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" );
}
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 ) )
{
continue; // not in selected polygon (pre-check)
@ -358,22 +371,26 @@ public class SuspectManager extends Thread
{
continue; // known false positive
}
if ( isFixed( id, suspectFile ) )
if ( isFixed( id, suspects.timestamp ) )
{
continue; // known fixed
}
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 ) )
{
continue; // not in selected polygon
}
if ( pass == 1 )
if ( maxprio == 0 )
{
maxprio = prio;
continue;
maxprio = nprio;
bw.write( "current level: " + getLevelDecsription( maxprio ) + "<br><br>\n" );
}
String countryId = country + "/" + filter + "/" + id;
File confirmedEntry = new File( "confirmednegatives/" + id );
@ -389,7 +406,6 @@ public class SuspectManager extends Thread
String url2 = "/brouter/suspects" + countryId;
bw.write( "<a href=\"" + url2 + "\">" + dlon + "," + dlat + "</a>" + hint + "<br>\n" );
}
r.close();
}
}
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 );
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;
}
}
}