Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic local data mode (2.3 beta) #267

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
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 app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ android {
applicationId "org.blitzortung.android.app"
minSdkVersion 21
targetSdkVersion 34
versionCode 325
versionName '2.2.6'
versionCode 328
versionName '2.3-beta2'
multiDexEnabled false
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ package org.blitzortung.android.alert.handler

import android.content.res.Resources
import android.location.Location
import android.util.Log
import org.blitzortung.android.alert.AlertParameters
import org.blitzortung.android.alert.AlertResult
import org.blitzortung.android.alert.data.AlertSector
import org.blitzortung.android.app.Main.Companion.LOG_TAG
import org.blitzortung.android.data.beans.GridElement
import org.blitzortung.android.data.beans.GridParameters
import org.blitzortung.android.data.beans.Strike
Expand All @@ -39,7 +41,13 @@ open class AlertDataHandler @Inject internal constructor(
fun checkStrikes(
strikes: Strikes, location: Location, parameters: AlertParameters,
referenceTime: Long = System.currentTimeMillis()
): AlertResult {
): AlertResult? {
val gridParameters: GridParameters? = strikes.gridParameters
if (gridParameters != null && !gridParameters.isGlobal && !gridParameters.contains(location.longitude, location.latitude, 0.2)) {
Log.v(LOG_TAG, "Location $location is not in grid ${gridParameters.longitudeInterval} + ${gridParameters.latitudeInterval}")
return null
}

val sectors = createSectors(parameters)

val thresholdTime = referenceTime - parameters.alarmInterval
Expand All @@ -54,7 +62,7 @@ open class AlertDataHandler @Inject internal constructor(
checkStrike(
alertSector,
strike,
strikes.gridParameters,
gridParameters,
parameters.measurementSystem,
location,
thresholdTime
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/org/blitzortung/android/app/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ class Main : FragmentActivity(), OnSharedPreferenceChangeListener {
}

with(binding.histogramView) {
mapFragment = [email protected]
setStrikesOverlay(strikeListOverlay)
setOnClickListener {
val currentResult = currentResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@ import android.graphics.RectF
import android.util.AttributeSet
import android.util.Log
import org.blitzortung.android.app.Main
import org.blitzortung.android.app.Main.Companion.LOG_TAG
import org.blitzortung.android.app.R
import org.blitzortung.android.data.Parameters
import org.blitzortung.android.data.beans.GridParameters
import org.blitzortung.android.data.provider.result.ResultEvent
import org.blitzortung.android.map.MapFragment
import org.blitzortung.android.map.overlay.StrikeListOverlay
import org.blitzortung.android.protocol.Event
import org.blitzortung.android.util.TabletAwareView

private const val SMALL_TEXT_SCALE = 0.6f

class HistogramView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
Expand All @@ -40,10 +46,14 @@ class HistogramView @JvmOverloads constructor(
private val backgroundPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
private val foregroundPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
private val textPaint: Paint
private val smallTextPaint: Paint
private val defaultForegroundColor: Int
private val backgroundRect: RectF
private var strikesOverlay: StrikeListOverlay? = null
private var histogram: IntArray? = null
private var gridParameters: GridParameters? = null
private var parameters: Parameters? = null
lateinit var mapFragment: MapFragment

val dataConsumer = { event: Event ->
if (event is ResultEvent) {
Expand All @@ -61,6 +71,11 @@ class HistogramView @JvmOverloads constructor(
textSize = [email protected]
textAlign = Paint.Align.RIGHT
}
smallTextPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = defaultForegroundColor
textSize = [email protected] * SMALL_TEXT_SCALE
textAlign = Paint.Align.RIGHT
}

foregroundPaint.strokeWidth = 5f

Expand Down Expand Up @@ -94,21 +109,38 @@ class HistogramView @JvmOverloads constructor(
backgroundRect.set(0f, 0f, width.toFloat(), height.toFloat())
canvas.drawRect(backgroundRect, backgroundPaint)

var topCoordinate = padding

val bb = mapFragment.mapView.boundingBox
val text = "%.2f..%.2f %.2f..%.2f".format(bb.lonWest, bb.lonEast, bb.latSouth, bb.latNorth)
canvas.drawText(text, width - padding, topCoordinate + textSize / 1.2f * SMALL_TEXT_SCALE, smallTextPaint)
topCoordinate += (textSize + padding) * SMALL_TEXT_SCALE

val gridParameters = gridParameters
if (gridParameters != null) {
val text = "%.2f..%.2f %.2f..%.2f".format(gridParameters.longitudeStart, gridParameters.longitudeEnd, gridParameters.latitudeEnd, gridParameters.latitudeStart)
canvas.drawText(text, width - padding, topCoordinate + textSize / 1.2f * SMALL_TEXT_SCALE, smallTextPaint)
topCoordinate += (textSize + padding) * SMALL_TEXT_SCALE
}

val maximumCount = histogram.maxOrNull() ?: 0

canvas.drawText(
"%.1f/%s _".format(
maximumCount.toFloat() / minutesPerBin, resources.getString(R.string.unit_minute)
), width - 2 * padding, padding + textSize / 1.2f, textPaint
), width - 2 * padding, topCoordinate + textSize / 1.2f, textPaint
)

topCoordinate += textSize

val ymax = if (maximumCount == 0) 1 else maximumCount

val x0 = padding
val xd = (width - 2 * padding) / (histogram.size - 1)

val y0 = height - padding
val yd = (height - 2 * padding - textSize) / ymax
Log.v(LOG_TAG, "HistogramView.onDraw() height: $height, top $topCoordinate")
val yd = (height - topCoordinate - padding) / ymax

foregroundPaint.strokeWidth = 5f
for (i in 0 until histogram.size - 1) {
Expand Down Expand Up @@ -140,6 +172,8 @@ class HistogramView @JvmOverloads constructor(
histogram = null
} else {
val histogram = dataEvent.histogram
gridParameters = dataEvent.gridParameters
parameters = dataEvent.parameters

val hasHistogram = histogram != null && histogram.isNotEmpty()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ class LegendView @JvmOverloads constructor(
var strikesOverlay: StrikeListOverlay? = null

init {

setBackgroundColor(Color.TRANSPARENT)
}

Expand Down
62 changes: 57 additions & 5 deletions app/src/main/java/org/blitzortung/android/data/MainDataHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

package org.blitzortung.android.data

import android.animation.Animator
import android.animation.Animator.AnimatorListener
import android.content.Context
import android.content.SharedPreferences
import android.location.Location
Expand All @@ -40,11 +42,13 @@ import org.blitzortung.android.data.provider.result.RequestStartedEvent
import org.blitzortung.android.data.provider.result.ResultEvent
import org.blitzortung.android.data.provider.result.StatusEvent
import org.blitzortung.android.location.LocationEvent
import org.blitzortung.android.map.OwnMapView
import org.blitzortung.android.protocol.ConsumerContainer
import org.blitzortung.android.util.Period
import org.osmdroid.events.MapListener
import org.osmdroid.events.ScrollEvent
import org.osmdroid.events.ZoomEvent
import org.osmdroid.util.BoundingBox
import java.util.Locale
import java.util.concurrent.atomic.AtomicLong
import javax.inject.Inject
Expand Down Expand Up @@ -193,6 +197,9 @@ class MainDataHandler @Inject constructor(
}

private fun sendEvent(dataEvent: DataEvent) {
if (dataEvent is ResultEvent) {
localData.storeResult(dataEvent.gridParameters)
}
if (dataEvent is ResultEvent && dataEvent.flags.storeResult) {
dataConsumerContainer.storeAndBroadcast(dataEvent)
} else {
Expand Down Expand Up @@ -408,23 +415,46 @@ class MainDataHandler @Inject constructor(
}

override fun onScroll(event: ScrollEvent?): Boolean {
return false
return if (event != null) {
val mapView = event.source as OwnMapView
val updated = updateLocation(mapView.boundingBox)
ensureUpdate(updated, mapView)
} else {
false
}
}

override fun onZoom(event: ZoomEvent?): Boolean {
return if (event != null) {
updateAutoGridSize(event.zoomLevel)
val mapView = event.source as OwnMapView
val updateAutoGridSize = updateAutoGridSize(event.zoomLevel)
val updateLocation = updateLocation(mapView.boundingBox, updateAutoGridSize)
val updated = updateLocation || updateAutoGridSize
ensureUpdate(updated, mapView)
} else {
false
}
}

private fun ensureUpdate(updated: Boolean, mapView: OwnMapView): Boolean {
if (updated) {
if (mapView.isAnimating) {
addUpdateAfterAnimationListener(mapView)
} else {
updateData()
}
}
return updated
}

fun updateLocation(boundingBox: BoundingBox, force: Boolean = false): Boolean = localData.update(boundingBox, force)

fun updateAutoGridSize(zoomLevel: Double): Boolean =
if (autoGridSize) {
val gridSize = when {
zoomLevel >= 8f -> 5000
zoomLevel in 6f..8f -> 10000
zoomLevel in 4f..6f -> 25000
zoomLevel in 5.5f..8f -> 10000
zoomLevel in 4f..5.5f -> 25000
zoomLevel in 2f..4f -> 50000
else -> 100000
}
Expand All @@ -434,7 +464,6 @@ class MainDataHandler @Inject constructor(
"MainDataHandler.updateAutoGridSize() $zoomLevel : ${parameters.gridSize} -> $gridSize"
)
parameters = parameters.copy(gridSize = gridSize)
updateData()
true
} else {
false
Expand All @@ -443,6 +472,29 @@ class MainDataHandler @Inject constructor(
false
}

private fun addUpdateAfterAnimationListener(mapView: OwnMapView) {
val animator = mapView.animator()

if (animator != null && !animator.listeners.contains(animatorListener)) {
animator.addListener(animatorListener)
}
}

private val animatorListener = object : AnimatorListener {
override fun onAnimationStart(animation: Animator) {
}

override fun onAnimationEnd(animation: Animator) {
[email protected]()
}

override fun onAnimationCancel(animation: Animator) {
[email protected]()
}

override fun onAnimationRepeat(animation: Animator) {
}
}

fun calculateTotalCacheSize(): CacheSize = cache.calculateTotalSize()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import java.io.Serializable
data class Parameters(
val region: Int = -1,
val gridSize: Int = 0,
val dataArea: Int = 5,
val interval: TimeInterval = TimeInterval(),
val countThreshold: Int = 0,
val localReference: LocalReference? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ data class GridParameters(

val rectCenterLatitude: Double = latitudeStart - latitudeDelta * latitudeBins / 2.0

val longitudeEnd: Double = longitudeStart + longitudeDelta * longitudeBins

val latitudeEnd: Double = latitudeStart - latitudeDelta * latitudeBins

fun getCenterLongitude(offset: Int): Double {
return longitudeStart + longitudeDelta * (offset + 0.5)
}
Expand All @@ -46,18 +50,20 @@ data class GridParameters(
return latitudeStart - latitudeDelta * (offset + 0.5)
}

private val rectLongitudeDelta: Double = longitudeDelta * longitudeBins
val longitudeInterval: Double = longitudeDelta * longitudeBins

val latitudeInterval: Double = latitudeDelta * latitudeBins

private val rectLatitudeDelta: Double = latitudeDelta * latitudeBins
val isGlobal = longitudeInterval > 350 && latitudeInterval > 170

fun getRect(projection: Projection): RectF {
var leftTop = Point()
leftTop = projection.toPixels(
Coordsys.toMapCoords(longitudeStart, latitudeStart), leftTop
)
var bottomRight = Point()
val longitudeEnd = longitudeStart + rectLongitudeDelta
val latitudeEnd = latitudeStart - rectLatitudeDelta
val longitudeEnd = longitudeStart + longitudeInterval
val latitudeEnd = latitudeStart - latitudeInterval
bottomRight = projection.toPixels(
Coordsys.toMapCoords(
longitudeEnd,
Expand All @@ -68,4 +74,10 @@ data class GridParameters(
// Log.d(Main.LOG_TAG, "GridParameters.getRect() $longitudeStart - $longitudeEnd ($longitudeDelta, #$longitudeBins) $latitudeEnd - $latitudeStart ($latitudeDelta, #$latitudeBins)")
return RectF(leftTop.x.toFloat(), leftTop.y.toFloat(), bottomRight.x.toFloat(), bottomRight.y.toFloat())
}

fun contains(longitude: Double, latitude: Double, inset: Double = 0.0): Boolean {
val inLongitude = longitude in longitudeStart + inset..longitudeEnd - inset
val inLatitude = latitude in latitudeStart - latitudeDelta * latitudeBins + inset .. latitudeStart - inset
return inLongitude && inLatitude
}
}
Loading
Loading