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; double offsetZ = 0; 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); } }