Reputation: 86
I'm trying to create a radial FAB menu, and to define the positions for all of the circles I have an algorithm which in theory works just fine, however when I actually run it, the Y value gives me something strange.. I'll post my code real quick
NOTE THAT THIS PART DOESN'T REALLY MATTER UNLESS YOU NEED REFERENCE AS TO WHAT A VALUE MEANS
public class FABContainer : AbsoluteLayout
{
public static int NUMBER_FOR_RING = 1;
public static double ANGLE_INCREMENT = 360.0 / ((double)NUMBER_FOR_RING);
public static double CENTER_RADIUS = 100;
public static double WIDTH_MOD = 0.9;
public FABContainer()
{
this.BackgroundColor = Color.Transparent;
FAB fab = new FAB();
List<InternalFAB> internals = new List<InternalFAB>();
internals.Add(new InternalFAB(this, internals.Count)
{
});
this.Children.Add(fab);
foreach(InternalFAB f in internals) { this.Children.Add(f); };
}
}
public partial class FAB : SuaveControls.Views.FloatingActionButton
{
public FAB()
{
this.HeightRequest = FABContainer.CENTER_RADIUS;
this.WidthRequest = FABContainer.CENTER_RADIUS * FABContainer.WIDTH_MOD;
Debug.WriteLine($"CREATING NEW CENTER WITH W: {this.WidthRequest} H: {this.HeightRequest}");
this.Image = "Edit_Icon.png";
this.BackgroundColor = Color.Transparent;
this.CornerRadius = (int)this.HeightRequest;
}
}
internal class InternalFAB : SuaveControls.Views.FloatingActionButton
{
public static double DIST = 5;
public EventHandler OnClicked;
public static double radius = 80;
public InternalFAB(FABContainer container, int count)
{
this.HeightRequest = (radius);
this.WidthRequest = (radius * FABContainer.WIDTH_MOD * 0.95);
this.BackgroundColor = Color.Transparent;
int index = count + 1;
double AngleDistortion = ((double)index) * FABContainer.ANGLE_INCREMENT;
double xpos = (DIST + this.WidthRequest) * (Math.Cos((Math.PI / 180.0) * AngleDistortion));
double ypos = (DIST + this.HeightRequest) * (Math.Sin((Math.PI / 180.0) *AngleDistortion));
Debug.WriteLine($"CREATING NEW INTERNAL AT: {xpos},{ypos} from distortion {AngleDistortion}");
this.TranslationX = xpos;
this.TranslationY = ypos;
}
}
By the way it shouldn't matter but this is using Xamarin. Essentially the part that actually matters and is giving me a problem is this part:
double AngleDistortion = ((double)index) * FABContainer.ANGLE_INCREMENT;
double xpos = (DIST + this.WidthRequest) * (Math.Cos((Math.PI / 180.0) * AngleDistortion));
double ypos = (DIST + this.HeightRequest) * (Math.Sin((Math.PI / 180.0) *AngleDistortion));
Debug.WriteLine($"CREATING NEW INTERNAL AT: {xpos},{ypos} from distortion {AngleDistortion}");
For whatever reason, the Y value is returning as -2.08183080149804E-14 rather than the 0 that it is supposed to return in a "perfect" case. I ran through my code extensively to try to find the error to no avail.
If you need any more clarifications about my code, I'll tell you them right away.
Upvotes: 0
Views: 191
Reputation: 64904
The multiplication by 85 is not important to this issue, so I will leave that aside and just look at (effectively) Math.Sin(Math.PI * 2)
. The result of that is -2.44921270764475E-16
on my machine.
That floating point arithmetic is not exact plays a role of course, but the result is not some arbitrary nonsense. What happens here is that in close proximity to x = 2pi, sin(x)≈x - 2pi. However, Math.Sin(Math.PI * 2)
does not evaluate the sine at precisely 2pi, it cannot, 2pi is transcendental and definitely not representable as a floating point number. The input to the sine is already slightly "off", and has some value v=fl(2pi)
where fl
rounds a value to the nearest representable floating point number. Then sin(v) ≈ v - 2pi
, because v
is near 2pi.
So the result of Math.Sin(Math.PI * 2)
should approximately represent how far the 2 pi that we passed in as argument is off from the real 2 pi. Math.PI * 2
has an exact value of 6.28318530717958623199592693708837032318115234375 on my machine, according to Wolfram Alpha that is -2.4492935982947063544521318645500... × 10^-16 off from the real 2 pi, which is pretty close to that -2.44921270764475E-16
value from earlier. It's not exactly there, but close enough to make the point that it's not just something arbitrary.
Upvotes: 0
Reputation: 439
You are working with doubles, performing floating point arithmetic. Meaning everything you do is approximated. If you want exact values, maybe C# isn't your goto language. Mathematica has support for these kinds of values.
Upvotes: 4