Skip to content
Snippets Groups Projects
Commit f549947d authored by Radek Ošlejšek's avatar Radek Ošlejšek
Browse files

Merge branch '88-improved-maping-distances-on-heatmap' into 'master'

Resolve "Improved maping distances on heatmap"

Closes #88

See merge request grp-fidentis/analyst2!98
parents 84993954 414f4024
No related branches found
No related tags found
No related merge requests found
package cz.fidentis.analyst.gui;
import cz.fidentis.analyst.mesh.core.MeshFacet;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* @author Daniel Sokol
* <p>
* Class for computing histogram and modifing distances
*/
public class HistogramComponent extends JPanel {
private final DrawCanvas drawnHistogram = new DrawCanvas();
private final JSpinner minSpinner = new JSpinner();
private final JSpinner maxSpinner = new JSpinner();
private Map<MeshFacet, List<Double>> values;
private Double minValue = 1.0;
private Double maxValue = 10.0;
private Double oneStep = 1.0;
private final Map<Double, Integer> frequencies = new TreeMap<>();
private int maxFrequency = 1;
private int intervalsCount = 20;
public HistogramComponent() {
setupComponents();
}
/**
* Add swing components to frame
*/
private void setupComponents() {
setBackground(new Color(0, 174, 163));
setLayout(new BoxLayout(this,BoxLayout.PAGE_AXIS));
add(new JLabel("Number of intervals:"));
JSlider intervalSlider = new JSlider(JSlider.HORIZONTAL, 0, 200, intervalsCount);
intervalSlider.setMajorTickSpacing(20);
intervalSlider.setMinorTickSpacing(5);
intervalSlider.setPaintTicks(true);
intervalSlider.setPaintLabels(true);
intervalSlider.setBackground(new Color(0, 174, 163));
add(intervalSlider);
drawnHistogram.setMinimumSize(new Dimension(getMinimumSize().width, 330));
drawnHistogram.setMaximumSize(new Dimension(getMaximumSize().width, 330));
drawnHistogram.setPreferredSize(new Dimension(getPreferredSize().width, 330));
add(drawnHistogram);
Box tempBox = new Box(BoxLayout.LINE_AXIS);
tempBox.add(new JLabel("Select minimum value of distances"));
tempBox.add(minSpinner);
tempBox.add(new JLabel("Select maximum value of distances"));
tempBox.add(maxSpinner);
JButton newButton = new JButton("Set and Compute");
newButton.addActionListener(e -> {
intervalsCount = intervalSlider.getValue();
minValue = (Double) minSpinner.getValue();
maxValue = (Double) maxSpinner.getValue();
setSpinners();
cutValues();
computeFrequencies();
drawnHistogram.repaint();
});
tempBox.add(newButton);
add(tempBox);
}
/**
* Set spinners to new min a max values
*/
private void setSpinners() {
SpinnerModel minModel = new SpinnerNumberModel((double) minValue,
(double) minValue, (double) maxValue, (double) oneStep);
minSpinner.setModel(minModel);
SpinnerModel maxModel = new SpinnerNumberModel((double) maxValue,
(double) minValue, (double) maxValue, (double) oneStep);
maxSpinner.setModel(maxModel);
}
public Map<MeshFacet, List<Double>> getValues() {
return values;
}
/**
* Set new distances and compute their frequencies
*
* @param values Values
*/
public void setValues(Map<MeshFacet, List<Double>> values) {
this.values = values;
findMinMax();
computeFrequencies();
drawnHistogram.repaint();
setSpinners();
}
public void computeFrequencies() {
oneStep = maxValue - minValue;
if (maxValue < 0) {
oneStep = Math.abs(maxValue) - Math.abs(minValue);
}
oneStep /= intervalsCount;
//Remove old values in frequencies
frequencies.clear();
for (Double i = minValue; i < maxValue; i += oneStep) {
int currFrequency = 0; //Number of values in current interval
for (List<Double> facetValues : values.values() ){
for (Double temp : facetValues) {
if (temp >= i && temp < i + oneStep) {
currFrequency++;
}
}
}
if (currFrequency > maxFrequency) {
maxFrequency = currFrequency;
}
//Add beginning of interval and number of values in it
frequencies.put(i, currFrequency);
}
}
private void findMinMax() {
minValue = Double.MAX_VALUE;
maxValue = Double.MIN_VALUE;
for (List<Double> facetValues : values.values() ){
for (Double temp : facetValues) {
if (temp < minValue) {
minValue = temp;
}
if (temp > maxValue) {
maxValue = temp;
}
}
}
}
/**
* Cut of distances that are before minimum or after maximum distance selected by user
*/
private void cutValues() {
for (List<Double> double_values : values.values() ){
for (int i = 0; i < values.size(); ++i) {
if (double_values.get(i) < minValue) {
double_values.set(i, minValue);
} else if (double_values.get(i) > maxValue) {
double_values.set(i, maxValue);
}
}
}
}
public Double getMinValue() {
return minValue;
}
public Double getMaxValue() {
return maxValue;
}
/**
* @author Daniel Sokol
* <p>
* Internal class for drawing histogram
*/
private class DrawCanvas extends JPanel {
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(new Color(0, 174, 163));
int place = 0;
int moveStep = this.getWidth() / intervalsCount;
double heightModificator = (double) this.getHeight() / maxFrequency;
Graphics2D g2 = (Graphics2D) g;
Font font = new Font("Arial Narrow", Font.BOLD, 12);
AffineTransform affineTransform = new AffineTransform();
affineTransform.rotate(Math.toRadians(90), 0, 0);
g2.setFont(font.deriveFont(affineTransform));
for (Map.Entry<Double, Integer> entry : frequencies.entrySet()) {
g.setColor(Color.ORANGE);
int height = (int) (entry.getValue() * heightModificator);
g2.fillRect(place, 300 - height, moveStep - 2, height);
g.setColor(Color.BLACK);
String value = String.format("%.4f", entry.getKey());
g2.drawString(value, place, this.getHeight() - 50);
g2.drawString(entry.getValue().toString(), place, 50);
place += moveStep;
}
}
}
}
...@@ -4,55 +4,54 @@ import com.jogamp.opengl.GL; ...@@ -4,55 +4,54 @@ import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2; import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLAutoDrawable;
import cz.fidentis.analyst.face.HumanFace; import cz.fidentis.analyst.face.HumanFace;
import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.mesh.core.MeshModel;
import javax.vecmath.Vector3d;
import java.util.List;
import java.util.Map;
import static com.jogamp.opengl.GL.GL_FRONT_AND_BACK;
import static com.jogamp.opengl.GL.GL_VIEWPORT;
import static com.jogamp.opengl.GL2GL3.GL_FILL;
import static com.jogamp.opengl.GL2GL3.GL_LINE;
import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_MODELVIEW_MATRIX;
import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_PROJECTION_MATRIX;
import cz.fidentis.analyst.gui.Canvas; import cz.fidentis.analyst.gui.Canvas;
import cz.fidentis.analyst.gui.GeneralGLEventListener; import cz.fidentis.analyst.gui.GeneralGLEventListener;
import cz.fidentis.analyst.gui.HistogramComponent;
import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.mesh.core.MeshModel;
import cz.fidentis.analyst.mesh.core.MeshPoint; import cz.fidentis.analyst.mesh.core.MeshPoint;
import cz.fidentis.analyst.visitors.mesh.Curvature; import cz.fidentis.analyst.visitors.mesh.Curvature;
import cz.fidentis.analyst.visitors.mesh.HausdorffDistance; import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy; import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy;
import org.openide.util.Exceptions;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import java.awt.Color; import java.awt.Color;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.GridBagLayout; import java.awt.GridBagLayout;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.swing.JButton;
import javax.swing.JFrame; import static com.jogamp.opengl.GL.GL_FRONT_AND_BACK;
import javax.vecmath.Point3d; import static com.jogamp.opengl.GL.GL_VIEWPORT;
import org.openide.util.Exceptions; import static com.jogamp.opengl.GL2GL3.GL_FILL;
import static com.jogamp.opengl.GL2GL3.GL_LINE;
import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_MODELVIEW_MATRIX;
import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_PROJECTION_MATRIX;
/** /**
* Testing application displaying different heat maps in 3D. * Testing application displaying different heat maps in 3D.
* *
* @author Daniel Sokol * @author Daniel Sokol
* @author Radek Oslejsek * @author Radek Oslejsek
*/ */
public class HeatMapsTestApp extends GeneralGLEventListener { public class HeatMapsTestApp extends GeneralGLEventListener {
private static final JFrame TEST_FRAME = new JFrame(); private static final JFrame TEST_FRAME = new JFrame();
public final HistogramComponent histogram = new HistogramComponent();
private Map<MeshFacet, List<Double>> values; private Map<MeshFacet, List<Double>> values;
private final Color minColor = Color.BLUE; private final Color minColor = Color.BLUE;
private final Color maxColor = Color.RED; private final Color maxColor = Color.RED;
private double minDistance;
private double maxDistance;
/** /**
* Constructor. * Constructor.
* @param canvas Canvas * @param canvas Canvas
...@@ -60,10 +59,10 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -60,10 +59,10 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
public HeatMapsTestApp(Canvas canvas) { public HeatMapsTestApp(Canvas canvas) {
super(canvas); super(canvas);
} }
/** /**
* Main method * Main method
* @param args Input arguments * @param args Input arguments
* @throws IOException on IO error * @throws IOException on IO error
*/ */
public static void main(String[] args) { public static void main(String[] args) {
...@@ -78,7 +77,7 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -78,7 +77,7 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
Canvas testCanvas = new Canvas(); Canvas testCanvas = new Canvas();
HeatMapsTestApp colorListener = new HeatMapsTestApp(testCanvas); HeatMapsTestApp colorListener = new HeatMapsTestApp(testCanvas);
testCanvas.setListener(colorListener); testCanvas.setListener(colorListener);
gaussButton.addActionListener(e -> colorListener.computeGaussian()); gaussButton.addActionListener(e -> colorListener.computeGaussian());
meanButton.addActionListener(e -> colorListener.computeMean()); meanButton.addActionListener(e -> colorListener.computeMean());
maxButton.addActionListener(e -> colorListener.computeMaxPrincipal()); maxButton.addActionListener(e -> colorListener.computeMaxPrincipal());
...@@ -88,7 +87,8 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -88,7 +87,8 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
TEST_FRAME.setLayout(new GridBagLayout()); TEST_FRAME.setLayout(new GridBagLayout());
TEST_FRAME.setVisible(true); TEST_FRAME.setVisible(true);
TEST_FRAME.setSize(1600, 900); //TEST_FRAME.setSize(1920, 1080);
TEST_FRAME.setExtendedState(JFrame.MAXIMIZED_BOTH);
// Adding // Adding
GridBagConstraints c = new GridBagConstraints(); GridBagConstraints c = new GridBagConstraints();
...@@ -98,7 +98,7 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -98,7 +98,7 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
c.weighty = 1; c.weighty = 1;
c.weightx = 1; c.weightx = 1;
c.gridheight = 6; c.gridheight = 8;
c.gridwidth = 4; c.gridwidth = 4;
c.weightx = 4; c.weightx = 4;
TEST_FRAME.add(testCanvas, c); TEST_FRAME.add(testCanvas, c);
...@@ -106,28 +106,34 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -106,28 +106,34 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
c.gridwidth = 2; c.gridwidth = 2;
c.gridx = 4; c.gridx = 4;
c.weightx = 2; c.weightx = 2;
//testFrame.add(addButton, c);
c.gridy = 1; c.gridy = 1;
TEST_FRAME.add(colorListener.histogram,c);
c.weightx = 1;
c.gridwidth = 1;
c.gridy++;
TEST_FRAME.add(gaussButton, c); TEST_FRAME.add(gaussButton, c);
c.gridy = 2; c.gridx++;
TEST_FRAME.add(meanButton, c); TEST_FRAME.add(meanButton, c);
c.gridy = 3; c.gridy++;
c.gridx--;
TEST_FRAME.add(maxButton, c); TEST_FRAME.add(maxButton, c);
c.gridy = 4; c.gridx++;
TEST_FRAME.add(minButton, c); TEST_FRAME.add(minButton, c);
c.gridy = 5; c.gridy++;
c.gridx--;
TEST_FRAME.add(hdButton1, c); TEST_FRAME.add(hdButton1, c);
c.gridy = 6; c.gridx++;
TEST_FRAME.add(hdButton2, c); TEST_FRAME.add(hdButton2, c);
} }
@Override @Override
public void setModel(MeshModel model) { public void setModel(MeshModel model) {
super.setModel(model); super.setModel(model);
System.err.println(); System.err.println();
System.err.println("MODEL: " + getModel()); System.err.println("MODEL: " + getModel());
Set<Point3d> unique = new HashSet<>(); Set<Point3d> unique = new HashSet<>();
for (MeshPoint p: getModel().getFacets().get(0).getVertices()) { for (MeshPoint p: getModel().getFacets().get(0).getVertices()) {
unique.add(p.getPosition()); unique.add(p.getPosition());
...@@ -152,18 +158,17 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -152,18 +158,17 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
if (this.getModel() == null) { if (this.getModel() == null) {
return; return;
} }
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
Curvature vis = new Curvature(); Curvature vis = new Curvature();
this.getModel().compute(vis); this.getModel().compute(vis);
values = vis.getGaussianCurvatures(); values = vis.getGaussianCurvatures();
long duration = System.currentTimeMillis() - startTime; long duration = System.currentTimeMillis() - startTime;
System.err.println(duration + "\tmsec: Gaussian curvature"); System.err.println(duration + "\tmsec: Gaussian curvature");
minDistance = -0.02; histogram.setValues(values);
maxDistance = 0.008;
} }
/** /**
* Computes curvature * Computes curvature
*/ */
...@@ -171,18 +176,17 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -171,18 +176,17 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
if (this.getModel() == null) { if (this.getModel() == null) {
return; return;
} }
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
Curvature vis = new Curvature(); Curvature vis = new Curvature();
this.getModel().compute(vis); this.getModel().compute(vis);
values = vis.getMeanCurvatures(); values = vis.getMeanCurvatures();
long duration = System.currentTimeMillis() - startTime; long duration = System.currentTimeMillis() - startTime;
System.err.println(duration + "\tmsec: Mean curvature"); System.err.println(duration + "\tmsec: Mean curvature");
minDistance = -0.001; histogram.setValues(values);
maxDistance = 0.1;
} }
/** /**
* Computes curvature * Computes curvature
*/ */
...@@ -190,18 +194,17 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -190,18 +194,17 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
if (this.getModel() == null) { if (this.getModel() == null) {
return; return;
} }
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
Curvature vis = new Curvature(); Curvature vis = new Curvature();
this.getModel().compute(vis); this.getModel().compute(vis);
values = vis.getMinPrincipalCurvatures(); values = vis.getMinPrincipalCurvatures();
long duration = System.currentTimeMillis() - startTime; long duration = System.currentTimeMillis() - startTime;
System.err.println(duration + "\tmsec: Minimum principal curvature"); System.err.println(duration + "\tmsec: Minimum principal curvature");
minDistance = -0.05; histogram.setValues(values);
maxDistance = 0.03;
} }
/** /**
* Computes curvature * Computes curvature
*/ */
...@@ -209,18 +212,16 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -209,18 +212,16 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
if (this.getModel() == null) { if (this.getModel() == null) {
return; return;
} }
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
Curvature vis = new Curvature(); Curvature vis = new Curvature();
this.getModel().compute(vis); this.getModel().compute(vis);
values = vis.getMaxPrincipalCurvatures(); values = vis.getMaxPrincipalCurvatures();
long duration = System.currentTimeMillis() - startTime; long duration = System.currentTimeMillis() - startTime;
System.err.println(duration + "\tmsec: Maximum principal curvature"); System.err.println(duration + "\tmsec: Maximum principal curvature");
histogram.setValues(values);
minDistance = -0.02;
maxDistance = 0.25;
} }
/** /**
* Computes absolute HD * Computes absolute HD
*/ */
...@@ -239,11 +240,9 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -239,11 +240,9 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
} catch (IOException ex) { } catch (IOException ex) {
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
} }
List<Double> distanceList = values.get(getModel().getFacets().get(0)); histogram.setValues(values);
minDistance = distanceList.stream().mapToDouble(Double::doubleValue).min().getAsDouble();
maxDistance = distanceList.stream().mapToDouble(Double::doubleValue).max().getAsDouble();
} }
/** /**
* Computes relative HD * Computes relative HD
*/ */
...@@ -263,10 +262,9 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -263,10 +262,9 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
} }
List<Double> distanceList = values.get(getModel().getFacets().get(0)); List<Double> distanceList = values.get(getModel().getFacets().get(0));
minDistance = distanceList.stream().mapToDouble(Double::doubleValue).min().getAsDouble(); histogram.setValues(values);
maxDistance = distanceList.stream().mapToDouble(Double::doubleValue).max().getAsDouble();
} }
@Override @Override
public void display(GLAutoDrawable glad) { public void display(GLAutoDrawable glad) {
wireModel = glCanvas.getDrawWired(); // is wire-frame or not wireModel = glCanvas.getDrawWired(); // is wire-frame or not
...@@ -306,7 +304,7 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -306,7 +304,7 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
protected void drawHeatmap(MeshModel model) { protected void drawHeatmap(MeshModel model) {
for (int i = 0; i < model.getFacets().size(); i++) { for (int i = 0; i < model.getFacets().size(); i++) {
renderFaceWithHeatmap(model.getFacets().get(i), values.get(model.getFacets().get(i)), minDistance, maxDistance); renderFaceWithHeatmap(model.getFacets().get(i), histogram.getValues().get(model.getFacets().get(i)), histogram.getMinValue(), histogram.getMaxValue());
} }
} }
...@@ -334,13 +332,13 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -334,13 +332,13 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
protected Color getColor(Double currentDistance, Double minDistance, Double maxDistance) { protected Color getColor(Double currentDistance, Double minDistance, Double maxDistance) {
double currentParameter = ((currentDistance - minDistance) / (maxDistance - minDistance)); double currentParameter = ((currentDistance - minDistance) / (maxDistance - minDistance));
if (currentDistance > maxDistance) { if (currentDistance > maxDistance) {
currentParameter = 1.0; currentParameter = 1.0;
} else if (currentDistance < minDistance || (maxDistance - minDistance) == 0) { } else if (currentDistance < minDistance || (maxDistance - minDistance) == 0) {
currentParameter = 0.0; currentParameter = 0.0;
} }
float[] hsb1 = Color.RGBtoHSB(minColor.getRed(), minColor.getGreen(), minColor.getBlue(), null); float[] hsb1 = Color.RGBtoHSB(minColor.getRed(), minColor.getGreen(), minColor.getBlue(), null);
double h1 = hsb1[0]; double h1 = hsb1[0];
double s1 = hsb1[1]; double s1 = hsb1[1];
...@@ -377,7 +375,7 @@ public class HeatMapsTestApp extends GeneralGLEventListener { ...@@ -377,7 +375,7 @@ public class HeatMapsTestApp extends GeneralGLEventListener {
if (hue > 1) { if (hue > 1) {
hue = hue - 1; hue = hue - 1;
} }
double saturation = (1 - currentParameter) * s1 + currentParameter * s2; double saturation = (1 - currentParameter) * s1 + currentParameter * s2;
double brightness = (1 - currentParameter) * b1 + currentParameter * b2; double brightness = (1 - currentParameter) * b1 + currentParameter * b2;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment