diff --git a/js/Transform1.js b/js/Transform1.js new file mode 100644 index 0000000..41c92d6 --- /dev/null +++ b/js/Transform1.js @@ -0,0 +1,68 @@ +// Copyright 2021, University of Colorado Boulder + +/** + * One dimensional (scalar) transforms, which are invertible. + * + * @author Sam Reid (PhET Interactive Simulations) + */ + +import merge from '../../phet-core/js/merge.js'; +import Range from './Range.js'; +import dot from './dot.js'; + +const TOLERANCE = 1E-6; +const approxEquals = ( a, b ) => Math.abs( a - b ) <= TOLERANCE; + +class Transform1 { + + /** + * @param {function(number):number} evaluationFunction + * @param {function(number):number} inverseFunction + * @param {Object} [options] + */ + constructor( evaluationFunction, inverseFunction, options ) { + + options = merge( { + + // Used for asserting the inverse is correct, and that inputs are valid + domain: new Range( Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY ), + range: new Range( Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY ) + }, options ); + + // @private + this.evaluationFunction = evaluationFunction; + this.inverseFunction = inverseFunction; + this.domain = options.domain; + this.range = options.range; + } + + /** + * Evaluate the transform at the specified scalar. + * @param {number} x + * @returns {number} + * @public + */ + evaluate( x ) { + assert && assert( this.domain.contains( x ), 'Value out of domain' ); + const result = this.evaluationFunction( x ); + assert && assert( approxEquals( this.inverseFunction( result ), x ) ); + return result; + } + + /** + * Evaluate the inverse at the specified scalar. + * @param {number} x + * @returns {number} + * @public + */ + inverse( x ) { + assert && assert( this.range.contains( x ), 'Value out of range' ); + const result = this.inverseFunction( x ); + assert && assert( approxEquals( this.evaluationFunction( result ), x ) ); + return result; + } +} + +dot.register( 'Transform1', Transform1 ); + +export default Transform1; \ No newline at end of file