From a7831396df3bf52fea5b8fd66d953c6a365594a2 Mon Sep 17 00:00:00 2001 From: Benjamin Culkin Date: Tue, 10 Apr 2018 10:57:21 -0700 Subject: Update --- CSMath/src/CulkinAsssignmentNine.java | 670 ++++++++++++++++++++++++++++++++-- 1 file changed, 631 insertions(+), 39 deletions(-) (limited to 'CSMath') diff --git a/CSMath/src/CulkinAsssignmentNine.java b/CSMath/src/CulkinAsssignmentNine.java index 76af01a..50bbddb 100644 --- a/CSMath/src/CulkinAsssignmentNine.java +++ b/CSMath/src/CulkinAsssignmentNine.java @@ -2,6 +2,7 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dialog.ModalityType; +import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.event.ActionEvent; @@ -15,39 +16,53 @@ import java.util.Map; import java.util.function.Consumer; import javax.swing.BorderFactory; +import javax.swing.BoxLayout; import javax.swing.DefaultListModel; import javax.swing.JButton; +import javax.swing.JColorChooser; import javax.swing.JDialog; import javax.swing.JFormattedTextField; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; import javax.swing.ListCellRenderer; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; import javax.swing.border.BevelBorder; +import javax.swing.border.TitledBorder; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; public class CulkinAsssignmentNine { public final Holder currentCurve; public final Map curveDirectory; - - public CulkinAsssignmentNine() { - Bezier curve = new Bezier(); + public CulkinAsssignmentNine() { curveDirectory = new HashMap<>(); - curveDirectory.put("Default Curve", curve); - + currentCurve = new Holder<>(); - currentCurve.setVal(curve); + currentCurve.setVal(new Bezier()); } public static void main(String[] args) { CulkinAsssignmentNine assign = new CulkinAsssignmentNine(); + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException + | UnsupportedLookAndFeelException e) { + e.printStackTrace(); + } + JFrame fram = assign.setupFrame(); fram.setSize(640, 480); @@ -57,7 +72,7 @@ public class CulkinAsssignmentNine { private JFrame setupFrame() { JFrame fram = new JFrame("Bezier Grapher"); - fram.setLayout(new GridLayout(1, 1)); + fram.setLayout(new BorderLayout()); JPanel canvasPanel = new JPanel(); canvasPanel.setLayout(new GridLayout(1, 1)); @@ -77,12 +92,12 @@ public class CulkinAsssignmentNine { currentCurve.addHolderListener((val) -> { pointModel.clear(); - - for(TDPoint punkt : val.controls) { + + for (TDPoint punkt : val.controls) { pointModel.addElement(punkt); } }); - + JList pointList = new JList<>(pointModel); pointList.setCellRenderer(new TDPointRenderer()); @@ -97,7 +112,7 @@ public class CulkinAsssignmentNine { addPoint.addActionListener(new PointAdder(pointModel, currentCurve, fram)); JButton remPoint = new JButton("Remove Control Point"); - remPoint.addActionListener(new PointRemover(fram, pointList, pointModel)); + remPoint.addActionListener(new PointRemover(fram, pointList, pointModel, currentCurve)); buttonPanel.add(addPoint); buttonPanel.add(remPoint); @@ -107,11 +122,163 @@ public class CulkinAsssignmentNine { JSplitPane main = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, points, canvasPanel); - fram.add(main); + JPanel menuPanel = new JPanel(); + menuPanel.setLayout(new FlowLayout(FlowLayout.LEADING, 5, 1)); + + JPanel editingPanel = new JPanel(); + editingPanel.setLayout(new FlowLayout(FlowLayout.LEADING, 5, 1)); + editingPanel.setBorder(new BevelBorder(BevelBorder.RAISED)); + + JButton editCurveProperties = new JButton("Edit Curve Properties"); + editCurveProperties.addActionListener(new CurveEditor(fram, currentCurve)); + + editingPanel.add(editCurveProperties); + + JPanel destructivePanel = new JPanel(); + destructivePanel.setLayout(new FlowLayout(FlowLayout.LEADING, 5, 1)); + destructivePanel.setBorder(new BevelBorder(BevelBorder.RAISED)); + + JButton clearPoints = new JButton("Clear Points"); + clearPoints.addActionListener((ev) -> { + int confirm = JOptionPane.showConfirmDialog(fram, "Are you sure you want to clear the points?", + "Clear Points", JOptionPane.YES_NO_OPTION); + + if (confirm == JOptionPane.YES_OPTION) { + currentCurve.getVal().controls.clear(); + pointModel.clear(); + } + }); + + JButton resetCurve = new JButton("Reset Curve"); + resetCurve.addActionListener((ev) -> { + int confirm = JOptionPane.showConfirmDialog(fram, "Are you sure you want to reset the curve?", + "Clear Points", JOptionPane.YES_NO_OPTION); + + if (confirm == JOptionPane.YES_OPTION) { + currentCurve.setVal(new Bezier()); + } + }); + + destructivePanel.add(clearPoints); + destructivePanel.add(resetCurve); + + JPanel curvesPanel = new JPanel(); + curvesPanel.setLayout(new FlowLayout(FlowLayout.LEADING, 5, 1)); + curvesPanel.setBorder(new BevelBorder(BevelBorder.RAISED)); + + menuPanel.add(editingPanel); + menuPanel.add(destructivePanel); + menuPanel.add(curvesPanel); + + fram.add(main, BorderLayout.CENTER); + fram.add(menuPanel, BorderLayout.PAGE_START); + return fram; } } +class CurveEditor implements ActionListener { + private Bezier curve; + private JFrame fram; + + public CurveEditor(JFrame fram, Holder currentCurve) { + this.fram = fram; + + curve = currentCurve.getVal(); + + currentCurve.addHolderListener((val) -> { + curve = val; + }); + } + + @Override + public void actionPerformed(ActionEvent ev) { + JDialog dia = new JDialog(fram, "Curve Editor", ModalityType.MODELESS); + dia.setLayout(new BorderLayout()); + + JPanel fields = new JPanel(); + fields.setLayout(new BorderLayout()); + + LabeledInputPanel partsPanel = new LabeledInputPanel("# of Points to Graph", curve.parts); + + JTabbedPane colorPanel = new JTabbedPane(); + colorPanel.setBorder(new TitledBorder(new BevelBorder(BevelBorder.RAISED), "Colors")); + + ColorInputPanel curveColor = new ColorInputPanel(curve.curveColor, "Curve Color"); + ColorInputPanel pointColor = new ColorInputPanel(curve.pointColor, "Point Color"); + ColorInputPanel boxColor = new ColorInputPanel(curve.boxColor, "Bounding Box Color"); + + colorPanel.addTab("Curve Color", curveColor); + colorPanel.addTab("Point Color", pointColor); + colorPanel.addTab("Bounding Box Color", boxColor); + + LabeledInputPanel scalePanel = new LabeledInputPanel("Curve Scaling Multiplier", curve.scale); + + fields.add(partsPanel, BorderLayout.PAGE_START); + fields.add(colorPanel, BorderLayout.CENTER); + fields.add(scalePanel, BorderLayout.PAGE_END); + + JPanel buttons = new JPanel(); + buttons.setLayout(new GridLayout(1, 3)); + + JButton saveButton = new JButton("Save Changes"); + saveButton.addActionListener((aev) -> { + curve.parts = (Integer) partsPanel.field.getValue(); + curve.scale = (Double) scalePanel.field.getValue(); + + curve.curveColor = curveColor.picker.getColor(); + curve.pointColor = pointColor.picker.getColor(); + curve.boxColor = boxColor.picker.getColor(); + }); + + JButton resetButton = new JButton("Reset Changes"); + resetButton.addActionListener((aev) -> { + partsPanel.field.setValue(curve.parts); + scalePanel.field.setValue(curve.scale); + + curveColor.picker.setColor(curve.curveColor); + pointColor.picker.setColor(curve.pointColor); + boxColor.picker.setColor(curve.boxColor); + }); + + JButton cancelButton = new JButton("Cancel Changes"); + cancelButton.addActionListener((aev) -> { + dia.dispose(); + }); + + buttons.add(saveButton); + buttons.add(resetButton); + buttons.add(cancelButton); + + dia.add(fields, BorderLayout.CENTER); + dia.add(buttons, BorderLayout.PAGE_END); + + dia.pack(); + dia.setVisible(true); + } +} + +class ColorInputPanel extends JPanel { + private static final long serialVersionUID = 5201595672794938745L; + + public final JColorChooser picker; + + public ColorInputPanel(String label) { + this(Color.WHITE, label); + } + + public ColorInputPanel(Color init, String label) { + picker = new JColorChooser(init); + + setLayout(new BorderLayout()); + + JLabel lab = new JLabel(label); + + add(lab, BorderLayout.LINE_START); + add(picker, BorderLayout.CENTER); + } +} + class BezierPanel extends JPanel { public final Collection curves; @@ -121,13 +288,13 @@ class BezierPanel extends JPanel { super(); curves = new LinkedList<>(); - + setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); } - + public BezierPanel(Collection curvs) { super(); - + curves = curvs; setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); @@ -155,25 +322,38 @@ class BezierPanel extends JPanel { g.translate(halfWidth, halfHeight); for (Bezier curve : curves) { - g.setColor(Color.RED); - for(TDPoint control : curve.controls) { + if (curve.controls.isEmpty()) + continue; + + { + g.setColor(curve.boxColor); + TDPoint[] ex = curve.extrema(); + + g.drawLine((int) ex[0].x, (int) ex[0].y, (int) ex[1].x, (int) ex[1].y); + g.drawLine((int) ex[1].x, (int) ex[1].y, (int) ex[2].x, (int) ex[2].y); + g.drawLine((int) ex[2].x, (int) ex[2].y, (int) ex[3].x, (int) ex[3].y); + g.drawLine((int) ex[3].x, (int) ex[3].y, (int) ex[0].x, (int) ex[0].y); + } + + g.setColor(curve.pointColor); + for (TDPoint control : curve.controls) { drawCircle(g, control.x, control.y, 6); } - + for (int i = 0; i < curve.parts; i++) { double dT = 1.0 / curve.parts; TDPoint first = curve.scaleEval(dT * i); TDPoint second = curve.scaleEval(dT * (i + 1)); - - g.setColor(curve.col); + + g.setColor(curve.curveColor); g.drawLine((int) first.x, (int) first.y, (int) second.x, (int) second.y); } } } - + private static void drawCircle(Graphics g, double x, double y, int diameter) { - g.fillOval((int)x - diameter/2, (int)y - diameter/2, diameter, diameter); + g.fillOval((int) x - diameter / 2, (int) y - diameter / 2, diameter, diameter); } } @@ -181,10 +361,12 @@ class Bezier { public final List controls; public int parts = 100; - public int scale = 5; + public double scale = 5; + + public Color curveColor = Color.BLACK; + public Color pointColor = Color.RED; + public Color boxColor = Color.GREEN; - public Color col = Color.BLACK; - public Bezier(TDPoint... points) { controls = new ArrayList<>(); @@ -242,6 +424,40 @@ class Bezier { return curves; } + public TDPoint[] extrema() { + TDPoint[] box = new TDPoint[4]; + + double xMin = Double.MAX_VALUE, xMax = Double.MIN_VALUE; + double yMin = Double.MAX_VALUE, yMax = Double.MIN_VALUE; + + for (TDPoint punkt1 : controls) { + TDPoint punkt = punkt1.multiply(scale); + + if (punkt.x < xMin) { + xMin = punkt.x; + } + + if (punkt.x > xMax) { + xMax = punkt.x; + } + + if (punkt.y < yMin) { + yMin = punkt.y; + } + + if (punkt.y > yMax) { + yMax = punkt.y; + } + } + + box[0] = new TDPoint(xMin, yMin); + box[1] = new TDPoint(xMax, yMin); + box[2] = new TDPoint(xMax, yMax); + box[3] = new TDPoint(xMin, yMax); + + return box; + } + @Override public int hashCode() { final int prime = 31; @@ -326,6 +542,53 @@ class TDPoint { public String toString() { return "TDPoint [x=" + x + ", y=" + y + "]"; } + + public TDHPoint toTDHPoint() { + return new TDHPoint(x, y, 1); + } +} + +class TDHPoint extends TDPoint { + public final double z; + + public TDHPoint(double x, double y, double z) { + super(x, y); + + this.z = z; + } + + public TDPoint toTDPoint() { + return new TDPoint(x / z, y / z); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + long temp; + temp = Double.doubleToLongBits(z); + result = prime * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + TDHPoint other = (TDHPoint) obj; + if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z)) + return false; + return true; + } + + @Override + public String toString() { + return "TDHPoint [z=" + z + "]"; + } } final class TDPointRenderer extends JLabel implements ListCellRenderer { @@ -359,10 +622,18 @@ class PointRemover implements ActionListener { private final JList pointList; private final DefaultListModel pointModel; - public PointRemover(JFrame fram, JList pointList, DefaultListModel pointModel) { + private Bezier curve; + + public PointRemover(JFrame fram, JList pointList, DefaultListModel pointModel, + Holder curveHolder) { this.fram = fram; this.pointList = pointList; this.pointModel = pointModel; + + curve = curveHolder.getVal(); + curveHolder.addHolderListener((val) -> { + curve = val; + }); } @Override @@ -377,20 +648,22 @@ class PointRemover implements ActionListener { if (confirmed == JOptionPane.YES_OPTION) { pointModel.remove(selectedIndex); + curve.controls.remove(punkt); } } } class PointAdder implements ActionListener { private final DefaultListModel pointModel; - private Bezier curve; private final JFrame fram; + private Bezier curve; + public PointAdder(DefaultListModel pointModel, Holder curveHolder, JFrame fram) { this.pointModel = pointModel; this.curve = curveHolder.getVal(); this.fram = fram; - + curveHolder.addHolderListener((curv) -> { curve = curv; }); @@ -406,8 +679,8 @@ class PointAdder implements ActionListener { JPanel fields = new JPanel(); fields.setLayout(new GridLayout(2, 1)); - DoubleInputPanel xPanel = new DoubleInputPanel("X Coordinate: "); - DoubleInputPanel yPanel = new DoubleInputPanel("Y Coordinate: "); + LabeledInputPanel xPanel = new LabeledInputPanel("X Coordinate: ", 0.0); + LabeledInputPanel yPanel = new LabeledInputPanel("Y Coordinate: ", 0.0); fields.add(xPanel); fields.add(yPanel); @@ -444,10 +717,10 @@ class PointAdder implements ActionListener { } class AddListener implements ActionListener { - private final DoubleInputPanel xPanel; - private final DoubleInputPanel yPanel; + private final LabeledInputPanel xPanel; + private final LabeledInputPanel yPanel; - public AddListener(DoubleInputPanel xPanel, DoubleInputPanel yPanel) { + public AddListener(LabeledInputPanel xPanel, LabeledInputPanel yPanel) { this.xPanel = xPanel; this.yPanel = yPanel; } @@ -493,18 +766,18 @@ class CanvasRepainter implements ListDataListener { } } -class DoubleInputPanel extends JPanel { +class LabeledInputPanel extends JPanel { private static final long serialVersionUID = 1031310890698539040L; public final JFormattedTextField field; - public DoubleInputPanel(String label) { + public LabeledInputPanel(String label, Object val) { super(); setLayout(new BorderLayout()); JLabel xLabel = new JLabel(label); - field = new JFormattedTextField(0.0); + field = new JFormattedTextField(val); add(xLabel, BorderLayout.LINE_START); add(field, BorderLayout.CENTER); @@ -515,14 +788,14 @@ class Holder { private E val; private final List> listeners; - + public Holder() { listeners = new LinkedList<>(); } public Holder(E val) { this(); - + this.val = val; } @@ -532,7 +805,7 @@ class Holder { public void setVal(E val) { this.val = val; - + for (Consumer listen : listeners) { listen.accept(val); } @@ -541,6 +814,7 @@ class Holder { public void addHolderListener(Consumer listen) { listeners.add(listen); } + @Override public int hashCode() { final int prime = 31; @@ -570,4 +844,322 @@ class Holder { public String toString() { return "Holder [val=" + val + "]"; } +} + +enum TDHTransformType { + TRANSLATE, IDENTITY, SCALE, ROTATION, REFLECTION, SHEAR +} + +@FunctionalInterface +interface TDHTransform { + default TDHTransformType type() { + return TDHTransformType.IDENTITY; + } + + TDHPoint transform(TDHPoint punkt); +} + +class TDHIdentity implements TDHTransform { + @Override + public TDHPoint transform(TDHPoint punkt) { + return punkt; + } + + @Override + public String toString() { + return "TDHIdentity []"; + } +} + +class TDHTranslate implements TDHTransform { + public final double h; + public final double k; + + public TDHTranslate(double h, double k) { + this.h = h; + this.k = k; + } + + @Override + public TDHTransformType type() { + return TDHTransformType.TRANSLATE; + } + + @Override + public TDHPoint transform(TDHPoint punkt) { + double x = punkt.x + (punkt.z * h); + double y = punkt.y + (punkt.z * k); + + return new TDHPoint(x, y, punkt.z); + } +} + +class TDHScale implements TDHTransform { + public final double sx; + public final double sy; + public final double sz; + + public TDHScale(double sx, double sy, double sz) { + this.sx = sx; + this.sy = sy; + this.sz = sz; + } + + @Override + public TDHTransformType type() { + return TDHTransformType.SCALE; + } + + @Override + public TDHPoint transform(TDHPoint punkt) { + double x = punkt.x * sx; + double y = punkt.y * sy; + double z = punkt.z * sz; + + return new TDHPoint(x, y, z); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(sx); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(sy); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(sz); + result = prime * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TDHScale other = (TDHScale) obj; + if (Double.doubleToLongBits(sx) != Double.doubleToLongBits(other.sx)) + return false; + if (Double.doubleToLongBits(sy) != Double.doubleToLongBits(other.sy)) + return false; + if (Double.doubleToLongBits(sz) != Double.doubleToLongBits(other.sz)) + return false; + return true; + } + + @Override + public String toString() { + return "TDHScale [sx=" + sx + ", sy=" + sy + ", sz=" + sz + "]"; + } +} + +class TDHRotation implements TDHTransform { + public final double theta; + + public TDHRotation(double theta) { + super(); + this.theta = theta; + } + + @Override + public TDHPoint transform(TDHPoint punkt) { + double x = (punkt.x * Math.cos(theta)) - (punkt.y * Math.sin(theta)); + double y = (punkt.x * Math.sin(theta)) - (punkt.y * Math.cos(theta)); + + return new TDHPoint(x, y, punkt.z); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(theta); + result = prime * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TDHRotation other = (TDHRotation) obj; + if (Double.doubleToLongBits(theta) != Double.doubleToLongBits(other.theta)) + return false; + return true; + } + + @Override + public String toString() { + return "TDHRotation [theta=" + theta + "]"; + } +} + +class TDHXAxisReflection implements TDHTransform { + @Override + public TDHTransformType type() { + return TDHTransformType.REFLECTION; + } + + @Override + public TDHPoint transform(TDHPoint punkt) { + return new TDHPoint(punkt.x, -punkt.y, punkt.z); + } + + @Override + public String toString() { + return "TDHXAxisReflection []"; + } +} + +class TDHYAxisReflection implements TDHTransform { + @Override + public TDHTransformType type() { + return TDHTransformType.REFLECTION; + } + + @Override + public TDHPoint transform(TDHPoint punkt) { + return new TDHPoint(-punkt.x, punkt.y, punkt.z); + } + + @Override + public String toString() { + return "TDHYAxisReflection []"; + } +} + +class TDHPointRotation extends TDHRotation { + public final double x0; + public final double y0; + + public TDHPointRotation(double theta, double x0, double y0) { + super(theta); + + this.x0 = x0; + this.y0 = y0; + } + + @Override + public TDHTransformType type() { + return TDHTransformType.ROTATION; + } + + @Override + public TDHPoint transform(TDHPoint punkt) { + double x1 = (punkt.x * Math.cos(theta)) - (punkt.y * Math.sin(theta)); + double y1 = (punkt.x * Math.sin(theta)) - (punkt.y * Math.cos(theta)); + + double x2 = (-x0 * Math.cos(theta)) + (y0 * Math.sin(theta)) + x0; + double y2 = (-x0 * Math.sin(theta)) - (y0 * Math.cos(theta)) + y0; + + double x = x1 + (punkt.z * x2); + double y = y1 + (punkt.z * y2); + + return new TDHPoint(x, y, punkt.z); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + long temp; + temp = Double.doubleToLongBits(x0); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(y0); + result = prime * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + TDHPointRotation other = (TDHPointRotation) obj; + if (Double.doubleToLongBits(x0) != Double.doubleToLongBits(other.x0)) + return false; + if (Double.doubleToLongBits(y0) != Double.doubleToLongBits(other.y0)) + return false; + return true; + } + + @Override + public String toString() { + return "TDHPointRotation [x0=" + x0 + ", y0=" + y0 + "]"; + } +} + +class TDHLineReflection implements TDHTransform { + public final double a; + public final double b; + public final double c; + + public TDHLineReflection(double a, double b, double c) { + this.a = a; + this.b = b; + this.c = c; + } + + @Override + public TDHTransformType type() { + return TDHTransformType.REFLECTION; + } + + @Override + public TDHPoint transform(TDHPoint punkt) { + double x = 0; + double y = 0; + double z = 0; + + return new TDHPoint(x, y, z); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(a); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(b); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(c); + result = prime * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TDHLineReflection other = (TDHLineReflection) obj; + if (Double.doubleToLongBits(a) != Double.doubleToLongBits(other.a)) + return false; + if (Double.doubleToLongBits(b) != Double.doubleToLongBits(other.b)) + return false; + if (Double.doubleToLongBits(c) != Double.doubleToLongBits(other.c)) + return false; + return true; + } + + @Override + public String toString() { + return "TDHLineReflection [a=" + a + ", b=" + b + ", c=" + c + "]"; + } } \ No newline at end of file -- cgit v1.2.3