GeoPoint と範囲(GeoRectBounds)
MapConductor の座標型は GeoPoint ひとつだけです。プロバイダごとの LatLng・CLLocationCoordinate2D・LngLat に触れる必要はありません。矩形範囲は GeoRectBounds が受け持ち、南西と北東の 2 点で表します。どちらも 3 プラットフォームで同じメンバー構成です。
01 · GeoPoint
緯度・経度・標高の 3 つを持つ不変の値です。標高は省略でき、その場合は 0 として扱われます。等価比較とハッシュは緯度経度(と標高)の内容で決まるので、そのままマップのキーや差分判定に使えます。
生成方法は 3 つあります。コンストラクタ、緯度経度の順を明示するファクトリ、そして他の座標型からの変換です。順序の取り違えが起きやすい経度・緯度の並びは、名前で区別できるようにしてあります。
val tokyo = GeoPoint(35.6812, 139.7671) val haneda = GeoPoint.fromLatLong(35.548852, 139.784086) val fromLngLat = GeoPoint.fromLongLat(139.7671, 35.6812) // GeoPointInterface を実装する任意の値から val copied = GeoPoint.from(anyPositionLike) val url = tokyo.toUrlValue() // "35.681200,139.767100"
let tokyo = GeoPoint(latitude: 35.6812, longitude: 139.7671) let haneda = GeoPoint.fromLatLong(latitude: 35.548852, longitude: 139.784086) let fromLngLat = GeoPoint.fromLongLat(longitude: 139.7671, latitude: 35.6812) // GeoPointProtocol に準拠する任意の値から let copied = GeoPoint.from(position: anyPositionLike) let url = tokyo.toUrlValue() // "35.681200,139.767100"
import { createGeoPoint, fromLatLng, fromLngLat, GeoPoint } from '@mapconductor/js-sdk-core';
const tokyo = createGeoPoint({ latitude: 35.6812, longitude: 139.7671 });
const haneda = fromLatLng({ latitude: 35.548852, longitude: 139.784086 });
const fromLngLatPoint = fromLngLat({ longitude: 139.7671, latitude: 35.6812 });
// 名前空間からも同じものが引ける
const same = GeoPoint.fromLatLong({ latitude: 35.6812, longitude: 139.7671 });
const url = tokyo.toUrlValue(6); // "35.681200,139.767100"fromLatLng と fromLatLong、fromLngLat と fromLongLat は同じものの別名です。既存コードの命名にあわせて選べます。
02 · 正規化と妥当性
外部データの座標は範囲外だったり、経度が 360 度を超えていたりします。範囲に収める normalize と、範囲内かを確かめる isValid が用意されています。
範囲に収める
緯度は −90〜90 に切り詰め、経度は −180〜180 に折り返します。経度 200 は −160 になります。
範囲内かを確かめる
緯度が −90〜90、経度が −180〜180 に収まっているときだけ true。取り込み時の検証に使います。
// GeoPointInterface の拡張関数として提供される val safe = raw.normalize() if (!raw.isValid()) return
let safe = raw.normalize()
guard raw.isValid() else { return }const safe = raw.normalize(); if (!raw.isValid()) return;
03 · GeoRectBounds
南西と北東の 2 点で矩形を表します。点を足していけば全体を囲む範囲が育つ「伸びる箱」として使うのが基本です。作った直後は空(isEmpty)で、southWest と northEast は未設定です。
// ルート全体が入る範囲を作ってカメラを合わせる
val bounds = GeoRectBounds()
routePoints.forEach { bounds.extend(it) }
mapViewState.fitBounds(bounds = bounds, padding = 48)
// 表示範囲より少し広めに取得する
val fetchArea = bounds.expandedByDegrees(latPad = 0.05, lonPad = 0.05)let bounds = GeoRectBounds()
routePoints.forEach { bounds.extend(point: $0) }
mapState.fitBounds(bounds: bounds, padding: 48)
let fetchArea = bounds.expandedByDegrees(latPad: 0.05, lonPad: 0.05)import { createGeoRectBounds } from '@mapconductor/js-sdk-core';
const bounds = createGeoRectBounds();
routePoints.forEach(p => bounds.extend(p));
mapViewState.fitBounds(bounds, 48);
const fetchArea = bounds.expandedByDegrees(0.05, 0.05);04 · 範囲の使いどころ
GeoRectBounds は API のあちこちに現れます。どれも同じ型なので、一度作った範囲は使い回せます。
val spots = listOf(
GeoPoint.fromLatLong(35.6586, 139.7454), // 東京タワー
GeoPoint.fromLatLong(35.7101, 139.8107), // スカイツリー
GeoPoint.fromLatLong(35.6852, 139.7528), // 皇居
)
// 空の範囲から始めて、1 点ずつ広げる
val bounds = GeoRectBounds()
spots.forEach { bounds.extend(it) }
MapLibreMapView(state = mapViewState) {
spots.forEachIndexed { i, point ->
Marker(MarkerState(id = "spot-$i", position = point))
}
}
Button(onClick = {
// padding は画面の余白(論理ピクセル)。0 だと端の点が縁に張り付く
if (!bounds.isEmpty) mapViewState.fitBounds(bounds, padding = 64)
}) {
Text("全部を表示")
}