Reputation: 59
I created 2 GeoCoordinate
objects, LocA
and LocB
. I am continually updating the location info in LocA and LocB by using a timer and storing the values in a tuple list. In my code, LocA
is the last added point and LocB
is the second to last added point.
But I always face an exception during runtime.
How can I prevent this?
Here is my code;
public partial class Form1 : Form
{
List<Tuple<double, double>> myTuple2 = new List<Tuple<double, double>>();
GeoCoordinate LocA, LocB;
private void timer1_Tick(object sender, EventArgs e)
{
myTuple2.Add(new Tuple<double, double>(Convert.ToSingle(gPathBoylam), Convert.ToSingle(gPathEnlem)));
//gPathBoylam=Longitude info coming from gps,
//gPathEnlem=Lattitude info coming from gps,
if (myTuple2 != null && myTuple2.Any())
{
for (int i = 1; i < myTuple2.Count; i++)
{
LocA = new GeoCoordinate(myTuple2[i].Item1, myTuple2[i].Item2);
LocB = new GeoCoordinate(myTuple2[i-1].Item1, myTuple[i-1].Item2);
}
}
Upvotes: 0
Views: 676
Reputation: 13783
The problem you are experiencing is twofold:
for
loop is completely unnecessary as you are continually overwriting the same variables. After the for
loop has run, you will only have the results of the last iteration. Since your code does not care about the outcome of the previous iterations (since it blindly ignores and overwrites it), you should avoid performing them.Let me elaborate on both:
1 - Remove the for loop
Let's say you have 4 items in your list. You then run the for
loop:
for (int i = 1; i < myTuple2.Count; i++)
{
LocA = new GeoCoordinate(myTuple2[i].Item1, myTuple2[i].Item2);
LocB = new GeoCoordinate(myTuple2[i-1].Item1, myTuple[i-1].Item2);
}
Let me work out the iteration, number by number, so you see where you are going wrong.
//i = 1
LocA = new GeoCoordinate(myTuple2[1].Item1, myTuple2[1].Item2);
LocB = new GeoCoordinate(myTuple2[0].Item1, myTuple[0].Item2);
//i = 2
LocA = new GeoCoordinate(myTuple2[2].Item1, myTuple2[2].Item2);
LocB = new GeoCoordinate(myTuple2[1].Item1, myTuple[1].Item2);
//i = 3
LocA = new GeoCoordinate(myTuple2[3].Item1, myTuple2[3].Item2);
LocB = new GeoCoordinate(myTuple2[2].Item1, myTuple[2].Item2);
//the for loop stops here because when i = 4; it violates the "i < tuples.Count" condition
There is no point to the first two times where you set LocA
and LocB
. You overwrite the values immediately. So instead, just do the last iteration manually:
int lastItemIndex = myTuple.Count - 1;
int secondToLastItemIndex = lastItemIndex - 1;
LocA = new GeoCoordinate(myTuple2[lastItemIndex].Item1, myTuple2[lastItemIndex].Item2);
LocB = new GeoCoordinate(myTuple2[secondToLastItemIndex].Item1, myTuple[secondToLastItemIndex].Item2);
Note: You will want to add checks to prevent errors if there is only 1 item in the list. I kept my example simple to address the core issue
2 - The exception you see
The exception you see tells you the following:
System.ArgumentOutOfRangeException
The value of the parameter must be from -180.0 to 180.0
This is not a standard .Net exception. This is a custom exception that is being thrown intentionally. And the message of the exception reveals the problem:
Both latitude and longitude can only have relevant values between -180 and +180. Any number greater or smaller than this range is "incorrect" since there can only be a range of 360° in a circle.
LocA = new GeoCoordinate(-15, 75); //correct
LocA = new GeoCoordinate(0, 180); //correct
LocA = new GeoCoordinate(525, 12545); //INCORRECT (as per the exception message)
My GUESSES as to the cause of this issue:
1 There is a culture difference between the decimal ,
(comma) and .
(dot). If this is the case, a value like 175,5
might be parsed as 1755
. You need to make sure that this is not an issue.
Stop reading here and check this first. If this is the case, nothing else can help you except fixing the culture issue.
2 There could be something seriously wrong with your data. Maybe you are getting nonsensical numbers. I highly suggest using breakpoints to see which values you are getting. You might be getting garbage numbers that have no meaning.
If this is the case, you will have to read the GPS documentation.
It's not your fault that the data you are provided with is incorrect. However, it should be your duty to make sure that an unexpected value does not crash the system and instead handles this internally (or gives feedback to the user in a nice way).
3 The GPS is returning values between 0 and 360, but your library wants values between -180 and 180. (This is the most likely example. Technically speaking, your GPS could return values from any arbitrary range that spans 360°, but it seems weird to use anything other than (0)<->(360)
or (-180)<->(180)
.
It's possible to calculate the correct number based on an incorrect value by adding or subtracting 360° until you get in the correct range. E.g. a value of 359° can be converted to a value of -1°.
So the question becomes: how do I make sure that my value is between -180 and +180? Here's a simple method that will ensure your value is within the proper range:
public static double NormalizeAngle(double theAngle)
{
if(theAngle <= -180)
{
//we keep adding 360° until we reach an acceptable value.
while(!IsValidAngle(theAngle))
{
theAngle += 360;
}
return theAngle;
}
if(180 <= theAngle)
{
//we keep subtracting 360° until we reach an acceptable value.
while(!IsValidAngle(theAngle))
{
theAngle -= 360;
}
return theAngle;
}
//if neither if block was entered, then the angle was already valid!
return theAngle;
}
private static bool IsValidAngle(double theAngle)
{
return (-180 <= theAngle) && (theAngle <= 180);
}
If you add this (somewhere in your code base), you can then do the following:
LocA = new GeoCoordinate(
NormalizeAngle(myTuple2[lastItemIndex].Item1),
NormalizeAngle(myTuple2[lastItemIndex].Item2)
);
LocB
is the same of course.
Upvotes: 2