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
Expand Up @@ -2,7 +2,8 @@ package com.kylecorry.trail_sense.shared.dem.map_layers

import com.kylecorry.trail_sense.shared.map_layers.ui.layers.tiles.TileMapLayer

class AspectLayer : TileMapLayer<AspectMapTileSource>(AspectMapTileSource(), minZoomLevel = 10) {

override val layerId: String = AspectMapTileSource.SOURCE_ID
}
class AspectLayer : TileMapLayer<AspectMapTileSource>(
AspectMapTileSource(),
AspectMapTileSource.SOURCE_ID,
minZoomLevel = 10
)
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ class ContourGeoJsonSource : GeoJsonSource {

companion object {
const val SOURCE_ID = "contour"
const val SHOW_LABELS = "show_labels"
const val DEFAULT_SHOW_LABELS = true
const val COLOR = "color"
val DEFAULT_COLOR = ElevationColorStrategy.Brown
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,9 @@
package com.kylecorry.trail_sense.shared.dem.map_layers

import android.os.Bundle
import com.kylecorry.trail_sense.shared.map_layers.ui.layers.geojson.GeoJsonLayer

class ContourLayer : GeoJsonLayer<ContourGeoJsonSource>(
ContourGeoJsonSource(),
minZoomLevel = 13,
layerId = ContourGeoJsonSource.SOURCE_ID
) {

override fun setPreferences(preferences: Bundle) {
super.setPreferences(preferences)
renderer.configureLineStringRenderer(
shouldRenderLabels = preferences.getBoolean(
ContourGeoJsonSource.SHOW_LABELS,
ContourGeoJsonSource.DEFAULT_SHOW_LABELS
)
)
// TODO: More experimentation required before this is enabled for everyone
// renderer.configureLineStringRenderer(shouldRenderSmoothPaths = isDebug())
}

}
ContourGeoJsonSource.SOURCE_ID,
minZoomLevel = 13
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import com.kylecorry.trail_sense.shared.map_layers.ui.layers.tiles.TileMapLayer

class ElevationLayer : TileMapLayer<ElevationMapTileSource>(
ElevationMapTileSource(),
minZoomLevel = 10,
) {

override val layerId: String = ElevationMapTileSource.SOURCE_ID
}
ElevationMapTileSource.SOURCE_ID,
minZoomLevel = 10
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ package com.kylecorry.trail_sense.shared.dem.map_layers
import com.kylecorry.trail_sense.shared.map_layers.ui.layers.tiles.TileMapLayer

class HillshadeLayer :
TileMapLayer<HillshadeMapTileSource>(HillshadeMapTileSource(), minZoomLevel = 10) {

override val layerId: String = HillshadeMapTileSource.SOURCE_ID

override val isTimeDependent: Boolean = true

init {
shouldMultiply = true
}
}
TileMapLayer<HillshadeMapTileSource>(
HillshadeMapTileSource(),
HillshadeMapTileSource.SOURCE_ID,
minZoomLevel = 10,
shouldMultiply = true,
isTimeDependent = true
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package com.kylecorry.trail_sense.shared.dem.map_layers
import com.kylecorry.trail_sense.shared.map_layers.ui.layers.tiles.TileMapLayer

class RuggednessLayer :
TileMapLayer<RuggednessMapTileSource>(RuggednessMapTileSource(), minZoomLevel = 10) {

override val layerId: String = RuggednessMapTileSource.SOURCE_ID
}
TileMapLayer<RuggednessMapTileSource>(
RuggednessMapTileSource(),
RuggednessMapTileSource.SOURCE_ID,
minZoomLevel = 10
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package com.kylecorry.trail_sense.shared.dem.map_layers

import com.kylecorry.trail_sense.shared.map_layers.ui.layers.tiles.TileMapLayer

class SlopeLayer : TileMapLayer<SlopeMapTileSource>(SlopeMapTileSource(), minZoomLevel = 10) {

override val layerId: String = SlopeMapTileSource.SOURCE_ID
}
class SlopeLayer : TileMapLayer<SlopeMapTileSource>(
SlopeMapTileSource(),
SlopeMapTileSource.SOURCE_ID,
minZoomLevel = 10
)
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ object DefaultMapLayerDefinitions {
const val ENABLED = "enabled"
const val OPACITY = "opacity"
const val DEFAULT_OPACITY = 100
}
const val BACKGROUND_COLOR = "background_color"
const val SHOW_LABELS = "show_labels"
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class ConfigurableGeoJsonLayer(
) :
GeoJsonLayer<ConfigurableGeoJsonSource>(
ConfigurableGeoJsonSource(initialData),
layerId = layerId
layerId
) {

private var onClickListener: ((GeoJsonFeature) -> Boolean)? = null
Expand All @@ -28,4 +28,4 @@ class ConfigurableGeoJsonLayer(
override fun onClick(feature: GeoJsonFeature): Boolean {
return onClickListener?.invoke(feature) ?: super.onClick(feature)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import com.kylecorry.andromeda.canvas.ICanvasDrawer
import com.kylecorry.andromeda.core.units.PixelCoordinate
import com.kylecorry.andromeda.geojson.GeoJsonFeature
import com.kylecorry.andromeda.geojson.GeoJsonFeatureCollection
import com.kylecorry.andromeda.core.cache.AppServiceRegistry
import com.kylecorry.trail_sense.shared.UserPreferences
import com.kylecorry.trail_sense.shared.extensions.isClickable
import com.kylecorry.trail_sense.shared.getBounds
import com.kylecorry.trail_sense.shared.map_layers.MapLayerBackgroundTask
Expand All @@ -15,25 +17,32 @@ import com.kylecorry.trail_sense.shared.map_layers.ui.layers.IAsyncLayer
import com.kylecorry.trail_sense.shared.map_layers.ui.layers.IMapView
import com.kylecorry.trail_sense.shared.map_layers.ui.layers.MapLayerParams
import com.kylecorry.trail_sense.shared.map_layers.ui.layers.geojson.sources.GeoJsonSource
import com.kylecorry.trail_sense.shared.withId
import com.kylecorry.trail_sense.tools.map.MapToolRegistration
import com.kylecorry.trail_sense.tools.paths.ui.PathBackgroundColor
import com.kylecorry.trail_sense.tools.tools.infrastructure.Tools
import com.kylecorry.luna.timer.CoroutineTimer
import kotlinx.coroutines.CancellationException
import java.time.Duration
import java.time.Instant
import kotlin.math.roundToInt

typealias OnGeoJsonFeatureClickListener = (GeoJsonFeature) -> Unit

open class GeoJsonLayer<T : GeoJsonSource>(
protected val source: T,
override val layerId: String,
private val minZoomLevel: Int? = null,
private val taskRunner: MapLayerBackgroundTask = MapLayerBackgroundTask(),
override val layerId: String
override val isTimeDependent: Boolean = false,
private val refreshInterval: Duration? = null
) : IAsyncLayer {
val renderer = GeoJsonRenderer()
private var isInvalid = true
private var updateListener: (() -> Unit)? = null
private var onFeatureClick: OnGeoJsonFeatureClickListener? = null
protected var layerPreferences: Bundle = bundleOf()
private val refreshTimer = refreshInterval?.let { CoroutineTimer { refresh() } }

private var _timeOverride: Instant? = null
private var _renderTime: Instant = Instant.now()
Expand All @@ -50,6 +59,8 @@ open class GeoJsonLayer<T : GeoJsonSource>(
}

init {
val prefs = AppServiceRegistry.get<UserPreferences>()
renderer.configureLineStringRenderer(shouldRenderWithDrawLines = prefs.navigation.useFastPathRendering)
renderer.setOnClickListener(this::onClick)
taskRunner.addTask { context, viewBounds, bounds, projection ->
isInvalid = false
Expand Down Expand Up @@ -89,6 +100,23 @@ open class GeoJsonLayer<T : GeoJsonSource>(
DefaultMapLayerDefinitions.OPACITY,
DefaultMapLayerDefinitions.DEFAULT_OPACITY
) / 100f
// TODO: Eventually make this a geojson feature property instead of a global setting
if (preferences.containsKey(DefaultMapLayerDefinitions.BACKGROUND_COLOR)) {
val backgroundColorId =
preferences.getString(DefaultMapLayerDefinitions.BACKGROUND_COLOR)?.toLongOrNull()
renderer.configureLineStringRenderer(
backgroundColor = PathBackgroundColor.entries.withId(backgroundColorId ?: 0)
?: PathBackgroundColor.None
)
}
if (preferences.containsKey(DefaultMapLayerDefinitions.SHOW_LABELS)) {
renderer.configureLineStringRenderer(
shouldRenderLabels = preferences.getBoolean(
DefaultMapLayerDefinitions.SHOW_LABELS,
true
)
)
}
}

override fun draw(
Expand Down Expand Up @@ -144,13 +172,15 @@ open class GeoJsonLayer<T : GeoJsonSource>(
MapToolRegistration.BROADCAST_GEOJSON_FEATURE_SELECTION_CHANGED,
this::onSelectionBroadcast
)
refreshInterval?.let { refreshTimer?.interval(it, it) }
}

override fun stop() {
Tools.unsubscribe(
MapToolRegistration.BROADCAST_GEOJSON_FEATURE_SELECTION_CHANGED,
this::onSelectionBroadcast
)
refreshTimer?.stop()
taskRunner.stop()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,19 @@ import com.kylecorry.trail_sense.shared.map_layers.ui.layers.IAsyncLayer
import com.kylecorry.trail_sense.shared.map_layers.ui.layers.IMapView
import com.kylecorry.trail_sense.shared.map_layers.ui.layers.IMapViewProjection
import java.time.Instant
import java.time.Duration
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt

abstract class TileMapLayer<T : TileSource>(
protected val source: T,
override val layerId: String,
private val taskRunner: MapLayerBackgroundTask = MapLayerBackgroundTask(),
private var minZoomLevel: Int? = null
private var minZoomLevel: Int? = null,
private val shouldMultiply: Boolean = false,
override val isTimeDependent: Boolean = false,
private val refreshInterval: Duration? = null
) : IAsyncLayer {
private var _timeOverride: Instant? = null
private var _renderTime: Instant = Instant.now()
Expand All @@ -61,15 +66,6 @@ abstract class TileMapLayer<T : TileSource>(
isAntiAlias = false
isFilterBitmap = true
}
var shouldMultiply = false
set(value) {
field = value
if (value && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
layerPaint.setBlendMode(BlendModeCompat.MULTIPLY)
} else {
layerPaint.setBlendMode(BlendModeCompat.SRC_OVER)
}
}
var multiplyAlpha: Int = 255
set(value) {
field = value
Expand All @@ -88,6 +84,7 @@ abstract class TileMapLayer<T : TileSource>(
private val loadTimer = CoroutineTimer {
queue.load(16)
}
private val refreshTimer = refreshInterval?.let { CoroutineTimer { refresh() } }

private val sourceCleanupTask = BackgroundTask {
source.cleanup()
Expand All @@ -102,6 +99,11 @@ abstract class TileMapLayer<T : TileSource>(
}

init {
if (shouldMultiply && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
layerPaint.setBlendMode(BlendModeCompat.MULTIPLY)
} else {
layerPaint.setBlendMode(BlendModeCompat.SRC_OVER)
}
taskRunner.addTask { _: Context, _: Rectangle, _: CoordinateBounds, projection: IMapViewProjection ->
queue.setMapProjection(projection)
}
Expand Down Expand Up @@ -438,10 +440,12 @@ abstract class TileMapLayer<T : TileSource>(
notifyListeners()
}
loadTimer.interval(100)
refreshInterval?.let { refreshTimer?.interval(it, it) }
}

override fun stop() {
loadTimer.stop()
refreshTimer?.stop()
taskRunner.stop()
loader?.clearCache()
loader = null
Expand All @@ -462,6 +466,22 @@ abstract class TileMapLayer<T : TileSource>(
notifyListeners()
}

fun improveResolution(
bounds: CoordinateBounds,
zoom: Int,
minimumTileCount: Int
) {
var tileCount: Int
var zoomOffset = -1
do {
zoomOffset++
tileCount = TileMath.getTiles(bounds, zoom + zoomOffset).size
} while (tileCount < minimumTileCount && zoomOffset < 10)

setZoomOffset(zoomOffset)
notifyListeners()
}

private fun refreshTime() {
_renderTime = _timeOverride ?: Instant.now()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,11 @@
package com.kylecorry.trail_sense.tools.astronomy.map_layers

import com.kylecorry.andromeda.core.time.CoroutineTimer
import com.kylecorry.trail_sense.shared.map_layers.ui.layers.tiles.TileMapLayer
import java.time.Duration

class LunarEclipseLayer : TileMapLayer<LunarEclipseTileSource>(LunarEclipseTileSource()) {

override val isTimeDependent = true

override val layerId: String = LunarEclipseTileSource.SOURCE_ID

private val timer = CoroutineTimer {
refresh()
}

override fun start() {
super.start()
timer.interval(REFRESH_INTERVAL, REFRESH_INTERVAL)
}

override fun stop() {
super.stop()
timer.stop()
}

companion object {
private val REFRESH_INTERVAL: Duration = Duration.ofMinutes(2)
}
}
class LunarEclipseLayer : TileMapLayer<LunarEclipseTileSource>(
LunarEclipseTileSource(),
LunarEclipseTileSource.SOURCE_ID,
isTimeDependent = true,
refreshInterval = Duration.ofMinutes(2)
)
Original file line number Diff line number Diff line change
@@ -1,30 +1,11 @@
package com.kylecorry.trail_sense.tools.astronomy.map_layers

import com.kylecorry.andromeda.core.time.CoroutineTimer
import com.kylecorry.trail_sense.shared.map_layers.ui.layers.tiles.TileMapLayer
import java.time.Duration

class NightLayer : TileMapLayer<NightTileSource>(NightTileSource()) {

override val isTimeDependent = true

override val layerId: String = NightTileSource.SOURCE_ID

private val timer = CoroutineTimer {
refresh()
}

override fun start() {
super.start()
timer.interval(REFRESH_INTERVAL, REFRESH_INTERVAL)
}

override fun stop() {
super.stop()
timer.stop()
}

companion object {
private val REFRESH_INTERVAL: Duration = Duration.ofMinutes(1)
}
}
class NightLayer : TileMapLayer<NightTileSource>(
NightTileSource(),
NightTileSource.SOURCE_ID,
isTimeDependent = true,
refreshInterval = Duration.ofMinutes(1)
)
Loading