blob: 2c15c0dc48619a87326a35c03ea02332e80250e5 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.egg.paint
import java.util.LinkedList
import android.view.MotionEvent
class SpotFilter(internal var mBufSize: Int, posDecay: Float, pressureDecay: Float, internal var mPlotter: Plotter) {
val spots = LinkedList<MotionEvent.PointerCoords>() // newest at front
val tmpSpot = MotionEvent.PointerCoords()
var lastTool = MotionEvent.TOOL_TYPE_UNKNOWN
val posDecay: Float
val pressureDecay: Float
interface Plotter {
fun plot(s: MotionEvent.PointerCoords)
}
init {
this.posDecay = if (posDecay in 0f..1f) posDecay else 1f
this.pressureDecay = if (pressureDecay in 0f..1f) pressureDecay else 1f
}
fun filterInto(out: MotionEvent.PointerCoords, tool: Int): MotionEvent.PointerCoords {
lastTool = tool
var wi = 1f // weight for ith component (position)
var w = 0f // total weight
var wi_press = 1f // weight for ith component (pressure)
var w_press = 0f // total weight (pressure)
var x = 0f
var y = 0f
var pressure = 0f
var size = 0f
for (pi in spots) {
x += pi.x * wi
y += pi.y * wi
pressure += pi.pressure * wi_press
size += pi.size * wi_press
w += wi
wi *= posDecay // exponential backoff
w_press += wi_press
wi_press *= pressureDecay
if (PRECISE_STYLUS_INPUT && tool == MotionEvent.TOOL_TYPE_STYLUS) {
// just take the newest one, no need to average
break
}
}
out.x = x / w
out.y = y / w
out.pressure = pressure / w_press
out.size = size / w_press
return out
}
protected fun addInternal(c: MotionEvent.PointerCoords, tool: Int) {
val coord =
if (spots.size == mBufSize) {
spots.removeLast()
} else {
MotionEvent.PointerCoords()
}
coord.copyFrom(c)
spots.add(0, coord)
filterInto(tmpSpot, tool)
mPlotter.plot(tmpSpot)
}
fun add(cv: List<MotionEvent.PointerCoords>, tool: Int) {
for (c in cv) {
addInternal(c, tool)
}
}
fun add(evt: MotionEvent) {
val tool = evt.getToolType(0)
for (i in 0 until evt.historySize) {
evt.getHistoricalPointerCoords(0, i, tmpSpot)
addInternal(tmpSpot, tool)
}
evt.getPointerCoords(0, tmpSpot)
addInternal(tmpSpot, tool)
}
fun finish() {
while (spots.size > 0) {
filterInto(tmpSpot, lastTool)
spots.removeLast()
mPlotter.plot(tmpSpot)
}
spots.clear()
}
companion object {
var PRECISE_STYLUS_INPUT = true
}
}