Code archives/Algorithms/Interpolation library

This code has been declared by its author to be Public Domain code.

Download source code

Interpolation library by Bobysait2016
Here is a library to create interpolation between arrays of objects
-> Extends the types (BGradient, BGradient2, and BGradient3) to use it
there is already 2 extensions for Int[] and Float[]
You can create your own "interpolator" for Vector or any kind of objects
you'll need to implement a method for the lowest interpolation
Method Interpolate:Object(a:Object,b:Object, v:Double) Abstract

See the extended types for more details (they use linear interpolation, but they can be replaced by cos/sin/square interpolation etc ...)


-> use it as standalone include :
save the file and include it ...

-> use it as a module :
Add "Module yourname.interpolation" at the top of the file and save it to "interpolation.bmx" in a "yourname.mod" folder in your blitzmax mod's folder to build it as a module
Then just import it -> Import yourname.interpolation



The sample will show an interpolation of 3 levels of arrays
using color templates for Season, time of the day and altitude of the sky.


SuperStrict

Rem
undocument the @Module line to build as a module.
Save it as YOUR_BLITZMAX_PATH/mod/MDT.mod/Gradient.bmx
EndRem

'Module MDT.Gradient

' Abstract type ! Don't create instance of BGradient without extending it first !
' for purpose, see the Int4Gradient and Float4Gradient below
Type BGradient Abstract
	
	Field Objects:Object[];
	
	Method Interpolate:Object(a:Object,b:Object, v:Double) Abstract
	
	Method NewInstance:Object() Abstract
	
	Method OnCreate:BGradient(Size:Long=2)
		Self.Objects = New Object[Size];
		Local i:Int; For i=0 Until Size; Self.Objects[i] = Self.NewInstance(); Next;
		Return Self;
	End Method
	
	Method SetArray:BGradient( array:Object[])
		Self.Objects = array;
		Return Self;
	End Method
	
	Method Set:BGradient(id:Long, o:Object)
		If (id<0 Or id>=Self.Objects.Length) Then Return Self;
		Self.Objects[id] = o;
		Return Self;
	End Method
	
	Method Get:Object(v:Double)
		If (v<=0) Then Return Self.Objects[0];
		If (v>=1.0) Then Return Self.Objects[Self.Objects.Length-1];
		Local i:Double = v * (Self.Objects.Length-1), i0:Int = Floor(i); If (i0=i) Then Return	Self.Objects[i0];
		Return	Self.Interpolate (Self.Objects[i0], Self.Objects[i0+1], i-i0);
	End Method
End Type

Type BGradient2 Abstract
	Field Gradients:BGradient[];
	
	Method NewInstance:BGradient(SizeJ:Long) Abstract
	
	Method OnCreate:BGradient2(SizeI:Long=2, SizeJ:Long=2)
		Self.Gradients = New BGradient[SizeI];
		Local i:Int; For i=0 Until SizeI; Self.Gradients[i]=Self.NewInstance(SizeJ); Next;
		Return Self;
	End Method
	
	Method Get:Object(x:Double, y:Double)
		If (x<=0) Then Return Self.Gradients[0].Get(y);
		If (x>=1) Then Return Self.Gradients[Self.Gradients.Length-1].Get(y);
		Local i:Double = x * (Self.Gradients.Length-1), i0:Int = Floor(i);
		Return Self.Gradients[0].Interpolate (Self.Gradients[i0].Get(y), Self.Gradients[i0+1].Get(y), i-i0);
	End Method
	
	Method Gradient:BGradient(pId:Long)
		If (pId<0 or pId>=Self.Gradients.Length) Then Return Null;
		Return Self.Gradients[pId];
	End Method
End Type

Type BGradient3 Abstract
	Field Gradients:BGradient2[];
	
	Method NewInstance:BGradient2(SizeJ:Long, SizeK:Long) Abstract
	
	Method OnCreate:BGradient3(SizeI:Long=2, SizeJ:Long=2, SizeK:Long=2)
		Self.Gradients = New BGradient2[SizeI];
		Local i:Int; For i=0 Until SizeI; Self.Gradients[i] = Self.NewInstance(SizeJ,SizeK); Next;
		Return Self;
	End Method
	
	Method Get:Object(x:Double, y:Double, z:Double)
		If (x<=0) Then Return Self.Gradients[0].Get(y,z);
		If (x>=1) Then Return Self.Gradients[Self.Gradients.Length-1].Get(y,z);
		Local i:Double = x * (Self.Gradients.Length-1);
		Local i0:Int = Floor(i);
		Return Self.Gradients[0].Gradients[0].Interpolate (Self.Gradients[i0].Get(y,z), Self.Gradients[i0+1].Get(y,z), i-i0);
	End Method
	
	Method Gradient2:BGradient2(pId:Long)
		If (pId<0 or pId>=Self.Gradients.Length) Then Return Null;
		Return Self.Gradients[pId];
	End Method
	
	Method Gradient:BGradient(pIdI:Long, pIdJ:Long)
		If (pIdI<0 or pIdI>=Self.Gradients.Length) Then Return Null;
		If (Self.Gradients[pIdI]=Null) Then Return Null;
		Return Self.Gradients[pIdI].Gradient(pIdJ);
	End Method
End Type






' Prototype for Int4 And Float4 arrays
' for colors or vector position ...

Type Int4Gradient Extends BGradient
	Method NewInstance:Object()
		Return New Int[4];
	End Method
	
	Function Create:Int4Gradient(Size:Long=2)
		Return Int4Gradient(New Int4Gradient.OnCreate(Size));
	End Function
	
	' Mandatory -> interpolate between two objects and returns an object
	Method Interpolate:Object(o1:Object,o2:Object,v:Double)
		Local a:Int[] = Int[](o1)
		Local b:Int[] = Int[](o2)
		' returns a new array containing a linear interpolated color/position/...
		Return [Int(a[0]+(b[0]-a[0])*v), Int(a[1]+(b[1]-a[1])*v), Int(a[2]+(b[2]-a[2])*v), Int(a[3]+(b[3]-a[3])*v)];
	End Method
	
	Method Int4:Int[](x:Double)
		Return Int[] (Self.Get(x));
	End Method
End type

Type Int4Gradient2 Extends BGradient2
	Method NewInstance:BGradient(SizeJ:Long)
		Return New Int4Gradient.OnCreate(SizeJ);
	End Method
	
	Function Create:Int4Gradient2(SizeI:Long=2, SizeJ:Long=2)
		Return Int4Gradient2(New Int4Gradient2.OnCreate(SizeI,SizeJ));
	End Function
	
	Method Int4:Int[](x:Double,y:Double)
		Return Int[] (Self.Get(x,y));
	End Method
End Type

Type Int4Gradient3 Extends BGradient3
	Method NewInstance:BGradient2(SizeJ:Long, SizeK:Long)
		Return New Int4Gradient2.OnCreate(SizeJ, SizeK);
	End Method
	
	Function Create:Int4Gradient3(SizeI:Long=2, SizeJ:Long=2, SizeK:Long=2)
		Return Int4Gradient3(New Int4Gradient3.OnCreate(SizeI,SizeJ,SizeK));
	End Function
	
	Method Int4:Int[](x:Double,y:Double,z:Double)
		Return Int[] (Self.Get(x,y,z));
	End Method
End Type




Type Float4Gradient Extends BGradient
	Method NewInstance:Object()
		Return New Float[4];
	End Method
	
	Function Create:Float4Gradient(Size:Long=2)
		Return Float4Gradient(New Float4Gradient.OnCreate(Size));
	End Function
	
	Method Interpolate:Object(o1:Object,o2:Object,d:Double)
		Local a:Float[] = Float[](o1);
		Local b:Float[] = Float[](o2);
		Local v:Float = d;
		Return [a[0]+(b[0]-a[0])*v, a[1]+(b[1]-a[1])*v, a[2]+(b[2]-a[2])*v, a[3]+(b[3]-a[3])*v];
	End Method
	
	Method Float4:Float[](x:Double)
		Return Float[] (Self.Get(x));
	End Method
End type

Type Float4Gradient2 Extends BGradient2
	Method NewInstance:BGradient(SizeJ:Long)
		Return New Float4Gradient.OnCreate(SizeJ);
	End Method
	
	Function Create:Float4Gradient2(SizeI:Long=2, SizeJ:Long=2)
		Return Float4Gradient2(New Float4Gradient2.OnCreate(SizeI,SizeJ));
	End Function
	
	Method Float4:Float[](x:Double,y:Double)
		Return Float[] (Self.Get(x,y));
	End Method
End Type

Type Float4Gradient3 Extends BGradient3
	Method NewInstance:BGradient2(SizeJ:Long, SizeK:Long)
		Return New Float4Gradient2.OnCreate(SizeJ, SizeK);
	End Method
	
	Function Create:Float4Gradient3(SizeI:Long=2, SizeJ:Long=2, SizeK:Long=2)
		Return Float4Gradient3(New Float4Gradient3.OnCreate(SizeI,SizeJ,SizeK));
	End Function
	
	Method Float4:Float[](x:Double,y:Double,z:Double)
		Return Float[] (Self.Get(x,y,z));
	End Method
End Type

Comments

_PJ_2016
By use of cosine, you can produce smoother gradients between similar values or at extremeties.

Assume scale value of 0 to 1
Cos(value*2*Pi)=1 to -1

So Smooth= - (Cos(Value * 2 *Pi)+1) * 0.5


Bobysait2016

See the extended types for more details (they use linear interpolation, but they can be replaced by cos/sin/square interpolation etc ...)


it's up to you to set the interpolate method to use cos interpolation. I used linear because it's faster and only for purpose.

For example, in the Float4Gradient Interpolate method, we just replace
		Local v:Float = d;


by this

( -> result of sin [-Pi/2, +Pi/2] goes from -1 to 1
-> multiply the result by 0.5 to get [-0.5,0.5] range then add 0.5 to get [0.0,1.0]. And simple as that, you have your smooth interpolation )

		Local v:Float = 0.5+0.5*Sin(d*180-90); ' sinus interpolation smooth up -> higher medium -> smooth down



Code Archives Forum