summaryrefslogtreecommitdiff
path: root/CSMath/src/bezier/geom
diff options
context:
space:
mode:
Diffstat (limited to 'CSMath/src/bezier/geom')
-rw-r--r--CSMath/src/bezier/geom/Bezier.java219
-rw-r--r--CSMath/src/bezier/geom/BezierProperties.java84
-rw-r--r--CSMath/src/bezier/geom/Matrix.java55
-rw-r--r--CSMath/src/bezier/geom/TDHPoint.java85
-rw-r--r--CSMath/src/bezier/geom/TDPoint.java111
5 files changed, 554 insertions, 0 deletions
diff --git a/CSMath/src/bezier/geom/Bezier.java b/CSMath/src/bezier/geom/Bezier.java
new file mode 100644
index 0000000..46f1476
--- /dev/null
+++ b/CSMath/src/bezier/geom/Bezier.java
@@ -0,0 +1,219 @@
+package bezier.geom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import bezier.transforms.TDHIdentity;
+import bezier.transforms.TDHTransform;
+
+/**
+ * Represents a bezier curve.
+ */
+public class Bezier {
+ /**
+ * The control points of the curve.
+ */
+ public final List<TDPoint> controls;
+
+ /**
+ * 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) {
+ controls.add(punkt);
+ }
+ }
+
+ /**
+ * 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(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);
+
+ TDPoint punkt = evalIntern(t, controls.size() - 1, 0);
+
+ 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);
+ }
+ curves[0] = new Bezier(points);
+ }
+
+ {
+ /*
+ * 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);
+ }
+ curves[1] = new Bezier(points);
+ }
+
+ 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];
+
+ double xMin = Double.MAX_VALUE, xMax = Double.MIN_VALUE;
+ double yMin = Double.MAX_VALUE, yMax = Double.MIN_VALUE;
+
+ for (TDPoint punkt1 : controls) {
+ /*
+ * 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);
+ box[3] = new TDPoint(xMin, yMax);
+
+ return box;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((controls == null) ? 0 : controls.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Bezier other = (Bezier) obj;
+ if (controls == null) {
+ if (other.controls != null)
+ return false;
+ } else if (!controls.equals(other.controls))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Bezier [controls=%s]", controls);
+ }
+} \ No newline at end of file
diff --git a/CSMath/src/bezier/geom/BezierProperties.java b/CSMath/src/bezier/geom/BezierProperties.java
new file mode 100644
index 0000000..1b5443d
--- /dev/null
+++ b/CSMath/src/bezier/geom/BezierProperties.java
@@ -0,0 +1,84 @@
+package bezier.geom;
+
+import java.awt.Color;
+
+public 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
diff --git a/CSMath/src/bezier/geom/Matrix.java b/CSMath/src/bezier/geom/Matrix.java
new file mode 100644
index 0000000..a728a02
--- /dev/null
+++ b/CSMath/src/bezier/geom/Matrix.java
@@ -0,0 +1,55 @@
+package bezier.geom;
+
+public class Matrix {
+ public final double[][] mat;
+
+ public Matrix(double[][] mat) {
+ this.mat = mat;
+ }
+
+ public Matrix add(Matrix m) {
+ return add(m.mat);
+ }
+
+ public double[] scalarMultiply(double[] vec) {
+ double[] ret = new double[vec.length];
+
+ for(int i = 0; i < mat[0].length; i++) {
+ for(int j = 0; j < mat.length; j++) {
+ ret[i] += mat[i][j] * vec[j];
+ }
+ }
+
+ return ret;
+ }
+
+ public Matrix add(double[][] matr) {
+ double[][] ret = new double[mat.length][mat[0].length];
+
+ for(int i = 0; i < mat.length; i++) {
+ for(int j = 0; j < mat[0].length; j++) {
+ ret[i][j] = mat[i][j] + matr[i][j];
+ }
+ }
+
+ return new Matrix(ret);
+ }
+
+ public Matrix multiply(Matrix m) {
+ return multiply(m.mat);
+ }
+
+ public Matrix multiply(double[][] matr) {
+ double[][] ret = new double[mat.length][matr[0].length];
+
+ for (int i = 0; i < mat.length; i++) {
+ for (int j = 0; j < matr[0].length; j++) {
+ for (int k = 0; k < matr.length; k++) {
+ ret[i][j] += mat[i][k] * matr[k][j];
+ }
+ }
+ }
+
+ return new Matrix(ret);
+ }
+}
diff --git a/CSMath/src/bezier/geom/TDHPoint.java b/CSMath/src/bezier/geom/TDHPoint.java
new file mode 100644
index 0000000..40553a9
--- /dev/null
+++ b/CSMath/src/bezier/geom/TDHPoint.java
@@ -0,0 +1,85 @@
+package bezier.geom;
+
+/**
+ * A two-dimensional homogeneous point.
+ *
+ * @author bjculkin
+ *
+ */
+public 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);
+ }
+
+ @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 + ", x=" + x + ", y=" + y + "]";
+ }
+} \ No newline at end of file
diff --git a/CSMath/src/bezier/geom/TDPoint.java b/CSMath/src/bezier/geom/TDPoint.java
new file mode 100644
index 0000000..8074461
--- /dev/null
+++ b/CSMath/src/bezier/geom/TDPoint.java
@@ -0,0 +1,111 @@
+package bezier.geom;
+
+/**
+ * Represents a two-dimensional point.
+ *
+ * @author bjculkin
+ *
+ */
+public 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);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(x);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(y);
+ 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;
+ TDPoint other = (TDPoint) obj;
+ if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
+ return false;
+ if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ 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);
+ }
+} \ No newline at end of file