Skip to content

Instantly share code, notes, and snippets.

@IlyaPavlovskii
Created March 27, 2023 11:13
Show Gist options
  • Save IlyaPavlovskii/4bee00442263622e6250a60ae03491a3 to your computer and use it in GitHub Desktop.
Save IlyaPavlovskii/4bee00442263622e6250a60ae03491a3 to your computer and use it in GitHub Desktop.
package by.bulba.ipsc.calculator.feature.calculator.utils
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.layout.ScaleFactor
private val PATH_DATA_PARSER_REGEX = "(?=[A-Za-z]{1})".toRegex()
internal fun Size.scaleToEtalon(etalonVectorSize: Size): ScaleFactor {
return if (this.width < height) {
(this.width / etalonVectorSize.width)
.let { scale -> ScaleFactor(scale, scale) }
} else {
(this.height / etalonVectorSize.height)
.let { scale -> ScaleFactor(scale, scale) }
}
}
internal fun drawPathFromPathData(
path: Path = Path(),
scaleFactor: ScaleFactor,
pathData: String,
offsetSize: Size = Size(0f, 0f),
): Path {
val list = pathData.split(PATH_DATA_PARSER_REGEX)
var lastKnownOffset = Offset(0f, 0f)
list.forEach { pathPart ->
val startChar = try {
pathPart.toCharArray()[0]
} catch (aioobe: ArrayIndexOutOfBoundsException) {
return@forEach
}
val drawPathPattern = DrawPathPattern.parseKey(startChar) ?: return@forEach
when (drawPathPattern) {
DrawPathPattern.MOVE_TO -> {
val values = drawPathPattern.pattern.find(pathPart)?.groupValues ?: return@forEach
val x = values[3].toFloat()
val y = values[5].toFloat()
path.moveTo(scaleFactor = scaleFactor, x = x, y = y, offsetSize = offsetSize)
lastKnownOffset = Offset(x, y)
}
DrawPathPattern.LINE_TO -> {
val values = drawPathPattern.pattern.find(pathPart)?.groupValues ?: return@forEach
val x = values[3].toFloat()
val y = values[5].toFloat()
path.lineTo(scaleFactor = scaleFactor, x = x, y = y, offsetSize = offsetSize)
lastKnownOffset = Offset(x, y)
}
DrawPathPattern.HORIZONTAL_LINE_TO -> {
val values = drawPathPattern.pattern.find(pathPart)?.groupValues ?: return@forEach
val x = values[3].toFloat()
path.lineTo(scaleFactor = scaleFactor, x = x, y = lastKnownOffset.y, offsetSize = offsetSize)
lastKnownOffset = lastKnownOffset.copy(x = x)
}
DrawPathPattern.VERTICAL_LINE_TO -> {
val values = drawPathPattern.pattern.find(pathPart)?.groupValues ?: return@forEach
val y = values[3].toFloat()
path.lineTo(scaleFactor = scaleFactor, x = lastKnownOffset.x, y = y, offsetSize = offsetSize)
lastKnownOffset = lastKnownOffset.copy(y = y)
}
}
}
return path
}
private enum class DrawPathPattern(
val key: Char,
val pattern: Regex,
) {
MOVE_TO(
key = 'M',
pattern = "([A-Z](\\s)*)(\\d+(\\.\\d+)*),(\\d+(\\.\\d+)*)".toRegex(),
),
LINE_TO(
key = 'L',
pattern = "([A-Z](\\s)*)(\\d+(\\.\\d+)*),(\\d+(\\.\\d+)*)".toRegex(),
),
HORIZONTAL_LINE_TO(
key = 'H',
pattern = "([A-Z](\\s)*)(\\d+(\\.\\d+)*)".toRegex(),
),
VERTICAL_LINE_TO(
key = 'V',
pattern = "([A-Z](\\s)*)(\\d+(\\.\\d+)*)".toRegex(),
),
;
companion object {
fun parseKey(key: Char): DrawPathPattern? = values().firstOrNull { it.key == key }
}
}
private fun Path.moveTo(scaleFactor: ScaleFactor, x: Float, y: Float, offsetSize: Size) =
this.moveTo(
x * scaleFactor.scaleX + offsetSize.width,
y * scaleFactor.scaleY + offsetSize.height
)
private fun Path.lineTo(scaleFactor: ScaleFactor, x: Float, y: Float, offsetSize: Size) =
this.lineTo(
x * scaleFactor.scaleX + offsetSize.width,
y * scaleFactor.scaleY + offsetSize.height
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment