Last active
May 11, 2020 00:19
-
-
Save eclecticlogic/e46120cb719d38f5360e to your computer and use it in GitHub Desktop.
Fits a Cubic Bezier curve and allows you to treat it as y = f(x)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* @author kabram. | |
* | |
*/ | |
public class CubicBezierCurve { | |
private Point p0, p1, p2, p3; | |
private final Map<Double, Double> precomputed = new HashMap<>(); | |
public void setEndPoints(Point start, Point end) { | |
p0 = start; | |
p3 = end; | |
} | |
public void setControlPoints(Point c1, Point c2) { | |
p1 = c1; | |
p2 = c2; | |
} | |
public double get(double x, double precision) { | |
if (precomputed.containsKey(x)) { | |
return precomputed.get(x); | |
} else { | |
double t = (x - p0.x) / (p3.x - p0.x); | |
double x1 = getX(t); | |
double left = 0.0; | |
double right = 1.0; | |
while (Math.abs(x1 - x) > precision) { | |
if (x1 < x) { | |
left = t; | |
} else { | |
right = t; | |
} | |
t = (left + right) / 2.0; | |
x1 = getX(t); | |
} | |
return getY(t); | |
} | |
} | |
private double getY(double t) { | |
double t2 = Math.pow(t, 2); | |
double t3 = Math.pow(t, 3); | |
double a = Math.pow(1 - t, 3); | |
double b = 3.0 * (t - 2.0 * t2 + t3); | |
double c = 3.0 * (t2 - t3); | |
double d = t3; | |
return a * p0.y + b * p1.y + c * p2.y + d * p3.y; | |
} | |
private double getX(double t) { | |
double t2 = Math.pow(t, 2); | |
double t3 = Math.pow(t, 3); | |
double a = Math.pow(1 - t, 3); | |
double b = 3.0 * (t - 2.0 * t2 + t3); | |
double c = 3.0 * (t2 - t3); | |
double d = t3; | |
return a * p0.x + b * p1.x + c * p2.x + d * p3.x; | |
} | |
/** | |
* @param step Pre-compute values base on step value of x from start.x to end.x. | |
*/ | |
public void precompute(double step, double precision) { | |
double x = p0.x; | |
while (x <= p3.x * Math.signum(step)) { | |
precomputed.put(x, get(x, precision)); | |
x += step; | |
} | |
} | |
public static void main(String[] args) { | |
CubicBezierCurve curve = new CubicBezierCurve(); | |
curve.setEndPoints(new Point(0, 10), new Point(20, 0)); | |
curve.setControlPoints(new Point(0, 6), new Point(12, 0)); | |
System.out.println(curve.get(0.18, 0.001)); | |
} | |
public static class Point { | |
double x; | |
double y; | |
public Point() { | |
super(); | |
} | |
public Point(double x, double y) { | |
super(); | |
this.x = x; | |
this.y = y; | |
} | |
public static Point xy(double x, double y) { | |
return new Point(x, y); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment