From acf3fd1305284afac7c16ce0a8adb5d13343fd71 Mon Sep 17 00:00:00 2001 From: Benedikt Zoennchen Date: Fri, 13 Jul 2018 15:18:05 +0200 Subject: [PATCH] add some comments for the docu, refactoring of duplicated code, improve performance of the transformation of the output into trajectory jave objects. --- .../model/PostvisualizationModel.java | 35 +++--- .../projects/io/TrajectoryReader.java | 102 +++++++++--------- .../vadere/state/simulation/Trajectory.java | 78 ++++++++------ 3 files changed, 119 insertions(+), 96 deletions(-) diff --git a/VadereGui/src/org/vadere/gui/postvisualization/model/PostvisualizationModel.java b/VadereGui/src/org/vadere/gui/postvisualization/model/PostvisualizationModel.java index 54c809f39..c176981f0 100644 --- a/VadereGui/src/org/vadere/gui/postvisualization/model/PostvisualizationModel.java +++ b/VadereGui/src/org/vadere/gui/postvisualization/model/PostvisualizationModel.java @@ -100,10 +100,20 @@ public class PostvisualizationModel extends SimulationModel> agentsByStep, final Scenario vadere, final String projectPath) { - logger.info("start init postvis model"); - init(vadere, projectPath); + /** + * Initialize the {@link PostvisualizationModel}. + * + * @param agentsByStep the trajectory information: a list of agent (their position, target, group...) sorted by the time step. + * @param scenario the scenario which was used to produce the output the PostVis will display. + * @param projectPath the path to the project. + */ + public void init(final Map> agentsByStep, final Scenario scenario, final String projectPath) { + logger.info("start the initialization of the PostvisualizationModel."); + init(scenario, projectPath); this.agentsByStep = agentsByStep; + trajectories = new HashMap<>(); + + // to have fast access to the key values. Map map = agentsByStep .keySet().stream() .sorted(stepComparator) @@ -118,21 +128,22 @@ public class PostvisualizationModel extends SimulationModel entry.getValue().stream()) - .map(ped -> ped.getId()) - .distinct() - .map(id -> new Trajectory(agentsByStep, id)) - .collect(Collectors.toMap(t -> t.getPedestrianId(), t -> t)); - + for(Trajectory trajectory : trajectories.values()) { + trajectory.fill(); + } this.step = !steps.isEmpty() ? steps.get(0) : null; logger.info("finished init postvis model"); diff --git a/VadereSimulator/src/org/vadere/simulator/projects/io/TrajectoryReader.java b/VadereSimulator/src/org/vadere/simulator/projects/io/TrajectoryReader.java index 1b07f748c..b12c0bb9a 100644 --- a/VadereSimulator/src/org/vadere/simulator/projects/io/TrajectoryReader.java +++ b/VadereSimulator/src/org/vadere/simulator/projects/io/TrajectoryReader.java @@ -3,6 +3,7 @@ package org.vadere.simulator.projects.io; import org.apache.commons.math3.util.Pair; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; +import org.jetbrains.annotations.NotNull; import org.vadere.simulator.projects.Scenario; import org.vadere.simulator.projects.dataprocessing.processor.PedestrianPositionProcessor; import org.vadere.state.attributes.scenario.AttributesAgent; @@ -26,6 +27,18 @@ import java.util.stream.Collectors; /** * A TrajectoryReader is the counterpart of the {@link PedestrianPositionProcessor}. + * + * Output file assumptions: + * The TrajectoryReader assumes that the first row of the output is the headline and + * that there exist certain columns named: + * (id or pedestrianId) [mandatory], + * (step or timeStep) [mandatory], + * x [mandatory], + * y [mandatory], + * targetId [optional] and + * groupId [optional]. + * The order of the rows (expect for the first row / header) can be arbitrary. + * Columns has to be separated by {@link TrajectoryReader#SPLITTER} */ public class TrajectoryReader { @@ -110,13 +123,9 @@ public class TrajectoryReader { } } try { - if (pedIdIndex != -1 && xIndex != -1 && yIndex != -1 && stepIndex != -1 && groupIdIndex == -1) { + if (pedIdIndex != -1 && xIndex != -1 && yIndex != -1 && stepIndex != -1) { // load default values with no groups return readStandardTrajectoryFile(); - - } else if(pedIdIndex != -1 && xIndex != -1 && yIndex != -1 && stepIndex != -1) {//here groupIdIndex is != -1 - // load values with group information - return readGroupTrajectoryFile(); } else { throw new IOException("could not read trajectory file, some colums are missing."); @@ -130,59 +139,48 @@ public class TrajectoryReader { private Map> readStandardTrajectoryFile() throws IOException { try (BufferedReader in = IOUtils.defaultBufferedReader(this.trajectoryFilePath)) { - return in.lines() - .skip(1) //Skip header line - .map(line -> line.split(SPLITTER)) - .map(cells -> { - int step = Integer.parseInt(cells[stepIndex]); - int pedestrianId = Integer.parseInt(cells[pedIdIndex]); - VPoint pos = new VPoint(Double.parseDouble(cells[xIndex]), Double.parseDouble(cells[yIndex])); - - - int targetId = targetIdIndex != -1 ? Integer.parseInt(cells[targetIdIndex]) : -1; - - Pedestrian ped = new Pedestrian(new AttributesAgent(this.attributesPedestrian, pedestrianId), new Random()); - ped.setPosition(pos); - LinkedList targets = new LinkedList<>(); - targets.addFirst(targetId); - ped.setTargets(targets); - - return Pair.create(new Step(Integer.parseInt(cells[0])), ped); - }) - .collect(Collectors.groupingBy(Pair::getKey, Collectors.mapping(Pair::getValue, Collectors.toList()))); + return in.lines() // a stream of lines + .skip(1) // skip the first line i.e. the header + .map(line -> line.split(SPLITTER)) // split the line into string tokens + .map(rowTokens -> parseRowTokens(rowTokens)) // transform those tokens into a pair of java objects (step, agent) + .collect(Collectors.groupingBy(Pair::getKey, // group all agent objects by the step. + Collectors.mapping(Pair::getValue, Collectors.toList()))); } catch (Exception e){ logger.warn("could not read trajectory file. The file format might not be compatible or it is missing."); throw e; } } - private Map> readGroupTrajectoryFile() throws IOException{ - try (BufferedReader in = IOUtils.defaultBufferedReader(this.trajectoryFilePath)) { - return in.lines() - .skip(1) //Skip header line - .map(line -> line.split(SPLITTER)) - .map(cells -> { - int step = Integer.parseInt(cells[stepIndex]); - int pedestrianId = Integer.parseInt(cells[pedIdIndex]); - VPoint pos = new VPoint(Double.parseDouble(cells[xIndex]), Double.parseDouble(cells[yIndex])); - - - int targetId = targetIdIndex != -1 ? Integer.parseInt(cells[targetIdIndex]) : -1; - int groupId = targetIdIndex != -1 ? Integer.parseInt(cells[groupIdIndex]) : -1; - - Pedestrian ped = new Pedestrian(new AttributesAgent(this.attributesPedestrian, pedestrianId), new Random()); - ped.setPosition(pos); - ped.addGroupId(groupId); - LinkedList targets = new LinkedList<>(); - targets.addFirst(targetId); - ped.setTargets(targets); - - return Pair.create(new Step(Integer.parseInt(cells[0])), ped); - }) - .collect(Collectors.groupingBy(Pair::getKey, Collectors.mapping(Pair::getValue, Collectors.toList()))); - } catch (Exception e){ - logger.warn("could not read trajectory file. The file format might not be compatible or it is missing."); - throw e; + /** + * transforms the string tokens of the row (i.e. the values generated by the output processor of one row) + * into a {@link Pair} of ({@link Step}, {@link Agent}). + * + * @param rowTokens string tokens of the row + * @return a {@link Pair} of ({@link Step}, {@link Agent}) + */ + private Pair parseRowTokens(@NotNull final String[] rowTokens) { + // time step + int step = Integer.parseInt(rowTokens[stepIndex]); + + // pedestrian id + int pedestrianId = Integer.parseInt(rowTokens[pedIdIndex]); + Pedestrian ped = new Pedestrian(new AttributesAgent(this.attributesPedestrian, pedestrianId), new Random()); + + // pedestrian position + VPoint pos = new VPoint(Double.parseDouble(rowTokens[xIndex]), Double.parseDouble(rowTokens[yIndex])); + + // pedestrian target + int targetId = targetIdIndex != -1 ? Integer.parseInt(rowTokens[targetIdIndex]) : -1; + ped.setPosition(pos); + LinkedList targets = new LinkedList<>(); + targets.addFirst(targetId); + ped.setTargets(targets); + + if(groupIdIndex != -1) { + int groupId = targetIdIndex != -1 ? Integer.parseInt(rowTokens[groupIdIndex]) : -1; + ped.addGroupId(groupId); } + + return Pair.create(new Step(step), ped); } } diff --git a/VadereState/src/org/vadere/state/simulation/Trajectory.java b/VadereState/src/org/vadere/state/simulation/Trajectory.java index 47a7587f4..ce267ed87 100644 --- a/VadereState/src/org/vadere/state/simulation/Trajectory.java +++ b/VadereState/src/org/vadere/state/simulation/Trajectory.java @@ -1,6 +1,7 @@ package org.vadere.state.simulation; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -8,13 +9,13 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.math3.optim.OptimizationData; +import org.jetbrains.annotations.NotNull; import org.vadere.state.scenario.Agent; import org.vadere.util.geometry.shapes.VPoint; /** * A Trajectory is a list of {@link org.vadere.state.scenario.Pedestrian} objects, that can be seen - * as pedestrian states of the same - * pedestrian. The representing pedestrian is the same, so all + * as pedestrian states of the same pedestrian. The representing pedestrian is the same, so all * {@link org.vadere.state.scenario.Pedestrian} objects has * the same id but the state of a pedestrian changes over time. * @@ -31,6 +32,13 @@ public class Trajectory { private int pedestrianId; + public Trajectory(final int pedestrianId) { + this.pedestrianId = pedestrianId; + this.trajectoryPoints = new HashMap<>(); + this.firstStep = Optional.empty(); + this.lastStep = Optional.empty(); + } + public Trajectory(final Map> pedestrianByStep, final int pedestrianId) { this.pedestrianId = pedestrianId; @@ -61,6 +69,42 @@ public class Trajectory { } } + public void fill() { + if(!trajectoryPoints.isEmpty()) { + for(Step step : trajectoryPoints.keySet()) { + if(!firstStep.isPresent() || firstStep.get().getStepNumber() > step.getStepNumber()) { + firstStep = Optional.of(step); + } + + if(!lastStep.isPresent() || lastStep.get().getStepNumber() < step.getStepNumber()) { + lastStep = Optional.of(step); + } + } + + int start = firstStep.get().getStepNumber(); + int end = lastStep.get().getStepNumber(); + + for(int i = start+1; i < end; i++) { + Step currentStep = new Step(i); + if(!trajectoryPoints.containsKey(currentStep)) { + trajectoryPoints.put(currentStep, trajectoryPoints.get(new Step(currentStep.getStepNumber()-1))); + } + } + } + + } + + public void addStep(final Step step, @NotNull final Agent agent) { + if(!firstStep.isPresent() || firstStep.get().getStepNumber() > step.getStepNumber()) { + firstStep = Optional.of(step); + } + + if(!lastStep.isPresent() || lastStep.get().getStepNumber() < step.getStepNumber()) { + firstStep = Optional.of(step); + } + trajectoryPoints.put(step, agent); + } + public Optional getLifeTime() { return getEndStep().isPresent() && getStartStep().isPresent() ? Optional.of(getEndStep().get().getStepNumber() - getStartStep().get().getStepNumber()) : @@ -109,36 +153,6 @@ public class Trajectory { return !trajectoryPoints.containsKey(step) && (!lastStep.isPresent() || lastStep.get().compareTo(step) <= 0); } - /** - * Returns an Optional object. If the pedestrian is not appeared at the given time - * step, - * the Optional will be empty, the Optional will contain the Pedestrian object that is the last - * one - * in the list before (step+1). - * - * @param step the time step that specify the pedestrian state - * @return an Optional object which is empty if the pedestrian is not alive at the - * specific time step - */ - /* - * public Optional getAgent(final Step step) { - * Optional optionalPedestrian; - * if(trajectoryPoints.containsKey(step)) { - * optionalPedestrian = Optional.of(trajectoryPoints.get(step)); - * } - * else { - * Optional optionalStep = sortedSteps.stream().filter(s -> s.getStepNumber() <= - * step.getStepNumber()).max((Step::compareTo)); - * if(optionalStep.isPresent()) { - * optionalPedestrian = Optional.of(trajectoryPoints.get(optionalStep.get())); - * } - * else { - * optionalPedestrian = Optional.empty(); - * } - * } - * return optionalPedestrian; - * } - */ /** * Returns an Optional object. If the pedestrain has not appeared at step, the -- GitLab