1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.math4.legacy.analysis.interpolation;
18
19 import org.apache.commons.rng.simple.RandomSource;
20 import org.apache.commons.rng.sampling.UnitSphereSampler;
21 import org.apache.commons.math4.legacy.analysis.MultivariateFunction;
22 import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
23 import org.apache.commons.math4.legacy.exception.NoDataException;
24 import org.apache.commons.math4.legacy.exception.NotPositiveException;
25 import org.apache.commons.math4.legacy.exception.NullArgumentException;
26
27 /**
28 * Interpolator that implements the algorithm described in
29 * <em>William Dudziak</em>'s
30 * <a href="http://www.dudziak.com/microsphere.pdf">MS thesis</a>.
31 *
32 * @since 3.6
33 */
34 public class MicrosphereProjectionInterpolator
35 implements MultivariateInterpolator {
36 /** Brightness exponent. */
37 private final double exponent;
38 /** Microsphere. */
39 private final InterpolatingMicrosphere microsphere;
40 /** Whether to share the sphere. */
41 private final boolean sharedSphere;
42 /** Tolerance value below which no interpolation is necessary. */
43 private final double noInterpolationTolerance;
44
45 /**
46 * Create a microsphere interpolator.
47 *
48 * @param dimension Space dimension.
49 * @param elements Number of surface elements of the microsphere.
50 * @param exponent Exponent used in the power law that computes the
51 * @param maxDarkFraction Maximum fraction of the facets that can be dark.
52 * If the fraction of "non-illuminated" facets is larger, no estimation
53 * of the value will be performed, and the {@code background} value will
54 * be returned instead.
55 * @param darkThreshold Value of the illumination below which a facet is
56 * considered dark.
57 * @param background Value returned when the {@code maxDarkFraction}
58 * threshold is exceeded.
59 * @param sharedSphere Whether the sphere can be shared among the
60 * interpolating function instances. If {@code true}, the instances
61 * will share the same data, and thus will <em>not</em> be thread-safe.
62 * @param noInterpolationTolerance When the distance between an
63 * interpolated point and one of the sample points is less than this
64 * value, no interpolation will be performed (the value of the sample
65 * will be returned).
66 * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException
67 * if {@code dimension <= 0} or {@code elements <= 0}.
68 * @throws NotPositiveException if {@code exponent < 0}.
69 * @throws NotPositiveException if {@code darkThreshold < 0}.
70 * @throws org.apache.commons.math4.legacy.exception.OutOfRangeException if
71 * {@code maxDarkFraction} does not belong to the interval {@code [0, 1]}.
72 */
73 public MicrosphereProjectionInterpolator(int dimension,
74 int elements,
75 double maxDarkFraction,
76 double darkThreshold,
77 double background,
78 double exponent,
79 boolean sharedSphere,
80 double noInterpolationTolerance) {
81 this(new InterpolatingMicrosphere(dimension,
82 elements,
83 maxDarkFraction,
84 darkThreshold,
85 background,
86 UnitSphereSampler.of(RandomSource.MT_64.create(),
87 dimension)),
88 exponent,
89 sharedSphere,
90 noInterpolationTolerance);
91 }
92
93 /**
94 * Create a microsphere interpolator.
95 *
96 * @param microsphere Microsphere.
97 * @param exponent Exponent used in the power law that computes the
98 * weights (distance dimming factor) of the sample data.
99 * @param sharedSphere Whether the sphere can be shared among the
100 * interpolating function instances. If {@code true}, the instances
101 * will share the same data, and thus will <em>not</em> be thread-safe.
102 * @param noInterpolationTolerance When the distance between an
103 * interpolated point and one of the sample points is less than this
104 * value, no interpolation will be performed (the value of the sample
105 * will be returned).
106 * @throws NotPositiveException if {@code exponent < 0}.
107 */
108 public MicrosphereProjectionInterpolator(InterpolatingMicrosphere microsphere,
109 double exponent,
110 boolean sharedSphere,
111 double noInterpolationTolerance)
112 throws NotPositiveException {
113 if (exponent < 0) {
114 throw new NotPositiveException(exponent);
115 }
116
117 this.microsphere = microsphere;
118 this.exponent = exponent;
119 this.sharedSphere = sharedSphere;
120 this.noInterpolationTolerance = noInterpolationTolerance;
121 }
122
123 /**
124 * {@inheritDoc}
125 *
126 * @throws DimensionMismatchException if the space dimension of the
127 * given samples does not match the space dimension of the microsphere.
128 */
129 @Override
130 public MultivariateFunction interpolate(final double[][] xval,
131 final double[] yval)
132 throws DimensionMismatchException,
133 NoDataException,
134 NullArgumentException {
135 if (xval == null ||
136 yval == null) {
137 throw new NullArgumentException();
138 }
139 if (xval.length == 0) {
140 throw new NoDataException();
141 }
142 if (xval.length != yval.length) {
143 throw new DimensionMismatchException(xval.length, yval.length);
144 }
145 if (xval[0] == null) {
146 throw new NullArgumentException();
147 }
148 final int dimension = microsphere.getDimension();
149 if (dimension != xval[0].length) {
150 throw new DimensionMismatchException(xval[0].length, dimension);
151 }
152
153 // Microsphere copy.
154 final InterpolatingMicrosphere m = sharedSphere ? microsphere : microsphere.copy();
155
156 return new MultivariateFunction() {
157 /** {inheritDoc} */
158 @Override
159 public double value(double[] point) {
160 return m.value(point,
161 xval,
162 yval,
163 exponent,
164 noInterpolationTolerance);
165 }
166 };
167 }
168 }