This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push: new b85d81fee6 Increase the maximum number of coefficients that we can compute for Clenshaw summation. This is a generator of generator of code. Needed for "Equidistant Cylindrical" projection because the number of coefficients exceed the previous limit (which was 6). b85d81fee6 is described below commit b85d81fee65fa785167c7641d9d4ba8835fb704d Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Fri Apr 26 19:05:46 2024 +0200 Increase the maximum number of coefficients that we can compute for Clenshaw summation. This is a generator of generator of code. Needed for "Equidistant Cylindrical" projection because the number of coefficients exceed the previous limit (which was 6). --- .../apache/sis/referencing/ClenshawSummation.java | 141 +++++++++++++++++++-- 1 file changed, 132 insertions(+), 9 deletions(-) diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/ClenshawSummation.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/ClenshawSummation.java index a37b1a1616..96053fb6fa 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/ClenshawSummation.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/ClenshawSummation.java @@ -353,17 +353,140 @@ public final class ClenshawSummation { * @see <a href="https://issues.apache.org/jira/browse/SIS-465">SIS-465</a> */ private void compute() { - if (sineCoefficients.length > 6) { - throw new UnsupportedOperationException("Too many coefficients for current implementation."); - } cosineCoefficients = new Coefficient[] { - sum(1, 0, -1, 0, 1 ), // A′ = A - C + E - sum(0, 2, 0, -4, 0, 6), // B′ = 2B - 4D + 6F - sum(0, 0, 4, 0, -12 ), // C′ = 4C - 12E - sum(0, 0, 0, 8, 0, -32), // D′ = 8D - 32F - sum(0, 0, 0, 0, 16 ), // E′ = 16E - sum(0, 0, 0, 0, 0, 32), // F′ = 32F + sum(1, 0, -1, 0, 1, 0, -1 ), // A′ = A - C + E - G + sum(0, 2, 0, -4, 0, 6, 0, -8), // B′ = 2B - 4D + 6F - 8H + sum(0, 0, 4, 0, -12, 0, 24 ), // C′ = 4C - 12E + 24G + sum(0, 0, 0, 8, 0, -32, 0, 80), // D′ = 8D - 32F + 80H + sum(0, 0, 0, 0, 16, 0, -80 ), // E′ = 16E - 80G + sum(0, 0, 0, 0, 0, 32, 0, -192), // F′ = 32F - 192H + sum(0, 0, 0, 0, 0, 0, 64 ), // G′ = 64G + sum(0, 0, 0, 0, 0, 0, 0, 128), // H′ = 128H }; + if (sineCoefficients.length > cosineCoefficients.length) { + throw new UnsupportedOperationException("Too many coefficients for current implementation."); + } + } + + /** + * Computes the coefficients that are hard-coded in the {@link #compute()} method. + * This class needs to be executed only when the maximal number of terms increased. + * The formula is given by Charles F. F. Karney, Geodesics on an ellipsoid of revolution (2011) equation 59: + * + * <blockquote>f(θ) = ∑(aₙ⋅sin(n⋅θ)</blockquote> + * + * where the sum is from <var>n</var>=1 to <var>N</var> and <var>N</var> is the maximum number of terms. + * The equation can be rewritten as: + * + * <blockquote>f(θ) = b₁⋅sin(θ)</blockquote> + * + * where bₙ = + * <ul> + * <li>0 for <var>n</var> > <var>N</var>,</li> + * <li>aₙ + 2⋅bₙ₊₁⋅cos(θ) − bₙ₊₂ otherwise.</li> + * </ul> + * + * This class computes b₁. + */ + public static final class Precomputation { + /** + * The factors by which to multiply the aₙ terms. + * The first array index identifies the factors which is multiplied, in reverse order. + * For example, if there is 4 terms to compute, then the factors are in the following order: + * + * <ul> + * <li>{@code multiplicands[0]} = factors by which to multiply <var>D</var> (a₄).</li> + * <li>{@code multiplicands[1]} = factors by which to multiply <var>C</var> (a₃).</li> + * <li>{@code multiplicands[2]} = factors by which to multiply <var>B</var> (a₂).</li> + * <li>{@code multiplicands[3]} = factors by which to multiply <var>A</var> (a₁).</li> + * </ul> + * + * The second array index is the power by which to multiply {@code cos(θ)}. + */ + private final int[][] multiplicands; + + /** + * Creates a new step in the iteration process for computing the factors. + * This constructor shall be invoked with decreasing <var>n</var> values, + * with b₁ computed last. + * + * @param b1 result from the step at <var>n</var> + 1, or {@code null} if zero. + * @param b2 result from the step at <var>n</var> + 2, or {@code null} if zero. + */ + private Precomputation(final Precomputation b1, final Precomputation b2) { + final int length = (b1 != null) ? b1.multiplicands.length + 1 : 1; + multiplicands = new int[length][length]; + multiplicands[length - 1][0] = 1; + if (b2 != null) { + // Add −bₙ₊₂ — we add terms at the same power of cos(θ), therefor all indices match. + for (int term=0; term < b2.multiplicands.length; term++) { + final int max = b2.multiplicands[term].length; + for (int power=0; power<max; power++) { + multiplicands[term][power] -= b2.multiplicands[term][power]; + } + } + } + if (b1 != null) { + // Add +2⋅bₙ₊₁⋅cos(θ) — because of cos(θ), power indices are offset by one. + for (int term=0; term < b1.multiplicands.length; term++) { + final int max = b1.multiplicands[term].length; + for (int power=0; power<max; power++) { + multiplicands[term][power+1] += 2*b1.multiplicands[term][power]; + } + } + } + } + + /** + * Returns the factors for Clenshaw summation. + * + * @return string representation of the factors for Clenshaw summation. + */ + @Override + public String toString() { + final var sb = new StringBuilder(); + for (int power=0; power < multiplicands[0].length; power++) { + String separator = "sum("; + for (int term=multiplicands.length; --term >= 0;) { + sb.append(separator).append(multiplicands[term][power]); + separator = ", "; + } + sb.append("), // ").append((char) ('A' + power)).append("′ = "); + char symbol = 'A'; + boolean more = false; + for (int term=multiplicands.length; --term >= 0; symbol++) { + int m = multiplicands[term][power]; + if (m != 0) { + if (more) { + sb.append(' ').append(m < 0 ? '-' : '+'); + m = Math.abs(m); + } + sb.append(' '); + if (m != 1) sb.append(m); + sb.append(symbol); + more = true; + } + } + sb.append(System.lineSeparator()); + } + return sb.toString(); + } + + /** + * Computes and prints the factors for Clenshaw summation with the given number of terms. + * + * @param n the desired number of terms. + */ + public static void run(int n) { + Precomputation b2, b1 = null; + Precomputation result = null; + while (--n >= 0) { + b2 = b1; + b1 = result; + result = new Precomputation(b1, b2); + System.out.println(result); + } + } } /**