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> &gt; 
<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);
+            }
+        }
     }
 
     /**

Reply via email to