From 45c8b1289db15d4e09a5b9c7aacb29c23665830f Mon Sep 17 00:00:00 2001 From: Masashi Katsumata Date: Mon, 9 Nov 2026 09:38:06 -0800 Subject: [PATCH] Draw large polyline sets as raster tiles (PolylineTiler) The polyline controller gets a PolylineTiler, shown through the same raster layer path as the polygon tiles. HERE's map items are one layer, so the tiles go under them, above the polygon tiles (placed against each other by layer name). Whatever redraws from the polyline manager skips tiled entities (no native line). --- api/android-for-here.api | 2 ++ .../here/HereMapViewController.kt | 15 +++++++++++++ .../mapconductor/here/HereOverlayStacking.kt | 22 ++++++++++++++++++- .../raster/HereRasterLayerOverlayRenderer.kt | 22 +++++++++++++++++-- 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/api/android-for-here.api b/api/android-for-here.api index e3ef70e..e2b5f04 100644 --- a/api/android-for-here.api +++ b/api/android-for-here.api @@ -192,6 +192,8 @@ public final class com.mapconductor.here.HereOverlayStacking { public final com.here.sdk.mapview.MapLayerPriority rasterPriority(); public final com.here.sdk.mapview.MapLayerPriority groundImagePriority(); public final com.here.sdk.mapview.MapLayerPriority polygonTilePriority(); + public final com.here.sdk.mapview.MapLayerPriority polygonTilePriority(java.lang.String); + public final com.here.sdk.mapview.MapLayerPriority polylineTilePriority(java.lang.String); } public final class com.mapconductor.here.HereTypeAliasKt { } diff --git a/src/main/java/com/mapconductor/here/HereMapViewController.kt b/src/main/java/com/mapconductor/here/HereMapViewController.kt index 3c18070..4f18cf1 100644 --- a/src/main/java/com/mapconductor/here/HereMapViewController.kt +++ b/src/main/java/com/mapconductor/here/HereMapViewController.kt @@ -32,7 +32,10 @@ import com.mapconductor.core.marker.StrategyMarkerController import com.mapconductor.core.marker.dispatchGeoMarkerClick import com.mapconductor.core.polygon.OnPolygonEventHandler import com.mapconductor.core.polyline.OnPolylineEventHandler +import com.mapconductor.core.polyline.POLYLINE_TILE_LAYER_ID import com.mapconductor.core.polyline.PolylineState +import com.mapconductor.core.polyline.PolylineTiler +import com.mapconductor.core.polyline.polylineTileRasterLayerState import com.mapconductor.here.circle.HereCircleController import com.mapconductor.here.groundimage.HereGroundImageController import com.mapconductor.here.marker.HereMarkerController @@ -185,6 +188,18 @@ class HereMapViewController( } } } + + // Many polylines too: the same raster layer path, in the polyline band. + polylineController.tiler = + PolylineTiler().apply { + onTemplate = { template, tileSize -> + if (template != null) { + rasterLayerController.upsert(polylineTileRasterLayerState(template, tileSize)) + } else { + rasterLayerController.removeById(POLYLINE_TILE_LAYER_ID) + } + } + } } override fun moveCamera(position: MapCameraPosition) = handleMoveCamera(position) diff --git a/src/main/java/com/mapconductor/here/HereOverlayStacking.kt b/src/main/java/com/mapconductor/here/HereOverlayStacking.kt index abb1a8b..571998b 100644 --- a/src/main/java/com/mapconductor/here/HereOverlayStacking.kt +++ b/src/main/java/com/mapconductor/here/HereOverlayStacking.kt @@ -33,7 +33,27 @@ internal object HereOverlayStacking { * ポリゴンのタイル(SDK が描くラスター): ポリゴンの帯の一番下。GroundImage のアンカー * "traffic_on_route" の直後(GroundImage より上、map item より下)。 */ - fun polygonTilePriority(): MapLayerPriority = MapLayerPriorityBuilder().renderedAfterLayer(GROUND_IMAGE_ANCHOR).build() + fun polygonTilePriority(): MapLayerPriority = polygonTilePriority(beforeLayer = null) + + /** [polygonTilePriority]; when the polyline tiles are already on the map, just below them ([beforeLayer]). */ + fun polygonTilePriority(beforeLayer: String?): MapLayerPriority = + if (beforeLayer != null) { + MapLayerPriorityBuilder().renderedBeforeLayer(beforeLayer).build() + } else { + MapLayerPriorityBuilder().renderedAfterLayer(GROUND_IMAGE_ANCHOR).build() + } + + /** + * ポリラインのタイル(SDK が描くラスター): ポリゴンのタイルの上([afterLayer]、無ければ + * GroundImage のアンカーの直後)、map item の下。 + * + * HERE の map item(ポリゴン・サークル・ポリライン)は 1 枚の層にまとめて描かれ、 + * MapLayer をサークルとポリラインの間に挟めない。map item の下に置くので、ネイティブの + * ポリゴン・サークルもこのタイルの上に来る(帯の決まりからの、HERE だけの差)。 + * マーカーとマーカーのタイルより下、ポリゴンのタイルより上は守る。 + */ + fun polylineTilePriority(afterLayer: String?): MapLayerPriority = + MapLayerPriorityBuilder().renderedAfterLayer(afterLayer ?: GROUND_IMAGE_ANCHOR).build() private const val RASTER_ANCHOR = "route" private const val GROUND_IMAGE_ANCHOR = "traffic_on_route" diff --git a/src/main/java/com/mapconductor/here/raster/HereRasterLayerOverlayRenderer.kt b/src/main/java/com/mapconductor/here/raster/HereRasterLayerOverlayRenderer.kt index 53638d3..99b0943 100644 --- a/src/main/java/com/mapconductor/here/raster/HereRasterLayerOverlayRenderer.kt +++ b/src/main/java/com/mapconductor/here/raster/HereRasterLayerOverlayRenderer.kt @@ -14,6 +14,7 @@ import com.here.sdk.mapview.datasource.TileUrlProviderCallback import com.here.sdk.mapview.datasource.TileUrlProviderFactory import com.here.sdk.mapview.datasource.TilingScheme import com.mapconductor.core.polygon.POLYGON_TILE_LAYER_ID +import com.mapconductor.core.polyline.POLYLINE_TILE_LAYER_ID import com.mapconductor.core.raster.RasterLayerEntityInterface import com.mapconductor.core.raster.RasterLayerOverlayRendererInterface import com.mapconductor.core.raster.RasterLayerSource @@ -140,6 +141,7 @@ class HereRasterLayerOverlayRenderer( .forMap(holder.mapView.hereMap) .build() layer.setEnabled(state.visible) + if (isShapeTileLayer(state.id)) shapeTileLayers.add(state.id) HereRasterLayerHandle( dataSource = dataSource, layer = layer, @@ -155,20 +157,35 @@ class HereRasterLayerOverlayRenderer( } } + /** The SDK's shape tile layers on the map now (their ids), so each can be placed against the other. */ + private val shapeTileLayers = java.util.Collections.synchronizedSet(HashSet()) + /** * アプリのラスターはラスターの帯(GroundImage・map item の下)。マーカーのタイルは * マーカーの帯なので、ポリゴン等の map item より上(最後に描く)。ポリゴンのタイルは - * ポリゴンの帯の一番下(GroundImage の上、map item の下)。 + * ポリゴンの帯の一番下(GroundImage の上、map item の下)。ポリラインのタイルはその上 + * ([HereOverlayStacking.polylineTilePriority])。どちらも版が変わるたびに作り直すので、 + * もう片方があればそれを基準に置き、作った順に左右されないようにする。 */ private fun priorityFor(state: RasterLayerState): MapLayerPriority = if (state.id.startsWith("marker-tile-")) { MapLayerPriorityBuilder().renderedLast().build() } else if (state.id == POLYGON_TILE_LAYER_ID) { - HereOverlayStacking.polygonTilePriority() + HereOverlayStacking.polygonTilePriority( + beforeLayer = layerNameOf(POLYLINE_TILE_LAYER_ID).takeIf { POLYLINE_TILE_LAYER_ID in shapeTileLayers }, + ) + } else if (state.id == POLYLINE_TILE_LAYER_ID) { + HereOverlayStacking.polylineTilePriority( + afterLayer = layerNameOf(POLYGON_TILE_LAYER_ID).takeIf { POLYGON_TILE_LAYER_ID in shapeTileLayers }, + ) } else { HereOverlayStacking.rasterPriority() } + private fun layerNameOf(id: String) = "raster-layer-$id" + + private fun isShapeTileLayer(id: String) = id == POLYGON_TILE_LAYER_ID || id == POLYLINE_TILE_LAYER_ID + private fun updateLayer( handle: HereRasterLayerHandle, state: RasterLayerState, @@ -178,6 +195,7 @@ class HereRasterLayerOverlayRenderer( private fun removeLayer(entity: RasterLayerEntityInterface) { val handle = entity.layer + if (isShapeTileLayer(entity.state.id)) shapeTileLayers.remove(entity.state.id) handle.routeId?.let { tileServer.unregister(it) } handle.layer.destroy() handle.dataSource.destroy()