use of gnu.trove.list.TIntList in project OpenTripPlanner by opentripplanner.
the class GTFSPatternHopFactory method run.
/**
* Generate the edges. Assumes that there are already vertices in the graph for the stops.
*/
public void run(Graph graph) {
if (fareServiceFactory == null) {
fareServiceFactory = new DefaultFareServiceFactory();
}
fareServiceFactory.processGtfs(_dao);
// TODO: Why are we loading stops? The Javadoc above says this method assumes stops are aleady loaded.
loadStops(graph);
loadPathways(graph);
loadFeedInfo(graph);
loadAgencies(graph);
// TODO: Why is there cached "data", and why are we clearing it? Due to a general lack of comments, I have no idea.
// Perhaps it is to allow name collisions with previously loaded feeds.
clearCachedData();
/* Assign 0-based numeric codes to all GTFS service IDs. */
for (AgencyAndId serviceId : _dao.getAllServiceIds()) {
// TODO: FIX Service code collision for multiple feeds.
graph.serviceCodes.put(serviceId, graph.serviceCodes.size());
}
LOG.debug("building hops from trips");
Collection<Trip> trips = _dao.getAllTrips();
int tripCount = 0;
/* First, record which trips are used by one or more frequency entries.
* These trips will be ignored for the purposes of non-frequency routing, and
* all the frequency entries referencing the same trip can be added at once to the same
* Timetable/TripPattern.
*/
ListMultimap<Trip, Frequency> frequenciesForTrip = ArrayListMultimap.create();
for (Frequency freq : _dao.getAllFrequencies()) {
frequenciesForTrip.put(freq.getTrip(), freq);
}
/* Then loop over all trips, handling each one as a frequency-based or scheduled trip. */
int freqCount = 0;
int nonFreqCount = 0;
/* The hops don't actually exist when we build their geometries, but we have to build their geometries
* below, before we throw away the modified stopTimes, saving only the tripTimes (which don't have enough
* information to build a geometry). So we keep them here.
*
* A trip pattern actually does not have a single geometry, but one per hop, so we store an array.
* FIXME _why_ doesn't it have a single geometry?
*/
Map<TripPattern, LineString[]> geometriesByTripPattern = Maps.newHashMap();
TRIP: for (Trip trip : trips) {
if (++tripCount % 100000 == 0) {
LOG.debug("loading trips {}/{}", tripCount, trips.size());
}
// TODO: move to a validator module
if (!_calendarService.getServiceIds().contains(trip.getServiceId())) {
LOG.warn(graph.addBuilderAnnotation(new TripUndefinedService(trip)));
// Invalid trip, skip it, it will break later
continue TRIP;
}
/* Fetch the stop times for this trip. Copy the list since it's immutable. */
List<StopTime> stopTimes = new ArrayList<StopTime>(_dao.getStopTimesForTrip(trip));
/* GTFS stop times frequently contain duplicate, missing, or incorrect entries. Repair them. */
TIntList removedStopSequences = removeRepeatedStops(stopTimes);
if (!removedStopSequences.isEmpty()) {
LOG.warn(graph.addBuilderAnnotation(new RepeatedStops(trip, removedStopSequences)));
}
filterStopTimes(stopTimes, graph);
interpolateStopTimes(stopTimes);
/* If after filtering this trip does not contain at least 2 stoptimes, it does not serve any purpose. */
if (stopTimes.size() < 2) {
LOG.warn(graph.addBuilderAnnotation(new TripDegenerate(trip)));
continue TRIP;
}
/* Try to get the direction id for the trip, set to -1 if not found */
int directionId;
try {
directionId = Integer.parseInt(trip.getDirectionId());
} catch (NumberFormatException e) {
LOG.debug("Trip {} does not have direction id, defaults to -1");
directionId = -1;
}
/* Get the existing TripPattern for this filtered StopPattern, or create one. */
StopPattern stopPattern = new StopPattern(stopTimes);
TripPattern tripPattern = findOrCreateTripPattern(stopPattern, trip.getRoute(), directionId);
/* Create a TripTimes object for this list of stoptimes, which form one trip. */
TripTimes tripTimes = new TripTimes(trip, stopTimes, graph.deduplicator);
/* If this trip is referenced by one or more lines in frequencies.txt, wrap it in a FrequencyEntry. */
List<Frequency> frequencies = frequenciesForTrip.get(trip);
if (frequencies != null && !(frequencies.isEmpty())) {
for (Frequency freq : frequencies) {
tripPattern.add(new FrequencyEntry(freq, tripTimes));
freqCount++;
}
// TODO replace: createGeometry(graph, trip, stopTimes, hops);
} else /* This trip was not frequency-based. Add the TripTimes directly to the TripPattern's scheduled timetable. */
{
tripPattern.add(tripTimes);
nonFreqCount++;
}
// there would be a trip pattern with no geometry yet because it failed some of these tests
if (!geometriesByTripPattern.containsKey(tripPattern) && trip.getShapeId() != null && trip.getShapeId().getId() != null && !trip.getShapeId().getId().equals("")) {
// save the geometry to later be applied to the hops
geometriesByTripPattern.put(tripPattern, createGeometry(graph, trip, stopTimes));
}
}
// end foreach TRIP
LOG.info("Added {} frequency-based and {} single-trip timetable entries.", freqCount, nonFreqCount);
graph.hasFrequencyService = graph.hasFrequencyService || freqCount > 0;
graph.hasScheduledService = graph.hasScheduledService || nonFreqCount > 0;
/* Generate unique human-readable names for all the TableTripPatterns. */
TripPattern.generateUniqueNames(tripPatterns.values());
/* Generate unique short IDs for all the TableTripPatterns. */
TripPattern.generateUniqueIds(tripPatterns.values());
/* Loop over all new TripPatterns, creating edges, setting the service codes and geometries, etc. */
for (TripPattern tripPattern : tripPatterns.values()) {
tripPattern.makePatternVerticesAndEdges(graph, context.stationStopNodes);
// Add the geometries to the hop edges.
LineString[] geom = geometriesByTripPattern.get(tripPattern);
if (geom != null) {
for (int i = 0; i < tripPattern.hopEdges.length; i++) {
tripPattern.hopEdges[i].setGeometry(geom[i]);
}
// Make a geometry for the whole TripPattern from all its constituent hops.
// This happens only if geometry is found in geometriesByTripPattern,
// because that means that geometry was created from shapes instead "as crow flies"
tripPattern.makeGeometry();
}
// TODO this could be more elegant
tripPattern.setServiceCodes(graph.serviceCodes);
/* Iterate over all stops in this pattern recording mode information. */
TraverseMode mode = GtfsLibrary.getTraverseMode(tripPattern.route);
for (TransitStop tstop : tripPattern.stopVertices) {
tstop.addMode(mode);
if (mode == TraverseMode.SUBWAY) {
tstop.setStreetToStopTime(subwayAccessTime);
}
graph.addTransitMode(mode);
}
}
/* Identify interlined trips and create the necessary edges. */
interline(tripPatterns.values(), graph);
/* Interpret the transfers explicitly defined in transfers.txt. */
loadTransfers(graph);
/* Store parent stops in graph, even if not linked. These are needed for clustering*/
for (TransitStationStop stop : context.stationStopNodes.values()) {
if (stop instanceof TransitStation) {
TransitStation parentStopVertex = (TransitStation) stop;
graph.parentStopById.put(parentStopVertex.getStopId(), parentStopVertex.getStop());
}
}
// it is already done at deserialization, but standalone mode allows using graphs without serializing them.
for (TripPattern tableTripPattern : tripPatterns.values()) {
tableTripPattern.scheduledTimetable.finish();
}
// eh?
clearCachedData();
graph.putService(FareService.class, fareServiceFactory.makeFareService());
graph.putService(OnBoardDepartService.class, new OnBoardDepartServiceImpl());
}
use of gnu.trove.list.TIntList in project OpenTripPlanner by opentripplanner.
the class PropagatedTimesStore method setFromArray.
/**
* @param times for search (varying departure time), an array of travel times to each destination.
* @param includeInAverages for each iteration, whether that iteration should be included in average calculations.
* In RaptorWorker's Monte Carlo code we also include minima and maxima, which should
* not be included in averages.
* Iterations that are not included in averages are still used to determine extrema.
*/
public void setFromArray(int[][] times, boolean[] includeInAverages, ConfidenceCalculationMethod confidenceCalculationMethod) {
if (times.length == 0)
// nothing to do
return;
// assume array is rectangular
int nTargets = times[0].length;
// cache random numbers. This should be fine as we're mixing it with the number of minutes
// at which each destination is accessible, which is sometimes not 120, as well as the stop
// position in the list (note that we have cleverly chosen a number which is a prime
// so is not divisible by the number of iterations on the bootstrap). Finally recall that
// the maximum number of times we're sampling from is generally 120 and we modulo this,
// so the pigeonhole principle applies.
// this is effectively a "random number generator" with phase 10007
int[] randomNumbers = random.ints().limit(10007).map(Math::abs).toArray();
int nextRandom = 0;
int effectiveIterations = 0;
for (int i = 0; i < includeInAverages.length; i++) {
if (includeInAverages[i])
effectiveIterations++;
}
// loop over targets on the outside so we can bootstrap
TARGETS: for (int target = 0; target < nTargets; target++) {
// compute the average
int sum = 0;
int count = 0;
TIntList timeList = new TIntArrayList();
TIntList avgList = new TIntArrayList();
ITERATIONS: for (int i = 0; i < times.length; i++) {
if (times[i][target] == RaptorWorker.UNREACHED)
continue ITERATIONS;
if (includeInAverages[i]) {
avgList.add(times[i][target]);
sum += times[i][target];
count++;
}
timeList.add(times[i][target]);
}
// never reachable
if (count == 0)
continue TARGETS;
// wait times as well.
if (count >= effectiveIterations * req.reachabilityThreshold)
avgs[target] = sum / count;
// TODO: correctly handle partial accessibility for bootstrap and percentile options.
switch(confidenceCalculationMethod) {
case BOOTSTRAP:
// now bootstrap out a 95% confidence interval on the time
int[] bootMeans = new int[N_BOOTSTRAPS];
// prevent overflow
nextRandom += N_BOOTSTRAPS * count % randomNumbers.length;
final int randOff = nextRandom;
final int finalCount = count;
IntStream.range(0, N_BOOTSTRAPS).parallel().forEach(boot -> {
int bsum = 0;
// sample from the Monte Carlo distribution with replacement
for (int iter = 0; iter < finalCount; iter++) {
bsum += avgList.get(randomNumbers[(randOff + boot * iter) % randomNumbers.length] % avgList.size());
// bsum += timeList.get(random.nextInt(count));
}
bootMeans[boot] = bsum / finalCount;
});
Arrays.sort(bootMeans);
// 2.5 percentile of distribution of means
mins[target] = bootMeans[N_BOOTSTRAPS / 40];
// 97.5 percentile of distribution of means
maxs[target] = bootMeans[N_BOOTSTRAPS - N_BOOTSTRAPS / 40];
break;
case PERCENTILE:
timeList.sort();
mins[target] = timeList.get(timeList.size() / 40);
maxs[target] = timeList.get(39 * timeList.size() / 40);
break;
case NONE:
mins[target] = maxs[target] = avgs[target];
break;
case MIN_MAX:
default:
mins[target] = timeList.min();
// NB not using count here as it doesn't count iterations that are not included in averages
if (timeList.size() == times.length)
maxs[target] = timeList.max();
break;
}
}
}
use of gnu.trove.list.TIntList in project RecurrentComplex by Ivorforce.
the class IntAreas method visitCoordsExcept.
public static boolean visitCoordsExcept(int[] lower, int[] higher, TIntList except, Visitor<int[]> visitor) {
TIntList dimensions = new TIntArrayList(Ranges.to(lower.length));
dimensions.removeAll(except);
return visitCoords(lower, higher, lower.clone(), dimensions, visitor);
}
use of gnu.trove.list.TIntList in project Valkyrien-Warfare-Revamped by ValkyrienWarfare.
the class WorldPhysicsCollider method updatePotentialCollisionCache.
// TODO: The greatest physics lag starts here.
private void updatePotentialCollisionCache() {
ticksSinceCacheUpdate = 0D;
// in the same tick
if (Math.random() > .5) {
ticksSinceCacheUpdate -= .05D;
}
int oldSize = cachedPotentialHits.size();
// Resets the potential hits array in O(1) time! Isn't that something.
// cachedPotentialHits.resetQuick();
cachedPotentialHits.clear();
AxisAlignedBB shipBBOriginal = parent.getPhysicsTransformAABB();
if (shipBBOriginal == null) {
return;
}
final AxisAlignedBB shipBB = shipBBOriginal.grow(3);
// Use the physics tick collision box instead of the game tick collision box.
// We are using grow(3) on both because for some reason if we don't then ships start
// jiggling through the ground. God I can't wait for a new physics engine.
final AxisAlignedBB collisionBB = shipBB.grow(AABB_EXPANSION).expand(calculator.getLinearVelocity().x * .2, calculator.getLinearVelocity().y * .2, calculator.getLinearVelocity().z * .2);
// Ship is outside of world blockSpace, just skip this all togvalkyrium
if (collisionBB.maxY < 0 || collisionBB.minY > 255) {
return;
}
// Has a -1 on the minY value, I hope this helps with preventing things from
// falling through the floor
BlockPos min = new BlockPos(collisionBB.minX, Math.max(collisionBB.minY - 1, 0), collisionBB.minZ);
BlockPos max = new BlockPos(collisionBB.maxX, Math.min(collisionBB.maxY, 255), collisionBB.maxZ);
centerPotentialHit = new BlockPos((min.getX() + max.getX()) / 2D, (min.getY() + max.getY()) / 2D, (min.getZ() + max.getZ()) / 2D);
ChunkCache cache = parent.getCachedSurroundingChunks();
if (cache == null) {
System.err.println("VS Cached Surrounding Chunks was null! This is going to cause catastophric terrible events!!");
return;
}
int chunkMinX = min.getX() >> 4;
int chunkMaxX = (max.getX() >> 4) + 1;
int chunkMinZ = min.getZ() >> 4;
int chunkMaxZ = (max.getZ() >> 4) + 1;
// long startTime = System.nanoTime();
int minX = min.getX();
int minY = min.getY();
int minZ = min.getZ();
int maxX = max.getX();
int maxY = max.getY();
int maxZ = max.getZ();
// More multithreading!
if (VSConfig.MULTITHREADING_SETTINGS.multithreadCollisionCacheUpdate && parent.getBlockPositions().size() > 100) {
List<Triple<Integer, Integer, TIntList>> tasks = new ArrayList<>();
for (int chunkX = chunkMinX; chunkX < chunkMaxX; chunkX++) {
for (int chunkZ = chunkMinZ; chunkZ < chunkMaxZ; chunkZ++) {
tasks.add(new ImmutableTriple<>(chunkX, chunkZ, new TIntArrayList()));
}
}
Consumer<Triple<Integer, Integer, TIntList>> consumer = i -> {
// i is a Tuple<Integer, Integer>
// updateCollisionCacheParrallel(cache, cachedPotentialHits, i.getFirst(),
// i.getSecond(), minX, minY, minZ, maxX, maxY, maxZ);
updateCollisionCacheSequential(cache, i.getLeft(), i.getMiddle(), minX, minY, minZ, maxX, maxY, maxZ, shipBB, i.getRight());
};
ValkyrienSkiesMod.getPhysicsThreadPool().submit(() -> tasks.parallelStream().forEach(consumer)).join();
tasks.forEach(task -> cachedPotentialHits.addAll(task.getRight()));
} else {
// Cast to double to avoid overflow errors
double size = ((double) (chunkMaxX - chunkMinX)) * ((double) (chunkMaxZ - chunkMinZ));
if (size > 300000) {
// Sanity check; don't execute the rest of the code because we'll just freeze the physics thread.
return;
}
// TODO: VS thread freezes here.
for (int chunkX = chunkMinX; chunkX < chunkMaxX; chunkX++) {
for (int chunkZ = chunkMinZ; chunkZ < chunkMaxZ; chunkZ++) {
updateCollisionCacheSequential(cache, chunkX, chunkZ, minX, minY, minZ, maxX, maxY, maxZ, shipBB, cachedPotentialHits);
}
}
}
}
use of gnu.trove.list.TIntList in project Valkyrien-Warfare-Revamped by ValkyrienWarfare.
the class WorldWaterCollider method updatePotentialCollisionCache.
private void updatePotentialCollisionCache() {
secondsSinceCollisionCacheUpdate = 0;
// ships from all updating in the same tick
if (Math.random() > .5) {
secondsSinceCollisionCacheUpdate -= .01;
}
cachedPotentialHits.clear();
AxisAlignedBB shipBBOriginal = parent.getPhysicsTransformAABB();
if (shipBBOriginal == null) {
return;
}
// We are using grow(3) because its good.
final AxisAlignedBB shipBB = shipBBOriginal.grow(3);
final AxisAlignedBB collisionBB = shipBB.grow(AABB_EXPANSION).grow(2 * Math.ceil(RANGE_CHECK));
// Ship is outside of world blockSpace, just skip this
if (collisionBB.maxY < 0 || collisionBB.minY > 255) {
return;
}
// Has a -1 on the minY value, I hope this helps with preventing things from
// falling through the floor
final BlockPos min = new BlockPos(collisionBB.minX, Math.max(collisionBB.minY - 1, 0), collisionBB.minZ);
final BlockPos max = new BlockPos(collisionBB.maxX, Math.min(collisionBB.maxY, 255), collisionBB.maxZ);
centerPotentialHit = new BlockPos((min.getX() + max.getX()) / 2.0, (min.getY() + max.getY()) / 2.0, (min.getZ() + max.getZ()) / 2.0);
final ChunkCache cache = parent.getCachedSurroundingChunks();
if (cache == null) {
System.err.println("VS Cached Surrounding Chunks was null! This is going to cause catastophric terrible events!!");
return;
}
final int chunkMinX = min.getX() >> 4;
final int chunkMaxX = (max.getX() >> 4) + 1;
final int chunkMinZ = min.getZ() >> 4;
final int chunkMaxZ = (max.getZ() >> 4) + 1;
final int minX = min.getX();
final int minY = min.getY();
final int minZ = min.getZ();
final int maxX = max.getX();
final int maxY = max.getY();
final int maxZ = max.getZ();
// More multithreading!
if (VSConfig.MULTITHREADING_SETTINGS.multithreadCollisionCacheUpdate && parent.getBlockPositions().size() > 100) {
final List<Triple<Integer, Integer, TIntList>> tasks = new ArrayList<>();
for (int chunkX = chunkMinX; chunkX < chunkMaxX; chunkX++) {
for (int chunkZ = chunkMinZ; chunkZ < chunkMaxZ; chunkZ++) {
tasks.add(new ImmutableTriple<>(chunkX, chunkZ, new TIntArrayList()));
}
}
Consumer<Triple<Integer, Integer, TIntList>> consumer = i -> updateCollisionCacheSequential(cache, i.getLeft(), i.getMiddle(), minX, minY, minZ, maxX, maxY, maxZ, shipBB, i.getRight());
ValkyrienSkiesMod.getPhysicsThreadPool().submit(() -> tasks.parallelStream().forEach(consumer)).join();
tasks.forEach(task -> cachedPotentialHits.addAll(task.getRight()));
} else {
// Cast to double to avoid overflow errors
final double size = ((double) (chunkMaxX - chunkMinX)) * ((double) (chunkMaxZ - chunkMinZ));
if (size > 300000) {
// Sanity check; don't execute the rest of the code because we'll just freeze the physics thread.
return;
}
for (int chunkX = chunkMinX; chunkX < chunkMaxX; chunkX++) {
for (int chunkZ = chunkMinZ; chunkZ < chunkMaxZ; chunkZ++) {
updateCollisionCacheSequential(cache, chunkX, chunkZ, minX, minY, minZ, maxX, maxY, maxZ, shipBB, cachedPotentialHits);
}
}
}
}
Aggregations