Unintentional shortening (truncating) values in GraphicPath.AddLine - c#

I'm loading coordinate values with GraphichsPath.AddLine command, then drawing them and I've noticed my map is not quite accurate.
The code in question is as follows. I'm casting start and end coordinates from double to float since the command takes only float values, then multiplying them so they scale better:
GraphicsPath gp = new GraphicsPath();
gp.AddLine((float)(line.startX*10000), (float)(line.startY * 10000),
(float)(line.endX * 10000), (float)(line.endY * 10000));
For example, startX value is 15.742560625076294 but when i check the gp path data in debugger, I see it as 157425.609. The last 7 digits are shortened. And they are crucial because the difference in meters is important in this case.
Is this the limitation of a float value as opposed to double? How can I load the full values in said command?

Related

How to I calculate clock-angle on x-y axis using C#?

We have a monitoring application that can monitor in intervals like 5 minutes, 15 minutes, 1 hour, etc. That's represented on the x-axis; The y-axis is also scalable and have values like 1.2345 - 1.5567 or can be switched to values like 26000 - 30000, etc.
Once the scale is set on the x and y axis, they don't dynamically change without a whole complete data refresh.
That being said, we only want certain people to be notified depending on the clock angle, of say, the last 5 intervals along the y axis.
The clock angles will never go counter-clockwise past 0/12; likewise, they'll never go past 6 clockwise.
I know the 3 o'clock angle is obvious when the x axis value is exactly the same as it was 5 intervals ago.
But how does one even start coding for everything in between? I can get the differences in x values easily (in the example graphic below, it's 0.3), and the difference in the y-axis in the below graphic is 4.
So with trigonometry that's opposite over adjacent, which means a tan operation I believe? If so, 0.3/5 doesn't seem to yield any values that seem like a clock angle.
Since I can't get any farther than that, I have no idea how it would be coded in C# other than calculating the differences.
Any help would be greatly appreciated!
You should be using atan2 (wiki , docs)
From the wiki:
atan2(y, x) returns the angle θ between the ray to the point (x, y) and the positive x axis, confined to (−π, π]
Note that the result is in radians, so you need to convert it if you want degrees
As stated, one radian is equal to 180/π degrees. Thus, to convert from radians to degrees, multiply by 180/π.
A couple of things here. First I think what you are asking for is the angle φ below, given two data points (x1,y1) and (x2,y2).
The problem here is that the angle is measuring the indicated triangle in pixels and not in x, y units.
So it is incorrect to do var φ = Math.Atan( (y2-y1)/(x2-x1) ); because the x and y axis have different units and angles are always dimensionless.
What additional information is needed, is the size of the graph area in pixels, as well as the range of values. Alternatively, the scaling gx,gy in pixels/unit for both axis.
For example, if the x-axis needs 45 pixels to span 1 grid of 1 hour (60 minutes) then te scaling is double gx = 45/60.0, and if the y-axis needs also 45 pixels to span 1 grid of 0.1 value then double gy = 45/0.1.
Then you can use this to calculate the sides of the triangle in pixels before calculating the angle
var adjacent = gx*(x2-x1); // convert x-axis units to pixels
var opposing = gy*(y2-y1); // convert y-axis units to pixels
var φ = Math.Atan(addjacent/opposing) * (180/Math.PI);
The last part calculates the angle φ and converts it from radians to degrees.

Convert value to Angle with maximum value

I made a speedometer control My controller has a property called Angle that changes the shape of my speedometer (180 for Complete Circul, and so on...)
With the help of a converter, I can move the speedometer correctly
// values[0] = Angle
// values[1] = Value
var startAngle = System.Convert.ToDouble(values[0]) * -1;
var endAngle = startAngle + (((double)values[1]) * 2);
return endAngle;
Now I want to have a property called Maximum, And if the user sets it to 50, even if my circle is 360 degrees, the whole circle will be full with 50 values.
I used the following code but unfortunately it does not work properly
return value * angle / maximum;
also this is my arc
<x:Arc StartAngle="{Binding Angle, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource Positive2Nagative}}" EndAngle="{Binding Angle, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
UPDATE:
this code:
//a = s * A / max
value * angle / maximum;
Compile to this:
<loc:speedometer Angle="120" MaximumValue="50" Value="{Binding ElementName=sld, Path=Value}"
/>
UPDATE 2:
i fixed problem with this code
return ((value * angle / maximumValue * 2) - angle);
You're using a very strange notation for this.
Let's call a change in value of 1 a step. So 50 km/h maximum means 50 steps.
You want 50 steps between the start and end.
Your first task is to work out angle per step.
For that you need to know the angle the entire arc will go through.
If the start is always over there on the left of the vertical line then it's always negative.
Hence you want -1 * start for the left number of degrees offset from vertical.
The right is easy it's just end.
Hence (-1 * start) + end = totalArc degrees
That gives you how many degrees the 0 to max covers.
Let's call the thing you're representing speed. Because angle is a very very bad name for a variable in a calculation which is all about angles.
totalArc / maximum gives the value in degrees of each step in our speed.
Hence you want (totalArc / maximum) * speed.
That gives you the angle between the start and where the speed indicator should go to.
You will then have to work out what that means in terms of your display.
I would suggest the simplest is to rotatetransform whatever does the red stuff so 0 angle matches the start. Maybe you're already doing that though.
I think you are looking for the following:
Given an angle a, the equivalent value s, considering A degrees repesents the maximum value max, is:
s = a * max / A
Or what is pobably more useful, the angle a which reprenets a given speed s in a A degree speedometer with a maximum speed max is:
a = s * A / max
That said, I'm not really sure how your speedometer works. At first you talk about a 180º gauge and then you start talking about a full 360º one. Either way, A is either 180 or 360.

Float Values Either Defaulting To 1 or 0

I am trying to work out something for CellSize in Unity.
This is for the GridLayoutGroup component. I found something that when done with a calculator works perfectly fine: Screen.Width/1280 , Screen.Height/720.
Since I am using 720p as the base resolution and everything looks fine on there I use it as a base. 100x100 looks great for cell size on 720p.
For example their resolution is 1280:1024
It should come out (100, 142) However it always comes out (1.0, 1.0).
If the resolution is tiny... such as 320x200 it comes out (0.0, 0.0).
Here is my code:
SlotPanel.GetComponent<GridLayoutGroup>().cellSize = new Vector2((Cam.pixelWidth / 1280) * 100, (Cam.pixelHeight / 720) * 100);
Cam is the Camera that the player uses.
Another code that I tried was:
SlotPanel.GetComponenet<GridLayoutGroup>().cellSize = new Vector2((Screen.Width / 1280) * 100, (Screen.Height / 720) * 100);
Both result in the same issue. At this point I am at a loss of words for how annoyed I am. I don't understand why the math is right, but it does not work right.
Cam.pixelWidth / 1280 &c. is evaluated in integer arithmetic; any remainder is discarded.
Rewrite to 100.0 * Cam.pixelWidth / 1280 to ensure the evaluation takes place in floating point (due to promotion of the two integral arguments). There are other ways, but I find this one to be clearest since changing the first coefficient tells a reader of your code from the get-go what you want to do.
(If you require the type of the expression to be a single precision floating point type then use 100f in place of 100.0).
This is one of those cases where using excess parentheses is actually harmful.

C# - Numeric Variable Types - Base 2/Base 10 notations

there is one little thing making me puzzle in c# :)
Here is my variables & results:
decimal a1 = 0.2M;
decimal a2 = 1.0M;
a1 - a2 = -0.8
float b1 = 0.2F;
float b2 = 1.0F;
b1 - b2 = -0.8
double c1 = 0.2;
double c2 = 1.0;
c1 - c2 = -0.8
double x1 = 0.2F;
double x2 = 1.0F;
x1 - x2 = -0.799999997019768
Decimal - result is as expected for me, knowing that they work in base 10 notations.
Float - Surprised me, knowing it works on base 2 notation it actually shows result
as if it worked as base 10 notation with out loosing precision.
Double c - Same thing as for Float.
Double x - shows result that I would expect for Float to take place.
The Question is what's going on with Float, Double 'c' and 'x' groups? Why Double 'x' group lost its precision while Float group actually calculated in base 10 notation giving so to speak "expected" result from calculation? Wondering why declaring number types of Double x group as F so drastically changed its out come?
for what it worth I would only expect Decimal group give me '-0.8' result and all others some thing to '-0.799999997019768'.
looks like I'm missing some link of understanding that takes place in how calculation was taking care of.
First off - this has nothing to do with base 2 vs. base 10. All of your values are represented using base 10. Base 2 is not used whatsoever in this code.
looks like I'm missing some link of understanding that takes place in how calculation was taking care of.
Both float and double using a floating point representation for numbers, which is not 100% accurate. When you display the value, there is rounding taking place. Since float has inherently less precision, it's rounded to fewer decimal points, which can make it "appear" more accurate in some cases (even though it's actually less precise).
In your case, the reason the "x" group and the "c" group display differently is that you're declaring your x1 and x2 variables like so:
double x1 = 0.2F;
double x2 = 1.0F;
This is, effectively, the same as doing:
float temp = 0.2f;
double x1 = temp; // Convert from float to double, which has a loss of precision
temp = 1f;
double x2 = temp; // Convert from float to double, which has a loss of precision
As such, x1 and x2 do not have exactly the same values as c1 and c2. This is causing even more loss of precision, which later, when the subtraction occurs, is enough that the printing doesn't round anymore.
A good article to read if you want to truly understand this is What Every Computer Scientist Should Know About Floating-Point Arithmetic. Most common programming languages use similar representations for floating point numbers, so the issues are fairly universal.
There is a longstanding source of programmer confusion in C# that the language spec allows most intermediate operations on floating-point values to be carried out with extra precision. Compilers often do this in order to speed things up, because many processors are faster that way. I don't know the specific details well (someone who does can feel free to correct me if I'm wrong), but it seems likely that the calculations in the b section are using this extra precision.
In the x group, the double variables already have the extra precision, but putting a float-type constant into them may well be causing the compiler to behave subtly differently, leading to the less-precise results. Since the doubles are already slightly off from where they should be, the full double precision is simply carrying the error forward.
Ultimately, floating-point precision in C# is very much not something to be explicitly relied upon, as the compiler has a lot of leeway to adjust things slightly as it chooses, however it thinks will optimize best, as long as it provides the minimum amount of precision spelled out in the spec.
Oh, and none of this has anything to do with base 2.

"Converting" float to double in C#

I have property for the life of an particle (I'm simulating particle systems) which is a float value, because I also use it for transparency (alpha is float). I have read questions about converting float to double and realized that it is quite a problem, so I'll probably can't convert float to double. Problem is that I want try to calculate path of the particle from the life variable like:
particle.x += particle.xi;
particle.xi = Math.Sin(life);
Note: life value is at the beginning 1.0f and decreasing to 0 (if its <0.0f I reinitialize the particle and set the life to 1.0f).
But the Sin wants the the double value ... and we are back at the beginning.
So one solution can be changing the type of life property to double and when I use it for transparency I will just this double convert to float which shouldn't be big problem (I guess).
But my question is if is there any other way to do it, cause double also cost more memory (I don't know what more means in this case - I guess to times more, lets say I'll have 500 particles and each will have this property). I just need somehow calculate sin value from this float property.
So is it possible? Are my concerns about memory important?
This should work:
particle.x += particle.xi;
particle.xi = (float) Math.Sin(life);
It doesn't "use more memory", it simply converts the value to a double temporarily while it's recalculating it, then converts it back to a float when it goes to store the value.
To go into a bit more detail: that Math.Sin requires a double, but the float can be converted to this higher precision without loss, so it just "magically works" (an implicit cast from float to double). However, to convert the resulting double back to a float, you will be reducing the precision of the number and so the compiler (which doesn't know if this will be acceptable to you) won't do it unless you force it to (by using (float) which is an explicit cast from double to float).

Categories

Resources