/* * Geotools 2 - OpenSource mapping toolkit * (C) 2003, Geotools Project Managment Committee (PMC) * (C) 2002, Institut de Recherche pour le Développement * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.geotools.ct; // J2SE dependencies import java.io.Serializable; /** * A one dimensional, logarithmic transform. Input values are converted into output values * using the following equation: * *
y = {@link #offset}+log{@link #base}x
y = offset + log_base(x)
*
* @param base The base of the logarithm.
* @param offset The offset to add to the logarithm.
*/
protected LogarithmicTransform1D(final double base, final double offset) {
this.base = base;
this.offset = offset;
this.lnBase = Math.log(base);
}
/**
* Gets the dimension of input points, which is 1.
*/
public int getDimSource() {
return 1;
}
/**
* Gets the dimension of output points, which is 1.
*/
public int getDimTarget() {
return 1;
}
/**
* Creates the inverse transform of this object.
*/
public MathTransform inverse() {
if (inverse == null) {
inverse = new ExponentialTransform1D(this);
}
return inverse;
}
/**
* Gets the derivative of this function at a value.
*/
public double derivative(final double value) {
return 1 / (lnBase * value);
}
/**
* Transforms the specified value.
*/
public double transform(final double value) {
return Math.log(value)/lnBase + offset;
}
/**
* Transforms a list of coordinate point ordinal values.
*/
public void transform(final float[] srcPts, int srcOff,
final float[] dstPts, int dstOff, int numPts)
{
if (srcPts!=dstPts || srcOff>=dstOff) {
while (--numPts >= 0) {
dstPts[dstOff++] = (float) (Math.log(srcPts[srcOff++])/lnBase + offset);
}
} else {
srcOff += numPts;
dstOff += numPts;
while (--numPts >= 0) {
dstPts[--dstOff] = (float) (Math.log(srcPts[srcOff++])/lnBase + offset);
}
}
}
/**
* Transforms a list of coordinate point ordinal values.
*/
public void transform(final double[] srcPts, int srcOff,
final double[] dstPts, int dstOff, int numPts)
{
if (srcPts!=dstPts || srcOff>=dstOff) {
while (--numPts >= 0) {
dstPts[dstOff++] = Math.log(srcPts[srcOff++])/lnBase + offset;
}
} else {
srcOff += numPts;
dstOff += numPts;
while (--numPts >= 0) {
dstPts[--dstOff] = Math.log(srcPts[srcOff++])/lnBase + offset;
}
}
}
/**
* Concatenates in an optimized way a {@link MathTransform} other
to this
* MathTransform
. This implementation can optimize some concatenation with
* {@link LinearTransform1D} and {@link ExponentialTransform1D}.
*
* @param other The math transform to apply.
* @param applyOtherFirst true
if the transformation order is other
* followed by this
, or false
if the transformation order is
* this
followed by other
.
* @return The combined math transform, or null
if no optimized combined
* transform is available.
*/
MathTransform concatenate(final MathTransform other, final boolean applyOtherFirst) {
if (other instanceof LinearTransform) {
final LinearTransform1D linear = (LinearTransform1D) other;
if (applyOtherFirst) {
if (linear.offset==0 && linear.scale>0) {
return new LogarithmicTransform1D(base, Math.log(linear.scale)/lnBase+offset);
}
} else {
final double newBase = Math.pow(base, 1/linear.scale);
if (!Double.isNaN(newBase)) {
return new LogarithmicTransform1D(newBase, linear.scale*offset + linear.offset);
}
}
} else if (other instanceof ExponentialTransform1D) {
return ((ExponentialTransform1D) other).concatenateLog(this, !applyOtherFirst);
}
return super.concatenate(other, applyOtherFirst);
}
/**
* Returns a hash value for this transform.
* This value need not remain consistent between
* different implementations of the same class.
*/
public int hashCode() {
long code;
code = 75493004 + Double.doubleToLongBits(base);
code = code*37 + Double.doubleToLongBits(offset);
return (int)(code >>> 32) ^ (int)code;
}
/**
* Compares the specified object with
* this math transform for equality.
*/
public boolean equals(final Object object) {
if (object==this) {
// Slight optimization
return true;
}
if (super.equals(object)) {
final LogarithmicTransform1D that = (LogarithmicTransform1D) object;
return Double.doubleToLongBits(this.base) == Double.doubleToLongBits(that.base) &&
Double.doubleToLongBits(this.offset) == Double.doubleToLongBits(that.offset);
}
return false;
}
/**
* Returns the WKT for this math transform.
*/
public String toString() {
final StringBuffer buffer = paramMT("Logarithmic");
addParameter(buffer, "base", base);
if (offset != 0) {
// TODO: The following is NOT a parameter. For WKT formatting, we should decompose this
// LogarithmicTransform1D into a ConcatenatedTransform using a AffineTransform instead.
addParameter(buffer, "offset", offset);
}
buffer.append(']');
return buffer.toString();
}
}