为什么我的GeoCoordinate值不在正确的范围内?

时间:2017-05-24 08:27:39

标签: c# winforms tuples latitude-longitude

我创建了2个GeoCoordinate个对象,LocALocB。我通过使用计时器并将值存储在元组列表中,不断更新LocA和LocB中的位置信息。在我的代码中,LocA是最后添加的点,LocB是倒数第二个添加点 但是我总是在运行时遇到异常。

我该如何防止这种情况?

enter image description here

这是我的代码;

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);        
            }            
        }

1 个答案:

答案 0 :(得分:1)

您遇到的问题有两个:

  1. 由于您不断覆盖相同的变量,因此for循环完全没必要。运行for循环后,您将只获得最后次迭代的结果。由于您的代码不关心先前迭代的结果(因为它盲目地忽略并覆盖它),您应该避免执行它们。
  2. 您看到的例外情况与您的代码无关,而是与您从GPS收到的数据相关。
  3. 让我详细说明两者:

    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
    

    前两次设置LocALocB没有意义。您立即覆盖这些值。因此,只需手动完成最后一次迭代:

    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当然是一样的。