using System.Collections.Generic;
public class TArray<T> : List<T>{
public FVector( float x, float y, float z ){
return X + "," + Y + "," + Z;
public static class Ext {
public static int Num( this TArray<FVector> array ){
public static int Num( this TArray<int> array ){
public static float EaseInOutQuad( float t, float b , float c, float d ) {
if ((t/=d/2) < 1) return c/2*t*t + b;
return -c/2 * ((--t)*(t-2) - 1) + b;
public static float EaseNone(float t,float b , float c, float d) {
static void Dlog( string log ){
Console.WriteLine( log );
void Print( TArray<FVector> Locs, bool showIdx = false ){
for( int i = 0, len = Locs.Num(); i < len; i++ ) {
str += ( "[" + i.ToString() + "]" ).PadLeft(4, ' ') + " ";
Console.WriteLine( str );
for( int i = 0, len = Locs.Num(); i < len; i++ ) {
str += Loc.Z.ToString().PadLeft(3, ' ') + ", ";
Console.WriteLine( str );
void FindPeaks( TArray<FVector> Locs, out float MaxZ, out int MaxCnt, out TArray<int> Indexes ) {
Indexes = new TArray<int>();
for( int i = 1, len = Locs.Num()-1; i< len; i++ ) {
} else if( MaxZ == Locs[i].Z ) {
Dlog( "MaxZ("+MaxZ+"), MaxCnt("+MaxCnt+"), idx("+ String.Join( ", ", Indexes ) +")" );
void FlattenPeaks( TArray<FVector> Locs, TArray<int>Indexes, float MaxZ, int MaxCnt ){
string dbgStr = "\n *** work on our peaks ***\nchanging idxes ";
for( int idx = Indexes[0]+1, klen = Indexes[MaxCnt-1]; idx < klen; idx++ ){
Dlog( dbgStr + " to " + MaxZ );
void WorkOnTheSlope( TArray<FVector> Locs, TArray<int> workingIdxes ){
int idxesLen = workingIdxes.Num();
string dbgStr = "\n *** work on our hills ***\nidxes: ";
for( int wi = 0; wi < idxesLen; wi++ ) {
dbgStr += workingIdxes[wi] + ", ";
for( int wi = 0; wi < idxesLen-1; wi++ ) {
int i = workingIdxes[wi];
int nxtI = workingIdxes[nxtWi];
float diff = Locs[nxtI].Z - Locs[i].Z;
Dlog( "["+i+"]"+ Locs[i].Z.ToString().PadLeft(2, ' ') +" -> ["+nxtI+"]" + Locs[nxtI].Z.ToString().PadLeft(2, ' ') + "; diff: " + diff );
Dlog( "["+i+"]"+ Locs[i].Z.ToString().PadLeft(2, ' ') +" -> ["+nxtI+"]" + Locs[nxtI].Z.ToString().PadLeft(2, ' ') + "; diff: " + diff + "; a downhill" );
for( int wj = nxtWi; wj < idxesLen; wj++ ) {
int j = workingIdxes[wj];
if( SPeak < Locs[j].Z ) {
Dlog( "\t["+j+"] " + Locs[j].Z + " <- this is our peak, div: " + div );
for( int wk = nxtWi; wk < wj; wk++ ) {
int k = workingIdxes[wk];
float newZ = SPeak + (EPeak-SPeak) * (float)(wk+1-nxtWi) / div ;
Dlog( "\t\tset ["+k+"] " + Locs[k].Z + " to " + newZ + "; alpha("+((wk+1-nxtWi) / div)+")" );
Dlog( "\t["+j+"] " + Locs[j].Z + " <- nah, current peak is " + SPeak );
bool IsEndZHigherThanMaxZ( TArray<FVector> Locs, int len, float MaxZ, float EndZ ){
float EZ = Locs[(int)div].Z;
string dbgStr = "\n *** just uphill ***\npeak("+MaxZ+") is lower than our endZ("+EndZ+"); SZ("+SZ+"), EZ("+EZ+"), div("+div+")";
for( int i = 1; i < len-1; i++ ) {
dbgStr += "\n["+i+"] " + Locs[i].Z.ToString().PadLeft( 3, ' ' ) + " ratio("+i+"/"+div+")";
Locs[i].Z = Ext.EaseInOutQuad( i, SZ, EZ-SZ, div );
dbgStr += " -> " + Locs[i].Z;
TArray<float> Calc( float headLen, float tailLen, float midLen, float totalLen ) {
if( totalLen <= ( headLen + tailLen ) / 2f ){
Dlog( "totalLen("+totalLen+") <= ( headLen + tailLen ) / 2f; " + ( (headLen + tailLen)/2f ) + ")" );
return new TArray<float>() {
float halfHdeadLen = headLen / 2f;
float halfTaildLen = tailLen / 2f;
TArray<float> dist = new TArray<float>();
dist.Add( headLen / 2f );
float _ttlLen = totalLen - headLen / 2f;
TArray<FVector> Locs = new TArray<FVector>();
Locs.Add( new FVector( 0, 0, 8 ) );
Locs.Add( new FVector( 0, 0, 5.5f ) );
Locs.Add( new FVector( 0, 0, 5 ) );
Locs.Add( new FVector( 0, 0, 2.4f ) );
Locs.Add( new FVector( 0, 0, 2.3f ) );
Locs.Add( new FVector( 0, 0, 2.2f ) );
Locs.Add( new FVector( 0, 0, 2 ) );
Locs.Add( new FVector( 0, 0, 1 ) );
Locs.Add( new FVector( 0, 0, 15 ) );
Locs.Add( new FVector( 0, 0, 17 ) );
Locs.Add( new FVector( 0, 0, 13 ) );
Locs.Add( new FVector( 0, 0, 14 ) );
Locs.Add( new FVector( 0, 0, 20 ) );
Locs.Add( new FVector( 0, 0, 7 ) );
Locs.Add( new FVector( 0, 0, 5 ) );
Locs.Add( new FVector( 0, 0, 10 ) );
Locs.Add( new FVector( 0, 0, 3 ) );
Locs.Add( new FVector( 0, 0, 5 ) );
Locs.Add( new FVector( 0, 0, 1 ) );
Locs.Add( new FVector( 0, 0, 15 ) );
Locs.Add( new FVector( 0, 0, 17 ) );
Locs.Add( new FVector( 0, 0, 13 ) );
Locs.Add( new FVector( 0, 0, 20 ) );
Locs.Add( new FVector( 0, 0, 9 ) );
Locs.Add( new FVector( 0, 0, 8 ) );
Locs.Add( new FVector( 0, 0, 20 ) );
Locs.Add( new FVector( 0, 0, 10 ) );
Locs.Add( new FVector( 0, 0, 9 ) );
Locs.Add( new FVector( 0, 0, 8 ) );
Locs.Add( new FVector( 0, 0, 7 ) );
Locs.Add( new FVector( 0, 0, 20 ) );
Locs.Add( new FVector( 0, 0, 14 ) );
Locs.Add( new FVector( 0, 0, 11 ) );
Locs.Add( new FVector( 0, 0, 10 ) );
Locs.Add( new FVector( 0, 0, 4 ) );
Locs.Add( new FVector( 0, 0, 6.7f ) );
Locs.Add( new FVector( 0, 0, 6 ) );
Locs.Add( new FVector( 0, 0, 5 ) );
Locs.Add( new FVector( 0, 0, 4 ) );
Locs.Add( new FVector( 0, 0, 7 ) );
Locs.Add( new FVector( 0, 0, 1 ) );
Locs.Add( new FVector( 0, 0, 1 ) );
Locs.Add( new FVector( 0, 0, 2 ) );
Locs.Add( new FVector( 0, 0, 2.2f ) );
Locs.Add( new FVector( 0, 0, 2.3f ) );
Locs.Add( new FVector( 0, 0, 2.4f ) );
Locs.Add( new FVector( 0, 0, 5 ) );
Locs.Add( new FVector( 0, 0, 5.5f ) );
Locs.Add( new FVector( 0, 0, 8 ) );
Locs.Add( new FVector( 0, 0, 1 ) );
Locs.Add( new FVector( 0, 0, 5 ) );
Locs.Add( new FVector( 0, 0, 3 ) );
Locs.Add( new FVector( 0, 0, 10 ) );
Locs.Add( new FVector( 0, 0, 5 ) );
Locs.Add( new FVector( 0, 0, 7 ) );
Locs.Add( new FVector( 0, 0, 20 ) );
Locs.Add( new FVector( 0, 0, 13 ) );
Locs.Add( new FVector( 0, 0, 17 ) );
Locs.Add( new FVector( 0, 0, 15 ) );
Locs.Add( new FVector( 0, 0, 0 ) );
Locs.Add( new FVector( 0, 0, 7 ) );
Locs.Add( new FVector( 0, 0, 4 ) );
Locs.Add( new FVector( 0, 0, 5 ) );
Locs.Add( new FVector( 0, 0, 8 ) );
Locs.Add( new FVector( 0, 0, 4 ) );
Locs.Add( new FVector( 0, 0, 10 ) );
Locs.Add( new FVector( 0, 0, 11 ) );
Locs.Add( new FVector( 0, 0, 14 ) );
Locs.Add( new FVector( 0, 0, 20 ) );
Locs.Add( new FVector( 0, 0, 7 ) );
Locs.Add( new FVector( 0, 0, 8 ) );
Locs.Add( new FVector( 0, 0, 9 ) );
Locs.Add( new FVector( 0, 0, 10 ) );
Locs.Add( new FVector( 0, 0, 20 ) );
Locs.Add( new FVector( 0, 0, 8 ) );
Locs.Add( new FVector( 0, 0, 9 ) );
Locs.Add( new FVector( 0, 0, 20 ) );
Locs.Add( new FVector( 0, 0, 13 ) );
Locs.Add( new FVector( 0, 0, 17 ) );
Locs.Add( new FVector( 0, 0, 15 ) );
float Elevation = Locs[len-1].Z - Locs[0].Z;
Dlog( "Elevation: " + Elevation + "; flat" );
} else if( 0 < Elevation ){
Dlog( "Elevation: " + Elevation + "; heading up" );
FindPeaks( Locs, out MaxZ, out MaxCnt, out Indexes );
if( IsEndZHigherThanMaxZ( Locs, len, MaxZ, Locs[len-1].Z ) ) {
} else if( MaxCnt == 1 ) {
TArray<int>frontWorkingIdx = new TArray<int>();
for( int i = 0; i <= Indexes[0]; i++ ) {
frontWorkingIdx.Add( i );
WorkOnTheSlope( Locs, frontWorkingIdx );
TArray<int>backWorkingIdx = new TArray<int>();
for( int i = len-1; Indexes[Indexes.Num()-1] <= i; i-- ) {
WorkOnTheSlope( Locs, backWorkingIdx );
FlattenPeaks( Locs, Indexes, MaxZ, MaxCnt );
TArray<int>frontWorkingIdx = new TArray<int>();
for( int i = 0; i <= Indexes[0]; i++ ) {
frontWorkingIdx.Add( i );
WorkOnTheSlope( Locs, frontWorkingIdx );
TArray<int>backWorkingIdx = new TArray<int>();
for( int i = len-1; Indexes[Indexes.Num()-1] <= i; i-- ) {
WorkOnTheSlope( Locs, backWorkingIdx );
Dlog( "Elevation: " + Elevation + "; heading dn" );
FindPeaks( Locs, out MaxZ, out MaxCnt, out Indexes );
if( IsEndZHigherThanMaxZ( Locs, len, MaxZ, Locs[0].Z ) ) {
} else if( MaxCnt == 1 ) {
TArray<int>frontWorkingIdx = new TArray<int>();
for( int i = 0; i <= Indexes[0]; i++ ) {
frontWorkingIdx.Add( i );
WorkOnTheSlope( Locs, frontWorkingIdx );
TArray<int>backWorkingIdx = new TArray<int>();
for( int i = len-1; Indexes[Indexes.Num()-1] <= i; i-- ) {
WorkOnTheSlope( Locs, backWorkingIdx );
FlattenPeaks( Locs, Indexes, MaxZ, MaxCnt );
TArray<int>frontWorkingIdx = new TArray<int>();
for( int i = 0; i <= Indexes[0]; i++ ) {
frontWorkingIdx.Add( i );
WorkOnTheSlope( Locs, frontWorkingIdx );
TArray<int>backWorkingIdx = new TArray<int>();
for( int i = len-1; Indexes[Indexes.Num()-1] <= i; i-- ) {
WorkOnTheSlope( Locs, backWorkingIdx );
Dlog( "------------------" );