View Javadoc
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 }