Skip to content
This repository was archived by the owner on Dec 27, 2024. It is now read-only.

Commit 93f1276

Browse files
committed
add cycles
1 parent cc6449f commit 93f1276

File tree

4 files changed

+479
-9
lines changed

4 files changed

+479
-9
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/*
2+
* Copyright (C) 2020 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+
package curves
17+
18+
import java.util.*
19+
20+
/**
21+
* This generates variable frequency oscillation curves
22+
*
23+
*
24+
*/
25+
class Cycles {
26+
private var mPeriod = floatArrayOf()
27+
private var mPosition = floatArrayOf()
28+
private lateinit var mArea: FloatArray
29+
private var mCustomType: String? = null
30+
private var mCustomCurve: MonoSpline? = null
31+
private var mType = 0
32+
private var mPI2 = Math.PI.toFloat() * 2
33+
private var mNormalized = false
34+
override fun toString(): String {
35+
return "pos =" + Arrays.toString(mPosition) + " period=" + Arrays.toString(mPeriod)
36+
}
37+
38+
// @TODO: add description
39+
fun setType(type: Int, customType: String) {
40+
mType = type
41+
mCustomType = customType
42+
if (mCustomType != null) {
43+
mCustomCurve = buildWave(customType)
44+
}
45+
}
46+
47+
// @TODO: add description
48+
fun addPoint(position: Float, period: Float) {
49+
val len = mPeriod.size + 1
50+
var j = Arrays.binarySearch(mPosition, position)
51+
if (j < 0) {
52+
j = -j - 1
53+
}
54+
mPosition = Arrays.copyOf(mPosition, len)
55+
mPeriod = Arrays.copyOf(mPeriod, len)
56+
mArea = FloatArray(len)
57+
System.arraycopy(mPosition, j, mPosition, j + 1, len - j - 1)
58+
mPosition[j] = position
59+
mPeriod[j] = period
60+
mNormalized = false
61+
}
62+
63+
/**
64+
* After adding point every thing must be normalized
65+
*/
66+
fun normalize() {
67+
var totalArea = 0f
68+
var totalCount = 0f
69+
for (i in mPeriod.indices) {
70+
totalCount += mPeriod[i]
71+
}
72+
for (i in 1 until mPeriod.size) {
73+
val h = (mPeriod[i - 1] + mPeriod[i]) / 2
74+
val w = mPosition[i] - mPosition[i - 1]
75+
totalArea = totalArea + w * h
76+
}
77+
// scale periods to normalize it
78+
for (i in mPeriod.indices) {
79+
mPeriod[i] *= (totalCount / totalArea)
80+
}
81+
mArea[0] = 0f
82+
for (i in 1 until mPeriod.size) {
83+
val h = (mPeriod[i - 1] + mPeriod[i]) / 2
84+
val w = mPosition[i] - mPosition[i - 1]
85+
mArea[i] = mArea[i - 1] + w * h
86+
}
87+
mNormalized = true
88+
}
89+
90+
fun getP(time: Float): Float {
91+
var time = time
92+
if (time < 0) {
93+
time = 0f
94+
} else if (time > 1) {
95+
time = 1f
96+
}
97+
var index = Arrays.binarySearch(mPosition, time)
98+
var p = 0f
99+
if (index > 0) {
100+
p = 1f
101+
} else if (index != 0) {
102+
index = -index - 1
103+
val t = time
104+
val m = ((mPeriod[index] - mPeriod[index - 1])
105+
/ (mPosition[index] - mPosition[index - 1]))
106+
p = mArea[index - 1] + (mPeriod[index - 1] - m * mPosition[index - 1]) * (t - mPosition[index - 1]) + m * (t * t - mPosition[index - 1] * mPosition[index - 1]) / 2
107+
}
108+
return p
109+
}
110+
111+
// @TODO: add description
112+
fun getValue(time: Float, phase: Float): Float {
113+
val angle = phase + getP(time) // angle is / by 360
114+
return when (mType) {
115+
SIN_WAVE -> Math.sin((mPI2 * angle).toDouble()).toFloat()
116+
SQUARE_WAVE -> Math.signum(0.5 - angle % 1).toFloat()
117+
TRIANGLE_WAVE -> 1 - Math.abs((angle * 4 + 1) % 4 - 2)
118+
SAW_WAVE -> (angle * 2 + 1) % 2 - 1
119+
REVERSE_SAW_WAVE -> 1 - (angle * 2 + 1) % 2
120+
COS_WAVE -> Math.cos((mPI2 * (phase + angle)).toDouble()).toFloat()
121+
BOUNCE -> {
122+
val x = 1 - Math.abs(angle * 4 % 4 - 2)
123+
1 - x * x
124+
}
125+
126+
CUSTOM -> mCustomCurve!!.getPos((angle % 1), 0)
127+
else -> Math.sin((mPI2 * angle).toDouble()).toFloat()
128+
}
129+
}
130+
131+
fun getDP(time: Float): Float {
132+
var time = time
133+
if (time <= 0) {
134+
time = 0.00001f
135+
} else if (time >= 1) {
136+
time = .999999f
137+
}
138+
var index = Arrays.binarySearch(mPosition, time)
139+
var p = 0f
140+
if (index > 0) {
141+
return 0f
142+
}
143+
if (index != 0) {
144+
index = -index - 1
145+
val t = time
146+
val m = ((mPeriod[index] - mPeriod[index - 1])
147+
/ (mPosition[index] - mPosition[index - 1]))
148+
p = m * t + (mPeriod[index - 1] - m * mPosition[index - 1])
149+
}
150+
return p
151+
}
152+
153+
// @TODO: add description
154+
fun getSlope(time: Float, phase: Float, dphase: Float): Float {
155+
val angle = phase + getP(time)
156+
val dangle_dtime = getDP(time) + dphase
157+
return when (mType) {
158+
SIN_WAVE -> (mPI2 * dangle_dtime * Math.cos((mPI2 * angle).toDouble())).toFloat()
159+
SQUARE_WAVE -> 0f
160+
TRIANGLE_WAVE -> 4 * dangle_dtime * Math.signum((angle * 4 + 3) % 4 - 2)
161+
SAW_WAVE -> dangle_dtime * 2
162+
REVERSE_SAW_WAVE -> -dangle_dtime * 2
163+
COS_WAVE -> (-mPI2 * dangle_dtime * Math.sin((mPI2 * angle).toDouble())).toFloat()
164+
BOUNCE -> 4 * dangle_dtime * ((angle * 4 + 2) % 4 - 2)
165+
CUSTOM -> mCustomCurve!!.getSlope((angle % 1), 0)
166+
else -> (mPI2 * dangle_dtime * Math.cos((mPI2 * angle).toDouble())).toFloat()
167+
}
168+
}
169+
170+
companion object {
171+
var TAG = "Oscillator"
172+
const val SIN_WAVE = 0 // theses must line up with attributes
173+
const val SQUARE_WAVE = 1
174+
const val TRIANGLE_WAVE = 2
175+
const val SAW_WAVE = 3
176+
const val REVERSE_SAW_WAVE = 4
177+
const val COS_WAVE = 5
178+
const val BOUNCE = 6
179+
const val CUSTOM = 7
180+
181+
/**
182+
* This builds a monotonic spline to be used as a wave function
183+
*/
184+
fun buildWave(configString: String): MonoSpline {
185+
// done this way for efficiency
186+
val values = FloatArray(configString.length / 2)
187+
var start = configString.indexOf('(') + 1
188+
var off1 = configString.indexOf(',', start)
189+
var count = 0
190+
while (off1 != -1) {
191+
val tmp = configString.substring(start, off1).trim { it <= ' ' }
192+
values[count++] = tmp.toFloat()
193+
off1 = configString.indexOf(',', off1 + 1.also { start = it })
194+
}
195+
off1 = configString.indexOf(')', start)
196+
val tmp = configString.substring(start, off1).trim { it <= ' ' }
197+
values[count++] = tmp.toFloat()
198+
return buildWave(Arrays.copyOf(values, count))
199+
}
200+
201+
private fun buildWave(values: FloatArray): MonoSpline {
202+
val length = values.size * 3 - 2
203+
val len = values.size - 1
204+
val gap = 1.0f / len
205+
val points = ArrayList<FloatArray>(length)
206+
val time = FloatArray(length)
207+
for (i in values.indices) {
208+
val v = values[i]
209+
points[i + len][0] = v
210+
time[i + len] = i * gap
211+
if (i > 0) {
212+
points[i + len * 2][0] = v + 1
213+
time[i + len * 2] = i * gap + 1
214+
points[i - 1][0] = v - 1 - gap
215+
time[i - 1] = i * gap + -1 - gap
216+
}
217+
}
218+
return MonoSpline(time, points)
219+
}
220+
}
221+
}

desktop/interpolationEngines/src/main/kotlin/curves/Spline.kt

+9-6
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ class Spline(points: List<FloatArray>) {
5555
}
5656
mCurveLength = FloatArray(mPoints - 1)
5757
mTotalLength = 0.0f
58-
val temp = arrayOfNulls<Cubic>(mDimensionality)
58+
val dummy = Cubic(0f, 0f, 0f, 0f)
59+
val temp = Array<Cubic>(mDimensionality) {
60+
dummy
61+
}
5962
for (p in mCurveLength.indices) {
6063

6164
for (d in 0 until mDimensionality) {
@@ -106,7 +109,7 @@ class Spline(points: List<FloatArray>) {
106109
return mCurve[splineNumber][k].eval(pos / mCurveLength[k])
107110
}
108111

109-
private fun approxLength(curve: Array<Cubic?>): Float {
112+
private fun approxLength(curve: Array<Cubic>): Float {
110113
var sum = 0.0f
111114
val n = curve.size
112115
val old = FloatArray(n)
@@ -115,7 +118,7 @@ class Spline(points: List<FloatArray>) {
115118
var s = 0.0f
116119
for (j in 0 until n) {
117120
var tmp = old[j]
118-
old[j] = curve[j]!!.eval(i)
121+
old[j] = curve[j].eval(i)
119122
tmp -= old[j]
120123
s += tmp * tmp
121124
}
@@ -127,7 +130,7 @@ class Spline(points: List<FloatArray>) {
127130
var s = 0.0f
128131
for (j in 0 until n) {
129132
var tmp = old[j]
130-
old[j] = curve[j]!!.eval(1.0f)
133+
old[j] = curve[j].eval(1.0f)
131134
tmp -= old[j]
132135
s += tmp * tmp
133136
}
@@ -170,8 +173,8 @@ class Spline(points: List<FloatArray>) {
170173
for (i in n - 1 downTo 0) {
171174
d[i] = delta[i] - gamma[i] * d[i + 1]
172175
}
173-
return Array(n) {i->
174-
Cubic(
176+
return Array(n) { i ->
177+
Cubic(
175178
x[i], d[i], 3 * (x[i + 1] - x[i]) - (2
176179
* d[i]) - d[i + 1], 2 * (x[i] - x[i + 1]) + d[i] + d[i + 1]
177180
)

0 commit comments

Comments
 (0)