16.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit 1d6c7133 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen
Browse files

finish new property data structure supported by fastutil.

parent 7ac00df9
package org.vadere.meshing.mesh.gen;
import it.unimi.dsi.fastutil.booleans.BooleanArrayList;
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
......@@ -38,12 +39,17 @@ public class AMesh implements IMesh<AVertex, AHalfEdge, AFace>, Cloneable {
private AFace boundary;
private List<AHalfEdge> edges;
private List<AVertex> vertices;
//TODO: test the new property structure!
private Map<String, AObjectArrayList<?>> verticesData;
private Map<String, AObjectArrayList<?>> halfEdgesData;
private Map<String, AObjectArrayList<?>> facesData;
private Map<String, DoubleArrayList> verticesDoubleData;
private Map<String, DoubleArrayList> facesDoubleData;
private Map<String, DoubleArrayList> halfEdgesDoubleData;
private Map<String, BooleanArrayList> verticesBooleanData;
private Map<String, BooleanArrayList> facesBooleanData;
private Map<String, BooleanArrayList> halfEdgesBooleanData;
public AMesh() {
clear();
......@@ -61,12 +67,18 @@ public class AMesh implements IMesh<AVertex, AHalfEdge, AFace>, Cloneable {
this.numberOfEdges = 0;
this.numberOfVertices = 0;
this.numberOfHoles = 0;
this.verticesData = new HashMap<>();
this.halfEdgesData = new HashMap<>();
this.facesData = new HashMap<>();
this.verticesDoubleData = new HashMap<>();
this.halfEdgesData = new HashMap<>();
this.facesDoubleData = new HashMap<>();
this.verticesBooleanData = new HashMap<>();
this.halfEdgesBooleanData = new HashMap<>();
this.facesBooleanData = new HashMap<>();
}
@Override
......@@ -223,6 +235,72 @@ public class AMesh implements IMesh<AVertex, AHalfEdge, AFace>, Cloneable {
dataArray.set(face.getId(), data);
}
@Override
public void setDoubleData(@NotNull final AFace face, @NotNull final String name, final double data) {
if(!facesDoubleData.containsKey(name)) {
DoubleArrayList dataArray = new DoubleArrayList(faces.size());
facesDoubleData.put(name, dataArray);
}
DoubleArrayList dataArray = facesDoubleData.get(name);
assert dataArray.size() == faces.size();
dataArray.set(face.getId(), data);
}
@Override
public void setDoubleData(@NotNull final AVertex vertex, @NotNull final String name, final double data) {
if(!verticesDoubleData.containsKey(name)) {
DoubleArrayList dataArray = new DoubleArrayList(vertices.size());
verticesDoubleData.put(name, dataArray);
}
DoubleArrayList dataArray = verticesDoubleData.get(name);
assert dataArray.size() == vertices.size();
dataArray.set(vertex.getId(), data);
}
@Override
public void setDoubleData(@NotNull final AHalfEdge edge, @NotNull final String name, final double data) {
if(!halfEdgesDoubleData.containsKey(name)) {
DoubleArrayList dataArray = new DoubleArrayList(edges.size());
halfEdgesDoubleData.put(name, dataArray);
}
DoubleArrayList dataArray = halfEdgesDoubleData.get(name);
assert dataArray.size() == edges.size();
dataArray.set(edge.getId(), data);
}
@Override
public void setBooleanData(@NotNull final AFace face, @NotNull final String name, final boolean data) {
if(!facesBooleanData.containsKey(name)) {
BooleanArrayList dataArray = new BooleanArrayList(faces.size());
facesBooleanData.put(name, dataArray);
}
BooleanArrayList dataArray = facesBooleanData.get(name);
assert dataArray.size() == faces.size();
dataArray.set(face.getId(), data);
}
@Override
public void setBooleanData(@NotNull final AVertex vertex, @NotNull final String name, final boolean data) {
if(!verticesBooleanData.containsKey(name)) {
BooleanArrayList dataArray = new BooleanArrayList(vertices.size());
verticesBooleanData.put(name, dataArray);
}
BooleanArrayList dataArray = verticesBooleanData.get(name);
assert dataArray.size() == vertices.size();
dataArray.set(vertex.getId(), data);
}
@Override
public void setBooleanData(@NotNull final AHalfEdge edge, @NotNull final String name, final boolean data) {
if(!halfEdgesBooleanData.containsKey(name)) {
BooleanArrayList dataArray = new BooleanArrayList(edges.size());
halfEdgesBooleanData.put(name, dataArray);
}
BooleanArrayList dataArray = halfEdgesBooleanData.get(name);
assert dataArray.size() == edges.size();
dataArray.set(edge.getId(), data);
}
private void fill(@NotNull final ObjectArrayList<?> data, final int n) {
for(int i = 0; i < n; i++) {
data.add(null);
......@@ -574,6 +652,24 @@ public class AMesh implements IMesh<AVertex, AHalfEdge, AFace>, Cloneable {
}
clone.verticesDoubleData = clonedVerticessDoubleData;
Map<String, BooleanArrayList> clonedFacesBooleanData = new HashMap<>();
for(var entry : facesBooleanData.entrySet()) {
clonedFacesBooleanData.put(entry.getKey(), entry.getValue().clone());
}
clone.facesBooleanData = clonedFacesBooleanData;
Map<String, BooleanArrayList> clonedHalfEdgesBooleanData = new HashMap<>();
for(var entry : halfEdgesBooleanData.entrySet()) {
clonedHalfEdgesBooleanData.put(entry.getKey(), entry.getValue().clone());
}
clone.halfEdgesBooleanData = clonedHalfEdgesBooleanData;
Map<String, BooleanArrayList> clonedVerticessBooleanData = new HashMap<>();
for(var entry : verticesBooleanData.entrySet()) {
clonedVerticessBooleanData.put(entry.getKey(), entry.getValue().clone());
}
clone.verticesBooleanData = clonedVerticessBooleanData;
return clone;
} catch (CloneNotSupportedException e) {
......@@ -694,16 +790,28 @@ public class AMesh implements IMesh<AVertex, AHalfEdge, AFace>, Cloneable {
list.set(vertexMap[i], list.getDouble(i));
list.set(i, tmp);
}
for(var list : verticesBooleanData.values()) {
boolean tmp = list.getBoolean(vertexMap[i]);
list.set(vertexMap[i], list.getBoolean(i));
list.set(i, tmp);
}
}
for(var list : verticesDoubleData.values()) {
if(vertexMap.length < facesDoubleData.size()) {
if(vertexMap.length < verticesDoubleData.size()) {
list.trim(vertexMap.length);
}
}
for(var list : verticesBooleanData.values()) {
if(vertexMap.length < verticesBooleanData.size()) {
list.trim(vertexMap.length);
}
}
for(var list : verticesData.values()) {
if(vertexMap.length < facesDoubleData.size()) {
if(vertexMap.length < verticesData.size()) {
list.trim(vertexMap.length);
}
}
......@@ -720,16 +828,28 @@ public class AMesh implements IMesh<AVertex, AHalfEdge, AFace>, Cloneable {
list.set(edgeMap[i], list.getDouble(i));
list.set(i, tmp);
}
for(var list : halfEdgesBooleanData.values()) {
boolean tmp = list.getBoolean(edgeMap[i]);
list.set(edgeMap[i], list.getBoolean(i));
list.set(i, tmp);
}
}
for(var list : halfEdgesDoubleData.values()) {
if(edgeMap.length < facesDoubleData.size()) {
if(edgeMap.length < halfEdgesDoubleData.size()) {
list.trim(edgeMap.length);
}
}
for(var list : halfEdgesBooleanData.values()) {
if(edgeMap.length < halfEdgesBooleanData.size()) {
list.trim(edgeMap.length);
}
}
for(var list : halfEdgesData.values()) {
if(edgeMap.length < facesDoubleData.size()) {
if(edgeMap.length < halfEdgesData.size()) {
list.trim(edgeMap.length);
}
}
......@@ -746,6 +866,12 @@ public class AMesh implements IMesh<AVertex, AHalfEdge, AFace>, Cloneable {
list.set(faceMap[i], list.getDouble(i));
list.set(i, tmp);
}
for(var list : facesBooleanData.values()) {
boolean tmp = list.getBoolean(faceMap[i]);
list.set(faceMap[i], list.getBoolean(i));
list.set(i, tmp);
}
}
for(var list : facesDoubleData.values()) {
......@@ -754,8 +880,14 @@ public class AMesh implements IMesh<AVertex, AHalfEdge, AFace>, Cloneable {
}
}
for(var list : facesBooleanData.values()) {
if(faceMap.length < facesBooleanData.size()) {
list.trim(faceMap.length);
}
}
for(var list : facesData.values()) {
if(faceMap.length < facesDoubleData.size()) {
if(faceMap.length < facesData.size()) {
list.trim(faceMap.length);
}
}
......
......@@ -319,7 +319,9 @@ public interface IMesh<V extends IVertex, E extends IHalfEdge, F extends IFace>
setData(vertex, name, data);
}
//default void setDoubleDataNull
//default void setBooleanNull(@NotNull final V vertex, @NotNull final String name, boolean nil) {}
//default void setDoubleNull(@NotNull final V vertex, @NotNull final String name, double nil) {}
/**
* Returns the data saved on the half-edge in O(1) if there is any and otherwise <tt>Optional.empty()</tt>.
......
package org.vadere.simulator.models.osm.updateScheme;
import org.jetbrains.annotations.NotNull;
import org.vadere.meshing.mesh.gen.IncrementalTriangulation;
import org.vadere.meshing.mesh.gen.MeshPanel;
import org.vadere.meshing.mesh.gen.PFace;
import org.vadere.meshing.mesh.gen.PHalfEdge;
import org.vadere.meshing.mesh.gen.PMesh;
import org.vadere.meshing.mesh.gen.PVertex;
import org.vadere.meshing.mesh.triangulation.triangulator.gen.GenPointSetTriangulator;
import org.vadere.meshing.mesh.inter.IIncrementalTriangulation;
import org.vadere.simulator.models.osm.PedestrianOSM;
import org.vadere.state.scenario.Topography;
import org.vadere.util.geometry.LinkedCellsGrid;
......@@ -30,9 +31,10 @@ public class UpdateSchemeEventDrivenParallel extends UpdateSchemeEventDriven {
private LinkedCellsGrid<PedestrianOSM> linkedCellsGrid;
private boolean[][] locked;
private double pedestrianPotentialWidth;
private Map<PedestrianOSM, PVertex> map;
private PMesh mesh;
private MeshPanel<PVertex, PHalfEdge, PFace> panel;
private Map<PedestrianOSM, PVertex> map;
private IIncrementalTriangulation<PVertex, PHalfEdge, PFace> triangulation;
public UpdateSchemeEventDrivenParallel(@NotNull final Topography topography, @NotNull final double pedestrianPotentialWidth) {
......@@ -74,16 +76,22 @@ public class UpdateSchemeEventDrivenParallel extends UpdateSchemeEventDriven {
int counter = 1;
// event driven update ignores time credits
do{
mesh = new PMesh<>();
Collection<PedestrianPoint> pedPoints = topography.getElements(PedestrianOSM.class)
do {
mesh = new PMesh();
Collection<VPoint> pedPoints = topography.getElements(PedestrianOSM.class)
.stream()
.map(ped -> new PedestrianPoint(ped.getPosition(), ped))
.map(ped -> ped.getPosition())
.collect(Collectors.toList());
GenPointSetTriangulator<PVertex, PHalfEdge, PFace> triangulator
= new GenPointSetTriangulator<>(pedPoints, mesh);
triangulator.generate();
triangulation = new IncrementalTriangulation(mesh);
for(PedestrianOSM pedestrianOSM : topography.getElements(PedestrianOSM.class)) {
PHalfEdge halfEdge = triangulation.insert(pedestrianOSM.getPosition().getX(), pedestrianOSM.getPosition().getY());
PVertex vertex = triangulation.getMesh().getVertex(halfEdge);
triangulation.getMesh().setData(vertex, "pedestrian", pedestrianOSM);
map.put(pedestrianOSM, vertex);
}
triangulation.finish();
if(panel == null) {
panel = new MeshPanel<>(mesh, 1000, 1000);
......@@ -93,9 +101,9 @@ public class UpdateSchemeEventDrivenParallel extends UpdateSchemeEventDriven {
panel.getMeshRenderer().setMesh(mesh);
}
for(PVertex pedestrianPoint : mesh.getVertices()) {
/*for(PVertex pedestrianPoint : mesh.getVertices()) {
map.put(mesh.getPoint(pedestrianPoint).pedestrianOSM, pedestrianPoint);
}
}*/
panel.repaint();
......@@ -151,19 +159,26 @@ public class UpdateSchemeEventDrivenParallel extends UpdateSchemeEventDriven {
logger.info("avoided updates: " + count);
}
private boolean requireUpdate(PedestrianOSM pedestrianOSM) {
private boolean requireUpdate(@NotNull final PedestrianOSM pedestrianOSM) {
PVertex vertex = map.get(pedestrianOSM);
if(mesh.getPoint(vertex).hasChanged()) {
if(hasChanged(pedestrianOSM)) {
return true;
}
for(PVertex v : mesh.getAdjacentVertexIt(vertex)) {
if(mesh.getPoint(v).hasChanged()) {
PedestrianOSM ped = triangulation.getMesh().getData(v, "pedestrian", PedestrianOSM.class).get();
if(hasChanged(ped)) {
return true;
}
}
return false;
}
private boolean hasChanged(@NotNull final PedestrianOSM pedestrianOSM) {
return pedestrianOSM.getLastPosition().equals(pedestrianOSM.getPosition());
}
private class PedestrianPoint implements IPoint {
private final PedestrianOSM pedestrianOSM;
......
......@@ -155,7 +155,7 @@ public interface IPotentialField {
/**
* Generate the mesh, we use the pointer based implementation here.
*/
PEikMesh meshGenerator = new PEikMesh<>(distanceFunc,edgeLengthFunction, 0.7, bbox, holes);
PEikMesh meshGenerator = new PEikMesh(distanceFunc,edgeLengthFunction, 0.7, bbox, holes);
IIncrementalTriangulation<PVertex, PHalfEdge, PFace> triangulation = meshGenerator.generate();
ITimeCostFunction timeCost = TimeCostFunctionFactory.create(
......
......@@ -41,6 +41,6 @@ public class PotentialFieldCalculatorNone implements EikonalSolver {
*/
@Override
public IMesh<?, ?, ?> getDiscretization() {
return new PMesh<>();
return new PMesh();
}
}
package org.vadere.simulator.models.potential.solver.calculators.mesh;
import org.apache.commons.lang3.tuple.Triple;
import org.jetbrains.annotations.NotNull;
import org.vadere.meshing.mesh.inter.IFace;
import org.vadere.meshing.mesh.inter.IHalfEdge;
......@@ -9,7 +8,6 @@ import org.vadere.meshing.mesh.inter.IMesh;
import org.vadere.meshing.mesh.inter.IVertex;
import org.vadere.simulator.models.potential.solver.calculators.EikonalSolver;
import org.vadere.simulator.models.potential.solver.timecost.ITimeCostFunction;
import org.vadere.util.data.cellgrid.IPotentialPoint;
import org.vadere.util.data.cellgrid.PathFindingTag;
import org.vadere.util.geometry.GeometryUtils;
import org.vadere.util.geometry.shapes.IPoint;
......@@ -22,11 +20,9 @@ import org.vadere.util.math.MathUtil;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.PriorityQueue;
import java.util.Set;
......@@ -39,18 +35,17 @@ import java.util.function.Predicate;
* The quality of the result depends on the quality of the triangulation. For a high accuracy the triangulation
* should not contain too many non-acute triangles.
*
* @param <P> the type of the points of the triangulation extending {@link IPotentialPoint}
* @param <V> the type of the vertices of the triangulation
* @param <E> the type of the half-edges of the triangulation
* @param <F> the type of the faces of the triangulation
*/
public class EikonalSolverFMMTriangulation<P extends IPotentialPoint, V extends IVertex, E extends IHalfEdge, F extends IFace> implements EikonalSolver {
public class EikonalSolverFMMTriangulation<V extends IVertex, E extends IHalfEdge, F extends IFace> implements EikonalSolver {
private static Logger logger = Logger.getLogger(EikonalSolverFMMTriangulation.class);
private Set<F> nonAccuteTris = new HashSet<>();
private Map<Triple<P, P, P>, Double> angles = new HashMap();
private Map<Triple<P, P, P>, Double> sinPhis = new HashMap();
private Map<Triple<P, P, P>, Double> cosPhis = new HashMap();
public static final String namePotential = "potential";
public static final String namePathFindingTag = "pathFindingTag";
static {
logger.setInfo();
......@@ -87,11 +82,9 @@ public class EikonalSolverFMMTriangulation<P extends IPotentialPoint, V extends
* Comparator for the heap. Vertices of points with small potentials are at the top of the heap.
*/
private Comparator<V> pointComparator = (v1, v2) -> {
P p1 = getMesh().getPoint(v1);
P p2 = getMesh().getPoint(v2);
if (p1.getPotential() < p2.getPotential()) {
if (getPotential(v1) < getPotential(v2)) {
return -1;
} else if(p1.getPotential() > p2.getPotential()) {
} else if(getPotential(v1) > getPotential(v2)) {
return 1;
}
else {
......@@ -189,15 +182,12 @@ public class EikonalSolverFMMTriangulation<P extends IPotentialPoint, V extends
*/
private void initialFace(@NotNull final F face, @NotNull final IDistanceFunction distanceFunction) {
for(V vertex : getMesh().getVertexIt(face)) {
P potentialPoint = getMesh().getPoint(vertex);
double distance = distanceFunction.apply(potentialPoint);
if(potentialPoint.getPathFindingTag() != PathFindingTag.Undefined) {
double distance = distanceFunction.apply(vertex);
if(getPathFindingTag(vertex) != PathFindingTag.Undefined) {
narrowBand.remove(vertex);
}
potentialPoint.setPotential(Math.min(potentialPoint.getPotential(), distance * timeCostFunction.costAt(potentialPoint)));
potentialPoint.setPathFindingTag(PathFindingTag.Reached);
updatePotential(vertex, distance / getTimeCost(vertex));
setPathFindingTag(vertex, PathFindingTag.Reached);
narrowBand.add(vertex);
}
}
......@@ -212,7 +202,7 @@ public class EikonalSolverFMMTriangulation<P extends IPotentialPoint, V extends
if (!calculationFinished) {
while (narrowBand.size() > 0) {
V vertex = narrowBand.poll();
getMesh().getPoint(vertex).setPathFindingTag(PathFindingTag.Reached);
setPathFindingTag(vertex, PathFindingTag.Reached);
updatePotentialOfNeighbours(vertex);
}
calculationFinished = true;
......@@ -220,36 +210,40 @@ public class EikonalSolverFMMTriangulation<P extends IPotentialPoint, V extends
}
private void reset() {
triangulation.getMesh().streamPoints().forEach(p -> p.setPathFindingTag(PathFindingTag.Undefined));
triangulation.getMesh().streamPoints().forEach(p -> p.setPotential(Double.MAX_VALUE));
triangulation.getMesh().streamVertices().forEach(v -> setPathFindingTag(v, PathFindingTag.Undefined));
triangulation.getMesh().streamVertices().forEach(v -> setPotential(v, Double.MAX_VALUE));
calculationFinished = false;
for(V vertex : targetVertices) {
P potentialPoint = getMesh().getPoint(vertex);
double distance = Math.max(distFunc.apply(potentialPoint), 0);
double distance = Math.max(distFunc.apply(vertex), 0);
if(potentialPoint.getPathFindingTag() != PathFindingTag.Undefined) {
if(getPathFindingTag(vertex) != PathFindingTag.Undefined) {
narrowBand.remove(vertex);
}
potentialPoint.setPotential(Math.min(potentialPoint.getPotential(), distance / timeCostFunction.costAt(potentialPoint)));
potentialPoint.setPathFindingTag(PathFindingTag.Reached);
updatePotential(vertex, distance / getTimeCost(vertex));
setPathFindingTag(vertex, PathFindingTag.Reached);
narrowBand.add(vertex);
for(V v : triangulation.getMesh().getAdjacentVertexIt(vertex)) {
P potentialP = getMesh().getPoint(v);
if(potentialP.getPathFindingTag() == PathFindingTag.Undefined) {
double dist = Math.max(distFunc.apply(potentialP), 0);
logger.debug("T at " + potentialP + " = " + dist);
potentialP.setPotential(Math.min(potentialP.getPotential(), dist / timeCostFunction.costAt(potentialP)));
potentialP.setPathFindingTag(PathFindingTag.Reachable);
if(getPathFindingTag(v) == PathFindingTag.Undefined) {
double dist = Math.max(distFunc.apply(v), 0);
logger.debug("T at " + v + " = " + dist);
updatePotential(v, dist / getTimeCost(v));
setPathFindingTag(v, PathFindingTag.Reachable);
narrowBand.add(v);
}
}
}
}
private double getTimeCost(@NotNull final V vertex) {
return timeCostFunction.costAt(vertex);
}
private void updatePotential(@NotNull final V vertex, final double potential) {
setPotential(vertex, Math.min(getPotential(vertex), potential));
}
// unknownPenalty is ignored.
@Override
public double getPotential(@NotNull final IPoint pos, final double unknownPenalty, final double weight) {
......@@ -280,14 +274,13 @@ public class EikonalSolverFMMTriangulation<P extends IPotentialPoint, V extends
* @param x the x-coordinate of the point
* @param y the y-coordinate of the point
*
* @param <P> the type of the points of the triangulation extending {@link IPotentialPoint}
* @param <V> the type of the vertices of the triangulation
* @param <E> the type of the half-edges of the triangulation
* @param <F> the type of the faces of the triangulation
*
* @return the interpolated value of the traveling time T at (x, y)
*/
private static <P extends IPotentialPoint, V extends IVertex, E extends IHalfEdge, F extends IFace> double getPotential(
private static <V extends IVertex, E extends IHalfEdge, F extends IFace> double getPotential(
@NotNull final IIncrementalTriangulation<V, E, F> triangulation,
final double x,
final double y) {
......@@ -302,7 +295,11 @@ public class EikonalSolverFMMTriangulation<P extends IPotentialPoint, V extends
// logger.warn("no triangle found for coordinates (" + x + "," + y + ")");
}
else {
result = InterpolationUtil.barycentricInterpolation(triangulation.getMesh().getPoints(optFace.get()), x, y);
E edge = triangulation.getMesh().getEdge(optFace.get());
V v1 = triangulation.getMesh().getVertex(edge);
V v2 = triangulation.getMesh().getVertex(triangulation.getMesh().getNext(edge));
V v3 = triangulation.getMesh().getVertex(triangulation.getMesh().getPrev(edge));
result = InterpolationUtil.barycentricInterpolation(v1, v2, v3, v -> triangulation.getMesh().getDoubleData(v, namePotential), x, y);
}
return result;
}
......@@ -331,18 +328,16 @@ public class EikonalSolverFMMTriangulation<P extends IPotentialPoint, V extends
*/
private void updatePotential(@NotNull final V vertex) {
double potential = recomputePotential(vertex);
P potentialPoint = getMesh().getPoint(vertex);
if(potential < potentialPoint.getPotential()) {
if(potentialPoint.getPathFindingTag() == PathFindingTag.Reachable) {
if(potential < getPotential(vertex)) {
if(getPathFindingTag(vertex) == PathFindingTag.Reachable) {
narrowBand.remove(vertex);
}
potentialPoint.setPotential(potential);
potentialPoint.setPathFindingTag(PathFindingTag.Reachable);
setPotential(vertex, potential);
setPathFindingTag(vertex, PathFindingTag.Reachable);
narrowBand.add(vertex);
}
if(potentialPoint.getPathFindingTag() == PathFindingTag.Undefined) {
if(getPathFindingTag(vertex) == PathFindingTag.Undefined) {
logger.debug("could not set neighbour vertex" + vertex);
}
}
......@@ -361,9 +356,9 @@ public class EikonalSolverFMMTriangulation<P extends IPotentialPoint, V extends
// value accordingly
double potential = Double.MAX_VALUE;
for(F face : getMesh().getAdjacentFacesIt(vertex)) {