Search code examples
javagenericsnumberstween

Generic Number Tweening (Help me do one strange trick..)


I am trying to make as generic as possible method for tweening between various types of values.

So, given a start and end value thats, say, either an Int,Float or Double as well as the number of steps (int), it will return values evenly distributed along those steps in the same type.

However, I am starting to suspect;

a) My knowledge of generics is terrible.

b) This might not be possible :(

So, just to be clear, one example;

SpiffyTween<Double> meep = new SpiffyTween<Double>(1d,10d, 100);

while (meep.hasNext()){
        Log.info("value="+meep.next());
}

Would return 0.0,0.1,0.2..etc upto 9.9

But SpiffyTween could also work with other number types without needing separate code for each.

Heres the code I have right now;

class SpiffyTween<T extends Number> implements SpiffyGenericTween<T>
{

static Logger Log = Logger.getLogger("SpiffyTween <Number>");

private T start;
private T end;
int totalsteps=0;

int CurrentStep = 0;
ArrayList<T> steps = new ArrayList<T>();

public SpiffyTween(T start,T end, int steps) {

    this.start = start;
    this.end = end;
    this.totalsteps = steps;

    precalculate();

}



private void precalculate() {

    //calc step difference 
    double dif = ((end.doubleValue() -start.doubleValue())/totalsteps);

    Log.info("dif="+dif);

    int i=0;
    while(i<totalsteps){


        T stepvalue = (T)((Number)(start.doubleValue() +(dif*i)));


        steps.add(stepvalue);


        Log.info("add step="+stepvalue);
        i++;
    }



}


public T next(){

    T currentVal = steps.get(CurrentStep);
    CurrentStep++;      

    return currentVal;

}


@Override
public boolean hasNext() {
    if (CurrentStep<totalsteps){
        return true;
    }
    return false;
}



}

This works...ish. While the numbers come out aproximately right occasionally theres values like; 9.600000000000001 or 2.4000000000000004

I am assuming thats to do with the unchecked type conversion here;

        T stepvalue = (T)((Number)(start.doubleValue() +(dif*i)));

But I cant work out how to do it better.

Whatever the solution (if theres one), my longterm plan is to try to make similar code that can also work on arrays of various number types. So, you could tween between 3 dimensional points by feeding it an array of the x/y/z co-ordinates of the start and end.

Also, possibly more relevantly, in the code example here its basic addition being done. I probably want other types of tweening possible, so that would make the maths more complex. Is the better route to convert to, say, BigNumber, and then (somehow) back to the initial T later after all the processing is done?

Thanks in advance for any help or pointers.


Solution

  • YOu don't really need Generics to write code once. Consider the code below. Your exercise is to extend to other dimensions and to ensure caller does not use less than one step:

    Tween Class

    package com.example.stepup;
    public class Tween {
        public static int[] get1DimSteps (int start, int end, int steps) {
            double[] preciseResult = get1DimSteps((double) start, (double) end, steps);
            int[] result = new int[steps];
            for (int i=0; i<steps; i++) {
                result[i] = (int) (preciseResult[i] + 0.5D);
            }
            return result;
        }
    
        public static double[] get1DimSteps (float start, float end, int steps) {
            double[] result = get1DimSteps((double)start, (double)end, steps);
            return result;
        }
    
        public static double[] get1DimSteps (double start, double end, int steps) {
            double distance;
            double stepSize;
            double[] result = new double[steps];
    
            distance = end - start;
            stepSize = distance / steps;
            for (int i=0; i < steps; i++) {
                result[i] = start + stepSize*i;
            }
            return result;
        }
    }
    

    StepupTest Class

    package com.example.stepup;
    public class StepupTest {
        public static void main(String[] args) {
            // get steps from "start" to "finish"
    
            int startI = -1;
            int endI =999;
            float start = (float) startI;
            float end = (float) endI;
            double startD = (double) startI;
            double endD = (double) endI;
            int numberOfSteps = 100;
    
            double[] steps = Tween.get1DimSteps( start, end, numberOfSteps);
            double[] stepsD = Tween.get1DimSteps(startD, endD, numberOfSteps);
            int[] stepsI = Tween.get1DimSteps(startI, endI, numberOfSteps);
    
            for (int i=0; i < numberOfSteps; i++) {
                System.out.println(" " + i + ". " + steps[i] + ", " + stepsD[i] + ", " + stepsI[i]);
            }
        }
    }