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
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.mapconductor.maplibre

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.mapconductor.compose.circle.Circles
import com.mapconductor.core.circle.CIRCLE_TILE_LAYER_ID
import com.mapconductor.core.circle.CircleState
import com.mapconductor.core.features.GeoPoint
import java.io.File
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

/** Exercises bulk registration through the real map host, not just the core tiler. */
@RunWith(AndroidJUnit4::class)
class MapLibreCircleTilingDeviceTest {
@get:Rule val compose = createComposeRule()

@Test
fun circlesSwitchBetweenTilesAndNativeAndSurviveStyleReload() {
val context = InstrumentationRegistry.getInstrumentation().targetContext
fun design(name: String): MapLibreDesign {
val file = File(context.cacheDir, "circle-device-$name.json")
file.writeText("""{"version":8,"name":"$name","sources":{},"layers":[{"id":"background","type":"background"}]}""")
return MapLibreDesign(id = name, styleJsonURL = "file://${file.absolutePath}")
}
val first = design("first")
val second = design("second")
val state = MapLibreViewState(mapDesignType = first, id = "circle-device")
val many = (0..2000).map { i ->
CircleState(center = GeoPoint(35.6 + i * 0.00001, 139.7), radiusMeters = 20.0, id = "circle-$i")
}
var circles by mutableStateOf(many)
compose.setContent {
MapLibreMapView(state = state, modifier = Modifier.fillMaxSize()) { Circles(circles) }
}
fun tiled(design: String): Boolean {
var result = false
InstrumentationRegistry.getInstrumentation().runOnMainSync {
val style = state.getMapViewHolder()?.map?.style
result = style?.isFullyLoaded == true && style.uri == (if (design == "first") first.styleJsonURL else second.styleJsonURL) &&
style.layers.any { it.id.contains(CIRCLE_TILE_LAYER_ID) }
}
return result
}
compose.waitUntil(30_000) { tiled("first") }
compose.runOnUiThread { state.mapDesignType = second }
compose.waitUntil(30_000) { tiled("second") }
compose.runOnUiThread { circles = many.take(1) }
compose.waitUntil(30_000) {
var native = false
InstrumentationRegistry.getInstrumentation().runOnMainSync {
val style = state.getMapViewHolder()?.map?.style
native = style?.isFullyLoaded == true && style.layers.none { it.id.contains(CIRCLE_TILE_LAYER_ID) }
}
native
}
compose.runOnUiThread { circles = many }
compose.waitUntil(30_000) { tiled("second") }
assertTrue(tiled("second"))
compose.runOnUiThread { circles = emptyList() }
compose.waitUntil(30_000) { !tiled("second") }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ internal object MapLibreOverlayStacking {
/** ポリゴンのタイル(ラスター): ポリゴンの帯の一番下。 */
val POLYGON_TILE = key(OverlayKind.Polygon, Int.MIN_VALUE)

/** 円のタイル(ラスター): サークルの帯の一番下(ポリゴンの上、ネイティブの円とポリラインのタイルの下)。 */
val CIRCLE_TILE = key(OverlayKind.Circle, Int.MIN_VALUE)

/** ポリラインのタイル(ラスター): ポリラインの帯の一番下(サークルの上、ネイティブのポリラインの下)。 */
val POLYLINE_TILE = key(OverlayKind.Polyline, Int.MIN_VALUE)

Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/mapconductor/maplibre/MapLibreViewController.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.mapconductor.maplibre

import com.mapconductor.core.circle.CIRCLE_TILE_LAYER_ID
import com.mapconductor.core.circle.CircleTiler
import com.mapconductor.core.circle.circleTileRasterLayerState
import com.mapconductor.core.circle.OnCircleEventHandler
import com.mapconductor.core.controller.BaseMapViewController
import com.mapconductor.core.features.GeoPointInterface
Expand Down Expand Up @@ -124,6 +127,18 @@ class MapLibreViewController(
}
}

// Many circles too: the same raster layer path, in the circle band.
circleController.tiler =
CircleTiler().apply {
onTemplate = { template, tileSize ->
if (template != null) {
rasterLayerController.upsert(circleTileRasterLayerState(template, tileSize))
} else {
rasterLayerController.removeById(CIRCLE_TILE_LAYER_ID)
}
}
}

// Many polylines too: the same raster layer path, in the polyline band.
polylineController.tiler =
PolylineTiler().apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class MapLibreCircleOverlayRenderer(

/** Reapply the current composition after a MapLibre style is created or replaced. */
fun redraw() {
val circles = circleManager.allEntities()
val circles = circleManager.nativeEntities().filter { (it.circle as MapLibreActualCircle?) != null }
holder.map.style?.let { style ->
coroutine.launch { layer.draw(circles, style) }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mapconductor.maplibre.raster

import com.mapconductor.core.circle.CIRCLE_TILE_LAYER_ID
import com.mapconductor.core.controller.OverlayKind
import com.mapconductor.core.polygon.POLYGON_TILE_LAYER_ID
import com.mapconductor.core.polyline.POLYLINE_TILE_LAYER_ID
Expand Down Expand Up @@ -32,6 +33,8 @@ class MapLibreRasterLayerOverlayRenderer(

private fun isPolylineTileRaster(state: RasterLayerState): Boolean = state.id == POLYLINE_TILE_LAYER_ID

private fun isCircleTileRaster(state: RasterLayerState): Boolean = state.id == CIRCLE_TILE_LAYER_ID

override suspend fun onAdd(
data: List<RasterLayerOverlayRendererInterface.AddParamsInterface>,
): List<MapLibreRasterLayerHandle?> =
Expand Down Expand Up @@ -120,6 +123,8 @@ class MapLibreRasterLayerOverlayRenderer(
MapLibreOverlayStacking.MARKER_TILE
} else if (isPolygonTileRaster(state)) {
MapLibreOverlayStacking.POLYGON_TILE
} else if (isCircleTileRaster(state)) {
MapLibreOverlayStacking.CIRCLE_TILE
} else if (isPolylineTileRaster(state)) {
MapLibreOverlayStacking.POLYLINE_TILE
} else {
Expand Down Expand Up @@ -157,7 +162,7 @@ class MapLibreRasterLayerOverlayRenderer(
val ordered =
stateById.values
.asSequence()
.filter { !isMarkerTileRaster(it) && !isPolygonTileRaster(it) && !isPolylineTileRaster(it) }
.filter { !isMarkerTileRaster(it) && !isPolygonTileRaster(it) && !isPolylineTileRaster(it) && !isCircleTileRaster(it) }
.sortedBy { it.zIndex }
.mapNotNull { state -> handleById[state.id]?.let { handle -> state to handle } }
.toList()
Expand Down
Loading