我创建了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);
}
}
答案 0 :(得分:1)
您遇到的问题有两个:
for
循环完全没必要。运行for
循环后,您将只获得最后次迭代的结果。由于您的代码不关心先前迭代的结果(因为它盲目地忽略并覆盖它),您应该避免执行它们。让我详细说明两者:
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);
注意:如果列表中只有1个项目,您将需要添加检查以防止错误。我让我的例子很简单,以解决核心问题
2 - 您看到的例外情况
您看到的异常会告诉您以下内容:
System.ArgumentOutOfRangeException
参数的值必须为-180.0到180.0
这不是标准的.Net异常。这是一个故意抛出的自定义异常。异常的消息揭示了问题:
纬度和经度都只能在-180和+180之间具有相关值。任何大于或小于此范围的数字都是“不正确的”,因为圆圈中只能有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文档。
您提供的数据不正确并不是您的错。但是,您应该确保意外的值不会导致系统崩溃,而是在内部处理(或以漂亮的方式向用户提供反馈)。
3 GPS返回0到360之间的值,但是您的库需要介于-180和180之间的值。(这是最可能的示例。从技术上讲,您的GPS可以返回任何值跨越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
当然是一样的。