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.
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;
}