Skip to content

Commit

Permalink
Draw AR grid
Browse files Browse the repository at this point in the history
Closes #2036 and closes #2039
  • Loading branch information
kylecorry31 committed Nov 21, 2023
1 parent 6b6f7d8 commit 8b85b7d
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.kylecorry.sol.units.Coordinate
import com.kylecorry.trail_sense.R
import com.kylecorry.trail_sense.shared.FormatService
import com.kylecorry.trail_sense.shared.camera.AugmentedRealityUtils
import com.kylecorry.trail_sense.shared.extensions.getValuesBetween

class LinearCompassView : BaseCompassView {

Expand Down Expand Up @@ -112,26 +113,6 @@ class LinearCompassView : BaseCompassView {
noStroke()
}

/**
* Returns the values between min and max, inclusive, that are divisible by divisor
* @param min The minimum value
* @param max The maximum value
* @param divisor The divisor
* @return The values between min and max, inclusive, that are divisible by divisor
*/
private fun getValuesBetween(min: Float, max: Float, divisor: Float): List<Float> {
val values = mutableListOf<Float>()
val start = min.roundNearest(divisor)
var i = start
while (i <= max) {
if (i >= min) {
values.add(i)
}
i += divisor
}
return values
}

override fun setup() {
super.setup()
textAlign(TextAlign.Center)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kylecorry.trail_sense.shared.extensions

import com.kylecorry.sol.math.SolMath.roundNearest
import com.kylecorry.sol.math.geometry.Size
import com.kylecorry.sol.science.geology.CoordinateBounds
import com.kylecorry.sol.science.geology.Geofence
Expand All @@ -20,4 +21,24 @@ fun CoordinateBounds.Companion.from(geofences: List<Geofence>): CoordinateBounds
}

return from(corners)
}

/**
* Returns the values between min and max, inclusive, that are divisible by divisor
* @param min The minimum value
* @param max The maximum value
* @param divisor The divisor
* @return The values between min and max, inclusive, that are divisible by divisor
*/
fun getValuesBetween(min: Float, max: Float, divisor: Float): List<Float> {
val values = mutableListOf<Float>()
val start = min.roundNearest(divisor)
var i = start
while (i <= max) {
if (i >= min) {
values.add(i)
}
i += divisor
}
return values
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package com.kylecorry.trail_sense.tools.augmented_reality

import android.graphics.Color
import android.graphics.Path
import androidx.annotation.ColorInt
import com.kylecorry.andromeda.canvas.ICanvasDrawer
import com.kylecorry.andromeda.canvas.TextMode
import com.kylecorry.andromeda.core.units.PixelCoordinate
import com.kylecorry.sol.math.SolMath
import com.kylecorry.sol.math.SolMath.roundNearest
import com.kylecorry.trail_sense.R
import com.kylecorry.trail_sense.shared.extensions.getValuesBetween
import kotlin.math.absoluteValue
import kotlin.math.hypot

class ARGridLayer(
private val spacing: Int = 30,
@ColorInt private val color: Int = Color.WHITE,
@ColorInt private val northColor: Int = color,
@ColorInt private val horizonColor: Int = color,
@ColorInt private val labelColor: Int = color,
private val thicknessDp: Float = 1f,
private val resolutionDegrees: Int = 5
) : ARLayer {

private var isSetup = false
private var textSize: Float = 0f
private var northString: String = ""
private var southString: String = ""
private var eastString: String = ""
private var westString: String = ""

override fun draw(drawer: ICanvasDrawer, view: AugmentedRealityView) {

if (!isSetup){
textSize = drawer.sp(16f)
northString = view.context.getString(R.string.direction_north)
southString = view.context.getString(R.string.direction_south)
eastString = view.context.getString(R.string.direction_east)
westString = view.context.getString(R.string.direction_west)
isSetup = true
}

val maxAngle = hypot(view.fov.width, view.fov.height) * 1.2f

val minVertical = (view.inclination - maxAngle / 2f).toInt().coerceIn(-90, 90)
val maxVertical = (view.inclination + maxAngle / 2f).toInt().coerceIn(-90, 90)

val isPoleVisible = minVertical.absoluteValue == 90 || maxVertical.absoluteValue == 90

val minHorizontal = if (isPoleVisible) 0 else (view.azimuth - maxAngle / 2f).toInt()
val maxHorizontal = if (isPoleVisible) 360 else (view.azimuth + maxAngle / 2f).toInt()

val latitudes = getValuesBetween(minVertical.toFloat(), maxVertical.toFloat(), spacing.toFloat())
val longitudes = getValuesBetween(minHorizontal.toFloat(), maxHorizontal.toFloat(), spacing.toFloat()).distinctBy {
SolMath.normalizeAngle(it)
}

drawer.noFill()
drawer.strokeWeight(drawer.dp(thicknessDp))

// Draw horizontal lines
val horizontalPointRange = steppedRangeInclusive(minHorizontal, maxHorizontal, resolutionDegrees)
for (i in latitudes) {
var previous: PixelCoordinate? = null
for (j in horizontalPointRange) {
if (i.toInt() == 0){
drawer.stroke(horizonColor)
} else {
drawer.stroke(color)
}
val pixel = view.toPixel(AugmentedRealityView.HorizonCoordinate(j.toFloat(), i))
if (previous != null){
drawer.line(previous.x, previous.y, pixel.x, pixel.y)
}
previous = pixel
}
}

// Draw vertical lines
val verticalPointRange = steppedRangeInclusive(minVertical, maxVertical, resolutionDegrees)
for (i in longitudes) {
var previous: PixelCoordinate? = null
for (j in verticalPointRange) {
if (i.toInt() == 0){
drawer.stroke(northColor)
} else {
drawer.stroke(color)
}
val pixel = view.toPixel(AugmentedRealityView.HorizonCoordinate(i, j.toFloat()))
if (previous != null){
drawer.line(previous.x, previous.y, pixel.x, pixel.y)
}
previous = pixel
}
}


drawer.noStroke()

// Draw cardinal direction labels
val offset = 2f
val north = view.toPixel(AugmentedRealityView.HorizonCoordinate(0f, offset))
val south = view.toPixel(AugmentedRealityView.HorizonCoordinate(180f, offset))
val east = view.toPixel(AugmentedRealityView.HorizonCoordinate(90f, offset))
val west = view.toPixel(AugmentedRealityView.HorizonCoordinate(-90f, offset))

drawLabel(drawer, view, northString, north)
drawLabel(drawer, view, southString, south)
drawLabel(drawer, view, eastString, east)
drawLabel(drawer, view, westString, west)
}

private fun drawLabel(drawer: ICanvasDrawer, view: AugmentedRealityView, text: String, position: PixelCoordinate){
drawer.textSize(drawer.sp(16f))
drawer.fill(labelColor)
drawer.push()
drawer.rotate(view.sideInclination, position.x, position.y)
drawer.text(text, position.x, position.y)
drawer.pop()
}

private fun steppedRangeInclusive(min: Int, max: Int, step: Int): List<Int> {
val values = mutableListOf<Int>()
for (i in min..max step step) {
values.add(i)
}
if (values.lastOrNull() != max){
values.add(max)
}
return values
}

override fun invalidate() {
// Do nothing
}

override fun onClick(
drawer: ICanvasDrawer,
view: AugmentedRealityView,
pixel: PixelCoordinate
): Boolean {
return false
}

override fun onFocus(drawer: ICanvasDrawer, view: AugmentedRealityView): Boolean {
return false
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import androidx.core.view.updateLayoutParams
import com.kylecorry.andromeda.core.coroutines.onDefault
import com.kylecorry.andromeda.core.coroutines.onMain
import com.kylecorry.andromeda.core.system.Resources
import com.kylecorry.andromeda.core.ui.Colors.withAlpha
import com.kylecorry.andromeda.fragments.BoundFragment
import com.kylecorry.andromeda.fragments.inBackground
import com.kylecorry.andromeda.fragments.observeFlow
Expand Down Expand Up @@ -73,8 +74,13 @@ class AugmentedRealityFragment : BoundFragment<FragmentAugmentedRealityBinding>(

private val sunLayer = ARMarkerLayer()
private val moonLayer = ARMarkerLayer()
private val horizonLayer = ARHorizonLayer()
private val northLayer = ARNorthLayer()
private val gridLayer = ARGridLayer(
30,
northColor = AppColor.Orange.color,
horizonColor = Color.WHITE,
labelColor = Color.WHITE,
color = Color.WHITE.withAlpha(100)
)

private var isCameraEnabled = true

Expand Down Expand Up @@ -103,7 +109,7 @@ class AugmentedRealityFragment : BoundFragment<FragmentAugmentedRealityBinding>(
binding.camera.setScaleType(PreviewView.ScaleType.FIT_CENTER)
binding.camera.setShowTorch(false)

binding.arView.setLayers(listOf(northLayer, horizonLayer, sunLayer, moonLayer, beaconLayer))
binding.arView.setLayers(listOf(gridLayer, sunLayer, moonLayer, beaconLayer))

binding.cameraToggle.setOnClickListener {
if (isCameraEnabled) {
Expand Down

0 comments on commit 8b85b7d

Please sign in to comment.