Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/android-for-openmobilemaps.api
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,8 @@ public final class com.mapconductor.openmobilemaps.marker.OpenMobileMapsMarkerCo
public final class com.mapconductor.openmobilemaps.tile.WebMercatorTileLayerConfig extends io.openmobilemaps.mapscore.shared.map.layers.tiled.Tiled2dMapLayerConfig {
public static final double WORLD_WIDTH_METERS;
public static final double HALF_WORLD;
public com.mapconductor.openmobilemaps.tile.WebMercatorTileLayerConfig(java.lang.String, java.lang.String, int, int, int, com.mapconductor.core.raster.TileScheme, int, boolean);
public com.mapconductor.openmobilemaps.tile.WebMercatorTileLayerConfig(java.lang.String, java.lang.String, int, int, int, com.mapconductor.core.raster.TileScheme, int, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker);
public com.mapconductor.openmobilemaps.tile.WebMercatorTileLayerConfig(java.lang.String, java.lang.String, int, int, int, com.mapconductor.core.raster.TileScheme, int, boolean, boolean);
public com.mapconductor.openmobilemaps.tile.WebMercatorTileLayerConfig(java.lang.String, java.lang.String, int, int, int, com.mapconductor.core.raster.TileScheme, int, boolean, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker);
public int getCoordinateSystemIdentifier();
public java.lang.String getLayerName();
public java.lang.String getTileUrl(int, int, int, int);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,9 @@ class OpenMobileMapsRasterLayerOverlayRenderer(
// ラスターオーバーレイは透過前提なので、粗い親レベルを重ね描きしない
numDrawPreviousLayers = 0,
maskTile = true,
// 切り捨てだと、ズーム 17.75 で z17 を 1.68 倍に伸ばして出す。MapLibre 系は z18 を
// 0.84 倍で出すので、マーカータイルのアイコンとラベルが 2 倍違って見えた。
roundToNearestLevel = true,
)
val layer = Tiled2dMapRasterLayerInterface.create(config, loaders)
layer.setAlpha(state.opacity)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ import com.mapconductor.core.tileserver.TileServerRegistry
import com.mapconductor.openmobilemaps.OpenMobileMapsActualMarker
import com.mapconductor.openmobilemaps.OpenMobileMapsMarkerOverlayRenderer
import java.util.UUID
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.withPermit

Expand Down Expand Up @@ -123,11 +126,12 @@ class OpenMobileMapsMarkerController(
if (currentFinger == prevFinger) return

semaphore.withPermit {
// 件数だけが要る。allEntities() は全件の写しを作るので、ラベルの付け替えのように
// 数十本が続けて変わると、そのたびに 14 万件を写すことになる。
val tilingEnabled =
markerTiling.enabled && markerManager.allEntities().size >= markerManager.minMarkerCount
markerTiling.enabled && markerManager.getMemoryStats().entityCount >= markerManager.minMarkerCount
val wantsTiled = tilingEnabled && !state.draggable && state.getAnimation() == null
val wasTiled = tiledMarkerIds.contains(state.id)
val markerIcon = state.icon?.toBitmapIcon() ?: defaultMarkerIcon

if (wantsTiled) {
if (!wasTiled) {
Expand All @@ -145,14 +149,19 @@ class OpenMobileMapsMarkerController(
tiling = true,
),
)
renderer.onPostProcess()
syncTiledOverlay()
// タイル担当のままなら、ネイティブのマーカーには何も起きていない。onPostProcess は
// 全件を写してネイティブ分を描き直すので(14 万件で 1 回 50ms)、ネイティブから
// タイルへ移ったときだけ呼ぶ。
if (!wasTiled) renderer.onPostProcess()
scheduleTileRefresh()
return@withPermit
}

if (wasTiled) {
tiledMarkerIds.remove(state.id)
}
// ネイティブマーカーとして描くときだけ焼き込む。タイル担当なら要らない。
val markerIcon = state.icon?.toBitmapIcon() ?: defaultMarkerIcon

val params =
object : MarkerOverlayRendererInterface.ChangeParamsInterface<OpenMobileMapsActualMarker> {
Expand Down Expand Up @@ -183,14 +192,33 @@ class OpenMobileMapsMarkerController(
renderer.onPostProcess()

if (tiledMarkerIds.isNotEmpty()) {
syncTiledOverlay()
scheduleTileRefresh()
} else {
removeTileOverlay()
}
}
viewportSwitch.requestReapply()
}

private var tileRefreshJob: Job? = null

/**
* 1 本ずつの変更からの描き直しを 1 回にまとめる。
*
* ラベルの付け替えのように数十本が続けて変わると、1 本ごとにラスターソースを差し替え、
* そのたびに地図が見えているタイルを全部取り直していた(MapLibre・Pixel 5a で 45 回、
* 描き直したタイル 494 枚、最後のタイルまで 6 秒)。続けて来た変更は
* [TILE_REFRESH_COALESCE] の間に受けて、まとめて 1 回だけ差し替える。
*/
private fun scheduleTileRefresh() {
if (tileRefreshJob?.isActive == true) return
tileRefreshJob =
coroutine.launch {
delay(TILE_REFRESH_COALESCE)
semaphore.withPermit { syncTiledOverlay() }
}
}

override suspend fun clear() {
viewportSwitch.destroy()
semaphore.withPermit {
Expand Down Expand Up @@ -226,6 +254,8 @@ class OpenMobileMapsMarkerController(

override fun destroy() {
viewportSwitch.destroy()
// 待っている描き直しが後から走ると、外したタイル経路をまた登録してしまう。
tileRefreshJob?.cancel()
// タイルサーバはプロセス共有のシングルトン。**stop してはいけない**
// (他の地図やオーバーレイ拡張のタイルまで止まる)。自分の経路だけ外す。
markerTileGroupId?.let { tileServer.unregister(it) }
Expand Down Expand Up @@ -319,4 +349,9 @@ class OpenMobileMapsMarkerController(
rasterLayerCallback?.onRasterLayerUpdate(null)
markerTileRasterLayerState = null
}

private companion object {
/** 続けて来る変更を 1 回の描き直しにまとめる窓。1 フレーム分。 */
val TILE_REFRESH_COALESCE = 16.milliseconds
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import kotlin.math.pow
* @param urlTemplate `{z}` `{x}` `{y}` を含む URL。
* @param tileSize タイル 1 枚の一辺(**dp**)。OSM 系は 256、@2x 系は 512。
* @param scheme [TileScheme.TMS] なら y を反転する。
* @param roundToNearestLevel true ならカメラのズームを四捨五入したレベルのタイルを出す
* (MapLibre 系・Mapbox・HERE・ArcGIS と同じ)。false は OpenMobileMaps の既定どおり切り捨てる。
*/
class WebMercatorTileLayerConfig(
private val layerName: String,
Expand All @@ -45,6 +47,7 @@ class WebMercatorTileLayerConfig(
private val scheme: TileScheme = TileScheme.XYZ,
private val numDrawPreviousLayers: Int = 2,
private val maskTile: Boolean = false,
private val roundToNearestLevel: Boolean = false,
) : Tiled2dMapLayerConfig() {
override fun getCoordinateSystemIdentifier(): Int = CoordinateSystemIdentifiers.EPSG3857()

Expand Down Expand Up @@ -94,7 +97,8 @@ class WebMercatorTileLayerConfig(

override fun getZoomInfo(): Tiled2dMapZoomInfo =
Tiled2dMapZoomInfo(
1.0f,
// √2 で次のレベルへ半段早く切り替わり、切り捨てが四捨五入になる。
if (roundToNearestLevel) 1.4142135f else 1.0f,
numDrawPreviousLayers,
0,
false,
Expand Down
Loading