为什么我的 GeoCoordinate 值不在正确的范围内?
Why are my GeoCoordinate values not in the correct range?
我创建了 2 个 GeoCoordinate
对象,LocA
和 LocB
。我通过使用计时器并将值存储在元组列表中来不断更新 LocA 和 LocB 中的位置信息。在我的代码中,LocA
是最后添加的点,LocB
是倒数第二个添加的点。
但是我在运行时总是遇到异常。
我怎样才能避免这种情况?
这是我的代码;
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);
}
}
您遇到的问题是双重的:
for
循环完全没有必要,因为您会不断地覆盖相同的变量。在 for
循环有 运行 之后,您将只有 last 迭代的结果。由于您的代码不关心先前迭代的结果(因为它会盲目地忽略并覆盖它),因此您应该避免执行它们。
- 您看到的异常与您的代码无关,而是与您从 GPS 收到的 数据 有关。
让我详细说明一下:
1 - 删除 for 循环
假设您的列表中有 4 个项目。然后你 运行 for
循环:
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);
}
让我逐个计算迭代次数,这样您就知道哪里出错了。
//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
前两次设置 LocA
和 LocB
没有意义。您立即覆盖这些值。因此,只需手动执行最后一次迭代:
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);
注意:如果列表中只有一项,您需要添加检查以防止出错。为了解决核心问题,我让示例保持简单
2 - 您看到的异常
您看到的异常告诉您以下内容:
System.ArgumentOutOfRangeException
The value of the parameter must be from -180.0 to 180.0
这不是标准的 .Net 异常。这是有意抛出的自定义异常。异常消息揭示了问题:
纬度和经度只能有-180到+180之间的相关值。任何大于或小于这个范围的数字都是"incorrect",因为一个圆只能有360°的范围。
LocA = new GeoCoordinate(-15, 75); //correct
LocA = new GeoCoordinate(0, 180); //correct
LocA = new GeoCoordinate(525, 12545); //INCORRECT (as per the exception message)
我对这个问题原因的猜测:
1 小数点 ,
(逗号)和 .
(点)之间存在文化差异。如果是这种情况,像 175,5
这样的值可能会被解析为 1755
。您需要确保这不是问题。
先看这里。如果是这种情况,除了解决文化问题,没有别的办法可以帮助您。
2 您的数据可能存在严重错误。也许你得到了无意义的数字。我强烈建议使用断点来查看您获得的值。您可能会收到毫无意义的垃圾号码。
如果是这种情况,您将必须阅读 GPS 文档。
提供给您的数据不正确不是您的错。但是,您有责任确保意外值不会使系统崩溃,而是在内部处理(或以 nice 方式向用户提供反馈)。
3 GPS returning 值介于 0 和 360 之间,但您的图书馆需要介于 -180 和 180 之间的值。(这是最可能的示例。从技术上讲,您的 GPS 可以 return 跨越 360° 的任意范围内的值,但是使用 (0)<->(360)
或 (-180)<->(180)
.
以外的任何值似乎很奇怪
通过加减 360° 直到达到正确的范围,可以根据不正确的值计算出正确的数字。例如。 359° 的值可以转换为 -1° 的值。
所以问题就变成了:如何确保我的值在-180和+180之间?这是一个简单的方法,可以确保您的值在适当的范围内:
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);
}
如果您添加此内容(在您的代码库中的某处),您可以执行以下操作:
LocA = new GeoCoordinate(
NormalizeAngle(myTuple2[lastItemIndex].Item1),
NormalizeAngle(myTuple2[lastItemIndex].Item2)
);
LocB
当然是一样的
我创建了 2 个 GeoCoordinate
对象,LocA
和 LocB
。我通过使用计时器并将值存储在元组列表中来不断更新 LocA 和 LocB 中的位置信息。在我的代码中,LocA
是最后添加的点,LocB
是倒数第二个添加的点。
但是我在运行时总是遇到异常。
我怎样才能避免这种情况?
这是我的代码;
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);
}
}
您遇到的问题是双重的:
for
循环完全没有必要,因为您会不断地覆盖相同的变量。在for
循环有 运行 之后,您将只有 last 迭代的结果。由于您的代码不关心先前迭代的结果(因为它会盲目地忽略并覆盖它),因此您应该避免执行它们。- 您看到的异常与您的代码无关,而是与您从 GPS 收到的 数据 有关。
让我详细说明一下:
1 - 删除 for 循环
假设您的列表中有 4 个项目。然后你 运行 for
循环:
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);
}
让我逐个计算迭代次数,这样您就知道哪里出错了。
//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
前两次设置 LocA
和 LocB
没有意义。您立即覆盖这些值。因此,只需手动执行最后一次迭代:
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);
注意:如果列表中只有一项,您需要添加检查以防止出错。为了解决核心问题,我让示例保持简单
2 - 您看到的异常
您看到的异常告诉您以下内容:
System.ArgumentOutOfRangeException
The value of the parameter must be from -180.0 to 180.0
这不是标准的 .Net 异常。这是有意抛出的自定义异常。异常消息揭示了问题:
纬度和经度只能有-180到+180之间的相关值。任何大于或小于这个范围的数字都是"incorrect",因为一个圆只能有360°的范围。
LocA = new GeoCoordinate(-15, 75); //correct
LocA = new GeoCoordinate(0, 180); //correct
LocA = new GeoCoordinate(525, 12545); //INCORRECT (as per the exception message)
我对这个问题原因的猜测:
1 小数点 ,
(逗号)和 .
(点)之间存在文化差异。如果是这种情况,像 175,5
这样的值可能会被解析为 1755
。您需要确保这不是问题。
先看这里。如果是这种情况,除了解决文化问题,没有别的办法可以帮助您。
2 您的数据可能存在严重错误。也许你得到了无意义的数字。我强烈建议使用断点来查看您获得的值。您可能会收到毫无意义的垃圾号码。
如果是这种情况,您将必须阅读 GPS 文档。
提供给您的数据不正确不是您的错。但是,您有责任确保意外值不会使系统崩溃,而是在内部处理(或以 nice 方式向用户提供反馈)。
3 GPS returning 值介于 0 和 360 之间,但您的图书馆需要介于 -180 和 180 之间的值。(这是最可能的示例。从技术上讲,您的 GPS 可以 return 跨越 360° 的任意范围内的值,但是使用 (0)<->(360)
或 (-180)<->(180)
.
通过加减 360° 直到达到正确的范围,可以根据不正确的值计算出正确的数字。例如。 359° 的值可以转换为 -1° 的值。
所以问题就变成了:如何确保我的值在-180和+180之间?这是一个简单的方法,可以确保您的值在适当的范围内:
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);
}
如果您添加此内容(在您的代码库中的某处),您可以执行以下操作:
LocA = new GeoCoordinate(
NormalizeAngle(myTuple2[lastItemIndex].Item1),
NormalizeAngle(myTuple2[lastItemIndex].Item2)
);
LocB
当然是一样的