/*
* Copyright 2006-2017 ICEsoft Technologies Canada Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS
* IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package org.icepdf.core.pobjects.functions;
import org.icepdf.core.pobjects.Dictionary;
import org.icepdf.core.pobjects.Name;
import java.util.Arrays;
import java.util.List;
/**
* <p>This class <code>Function_2</code> represents a generic Type 2, exponentail
* interpolation function type. Type 2 functions include a set of parameters that
* define an exponential interpolation of one input value and n output values:<p>
* <br>
* <ul>
* <li>f(x) = y<sub>0</sub>, ..., y<sub>n-1</sub></li>
* </ul>
* <br>
* <p>Values of <code>Domain</code> must constrain x in such a way that if
* <code>N</code> is not an integer, all values of x must be non-negative, and if
* <code>N</code> is negative, no value of x may be zero. Typically,
* <code>Domain</code> is declared as [0.0 1.0], and <code>N</code> is a postive
* number. The <code>Range</code> attribute is optional and can be used to clip
* the output to a specified range. Note that when <code>N</code> is 1, the
* function performs a linear interpolation between <code>C0</code> and
* <code>C1</code>; therefore, the function cna also be expressed as a sampled
* function (type 0). </p>
*
* @see Function
* @since 1.0
*/
public class Function_2 extends Function {
public static final Name N_KEY = new Name("N");
public static final Name C0_KEY = new Name("C0");
public static final Name C1_KEY = new Name("C1");
// The interpolation exponent. Each input value x will return n values,
// given by:
// y<sub>j</sub> = CO<sub>j</sub> + x<sup>N</sup> x (C1<sub>j</sub> - C0<sub>j</sub>)
// for 0 <= j < n
private float N;
// An array of n numbers defining the function result when x = 0.0. Default
// value is [0.0]
private float C0[] = {0.0f};
// An array of n number defining the function result when x = 1.0. Default
// value is [1.0]
private float C1[] = {1.0f};
/**
* Creates a new instance of a type 2 function.
*
* @param d function's dictionary.
*/
Function_2(Dictionary d) {
super(d);
// Setup and assign N, interpolation exponent
N = d.getFloat(N_KEY);
// Convert C0 dictionary values.
List c0 = (List) d.getObject(C0_KEY);
if (c0 != null) {
C0 = new float[c0.size()];
for (int i = 0; i < c0.size(); i++) {
C0[i] = ((Number) c0.get(i)).floatValue();
}
}
// legacy PDFGo code, guessing that setting default value should just
// be [0.0] and not assigned for each possible entry.
/*else {
for (int i = 0; i < range.length/2; i++) {
C0[i] = 0f;
}
}*/
// Convert C1 dictionary values
List c1 = (List) d.getObject(C1_KEY);
if (c1 != null) {
C1 = new float[c1.size()];
for (int i = 0; i < c1.size(); i++) {
C1[i] = ((Number) c1.get(i)).floatValue();
}
}
// legacy PDFGo code, guessing that setting default value should just
// be [1.0] and not assigned for each possible entry.
/*else {
for (int i = 0; i < range.length/2; i++) {
C1[i] = 1f;
}
}*/
}
/**
* <p>Exponential Interpolation calculation. Each input value x will return
* n values, given by:</p>
* <ul>
* <li>y<sub>j</sub> =
* CO<sub>j</sub> + x<sup>N</sup> x (C1<sub>j</sub> - C0<sub>j</sub>), for 0 <= j < n</li>
* </ul>
*
* @param x input values m
* @return output values n
*/
public float[] calculate(float[] x) {
// create output array
float y[] = new float[x.length * C0.length];
float yValue;
// for each y value, apply exponential interpolation function
for (int i = 0; i < x.length; i++) {
// C0 and C1 should have the same length work through C0 length
for (int j = 0; j < C0.length; j++) {
// apply the function as defined above.
yValue = (float) (C0[j] + Math.pow(Math.abs(x[i]), N) * (C1[j] - C0[j]));
// Range is optional but if present should be used to clip the output
if (range != null)
yValue = Math.min(Math.max(yValue, range[2 * j]), range[2 * j + 1]);
// finally assign the interpolation value.
y[i * C0.length + j] = yValue;
}
}
return y;
}
public String toString() {
return "FunctionType: " + functionType +
"\n domain: " + Arrays.toString(domain) +
"\n range: " + Arrays.toString(range) +
"\n N: " + N +
"\n C0: " + Arrays.toString(C0) +
"\n C1: " + Arrays.toString(C1);
}
}