Commit 93ece71d authored by hm-schuhba1's avatar hm-schuhba1

Merge branch 'add_bonnmotionProcessor' into 'master'

Add BonnMotion processor

See merge request !59
parents 6ab16319 c7c861dc
Pipeline #111592 passed with stages
in 203 minutes and 57 seconds
package org.vadere.simulator.projects.dataprocessing.datakey;
import org.jetbrains.annotations.NotNull;
import org.vadere.simulator.projects.dataprocessing.outputfile.BonnMotionTrajectoryFile;
import java.util.Objects;
/**
* It's nearly identical to {@link PedestrianIdKey} with the distinction that the key part is not
* printed. The key is not needed here.
*
* @author Stefan Schuhbäck
*/
@OutputFileMap(outputFileClass = BonnMotionTrajectoryFile.class)
public class BonnMotionKey implements DataKey<BonnMotionKey> {
private final int pedId;
public BonnMotionKey(int pedId) {
this.pedId = pedId;
}
public static String getHeader() {
return "";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BonnMotionKey that = (BonnMotionKey) o;
return pedId == that.pedId;
}
@Override
public int hashCode() {
return Objects.hash(pedId);
}
@Override
public int compareTo(@NotNull BonnMotionKey o) {
return Integer.compare(pedId, o.pedId);
}
@Override
public String toString() {
return Integer.toString(this.pedId);
}
}
package org.vadere.simulator.projects.dataprocessing.outputfile;
import org.vadere.annotation.factories.outputfiles.OutputFileClass;
import org.vadere.simulator.projects.dataprocessing.datakey.BonnMotionKey;
import java.util.List;
/**
* Write BonnMotion trajectory file. This file does not contain headers or key columns see {@link
* org.vadere.simulator.projects.dataprocessing.processor.BonnMotionTrajectoryProcessor}.
*
* Therefore the {@link #printHeader()} and {@link #addkeysToLine(List, String[])} are overwritten.
*
* @author Stefan Schuhbäck
*/
@OutputFileClass(dataKeyMapping = BonnMotionKey.class)
public class BonnMotionTrajectoryFile extends OutputFile<BonnMotionKey> {
public BonnMotionTrajectoryFile() {
super(BonnMotionKey.getHeader());
}
@Override
void printHeader() {
// do nothing. This File does not need the header.
}
@Override
List<String> addkeysToLine(List<String> fields, String[] keyFieldArray) {
// do nothing. This File does not need the key value.
return fields;
}
}
......@@ -138,7 +138,7 @@ public abstract class OutputFile<K extends DataKey<K>> {
writeLine(this.writer, line);
}
private void printHeader() {
void printHeader() {
writeLine(this.writer, this.getEntireHeader());
}
......@@ -217,18 +217,29 @@ public abstract class OutputFile<K extends DataKey<K>> {
private List<String> composeLine(String[] keyFieldArray,
@SuppressWarnings("rawtypes") Function<DataProcessor, Stream<String>> valueFields){
final List<String> fields = new
LinkedList<>(Arrays.asList(keyFieldArray));
final List<String> fields = new LinkedList<>();
addkeysToLine(fields, keyFieldArray);
addProcessorToLine(fields, valueFields);
return fields;
}
List<String> addkeysToLine(final List<String> fields, String[] keyFieldArray){
fields.addAll(Arrays.asList(keyFieldArray));
return fields;
}
List<String> addProcessorToLine(final List<String> fields, Function<DataProcessor, Stream<String>> valueFields){
final List<String> processorFields = dataProcessors.stream()
.flatMap(valueFields)
.collect(Collectors.toList());
fields.addAll(processorFields);
return fields;
}
private void writeLine(VadereWriter out, final List<String> fields) {
out.println(String.join(this.separator, fields));
}
......
package org.vadere.simulator.projects.dataprocessing.processor;
import org.apache.commons.lang3.tuple.Pair;
import org.vadere.annotation.factories.dataprocessors.DataProcessorClass;
import org.vadere.simulator.control.SimulationState;
import org.vadere.simulator.projects.dataprocessing.ProcessorManager;
import org.vadere.simulator.projects.dataprocessing.datakey.BonnMotionKey;
import org.vadere.simulator.projects.dataprocessing.datakey.TimestepPedestrianIdKey;
import org.vadere.state.attributes.processor.AttributesBonnMotionTrajectoryProcessor;
import org.vadere.state.attributes.processor.AttributesProcessor;
import org.vadere.util.geometry.shapes.VPoint;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* This processor creates trace files based on the output of BonnMotion. BonnMotion is a mobility
* scenario generation and analysis tool developed by the Communication Systems group at University
* of Bonn et. al. (https://sys.cs.uos.de/bonnmotion/index.shtml)
*
* This format is used by the omnet++ to add pre-recorded mobility data to a network simulation.
* https://doc.omnetpp.org/inet/api-current/neddoc/inet.mobility.single.BonnMotionMobility.html
*
* The trace is based on a node-by-line waypoints. Thus each line represents one pedestrian and
* each waypoint consist of 3-Tupel (2D) or 4-Tupel (3D) encoding (time X-Coord Y-Coord Z-Coord)
*
* This Processor only supports 2D waypoints.
*
* @author Stefan Schuhbäck
*/
@DataProcessorClass()
public class BonnMotionTrajectoryProcessor extends DataProcessor<BonnMotionKey, List<Pair<Double, VPoint>>> {
private PedestrianPositionProcessor pedestrianPositionProcessor;
private AttributesBonnMotionTrajectoryProcessor attr;
public BonnMotionTrajectoryProcessor() {
super(""); // no headers.
setAttributes(new AttributesBonnMotionTrajectoryProcessor());
}
@Override
public void init(ProcessorManager manager) {
super.init(manager);
this.attr =
(AttributesBonnMotionTrajectoryProcessor) this.getAttributes();
this.pedestrianPositionProcessor = (PedestrianPositionProcessor) manager.getProcessor(
attr.getPedestrianPositionProcessorId()
);
}
@Override
public AttributesProcessor getAttributes() {
if (super.getAttributes() == null) {
setAttributes(new AttributesBonnMotionTrajectoryProcessor());
}
return super.getAttributes();
}
@Override
protected void doUpdate(SimulationState state) {
//ensure pedestrianPositionProcessor was updated.
this.pedestrianPositionProcessor.doUpdate(state);
}
/**
* Use the trajectory data from the {@link PedestrianPositionProcessor} and create the
* BonnMotion trajectory. Apply the scale and transformation set in the attributes.
*
* @param state Last simulation state
*/
@Override
public void postLoop(SimulationState state) {
double simTimeStepLength =
state.getScenarioStore().getAttributesSimulation().getSimTimeStepLength();
// retrieve trajectory data from pedestrianPositionProcessor and transform them to
// the BonnMotion trajectory.
Map<TimestepPedestrianIdKey, VPoint> trajectories = this.pedestrianPositionProcessor.getData();
trajectories.entrySet().forEach(e -> {
int pedId = e.getKey().getPedestrianId();
double time = e.getKey().getTimestep() * simTimeStepLength;
VPoint point = e.getValue().multiply(attr.getScale());
point = point.add(attr.getTranslate());
Pair<Double, VPoint> wayPoint = Pair.of(time, point);
addWayPoint(pedId, wayPoint);
});
sortWayPoints();
}
@Override
public String[] toStrings(BonnMotionKey key) {
List<Pair<Double, VPoint>> dataList = getValue(key);
if (dataList == null) {
return new String[]{"0 0 0"};
} else {
String data = dataList.stream()
.map(pair -> String.format("%f %f %f",
pair.getKey(), pair.getRight().x, pair.getRight().y))
.collect(Collectors.joining(" "));
return new String[]{data};
}
}
// ensure the correct order for each line (aka pedestrian)
private synchronized void sortWayPoints() {
getData().entrySet().forEach(e -> {
List<Pair<Double, VPoint>> dataList = e.getValue();
dataList.sort(Comparator.comparing(Pair::getLeft));
});
}
// add wayPoint for given pedId to value list. If it's the first element create the list.
private synchronized void addWayPoint(int pedId, Pair<Double, VPoint> wayPoint) {
BonnMotionKey bonnMotionKey = new BonnMotionKey(pedId);
List<Pair<Double, VPoint>> dataList = getValue(bonnMotionKey);
if (dataList == null) {
dataList = new ArrayList<>();
dataList.add(wayPoint);
putValue(bonnMotionKey, dataList);
} else {
dataList.add(wayPoint);
}
}
}
......@@ -28,7 +28,7 @@ public class PedestrianDensityCountingProcessor extends PedestrianDensityProcess
@Override
public AttributesProcessor getAttributes() {
if(super.getAttributes() == null) {
if(super.getAttributes() == null || !(super.getAttributes() instanceof AttributesPedestrianDensityCountingProcessor)) {
setAttributes(new AttributesPedestrianDensityCountingProcessor());
}
......
......@@ -2,7 +2,6 @@ package org.vadere.simulator.projects.dataprocessing.processor;
import org.mockito.Mockito;
import org.vadere.simulator.projects.dataprocessing.datakey.TimestepKey;
import org.vadere.simulator.projects.dataprocessing.writer.VadereWriterFactory;
import org.vadere.simulator.utils.PedestrianListBuilder;
import org.vadere.state.attributes.processor.AttributesAreaDensityVoronoiProcessor;
import org.vadere.state.attributes.scenario.AttributesMeasurementArea;
......@@ -24,12 +23,12 @@ public class AreaDensityVoronoiProcessorTestEnv extends ProcessorTestEnv<Timeste
PedestrianListBuilder b = new PedestrianListBuilder();
AreaDensityVoronoiProcessorTestEnv() {
try {
testedProcessor = processorFactory.createDataProcessor(AreaDensityVoronoiProcessor.class);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
testedProcessor.setId(nextProcessorId());
super(AreaDensityVoronoiProcessor.class, TimestepKey.class);
}
@Override
void initializeDependencies() {
// add measurement area
AttributesAreaDensityVoronoiProcessor attr =
(AttributesAreaDensityVoronoiProcessor) testedProcessor.getAttributes();
......@@ -39,15 +38,6 @@ public class AreaDensityVoronoiProcessorTestEnv extends ProcessorTestEnv<Timeste
new AttributesMeasurementArea(42, new VRectangle(0, 0, 16, 16)));
Mockito.when(manager.getMeasurementArea(42)).thenReturn(measurementArea);
try {
outputFile = outputFileFactory.createDefaultOutputfileByDataKey(
TimestepKey.class,
testedProcessor.getId()
);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
outputFile.setVadereWriterFactory(VadereWriterFactory.getStringWriterFactory());
}
public void loadCollinearSetup() {
......
......@@ -2,7 +2,6 @@ package org.vadere.simulator.projects.dataprocessing.processor;
import org.mockito.Mockito;
import org.vadere.simulator.projects.dataprocessing.datakey.TimestepKey;
import org.vadere.simulator.projects.dataprocessing.writer.VadereWriterFactory;
import org.vadere.simulator.utils.PedestrianListBuilder;
import org.vadere.state.attributes.processor.AttributesAreaSpeedProcessor;
import org.vadere.state.attributes.scenario.AttributesMeasurementArea;
......@@ -23,46 +22,25 @@ public class AreaSpeedProcessorTestEnv extends ProcessorTestEnv<TimestepKey, Dou
private PedestrianListBuilder b = new PedestrianListBuilder();
@SuppressWarnings("unchecked")
AreaSpeedProcessorTestEnv() {
try {
testedProcessor = processorFactory.createDataProcessor(AreaSpeedProcessor.class);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
testedProcessor.setId(nextProcessorId());
int pedPosProcId = nextProcessorId();
int pedVelProcId = nextProcessorId();
super(AreaSpeedProcessor.class, TimestepKey.class);
}
@Override
void initializeDependencies() {
AttributesAreaSpeedProcessor attr =
(AttributesAreaSpeedProcessor) testedProcessor.getAttributes();
attr.setPedestrianPositionProcessorId(pedPosProcId);
attr.setPedestrianVelocityProcessorId(pedVelProcId);
PedestrianVelocityProcessorTestEnv pedVelProcEnv = new PedestrianVelocityProcessorTestEnv(pedVelProcId);
DataProcessor pedVelProc = pedVelProcEnv.getTestedProcessor();
addRequiredProcessors(pedVelProcEnv);
Mockito.when(manager.getProcessor(pedVelProcId)).thenReturn(pedVelProc);
int pedPosProcId = addDependentProcessor(PedestrianPositionProcessorTestEnv::new);
int pedVelProcId = addDependentProcessor(PedestrianVelocityProcessorTestEnv::new);
PedestrianPositionProcessorTestEnv pedPosProcEnv = new PedestrianPositionProcessorTestEnv(pedPosProcId);
DataProcessor pedPosProc = pedPosProcEnv.getTestedProcessor();
addRequiredProcessors(pedPosProcEnv);
Mockito.when(manager.getProcessor(pedPosProcId)).thenReturn(pedPosProc);
attr.setPedestrianPositionProcessorId(pedPosProcId);
attr.setPedestrianVelocityProcessorId(pedVelProcId);
attr.setMeasurementAreaId(99);
MeasurementArea measurementArea = new MeasurementArea(
new AttributesMeasurementArea(99, new VRectangle(0, 0, 4, 5)));
Mockito.when(manager.getMeasurementArea(99)).thenReturn(measurementArea);
try {
outputFile = outputFileFactory.createDefaultOutputfileByDataKey(
TimestepKey.class,
testedProcessor.getId()
);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
outputFile.setVadereWriterFactory(VadereWriterFactory.getStringWriterFactory());
}
@Override
......
package org.vadere.simulator.projects.dataprocessing.processor;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
@Ignore
public class BonnMotionTrajectoryProcessorTest extends ProcessorTest {
@Before
public void setup(){
processorTestEnv = new BonnMotionTrajectoryProcessorTestEnv();
super.setup();
}
@Test
public void doUpdate() throws Exception{
//DefaultSimulationStateMocks
super.doUpdate();
}
}
\ No newline at end of file
package org.vadere.simulator.projects.dataprocessing.processor;
import org.apache.commons.lang3.tuple.Pair;
import org.vadere.simulator.projects.dataprocessing.datakey.BonnMotionKey;
import org.vadere.simulator.utils.PedestrianListBuilder;
import org.vadere.state.attributes.processor.AttributesBonnMotionTrajectoryProcessor;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.util.geometry.shapes.VPoint;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.when;
public class BonnMotionTrajectoryProcessorTestEnv
extends ProcessorTestEnv<BonnMotionKey, List<Pair<Double, VPoint>>> {
private PedestrianListBuilder b = new PedestrianListBuilder();
public BonnMotionTrajectoryProcessorTestEnv() {
this(1);
}
BonnMotionTrajectoryProcessorTestEnv(int nextProcessorId) {
super(BonnMotionTrajectoryProcessor.class, BonnMotionKey.class, nextProcessorId);
}
@Override
void initializeDependencies() {
int pedPosProcessorId = addDependentProcessor(PedestrianPositionProcessorTestEnv::new);
AttributesBonnMotionTrajectoryProcessor attr =
(AttributesBonnMotionTrajectoryProcessor) testedProcessor.getAttributes();
attr.setPedestrianPositionProcessorId(pedPosProcessorId);
}
@Override
public void loadDefaultSimulationStateMocks() {
addSimState(new SimulationStateMock(1) {
@Override
public void mockIt() {
b.clear()
.add(1, new VPoint(1.0, 1.0))
.add(2, new VPoint(3.5, 2.5));
when(state.getTopography().getElements(Pedestrian.class)).thenReturn(b.getList());
when(state.getScenarioStore().getAttributesSimulation().getSimTimeStepLength()).thenReturn(0.4);
}
});
addSimState(new SimulationStateMock(2) {
@Override
public void mockIt() {
b.clear()
.add(1, new VPoint(2.0, 2.0))
.add(2, new VPoint(3.5, 3.5));
when(state.getTopography().getElements(Pedestrian.class)).thenReturn(b.getList());
when(state.getScenarioStore().getAttributesSimulation().getSimTimeStepLength()).thenReturn(0.4);
}
});
addSimState(new SimulationStateMock(3) {
@Override
public void mockIt() {
b.clear()
.add(1, new VPoint(3.0, 3.0))
.add(2, new VPoint(3.5, 4.5));
when(state.getTopography().getElements(Pedestrian.class)).thenReturn(b.getList());
when(state.getScenarioStore().getAttributesSimulation().getSimTimeStepLength()).thenReturn(0.4);
}
});
}
@Override
List<String> getExpectedOutputAsList() {
List<String> ret = new ArrayList<>();
ret.add("0.400000 1.000000 1.000000 0.800000 2.000000 2.000000 1.200000 3.000000 3.000000");
ret.add("0.400000 3.500000 2.500000 0.800000 3.500000 3.500000 1.200000 3.500000 4.500000");
return ret;
}
}
package org.vadere.simulator.projects.dataprocessing.processor;
import org.mockito.Mockito;
import org.vadere.simulator.projects.dataprocessing.datakey.NoDataKey;
import org.vadere.simulator.projects.dataprocessing.writer.VadereWriterFactory;
import org.vadere.simulator.utils.PedestrianListBuilder;
import org.vadere.state.attributes.processor.AttributesEvacuationTimeProcessor;
import org.vadere.state.scenario.Pedestrian;
......@@ -23,42 +21,15 @@ public class EvacuationTimeProcessorTestEnv extends ProcessorTestEnv<NoDataKey,
this(1);
}
@SuppressWarnings("unchecked")
private EvacuationTimeProcessorTestEnv(int nextProcessorId) {
try {
testedProcessor = processorFactory.createDataProcessor(EvacuationTimeProcessor.class);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
testedProcessor.setId(nextProcessorId);
this.nextProcessorId = nextProcessorId + 1;
DataProcessor pedEvacTimeProc;
PedestrianEvacuationTimeProcessorTestEnv pedEvacTimeProcEnv;
int pedEvacTimeProcId = nextProcessorId();
//add ProcessorId of required Processors to current Processor under test
super(EvacuationTimeProcessor.class, NoDataKey.class, nextProcessorId);
}
@Override
void initializeDependencies() {
AttributesEvacuationTimeProcessor attr = (AttributesEvacuationTimeProcessor) testedProcessor.getAttributes();
int pedEvacTimeProcId = addDependentProcessor(PedestrianEvacuationTimeProcessorTestEnv::new);
attr.setPedestrianEvacuationTimeProcessorId(pedEvacTimeProcId);
//create required Processor enviroment and add it to current Processor under test
pedEvacTimeProcEnv = new PedestrianEvacuationTimeProcessorTestEnv(pedEvacTimeProcId);
pedEvacTimeProc = pedEvacTimeProcEnv.getTestedProcessor();
Mockito.when(manager.getProcessor(pedEvacTimeProcId)).thenReturn(pedEvacTimeProc);
addRequiredProcessors(pedEvacTimeProcEnv);
//setup output file with different VadereWriter impl for test
try {
outputFile = outputFileFactory.createDefaultOutputfileByDataKey(
NoDataKey.class,
testedProcessor.getId()
);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
outputFile.setVadereWriterFactory(VadereWriterFactory.getStringWriterFactory());
}
void loadSimulationStateMocksNaN() {
......
......@@ -3,7 +3,6 @@ package org.vadere.simulator.projects.dataprocessing.processor;
import org.mockito.Mockito;
import org.vadere.simulator.projects.dataprocessing.datakey.NoDataKey;
import org.vadere.simulator.projects.dataprocessing.datakey.OverlapData;
import org.vadere.simulator.projects.dataprocessing.writer.VadereWriterFactory;
import org.vadere.simulator.utils.PedestrianListBuilder;
import org.vadere.state.attributes.processor.AttributesMaxOverlapProcessor;
import org.vadere.state.scenario.DynamicElement;
......@@ -25,42 +24,17 @@ public class MaxOverlapProcessorTestEnv extends ProcessorTestEnv<NoDataKey, Doub
this(1);
}
@SuppressWarnings("unchecked")
private MaxOverlapProcessorTestEnv(int nextProcessorId) {
try {
testedProcessor = processorFactory.createDataProcessor(MaxOverlapProcessor.class);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
testedProcessor.setId(nextProcessorId);
this.nextProcessorId = nextProcessorId + 1;
DataProcessor pedestrianOverlapProcessor;
PedestrianOverlapProcessorTestEnv pedestrianOverlapProcessorTestEnv;
int pedestrianOverlapProcessorId = nextProcessorId();
MaxOverlapProcessorTestEnv(int nextProcessorId) {
super(MaxOverlapProcessor.class, NoDataKey.class, nextProcessorId);
}
@Override
void initializeDependencies() {
//add ProcessorId of required Processors to current Processor under test
int pedestrianOverlapProcessorId = addDependentProcessor(PedestrianOverlapProcessorTestEnv::new);
AttributesMaxOverlapProcessor attr = (AttributesMaxOverlapProcessor) testedProcessor.getAttributes();
attr.setPedestrianOverlapProcessorId(pedestrianOverlapProcessorId);
//create required Processor enviroment and add it to current Processor under test
pedestrianOverlapProcessorTestEnv = new PedestrianOverlapProcessorTestEnv(pedestrianOverlapProcessorId);
pedestrianOverlapProcessor = pedestrianOverlapProcessorTestEnv.getTestedProcessor();
Mockito.when(manager.getProcessor(pedestrianOverlapProcessorId)).thenReturn(pedestrianOverlapProcessor);
addRequiredProcessors(pedestrianOverlapProcessorTestEnv);
//setup output file with different VadereWriter impl for test
try {
outputFile = outputFileFactory.createDefaultOutputfileByDataKey(
NoDataKey.class,
testedProcessor.getId()
);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
outputFile.setVadereWriterFactory(VadereWriterFactory.getStringWriterFactory());
}
private LinkedCellsGrid<DynamicElement> getCellGridMock(PedestrianListBuilder b) {
......@@ -71,7 +45,7 @@ public class MaxOverlapProcessorTestEnv extends ProcessorTestEnv<NoDataKey, Doub
@Override
public void loadDefaultSimulationStateMocks() {
double minDist = 0.195*2;
double minDist = 0.195 * 2;
clearStates();
......@@ -102,10 +76,10 @@ public class MaxOverlapProcessorTestEnv extends ProcessorTestEnv<NoDataKey, Doub
Mockito.when(state.getTopography().getSpatialMap(DynamicElement.class)).thenReturn(getCellGridMock(b));
Mockito.when(state.getTopography().getAttributesPedestrian().getRadius()).thenReturn(0.195);
OverlapData dist1 = b.overlapData(1,5,minDist);
OverlapData dist2 = b.overlapData(5,1,minDist);
OverlapData dist3 = b.overlapData(1,3,minDist);
OverlapData dist4 = b.overlapData(3,1, minDist);
OverlapData dist1 = b.overlapData(1, 5, minDist);
OverlapData dist2 = b.overlapData(5, 1, minDist);
OverlapData dist3 = b.overlapData(1, 3, minDist);
OverlapData dist4 = b.overlapData(3, 1, minDist);
double maxDist = 0;
if (dist1.getOverlap() > maxDist)
......
......@@ -2,7 +2,6 @@ package org.vadere.simulator.projects.dataprocessing.processor;
import org.mockito.Mockito;
import org.vadere.simulator.projects.dataprocessing.datakey.NoDataKey;
import org.vadere.simulator.projects.dataprocessing.writer.VadereWriterFactory;
import org.vadere.simulator.utils.PedestrianListBuilder;
import org.vadere.state.attributes.processor.AttributesMeanPedestrianEvacuationTimeProcessor;
import org.vadere.state.scenario.Pedestrian;
......@@ -17,41 +16,15 @@ public class MeanPedestrianEvacuationTimeProcessorTestEnv extends ProcessorTestE
private PedestrianListBuilder b = new PedestrianListBuilder();