diff options
Diffstat (limited to 'CSMath/src/CulkinAsssignmentNine.java')
| -rw-r--r-- | CSMath/src/CulkinAsssignmentNine.java | 706 |
1 files changed, 657 insertions, 49 deletions
diff --git a/CSMath/src/CulkinAsssignmentNine.java b/CSMath/src/CulkinAsssignmentNine.java index 4626cc8..bc81796 100644 --- a/CSMath/src/CulkinAsssignmentNine.java +++ b/CSMath/src/CulkinAsssignmentNine.java @@ -8,7 +8,6 @@ import java.awt.GridLayout; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
@@ -20,6 +19,7 @@ import javax.swing.BorderFactory; import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JColorChooser;
+import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
@@ -49,6 +49,7 @@ public class CulkinAsssignmentNine { * The current bezier curve.
*/
public final Holder<Bezier> currentCurve;
+
/**
* The directory of all bezier curves.
*/
@@ -75,6 +76,9 @@ public class CulkinAsssignmentNine { public static void main(String[] args) {
CulkinAsssignmentNine assign = new CulkinAsssignmentNine();
+ /*
+ * Use the native look and feel.
+ */
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
@@ -84,11 +88,17 @@ public class CulkinAsssignmentNine { JFrame fram = assign.setupFrame();
+ /*
+ * Display the GUI.
+ */
fram.setSize(640, 480);
fram.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
fram.setVisible(true);
}
+ /*
+ * Setup the main JFrame
+ */
private JFrame setupFrame() {
JFrame fram = new JFrame("Bezier Grapher");
fram.setLayout(new BorderLayout());
@@ -107,8 +117,15 @@ public class CulkinAsssignmentNine { listPanel.setLayout(new GridLayout(1, 1));
DefaultListModel<TDPoint> pointModel = new DefaultListModel<>();
+
+ /*
+ * Repaint the canvas whenever the list changes.
+ */
pointModel.addListDataListener(new CanvasRepainter(canvas));
+ /*
+ * Update the list whenever the curve changes.
+ */
currentCurve.addHolderListener((val) -> {
pointModel.clear();
@@ -118,6 +135,10 @@ public class CulkinAsssignmentNine { });
JList<TDPoint> pointList = new JList<>(pointModel);
+
+ /*
+ * Use special point renderer.
+ */
pointList.setCellRenderer(new TDPointRenderer());
JScrollPane listScroller = new JScrollPane(pointList);
@@ -127,6 +148,9 @@ public class CulkinAsssignmentNine { JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1, 2));
+ /*
+ * Setup action buttons.
+ */
JButton addPoint = new JButton("Add Control Points...");
addPoint.addActionListener(new PointAdder(pointModel, currentCurve, fram));
@@ -157,6 +181,9 @@ public class CulkinAsssignmentNine { destructivePanel.setLayout(new FlowLayout(FlowLayout.LEADING, 5, 1));
destructivePanel.setBorder(new BevelBorder(BevelBorder.RAISED));
+ /*
+ * Clear all curve points.
+ */
JButton clearPoints = new JButton("Clear Points");
clearPoints.addActionListener((ev) -> {
int confirm = JOptionPane.showConfirmDialog(fram, "Are you sure you want to clear the points?",
@@ -168,6 +195,9 @@ public class CulkinAsssignmentNine { }
});
+ /*
+ * Reset to use new curve.
+ */
JButton resetCurve = new JButton("Reset Curve");
resetCurve.addActionListener((ev) -> {
int confirm = JOptionPane.showConfirmDialog(fram, "Are you sure you want to reset the curve?",
@@ -175,9 +205,11 @@ public class CulkinAsssignmentNine { if (confirm == JOptionPane.YES_OPTION) {
currentCurve.getVal().controls.clear();
-
+
currentCurve.setVal(new Bezier());
-
+
+ curveDirectory.put("Default", currentCurve.getVal());
+
canvas.repaint();
}
});
@@ -185,13 +217,16 @@ public class CulkinAsssignmentNine { destructivePanel.add(clearPoints);
destructivePanel.add(resetCurve);
+ /*
+ * This isn't implemented yet.
+ */
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);
+ // menuPanel.add(curvesPanel);
fram.add(main, BorderLayout.CENTER);
fram.add(menuPanel, BorderLayout.PAGE_START);
@@ -200,6 +235,9 @@ public class CulkinAsssignmentNine { }
}
+/*
+ * Do editing of curve properties.
+ */
class CurveEditor implements ActionListener {
private Bezier curve;
private JFrame fram;
@@ -211,6 +249,9 @@ class CurveEditor implements ActionListener { curve = currentCurve.getVal();
+ /*
+ * Set the curve to the right one.
+ */
currentCurve.addHolderListener((val) -> {
curve = val;
});
@@ -224,20 +265,20 @@ class CurveEditor implements ActionListener { JPanel fields = new JPanel();
fields.setLayout(new BorderLayout());
- LabeledInputPanel partsPanel = new LabeledInputPanel("# of Points to Graph", curve.parts);
+ LabeledInputPanel partsPanel = new LabeledInputPanel("# of Points to Graph", curve.data.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");
+ ColorInputPanel curveColor = new ColorInputPanel(curve.data.curveColor, "Curve Color");
+ ColorInputPanel pointColor = new ColorInputPanel(curve.data.pointColor, "Point Color");
+ ColorInputPanel boxColor = new ColorInputPanel(curve.data.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);
+ LabeledInputPanel scalePanel = new LabeledInputPanel("Curve Scaling Multiplier", curve.data.scale);
fields.add(partsPanel, BorderLayout.PAGE_START);
fields.add(colorPanel, BorderLayout.CENTER);
@@ -246,26 +287,32 @@ class CurveEditor implements ActionListener { JPanel buttons = new JPanel();
buttons.setLayout(new GridLayout(1, 3));
+ /*
+ * Persist changes to curve.
+ */
JButton saveButton = new JButton("Save Changes");
saveButton.addActionListener((aev) -> {
- curve.parts = (Integer) partsPanel.field.getValue();
- curve.scale = (Double) scalePanel.field.getValue();
+ curve.data.parts = (Integer) partsPanel.field.getValue();
+ curve.data.scale = (Double) scalePanel.field.getValue();
- curve.curveColor = curveColor.picker.getColor();
- curve.pointColor = pointColor.picker.getColor();
- curve.boxColor = boxColor.picker.getColor();
+ curve.data.curveColor = curveColor.picker.getColor();
+ curve.data.pointColor = pointColor.picker.getColor();
+ curve.data.boxColor = boxColor.picker.getColor();
canvas.repaint();
});
+ /*
+ * Reset fields to match curve.
+ */
JButton resetButton = new JButton("Reset Changes");
resetButton.addActionListener((aev) -> {
- partsPanel.field.setValue(curve.parts);
- scalePanel.field.setValue(curve.scale);
+ partsPanel.field.setValue(curve.data.parts);
+ scalePanel.field.setValue(curve.data.scale);
- curveColor.picker.setColor(curve.curveColor);
- pointColor.picker.setColor(curve.pointColor);
- boxColor.picker.setColor(curve.boxColor);
+ curveColor.picker.setColor(curve.data.curveColor);
+ pointColor.picker.setColor(curve.data.pointColor);
+ boxColor.picker.setColor(curve.data.boxColor);
});
JButton cancelButton = new JButton("Cancel Changes");
@@ -285,6 +332,9 @@ class CurveEditor implements ActionListener { }
}
+/*
+ * Panel for inputting colors.
+ */
class ColorInputPanel extends JPanel {
private static final long serialVersionUID = 5201595672794938745L;
@@ -306,6 +356,9 @@ class ColorInputPanel extends JPanel { }
}
+/*
+ * Panel that graphs a set of bezier curves.
+ */
class BezierPanel extends JPanel {
public final Collection<Bezier> curves;
@@ -339,22 +392,37 @@ class BezierPanel extends JPanel { g.setColor(Color.WHITE);
+ /*
+ * Draw background
+ */
g.fillRect(0, 0, ourWidth, ourHeight);
g.setColor(Color.BLUE);
+ /*
+ * Draw coordinate grid.
+ */
g.drawLine(halfWidth, 0, halfWidth, ourHeight);
g.drawLine(0, halfHeight, ourWidth, halfHeight);
+ /*
+ * Transform to place points at center of grid w/ right orientation.
+ */
TDHTransform translate = new TDHCombination(new TDHXAxisReflection(), new TDHTranslate(halfWidth, halfHeight));
for (Bezier curve : curves) {
+ /*
+ * Skip curves with no points.
+ */
if (curve.controls.isEmpty()) {
continue;
}
{
- g.setColor(curve.boxColor);
+ /*
+ * Draw curve bounding box.
+ */
+ g.setColor(curve.data.boxColor);
TDPoint[] ex = curve.extrema(translate);
g.drawLine((int) ex[0].x, (int) ex[0].y, (int) ex[1].x, (int) ex[1].y);
@@ -363,18 +431,24 @@ class BezierPanel extends JPanel { g.drawLine((int) ex[3].x, (int) ex[3].y, (int) ex[0].x, (int) ex[0].y);
}
- g.setColor(curve.pointColor);
+ g.setColor(curve.data.pointColor);
for (TDPoint control : curve.controls) {
- TDHPoint translatedPoint = translate.transform(control.multiply(curve.scale).toTDHPoint());
+ /*
+ * Draw curve points.
+ */
+ TDHPoint translatedPoint = translate.transform(control.multiply(curve.data.scale).toTDHPoint());
control = translatedPoint.toTDPoint();
drawCircle(g, control.x, control.y, 6);
}
- g.setColor(curve.curveColor);
- for (int i = 0; i < curve.parts; i++) {
- double dT = 1.0 / curve.parts;
+ g.setColor(curve.data.curveColor);
+ for (int i = 0; i < curve.data.parts; i++) {
+ /*
+ * Draw curve itself.
+ */
+ double dT = 1.0 / curve.data.parts;
TDPoint firt = curve.scaleEval(dT * i);
TDPoint secod = curve.scaleEval(dT * (i + 1));
@@ -387,22 +461,37 @@ class BezierPanel extends JPanel { }
}
+ /*
+ * Draw a circle of a given diameter at a point.
+ */
private static void drawCircle(Graphics g, double x, double y, int diameter) {
g.fillOval((int) x - diameter / 2, (int) y - diameter / 2, diameter, diameter);
}
}
+/**
+ * Represents a bezier curve.
+ */
class Bezier {
+ /**
+ * The control points of the curve.
+ */
public final List<TDPoint> controls;
- public int parts = 100;
- public double scale = 5;
-
- public Color curveColor = Color.BLACK;
- public Color pointColor = Color.RED;
- public Color boxColor = Color.GREEN;
+ /**
+ * The display properties for the curve.
+ */
+ public BezierProperties data;
+ /**
+ * Create a new bezier curve from a set of control points.
+ *
+ * @param points
+ * The control points to use.
+ */
public Bezier(TDPoint... points) {
+ data = new BezierProperties();
+
controls = new ArrayList<>();
for (TDPoint punkt : points) {
@@ -410,10 +499,23 @@ class Bezier { }
}
+ /**
+ * Do a scaled evaluation of the curve.
+ *
+ * @param t
+ * The value to evaluate at.
+ * @return The point on the curve, scaled by the curves scaling factor.
+ */
public TDPoint scaleEval(double t) {
- return eval(t).multiply(scale);
+ return eval(t).multiply(data.scale);
}
+ /**
+ * Do a scaled evaluation of the curve.
+ *
+ * @param t
+ * The value to evaluate at.
+ */
public TDPoint eval(double t) {
if (controls.isEmpty())
return new TDPoint(0, 0);
@@ -423,24 +525,49 @@ class Bezier { return punkt;
}
+ /*
+ * Recursive evaluation of bezier curve.
+ */
private TDPoint evalIntern(double t, int j, int k) {
+ /*
+ * Base case.
+ */
if (j <= 0) {
return controls.get(k);
}
+ /*
+ * Get the two component points.
+ */
TDPoint l = evalIntern(t, j - 1, k);
TDPoint r = evalIntern(t, j - 1, k + 1);
+ /*
+ * Adjust them by parameter value
+ */
l = l.multiply(1 - t);
r = r.multiply(t);
+ /*
+ * Give back their sum
+ */
return TDPoint.add(l, r);
}
+ /**
+ * Split a curve into two curves at a specific point.
+ *
+ * @param t
+ * The point to split the curve at.
+ * @return The two curves, split at that point.
+ */
public Bezier[] decompose(double t) {
Bezier[] curves = new Bezier[2];
{
+ /*
+ * Get the first curve.
+ */
TDPoint[] points = new TDPoint[controls.size()];
for (int i = 0; i < points.length; i++) {
points[i] = evalIntern(t, i, 0);
@@ -449,6 +576,9 @@ class Bezier { }
{
+ /*
+ * Get the second curve.
+ */
TDPoint[] points = new TDPoint[controls.size()];
for (int i = 0; i < points.length; i++) {
points[i] = evalIntern(t, (points.length - 1) - i, i);
@@ -459,10 +589,22 @@ class Bezier { return curves;
}
+ /**
+ * Get the bounding box for this curves control points.
+ *
+ * @return The bounding box for the control points.
+ */
public TDPoint[] extrema() {
return extrema(new TDHIdentity());
}
+ /**
+ * Get the bounding box for a transformed version of this curves control points.
+ *
+ * @param transform
+ * The transform to apply to the control points.
+ * @return The bounding box for the transformed control points.
+ */
public TDPoint[] extrema(TDHTransform transform) {
TDPoint[] box = new TDPoint[4];
@@ -470,27 +612,36 @@ class Bezier { double yMin = Double.MAX_VALUE, yMax = Double.MIN_VALUE;
for (TDPoint punkt1 : controls) {
- TDPoint punkt = punkt1.multiply(scale);
-
+ /*
+ * Get transformed point
+ */
+ TDPoint punkt = punkt1.multiply(data.scale);
punkt = transform.transform(punkt.toTDHPoint()).toTDPoint();
+ /*
+ * Set min/max x vals
+ */
if (punkt.x < xMin) {
xMin = punkt.x;
}
-
if (punkt.x > xMax) {
xMax = punkt.x;
}
+ /*
+ * Set min/max y vals
+ */
if (punkt.y < yMin) {
yMin = punkt.y;
}
-
if (punkt.y > yMax) {
yMax = punkt.y;
}
}
+ /*
+ * Create returned points.
+ */
box[0] = new TDPoint(xMin, yMin);
box[1] = new TDPoint(xMax, yMin);
box[2] = new TDPoint(xMax, yMax);
@@ -530,23 +681,69 @@ class Bezier { }
}
+/**
+ * Represents a two-dimensional point.
+ *
+ * @author bjculkin
+ *
+ */
class TDPoint {
+ /**
+ * The x coordinate.
+ */
public final double x;
+
+ /**
+ * The y coordinate.
+ */
public final double y;
+ /**
+ * Create a new two-dimensional point.
+ *
+ * @param x
+ * The x coordinate.
+ * @param y
+ * The y coordinate.
+ */
public TDPoint(double x, double y) {
this.x = x;
this.y = y;
}
+ /**
+ * Create a new two-dimensional point.
+ *
+ * @param x
+ * The x coordinate.
+ * @param y
+ * The y coordinate.
+ * @return A point with those coordinates.
+ */
public static TDPoint p2(double x, double y) {
return new TDPoint(x, y);
}
+ /**
+ * Return a new scaled point.
+ *
+ * @param s
+ * The amount to scale by.
+ * @return A point scaled by the specified amount.
+ */
public TDPoint multiply(double s) {
return p2(x * s, y * s);
}
+ /**
+ * Add two points together.
+ *
+ * @param p1
+ * The first point to add.
+ * @param p2
+ * The second point to add.
+ * @return The sum of the points.
+ */
public static TDPoint add(TDPoint p1, TDPoint p2) {
return p2(p1.x + p2.x, p1.y + p2.y);
}
@@ -584,21 +781,67 @@ class TDPoint { return "TDPoint [x=" + x + ", y=" + y + "]";
}
+ /**
+ * Convert this point to a two-dimensional homogeneous point.
+ *
+ * @return A homogeneous version of this point.
+ */
public TDHPoint toTDHPoint() {
- return new TDHPoint(x, y, 1);
+ return new TDHPoint(x, y);
}
}
+/**
+ * A two-dimensional homogeneous point.
+ *
+ * @author bjculkin
+ *
+ */
class TDHPoint extends TDPoint {
+ /**
+ * The homogeneous coordinate for the point.
+ */
public final double z;
+ /**
+ * Create a new two-dimensional homogeneous point.
+ *
+ * @param x
+ * The x coordinate.
+ * @param y
+ * The y coordinate.
+ * @param z
+ * The homogeneous coordinate.
+ */
public TDHPoint(double x, double y, double z) {
super(x, y);
this.z = z;
}
+ /**
+ * Create a new two-dimensional homogeneous point.
+ *
+ * The homogeneous coordinate is set to 1.
+ *
+ * @param x
+ * The x coordinate.
+ * @param y
+ * The y coordinate.
+ */
+ public TDHPoint(double x, double y) {
+ this(x, y, 1);
+ }
+
+ /**
+ * Convert this point to a plain two-dimensional point.
+ *
+ * @return A two-dimensional version of this point.
+ */
public TDPoint toTDPoint() {
+ /*
+ * Convert back down by dividing each coordinate by the homogeneous value.
+ */
return new TDPoint(x / z, y / z);
}
@@ -628,13 +871,22 @@ class TDHPoint extends TDPoint { @Override
public String toString() {
- return "TDHPoint [z=" + z + "]";
+ return "TDHPoint [z=" + z + ", x=" + x + ", y=" + y + "]";
}
}
+/**
+ * Renderer for TDPoints in JLists.
+ *
+ * @author bjculkin
+ *
+ */
final class TDPointRenderer extends JLabel implements ListCellRenderer<TDPoint> {
private static final long serialVersionUID = 629873168260730449L;
+ /**
+ * Create a new TDPoint renderer.
+ */
public TDPointRenderer() {
setOpaque(true);
setHorizontalAlignment(CENTER);
@@ -658,6 +910,12 @@ final class TDPointRenderer extends JLabel implements ListCellRenderer<TDPoint> }
}
+/**
+ * Listener to remove points from a bezier curve.
+ *
+ * @author bjculkin
+ *
+ */
class PointRemover implements ActionListener {
private final JFrame fram;
private final JList<TDPoint> pointList;
@@ -665,12 +923,27 @@ class PointRemover implements ActionListener { private Bezier curve;
+ /**
+ * Create a new listener to remove points from a bezier curve.
+ *
+ * @param fram
+ * The frame to use.
+ * @param pointList
+ * The list the points are stored in.
+ * @param pointModel
+ * The data backing the list.
+ * @param curveHolder
+ * The current curve.
+ */
public PointRemover(JFrame fram, JList<TDPoint> pointList, DefaultListModel<TDPoint> pointModel,
Holder<Bezier> curveHolder) {
this.fram = fram;
this.pointList = pointList;
this.pointModel = pointModel;
+ /*
+ * Change our curve if the current one changes.
+ */
curve = curveHolder.getVal();
curveHolder.addHolderListener((val) -> {
curve = val;
@@ -680,12 +953,13 @@ class PointRemover implements ActionListener { @Override
public void actionPerformed(ActionEvent ev) {
int selectedIndex = pointList.getSelectedIndex();
-
+
/*
* Nothing selected.
*/
- if(selectedIndex == -1) return;
-
+ if (selectedIndex == -1)
+ return;
+
TDPoint punkt = pointModel.get(selectedIndex);
String msg = String.format("Do you want to remove the control point (%.2f, %.2f)?", punkt.x, punkt.y);
@@ -699,17 +973,36 @@ class PointRemover implements ActionListener { }
}
+/**
+ * Listener for adding points to a bezier curve.
+ *
+ * @author bjculkin
+ *
+ */
class PointAdder implements ActionListener {
private final DefaultListModel<TDPoint> pointModel;
private final JFrame fram;
private Bezier curve;
+ /**
+ * Create a listener that adds points to a bezier curve.
+ *
+ * @param pointModel
+ * The place to store points.
+ * @param curveHolder
+ * The curve to add to.
+ * @param fram
+ * The frame to use.
+ */
public PointAdder(DefaultListModel<TDPoint> pointModel, Holder<Bezier> curveHolder, JFrame fram) {
this.pointModel = pointModel;
this.curve = curveHolder.getVal();
this.fram = fram;
+ /*
+ * Change our curve if the current one changes.
+ */
curveHolder.addHolderListener((curv) -> {
curve = curv;
});
@@ -747,10 +1040,12 @@ class PointAdder implements ActionListener { buttons.add(add);
buttons.add(cancel);
+ /*
+ * Change focus to each field on action
+ */
xPanel.field.addActionListener((aev) -> {
yPanel.field.requestFocusInWindow();
});
-
yPanel.field.addActionListener((aev) -> {
addListener.actionPerformed(null);
});
@@ -762,6 +1057,12 @@ class PointAdder implements ActionListener { dia.setVisible(true);
}
+ /**
+ * Listener for adding points to a curve.
+ *
+ * @author bjculkin
+ *
+ */
class AddListener implements ActionListener {
private final LabeledInputPanel xPanel;
private final LabeledInputPanel yPanel;
@@ -773,6 +1074,9 @@ class PointAdder implements ActionListener { @Override
public void actionPerformed(ActionEvent aev) {
+ /*
+ * Add point to curve.
+ */
double xVal = (Double) xPanel.field.getValue();
double yVal = (Double) yPanel.field.getValue();
@@ -781,6 +1085,9 @@ class PointAdder implements ActionListener { pointModel.addElement(punkt);
curve.controls.add(punkt);
+ /*
+ * Reset field values.
+ */
xPanel.field.setValue(0.0);
yPanel.field.setValue(0.0);
@@ -789,34 +1096,63 @@ class PointAdder implements ActionListener { }
}
+/**
+ * Listener to repaint a component whenever a list changes.
+ *
+ * @author bjculkin
+ *
+ */
class CanvasRepainter implements ListDataListener {
- private final BezierPanel canvas;
+ private final JComponent comp;
- public CanvasRepainter(BezierPanel canvas) {
- this.canvas = canvas;
+ /**
+ * Create a new repaint listener.
+ *
+ * @param canvas
+ * The component to repaint.
+ */
+ public CanvasRepainter(JComponent canvas) {
+ this.comp = canvas;
}
@Override
public void intervalRemoved(ListDataEvent e) {
- canvas.repaint();
+ comp.repaint();
}
@Override
public void intervalAdded(ListDataEvent e) {
- canvas.repaint();
+ comp.repaint();
}
@Override
public void contentsChanged(ListDataEvent e) {
- canvas.repaint();
+ comp.repaint();
}
}
+/**
+ * A component for getting formatted input with a label.
+ *
+ * @author bjculkin
+ *
+ */
class LabeledInputPanel extends JPanel {
private static final long serialVersionUID = 1031310890698539040L;
+ /**
+ * The field input is stored in.
+ */
public final JFormattedTextField field;
+ /**
+ * Create a new labeled input component.
+ *
+ * @param label
+ * The label for the component.
+ * @param val
+ * The initial value for the field.
+ */
public LabeledInputPanel(String label, Object val) {
super();
setLayout(new BorderLayout());
@@ -830,33 +1166,78 @@ class LabeledInputPanel extends JPanel { }
}
+/**
+ * Dummy class for holding a value, and being notified when it changes.
+ *
+ * Essentially a pointer with change notifications.
+ *
+ * @author bjculkin
+ *
+ * @param <E>
+ * The type of held value.
+ */
class Holder<E> {
+ /*
+ * The held value.
+ */
private E val;
+ /*
+ * The listeners to notify.
+ */
private final List<Consumer<E>> listeners;
+ /**
+ * Create a new holder holding nothing.
+ */
public Holder() {
listeners = new LinkedList<>();
}
+ /**
+ * Create a new holder holding a specific value.
+ *
+ * @param val
+ * The value being held.
+ */
public Holder(E val) {
this();
this.val = val;
}
+ /**
+ * Get the contained value.
+ *
+ * @return The contained value.
+ */
public E getVal() {
return val;
}
+ /**
+ * Set the contained value, and notify listeners.
+ *
+ * @param val
+ * The new value.
+ */
public void setVal(E val) {
this.val = val;
+ /*
+ * Notify listeners.
+ */
for (Consumer<E> listen : listeners) {
listen.accept(val);
}
}
+ /**
+ * Add a listener.
+ *
+ * @param listen
+ * The listener to add.
+ */
public void addHolderListener(Consumer<E> listen) {
listeners.add(listen);
}
@@ -892,27 +1273,104 @@ class Holder<E> { }
}
+/**
+ * Types of transform to apply to TDHPoints.
+ *
+ * @author bjculkin
+ *
+ */
enum TDHTransformType {
- TRANSLATE, IDENTITY, SCALE, ROTATION, REFLECTION, SHEAR, COMBINATION, MATRIX
+ /**
+ * Coordinate translation.
+ */
+ TRANSLATE,
+ /**
+ * Do nothing transform.
+ */
+ IDENTITY,
+ /**
+ * Coordinate scaling.
+ */
+ SCALE,
+ /**
+ * Coordinate rotation.
+ */
+ ROTATION,
+ /**
+ * Coordinate reflection.
+ */
+ REFLECTION,
+ /**
+ * Coordinate shearing.
+ */
+ SHEAR,
+ /**
+ * Multiple transformations.
+ */
+ COMBINATION,
+ /**
+ * Arbitrary matrix transformation.
+ */
+ MATRIX
}
+/**
+ * Transformation applicable to TDHPoints.
+ *
+ * @author bjculkin
+ *
+ */
@FunctionalInterface
interface TDHTransform {
+ /**
+ * Get the type of this transform.
+ *
+ * Unknown transformations are assumed to be identity transforms.
+ *
+ * @return The type of this transform.
+ */
default TDHTransformType type() {
return TDHTransformType.IDENTITY;
}
+ /**
+ * Get the matrix representation of the transform.
+ *
+ * Unknown transformations are assumed to be identity transforms.
+ *
+ * @return The matrix representation of the transform.
+ */
default double[][] matrix() {
return new double[][] { new double[] { 1, 0, 0 }, new double[] { 0, 1, 0 }, new double[] { 0, 0, 1 } };
}
+ /**
+ * Get the inverse of the transform.
+ *
+ * Unknown transformations are assumed to be identity transforms.
+ *
+ * @return The inverse the transform.
+ */
default TDHTransform invert() {
return new TDHIdentity();
}
+ /**
+ * Apply the transform to a point.
+ *
+ * @param punkt
+ * The point to transform.
+ * @return A transformed version of the point.
+ */
TDHPoint transform(TDHPoint punkt);
}
+/**
+ * A transform that does nothing.
+ *
+ * @author bjculkin
+ *
+ */
class TDHIdentity implements TDHTransform {
@Override
public TDHPoint transform(TDHPoint punkt) {
@@ -925,10 +1383,30 @@ class TDHIdentity implements TDHTransform { }
}
+/**
+ * A transform that does coordinate translation.
+ *
+ * @author bjculkin
+ *
+ */
class TDHTranslate implements TDHTransform {
+ /**
+ * The amount to translate the x-coordinate by.
+ */
public final double h;
+ /**
+ * The amount to translate the y-coordinate by.
+ */
public final double k;
+ /**
+ * Create a new translation transform.
+ *
+ * @param h
+ * The amount to translate x by.
+ * @param k
+ * The amount to translate y by.
+ */
public TDHTranslate(double h, double k) {
this.h = h;
this.k = k;
@@ -991,11 +1469,60 @@ class TDHTranslate implements TDHTransform { }
}
+/**
+ * Transform that does coordinate scaling.
+ *
+ * @author bjculkin
+ *
+ */
class TDHScale implements TDHTransform {
+ /**
+ * Amount to scale x by.
+ */
public final double sx;
+ /**
+ * Amount to scale y by.
+ */
public final double sy;
+ /**
+ * Amount to scale the homogeneous coordinate by.
+ */
public final double sz;
+ /**
+ * Create a new scaling that scales each coordinate by an equal amount
+ *
+ * @param factor
+ * The amount to scale the coordinates by.
+ */
+ public TDHScale(double factor) {
+ this(factor, factor);
+ }
+
+ /**
+ * Create a new scaling that scales each coordinate separately.
+ *
+ * @param sx
+ * The amount to scale x by.
+ * @param sy
+ * The amount to scale y by.
+ */
+ public TDHScale(double sx, double sy) {
+ this(sx, sy, 1);
+ }
+
+ /**
+ * Create a new scaling that scales each coordinate separately.
+ *
+ * Includes the homogeneous coordinate.
+ *
+ * @param sx
+ * The amount to scale x by.
+ * @param sy
+ * The amount to scale y by.
+ * @param sz
+ * The amount to scale the homogeneous coordinate by.
+ */
public TDHScale(double sx, double sy, double sz) {
this.sx = sx;
this.sy = sy;
@@ -1429,4 +1956,85 @@ class TDHCombination implements TDHTransform { public String toString() {
return "TDHCombination [forms=" + forms + "]";
}
+}
+
+class BezierProperties {
+ /**
+ * The number of separate points to graph from the curve.
+ */
+ public int parts = 100;
+
+ /**
+ * The multiplier to apply to coordinates.
+ */
+ public double scale = 5;
+
+ /**
+ * The colors for varying parts of the curve.
+ */
+ public Color curveColor = Color.BLACK;
+ public Color pointColor = Color.RED;
+ public Color boxColor = Color.GREEN;
+
+ public BezierProperties() {
+ }
+
+ public BezierProperties(int parts, double scale, Color curveColor, Color pointColor, Color boxColor) {
+ this.parts = parts;
+ this.scale = scale;
+ this.curveColor = curveColor;
+ this.pointColor = pointColor;
+ this.boxColor = boxColor;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((boxColor == null) ? 0 : boxColor.hashCode());
+ result = prime * result + ((curveColor == null) ? 0 : curveColor.hashCode());
+ result = prime * result + parts;
+ result = prime * result + ((pointColor == null) ? 0 : pointColor.hashCode());
+ long temp;
+ temp = Double.doubleToLongBits(scale);
+ 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;
+ BezierProperties other = (BezierProperties) obj;
+ if (boxColor == null) {
+ if (other.boxColor != null)
+ return false;
+ } else if (!boxColor.equals(other.boxColor))
+ return false;
+ if (curveColor == null) {
+ if (other.curveColor != null)
+ return false;
+ } else if (!curveColor.equals(other.curveColor))
+ return false;
+ if (parts != other.parts)
+ return false;
+ if (pointColor == null) {
+ if (other.pointColor != null)
+ return false;
+ } else if (!pointColor.equals(other.pointColor))
+ return false;
+ if (Double.doubleToLongBits(scale) != Double.doubleToLongBits(other.scale))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "BezierProperties [parts=" + parts + ", scale=" + scale + ", curveColor=" + curveColor + ", pointColor="
+ + pointColor + ", boxColor=" + boxColor + "]";
+ }
}
\ No newline at end of file |
