Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.axe.path;
- import com.axe.core.Attribute;
- import com.axe.io.InputModel;
- import com.axe.io.OutputModel;
- import com.axe.math.Numbers;
- import com.axe.math.Scalari;
- /**
- * http://www.reddit.com/r/gamedev/comments/1ei88i/very_fast_2d_interpolation/
- *
- * @author Philip Diffenderfer
- *
- * @param <T>
- */
- public class KramerPath<T> implements Path<T>
- {
- public static final float DEFAULT_LOOSENESS = 0.0575f;
- protected Attribute<T>[] points;
- protected Attribute<T> temp0;
- protected Attribute<T> temp1;
- protected int depth;
- protected float looseness;
- protected boolean loops;
- protected float roughness;
- public KramerPath()
- {
- }
- public KramerPath( int depth, boolean loops, Attribute<T> ... points )
- {
- this( depth, loops, DEFAULT_LOOSENESS, 0.0f, points );
- }
- public KramerPath( int depth, boolean loops, float looseness, Attribute<T> ... points )
- {
- this( depth, loops, looseness, 0.0f, points );
- }
- public KramerPath( float roughness, boolean loops, Attribute<T> ... points )
- {
- this( 0, loops, DEFAULT_LOOSENESS, roughness, points );
- }
- public KramerPath( float roughness, boolean loops, float looseness, Attribute<T> ... points )
- {
- this( 0, loops, looseness, roughness, points );
- }
- protected KramerPath( int depth, boolean loops, float looseness, float roughness, Attribute<T> ... points )
- {
- this.depth = depth;
- this.loops = loops;
- this.looseness = looseness;
- this.roughness = roughness;
- this.points = points;
- this.temp0 = points[0].create();
- this.temp1 = points[0].create();
- }
- @Override
- public T set(Attribute<T> subject, float delta)
- {
- final int n = points.length;
- final float a = delta * n;
- final int i = Scalari.clamp( (int)a, 0, n - 1 );
- float d = a - i;
- if (depth != 0)
- {
- getPointWithExactDepth( i, d, subject );
- }
- else
- {
- getPointWithRoughness( i, d, subject );
- }
- return subject.get();
- }
- public void getPointWithExactDepth( int i, float d, Attribute<T> subject )
- {
- // v0 and v5 are used to calculate the next v1 or v4, at the next level.
- T v0 = points[ getActualIndex( i - 2 ) ].get();
- T v1 = points[ getActualIndex( i - 1 ) ].get();
- T v2 = points[ getActualIndex( i ) ].get();
- T v3 = points[ getActualIndex( i + 1 ) ].get();
- T v4 = points[ getActualIndex( i + 2 ) ].get();
- T v5 = points[ getActualIndex( i + 3 ) ].get();
- int k = depth;
- while (--k >= 0)
- {
- // Get mid point
- T mid = getPoint( v1, v2, v3, v4 );
- // If the desired point is closer to v2...
- if (d < 0.5f)
- {
- // shift all surrounding points one-level closer to v2
- if (k == 0)
- {
- v3 = mid;
- }
- else
- {
- T newEnd = v1;
- v5 = v4;
- v4 = v3;
- v3 = mid;
- v1 = getPoint( v0, v1, v2, v3 );
- v0 = newEnd;
- }
- // adjust d so it's between 0.0 an 1.0
- d = d * 2.0f;
- }
- // else, the desired point is closer to v3...
- else
- {
- // shift all surrounding points one-level closer to v3
- if (k == 0)
- {
- v2 = mid;
- }
- else
- {
- T newEnd = v4;
- v0 = v1;
- v1 = v2;
- v2 = mid;
- v4 = getPoint( v2, v3, v4, v5 );
- v5 = newEnd;
- }
- // adjust d so it's between 0.0 an 1.0
- d = (d - 0.5f) * 2.0f;
- }
- }
- // subject = (v3 - v2) * d + v2
- subject.interpolate( v2, v3, d );
- }
- public void getPointWithRoughness( int i, float d, Attribute<T> subject )
- {
- // v0 and v5 are used to calculate the next v1 or v4, at the next level.
- T v0 = points[ getActualIndex( i - 2 ) ].get();
- T v1 = points[ getActualIndex( i - 1 ) ].get();
- T v2 = points[ getActualIndex( i ) ].get();
- T v3 = points[ getActualIndex( i + 1 ) ].get();
- T v4 = points[ getActualIndex( i + 2 ) ].get();
- T v5 = points[ getActualIndex( i + 3 ) ].get();
- for (;;)
- {
- // Get mid point
- T mid = getPoint( v1, v2, v3, v4 );
- // if distance from mid to (v2->v3) is <= roughness, break
- // calculate the distance between all three points to form a triangle,
- // with the distances determine the perimeter then area. Use the
- // area = 0.5 * b * h formula to calculate height.
- float a = getDistance( v2, v3 );
- float b = getDistance( mid, v2 );
- float c = getDistance( mid, v3 );
- float p = (a + b + c) * 0.5f;
- float area = Numbers.sqrt( p * (p - a) * (p - b) * (p - c) );
- float height = area * 2.0f / a;
- if (height <= roughness)
- {
- break;
- }
- // If the desired point is closer to v2...
- if (d < 0.5f)
- {
- // shift all surrounding points one-level closer to v2
- T newEnd = v1;
- v5 = v4;
- v4 = v3;
- v3 = mid;
- v1 = getPoint( v0, v1, v2, v3 );
- v0 = newEnd;
- // adjust d so it's between 0.0 an 1.0
- d = d * 2.0f;
- }
- // else, the desired point is closer to v3...
- else
- {
- // shift all surrounding points one-level closer to v3
- T newEnd = v4;
- v0 = v1;
- v1 = v2;
- v2 = mid;
- v4 = getPoint( v2, v3, v4, v5 );
- v5 = newEnd;
- // adjust d so it's between 0.0 an 1.0
- d = (d - 0.5f) * 2.0f;
- }
- }
- // subject = (v3 - v2) * d + v2
- subject.interpolate( v2, v3, d );
- }
- public float getDistance( T a, T b )
- {
- temp0.set( a );
- return temp0.distance( b );
- }
- public T getPoint( T v1, T v2, T v3, T v4 )
- {
- // p = (0.5f + looseness) * (v2 + v3) - looseness * (v1 + v4)
- temp0.set( v2 );
- temp0.add( v3, 1f );
- temp0.scale( 0.5f + looseness );
- temp1.set( v1 );
- temp1.add( v4, 1f );
- temp0.add( temp1.get(), -looseness );
- return temp0.clone();
- }
- public int getActualIndex( int index )
- {
- final int n = points.length;
- return ( loops ? (index + n) % n : Scalari.clamp( index, 0, n - 1 ) );
- }
- @Override
- public int getAttributeCount()
- {
- return points.length;
- }
- @Override
- public Attribute<T> getAttribute(int index)
- {
- return points[ index ];
- }
- @Override
- public T get(int index)
- {
- return points[ index ].get();
- }
- public Attribute<T>[] points()
- {
- return points;
- }
- @Override
- public void read( InputModel input )
- {
- depth = input.readInt( "depth" );
- loops = input.readBoolean( "loops" );
- looseness = input.readFloat( "looseness" );
- points = input.readModelArray( "point", "point-type" );
- temp0 = points[0].create();
- temp1 = points[0].create();
- }
- @Override
- public void write( OutputModel output )
- {
- output.write( "depth", depth );
- output.write( "loops", loops );
- output.write( "looseness", looseness );
- output.writeModelArray( "point", points, "point-type" );
- }
- }
Add Comment
Please, Sign In to add comment