• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.egg.paint
18 
19 import java.util.LinkedList
20 
21 import android.view.MotionEvent
22 
23 class SpotFilter(internal var mBufSize: Int, posDecay: Float, pressureDecay: Float, internal var mPlotter: Plotter) {
24     val spots = LinkedList<MotionEvent.PointerCoords>() // newest at front
25     val tmpSpot = MotionEvent.PointerCoords()
26     var lastTool = MotionEvent.TOOL_TYPE_UNKNOWN
27 
28     val posDecay: Float
29     val pressureDecay: Float
30 
31     interface Plotter {
plotnull32         fun plot(s: MotionEvent.PointerCoords)
33     }
34 
35     init {
36         this.posDecay = if (posDecay in 0f..1f) posDecay else 1f
37         this.pressureDecay = if (pressureDecay in 0f..1f) pressureDecay else 1f
38     }
39 
filterIntonull40     fun filterInto(out: MotionEvent.PointerCoords, tool: Int): MotionEvent.PointerCoords {
41         lastTool = tool
42 
43         var wi = 1f // weight for ith component (position)
44         var w = 0f // total weight
45         var wi_press = 1f // weight for ith component (pressure)
46         var w_press = 0f // total weight (pressure)
47 
48         var x = 0f
49         var y = 0f
50         var pressure = 0f
51         var size = 0f
52         for (pi in spots) {
53             x += pi.x * wi
54             y += pi.y * wi
55 
56             pressure += pi.pressure * wi_press
57             size += pi.size * wi_press
58 
59             w += wi
60             wi *= posDecay // exponential backoff
61 
62             w_press += wi_press
63             wi_press *= pressureDecay
64 
65             if (PRECISE_STYLUS_INPUT && tool == MotionEvent.TOOL_TYPE_STYLUS) {
66                 // just take the newest one, no need to average
67                 break
68             }
69         }
70 
71         out.x = x / w
72         out.y = y / w
73         out.pressure = pressure / w_press
74         out.size = size / w_press
75         return out
76     }
77 
addInternalnull78     protected fun addInternal(c: MotionEvent.PointerCoords, tool: Int) {
79         val coord =
80                 if (spots.size == mBufSize) {
81                     spots.removeLast()
82                 } else {
83                     MotionEvent.PointerCoords()
84                 }
85         coord.copyFrom(c)
86 
87         spots.add(0, coord)
88 
89         filterInto(tmpSpot, tool)
90         mPlotter.plot(tmpSpot)
91     }
92 
addnull93     fun add(cv: List<MotionEvent.PointerCoords>, tool: Int) {
94         for (c in cv) {
95             addInternal(c, tool)
96         }
97     }
98 
addnull99     fun add(evt: MotionEvent) {
100         val tool = evt.getToolType(0)
101         for (i in 0 until evt.historySize) {
102             evt.getHistoricalPointerCoords(0, i, tmpSpot)
103             addInternal(tmpSpot, tool)
104         }
105         evt.getPointerCoords(0, tmpSpot)
106         addInternal(tmpSpot, tool)
107     }
108 
finishnull109     fun finish() {
110         while (spots.size > 0) {
111             filterInto(tmpSpot, lastTool)
112             spots.removeLast()
113             mPlotter.plot(tmpSpot)
114         }
115 
116         spots.clear()
117     }
118 
119     companion object {
120         var PRECISE_STYLUS_INPUT = true
121     }
122 }
123 
124 
125