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 /*****************************************************************************/