/// <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);
 }
 /// <summary>
 /// 座標省略時のコンストラクタ
 /// <para>内部パラメータには非値が代入され、使用準備は完了しますが値をセットしない限り運用できません。</para>
 /// </summary>
 /// <param name="unit">単位(°or rad)</param>
 /// <param name="datum">測地系</param>
 public RectangleField(AngleUnit unit = AngleUnit.Degree, Datum datum = Datum.WGS84)
 {
     this.param = new FieldParameter(unit, datum);
 }
 /// <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>
 /// コピーコンストラクタ
 /// </summary>
 /// <param name="field">コピー元のインスタンス</param>
 public RectangleField(RectangleField field)
 {
     this.param = field.param;
 }