From ffbeedc9682895420354300246f45555515a673b Mon Sep 17 00:00:00 2001 From: peabnuts123 Date: Sat, 12 Jan 2019 21:53:09 +1300 Subject: [PATCH] General code tidying and refactoring --- src/builders/Builder.ts | 6 +- src/builders/cylinder.ts | 36 ++++++------ src/builders/plane.ts | 67 +++++++++++------------ src/builders/sphere.ts | 12 ++-- src/interpolation.ts | 30 +++++----- src/mathconsts.ts | 31 ++++++++--- src/model/cylinder.ts | 14 ++--- src/model/line.ts | 4 +- src/model/plane.ts | 2 +- src/model/sphere.ts | 17 +++--- src/module/generator/billow.ts | 27 ++++++--- src/module/generator/cylinders.ts | 1 - src/module/generator/perlin.ts | 28 +++++++--- src/module/generator/ridgedmulti.ts | 4 +- src/noisegen.ts | 66 ++++++++++------------ src/noisemap.ts | 14 ++++- test/module/generator/billow.test.ts | 6 +- test/module/generator/perlin.test.ts | 6 +- test/module/generator/ridgedmulti.test.ts | 6 +- 19 files changed, 199 insertions(+), 178 deletions(-) diff --git a/src/builders/Builder.ts b/src/builders/Builder.ts index 19a1784..ce03292 100644 --- a/src/builders/Builder.ts +++ b/src/builders/Builder.ts @@ -30,7 +30,7 @@ export default abstract class Builder { * The destination noise map. * * The destination noise map will contain the coherent-noise values - * from this noise map after a successful call to the Build() method. + * from this noise map after a successful call to the build() method. * * The destination noise map must exist throughout the lifetime of * this object unless another noise map replaces that noise map. @@ -42,7 +42,7 @@ export default abstract class Builder { * @param width The width of the destination noise map, in points * @param height The height of the destination noise map, in points */ - public constructor(sourceModule: Module, width: number, height: number) { + public constructor(sourceModule: Module, width?: number, height?: number) { this.sourceModule = sourceModule; this.noiseMap = new NoiseMap(width, height); } @@ -61,7 +61,7 @@ export default abstract class Builder { * @param height The height of the destination noise map, in points. * * This method does not change the size of the destination noise map - * until the Build() method is called. + * until the build() method is called. */ public setSize(width: number, height: number): void { this.width = width; diff --git a/src/builders/cylinder.ts b/src/builders/cylinder.ts index 35c5d0b..2ff9bb9 100644 --- a/src/builders/cylinder.ts +++ b/src/builders/cylinder.ts @@ -39,12 +39,12 @@ class NoiseMapBuilderCylinder extends Builder { public get lowerAngleBound(): number { return this._lowerAngleBound; } - public set lowerAngleBound(v: number) { - if (v >= this.upperAngleBound) { + public set lowerAngleBound(value: number) { + if (value >= this.upperAngleBound) { throw new Error('Lower angle bound cannot be equal to or exceed upper angle bound!'); } - this._lowerAngleBound = v; + this._lowerAngleBound = value; } /** @@ -56,12 +56,12 @@ class NoiseMapBuilderCylinder extends Builder { public get lowerHeightBound(): number { return this._lowerHeightBound; } - public set lowerHeightBound(v: number) { - if (v >= this.upperHeightBound) { + public set lowerHeightBound(value: number) { + if (value >= this.upperHeightBound) { throw new Error('Lower angle height cannot be equal to or exceed upper angle height!'); } - this._lowerHeightBound = v; + this._lowerHeightBound = value; } /** @@ -72,12 +72,12 @@ class NoiseMapBuilderCylinder extends Builder { public get upperAngleBound(): number { return this._upperAngleBound; } - public set upperAngleBound(v: number) { - if (v <= this.lowerAngleBound) { + public set upperAngleBound(value: number) { + if (value <= this.lowerAngleBound) { throw new Error('Upper angle bound cannot be equal to or less than lower angle bound!'); } - this._upperAngleBound = v; + this._upperAngleBound = value; } /** @@ -89,12 +89,12 @@ class NoiseMapBuilderCylinder extends Builder { public get upperHeightBound(): number { return this._upperHeightBound; } - public set upperHeightBound(v: number) { - if (v <= this.lowerHeightBound) { + public set upperHeightBound(value: number) { + if (value <= this.lowerHeightBound) { throw new Error('Upper angle height cannot be equal to or less than lower angle height!'); } - this._upperHeightBound = v; + this._upperHeightBound = value; } public build(): NoiseMap { @@ -102,19 +102,19 @@ class NoiseMapBuilderCylinder extends Builder { let cylinder = new Cylinder(this.sourceModule); let xDelta = (this.upperAngleBound - this.lowerAngleBound) / this.width; let yDelta = (this.upperHeightBound - this.lowerHeightBound) / this.height; - let curAngle = this.lowerAngleBound; - let curHeight = this.lowerHeightBound; + let currentAngle = this.lowerAngleBound; + let currentHeight = this.lowerHeightBound; // Fill every point in the noise map with the output values from the model. for (let y = 0; y < this.height; y++) { - curAngle = this.lowerAngleBound; + currentAngle = this.lowerAngleBound; for (let x = 0; x < this.width; x++) { - this.noiseMap.setValue(x, y, cylinder.getValue(curAngle, curHeight)); - curAngle += xDelta; + this.noiseMap.setValue(x, y, cylinder.getValue(currentAngle, currentHeight)); + currentAngle += xDelta; } - curHeight += yDelta; + currentHeight += yDelta; } return this.noiseMap; diff --git a/src/builders/plane.ts b/src/builders/plane.ts index d2d1909..0233ccc 100644 --- a/src/builders/plane.ts +++ b/src/builders/plane.ts @@ -26,7 +26,7 @@ class NoiseMapBuilderPlane extends Builder { * Enabling seamless tiling builds a noise map with no seams at the * edges. This allows the noise map to be tileable. */ - public seamless: boolean; + public isSeamless: boolean; private _lowerXBound: number = 0; private _lowerZBound: number = 0; private _upperXBound: number = 1; @@ -36,12 +36,12 @@ class NoiseMapBuilderPlane extends Builder { * @param sourceModule The source module * @param width The width of the destination noise map, in points * @param height The height of the destination noise map, in points - * @param seamless A flag that enables or disables seamless tiling + * @param isSeamless A flag that enables or disables seamless tiling */ - constructor(sourceModule: Module, width: number = 256, height: number = 256, seamless: boolean = false) { + constructor(sourceModule: Module, width?: number, height?: number, isSeamless: boolean = false) { super(sourceModule, width, height); - this.seamless = seamless; + this.isSeamless = isSeamless; } /** @@ -52,12 +52,12 @@ class NoiseMapBuilderPlane extends Builder { public get lowerXBound(): number { return this._lowerXBound; } - public set lowerXBound(v: number) { - if (v >= this.upperXBound) { + public set lowerXBound(value: number) { + if (value >= this.upperXBound) { throw new Error('Lower X bound cannot be equal to or exceed upper X bound!'); } - this._lowerXBound = v; + this._lowerXBound = value; } /** @@ -68,12 +68,12 @@ class NoiseMapBuilderPlane extends Builder { public get lowerZBound(): number { return this._lowerZBound; } - public set lowerZBound(v: number) { - if (v >= this.upperZBound) { + public set lowerZBound(value: number) { + if (value >= this.upperZBound) { throw new Error('Lower Z bound cannot be equal to or exceed upper Z bound!'); } - this._lowerZBound = v; + this._lowerZBound = value; } /** @@ -84,12 +84,12 @@ class NoiseMapBuilderPlane extends Builder { public get upperXBound(): number { return this._upperXBound; } - public set upperXBound(v: number) { - if (v <= this.lowerXBound) { + public set upperXBound(value: number) { + if (value <= this.lowerXBound) { throw new Error('Upper X bound cannot be equal to or less than lower X bound!'); } - this._upperXBound = v; + this._upperXBound = value; } /** @@ -100,63 +100,58 @@ class NoiseMapBuilderPlane extends Builder { public get upperZBound(): number { return this._upperZBound; } - public set upperZBound(v: number) { - if (v <= this.lowerZBound) { + public set upperZBound(value: number) { + if (value <= this.lowerZBound) { throw new Error('Upper Z bound cannot be equal to or less than lower Z bound!'); } - this._upperZBound = v; + this._upperZBound = value; } public build(): NoiseMap { let xExtent = this.upperXBound - this.lowerXBound; let zExtent = this.upperZBound - this.lowerZBound; - // @TODO is this possible? seems to be covered by validation in setters - if (xExtent < 0 || zExtent < 0) { - throw new Error('Invalid bounds!'); - } - // Create the plane model. let plane = new Plane(this.sourceModule); let xDelta = xExtent / this.width; let zDelta = zExtent / this.height; - let curX = this.lowerXBound; - let curZ = this.lowerZBound; - let value; - let xBlend; + + let currentX = this.lowerXBound; + let currentZ = this.lowerZBound; // Fill every point in the noise map with the output values from the model. for (let z = 0; z < this.height; z++) { - curX = this.lowerXBound; + currentX = this.lowerXBound; for (let x = 0; x < this.width; x++) { - if (!this.seamless) { - value = plane.getValue(curX, curZ); + let value; + if (!this.isSeamless) { + value = plane.getValue(currentX, currentZ); } else { - xBlend = 1.0 - ((curX - this.lowerXBound) / xExtent); + let xBlend = 1.0 - ((currentX - this.lowerXBound) / xExtent); value = Interpolation.linear( Interpolation.linear( - plane.getValue(curX, curZ), - plane.getValue(curX + xExtent, curZ), + plane.getValue(currentX, currentZ), + plane.getValue(currentX + xExtent, currentZ), xBlend, ), Interpolation.linear( - plane.getValue(curX, curZ + zExtent), - plane.getValue(curX + xExtent, curZ + zExtent), + plane.getValue(currentX, currentZ + zExtent), + plane.getValue(currentX + xExtent, currentZ + zExtent), xBlend, ), - 1.0 - ((curZ - this.lowerZBound) / zExtent), + 1.0 - ((currentZ - this.lowerZBound) / zExtent), ); } this.noiseMap.setValue(x, z, value); - curX += xDelta; + currentX += xDelta; } - curZ += zDelta; + currentZ += zDelta; } return this.noiseMap; diff --git a/src/builders/sphere.ts b/src/builders/sphere.ts index 2f41737..d35259e 100644 --- a/src/builders/sphere.ts +++ b/src/builders/sphere.ts @@ -112,20 +112,20 @@ class NoiseMapBuilderSphere extends Builder { let sphere = new Sphere(this.sourceModule); let xDelta = (this.eastLonBound - this.westLonBound) / this.width; let yDelta = (this.northLatBound - this.southLatBound) / this.height; - let curLon = this.westLonBound; - let curLat = this.eastLonBound; + let currentLongitude = this.westLonBound; + let currentLatitude = this.eastLonBound; // Fill every point in the noise map with the output values from the model. for (let y = 0; y < this.height; y++) { - curLon = this.westLonBound; + currentLongitude = this.westLonBound; for (let x = 0; x < this.width; x++) { - this.noiseMap.setValue(x, y, sphere.getValue(curLat, curLon)); + this.noiseMap.setValue(x, y, sphere.getValue(currentLatitude, currentLongitude)); - curLon += xDelta; + currentLongitude += xDelta; } - curLat += yDelta; + currentLatitude += yDelta; } return this.noiseMap; diff --git a/src/interpolation.ts b/src/interpolation.ts index dbf124f..2c5163a 100644 --- a/src/interpolation.ts +++ b/src/interpolation.ts @@ -1,11 +1,11 @@ -const Interpolation = { +export default class Interpolation { /** * Performs cubic interpolation between two values bound between two other * values. * * The alpha value should range from 0.0 to 1.0. If the alpha value is - * 0.0, this function returns @a n1. If the alpha value is 1.0, this - * function returns @a n2. + * 0.0, this function returns n1. If the alpha value is 1.0, this + * function returns n2. * * @param n0 The value before the first value. * @param n1 The first value. @@ -16,20 +16,20 @@ const Interpolation = { * @returns The interpolated value. * */ - cubic(n0: number, n1: number, n2: number, n3: number, a: number): number { + public static cubic(n0: number, n1: number, n2: number, n3: number, a: number): number { let p = ((n3 - n2) - (n0 - n1)); let q = ((n0 - n1) - p); let r = (n2 - n0); let s = (n1); return (p * a * a * a + q * a * a + r * a + s); - }, + } /** * Performs linear interpolation between two values. * * The alpha value should range from 0.0 to 1.0. If the alpha value is - * 0.0, this function returns @a n0. If the alpha value is 1.0, this - * function returns @a n1. + * 0.0, this function returns n0. If the alpha value is 1.0, this + * function returns n1. * * @param n0 The first value. * @param n1 The second value. @@ -37,9 +37,9 @@ const Interpolation = { * * @returns The interpolated value. */ - linear(n0: number, n1: number, a: number): number { + public static linear(n0: number, n1: number, a: number): number { return ((1.0 - a) * (n0)) + (a * (n1)); - }, + } /** * Maps a value onto a cubic S-curve. @@ -49,9 +49,9 @@ const Interpolation = { * * @returns The mapped value. */ - cubicSCurve(a: number): number { + public static cubicSCurve(a: number): number { return (a * a * (3.0 - 2.0 * a)); - }, + } /** * Maps a value onto a quintic S-curve. @@ -63,12 +63,10 @@ const Interpolation = { * * @returns The mapped value. */ - quinticSCurve(a: number): number { + public static quinticSCurve(a: number): number { let a3 = (a * a * a); let a4 = (a3 * a); let a5 = (a4 * a); return ((6.0 * a5) - (15.0 * a4) + (10.0 * a3)); - }, -}; - -export default Interpolation; + } +} diff --git a/src/mathconsts.ts b/src/mathconsts.ts index dcd3f18..01a6998 100644 --- a/src/mathconsts.ts +++ b/src/mathconsts.ts @@ -1,9 +1,22 @@ -const MathConsts = { - PI: Math.PI, - SQRT_2: Math.SQRT2, - SQRT_3: 1.7320508075688772935, - DEG_TO_RAD: Math.PI / 180.0, - RAD_TO_DEG: 1.0 / (Math.PI / 180.0), -}; - -export default MathConsts; +export default class MathConsts { + /** + * Pi. This is the ratio of the circumference of a circle to its diameter. + */ + public static readonly PI = Math.PI; + /** + * The square root of 2. + */ + public static readonly SQRT_2 = Math.SQRT2; + /** + * The square root of 3. + */ + public static readonly SQRT_3 = 1.7320508075688772935; + /** + * Convert degrees to radians by multiplying by this constant. + */ + public static readonly DEG_TO_RAD = Math.PI / 180.0; + /** + * Convert radians to degrees by multiplying by this constant. + */ + public static readonly RAD_TO_DEG = 1.0 / (Math.PI / 180.0); +} diff --git a/src/model/cylinder.ts b/src/model/cylinder.ts index a79b5b3..93e17e7 100644 --- a/src/model/cylinder.ts +++ b/src/model/cylinder.ts @@ -22,23 +22,19 @@ class Cylinder extends Model { * (angle, height) coordinates of the specified input value located * on the surface of the cylinder. * - * This output value is generated by the noise module passed to the - * SetModule() method. - * * This cylinder has a radius of 1.0 unit and has infinite height. * It is oriented along the y axis. Its center is located at the * origin. * - * @param angle The angle around the cylinder's center, in degrees. - * @param y The height along the y axis. + * @param angleDegrees The angle around the cylinder's center, in degrees. + * @param height The height along the y axis. * * @returns The output value from the noise module. */ - // @TODO rename to `angleDegrees` - public getValue(angle: number, y: number): number { - let i = angle * MathConsts.DEG_TO_RAD; + public getValue(angleDegrees: number, height: number): number { + let i = angleDegrees * MathConsts.DEG_TO_RAD; - return this.sourceModule.getValue(Math.cos(i), y, Math.sin(i)); + return this.sourceModule.getValue(Math.cos(i), height, Math.sin(i)); } } diff --git a/src/model/line.ts b/src/model/line.ts index 0a2c28f..4fa409a 100644 --- a/src/model/line.ts +++ b/src/model/line.ts @@ -52,7 +52,7 @@ class Line extends Model { * on the line segment. * * The output value is generated by the noise module passed to the - * SetModule() method. This value may be attenuated (moved toward + * setModule() method. This value may be attenuated (moved toward * 0.0) as p approaches either end of the line segment; this is * the default behavior. * @@ -89,7 +89,7 @@ class Line extends Model { } /** - * Sets the position ( @a x, @a y, @a z ) of the start of the line + * Sets the position ( x, y, z ) of the start of the line * segment to choose values along. * * @param x x coordinate of the start position. diff --git a/src/model/plane.ts b/src/model/plane.ts index a96c20f..15bd9c0 100644 --- a/src/model/plane.ts +++ b/src/model/plane.ts @@ -23,7 +23,7 @@ class Plane extends Model { * on the surface of the plane. * * This output value is generated by the noise module passed to the - * SetModule() method. + * setModule() method. * * @param x The x coordinate of the input value. * @param z The z coordinate of the input value. diff --git a/src/model/sphere.ts b/src/model/sphere.ts index a6134e7..468f807 100644 --- a/src/model/sphere.ts +++ b/src/model/sphere.ts @@ -23,27 +23,24 @@ class Sphere extends Model { * (latitude, longitude) coordinates of the specified input value * located on the surface of the sphere. * - * This output value is generated by the noise module passed to the - * SetModule() method. - * * Use a negative latitude if the input value is located on the * southern hemisphere. * * Use a negative longitude if the input value is located on the * western hemisphere. * - * @param lat The latitude of the input value, in degrees. - * @param lon The longitude of the input value, in degrees. + * @param latitude The latitude of the input value, in degrees. + * @param longitude The longitude of the input value, in degrees. * * @returns The output value from the noise module. */ - public getValue(lat: number, lon: number): number { - let r: number = Math.cos(MathConsts.DEG_TO_RAD * lat); + public getValue(latitude: number, longitude: number): number { + let r: number = Math.cos(MathConsts.DEG_TO_RAD * latitude); return this.sourceModule.getValue( - Math.cos(MathConsts.DEG_TO_RAD * lon) * r, - Math.sin(MathConsts.DEG_TO_RAD * lat), - Math.sin(MathConsts.DEG_TO_RAD * lon) * r, + Math.cos(MathConsts.DEG_TO_RAD * longitude) * r, + Math.sin(MathConsts.DEG_TO_RAD * latitude), + Math.sin(MathConsts.DEG_TO_RAD * longitude) * r, ); } } diff --git a/src/module/generator/billow.ts b/src/module/generator/billow.ts index e0d8ba0..79deb5b 100644 --- a/src/module/generator/billow.ts +++ b/src/module/generator/billow.ts @@ -1,4 +1,4 @@ -import NoiseGen from '@app/noisegen'; +import NoiseGen, { Quality } from '@app/noisegen'; import { makeInt32Range } from '@app/util'; import GeneratorModule from './GeneratorModule'; @@ -17,10 +17,8 @@ class Billow extends GeneratorModule { public static readonly DEFAULT_BILLOW_LACUNARITY = 2.0; public static readonly DEFAULT_BILLOW_OCTAVE_COUNT = 6; public static readonly DEFAULT_BILLOW_PERSISTENCE = 0.5; - public static readonly DEFAULT_BILLOW_QUALITY = NoiseGen.QUALITY_STD; + public static readonly DEFAULT_BILLOW_QUALITY = Quality.Standard; public static readonly DEFAULT_BILLOW_SEED = 0; - - // @TODO enforce by throwing an error or something public static readonly BILLOW_MAX_OCTAVE = 30; /** @@ -35,10 +33,7 @@ class Billow extends GeneratorModule { * Quality of the billowy noise. */ public quality: number; - /** - * Total number of octaves that generate the billowy noise. - */ - public octaves: number; + /** * Persistence value of the billowy noise. */ @@ -48,6 +43,8 @@ class Billow extends GeneratorModule { */ public seed: number; + private _octaves: number = Billow.DEFAULT_BILLOW_OCTAVE_COUNT; + /** * @param frequency Frequency of the first octave. * @param lacunarity Frequency multiplier between successive octaves. @@ -67,6 +64,20 @@ class Billow extends GeneratorModule { this.quality = quality || Billow.DEFAULT_BILLOW_QUALITY; } + /** + * Total number of octaves that generate the billowy noise. + */ + public get octaves(): number { + return this._octaves; + } + public set octaves(value: number) { + if (value > Billow.BILLOW_MAX_OCTAVE) { + throw new Error(`Cannot set octaves greater than maximum of ${Billow.BILLOW_MAX_OCTAVE}`); + } + + this._octaves = value; + } + public getValue(x: number, y: number, z: number): number { let nx; let ny; diff --git a/src/module/generator/cylinders.ts b/src/module/generator/cylinders.ts index 5f436f1..7b50c4b 100644 --- a/src/module/generator/cylinders.ts +++ b/src/module/generator/cylinders.ts @@ -45,7 +45,6 @@ class Cylinders extends GeneratorModule { public getValue(x: number, y: number, z: number): number { x = (x * this.frequency); y = (y * this.frequency); - z = (z); let distFromCenter = Math.sqrt(x * x + z * z); let distFromSmallerSphere = distFromCenter - Math.floor(distFromCenter); diff --git a/src/module/generator/perlin.ts b/src/module/generator/perlin.ts index 4810e2c..f759f1b 100644 --- a/src/module/generator/perlin.ts +++ b/src/module/generator/perlin.ts @@ -1,4 +1,4 @@ -import NoiseGen from '@app/noisegen'; +import NoiseGen, { Quality } from '@app/noisegen'; import { makeInt32Range } from '@app/util'; import GeneratorModule from './GeneratorModule'; @@ -84,11 +84,8 @@ class Perlin extends GeneratorModule { public static readonly DEFAULT_PERLIN_LACUNARITY = 2.0; public static readonly DEFAULT_PERLIN_OCTAVE_COUNT = 6; public static readonly DEFAULT_PERLIN_PERSISTENCE = 0.5; - public static readonly DEFAULT_PERLIN_QUALITY = NoiseGen.QUALITY_STD; + public static readonly DEFAULT_PERLIN_QUALITY = Quality.Standard; public static readonly DEFAULT_PERLIN_SEED = 0; - - - // @TODO enforce by throwing an error or something public static readonly PERLIN_MAX_OCTAVE = 30; /** @@ -103,10 +100,7 @@ class Perlin extends GeneratorModule { * Quality of the Perlin noise. */ public quality: number; - /** - * Total number of octaves that generate the Perlin noise. - */ - public octaves: number; + /** * Persistence of the Perlin noise. */ @@ -116,6 +110,8 @@ class Perlin extends GeneratorModule { */ public seed: number; + private _octaves: number = Perlin.DEFAULT_PERLIN_OCTAVE_COUNT; + /** * @param frequency Frequency of the first octave. * @param lacunarity Frequency multiplier between successive octaves. @@ -135,6 +131,20 @@ class Perlin extends GeneratorModule { this.quality = quality || Perlin.DEFAULT_PERLIN_QUALITY; } + /** + * Total number of octaves that generate the billowy noise. + */ + public get octaves(): number { + return this._octaves; + } + public set octaves(value: number) { + if (value > Perlin.PERLIN_MAX_OCTAVE) { + throw new Error(`Cannot set octaves greater than maximum of ${Perlin.PERLIN_MAX_OCTAVE}`); + } + + this._octaves = value; + } + public getValue(x: number, y: number, z: number): number { let nx, ny, nz; let value = 0.0; diff --git a/src/module/generator/ridgedmulti.ts b/src/module/generator/ridgedmulti.ts index 5452b5c..e01c558 100644 --- a/src/module/generator/ridgedmulti.ts +++ b/src/module/generator/ridgedmulti.ts @@ -1,4 +1,4 @@ -import NoiseGen from '@app/noisegen'; +import NoiseGen, { Quality } from '@app/noisegen'; import { clamp, makeInt32Range } from '@app/util'; import GeneratorModule from './GeneratorModule'; @@ -58,7 +58,7 @@ class RidgedMulti extends GeneratorModule { public static readonly DEFAULT_RIDGED_FREQUENCY = 1.0; public static readonly DEFAULT_RIDGED_LACUNARITY = 2.0; public static readonly DEFAULT_RIDGED_OCTAVE_COUNT = 6; - public static readonly DEFAULT_RIDGED_QUALITY = NoiseGen.QUALITY_STD; + public static readonly DEFAULT_RIDGED_QUALITY = Quality.Standard; public static readonly DEFAULT_RIDGED_SEED = 0; public static readonly DEFAULT_RIDGED_OFFSET = 1.0; public static readonly DEFAULT_RIDGED_GAIN = 2.0; diff --git a/src/noisegen.ts b/src/noisegen.ts index 1603610..af69fd8 100644 --- a/src/noisegen.ts +++ b/src/noisegen.ts @@ -4,16 +4,7 @@ import VectorTable from '@app/vectortable'; // Type definitions type CoherentNoiseCallback = (x0: number, y0: number, z0: number, x1: number, y1: number, z1: number, xs: number, ys: number, zs: number) => number; -// @TODO type-definition -const NoiseGen = { - // Constants - X_NOISE_GEN: 1619, - Y_NOISE_GEN: 31337, - Z_NOISE_GEN: 6971, - SEED_NOISE_GEN: 1013, - SHIFT_NOISE_GEN: 8, - - // @TODO enum +export enum Quality { /** * Generates coherent noise quickly. When a coherent-noise function with * NoiseGen.prototype quality setting is used to generate a bump-map image, there are @@ -21,8 +12,7 @@ const NoiseGen = { * because the derivative of that function is discontinuous at integer * boundaries. */ - QUALITY_FAST: 0, - + Fast = 0, /** * Generates standard-quality coherent noise. When a coherent-noise * function with NoiseGen.prototype quality setting is used to generate a bump-map @@ -30,8 +20,7 @@ const NoiseGen = { * image. This is because the second derivative of that function is * discontinuous at integer boundaries. */ - QUALITY_STD: 1, - + Standard = 1, /** * Generates the best-quality coherent noise. When a coherent-noise * function with NoiseGen.prototype quality setting is used to generate a bump-map @@ -39,7 +28,16 @@ const NoiseGen = { * is because the first and second derivatives of that function are * continuous at integer boundaries. */ - QUALITY_BEST: 2, + Best = 2, +} + +export default class NoiseGen { + // Constants + private static readonly X_NOISE_GEN = 1619; + private static readonly Y_NOISE_GEN = 31337; + private static readonly Z_NOISE_GEN = 6971; + private static readonly SEED_NOISE_GEN = 1013; + private static readonly SHIFT_NOISE_GEN = 8; /** * Generates an integer-noise value from the coordinates of a @@ -58,7 +56,7 @@ const NoiseGen = { * always returns the same output value if the same input value is passed * to it. */ - intValueNoise3D(x: number, y: number, z: number, seed: number): number { + public static intValueNoise3D(x: number, y: number, z: number, seed: number): number { x = Math.floor(x); y = Math.floor(y); z = Math.floor(z); @@ -76,7 +74,7 @@ const NoiseGen = { n = (n >> 13) ^ n; return ((n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff); - }, + } /** * Generates a value-noise value from the coordinates of a @@ -95,9 +93,9 @@ const NoiseGen = { * always returns the same output value if the same input value is passed * to it. */ - valueNoise3D(x: number, y: number, z: number, seed: number = 0): number { + public static valueNoise3D(x: number, y: number, z: number, seed: number = 0): number { return 1.0 - (NoiseGen.intValueNoise3D(Math.floor(x), Math.floor(y), Math.floor(z), Math.floor(seed)) / 1073741824.0); - }, + } /** * Generates a gradient-noise value from the coordinates of a @@ -142,7 +140,7 @@ const NoiseGen = { * always returns the same output value if the same input value is passed * to it. */ - gradientNoise3D(fx: number, fy: number, fz: number, ix: number, iy: number, iz: number, seed: number = 1): number { + public static gradientNoise3D(fx: number, fy: number, fz: number, ix: number, iy: number, iz: number, seed: number = 1): number { // Randomly generate a gradient vector given the integer coordinates of the // input value. This implementation generates a random number and uses it // as an index into a normalized-vector lookup table. @@ -174,16 +172,14 @@ const NoiseGen = { (yvGradient * yvPoint) + (zvGradient * zvPoint) ) * 2.12; - }, + } // @TODO remove `seed` param, it is not used. Or maybe it should be? - // @TODO this should be private, it does not exist in the original libnoise - coherentNoise3D(x: number, y: number, z: number, seed?: number, quality?: number, func?: CoherentNoiseCallback): number { + private static coherentNoise3D(x: number, y: number, z: number, seed?: number, quality?: number, func?: CoherentNoiseCallback): number { if (!func) { throw new Error('Must provide proper interpolation function!'); } - // @TODO convert these default values to overloads if (!seed) { seed = 1; } else { @@ -191,7 +187,7 @@ const NoiseGen = { } if (!quality) { - quality = NoiseGen.QUALITY_STD; + quality = Quality.Standard; } else { quality = Math.floor(quality); } @@ -214,20 +210,20 @@ const NoiseGen = { let xs = 0, ys = 0, zs = 0; switch (quality) { - case NoiseGen.QUALITY_BEST: + case Quality.Best: xs = Interpolation.quinticSCurve(x - x0); ys = Interpolation.quinticSCurve(y - y0); zs = Interpolation.quinticSCurve(z - z0); break; - case NoiseGen.QUALITY_STD: + case Quality.Standard: xs = Interpolation.cubicSCurve(x - x0); ys = Interpolation.cubicSCurve(y - y0); zs = Interpolation.cubicSCurve(z - z0); break; default: - case NoiseGen.QUALITY_FAST: + case Quality.Fast: xs = x - x0; ys = y - y0; zs = z - z0; @@ -236,7 +232,7 @@ const NoiseGen = { // use provided function to interpolate return func(x0, y0, z0, x1, y1, z1, xs, ys, zs); - }, + } /** * Generates a value-coherent-noise value from the coordinates of a @@ -255,7 +251,7 @@ const NoiseGen = { * For an explanation of the difference between *gradient* noise and * *value* noise, see the comments for the gradientNoise3D() function. */ - valueCoherentNoise3D(x: number, y: number, z: number, seed: number, quality: number): number { + public static valueCoherentNoise3D(x: number, y: number, z: number, seed: number, quality: number): number { return NoiseGen.coherentNoise3D(x, y, z, seed, quality, (x0, y0, z0, x1, y1, z1, xs, ys, zs) => { // Now calculate the noise values at each vertex of the cube. To generate @@ -282,7 +278,7 @@ const NoiseGen = { return Interpolation.linear(iy0, iy1, zs); }); - }, + } /** * Generates a gradient-coherent-noise value from the coordinates of a @@ -301,7 +297,7 @@ const NoiseGen = { * For an explanation of the difference between *gradient* noise and * *value* noise, see the comments for the gradientNoise3D() function. */ - gradientCoherentNoise3D(x: number, y: number, z: number, seed: number, quality: number): number { + public static gradientCoherentNoise3D(x: number, y: number, z: number, seed: number, quality: number): number { return NoiseGen.coherentNoise3D(x, y, z, seed, quality, (x0, y0, z0, x1, y1, z1, xs, ys, zs) => { // Now calculate the noise values at each vertex of the cube. To generate @@ -327,7 +323,5 @@ const NoiseGen = { return Interpolation.linear(iy0, iy1, zs); }); - }, -}; - -export default NoiseGen; + } +} diff --git a/src/noisemap.ts b/src/noisemap.ts index 3d877d1..f5d1ab9 100644 --- a/src/noisemap.ts +++ b/src/noisemap.ts @@ -97,8 +97,12 @@ class NoiseMap { * @param height The new height for the noise map. */ public setSize(width: number, height: number): void { - // @TODO validate width and height are positive - // @TODO should this copy values to a new array i.e. clear anything out of bounds? + if (width <= 0) { + throw new Error("Cannot set size of noise map – width must be greater than 0"); + } else if (height <= 0) { + throw new Error("Cannot set size of noise map – height must be greater than 0"); + } + this.width = width; this.height = height; } @@ -115,7 +119,11 @@ class NoiseMap { * */ public setValue(x: number, y: number, value: number): void { - // @TODO No-op if x, y out of bounds + if (x < 0 || x >= this.width || y < 0 || y >= this.height) { + // x or y is out of bounds, no-op + return; + } + this.map[y * this.width + x] = value; } diff --git a/test/module/generator/billow.test.ts b/test/module/generator/billow.test.ts index 5ece8c4..579af0f 100644 --- a/test/module/generator/billow.test.ts +++ b/test/module/generator/billow.test.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; import { Billow } from '@app/module/generator'; -import NoiseGen from '@app/noisegen'; +import { Quality } from '@app/noisegen'; describe('module/generator/billow', () => { it("can construct successfully", () => { @@ -12,7 +12,7 @@ describe('module/generator/billow', () => { const octaves = 5; const persist = 0.4; const seed = 18; - const quality = NoiseGen.QUALITY_STD; + const quality = Quality.Standard; // Test const testFunc = () => { @@ -44,7 +44,7 @@ function createMockModule(): Billow { const octaves = 5; const persist = 0.4; const seed = 18; - const quality = NoiseGen.QUALITY_STD; + const quality = Quality.Standard; return new Billow(frequency, lacunarity, octaves, persist, seed, quality); } diff --git a/test/module/generator/perlin.test.ts b/test/module/generator/perlin.test.ts index 8ec2bb1..1242e8b 100644 --- a/test/module/generator/perlin.test.ts +++ b/test/module/generator/perlin.test.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; import { Perlin } from '@app/module/generator'; -import NoiseGen from '@app/noisegen'; +import { Quality } from '@app/noisegen'; describe('module/generator/perlin', () => { it("can construct successfully", () => { @@ -12,7 +12,7 @@ describe('module/generator/perlin', () => { const octaves = 6; const persist = 0.5; const seed = 0; - const quality = NoiseGen.QUALITY_STD; + const quality = Quality.Standard; // Test const testFunc = () => { @@ -44,7 +44,7 @@ function createMockModule(): Perlin { const octaves = 6; const persist = 0.5; const seed = 0; - const quality = NoiseGen.QUALITY_STD; + const quality = Quality.Standard; return new Perlin(frequency, lacunarity, octaves, persist, seed, quality); } diff --git a/test/module/generator/ridgedmulti.test.ts b/test/module/generator/ridgedmulti.test.ts index dabdf21..f21af28 100644 --- a/test/module/generator/ridgedmulti.test.ts +++ b/test/module/generator/ridgedmulti.test.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; import { RidgedMulti } from '@app/module/generator'; -import NoiseGen from '@app/noisegen'; +import { Quality } from '@app/noisegen'; describe('module/generator/ridgedmulti', () => { it("can construct successfully", () => { @@ -11,7 +11,7 @@ describe('module/generator/ridgedmulti', () => { const lacunarity = 2; const octaves = 6; const seed = 0; - const quality = NoiseGen.QUALITY_STD; + const quality = Quality.Standard; const offset = 1; const gain = 2; @@ -56,7 +56,7 @@ function createMockModule(): RidgedMulti { const lacunarity = 2; const octaves = 6; const seed = 0; - const quality = NoiseGen.QUALITY_STD; + const quality = Quality.Standard; const offset = 1; const gain = 2;