File indexing completed on 2025-01-19 03:55:16

0001 /*****************************************************************************/
0002 // Copyright 2006-2019 Adobe Systems Incorporated
0003 // All Rights Reserved.
0004 //
0005 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
0006 // accordance with the terms of the Adobe license agreement accompanying it.
0007 /*****************************************************************************/
0008 
0009 #include "dng_spline.h"
0010 
0011 #include "dng_assertions.h"
0012 #include "dng_exceptions.h"
0013 
0014 /******************************************************************************/
0015 
0016 dng_spline_solver::dng_spline_solver ()
0017 
0018     :   X ()
0019     ,   Y ()
0020     ,   S ()
0021 
0022     {
0023 
0024     }
0025 
0026 /******************************************************************************/
0027 
0028 dng_spline_solver::~dng_spline_solver ()
0029     {
0030 
0031     }
0032 
0033 /******************************************************************************/
0034 
0035 void dng_spline_solver::Reset ()
0036     {
0037 
0038     X.clear ();
0039     Y.clear ();
0040 
0041     S.clear ();
0042 
0043     }
0044 
0045 /******************************************************************************/
0046 
0047 void dng_spline_solver::Add (real64 x, real64 y)
0048     {
0049 
0050     X.push_back (x);
0051     Y.push_back (y);
0052 
0053     }
0054 
0055 /******************************************************************************/
0056 
0057 void dng_spline_solver::Solve ()
0058     {
0059 
0060     // This code computes the unique curve such that:
0061     //      It is C0, C1, and C2 continuous
0062     //      The second derivative is zero at the end points
0063 
0064     int32 count = (int32) X.size ();
0065 
0066     DNG_REQUIRE (count >= 2, "Too few points");
0067 
0068     int32 start = 0;
0069     int32 end   = count;
0070 
0071     real64 A =  X [start+1] - X [start];
0072     real64 B = (Y [start+1] - Y [start]) / A;
0073 
0074     S.resize (count);
0075 
0076     S [start] = B;
0077 
0078     int32 j;
0079 
0080     // Slopes here are a weighted average of the slopes
0081     // to each of the adjcent control points.
0082 
0083     for (j = start + 2; j < end; ++j)
0084         {
0085 
0086         real64 C = X [j] - X [j-1];
0087         real64 D = (Y [j] - Y [j-1]) / C;
0088 
0089         S [j-1] = (B * C + D * A) / (A + C);
0090 
0091         A = C;
0092         B = D;
0093 
0094         }
0095 
0096     S [end-1] = 2.0 * B - S [end-2];
0097     S [start] = 2.0 * S [start] - S [start+1];
0098 
0099     if ((end - start) > 2)
0100         {
0101 
0102         dng_std_vector<real64> E;
0103         dng_std_vector<real64> F;
0104         dng_std_vector<real64> G;
0105 
0106         E.resize (count);
0107         F.resize (count);
0108         G.resize (count);
0109 
0110         F [start] = 0.5;
0111         E [end-1] = 0.5;
0112         G [start] = 0.75 * (S [start] + S [start+1]);
0113         G [end-1] = 0.75 * (S [end-2] + S [end-1]);
0114 
0115         for (j = start+1; j < end - 1; ++j)
0116             {
0117 
0118             A = (X [j+1] - X [j-1]) * 2.0;
0119 
0120             E [j] = (X [j+1] - X [j]) / A;
0121             F [j] = (X [j] - X [j-1]) / A;
0122             G [j] = 1.5 * S [j];
0123 
0124             }
0125 
0126         for (j = start+1; j < end; ++j)
0127             {
0128 
0129             A = 1.0 - F [j-1] * E [j];
0130 
0131             if (j != end-1) F [j] /= A;
0132 
0133             G [j] = (G [j] - G [j-1] * E [j]) / A;
0134 
0135             }
0136 
0137         for (j = end - 2; j >= start; --j)
0138             G [j] = G [j] - F [j] * G [j+1];
0139 
0140         for (j = start; j < end; ++j)
0141             S [j] = G [j];
0142 
0143         }
0144 
0145     }
0146 
0147 /******************************************************************************/
0148 
0149 bool dng_spline_solver::IsIdentity () const
0150     {
0151 
0152     int32 count = (int32) X.size ();
0153 
0154     if (count != 2)
0155         return false;
0156 
0157     if (X [0] != 0.0 || X [1] != 1.0 ||
0158         Y [0] != 0.0 || Y [1] != 1.0)
0159         return false;
0160 
0161     return true;
0162 
0163     }
0164 
0165 /******************************************************************************/
0166 
0167 real64 dng_spline_solver::Evaluate (real64 x) const
0168     {
0169 
0170     int32 count = (int32) X.size ();
0171 
0172     // Check for off each end of point list.
0173 
0174     if (x <= X [0])
0175         return Y [0];
0176 
0177     if (x >= X [count-1])
0178         return Y [count-1];
0179 
0180     // Binary search for the index.
0181 
0182     int32 lower = 1;
0183     int32 upper = count - 1;
0184 
0185     while (upper > lower)
0186         {
0187 
0188         int32 mid = (lower + upper) >> 1;
0189 
0190         if (x == X [mid])
0191             {
0192             return Y [mid];
0193             }
0194 
0195         if (x > X [mid])
0196             lower = mid + 1;
0197         else
0198             upper = mid;
0199 
0200         }
0201 
0202     DNG_ASSERT (upper == lower, "Binary search error in point list");
0203 
0204     int32 j = lower;
0205 
0206     // X [j - 1] < x <= X [j]
0207     // A is the distance between the X [j] and X [j - 1]
0208     // B and C describe the fractional distance to either side. B + C = 1.
0209 
0210     // We compute a cubic spline between the two points with slopes
0211     // S[j-1] and S[j] at either end. Specifically, we compute the 1-D Bezier
0212     // with control values:
0213     //
0214     //      Y[j-1], Y[j-1] + S[j-1]*A, Y[j]-S[j]*A, Y[j]
0215 
0216     return EvaluateSplineSegment (x,
0217                                   X [j - 1],
0218                                   Y [j - 1],
0219                                   S [j - 1],
0220                                   X [j    ],
0221                                   Y [j    ],
0222                                   S [j    ]);
0223 
0224     }
0225 
0226 /*****************************************************************************/