Bimba.git

ref: e5c7dc933fba208aba52c3dcb305b522120b4b2c

app/src/main/java/xyz/apiote/bimba/czwek/repo/LineAbstract.kt


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: GPL-3.0-or-later

package xyz.apiote.bimba.czwek.repo

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Path
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.graphics.drawable.toBitmap
import xyz.apiote.bimba.czwek.R
import xyz.apiote.bimba.czwek.dpToPixel
import xyz.apiote.bimba.czwek.dpToPixelI
import kotlin.math.abs
import kotlin.math.pow

interface LineAbstract {
	fun textColour(c: Colour): Int {
		val black = relativeLuminance(Colour(0u, 0u, 0u)) + .05
		val white = relativeLuminance(Colour(255u, 255u, 255u)) + .05
		val colour = relativeLuminance(c) + .05
		return if ((white / colour) > (colour / black)) {
			Color.WHITE
		} else {
			Color.BLACK
		}
	}

	private fun relativeLuminance(colour: Colour): Double {
		val r = fromSRGB(colour.R.toDouble() / 0xff)
		val g = fromSRGB(colour.G.toDouble() / 0xff)
		val b = fromSRGB(colour.B.toDouble() / 0xff)
		return 0.2126 * r + 0.7152 * g + 0.0722 * b
	}

	private fun fromSRGB(part: Double): Double {
		return if (part <= 0.03928) {
			part / 12.92
		} else {
			((part + 0.055) / 1.055).pow(2.4)
		}
	}

	fun icon(context: Context, type: LineType, colour: Colour, scale: Float): Bitmap {
		val drawingBitmap = Bitmap.createBitmap(
			dpToPixelI(24f / scale), dpToPixelI(24f / scale), Bitmap.Config.ARGB_8888
		)
		val canvas = Canvas(drawingBitmap)

		canvas.drawPath(getSquirclePath(
			dpToPixel(.8f / scale), dpToPixel(.8f / scale), dpToPixelI(11.2f / scale)
		), Paint().apply { color = textColour(colour) })
		canvas.drawPath(getSquirclePath(
			dpToPixel(1.6f / scale), dpToPixel(1.6f / scale), dpToPixelI(10.4f / scale)
		), Paint().apply { color = colour.toInt() })

		val iconID = when (type) {
			LineType.BUS -> R.drawable.bus_black
			LineType.TRAM -> R.drawable.tram_black
			LineType.TROLLEYBUS -> R.drawable.trolleybus_black
			LineType.METRO -> R.drawable.metro_black
			LineType.RAIL -> R.drawable.train_black
			LineType.FERRY -> R.drawable.ferry_black
			LineType.CABLE_TRAM -> TODO()
			LineType.CABLE_CAR -> TODO()
			LineType.FUNICULAR -> TODO()
			LineType.MONORAIL -> R.drawable.monorail_black
			LineType.UNKNOWN -> R.drawable.vehicle_black
		}
		val icon = AppCompatResources.getDrawable(context, iconID)?.mutate()?.apply {
			setTint(textColour(colour))
		}?.toBitmap(dpToPixelI(19.2f / scale), dpToPixelI(19.2f / scale), Bitmap.Config.ARGB_8888)
		canvas.drawBitmap(
			icon!!, dpToPixel(2.4f / scale), dpToPixel(2.4f / scale), Paint()
		)
		return drawingBitmap
	}

	private fun getSquirclePath(
		left: Float, top: Float, radius: Int
	): Path {
		val radiusToPow = (radius * radius * radius).toDouble()
		val path = Path()
		path.moveTo(-radius.toFloat(), 0f)
		for (x in -radius..radius) path.lineTo(
			x.toFloat(), Math.cbrt(radiusToPow - abs(x * x * x)).toFloat()
		)
		for (x in radius downTo -radius) path.lineTo(
			x.toFloat(), -Math.cbrt(radiusToPow - abs(x * x * x)).toFloat()
		)
		path.close()
		val matrix = Matrix()
		matrix.postTranslate((left + radius), (top + radius))
		path.transform(matrix)
		return path
	}
}