Home > Mobile >  How do i simplify this math method (rotations to steps)
How do i simplify this math method (rotations to steps)

Time:04-20

So I am creating a snapping toolkit for unity, and I want to constrain snapping increments for rotations by specific values.

You can snap the rotations by increments of 2.5, 5, 10, 15, 30, 45 and 90 (so that when the user rotates an object, it will only rotate by that increment value).

I have a toolbar with a slider, the slider has 7 steps (0-6), each step representing a rotation. So I need to convert rotations to steps.

Image of slider

The code and functionality is done, but the functions for converting rotation to steps and vice versa is quite long and ugly. Is it possible to simplify/shorten it?

Steps and rotations:

Step Rotation
0 2.5
1 5
2 10
3 15
4 30
5 45
6 90

Code:

        private float ConvertFromStepToRotation(int step)
    {
        switch (step)
        {
            case 0:
                return 2.5f;
            case 1:
                return 5;
            case 2:
                return 10;
            case 3:
                return 15;
            case 4:
                return 30;
            case 5:
                return 45;
            case 6:
                return 90;
        }

        return 15;
    }

    private int ConvertFromRotationToStep(float rotation)
    {
        if (rotation >= 90)
        {
            return 6;
        }

        if (rotation >= 45)
        {
            return 5;
        }

        if (rotation >= 30)
        {
            return 4;
        }

        if (rotation >= 15)
        {
            return 3;
        }

        if (rotation >= 10)
        {
            return 2;
        }

        if (rotation >= 5)
        {
            return 1;
        }

        if (rotation >= 2.5f)
        {
            return 0;
        }

        return 2;
    }

Not a big deal, it just nags me that there should be a better way

edit: trying to get the table to work

CodePudding user response:

Looks like we could make this prettier with an array.

ConvertFromStepToRotation is an obvious candidate: we're just turning an index into a corresponding value, so we can use that to index into an array of values.

ConvertFromRotationToStep is slightly more tricky, but we can just loop through the array backwards, and return the first index for which rotation >= steps[i].

private static readonly float[] steps = new[] { 2.5f, 5f, 10f, 15f, 30f, 45f, 90f };

private float ConvertFromStepToRotation(int step)
{
    if (step < steps.Length)
    {
        return steps[step];
    }
    
    return 15f;
}

private int ConvertFromRotationToStep(float rotation)
{
    for (int i = steps.Length - 1; i >= 0; i  )
    {
        if (rotation >= steps[i])
        {
            return i;
        }
    }
    
    return 2;
}

CodePudding user response:

For a nice paranoid solution, the step s can be obtained from the angle a by the one-liner

s = floor(log(a)/log(√3)-1.5).

CodePudding user response:

In the scenario where you cannot rely on array indices (or you want better control over which step refers to which rotation), you could alternatively store the relations in a dictionary:

//using System.Collections.Generic;

private Dictionary<int, float> rotationForStep = new()
{
    [0] = 2.5f,
    //...
    [6] = 90
};

And implement your methods e.g. as follows:

//using System.Linq;

private float ConvertFromStepToRotation(int step)
{
    if (rotationForStep.TryGetValue(step, out float rotation))
    {
        return rotation;
    }
    
    return 15;
}

private int ConvertFromRotationToStep(float rotation)
{
    if (rotationForStep.Values.Any(v => v <= rotation))
    {
        return rotationForStep
            .Where(r => r.Value <= rotation)
            .MaxBy(r => r.Value)
            .Key;
    }
    
    return 2;
}

Alternatively for the last method:

//using System.Linq;

private int ConvertFromRotationToStep(float rotation)
{
    var possibleRotations = rotationForStep.Where(r => r.Value <= rotation);
    
    if (possibleRotations.Any())
    {
        return possibleRotations.MaxBy(r => r.Value).Key;
    }
    
    return 2;
}
  • Related