Package: com.multiversesocial.hyperview
Class: com.multiversesocial.hyperview.Spline
Source: src/com/multiversesocial/hyperview/Spline.java

Spline

HyperView V3.2 — class
version V3.2 class

Summary

A path a Gob travels along. V3.2: a real curve, followed in floating point. A Spline holds double control points, a curve type (CURVE_LINEAR, CURVE_BEZIER, CURVE_CATMULL_ROM), a speed in pixels per frame and the end logic in its flags. Give it to a Gob with Gob.attachSpline(); HyperView.run() then calls step(gob) once per display frame, which moves the Gob’s exact position fx,fy (doubles) along the curve; the Gob’s integer x,y are those rounded.

Why the old curves were only cosmetic (root cause)

Before 3.2 the constructor copied the points into x[] y[] z[] and, for CURVE_BEZIER, computed control points ctrlX/ctrlY which nothing ever read; CURVE_CATMULL_ROM was only a number stored in curveType. HyperView.run() moved the Gob from point to point with integer deltas dX/dY that computeDeltas() took from Octant.getOctant() (one of 8 directions, ±velocity per axis) — so every curve type travelled the same straight, octant snapped segments. Only the optional path line (PATH_LINE_ENA) was drawn from samples, which is why the curves looked curved on screen but the Gob did not follow them.

How it works now

Source file: Spline.java. Tests: test/.../SplineTest.java.

Hierarchy

Extends: none

Implements: SplineConstants

Referenced HyperView classes

Media files used

Declaration & members

public class Spline implements SplineConstants

Declared in src/com/multiversesocial/hyperview/Spline.java, lines 1–1234. 77 field(s), 8 constructor(s), 81 method(s). Every member has an anchor you can link to (e.g. Spline.html#<id>).

Fields (77)

DeclarationValue / initializerDescriptionSource
public int[] accelerationNo comment in source.line 79
public static final int ADV_ARRIVED= 1 (constant)moved along the pathline 93
public static final int ADV_FINISHED= 3 (constant)was already parked at the end, nothing happenedline 95
public static final int ADV_MOVING= 0 (constant)advance() / step() resultsline 92
public static final int ADV_PARKED= 2 (constant)reached the end this frame and stays there (COLLIDE_AT_END)line 94
private boolean closed= falsecontrol points (floating point)line 99
public int curPoint= 0end of the current segment (rounded)line 54
public int curRadius= 1No comment in source.line 78
public static final int CURVE_BEZIER= 1 (constant)No comment in source.line 87
public static final int CURVE_CATMULL_ROM= 2 (constant)No comment in source.line 88
public static final int CURVE_LINEAR= 0 (constant)Curve Typesline 86
private int curveType= CURVE_LINEARNo comment in source.line 89
public HyperView curView= nullCore Fieldsline 44
private boolean customHandles= falseBezier handles per segment (second)line 113
private double[] cxfloating point pathline 98
private double[] cyfloating point pathline 98
private double[] czfloating point pathline 98
public int deltaX= 1No comment in source.line 74
public int deltaY= 1No comment in source.line 74
private int dir= 1arc length travelled from the startline 102
private double distance= 0.0pixels per frame along the curveline 101
public int[] dXNo comment in source.line 50
public int[] dYNo comment in source.line 50
public int[] dZNo comment in source.line 50
public int[] fDXNo comment in source.line 61
public int[] fDYNo comment in source.line 61
public int[] fDZNo comment in source.line 61
public int fGPen= 1No comment in source.line 82
public int flags= 0index of the current segment's first pointline 55
public int[] fOctantReverse valuesline 66
public int[] fXBounce arrays (legacy, filled but not used by the stepper)line 60
public int[] fYBounce arrays (legacy, filled but not used by the stepper)line 60
public int[] fZBounce arrays (legacy, filled but not used by the stepper)line 60
private double[] h1xrounded samples for drawing (lazy)line 111
private double[] h1yrounded samples for drawing (lazy)line 111
private double[] h1zrounded samples for drawing (lazy)line 111
private double[] h2xBezier handles per segment (first)line 112
private double[] h2yBezier handles per segment (first)line 112
private double[] h2zBezier handles per segment (first)line 112
private static final int LEN_SUB= 4 (constant)arc length table samples per segmentline 105
private double length= 0.0number of segmentsline 108
public Color lineColor= Color.whiteNo comment in source.line 45
public byte mapType= 0Spline propertiesline 77
public int mass= 1speed in pixels per frame (int view of speed)line 57
public int maximumX= 0Path boundsline 70
public int maximumY= 0No comment in source.line 72
public int minimumX= 0x7fffffffNo comment in source.line 71
public int minimumY= 0x7fffffffNo comment in source.line 73
public Spline next= nullNo comment in source.line 80
Gob owner= nullthe Gob following this Spline (set by Gob.attachSpline)line 115
private boolean parked= false+1 forward, -1 backwardline 103
private static final int PATH_DIV= 24 (constant)chords per sample interval when measuring its lengthline 106
public int pathOffsetX= 0PATH_LINE_ENA draws the path shifted by this (e.g. half the Gob size)line 83
public int pathOffsetY= 0PATH_LINE_ENA draws the path shifted by this (e.g. half the Gob size)line 83
private int[] pathXarc length at sample k (k = 0 .. segs*res)line 110
private int[] pathYarc length at sample k (k = 0 .. segs*res)line 110
public Spline prev= nullNo comment in source.line 81
public int[] rDXNo comment in source.line 63
public int[] rDYNo comment in source.line 63
public int[] rDZNo comment in source.line 63
public int[] rOctantNo comment in source.line 67
public int[] rXNo comment in source.line 62
public int[] rYNo comment in source.line 62
public int[] rZNo comment in source.line 62
private int samplingResolution= 128arc length table samples per segmentline 104
private int segs= 0polyline points per segment for getPathX()/getPathY()line 107
private double speed= 1.0pixels per frame along the curveline 100
public int targetX= 0Movement stateline 53
public int targetY= 0Movement stateline 53
public int targetZ= 0Movement stateline 53
private double[] tLentotal arc length (x,y)line 109
private final double[] tmp= new double[3]No comment in source.line 114
public int totalPoints= 0Path data (rounded copies of the control points, kept for old readers; see the header)line 48
public int velocity= 1speed in pixels per frame (int view of speed)line 56
public int[] xNo comment in source.line 49
public int[] yNo comment in source.line 49
public int[] zNo comment in source.line 49

Constructors (8)

SignatureDescriptionSource
public Spline()An empty Spline without points; give it points with setPoints().line 120
public Spline(HyperView tView, double tSpeed, double[] tx, double[] ty, double[] tz, int curveType, int flags)Master constructor. Floating point control points tx,ty (and tz, or null for z = 1), speed tSpeed pixels per frame along the curve, curveType CURVE_LINEAR / CURVE_BEZIER / CURVE_CATMULL_ROM, flags = SplineConstants bits (one of STOP_AT_END, BOUNCE_AT_END, WRAP_AT_END, COLLIDE_AT_END, plus SP_ZBUFFER_ENA, PATH_LINE_ENA ...). The arc length table is built here.line 172
public Spline(HyperView tView, int tV, int[] tx, int[] ty)Legacy int constructor: speed tV pixels per frame, 2D or 3D integer points (z = 1 when omitted); builds the same floating point curve as the master constructor (curve type linear unless given).line 126
public Spline(HyperView tView, int tV, int[] tx, int[] ty, int flags)Legacy int constructor: speed tV pixels per frame, 2D or 3D integer points (z = 1 when omitted); builds the same floating point curve as the master constructor (curve type linear unless given).line 133
public Spline(HyperView tView, int tV, int[] tx, int[] ty, int curveType, boolean isCurve)Legacy int constructor: speed tV pixels per frame, 2D or 3D integer points (z = 1 when omitted); builds the same floating point curve as the master constructor (curve type linear unless given).line 147
public Spline(HyperView tView, int tV, int[] tx, int[] ty, int[] tz, int flags)Legacy int constructor: speed tV pixels per frame, 2D or 3D integer points (z = 1 when omitted); builds the same floating point curve as the master constructor (curve type linear unless given).line 140
public Spline(HyperView tView, int tV, int[] tx, int[] ty, int[] tz, int curveType, boolean isCurve)Legacy int constructor: speed tV pixels per frame, 2D or 3D integer points (z = 1 when omitted); builds the same floating point curve as the master constructor (curve type linear unless given).line 154
public Spline(HyperView tView, int tV, int[] tx, int[] ty, int[] tz, int curveType, int flags)Legacy int constructor: speed tV pixels per frame, 2D or 3D integer points (z = 1 when omitted); builds the same floating point curve as the master constructor (curve type linear unless given).line 161

Methods (81)

SignatureDescriptionSource
public void addPoint(double px, double py, double pz)Append a control point and rebuild the curve (the distance travelled is kept).line 950
public void addPoint(int px, int py)Append a control point (z = 1); see addPoint(double,double,double).line 938
public void addPoint(int px, int py, int pz)Append a control point.line 944
public int advance()Advance one frame: the distance changes by speed (backwards when dir is -1) and the END logic is applied. Does not touch a Gob (see step()). Returns ADV_MOVING, ADV_ARRIVED, ADV_PARKED or ADV_FINISHED. End modes (flags & END_LOGIC), applied with the overshoot carried over, so the speed stays constant through the turn: WRAP_AT_END d -= length (d += length when going backwards): the Gob re-enters at the other end. A closed Spline is seamless, an open one jumps. BOUNCE_AT_END d = 2*length - d, direction reverses (SP_FORWARD follows it); the same at 0. COLLIDE_AT_END d = length (or 0), flags ARRIVED, the Gob stays on the end point and keeps its Spline (the CollisionManager tests it every frame). Alone it is the "park" mode; with WRAP or BOUNCE the Gob keeps moving and is simply a collision participant. STOP_AT_END or none: d = end point, ARRIVED, ADV_FINISHED: step() then detaches the ...line 588
public int advance(double ds)Same with an explicit step ds (pixels, >= 0) instead of the speed.line 594
private void autoHandles()Handles of CURVE_BEZIER: tangent at point j = direction of (P[j+1] - P[j-1]); handle length = chord / 3.line 294
private void buildCurve()No comment in source.line 255
private static double clampBetween(double v, double a, double b)No comment in source.line 341
public void cleanUp()Release the arrays and the references; the Spline can not be used afterwards.line 1164
public void computeDeltas()Refresh the legacy int arrays dX/dY/dZ and octants (old readers only: the Gob does not follow them any more).line 723
public void computeRDeltas()Same for the reverse (rDX, rDY, rOctant) arrays.line 757
public static Spline createCircle(HyperView view, int cx, int cy, int radius, int points, int speed)A closed circle of radius pixels round cx,cy through points points (CURVE_BEZIER), speed pixels per frame. Flags WRAP_AT_END | SP_ZBUFFER_ENA: it loops seamlessly and z swings 10 -/+ 4 (nearest at the bottom). Before 3.2 it set the z flag but no end logic.line 1068
public static Spline createCircle(HyperView view, int cx, int cy, int radius, int points, int speed, int flags)The same with explicit flags (replace the defaults completely, e.g. WRAP_AT_END alone for a circle of constant size, or COLLIDE_AT_END).line 1074
public static Spline createEllipse(HyperView view, int cx, int cy, int rx, int ry, int points, int speed)A closed ellipse (radii rx, ry) round cx,cy, same defaults as createCircle: WRAP_AT_END | SP_ZBUFFER_ENA. The speed is the same all round the ellipse.line 1080
public static Spline createEllipse(HyperView view, int cx, int cy, int rx, int ry, int points, int speed, int flags)The same with explicit flags (they replace the defaults).line 1086
public static Spline createHeart(HyperView view, int cx, int cy, int size, int speed)A closed heart shape (32 points, CURVE_BEZIER) round cx,cy, size = half the width in pixels. Default end logic WRAP_AT_END; no z.line 1136
public static Spline createHeart(HyperView view, int cx, int cy, int size, int speed, int flags)The same with explicit flags (they replace WRAP_AT_END).line 1142
public static Spline createSpiral(HyperView view, int cx, int cy, int startR, int endR, int turns, int points, int speed)An open spiral from radius startR to endR with turns turns (CURVE_BEZIER). Default end logic BOUNCE_AT_END: out and back again.line 1112
public static Spline createSpiral(HyperView view, int cx, int cy, int startR, int endR, int turns, int points, int speed, int flags)The same with explicit flags (they replace BOUNCE_AT_END).line 1118
private int endAt(double pos, boolean collide)No comment in source.line 659
private void evalSegment(int seg, double t, double[] out)No comment in source.line 358
private void evalU(double u, double[] out)curve at u = segment + t (0 .. segs)line 391
public double[] getArcLengthTable()A copy of the arc length table: entry k = pixels from the start to sample k (non decreasing, last = length).line 471
public void getControlPoint(int i, double[] out)Control point i (floating point): out[0]=x, out[1]=y, out[2]=z.line 508
public int getCurrentPoint()Index of the control point at the start of the current segment (legacy; see getSegmentCount, getDistance).line 1049
public int getCurrentX()The path position now, rounded (the Gob's x,y while this Spline drives it).line 1037
public int getCurrentY()The path y now, rounded.line 1039
public int getCurrentZ()The path z now, rounded.line 1041
public int getCurveType()CURVE_LINEAR, CURVE_BEZIER or CURVE_CATMULL_ROM.line 1053
public int getDirection()+1 while travelling from the first point to the last, -1 backwards (BOUNCE_AT_END, reverse()).line 456
public double getDistance()Pixels travelled from the start of the path.line 434
public String getFlagString()The set Spline flag bits as text (SP_FORWARD|WRAP_AT_END ...), for debugging and the Info steps.line 1208
public double getLength()Total arc length of the curve in pixels (measured in x,y).line 431
public Gob getOwner()The Gob which follows this Spline, or null.line 1059
public int getPathLength()Number of entries of getPathX()/getPathY().line 483
public int[] getPathX()x of the curve samples rounded to int pixels (for drawing the path); do not modify.line 477
public int[] getPathY()y of the curve samples rounded to int pixels (for drawing the path); do not modify.line 480
public void getPointAtLength(double s, double[] out)The point s pixels along the curve (s clamped to 0..length): out[0]=x, out[1]=y, out[2]=z.line 459
public void getPointOnSegment(int seg, double t, double[] out)The curve inside segment seg (0 .. getSegmentCount()-1) at t in [0,1]: out[0]=x, out[1]=y, out[2]=z. t=0 is the segment's first control point and t=1 its second (the next one; the first for the closing segment of a closed Spline). This is the plain curve parameter, not arc length.line 353
public void getPoint(double[] out)The point at the current distance: out[0]=x, out[1]=y, out[2]=z.line 465
public double getProgress()Fraction of the path travelled, 0..1.line 1055
public int getSamplingResolution()Samples per segment of the arc length table.line 474
public int getSegmentCount()Number of curve segments: points-1, or points for a closed Spline, 0 for a single point.line 428
public double getSpeed()Speed in pixels per frame along the curve.line 446
public void getStart(double[] out)Where the Gob starts: the first point of the path (x,y,z of getPointAtLength(0)).line 715
public int getTargetX()Legacy: x of the end of the current segment (rounded).line 1043
public int getTargetY()Legacy: y of the end of the current segment (rounded).line 1045
public int getTargetZ()Legacy: z of the end of the current segment (rounded).line 1047
public int getTotalPoints()Number of control points.line 1051
private int idx(int i)No comment in source.line 247
private void initBounceArrays()No comment in source.line 788
private boolean isClosedEff()No comment in source.line 242
public boolean isClosed()No comment in source.line 534
public boolean isParked()True if the Spline is parked on its end point (COLLIDE_AT_END arrived).line 1057
private double locate(double s)largest sample index k <= segs*res-1 with tLen[k] <= s; frac = position inside [k,k+1]line 408
private void makePath()a polyline of the curve for drawing: PATH_DIV points per segment (and the end point)line 486
private void pointsChanged()Rebuild everything derived from the control points (legacy int arrays, curve, length table).line 216
public void reset()Back to the first point: distance 0, direction forward, no longer parked, ARRIVED cleared.line 926
public void reverse()Run the path the other way from where the Gob is now (the direction flips and SP_FORWARD follows, the Gob does not jump); clears the parked state.line 912
public void scale(double factor)Scale x, y and z of all control points by factor; the speed is not changed, so the length scales, and the fraction of the path travelled is kept.line 996
public void setBezierHandles(double[] c1x, double[] c1y, double[] c2x, double[] c2y)CURVE_BEZIER with your own handles: for segment i (point i to point i+1, getSegmentCount() entries) c1 is the handle after point i and c2 the handle before point i+1, in x,y. z uses straight thirds. The arrays are copied. setCurveType()/setClosed()/setPoints() go back to the automatic handles.line 550
public void setClosed(boolean c)A closed Spline has a last segment from the final point back to the first (3 or more points).line 537
public void setCurveType(int type)Change the curve type (CURVE_LINEAR, CURVE_BEZIER, CURVE_CATMULL_ROM) and rebuild the curve; the distance travelled is kept.line 866
public void setDistance(double d)Put the travelled distance anywhere on the path (clamped to 0..length). Clears the parked state.line 437
public void setLineColor(Color color)Colour of the path line drawn when PATH_LINE_ENA is set.line 894
public void setPoints(double[] tx, double[] ty, double[] tz)Replace the control points (copied; tz may be null = z 1). The travelled distance restarts at 0.line 514
public void setSamplingResolution(int resolution)Samples per segment of the arc length table (at least 4, default 128); the curve is rebuilt. More samples = more exact constant speed.line 876
public void setSpeed(double pixelsPerFrame)Set the speed (pixels per frame, floating point; also sets the int velocity).line 449
public void setTarget(int tx, int ty, int tz)Legacy: sets targetX/Y/Z only; the Gob does not use them any more.line 900
public void setVelocity(int newVelocity)Legacy int speed in pixels per frame; same as setSpeed(double).line 885
public void setView(HyperView tView)The HyperView this Spline belongs to.line 845
public boolean step(Gob g)HyperView.run() calls this once per display frame for the Gob that follows this Spline: advance() and write the position. The Gob's float position (fx,fy,fz) is the curve point; x,y,z are those rounded (z only when SP_ZBUFFER_ENA). Returns false when the Gob has let go of the Spline (STOP_AT_END).line 692
private void syncLegacy()curPoint / targetX.. for old readersline 673
private static double[] toDouble(int[] a)No comment in source.line 205
public String toString()STRING REPRESENTATIONline 1190
public void translate(double dx, double dy, double dz)Move all control points by dx,dy,dz (floating point); the distance travelled is kept.line 976
public void translate(int dx, int dy)Move all control points by dx,dy.line 963
public void translate(int dx, int dy, int dz)Move all control points by dx,dy,dz.line 969
public void updateBounds()Recompute minimumX/Y and maximumX/Y of the control points.line 1018
public void ZBufferDisable()Clear SP_ZBUFFER_ENA.line 858
public void ZBufferEna()Set SP_ZBUFFER_ENA: the Gob follows the z of the path and its size = widthBase / z.line 851

Examples

// a curved path, constant speed 4 px/frame, bouncing at the ends
double x[] = {50,170,290,410,530,590};
double y[] = {360,170,360,170,360,250};
Spline s = new Spline(view,4.0,x,y,null,Spline.CURVE_BEZIER,SplineConstants.BOUNCE_AT_END);
s.flags |= SplineConstants.PATH_LINE_ENA;      // draw the curve (optional)
Gob g = new Gob(view,"ea2.gif",46,47,GOB_ON_DISPLAY);
view.addGob(g);
g.attachSpline(s);                              // g now follows the curve; g.getSpline() == s
...
g.detachSpline();                               // lets go where it is

// a closed circle that loops forever, at constant size
Spline c = Spline.createCircle(view,320,240,120,36,5,SplineConstants.WRAP_AT_END);

// the exact position (doubles) and the rounded one
double fx = g.getFloatX(), fy = g.getFloatY();   // g.x == Math.round(fx)

Old callers still work: new Spline(this,1,xLocs0,yLocs0,zLocs0,BOUNCE_AT_END) (ViewMain), new Spline(curView,5,xLocs1,yLocs1,SplineConstants.BOUNCE_AT_END) (MegaMooV), Gob.addSpline(s), new Gob(view,name,w,h,spline,flags).

Hits--