commonMain.ru.casperix.math.perlin.CachedValueNoise2D.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of math Show documentation
Show all versions of math Show documentation
Simple set of geometric and other types
package ru.casperix.math.perlin
import ru.casperix.math.array.float64.DoubleMap2D
import ru.casperix.math.axis_aligned.int32.Box2i
import ru.casperix.math.vector.int32.Vector2i
import ru.casperix.math.function.Function2D
import ru.casperix.math.interpolation.float64.hermiteInterpolate
class CachedValueNoise2D(val source: ValueNoise2D, val area: Box2i) {
class CacheInfo(val octave: ValueNoise2D.OctaveCache, val map: DoubleMap2D, val offset: Vector2i)
init {
if (source.interpolateFunction != hermiteInterpolate)
throw Error("Support only hermite interpolate")
}
val normalizer = source.normalizer
val octaves = Array(source.octaves.size) { index ->
val octave = source.octaves[index]
createRandomCache(octave)
}
private fun createRandomCache(octave: ValueNoise2D.OctaveCache): CacheInfo {
val minX = (area.min.x * octave.frequencyX).toInt()
val minY = (area.min.y * octave.frequencyY).toInt()
val maxX = (area.max.x * octave.frequencyX).toInt() + 1
val maxY = (area.max.y * octave.frequencyY).toInt() + 1
val map = DoubleMap2D.createByXY(Vector2i(maxX - minX + 1, maxY - minY + 1)) {
ValueNoise2D.randomWithFactor(it.x + minX, it.y + minY, octave.primeNumber)
}
return CacheInfo(octave, map, Vector2i(minX, minY))
}
val output: Function2D = { x, y ->
var total = 0.0
for (cache in octaves) {
val octave = cache.octave
total += interpolate2dFlat(x * octave.frequencyX - cache.offset.x, y * octave.frequencyY - cache.offset.y, cache.map) * octave.amplitude
}
total * normalizer
}
private fun interpolateFunction(a: Double, b: Double, x: Double): Double {
return a + (b - a) * (3.0 - 2.0 * x) * x * x
}
private fun interpolate2dFlat(fx: Double, fy: Double, randoms: DoubleMap2D): Double {
val baseX = fx.toInt()
val fractionalX = fx - baseX
val baseY = fy.toInt()
val fractionalY = fy - baseY
val directArray = randoms.array
val firstIndex = baseX + randoms.sizeX * baseY
val v1 = directArray[firstIndex]
val v2 = directArray[firstIndex + 1]
val v3 = directArray[firstIndex + randoms.sizeX]
val v4 = directArray[firstIndex + 1 + randoms.sizeX]
val i1 = interpolateFunction(v1, v2, fractionalX)
val i2 = interpolateFunction(v3, v4, fractionalX)
return interpolateFunction(i1, i2, fractionalY)
}
}