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
9 changes: 9 additions & 0 deletions api/android-for-mappls.api
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ public final class com.mapconductor.mappls.MapplsMapViewSaver extends com.mapcon
public final class com.mapconductor.mappls.MapplsMapViewScope extends com.mapconductor.compose.MapViewScope {
public com.mapconductor.mappls.MapplsMapViewScope();
}
public final class com.mapconductor.mappls.MapplsOverlayStacking {
public static final com.mapconductor.mappls.MapplsOverlayStacking INSTANCE;
public final com.mapconductor.core.controller.OverlayLayerStack stackOf(com.mappls.sdk.maps.MapplsMap);
public final com.mapconductor.core.controller.OverlayStacking$Key key(com.mapconductor.core.controller.OverlayKind, int);
public final com.mapconductor.core.controller.OverlayStacking$Key getMARKER_TILE();
public final com.mapconductor.core.controller.OverlayStacking$Key getMARKER_DRAG();
public final void add(com.mappls.sdk.maps.MapplsMap, com.mappls.sdk.maps.Style, com.mappls.sdk.maps.style.layers.Layer, com.mapconductor.core.controller.OverlayStacking$Key);
public final void remove(com.mappls.sdk.maps.MapplsMap, com.mappls.sdk.maps.Style, java.lang.String);
}
public final class com.mapconductor.mappls.MapplsPolyUtilsKt {
public static final java.util.List<com.mappls.sdk.geojson.Feature> createMapplsLines-rXlOB7A(java.lang.String, java.util.List<? extends com.mapconductor.core.features.GeoPointInterface>, boolean, long, float, int);
public static final java.lang.String toMapplsColorString-8_81llA(long);
Expand Down
86 changes: 86 additions & 0 deletions src/main/java/com/mapconductor/mappls/MapplsOverlayStacking.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.mapconductor.mappls

import android.util.Log
import com.mapconductor.core.controller.OverlayKind
import com.mapconductor.core.controller.OverlayLayerStack
import com.mapconductor.core.controller.OverlayStacking
import com.mappls.sdk.maps.MapplsMap
import com.mappls.sdk.maps.Style
import com.mappls.sdk.maps.style.layers.Layer
import com.mappls.sdk.maps.style.layers.SymbolLayer
import java.util.WeakHashMap

/**
* オーバーレイの層をスタイルのどこへ入れるか([OverlayStacking] の帯の順)。
*
* 下から: ラスター < GroundImage < ポリゴン < サークル < ポリライン < マーカー
* (マーカーのタイルはマーカーの帯の一番下、ドラッグ中の層は一番上)。
*
* 位置は毎回スタイルの今の並びから決めるので、追加した順・送り直し・
* スタイルの読み直し(デザイン変更)に左右されない。
*
* ラスターだけはベースマップのラベル(SDK の層でない最初の symbol 層)の下に入れる。
* それ以外の帯はラベルの上に乗る(従来どおり)。
*/
internal object MapplsOverlayStacking {
private val stacks = WeakHashMap<MapplsMap, OverlayLayerStack>()

fun stackOf(map: MapplsMap): OverlayLayerStack = synchronized(stacks) { stacks.getOrPut(map) { OverlayLayerStack() } }

fun key(
kind: OverlayKind,
zIndex: Int = 0,
) = OverlayStacking.Key(kind, zIndex)

/** マーカーのタイル(ラスター): マーカーの帯の一番下。 */
val MARKER_TILE = key(OverlayKind.Marker, Int.MIN_VALUE)

/** ドラッグ中のマーカーの層: マーカーの帯の一番上。 */
val MARKER_DRAG = key(OverlayKind.Marker, Int.MAX_VALUE)

/**
* [layer] を [key] の位置へ足す。同じ id の層が既にあれば何もしない
* (位置を変えたいときは先に [remove] する)。
*/
fun add(
map: MapplsMap,
style: Style,
layer: Layer,
key: OverlayStacking.Key,
) {
val stack = stackOf(map)
stack.put(layer.id, key)
if (style.getLayer(layer.id) != null) return
val layers = style.layers
val ids = layers.map { it.id }
var before = stack.beforeId(ids, key)
if (key.kind == OverlayKind.RasterLayer) {
val label = layers.firstOrNull { it is SymbolLayer && stack.keyOf(it.id) == null }?.id
if (label != null && (before == null || ids.indexOf(label) < ids.indexOf(before))) {
before = label
}
}
try {
if (before != null) style.addLayerBelow(layer, before) else style.addLayer(layer)
} catch (e: Exception) {
if (style.getLayer(layer.id) != null) return
try {
style.addLayer(layer)
} catch (e2: Exception) {
Log.w("Mappls", "Failed to add layer: ${layer.id} (${e2.message})")
}
}
}

fun remove(
map: MapplsMap,
style: Style?,
layerId: String,
) {
stackOf(map).remove(layerId)
try {
style?.removeLayer(layerId)
} catch (_: Exception) {
}
}
}
17 changes: 6 additions & 11 deletions src/main/java/com/mapconductor/mappls/MapplsViewController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -337,19 +337,14 @@ class MapplsViewController(
styleInstance?.let { style ->
renderer.ensureDefaultIcon(style)
ensureGeoJsonSource(style, renderer.markerLayer.sourceId)
addLayerAboveSafely(
style = style,
layer = renderer.markerLayer.layer,
layerId = renderer.markerLayer.layerId,
aboveId = polylineController.renderer.layer.layerId,
MapplsOverlayStacking.add(
holder.map,
style,
renderer.markerLayer.layer,
MapplsOverlayStacking.key(com.mapconductor.core.controller.OverlayKind.Marker),
)
ensureGeoJsonSource(style, renderer.dragLayer.sourceId)
addLayerAboveSafely(
style = style,
layer = renderer.dragLayer.layer,
layerId = renderer.dragLayer.layerId,
aboveId = renderer.markerLayer.layerId,
)
MapplsOverlayStacking.add(holder.map, style, renderer.dragLayer.layer, MapplsOverlayStacking.MARKER_DRAG)
renderer.redraw()
renderer.drawDragLayer()
}
Expand Down
97 changes: 27 additions & 70 deletions src/main/java/com/mapconductor/mappls/MapplsViewControllerStyle.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mapconductor.mappls

import com.mapconductor.core.controller.OverlayKind
import com.mapconductor.mappls.marker.MapplsMarkerOverlayRenderer
import com.mappls.sdk.maps.Style
import com.mappls.sdk.maps.style.expressions.Expression
Expand All @@ -17,7 +18,9 @@ import kotlinx.coroutines.launch
*
* Mappls はスタイルが読み込み直されるたびにレイヤーが全部消えるため、ここは
* 何度呼ばれても同じ状態になるように書いてある(`ensureGeoJsonSource` /
* `addLayerSafely` はいずれも既存があれば作らない)。
* [MapplsOverlayStacking.add] はいずれも既存があれば作らない)。層の位置は
* [MapplsOverlayStacking] が帯の順(ラスター < GroundImage < ポリゴン < サークル <
* ポリライン < マーカー)で決める。
*
* ポリゴンの z 順は**レイヤーを z 値ごとに用意して**表現する。Mappls には
* フィーチャー単位の z 指定が無く、レイヤーの並び順だけが順序を決めるため。
Expand All @@ -34,6 +37,7 @@ internal fun MapplsViewController.ensureGeoJsonSource(
}
}

// 層の位置は MapplsOverlayStacking が決める。以下 2 つは公開 API の互換のために残している(SDK 内では未使用)。
internal fun MapplsViewController.addLayerSafely(
style: Style,
layer: Layer,
Expand Down Expand Up @@ -84,71 +88,38 @@ internal fun MapplsViewController.setupStyle(style: Style) {
ensureGeoJsonSource(style, polygonController.renderer.outline.layer.sourceId)
ensureGeoJsonSource(style, polygonController.renderer.fill.layer.sourceId)

// Circle cts as anchor above polygons
// 層の位置は MapplsOverlayStacking が帯の順で決める(追加の順に依らない)。
val stacking = MapplsOverlayStacking
val map = holder.map
val markerRenderer = markerController.renderer as MapplsMarkerOverlayRenderer

ensureGeoJsonSource(style, circleController.renderer.layer.sourceId)
addLayerSafely(
style = style,
layer = circleController.renderer.layer.layer,
layerId = circleController.renderer.layer.layerId,
)
// Circle stroke (LineLayer) directly above the circle fill
addLayerAboveSafely(
style = style,
layer = circleController.renderer.layer.strokeLayer,
layerId = circleController.renderer.layer.strokeLayerId,
aboveId = circleController.renderer.layer.layerId,
)
stacking.add(map, style, circleController.renderer.layer.layer, stacking.key(OverlayKind.Circle))
// 線は塗りの直後(同じ鍵なら後から入れたものが上)。
stacking.add(map, style, circleController.renderer.layer.strokeLayer, stacking.key(OverlayKind.Circle))

// Polyline (general) acts as anchor above circles
ensureGeoJsonSource(style, polylineController.renderer.layer.sourceId)
addLayerSafely(
style = style,
layer = polylineController.renderer.layer.layer,
layerId = polylineController.renderer.layer.layerId,
)
stacking.add(map, style, polylineController.renderer.layer.layer, stacking.key(OverlayKind.Polyline))

// Add z-indexed polygon layers below general polylines
ensurePolygonZLayers(style)

// Marker - add source and layer at the top
ensureGeoJsonSource(style, (markerController.renderer as MapplsMarkerOverlayRenderer).markerLayer.sourceId)
addLayerAboveSafely(
style = style,
layer = (markerController.renderer as MapplsMarkerOverlayRenderer).markerLayer.layer,
layerId = (markerController.renderer as MapplsMarkerOverlayRenderer).markerLayer.layerId,
aboveId = polylineController.renderer.layer.layerId,
)
(markerController.renderer as MapplsMarkerOverlayRenderer).redraw()
ensureGeoJsonSource(style, markerRenderer.markerLayer.sourceId)
stacking.add(map, style, markerRenderer.markerLayer.layer, stacking.key(OverlayKind.Marker))
markerRenderer.redraw()

// Drag layer above marker layer
ensureGeoJsonSource(style, (markerController.renderer as MapplsMarkerOverlayRenderer).dragLayer.sourceId)
addLayerAboveSafely(
style = style,
layer = (markerController.renderer as MapplsMarkerOverlayRenderer).dragLayer.layer,
layerId = (markerController.renderer as MapplsMarkerOverlayRenderer).dragLayer.layerId,
aboveId = (markerController.renderer as MapplsMarkerOverlayRenderer).markerLayer.layerId,
)
(markerController.renderer as MapplsMarkerOverlayRenderer).redraw()
ensureGeoJsonSource(style, markerRenderer.dragLayer.sourceId)
stacking.add(map, style, markerRenderer.dragLayer.layer, stacking.MARKER_DRAG)
markerRenderer.redraw()

markerEventControllers
.map { it.renderer as MapplsMarkerOverlayRenderer }
.filter { it != markerController.renderer }
.forEach { renderer ->
renderer.ensureDefaultIcon(style)
ensureGeoJsonSource(style, renderer.markerLayer.sourceId)
addLayerAboveSafely(
style = style,
layer = renderer.markerLayer.layer,
layerId = renderer.markerLayer.layerId,
aboveId = polylineController.renderer.layer.layerId,
)
stacking.add(map, style, renderer.markerLayer.layer, stacking.key(OverlayKind.Marker))
ensureGeoJsonSource(style, renderer.dragLayer.sourceId)
addLayerAboveSafely(
style = style,
layer = renderer.dragLayer.layer,
layerId = renderer.dragLayer.layerId,
aboveId = renderer.markerLayer.layerId,
)
stacking.add(map, style, renderer.dragLayer.layer, stacking.MARKER_DRAG)
renderer.redraw()
renderer.drawDragLayer()
}
Expand All @@ -167,7 +138,6 @@ internal fun MapplsViewController.setupStyle(style: Style) {
internal fun MapplsViewController.ensurePolygonZLayers(style: Style) {
val fillSourceId = polygonController.renderer.fill.layer.sourceId
val outlineSourceId = polygonController.renderer.outline.layer.sourceId
val anchorId = polylineController.renderer.layer.layerId

val zSet =
polygonController.polygonManager
Expand All @@ -180,14 +150,8 @@ internal fun MapplsViewController.ensurePolygonZLayers(style: Style) {
toRemove.forEach { z ->
val fillId = "polygon-fill-layer-$z"
val outlineId = "polygon-outline-layer-$z"
try {
style.removeLayer(outlineId)
} catch (_: Exception) {
}
try {
style.removeLayer(fillId)
} catch (_: Exception) {
}
MapplsOverlayStacking.remove(holder.map, style, outlineId)
MapplsOverlayStacking.remove(holder.map, style, fillId)
}

val zList = zSet.toList().sorted()
Expand All @@ -213,11 +177,7 @@ internal fun MapplsViewController.ensurePolygonZLayers(style: Style) {
),
)
}
try {
style.addLayerBelow(fill, anchorId)
} catch (_: Exception) {
style.addLayer(fill)
}
MapplsOverlayStacking.add(holder.map, style, fill, MapplsOverlayStacking.key(OverlayKind.Polygon, z))
}

if (style.getLayer(outlineId) == null) {
Expand Down Expand Up @@ -246,11 +206,8 @@ internal fun MapplsViewController.ensurePolygonZLayers(style: Style) {
),
)
}
try {
style.addLayerAbove(outline, fillId)
} catch (_: Exception) {
style.addLayer(outline)
}
// 塗りの直後(同じ鍵なら後から入れたものが上)。
MapplsOverlayStacking.add(holder.map, style, outline, MapplsOverlayStacking.key(OverlayKind.Polygon, z))
}
}
polygonZLayers.clear()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.mapconductor.mappls.groundimage

import com.mapconductor.core.controller.OverlayKind
import com.mapconductor.core.features.GeoRectBounds
import com.mapconductor.core.groundimage.AbstractGroundImageOverlayRenderer
import com.mapconductor.core.groundimage.GroundImageEntityInterface
import com.mapconductor.core.groundimage.GroundImageFingerPrint
import com.mapconductor.core.groundimage.GroundImageState
import com.mapconductor.mappls.MapplsActualGroundImage
import com.mapconductor.mappls.MapplsMapViewHolderInterface
import com.mapconductor.mappls.MapplsOverlayStacking
import com.mappls.sdk.maps.Style
import com.mappls.sdk.maps.geometry.LatLng
import com.mappls.sdk.maps.geometry.LatLngQuad
Expand Down Expand Up @@ -104,25 +106,20 @@ class MapplsGroundImageOverlayRenderer(
Log.w("Mappls", "Failed to add ground image source: ${e.message}")
}

try {
style.addLayerBelow(layer, BELOW_LAYER_ID)
} catch (_: Exception) {
try {
style.addLayer(layer)
} catch (e: Exception) {
Log.w("Mappls", "Failed to add ground image layer: ${e.message}")
}
}
// GroundImage の帯(ラスターの上、ポリゴンの下)。送り直しても同じ位置。
MapplsOverlayStacking.add(
holder.map,
style,
layer,
MapplsOverlayStacking.key(OverlayKind.GroundImage),
)
}

private fun removeSourceAndLayerIfExists(
style: Style,
handle: MapplsGroundImageHandle,
) {
try {
style.removeLayer(handle.layerId)
} catch (_: Exception) {
}
MapplsOverlayStacking.remove(holder.map, style, handle.layerId)
try {
style.removeSource(handle.sourceId)
} catch (_: Exception) {
Expand Down Expand Up @@ -185,7 +182,6 @@ class MapplsGroundImageOverlayRenderer(
opacity = opacity,
)

companion object {
private const val BELOW_LAYER_ID = "polyline-layer"
}
// 公開 API(Companion)の互換のために残している。
companion object
}
Loading
Loading