package org.squidy.nodes.reactivision.remote; import java.awt.Graphics2D; import java.util.Vector; public class CatmullRomSpline { private Vector<GridPoint> controlPoints; public CatmullRomSpline() { controlPoints = new Vector<GridPoint>(); } public void addControlPoint(GridPoint p) { controlPoints.addElement(p); } public void draw(Graphics2D g) { for (int i = 0; i < controlPoints.size() - 1; ++i) if (controlPoints.get(i).isSet && controlPoints.get(i+1).isSet) drawSplineSegment(getPrevious(i), controlPoints.get(i), controlPoints.get(i+1), getNext(i+1), g); else break; } private GridPoint getPrevious(int position) { if (position > 0) return controlPoints.get(position - 1); return controlPoints.get(0); } private GridPoint getNext(int position) { if (position < controlPoints.size() - 1 && controlPoints.get(position+1).isSet) return controlPoints.get(position + 1); return controlPoints.get(position); } private static void drawSplineSegment(GridPoint p1, GridPoint p2, GridPoint p3, GridPoint p4, Graphics2D g) { final int steps = 10; final int x[] = new int[steps]; final int y[] = new int[steps]; final float m_0 = (p3.y - p1.y)/2; final float m_1 = (p4.y - p2.y)/2; for (int i = 0; i < steps; ++i) { final float t = (float)i / (steps - 1); x[i] = (int)(p2.x + t * (p3.x - p2.x)); y[i] = (int)(h_00(t)*p2.y + h_10(t)*m_0 + h_01(t)*p3.y + h_11(t)*m_1); } g.drawPolyline(x, y, x.length); } /** * * @param segmentLocation = segment number + t * @return a GridPoint with absolute coordinates */ public GridPoint getInterpolated(float segmentLocation) { final GridPoint point = new GridPoint(); float t = segmentLocation - (int)segmentLocation; final GridPoint p1 = getPrevious((int)segmentLocation); final GridPoint p2 = controlPoints.get((int)segmentLocation); int i = (int)segmentLocation + 1; if (i + 1 >= controlPoints.size()) i = controlPoints.size() - 1; final GridPoint p3 = controlPoints.get(i); final GridPoint p4 = getNext(i); final float m_0 = (p3.y - p1.y)/2; final float m_1 = (p4.y - p2.y)/2; point.x = p2.x + t * (p3.x - p2.x); point.y = h_00(t)*p2.y + h_10(t)*m_0 + h_01(t)*p3.y + h_11(t)*m_1; return point; } private static float h_00(float t) { return (1 + 2*t)*(1 - t)*(1 - t); } private static float h_10(float t) { return t*(1 - t)*(1 - t); } private static float h_01(float t) { return t*t*(3 - 2*t); } private static float h_11(float t) { return t*t*(t - 1); } public int size() { return controlPoints.size(); } }