Newer
Older
package cz.fidentis.analyst.symmetry;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.geom.Line2D;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.JPanel;
import javax.vecmath.Point3d;
/**
* Panel for graphing polyline profiles
*
* @author Dominik Racek
*/
public class PolylinePanel extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = 500;
private static final int BORDER_GAP = 15;
private static final Color PRIMARY_COLOR = Color.green;
private static final Color SECONDARY_COLOR = Color.blue;
private static final Stroke GRAPH_STROKE = new BasicStroke(3f);
private List<Point3d> primaryPoints;
private List<Point3d> secondaryPoints;
private List<Point3d> primaryMirrorPoints;
private List<Point3d> secondaryMirrorPoints;
private boolean alignProfiles = false;
private double primaryOffsetZ = 0;
private boolean mirrorCuts = false;
private double scale = Double.POSITIVE_INFINITY;
/**
* Comparator for Point3d based on Y value
*
* @author Dominik Racek
*/
public class CompareY implements Comparator<Point3d> {
/**
* Compare two Points3d objects
*/
public int compare(final Point3d a, final Point3d b) {
if (a.y < b.y) {
return -1;
} else if (a.y > b.y) {
return 1;
} else {
return 0;
}
}
}
/**
* Constructor for one face
*/
public PolylinePanel(List<Point3d> values) {
this.primaryPoints = values;
Collections.sort(this.primaryPoints, new CompareY());
}
/**
* Constructor for two faces
*/
public PolylinePanel(List<Point3d> primaryPoints, List<Point3d> secondaryPoints) {
this.primaryPoints = primaryPoints;
this.secondaryPoints = secondaryPoints;
Collections.sort(this.primaryPoints, new CompareY());
Collections.sort(this.secondaryPoints, new CompareY());
}
protected void drawFace(Graphics2D g2, List<Point3d> values, Color faceColor, boolean isPrimary) {
double minZ = Double.POSITIVE_INFINITY;
double maxZ = Double.NEGATIVE_INFINITY;
double minY = Double.POSITIVE_INFINITY;
double maxY = Double.NEGATIVE_INFINITY;
for (int i = 0; i < values.size(); i++) {
if (values.get(i).z < minZ) {
minZ = values.get(i).z;
}
if (values.get(i).z > maxZ) {
maxZ = values.get(i).z;
}
if (values.get(i).y < minY) {
minY = values.get(i).y;
}
if (values.get(i).y > maxY) {
maxY = values.get(i).y;
}
}
//only calculate scale for the first face and use it for the second as well
if (scale == Double.POSITIVE_INFINITY) {
scale = ((double) PREF_H - 2 * BORDER_GAP) / (maxY - minY);
}
//Calculate the offsets
if (mirrorCuts) {
if (secondaryPoints == null) {
//Mirror cuts with single face - center the face
this.primaryOffsetZ = (PREF_W * 0.7) - (maxZ * scale);
offsetZ = this.primaryOffsetZ;
} else {
//Mirror cuts with two faces - separate primary and secondary
offsetZ = isPrimary ? (PREF_W * 0.4) - (maxZ * scale) : (PREF_W * 0.9) - (maxZ * scale);
}
} else {
//No mirror cuts - center all faces
if (isPrimary) {
this.primaryOffsetZ = (PREF_W * 0.7) - (maxZ * scale);
}
offsetZ = this.alignProfiles ? (PREF_W * 0.7) - (maxZ * scale) : this.primaryOffsetZ;
//Draw lines
g2.setColor(faceColor);
g2.setStroke(GRAPH_STROKE);
for (int i = 0; i < values.size() - 1; i++) {
double z1 = (values.get(i).z) * scale + BORDER_GAP + offsetZ;
double y1 = (maxY - values.get(i).y) * scale + BORDER_GAP;
double z2 = (values.get(i + 1).z) * scale + BORDER_GAP + offsetZ;
double y2 = (maxY - values.get(i + 1).y) * scale + BORDER_GAP;
g2.draw(new Line2D.Double(z1, y1, z2, y2));
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
if (mirrorCuts) {
drawFace(g2, primaryPoints, PRIMARY_COLOR, true);
drawFace(g2, primaryMirrorPoints, SECONDARY_COLOR, true);
if (secondaryPoints != null) {
drawFace(g2, secondaryPoints, PRIMARY_COLOR, false);
drawFace(g2, secondaryMirrorPoints, SECONDARY_COLOR, false);
}
} else {
drawFace(g2, primaryPoints, PRIMARY_COLOR, true);
if (secondaryPoints != null) {
drawFace(g2, secondaryPoints, SECONDARY_COLOR, false);
}
}
/**
* Sets primary points and draws them in the panel
*
* @param points primary points
*/
public void setPrimaryPoints(List<Point3d> points) {
this.primaryPoints = points;
Collections.sort(this.primaryPoints, new CompareY());
repaint();
}
/**
* Sets primary mirror points.
* Only draws them if mirrorCuts is checked
*
* @param points primary mirror points
*/
public void setPrimaryMirrorPoints(List<Point3d> points) {
this.primaryMirrorPoints = points;
Collections.sort(this.primaryMirrorPoints, new CompareY());
repaint();
}
/**
* Sets secondary points and draws them in the panel
*
* @param points secondary points
*/
public void setSecondaryPoints(List<Point3d> points) {
this.secondaryPoints = points;
Collections.sort(this.secondaryPoints, new CompareY());
repaint();
}
/**
* Sets secondary mirror points.
* Only draws them if mirrorCuts is checked
*
* @param points secondary mirror points
*/
public void setSecondaryMirrorPoints(List<Point3d> points) {
this.secondaryMirrorPoints = points;
Collections.sort(this.secondaryMirrorPoints, new CompareY());
repaint();
}
/**
* Aligns the drawn faces in the panel
*
* @param align
*/
public void setAlignProfiles(boolean align) {
this.alignProfiles = align;
repaint();
}
/**
* Displays the mirror cuts
*
* @param mirror
*/
public void setMirrorCuts(boolean mirror) {
this.mirrorCuts = mirror;
repaint();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}