Starting from 2021-07-01, all LRZ GitLab users will be required to explicitly accept the GitLab Terms of Service. Please see the detailed information at https://doku.lrz.de/display/PUBLIC/GitLab and make sure that your projects conform to the requirements.

Commit 2d44e5e3 authored by Stefan Schuhbaeck's avatar Stefan Schuhbaeck
Browse files

Merge branch 'master' into ScenarioCheckerRefactor

parents eae49bb3 f642c5fd
Pipeline #71450 failed with stages
in 66 minutes and 47 seconds
......@@ -290,6 +290,7 @@ TopographyCreator.btnRedo.tooltip=Redo
TopographyCreator.btnCutTopography.tooltip=Cut Scenario
TopographyCreator.btnInsertPedestrian.tooltip=Pedestrian
TopographyCreator.btnTopographyBound.tooltip=Topography Bound
TopographyCreator.btnTranslation.tooltip=Translate topography
TopographyCreator.btnInsertObstacle.tooltip=Obstacle
TopographyCreator.btnInsertTarget.tooltip=Target
TopographyCreator.btnInsertSource.tooltip=Source
......
......@@ -285,6 +285,7 @@ TopographyCreator.btnInsertPedestrian.tooltip=Fu\u00dfg\u00e4nger
TopographyCreator.btnInsertObstacle.tooltip=Hindernis
TopographyCreator.btnInsertTarget.tooltip=Ziel
TopographyCreator.btnTopographyBound.tooltip=Topographie Grenze
TopographyCreator.btnTranslation.tooltip=Topographie verschieben
TopographyCreator.btnInsertSource.tooltip=Quelle
TopographyCreator.btnInsertStairs.tooltip=Treppen
TopographyCreator.btnErase.tooltip=Radierer
......
......@@ -4,6 +4,8 @@ import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.vadere.gui.components.model.IDefaultModel;
import java.awt.*;
......@@ -15,6 +17,7 @@ import java.awt.geom.Rectangle2D;
*/
public class JViewportChangeListener implements ChangeListener {
private Logger logger = LogManager.getLogger(JViewportChangeListener.class);
private final JScrollBar verticalScrollBar;
private final IDefaultModel defaultModel;
......@@ -26,14 +29,25 @@ public class JViewportChangeListener implements ChangeListener {
@Override
public void stateChanged(final ChangeEvent e) {
Rectangle2D.Double topographyBound = defaultModel.getTopographyBound();
Rectangle2D.Double viewp = defaultModel.getViewportBound();
JViewport viewPort = (JViewport) e.getSource();
if (topographyBound != null) {
Rectangle rect = viewPort.getViewRect();
double x = Math.max(0.0, rect.getX() / defaultModel.getScaleFactor());
double y = Math.max(0.0, topographyBound.getHeight()
- ((rect.getY() + verticalScrollBar.getHeight()) / defaultModel.getScaleFactor()));
double x = Math.max(topographyBound.getMinX(), topographyBound.getMinX() + rect.getX() / defaultModel.getScaleFactor());
double barHeight;
if(verticalScrollBar.getHeight() > 0) {
barHeight = verticalScrollBar.getHeight();
}
else {
barHeight = rect.getHeight();
}
double y = Math.max(topographyBound.getMinY(), topographyBound.getMinY() + topographyBound.getHeight()
- ((rect.getY() + barHeight) / defaultModel.getScaleFactor()));
double w = rect.getWidth() / defaultModel.getScaleFactor();
double h = rect.getHeight() / defaultModel.getScaleFactor();
defaultModel.setViewportBound(new Rectangle2D.Double(x, y, w, h));
defaultModel.notifyObservers();
}
......
......@@ -35,6 +35,8 @@ public class ViewportChangeListener implements IViewportChangeListener {
boolean scaleChanges = defaultModel.setScale(scale);
if (scaleChanges || !viewport.equals(defaultModel.getViewportBound())) {
double dx = viewportBound.getMinX() - topographyBound.getMinX();
double dy = viewportBound.getMinY() - topographyBound.getMinY();
if (scaleChanges) {
defaultModel.notifyScaleListeners();
}
......@@ -44,11 +46,16 @@ public class ViewportChangeListener implements IViewportChangeListener {
viewport.getView().setPreferredSize(new Dimension(
(int) (topographyBound.getWidth() * scale),
(int) (topographyBound.getHeight() * scale)));
viewport.setViewSize(new Dimension((int) (topographyBound.getWidth() * scale),
viewport.setViewSize(new Dimension(
(int) (topographyBound.getWidth() * scale),
(int) (topographyBound.getHeight() * scale)));
viewport.setViewPosition(new Point((int) ((viewportBound.getX()) * scale),
(int) ((topographyBound.getHeight() - (viewportBound.getY() + viewportBound.getHeight()))
viewport.setViewPosition(new Point(
(int) (dx * scale),
(int) ((topographyBound.getHeight() - (dy + viewportBound.getHeight()))
* scale)));
defaultModel.notifyObservers();
}
}
......
......@@ -7,6 +7,7 @@ import org.vadere.gui.components.view.ISelectScenarioElementListener;
import org.vadere.state.scenario.ScenarioElement;
import org.vadere.state.types.ScenarioElementType;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VShape;
import org.vadere.util.voronoi.VoronoiDiagram;
......@@ -123,6 +124,8 @@ public abstract class DefaultModel<T extends DefaultConfig> extends Observable i
@Override
public boolean setScale(final double scale) {
boolean hasChanged = true;
double oldScale = scaleFactor;
if (scale < MIN_SCALE_FACTOR) {
this.scaleFactor = MIN_SCALE_FACTOR;
} else if (scale > MAX_SCALE_FACTOR) {
......@@ -133,7 +136,15 @@ public abstract class DefaultModel<T extends DefaultConfig> extends Observable i
hasChanged = false;
}
// update the viewport, since it depends on the scaleFactor
if (hasChanged) {
Rectangle2D.Double oldViewPort = getViewportBound();
Rectangle2D.Double newViewPort = new Rectangle2D.Double(
oldViewPort.getMinX(),
oldViewPort.getMinY(),
oldViewPort.getWidth() * oldScale / scaleFactor,
oldViewPort.getHeight() * oldScale / scaleFactor);
setViewportBound(newViewPort);
setChanged();
}
return hasChanged;
......@@ -430,9 +441,14 @@ public abstract class DefaultModel<T extends DefaultConfig> extends Observable i
getWindowBound().getHeight() / getViewportBound().getHeight());
}
/**
*
* @param pInPixel the mouse position of the mouse event
* @return
*/
protected VPoint pixelToWorld(final VPoint pInPixel) {
return new VPoint(pInPixel.getX() / scaleFactor + getTopographyBound().getX(),
(getTopographyBound().getHeight() * scaleFactor - pInPixel.getY()) / scaleFactor);
return new VPoint(pInPixel.getX() / scaleFactor + getTopographyBound().getMinX(),
getTopographyBound().getMinY() + (getTopographyBound().getHeight() * scaleFactor - pInPixel.getY()) / scaleFactor);
/*
* return new VPoint(pInPixel.getX() / scaleFactor + getTopographyBound().getX() +
* getViewportBound().getX(),
......
......@@ -20,11 +20,7 @@ public class CLGaussianCalculator {
private IGaussianFilter filterPedestrians;
public CLGaussianCalculator(final SimulationModel model,
final double scale,
final double measurementRadius,
final Color color,
final boolean visualisation,
final boolean scenarioBound) {
final double scale) {
this.scenarioWidth = (int) model.getTopographyBound().getWidth();
this.scenarioHeight = (int) model.getTopographyBound().getHeight();
......@@ -60,7 +56,7 @@ public class CLGaussianCalculator {
// double bound = filter.getMaxFilteredValue();
double max = 1.00;
double factor = maxColorValue / max;
System.out.println(filterPedestrians.getMaxFilteredValue()); // 0.1259
//System.out.println(filterPedestrians.getMaxFilteredValue()); // 0.1259
for (int x = 0; x < filterPedestrians.getMatrixWidth(); x++) {
for (int y = 0; y < filterPedestrians.getMatrixHeight(); y++) {
......
package org.vadere.gui.components.view;
import org.jetbrains.annotations.NotNull;
import org.vadere.gui.components.model.IDefaultModel;
import org.vadere.state.scenario.Agent;
import org.vadere.state.scenario.ScenarioElement;
......@@ -24,27 +25,28 @@ import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.Collection;
/**
* @author Benedikt Zoennchen
*/
public abstract class DefaultRenderer {
private IDefaultModel defaultModel;
private BufferedImage logo;
private static final double rotNeg90 = - Math.PI /2;
public DefaultRenderer(final IDefaultModel defaultModel) {
this(defaultModel, true, false);
}
public DefaultRenderer(final IDefaultModel defaultModel, final boolean doubleBuffering,
final boolean hideBoundingBoxBorder) {
/**
* <p>Default constructor.</p>
*
* @param defaultModel
*/
public DefaultRenderer(@NotNull final IDefaultModel defaultModel) {
this.defaultModel = defaultModel;
this.logo = null;
}
/**
* Render the content. If doublebuffering is true, the whole content will be drawn on a new
* image.
* Otherwise the content will be drawn on the graphics object directly.
*
* <p></p>
*
* @param targetGraphics2D
* @param width
* @param height
......@@ -54,32 +56,32 @@ public abstract class DefaultRenderer {
}
public void render(final Graphics2D targetGraphics2D, final int x, final int y, final int width, final int height) {
//if(doubleBuffering) {
targetGraphics2D.drawImage(renderImage(width, height), x, y, null);
//} else {
//targetGraphics2D.translate(x, y);
//renderGraphics(targetGraphics2D, width, height);
// }
targetGraphics2D.drawImage(renderImage(width, height), x, y, null);
targetGraphics2D.dispose();
}
public void renderGraphics(final Graphics2D targetGraphics2D, final int width, final int height) {
targetGraphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// (1) clear background
targetGraphics2D.setColor(Color.GRAY);
//targetGraphics2D.fill();
targetGraphics2D.fillRect(0, 0, width, height);
// (2) render everything which can be rendered before the transformation
renderPreTransformation(targetGraphics2D, width, height);
// (3)
transformGraphics(targetGraphics2D);
// (4) render everything which can be rendered after the transformation
renderPostTransformation(targetGraphics2D, width, height);
}
public BufferedImage renderImage(final int width, final int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D bufferGraphics2D = (Graphics2D) image.getGraphics();
renderGraphics(bufferGraphics2D, width, height);
return image;
}
......@@ -92,8 +94,10 @@ public abstract class DefaultRenderer {
protected void renderPostTransformation(final Graphics2D graphics2D, final int width, final int height) {
graphics2D.setColor(Color.WHITE);
graphics2D.fill(new VRectangle(defaultModel.getBoundingBoxWidth(),
defaultModel.getBoundingBoxWidth(),
Rectangle2D.Double topographyBound = defaultModel.getTopographyBound();
graphics2D.fill(new VRectangle(
topographyBound.getMinX() + defaultModel.getBoundingBoxWidth(),
topographyBound.getMinY() + defaultModel.getBoundingBoxWidth(),
(defaultModel.getTopographyBound().getWidth() - defaultModel.getBoundingBoxWidth() * 2),
(defaultModel.getTopographyBound().getHeight() - defaultModel.getBoundingBoxWidth() * 2)));
......@@ -103,6 +107,7 @@ public abstract class DefaultRenderer {
Rectangle2D.Double topographyBound = defaultModel.getTopographyBound();
mirrowHorizonzal(graphics2D, (int) (topographyBound.getHeight() * defaultModel.getScaleFactor()));
graphics2D.scale(defaultModel.getScaleFactor(), defaultModel.getScaleFactor());
//graphics2D.translate(-topographyBound.getMinX(), -topographyBound.getMinY());
/*
* This calculation we need since the viewport.y = 0 if the user scrolls to the bottom
......@@ -110,7 +115,7 @@ public abstract class DefaultRenderer {
Rectangle2D.Double viewportBound = defaultModel.getViewportBound();
double dy = topographyBound.getHeight() - viewportBound.getHeight();
graphics2D.translate(-viewportBound.getX(), Math.max((dy - viewportBound.getY()), 0));
graphics2D.translate(-viewportBound.getX(), Math.max((dy - viewportBound.getY()), - viewportBound.getY()));
// graphics2D.translate(+viewportBound.getX(), -Math.max((dy - viewportBound.getY()), 0));
}
......@@ -198,15 +203,25 @@ public abstract class DefaultRenderer {
*/
double dy = defaultModel.getTopographyBound().getHeight() - defaultModel.getViewportBound().getHeight();
// undo the viewport translation
graphics.translate(defaultModel.getViewportBound().getX(),
-Math.max((dy - defaultModel.getViewportBound().getY()), 0));
-Math.max((dy - defaultModel.getViewportBound().getY()), -defaultModel.getViewportBound().getY()));
graphics.scale(1.0 / scale, 1.0 / scale);
graphics.translate(0, +defaultModel.getTopographyBound().getHeight() * defaultModel.getScaleFactor());
graphics.scale(1.0, -1.0);
graphics.translate(0, 2.0);
graphics.scale(0.25, 0.25);
graphics.drawImage(logo, 0, 0, null);
// undo all scaling and translation
graphics.scale(1.0/0.25, 1.0/0.25);
graphics.translate(0, 1.0/2.0);
graphics.scale(1.0, -1.0);
graphics.translate(0, -defaultModel.getTopographyBound().getHeight() * defaultModel.getScaleFactor());
graphics.translate(-defaultModel.getViewportBound().getX(),
Math.max((dy - defaultModel.getViewportBound().getY()), -defaultModel.getViewportBound().getY()));
}
protected boolean hasLogo() {
......@@ -256,10 +271,10 @@ public abstract class DefaultRenderer {
protected void renderGrid(final Graphics2D g) {
g.setColor(Color.LIGHT_GRAY);
g.setStroke(new BasicStroke(getGridLineWidth()));
for (double y = 0; y <= defaultModel.getTopographyBound().height + 0.01; y +=
Rectangle2D.Double bound = defaultModel.getTopographyBound();
for (double y = bound.getMinY(); y <= bound.getMaxY() + 0.01; y +=
defaultModel.getGridResolution()) {
for (double x = 0; x <= defaultModel.getTopographyBound().width + 0.01; x +=
for (double x = bound.getMinX(); x <= bound.getMaxX() + 0.01; x +=
defaultModel.getGridResolution()) {
g.draw(new Line2D.Double(x - defaultModel.getGridResolution() * 0.2, y,
x + defaultModel.getGridResolution()
......@@ -611,8 +626,8 @@ public abstract class DefaultRenderer {
}
private static void mirrowHorizonzal(final Graphics2D graphics2D, final int height) {
graphics2D.scale(1, -1);
graphics2D.translate(0, -height);
graphics2D.scale(1.0, -1.0);
graphics2D.translate(0.0, -height);
}
private float getGridLineWidth() {
......
......@@ -24,6 +24,7 @@ import org.vadere.gui.renderer.agent.AgentRender;
import org.vadere.state.scenario.Agent;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VTriangle;
public abstract class SimulationRenderer extends DefaultRenderer {
......@@ -55,8 +56,9 @@ public abstract class SimulationRenderer extends DefaultRenderer {
protected void renderPreTransformation(Graphics2D graphics2D, int width, int height) {
if (model.isFloorFieldAvailable() && (model.config.isShowTargetPotentialField() || model.config.isShowPotentialField())) {
synchronized (model) {
renderPotentialField(graphics2D,
(int)(Math.min(model.getTopographyBound().width, model.getViewportBound().width) * model.getScaleFactor()),
renderPotentialFieldOnViewport(graphics2D,
0, 0,
(int)(Math.min(model.getTopographyBound().width, model.getViewportBound().width) * model.getScaleFactor()),
(int)(Math.min(model.getTopographyBound().height, model.getViewportBound().height) * model.getScaleFactor()));
}
}
......@@ -150,9 +152,7 @@ public abstract class SimulationRenderer extends DefaultRenderer {
}
private void renderDensity(final Graphics2D g) {
CLGaussianCalculator densityCalculator = new CLGaussianCalculator(model, model.config.getDensityScale(),
model.config.getDensityMeasurementRadius(),
model.config.getDensityColor(), true, true);
CLGaussianCalculator densityCalculator = new CLGaussianCalculator(model, model.config.getDensityScale());
/*
* if (obstacleDensity == null || !model.config.getDensityColor().equals(lastDensityColor)
* || model.getTopographyId() != topographyId) {
......@@ -169,45 +169,94 @@ public abstract class SimulationRenderer extends DefaultRenderer {
*/
BufferedImage densityImage = densityCalculator.getDensityImage();
Rectangle2D.Double bound = model.getTopographyBound();
g.translate(bound.getX(), bound.getY());
g.scale(1.0 / model.config.getDensityScale(), 1.0 / model.config.getDensityScale());
g.drawImage(densityImage, 0, 0, null);
// g.drawImage(pedestrianDensity, 0, 0, null);
g.scale(model.config.getDensityScale(), model.config.getDensityScale());
g.scale(model.config.getDensityScale(), model.config.getDensityScale());
g.translate(-bound.getX(), -bound.getY());
densityCalculator.destroy();
}
private void renderPotentialField(final Graphics2D g, final int width, final int height) {
private void renderPotentialFieldOnViewport(final Graphics2D g, final int xPos, final int yPos, final int width, final int height) {
logger.info("resolution = " + width + ", " + height);
/*
* This calculation we need since the viewport.y = 0 if the user scrolls to the bottom
*/
VRectangle bound = new VRectangle(model.getTopographyBound());
Rectangle2D.Double viewportBound = model.getViewportBound();
double dy = model.getTopographyBound().getHeight() - viewportBound.getHeight();
int startX = (int) (viewportBound.getX() * model.getScaleFactor());
int startY = (int) (Math.max((dy - viewportBound.getY()), 0) * model.getScaleFactor());
potentialFieldImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
potentialFieldImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < potentialFieldImage.getWidth(); x++) {
for (int y = 0; y < potentialFieldImage.getHeight(); y++) {
Color c;
double potential = model.getPotential(x + startX, y + startY);
if (potential >= MAX_POTENTIAL) {
c = model.config.getObstacleColor();
} else if (potential % CONTOUR_STEP <= CONTOUR_THINKNESS) {
c = Color.BLACK;
} else {
c = colorHelper.numberToColor(potential % 100);
VPoint pos = new VPoint(
viewportBound.getMinX() + x / model.getScaleFactor(),
viewportBound.getMinY() + (potentialFieldImage.getHeight() - 1 - y) / model.getScaleFactor());
if(bound.contains(pos)) {
double potential = (double)model.getPotentialField().apply(pos);
if (potential >= MAX_POTENTIAL) {
c = model.config.getObstacleColor();
} else if (potential % CONTOUR_STEP <= CONTOUR_THINKNESS) {
c = Color.BLACK;
} else {
c = colorHelper.numberToColor(potential % 100);
}
potentialFieldImage.setRGB(x, y, c.getRGB());
}
potentialFieldImage.setRGB(x, y, c.getRGB());
}
}
g.drawImage(potentialFieldImage, 0, 0, null);
g.drawImage(potentialFieldImage, xPos, yPos, null);
}
private void renderPotentialField(final Graphics2D g, final int xPos, final int yPos, final int width, final int height) {
/*
* This calculation we need since the viewport.y = 0 if the user scrolls to the bottom
*/
VRectangle bound = new VRectangle(model.getTopographyBound());
Rectangle2D.Double viewportBound = model.getViewportBound();
double dy = model.getTopographyBound().getHeight() - viewportBound.getHeight();
int startX = (int) (viewportBound.getX() * model.getScaleFactor());
int startY = (int) (Math.max((dy - viewportBound.getY()), 0) * model.getScaleFactor());
potentialFieldImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < potentialFieldImage.getWidth(); x++) {
for (int y = 0; y < potentialFieldImage.getHeight(); y++) {
Color c;
VPoint pos = new VPoint(
bound.getMinX() + x / model.getScaleFactor(),
bound.getMinY() + bound.getHeight() - y / model.getScaleFactor());
if(bound.contains(pos)) {
double potential = (double)model.getPotentialField().apply(pos);
if (potential >= MAX_POTENTIAL) {
c = model.config.getObstacleColor();
} else if (potential % CONTOUR_STEP <= CONTOUR_THINKNESS) {
c = Color.BLACK;
} else {
c = colorHelper.numberToColor(potential % 100);
}
potentialFieldImage.setRGB(x, y, c.getRGB());
}
}
}
g.drawImage(potentialFieldImage, xPos, yPos, null);
}
protected abstract void renderSimulationContent(final Graphics2D g);
private float getGridLineWidth() {
......
package org.vadere.gui.postvisualization.control;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.vadere.gui.postvisualization.model.PedestrianColorTableModel;
import org.vadere.gui.postvisualization.model.PostvisualizationModel;
import org.vadere.util.io.parser.JsonLogicParser;
import org.vadere.util.io.parser.VPredicate;
import java.text.ParseException;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
/**
* @author Benedikt Zoennchen
*/
public class TableListenerLogicExpression implements TableModelListener {
private static final Logger logger = LogManager.getLogger(TableListenerLogicExpression.class);
private PostvisualizationModel model;
private PedestrianColorTableModel pedestrianColorTableModel;
public TableListenerLogicExpression(@NotNull final PostvisualizationModel model, @NotNull final PedestrianColorTableModel pedestrianColorTableModel) {
this.model = model;
this.pedestrianColorTableModel = pedestrianColorTableModel;
}
@Override
public void tableChanged(final TableModelEvent e) {
for (int row = e.getFirstRow(); row <= e.getLastRow(); row++) {
if (row >= 0 && e.getColumn() == PedestrianColorTableModel.CIRTERIA_COLUMN) {
try {
String expression = pedestrianColorTableModel.getValueAt(row, e.getColumn()).toString();
VPredicate<JsonNode> evaluator = new JsonLogicParser(expression).parse();
model.putExpression(row, evaluator);
} catch (ParseException e1) {
model.removeExpression(row);
pedestrianColorTableModel.setValueAt("", e.getColumn(), row);
logger.warn(e1.getLocalizedMessage());
}
}
}
}
}
......@@ -19,6 +19,7 @@ import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.vadere.gui.components.model.SimulationModel;
import org.vadere.gui.postvisualization.control.TableListenerLogicExpression;
import org.vadere.gui.postvisualization.utils.PotentialFieldContainer;
import org.vadere.simulator.projects.Scenario;
import org.vadere.state.scenario.Agent;
......@@ -83,23 +84,18 @@ public class PostvisualizationModel extends SimulationModel<PostvisualizationCon
}
}*/
this.pedestrianColorTableModel.addTableModelListener(
e -> {
for (int row = e.getFirstRow(); row <= e.getLastRow(); row++) {
if (row >= 0 && e.getColumn() == PedestrianColorTableModel.CIRTERIA_COLUMN) {
try {
VPredicate<JsonNode> evaluator = new JsonLogicParser(
pedestrianColorTableModel.getValueAt(row, e.getColumn()).toString()).parse();
colorEvalFunctions.put(row, evaluator);
} catch (ParseException e1) {
colorEvalFunctions.remove(row);
logger.warn(e1.getLocalizedMessage());
}
}
}
});
this.pedestrianColorTableModel.addTableModelListener(new TableListenerLogicExpression(this, pedestrianColorTableModel));
}
public void putExpression(final int row, @NotNull final VPredicate<JsonNode> predicate) {
colorEvalFunctions.put(row, predicate);
}
public void removeExpression(final int row) {
colorEvalFunctions.remove(row);
}
/**
* Initialize the {@link PostvisualizationModel}.