Skip to content

Instantly share code, notes, and snippets.

@jiulongw
Last active December 21, 2017 06:20
Show Gist options
  • Save jiulongw/68537473e475e79cb9df413517553da3 to your computer and use it in GitHub Desktop.
Save jiulongw/68537473e475e79cb9df413517553da3 to your computer and use it in GitHub Desktop.
Backup of experiment code Kotlin Drawing with variable width stroke
class Stroke(val start: Segment) {
data class Segment(val point: PointF, val width: Float, val direction: PointF)
private val vertices = ArrayList<Float>()
fun addPoint(point: PointF, width: Float) {
if (vertices.isEmpty()) {
start.direction.set(direction(start.point, point))
val (a, b) = edgeOf(start.point, start.direction, start.width)
vertices.add(a.x)
vertices.add(a.y)
vertices.add(b.x)
vertices.add(b.y)
}
addVertices(point, width)
}
fun drawTo(canvas: Canvas, paint: Paint) {
if (vertices.isEmpty()) {
canvas.drawCircle(start.point.x, start.point.y, start.width / 2, paint)
} else {
val extent = start.width / 2
val p = PointF(-start.direction.y, start.direction.x)
var angle = Math.toDegrees(Math.acos(p.x.toDouble())).toFloat()
if (p.y < 0) {
angle = -angle
}
val path = Path()
path.moveTo(vertices[0], vertices[1])
var i = 1
while (i * 4 < vertices.size) {
val x = vertices[i * 4]
val y = vertices[i * 4 + 1]
path.lineTo(x, y)
i++
}
i--
while (i >= 0) {
val x = vertices[i * 4 + 2]
val y = vertices[i * 4 + 3]
path.lineTo(x, y)
i--
}
canvas.drawPath(path, paint)
// canvas.drawArc(start.point.x - extent, start.point.y - extent, start.point.x + extent, start.point.y + extent, angle, 180f, true, paint)
//
// canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.size, vertices.toFloatArray(), 0, vertices.toFloatArray(), 0, null, 0, triangles.toShortArray(), 0, triangles.size, paint)
}
}
private fun direction(from: PointF, to: PointF): PointF {
val d = PointF(to.x - from.x, to.y - from.y)
val length = d.length()
return if (length > 0) {
PointF(d.x / length, d.y / length)
} else {
PointF(1f, 0f)
}
}
private fun edgeOf(point: PointF, direction: PointF, width: Float): Pair<PointF, PointF> {
val p = PointF(-direction.y, direction.x)
return Pair(
PointF(point.x + p.x * width, point.y + p.y * width),
PointF(point.x - p.x * width, point.y - p.y * width)
)
}
private fun addVertices(to: PointF, width: Float) {
assert(vertices.size >= 2 * 2)
val ia = (vertices.size / 2) - 2
val ib = ia + 1
val a = PointF(vertices[ia * 2], vertices[ia * 2 + 1])
val b = PointF(vertices[ib * 2], vertices[ib * 2 + 1])
val from = PointF((a.x + b.x) / 2, (a.y + b.y) / 2)
val dir = direction(from, to)
val (c, d) = edgeOf(to, dir, width)
vertices.add(c.x)
vertices.add(c.y)
vertices.add(d.x)
vertices.add(d.y)
}
}
private fun updateLayerSize(layer: Layer?, size: Size, keepContent: Boolean): Layer {
if (layer == null) {
val bitmap = Bitmap.createBitmap(size.width, size.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
return Layer(bitmap, canvas)
} else if (layer.bitmap.width != size.width || layer.bitmap.height != size.height) {
val bitmap = Bitmap.createBitmap(size.width, size.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
if (keepContent) {
canvas.drawBitmap(layer.bitmap, null, Rect(0, 0, size.width, size.height), paint)
}
layer.bitmap.recycle()
return Layer(bitmap, canvas)
} else {
return layer
}
}
package ai.inlight.board.app
import android.graphics.*
import android.util.Log
/**
* Created by jiulongw on 12/20/17.
*/
class Stroke(point: PointF, width: Float) {
data class Segment(val point: PointF, val width: Float, val direction: PointF)
private val start = Segment(point, width, PointF())
private val vertices = ArrayList<Float>()
fun addPoint(point: PointF, width: Float) {
if (vertices.isEmpty()) {
start.direction.set(direction(start.point, point))
val (a, b) = edgeOf(start.point, start.direction, start.width)
vertices.add(a.x)
vertices.add(a.y)
vertices.add(b.x)
vertices.add(b.y)
}
addVertices(point, width)
}
fun drawTo(canvas: Canvas, paint: Paint) {
if (vertices.isEmpty()) {
canvas.drawCircle(start.point.x, start.point.y, start.width / 2, paint)
} else {
// val extent = start.width / 2
// val p = PointF(-start.direction.y, start.direction.x)
// var angle = Math.toDegrees(Math.acos(p.x.toDouble())).toFloat()
// if (p.y < 0) {
// angle = -angle
// }
//
// canvas.drawArc(start.point.x - extent, start.point.y - extent, start.point.x + extent, start.point.y + extent, angle, 180f, true, paint)
// val points = FloatArray(vertices.size * 6)
val path = Path()
path.moveTo(vertices[0], vertices[1])
for (i in 0 until vertices.size / 2 - 2 step 2) {
val k = i * 2
path.lineTo(vertices[k + 4], vertices[k + 5])
// val j = i * 12
// val k = i * 2
//
// points[j] = vertices[k]
// points[j + 1] = vertices[k + 1]
// points[j + 2] = vertices[k + 2]
// points[j + 3] = vertices[k + 3]
//
// points[j + 4] = vertices[k + 2]
// points[j + 5] = vertices[k + 3]
// points[j + 6] = vertices[k + 4]
// points[j + 7] = vertices[k + 5]
//
// points[j + 8] = vertices[k + 4]
// points[j + 9] = vertices[k + 5]
// points[j + 10] = vertices[k]
// points[j + 11] = vertices[k + 1]
//
// points[j + 12] = vertices[k + 2]
// points[j + 13] = vertices[k + 3]
// points[j + 14] = vertices[k + 4]
// points[j + 15] = vertices[k + 5]
//
// points[j + 16] = vertices[k + 4]
// points[j + 17] = vertices[k + 5]
// points[j + 18] = vertices[k + 6]
// points[j + 19] = vertices[k + 7]
//
// points[j + 20] = vertices[k + 6]
// points[j + 21] = vertices[k + 7]
// points[j + 22] = vertices[k + 2]
// points[j + 23] = vertices[k + 3]
}
for (i in vertices.size / 2 - 1 downTo 0 step 2) {
val k = i * 2
path.lineTo(vertices[k], vertices[k + 1])
}
canvas.drawPath(path, paint)
// canvas.drawPath(path, paint)
// canvas.drawLines(points, paint)
// while (i * 4 < vertices.size) {
// val x = vertices[i * 4]
// val y = vertices[i * 4 + 1]
//
// path.lineTo(x, y)
// i++
// }
//
// i--
//
// while (i >= 0) {
// val x = vertices[i * 4 + 2]
// val y = vertices[i * 4 + 3]
//
// path.lineTo(x, y)
// i--
// }
//
// canvas.drawPath(path, paint)
//
// canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.size, vertices.toFloatArray(), 0, vertices.toFloatArray(), 0, null, 0, triangles.toShortArray(), 0, triangles.size, paint)
}
}
private fun direction(from: PointF, to: PointF): PointF {
val d = PointF(to.x - from.x, to.y - from.y)
val length = d.length()
return if (length > 0) {
PointF(d.x / length, d.y / length)
} else {
PointF(1f, 0f)
}
}
private fun edgeOf(point: PointF, direction: PointF, width: Float): Pair<PointF, PointF> {
val p = PointF(-direction.y, direction.x)
return Pair(
PointF(point.x + p.x * width, point.y + p.y * width),
PointF(point.x - p.x * width, point.y - p.y * width)
)
}
private fun addVertices(to: PointF, width: Float) {
assert(vertices.size >= 2 * 2)
val ia = (vertices.size / 2) - 2
val ib = ia + 1
val a = PointF(vertices[ia * 2], vertices[ia * 2 + 1])
val b = PointF(vertices[ib * 2], vertices[ib * 2 + 1])
val from = PointF((a.x + b.x) / 2, (a.y + b.y) / 2)
val dir = direction(from, to)
val (c, d) = edgeOf(to, dir, width)
vertices.add(c.x)
vertices.add(c.y)
vertices.add(d.x)
vertices.add(d.y)
}
}
private fun handleMotionEvent(m: MotionEvent) {
when (m.actionMasked) {
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
val index = m.actionIndex
val id = m.getPointerId(index)
val x = m.getX(index) - offset.x
val y = m.getY(index) - offset.y
val path = Path()
val rect = RectF()
path.moveTo(x, y)
rect.offsetTo(x, y)
rect.inset(-extent, -extent)
contents[id] = DrawContent(path, rect, PointF(x, y), true)
}
MotionEvent.ACTION_MOVE -> {
Log.i("CanvasView", "Move: ${m.pointerCount}")
var ccc = 0
for (i in 0 until m.pointerCount) {
ccc++
val id = m.getPointerId(i)
val x = m.getX(i) - offset.x
val y = m.getY(i) - offset.y
Log.i("CanvasView", "i: $i, id: $id, x: $x, y: $y, ccc: $ccc")
val rect = RectF()
rect.offsetTo(x, y)
rect.inset(-extent, -extent)
val content = contents[id]!!
content.path.lineTo(x, y)
content.rect.union(rect)
content.lastPoint.set(x, y)
content.dirty = true
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment