summaryrefslogtreecommitdiff
path: root/android-app/app/src/main/temp/CompassRoseView.kt
diff options
context:
space:
mode:
Diffstat (limited to 'android-app/app/src/main/temp/CompassRoseView.kt')
-rwxr-xr-xandroid-app/app/src/main/temp/CompassRoseView.kt217
1 files changed, 217 insertions, 0 deletions
diff --git a/android-app/app/src/main/temp/CompassRoseView.kt b/android-app/app/src/main/temp/CompassRoseView.kt
new file mode 100755
index 0000000..8e755a3
--- /dev/null
+++ b/android-app/app/src/main/temp/CompassRoseView.kt
@@ -0,0 +1,217 @@
+package org.terst.nav.temp // Temporarily placing in 'temp' due to permissions, actual package should be 'org.terst.nav'
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Rect
+import android.util.AttributeSet
+import android.view.View
+import kotlin.math.cos
+import kotlin.math.min
+import kotlin.math.sin
+
+class CompassRoseView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+) : View(context, attrs, defStyleAttr) {
+
+ private var heading: Float = 0f // Current heading in degrees
+ set(value) {
+ field = value % 360 // Ensure heading is within 0-359
+ invalidate()
+ }
+ private var cog: Float = 0f // Course Over Ground in degrees
+ set(value) {
+ field = value % 360
+ invalidate()
+ }
+ private var isTrueHeading: Boolean = true // True for True heading, false for Magnetic
+
+ private val rosePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ color = Color.DKGRAY
+ style = Paint.Style.STROKE
+ strokeWidth = 2f
+ }
+
+ private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ color = Color.WHITE
+ textSize = 30f
+ textAlign = Paint.Align.CENTER
+ }
+
+ private val cardinalTextPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ color = Color.WHITE
+ textSize = 40f
+ textAlign = Paint.Align.CENTER
+ isFakeBoldText = true
+ }
+
+ private val majorTickPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ color = Color.WHITE
+ strokeWidth = 3f
+ }
+
+ private val minorTickPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ color = Color.GRAY
+ strokeWidth = 1f
+ }
+
+ private val headingNeedlePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ color = Color.RED
+ style = Paint.Style.FILL
+ }
+
+ private val cogArrowPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ color = Color.BLUE
+ style = Paint.Style.FILL
+ strokeWidth = 5f
+ }
+
+ private var viewCenterX: Float = 0f
+ private var viewCenterY: Float = 0f
+ private var radius: Float = 0f
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+ viewCenterX = w / 2f
+ viewCenterY = h / 2f
+ radius = min(w, h) / 2f - 40f // Leave some padding
+ textPaint.textSize = radius / 6f
+ cardinalTextPaint.textSize = radius / 4.5f
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ // Draw outer circle
+ canvas.drawCircle(viewCenterX, viewCenterY, radius, rosePaint)
+
+ // Draw cardinal and intercardinal points
+ drawCardinalPoints(canvas)
+
+ // Draw tick marks and degree labels
+ drawDegreeMarks(canvas)
+
+ // Draw heading needle
+ drawHeadingNeedle(canvas, heading, headingNeedlePaint, radius * 0.8f)
+
+ // Draw COG arrow
+ drawCogArrow(canvas, cog, cogArrowPaint, radius * 0.6f)
+
+ // Draw current heading text in the center
+ drawHeadingText(canvas)
+ }
+
+ private fun drawCardinalPoints(canvas: Canvas) {
+ val cardinalPoints = listOf("N", "E", "S", "W")
+ val angles = listOf(0f, 90f, 180f, 270f)
+ val textBound = Rect()
+
+ for (i in cardinalPoints.indices) {
+ val angleRad = Math.toRadians((angles[i] - 90).toDouble()).toFloat() // Adjust for canvas 0deg at 3 o'clock
+ val x = viewCenterX + (radius * 0.9f) * cos(angleRad)
+ val y = viewCenterY + (radius * 0.9f) * sin(angleRad)
+
+ val text = cardinalPoints[i]
+ cardinalTextPaint.getTextBounds(text, 0, text.length, textBound)
+ val textHeight = textBound.height()
+
+ canvas.drawText(text, x, y + textHeight / 2, cardinalTextPaint)
+ }
+ }
+
+ private fun drawDegreeMarks(canvas: Canvas) {
+ for (i in 0 until 360 step 5) {
+ val isMajor = (i % 30 == 0) // Major ticks every 30 degrees
+ val tickLength = if (isMajor) 30f else 15f
+ val currentTickPaint = if (isMajor) majorTickPaint else minorTickPaint
+ val startRadius = radius - tickLength
+
+ val angleRad = Math.toRadians((i - 90).toDouble()).toFloat() // Adjust for canvas 0deg at 3 o'clock
+
+ val startX = viewCenterX + startRadius * cos(angleRad)
+ val startY = viewCenterY + startRadius * sin(angleRad)
+ val endX = viewCenterX + radius * cos(angleRad)
+ val endY = viewCenterY + radius * sin(angleRad)
+
+ canvas.drawLine(startX, startY, endX, endY, currentTickPaint)
+
+ if (isMajor && i != 0) { // Draw degree labels for major ticks (except North)
+ val textRadius = radius - tickLength - textPaint.textSize / 2 - 10f
+ val textX = viewCenterX + textRadius * cos(angleRad)
+ val textY = viewCenterY + textRadius * sin(angleRad) + textPaint.textSize / 2
+
+ canvas.drawText(i.toString(), textX, textY, textPaint)
+ }
+ }
+ }
+
+ private fun drawHeadingNeedle(canvas: Canvas, angle: Float, paint: Paint, length: Float) {
+ val angleRad = Math.toRadians((angle - 90).toDouble()).toFloat() // Adjust for canvas 0deg at 3 o'clock
+ val endX = viewCenterX + length * cos(angleRad)
+ val endY = viewCenterY + length * sin(angleRad)
+
+ // Draw a simple triangle for the needle
+ val needleWidth = 20f
+ val path = android.graphics.Path()
+ path.moveTo(endX, endY)
+ path.lineTo(viewCenterX + needleWidth * cos(angleRad - Math.toRadians(90.0).toFloat()),
+ viewCenterY + needleWidth * sin(angleRad - Math.toRadians(90.0).toFloat()))
+ path.lineTo(viewCenterX + needleWidth * cos(angleRad + Math.toRadians(90.0).toFloat()),
+ viewCenterY + needleWidth * sin(angleRad + Math.toRadians(90.0).toFloat()))
+ path.close()
+ canvas.drawPath(path, paint)
+ }
+
+ private fun drawCogArrow(canvas: Canvas, angle: Float, paint: Paint, length: Float) {
+ val angleRad = Math.toRadians((angle - 90).toDouble()).toFloat() // Adjust for canvas 0deg at 3 o'clock
+ val endX = viewCenterX + length * cos(angleRad)
+ val endY = viewCenterY + length * sin(angleRad)
+
+ val startX = viewCenterX + (length * 0.5f) * cos(angleRad)
+ val startY = viewCenterY + (length * 0.5f) * sin(angleRad)
+
+ canvas.drawLine(startX, startY, endX, endY, paint)
+
+ // Draw arrow head
+ val arrowHeadLength = 25f
+ val arrowHeadWidth = 15f
+ val arrowPath = android.graphics.Path()
+ arrowPath.moveTo(endX, endY)
+ arrowPath.lineTo(endX - arrowHeadLength * cos(angleRad - Math.toRadians(30.0).toFloat()),
+ endY - arrowHeadLength * sin(angleRad - Math.toRadians(30.0).toFloat()))
+ arrowPath.moveTo(endX, endY)
+ arrowPath.lineTo(endX - arrowHeadLength * cos(angleRad + Math.toRadians(30.0).toFloat()),
+ endY - arrowHeadLength * sin(angleRad + Math.toRadians(30.0).toFloat()))
+ canvas.drawPath(arrowPath, paint)
+ }
+
+ private fun drawHeadingText(canvas: Canvas) {
+ val headingText = "${heading.toInt()}°" + if (isTrueHeading) "T" else "M"
+ textPaint.color = Color.WHITE
+ textPaint.textSize = radius / 3.5f // Larger text for main heading
+ canvas.drawText(headingText, viewCenterX, viewCenterY + textPaint.textSize / 3, textPaint)
+ }
+
+ /**
+ * Sets the current heading to display.
+ * @param newHeading The new heading value in degrees (0-359).
+ * @param isTrue Whether the heading is True (magnetic variation applied) or Magnetic.
+ */
+ fun setHeading(newHeading: Float, isTrue: Boolean) {
+ this.heading = newHeading
+ this.isTrueHeading = isTrue
+ invalidate()
+ }
+
+ /**
+ * Sets the Course Over Ground (COG) to display.
+ * @param newCog The new COG value in degrees (0-359).
+ */
+ fun setCog(newCog: Float) {
+ this.cog = newCog
+ invalidate()
+ }
+}