Commit 7cce3d9c authored by BZoennchen's avatar BZoennchen

improve garbage collection for the meshes, fix bug in walk and jump algorithm,...

improve garbage collection for the meshes, fix bug in walk and jump algorithm, prepare for mesh drawing into a panel for the gui.
parent 392cb49e
......@@ -26,6 +26,7 @@ public class DefaultSimulationConfig extends DefaultConfig {
private boolean showPedestrians = true;
private boolean showWalkdirection = false;
private boolean showTargetPotentialField = false;
private boolean showTargetPotentielFieldMesh = false;
private boolean showPotentialField = false;
private boolean showTrajectories = false;
private boolean showGrid = false;
......@@ -64,6 +65,7 @@ public class DefaultSimulationConfig extends DefaultConfig {
this.showStairs = config.showStairs;
this.showGroups = config.showGroups;
this.showPotentialField = config.showPotentialField;
this.showTargetPotentielFieldMesh = config.showTargetPotentielFieldMesh;
}
public boolean isShowGroups() {
......@@ -110,6 +112,15 @@ public class DefaultSimulationConfig extends DefaultConfig {
return showTargets;
}
public void setShowTargetPotentielFieldMesh(final boolean showTargetPotentielFieldMesh) {
this.showTargetPotentielFieldMesh = showTargetPotentielFieldMesh;
setChanged();
}
public boolean isShowTargetPotentielFieldMesh() {
return showTargetPotentielFieldMesh;
}
public void setShowTargets(boolean showTargets) {
this.showTargets = showTargets;
setChanged();
......
......@@ -4,7 +4,11 @@ package org.vadere.gui.components.model;
import java.util.Collection;
import java.util.function.Function;
import org.vadere.meshing.mesh.gen.PMesh;
import org.vadere.meshing.mesh.inter.IMesh;
import org.vadere.simulator.models.potential.solver.calculators.mesh.PotentialPoint;
import org.vadere.state.scenario.Agent;
import org.vadere.util.data.cellgrid.IPotentialPoint;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
......@@ -38,8 +42,8 @@ public abstract class SimulationModel<T extends DefaultSimulationConfig> extends
return config;
}
public double getPotential(final int x, final int y) {
return getPotentialField().apply(pixelToWorld(new VPoint(x, y)));
public IMesh<? extends IPotentialPoint, ?, ?, ?> getDiscretization() {
return new PMesh<IPotentialPoint>((x,y) -> new PotentialPoint(x,y));
}
/*public double getPotential(final int x, final int y) {
......
......@@ -2,9 +2,12 @@ package org.vadere.gui.components.view;
import org.jetbrains.annotations.NotNull;
import org.vadere.gui.components.model.IDefaultModel;
import org.vadere.meshing.mesh.gen.MeshRenderer;
import org.vadere.meshing.mesh.inter.IMesh;
import org.vadere.state.scenario.Agent;
import org.vadere.state.scenario.ScenarioElement;
import org.vadere.state.scenario.Stairs;
import org.vadere.util.data.cellgrid.IPotentialPoint;
import org.vadere.util.geometry.shapes.Vector2D;
import org.vadere.util.geometry.shapes.VCircle;
import org.vadere.util.geometry.shapes.VLine;
......@@ -63,7 +66,6 @@ public abstract class DefaultRenderer {
targetGraphics2D.dispose();
}
public void renderGraphics(final Graphics2D targetGraphics2D, final int width, final int height) {
targetGraphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
......@@ -594,6 +596,11 @@ public abstract class DefaultRenderer {
}
}
protected void renderMesh(final Graphics2D g, @NotNull final IMesh<? extends IPotentialPoint, ?, ?, ?> mesh, final int width, final int height) {
MeshRenderer<? extends IPotentialPoint, ?, ?, ?> meshRenderer = new MeshRenderer<>(mesh);
meshRenderer.render(g, width, height);
}
protected void renderVoronoiDiagram(final Graphics2D g, final VoronoiDiagram voronoiDiagram) {
synchronized (voronoiDiagram) {
if (voronoiDiagram != null) {
......
......@@ -99,6 +99,10 @@ public abstract class SimulationRenderer extends DefaultRenderer {
renderVoronoiDiagram(graphics, model.getVoronoiDiagram());
}
if(model.config.isShowTargetPotentielFieldMesh()) {
renderMesh(graphics, model.getDiscretization(), width, height);
}
renderSimulationContent(graphics);
if (model.isElementSelected()) {
......
......@@ -7,13 +7,17 @@ import org.jetbrains.annotations.Nullable;
import org.vadere.gui.onlinevisualization.model.OnlineVisualizationModel;
import org.vadere.gui.onlinevisualization.view.MainPanel;
import org.vadere.gui.onlinevisualization.view.OnlineVisualisationWindow;
import org.vadere.meshing.mesh.inter.IMesh;
import org.vadere.simulator.control.PassiveCallback;
import org.vadere.simulator.models.potential.fields.IPotentialField;
import org.vadere.simulator.models.potential.fields.IPotentialFieldTarget;
import org.vadere.state.scenario.Agent;
import org.vadere.state.scenario.Topography;
import org.vadere.util.data.cellgrid.IPotentialPoint;
import org.vadere.util.geometry.shapes.VRectangle;
import java.util.function.Function;
public class OnlineVisualization implements PassiveCallback {
/**
......@@ -28,18 +32,21 @@ public class OnlineVisualization implements PassiveCallback {
public final IPotentialField potentialFieldTarget;
public final Agent selectedAgent;
public final IPotentialField potentialField;
public final Function<Agent, IMesh<? extends IPotentialPoint, ?, ?, ?>> discretizations;
public ObservationAreaSnapshotData(
final double simTimeInSec,
@NotNull final Topography scenario,
@Nullable final IPotentialField potentialFieldTarget,
@Nullable final IPotentialField potentialField,
@Nullable final Agent selectedAgent) {
@Nullable final Agent selectedAgent,
@Nullable final Function<Agent, IMesh<? extends IPotentialPoint, ?, ?, ?>> discretizations) {
this.simTimeInSec = simTimeInSec;
this.scenario = scenario;
this.potentialFieldTarget = potentialFieldTarget;
this.potentialField = potentialField;
this.selectedAgent = selectedAgent;
this.discretizations = discretizations;
}
}
......@@ -117,6 +124,7 @@ public class OnlineVisualization implements PassiveCallback {
synchronized (model.getDataSynchronizer()) {
/* Push new snapshot of the observation area to the draw thread. */
IPotentialField pft = (model.config.isShowTargetPotentialField() && potentialFieldTarget != null) ? potentialFieldTarget.getSolution() : null;
Function<Agent, IMesh<? extends IPotentialPoint, ?, ?, ?>> discretizations = (model.config.isShowTargetPotentielFieldMesh() && potentialFieldTarget != null) ? potentialFieldTarget.getDiscretization() : null;
IPotentialField pedPotentialField = null;
Agent selectedAgent = null;
......@@ -125,7 +133,7 @@ public class OnlineVisualization implements PassiveCallback {
pedPotentialField = IPotentialField.copyAgentField(potentialField, selectedAgent, new VRectangle(model.getTopographyBound()), 0.1);
}
ObservationAreaSnapshotData data = new ObservationAreaSnapshotData(simTimeInSec, scenario.clone(), pft, pedPotentialField, selectedAgent);
ObservationAreaSnapshotData data = new ObservationAreaSnapshotData(simTimeInSec, scenario.clone(), pft, pedPotentialField, selectedAgent, discretizations);
model.pushObservationAreaSnapshot(data);
}
}
......
......@@ -11,8 +11,12 @@ import java.util.stream.Collectors;
import org.vadere.gui.components.model.DefaultSimulationConfig;
import org.vadere.gui.components.model.SimulationModel;
import org.vadere.gui.onlinevisualization.OnlineVisualization;
import org.vadere.meshing.mesh.gen.PMesh;
import org.vadere.meshing.mesh.inter.IMesh;
import org.vadere.simulator.models.potential.fields.IPotentialField;
import org.vadere.simulator.models.potential.solver.calculators.mesh.PotentialPoint;
import org.vadere.state.scenario.*;
import org.vadere.util.data.cellgrid.IPotentialPoint;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.voronoi.VoronoiDiagram;
......@@ -33,6 +37,8 @@ public class OnlineVisualizationModel extends SimulationModel<DefaultSimulationC
private IPotentialField potentialField = null;
private Function<Agent, IMesh<? extends IPotentialPoint, ?, ?, ?>> discretizations = null;
private Agent agent = null;
/**
......@@ -112,6 +118,7 @@ public class OnlineVisualizationModel extends SimulationModel<DefaultSimulationC
potentialFieldTarget = observationAreaSnapshot.potentialFieldTarget;
potentialField = observationAreaSnapshot.potentialField;
agent = observationAreaSnapshot.selectedAgent;
discretizations = observationAreaSnapshot.discretizations;
/*
* if(topography == null ||
......@@ -201,6 +208,15 @@ public class OnlineVisualizationModel extends SimulationModel<DefaultSimulationC
return f;
}
@Override
public IMesh<? extends IPotentialPoint, ?, ?, ?> getDiscretization() {
if(discretizations != null && config.isShowTargetPotentielFieldMesh() && agent.equals(getSelectedElement())) {
return discretizations.apply(agent);
}
return new PMesh<IPotentialPoint>((x, y) -> new PotentialPoint(x, y));
}
@Override
public double getGridResolution() {
return config.getGridWidth();
......
......@@ -2,6 +2,7 @@ package org.vadere.gui.projectview;
import org.apache.commons.lang3.time.StopWatch;
import org.vadere.gui.components.utils.Recorder;
import org.vadere.meshing.mesh.gen.MeshRenderer;
import org.vadere.util.visualization.ColorHelper;
import org.vadere.util.geometry.GeometryUtils;
import org.vadere.meshing.mesh.gen.AFace;
......@@ -61,8 +62,11 @@ public class RecordTriangulationMovie {
//ColorHelper.numberToHurColor((float)f.getId() / meshImprover.getMesh().getNumberOfFaces());
//new ColorHelper(meshImprover.getMesh().getNumberOfFaces()).numberToColor(f.getId());
MeshRenderer<EikMeshPoint, AVertex<EikMeshPoint>, AHalfEdge<EikMeshPoint>, AFace<EikMeshPoint>> meshRenderer = new MeshRenderer<>(
meshImprover.getMesh(), f -> false, colorFunction1);
MeshPanel<EikMeshPoint, AVertex<EikMeshPoint>, AHalfEdge<EikMeshPoint>, AFace<EikMeshPoint>> distmeshPanel = new MeshPanel<>(
meshImprover.getMesh(), f -> false, bbound.getWidth()*1000, bbound.getHeight()*1000, bbound, colorFunction1);
meshRenderer, bbound.getWidth()*1000, bbound.getHeight()*1000);
JFrame frame = distmeshPanel.display();
frame.setVisible(true);
......@@ -84,16 +88,15 @@ public class RecordTriangulationMovie {
while (nSteps < 300) {
nSteps++;
distmeshPanel.refresh();
if(!meshImprover.initializationFinished()) {
addPictures(recorder, distmeshPanel, 10);
addPictures(recorder, meshRenderer, 10, (int)bbound.getWidth()*1000, (int)bbound.getHeight()*1000);
}
else if(finished) {
finished = false;
addPictures(recorder, distmeshPanel, 20);
addPictures(recorder, meshRenderer, 20, (int)bbound.getWidth()*1000, (int)bbound.getHeight()*1000);
}
addPictures(recorder, distmeshPanel, 5);
addPictures(recorder, meshRenderer, 5, (int)bbound.getWidth()*1000, (int)bbound.getHeight()*1000);
/*try {
......@@ -114,11 +117,13 @@ public class RecordTriangulationMovie {
}
public static void addPictures(Recorder recorder,
MeshPanel<EikMeshPoint, AVertex<EikMeshPoint>, AHalfEdge<EikMeshPoint>, AFace<EikMeshPoint>> distmeshPanel,
int frames) throws IOException {
MeshRenderer<EikMeshPoint, AVertex<EikMeshPoint>, AHalfEdge<EikMeshPoint>, AFace<EikMeshPoint>> renderer,
int frames,
int width,
int height) throws IOException {
for(int i = 0; i < frames; i++) {
recorder.addPicture(distmeshPanel.getImage());
recorder.addPicture(renderer.renderImage(width, height));
}
}
......
......@@ -30,7 +30,7 @@ public class DelaunayTriangulationExamples {
randomTriangulator.generate();
// display the result
MeshPanel meshPanel = new MeshPanel(triangulation.getMesh(), 500, 500, bound);
MeshPanel meshPanel = new MeshPanel(triangulation.getMesh(), 500, 500);
meshPanel.display();
}
......
......@@ -65,8 +65,7 @@ public class EikMeshExamples {
// (optional) define the gui to display the mesh
MeshPanel<EikMeshPoint, PVertex<EikMeshPoint>, PHalfEdge<EikMeshPoint>, PFace<EikMeshPoint>> meshPanel = new MeshPanel<>(
meshImprover.getMesh(), 1000, 800,
new VRectangle(boundary.getBounds()));
meshImprover.getMesh(), 1000, 800);
// generate the mesh
meshImprover.generate();
......@@ -99,8 +98,7 @@ public class EikMeshExamples {
// (optional) define the gui to display the mesh
MeshPanel<EikMeshPoint, PVertex<EikMeshPoint>, PHalfEdge<EikMeshPoint>, PFace<EikMeshPoint>> meshPanel = new MeshPanel<>(
meshImprover.getMesh(), 1000, 800,
bound);
meshImprover.getMesh(), 1000, 800);
// generate the mesh
meshImprover.generate();
......@@ -133,8 +131,7 @@ public class EikMeshExamples {
// (optional) define the gui to display the mesh
MeshPanel<EikMeshPoint, PVertex<EikMeshPoint>, PHalfEdge<EikMeshPoint>, PFace<EikMeshPoint>> meshPanel = new MeshPanel<>(
meshImprover.getMesh(), 1000, 800,
bound);
meshImprover.getMesh(), 1000, 800);
// generate the mesh
meshImprover.generate();
......@@ -166,8 +163,7 @@ public class EikMeshExamples {
// (optional) define the gui to display the mesh
MeshPanel<EikMeshPoint, PVertex<EikMeshPoint>, PHalfEdge<EikMeshPoint>, PFace<EikMeshPoint>> meshPanel = new MeshPanel<>(
meshImprover.getMesh(), 1000, 800,
bound);
meshImprover.getMesh(), 1000, 800);
// generate the mesh
meshImprover.generate();
......@@ -201,8 +197,7 @@ public class EikMeshExamples {
// (optional) define the gui to display the mesh
MeshPanel<EikMeshPoint, PVertex<EikMeshPoint>, PHalfEdge<EikMeshPoint>, PFace<EikMeshPoint>> meshPanel = new MeshPanel<>(
meshImprover.getMesh(), 1000, 800,
bound);
meshImprover.getMesh(), 1000, 800);
// generate the mesh
meshImprover.generate();
......@@ -238,8 +233,7 @@ public class EikMeshExamples {
// (optional) define the gui to display the mesh
MeshPanel<EikMeshPoint, PVertex<EikMeshPoint>, PHalfEdge<EikMeshPoint>, PFace<EikMeshPoint>> meshPanel = new MeshPanel<>(
meshImprover.getMesh(), 1000, 800,
bound);
meshImprover.getMesh(), 1000, 800);
// generate the mesh
meshImprover.generate();
......@@ -297,8 +291,7 @@ public class EikMeshExamples {
// (optional) define the gui to display the mesh
MeshPanel<MyPoint, PVertex<MyPoint>, PHalfEdge<MyPoint>, PFace<MyPoint>> meshPanel = new MeshPanel<>(
meshImprover.getMesh(), 1000, 800,
bound);
meshImprover.getMesh(), 1000, 800);
// generate the mesh
meshImprover.generate();
......
......@@ -381,6 +381,28 @@ public class AMesh<P extends IPoint> implements IMesh<P, AVertex<P>, AHalfEdge<P
return () -> streamEdges().iterator();
}
@Override
public AVertex<P> getRandomVertex(@NotNull Random random) {
int startIndex = random.nextInt(vertices.size());
int index = startIndex;
// look above
while (index < vertices.size() && isDestroyed(vertices.get(index))) {
index++;
}
// look below
if(isDestroyed(vertices.get(index))) {
index = startIndex - 1;
while (index >= 0 && isDestroyed(vertices.get(index))) {
index--;
}
}
return vertices.get(index);
}
@Override
public int getNumberOfVertices() {
return numberOfVertices;
......
......@@ -82,7 +82,7 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
private static Logger log = LogManager.getLogger(IncrementalTriangulation.class);
static {
ITriConnectivity.log.setLevel(Level.DEBUG);
ITriConnectivity.log.setLevel(Level.INFO);
}
/**
......
......@@ -27,8 +27,7 @@ public class JumpAndWalk<P extends IPoint, V extends IVertex<P>, E extends IHalf
}
private Optional<F> getStartFace(final IPoint endPoint) {
List<V> vertices = triangulation.getMesh().getVertices();
int n = vertices.size();
int n = triangulation.getMesh().getNumberOfVertices();
if(n < 20) {
return Optional.empty();
......@@ -38,8 +37,8 @@ public class JumpAndWalk<P extends IPoint, V extends IVertex<P>, E extends IHalf
double max = Math.pow(n, 1.0/3.0);
for(int i = 0; i < max; i++) {
int index = random.nextInt(n);
V vertex = vertices.get(index);
V vertex = triangulation.getMesh().getRandomVertex(random);
if(result == null || endPoint.distanceSq(vertex) < endPoint.distanceSq(result)) {
result = vertex;
......
package org.vadere.meshing.mesh.gen;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.vadere.util.visualization.ColorHelper;
import org.vadere.meshing.mesh.inter.IFace;
import org.vadere.meshing.mesh.inter.IHalfEdge;
import org.vadere.meshing.mesh.inter.IMesh;
......@@ -11,9 +8,6 @@ import org.vadere.meshing.mesh.inter.IVertex;
import org.vadere.util.geometry.shapes.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Function;
import java.util.function.Predicate;
......@@ -31,12 +25,7 @@ import javax.swing.*;
*/
public class MeshPanel<P extends IPoint, V extends IVertex<P>, E extends IHalfEdge<P>, F extends IFace<P>> extends Canvas {
private static final Logger log = LogManager.getLogger(MeshPanel.class);
/**
* The mesh which will be rendered.
*/
private IMesh<P, V, E, F> mesh;
private MeshRenderer<P, V, E, F> meshRenderer;
/**
* The width of the canvas.
......@@ -48,40 +37,30 @@ public class MeshPanel<P extends IPoint, V extends IVertex<P>, E extends IHalfEd
*/
private double height;
/**
* A {@link Collection} of {@link F} from the mesh.
* Ths collection exist to avoid the {@link java.util.ConcurrentModificationException}.
*/
private Collection<F> faces;
/**
* A {@link Predicate} of {@link F} which marks a face to be drawn (not filled) in a special way.
*/
private final Predicate<F> alertPred;
/**
* The bound of the mesh.
*/
private VRectangle bound;
/**
* The scaling between the mesh bound-size and the canvas bound-size.
*/
private final double scale;
/**
* A function which decides by which color the face should be filled.
* Default constructor.
*
* @param meshRenderer a renderer which draws the mesh
* @param width the width of the canvas
* @param height the height of the canvas
*/
private Function<F, Color> colorFunction;
public MeshPanel(
@NotNull final MeshRenderer<P, V, E, F> meshRenderer,
final double width,
final double height) {
this.meshRenderer = meshRenderer;
this.height = height;
this.width = width;
}
/**
* Default constructor.
* Construct a mesh panel filling faces with the color defined by the color function.
*
* @param mesh the mesh which will be rendered
* @param alertPred a {@link Predicate} of {@link F} which marks a face to be drawn in a special way.
* @param width width of the canvas
* @param height height of the canvas
* @param bound bound of the mesh
* @param colorFunction color function coloring faces
*/
public MeshPanel(
......@@ -89,16 +68,10 @@ public class MeshPanel<P extends IPoint, V extends IVertex<P>, E extends IHalfEd
@NotNull final Predicate<F> alertPred,
final double width,
final double height,
@NotNull final VRectangle bound,
@NotNull final Function<F, Color> colorFunction) {
this.mesh = mesh;
this.width = width;
this.meshRenderer = new MeshRenderer<>(mesh, alertPred, colorFunction);
this.height = height;
this.alertPred = alertPred;
this.bound = bound;
this.scale = Math.min(width / bound.getWidth(), height / bound.getHeight());
this.faces = new ArrayList<>();
this.colorFunction = colorFunction;
this.width = width;
}
/**
......@@ -108,15 +81,13 @@ public class MeshPanel<P extends IPoint, V extends IVertex<P>, E extends IHalfEd
* @param alertPred a {@link Predicate} of {@link F} which marks a face to be drawn in a special way.
* @param width width of the canvas
* @param height height of the canvas
* @param bound bound of the mesh
*/
public MeshPanel(
@NotNull final IMesh<P, V, E, F> mesh,
@NotNull final Predicate<F> alertPred,
final double width,
final double height,
@NotNull final VRectangle bound) {
this(mesh, alertPred, width, height, bound, f -> Color.WHITE);
final double height) {
this(mesh, alertPred, width, height, f -> Color.WHITE);
}
/**
......@@ -125,82 +96,19 @@ public class MeshPanel<P extends IPoint, V extends IVertex<P>, E extends IHalfEd
* @param mesh the mesh which will be rendered
* @param width width of the canvas
* @param height height of the canvas
* @param bound bound of the mesh
*/
public MeshPanel(
@NotNull final IMesh<P, V, E, F> mesh,
final double width,
final double height,
@NotNull final VRectangle bound) {
this(mesh, f -> false, width, height, bound, f -> Color.WHITE);
final double height) {
this(mesh, f -> false, width, height, f -> Color.WHITE);
}
@Override
public void update(Graphics g) {
// TODO clone it!
synchronized (mesh) {
refresh();
super.update(g);
}
}
public void refresh() {
synchronized (mesh) {
faces = mesh.clone().getFaces();
}
}
/**
* Constructs the image {@link BufferedImage} which will be drawn to the canvas / panel.
*
* @return an image of the mesh
*/
public BufferedImage getImage() {
BufferedImage image = new BufferedImage((int)width, (int)height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = (Graphics2D) image.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fill(new VRectangle(0, 0, width, height));
Font currentFont = graphics.getFont();
Font newFont = currentFont.deriveFont(currentFont.getSize() * 0.064f);
graphics.setFont(newFont);
graphics.setColor(Color.GRAY);
graphics.translate(-bound.getMinX() * scale, -bound.getMinY() * scale);
graphics.scale(scale, scale);
//graphics.translate(-bound.getMinX()+(0.5*Math.max(0, bound.getWidth()-bound.getHeight())), -bound.getMinY() + (bound.getHeight()-height / scale));
graphics.setStroke(new BasicStroke(0.003f));
graphics.setColor(Color.BLACK);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
/*int groupSize = 64;
ColorHelper colorHelper = new ColorHelper(faces.size());*/
for(F face : faces) {
VPolygon polygon = mesh.toTriangle(face);
graphics.setColor(colorFunction.apply(face));
graphics.fill(polygon);
if(alertPred.test(face)) {
graphics.setColor(Color.RED);
graphics.draw(polygon);
}
else {
graphics.setColor(Color.GRAY);
graphics.draw(polygon);
}
}
return image;
}
@Override
public void paint(Graphics g) {
// double buffering => draw into an image
Graphics2D graphics2D = (Graphics2D) g;
graphics2D.drawImage(getImage(), 0, 0, null);
meshRenderer.render((Graphics2D) g, (int)Math.ceil(width), (int)Math.ceil(height));
}
public JFrame display() {
......
package org.vadere.meshing.mesh.gen;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.vadere.meshing.mesh.inter.IFace;
import org.vadere.meshing.mesh.inter.IHalfEdge;
import org.vadere.meshing.mesh.inter.IMesh;
import org.vadere.meshing.mesh.inter.IVertex;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VPolygon;
import org.vadere.util.geometry.shapes.VRectangle;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* This helper class renders a {@link IMesh} into a {@link BufferedImage} or a {@link Graphics2D}.
*
* @author Benedikt Zoennchen
*
* @param <P> the type of the points (containers)
* @param <V> the type of the vertices
* @param <E> the type of the half-edges
* @param <F> the type of the faces
*/
public class MeshRenderer<P extends IPoint, V extends IVertex<P>, E extends IHalfEdge<P>, F extends IFace<P>> {
private static final Logger log = LogManager.getLogger(MeshRenderer.class);
/**
* The mesh which will be rendered.
*/
private IMesh<P, V, E, F> mesh;
/**
* A {@link Collection} of {@link F} from the mesh.
* Ths collection exist to avoid the {@link java.util.ConcurrentModificationException}.
*/
private Collection<F> faces;
/**
* A {@link Predicate} of {@link F} which marks a face to be drawn (not filled) in a special way.
*/
private final Predicate<F> alertPred;
/**
* A function which decides by which color the face should be filled.
*/
private Function<F, Color> colorFunction;
/**
* Default constructor.
*
* @param mesh the mesh which will be rendered
* @param alertPred a {@link Predicate} of {@link F} which marks a face to be drawn in a special way.
* @param colorFunction color function coloring faces
*/
public MeshRenderer(
@NotNull final IMesh<P, V, E, F> mesh,
<