/// <summary>
 /// コンストラクタ
 /// <para>中心座標と半径[km]を指定すると、その円を格納できる四角い領域を宣言します。</para>
 /// </summary>
 /// <param name="x">中心座標</param>
 /// <param name="radius">半径[km]</param>
 public RectangleField(Blh x, double radius)
 {
     this.param = new FieldParameter(x.Unit, x.DatumKind);
     var len = x.GetUnitLengthForEN();
     var dn = radius * 1000.0 / len.N;
     var de = radius * 1000.0 / len.E;
     var pos = new Blh(dn, de, 0.0, AngleUnit.Degree, x.DatumKind);
     x.Unit = AngleUnit.Degree;
     RectangleField.SetLatAndEastWestLon(x - pos, ref this.param);
     RectangleField.SetLatAndEastWestLon(x + pos, ref this.param);
 }
Example #2
0
        /* プロパティ ************************************/
        /* メソッド **************************************/
        /// <summary>
        /// 文字列を解析して、そこに含まれる1エポック分の測位情報を返す
        /// </summary>
        /// <param name="line">被解析文字列</param>
        /// <returns>測位情報の解析データ<para>null: 解析不可能であった場合</para></returns>
        public PositioningInfo Parse(string line)
        {
            Match m = this.regexGroup.Match(line);                // マッチチェック
            if (m.Success)
            {
                Blh pos = new Blh();                                // 初期値は全て0になっている
                PositioningInfo ans = new PositioningInfo();

                int day = int.Parse(m.Groups["day"].Value);
                int month = int.Parse(m.Groups["month"].Value);
                int year = int.Parse(m.Groups["year"].Value);
                int hour = int.Parse(m.Groups["hour"].Value);
                int min = int.Parse(m.Groups["min"].Value);
                int sec = int.Parse(m.Groups["sec"].Value);
                ans.Time = new DateTime(year, month, day, hour, min, sec);

                pos.B = double.Parse(m.Groups["lat"].Value);
                pos.L = double.Parse(m.Groups["lon"].Value);
                pos.H = double.Parse(m.Groups["height"].Value);
                ans.Position = pos;
                return ans;
            }
            else
                return null;
        }
 /// <summary>
 /// コンストラクタ
 /// <para>2つの座標を指定すると、大小関係からマップの座標を自動的に決定する。</para>
 /// <para>経度に関しては、より小さな領域となる座標を選択する。</para>
 /// </summary>
 /// <param name="x1">座標1</param>
 /// <param name="x2">座標2</param>
 /// <param name="unit">単位(°or rad)</param>
 /// <param name="datum">測地系</param>
 public RectangleField(Blh x1, Blh x2, AngleUnit unit = AngleUnit.Degree, Datum datum = Datum.WGS84)
 {
     this.param = new FieldParameter(unit, datum);
     RectangleField.SetLatAndEastWestLon(x1, ref this.param);
     RectangleField.SetLatAndEastWestLon(x2, ref this.param);
 }
 /// <summary>
 /// 緯度経度を更新する
 /// </summary>
 /// <param name="additionalPos">追加座標</param>
 /// <param name="param">領域パラメータ</param>
 private static void SetLatAndEastWestLon(Blh additionalPos, ref FieldParameter param)
 {
     additionalPos.Unit = param.unit;                                    // 単位を変換(統一する)
     additionalPos.DatumKind = param.datum;                              // 測地系を統一
     // まずは緯度の値をセット(これは単純で良い)
     if (double.IsNaN(param.upperLat)) param.upperLat = additionalPos.B; // 未セットならセットするし、保持データと比べて大きい/小さければ格納する。
     if (param.upperLat < additionalPos.B) param.upperLat = additionalPos.B;
     if (double.IsNaN(param.lowerLat)) param.lowerLat = additionalPos.B;
     if (param.lowerLat > additionalPos.B) param.lowerLat = additionalPos.B;
     // 次に経度の処理
     if (double.IsNaN(param.eastLon)) param.eastLon = additionalPos.L;   // 未セットならセット
     if (double.IsNaN(param.westLon)) param.westLon = additionalPos.L;
     if (double.IsNaN(param.centerLon))
     {
         param.centerLon = additionalPos.L;                                // 初回時は代入するだけ
     }
     else
     {
         // まずは経度の東端と西端の処理
         Blh currentCenter = new Blh(0, param.centerLon, 0, param.unit, param.datum);        // 中央の経度を持つ座標を生成(このメソッド中では、緯度は0で宣言して引き算しないと、Blh構造体の仕様による要因で計算を誤る。)
         Blh relativeNewPos = additionalPos - currentCenter;                                 // currentCenter基準の相対座標を計算
         if (relativeNewPos.L > 0.0)                                                         // additionalPosがcurrentCenterよりも東側にある
         {
             Blh currentEast = new Blh(0, param.eastLon, 0, param.unit, param.datum);        // 東端の経度を持つ座標を生成
             Blh relativeCurrentEast = currentEast - currentCenter;                          // currentCenter基準の現東端の相対座標を計算
             if (relativeNewPos.L > relativeCurrentEast.L) param.eastLon = additionalPos.L;  // より東に属する方を採用する
         }
         else if (relativeNewPos.L < 0.0)                                                    // additionalPosがcurrentCenterよりも西側にある
         {
             Blh currentWest = new Blh(0, param.westLon, 0, param.unit, param.datum);        // 西端の経度を持つ座標を生成
             Blh relativeCurrentWest = currentWest - currentCenter;                          // currentCenter基準の現西端の相対座標を計算
             if (relativeNewPos.L < relativeCurrentWest.L) param.westLon = additionalPos.L;  // より西に属する方を採用する
         }
         // 次に経度中央の計算(変数のスコープがうざいのでかっこを付けてスコープを限定化する)
         // 以下は新規追加の座標が中央座標に対してπ以上の更新量が無ければ成り立つ。上のアルゴリズムを変更する際には細心の注意を払うこと。
         {
             Blh currentWest = new Blh(0, param.westLon, 0, param.unit, param.datum);        // 西端の経度を持つ座標を生成
             Blh currentEast = new Blh(0, param.eastLon, 0, param.unit, param.datum);        // 東端の経度を持つ座標を生成
             Blh candidate = currentWest.GetMedian(currentEast);                             // 中間の座標を計算する。この時点では領域のセンターかどうかは不明。
             Blh relationCandidate = candidate - currentEast;                                // 東端を基準に見た候補座標の相対座標を計算
             Blh relatinCurrentCenter = currentCenter - currentEast;                         // 東端を基準に見た現中央座標の相対座標を計算
             double half = 180.0;
             if (param.unit == AngleUnit.Radian) half = half * Math.PI / 180.0;              // 経度をπだけ進める準備
             if (relationCandidate.L * relatinCurrentCenter.L < 0) candidate = new Blh(0, candidate.L + half, 0, param.unit, param.datum); // 地球の反対側でなかったかをチェックして、反対側ならπ進める
             param.centerLon = candidate.L;                                                  // 中心座標を更新
         }
     }
     return;
 }
 /// <summary>
 /// 領域をBlh型の配列として返す
 /// <para>格納の順番はKMLのポリゴンで四角く描かれる順番にしています。</para>
 /// </summary>
 /// <returns>領域の四隅をBlh型の配列に加工したもの</returns>
 public Blh[] ToArray()
 {
     Blh[] arr = new Blh[4];
     arr[0] = this.UpperLeft;
     arr[1] = this.UpperRight;
     arr[2] = this.LowerRight;
     arr[3] = this.LowerLeft;
     return arr;
 }
 /// <summary>
 /// 座標の配列から領域を生成する
 /// <para>自動的に過去の履歴と比較されて領域が拡張されます。</para>
 /// </summary>
 /// <param name="pos">セットする座標</param>
 public void Set(Blh[] pos)
 {
     foreach (Blh _pos in pos) this.Set(_pos);
 }
 /// <summary>
 /// 座標をセットする
 /// <para>自動的に過去の履歴と比較されて領域が拡張されます。</para>
 /// </summary>
 /// <param name="pos">セットする座標</param>
 public void Set(Blh pos)
 {
     SetLatAndEastWestLon(pos, ref this.param);
     return;
 }
 /// <summary>
 /// 領域を指定マージン[km]にて拡張した領域を返します
 /// <para>非破壊的メソッド</para>
 /// <para>経度方向は高緯度に合わせ、緯度方向は低緯度に合わせて拡張します。</para>
 /// </summary>
 /// <param name="marginKm">マージン[km]<para>負値の場合は処理を行いません。</para></param>
 /// <returns>拡張済みのオブジェクト<para>引数のmarginが負値の場合はnullを返します。</para></returns>
 public RectangleField Extend(double marginKm)
 {
     RectangleField ans = null;
     if (marginKm > 0)
     {
         ans = new RectangleField(this);
         Blh highLat, lowLat;
         if (Math.Abs(this.LowerLeft.B) > Math.Abs(this.UpperLeft.B))
         {
             highLat = this.LowerLeft;
             lowLat = this.UpperLeft;
         }
         else
         {
             highLat = this.UpperLeft;
             lowLat = this.LowerLeft;
         }
         double n = marginKm * 1000.0 / lowLat.GetUnitLengthForEN().N;      // 緯度が低い方が緯度方向の単位距離が短い
         double e = marginKm * 1000.0 / highLat.GetUnitLengthForEN().E;     // 緯度が高い方が経度方向の単位距離は短い
         Blh pad = new Blh(n, e);
         ans.Set(this.UpperRight + pad);
         ans.Set(this.LowerLeft - pad);
     }
     return ans;
 }
Example #9
0
        /// <summary>
        /// GGAを解析して、測位情報を返す
        /// <para>現時点では緯度と経度と楕円体高しか返していないんだけど・・・</para>
        /// </summary>
        /// <param name="str">解析文字列</param>
        /// <returns></returns>
        public static PositioningInfo Parse(string str)
        {
            Blh pos = new Blh();                                // 初期値は全て0になっている
            PositioningInfo ans = new PositioningInfo();

            Match m = GGA.regexGroup.Match(str);                // マッチチェック
            if (m.Success) {
                string clock = m.Groups["clock"].Value;
                string lat = m.Groups["lat"].Value;
                string lon = m.Groups["lon"].Value;
                string alt_MSL = m.Groups["Alt_MSL"].Value;
                string alt_Geoid = m.Groups["Alt_Geoid"].Value;

                // 緯度経度と高度を取得する
                double _lat = 0.0, _lon = 0.0;
                if (lat != "") _lat = double.Parse(lat);
                if (_lat != 0.0) _lat = (double)((int)(_lat / 100.0d)) + (_lat % 100.0) / 60.0d;    // 単位を度へ変換する
                pos.B = _lat;
                if (m.Groups["NorS"].Value == "S") pos.B = -pos.B;                                  // 南緯は負数とする
                if (lon != "") _lon = double.Parse(lon);
                if (_lon != 0.0) _lon = (double)((int)(_lon / 100.0d)) + (_lon % 100.0) / 60.0d;
                pos.L = _lon;
                if (m.Groups["EorW"].Value == "W") pos.L = -pos.L;                                  // 西経は負数とする
                if (alt_MSL != "" && alt_Geoid != "") pos.H = double.Parse(alt_MSL) + double.Parse(alt_Geoid);// 平均海水面高とジオイド高を足して楕円体高とする
            }
            ans.Position = pos;
            return ans;
        }