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