Bimba.git

ref: v3.7.0

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
103
104
// 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.cbrt
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 -> R.drawable.cablecar_black
			LineType.CABLE_CAR -> R.drawable.cabletram_black
			LineType.FUNICULAR -> R.drawable.funicular_black
			LineType.MONORAIL -> R.drawable.monorail_black
			LineType.UNKNOWN -> R.drawable.vehicle_black
			LineType.PLANE -> R.drawable.plane_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(), cbrt(radiusToPow - abs(x * x * x)).toFloat()
		)
		for (x in radius downTo -radius) path.lineTo(
			x.toFloat(), -cbrt(radiusToPow - abs(x * x * x)).toFloat()
		)
		path.close()
		val matrix = Matrix()
		matrix.postTranslate((left + radius), (top + radius))
		path.transform(matrix)
		return path
	}
}