All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.ru.casperix.math.perlin.CachedValueNoise2D.kt Maven / Gradle / Ivy

There is a newer version: 1.9.0
Show newest version
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)
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy