CoastalME (Coastal Modelling Environment)
Simulates the long-term behaviour of complex coastlines
Loading...
Searching...
No Matches
smooth_line.cpp
Go to the documentation of this file.
1
10
11/* ==============================================================================================================================
12 This file is part of CoastalME, the Coastal Modelling Environment.
13
14 CoastalME is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19==============================================================================================================================*/
20#include <assert.h>
21
22#include <cmath>
23using std::pow;
24
25#include <iostream>
26using std::cerr;
27using std::endl;
28using std::ios;
29
30#include "cme.h"
31#include "simulation.h"
32#include "2d_point.h"
33#include "2di_point.h"
34#include "line.h"
35
36// Visible throughout this file. Note that arrays here are used from index 1
38
39namespace
40{
41void LUDecomp(Matrix, int const, int const, int[], int*, int*);
42void LULinearSolve(Matrix const, int const, int const[], double[]);
43} // namespace
44
45//===============================================================================================================================
47//===============================================================================================================================
49{
51
52 // Note that m_nCoastSmoothingWindowSize must be odd (have already checked this)
53 int const nHalfWindow = m_nCoastSmoothingWindowSize / 2;
54
55 // Calculate the shift index for this value of nHalfWindow
56 int j = 3;
57
58 for (int i = 2; i <= nHalfWindow + 1; i++)
59 {
60 m_VnSavGolIndexCoast[i] = i - j;
61 j += 2;
62 }
63
64 j = 2;
65
66 for (int i = nHalfWindow + 2; i <= m_nCoastSmoothingWindowSize; i++)
67 {
68 m_VnSavGolIndexCoast[i] = i - j;
69 j += 2;
70 }
71
72 // Now calculate the Savitzky-Golay filter coefficients
74
76}
77
78//===============================================================================================================================
80//===============================================================================================================================
81CGeomLine CSimulation::LSmoothCoastSavitzkyGolay(CGeomLine* pLineIn, int const nStartEdge, int const nEndEdge) const
82{
83 // Note that m_nCoastSmoothingWindowSize must be odd (have already checked this)
84 int const nHalfWindow = m_nCoastSmoothingWindowSize / 2;
85
86 // Make a copy of the unsmoothed CGeomLine (must be blank)
87 int const nSize = pLineIn->nGetSize();
88 CGeomLine LTemp;
89 LTemp.Resize(nSize);
90
91 // Apply the Savitzky-Golay smoothing filter
92 for (int i = 0; i < nSize; i++)
93 {
94 CGeom2DPoint const PtThis(pLineIn->dGetXAt(i), pLineIn->dGetYAt(i));
95 CGeom2DIPoint const PtiThis = PtiExtCRSToGridRound(&PtThis);
96 int nXThis = PtiThis.nGetX();
97 int nYThis = PtiThis.nGetY();
98
99 // Safety check
100 if (! bIsWithinValidGrid(nXThis, nYThis))
101 KeepWithinValidGrid(nXThis, nYThis);
102
103 // Don't smooth intervention cells
104 if (bIsInterventionCell(nXThis, nYThis))
105 {
106 LTemp[i] = pLineIn->pPtGetAt(i);
107 continue;
108 }
109
110 if (i < nHalfWindow)
111 {
112 // For the first few values of LTemp, just apply a running mean with a variable-sized window
113 int nTmpWindow = 0;
114 double dWindowTotX = 0, dWindowTotY = 0;
115
116 for (int j = -nHalfWindow; j < m_nCoastSmoothingWindowSize - nHalfWindow; j++)
117 {
118 int const k = i + j;
119
120 if ((k > 0) && (k < nSize))
121 {
122 dWindowTotX += pLineIn->dGetXAt(k);
123 dWindowTotY += pLineIn->dGetYAt(k);
124 nTmpWindow++;
125 }
126 }
127
128 switch (nStartEdge)
129 {
130 case NORTH:
131 case SOUTH:
132 // Don't apply the filter in the Y direction
133 LTemp[i] = CGeom2DPoint(dWindowTotX / nTmpWindow, pLineIn->dGetYAt(i));
134 // LTemp.SetXAt(i, dWindowTotX / static_cast<double>(nTmpWindow));
135 // LTemp.SetYAt(i, pLineIn->dGetYAt(i));
136 break;
137
138 case EAST:
139 case WEST:
140 // Don't apply the filter in the X direction
141 LTemp[i] = CGeom2DPoint(pLineIn->dGetXAt(i), dWindowTotY / nTmpWindow);
142 // LTemp.SetXAt(i, pLineIn->dGetXAt(i));
143 // LTemp.SetYAt(i, dWindowTotY / static_cast<double>(nTmpWindow));
144 break;
145 }
146 }
147
148 else if (i >= (nSize - nHalfWindow))
149 {
150 // For the last few values of PtVTemp, just apply a running mean with a variable-sized window
151 int nTmpWindow = 0;
152 double dWindowTotX = 0, dWindowTotY = 0;
153
154 for (int j = -nHalfWindow; j < m_nCoastSmoothingWindowSize - nHalfWindow; j++)
155 {
156 int const k = i + j;
157
158 if ((k > 0) && (k < nSize))
159 {
160 dWindowTotX += pLineIn->dGetXAt(k);
161 dWindowTotY += pLineIn->dGetYAt(k);
162 nTmpWindow++;
163 }
164 }
165
166 switch (nEndEdge)
167 {
168 case NORTH:
169 case SOUTH:
170 // Don't apply the filter in the Y direction
171 LTemp[i] = CGeom2DPoint(dWindowTotX / nTmpWindow, pLineIn->dGetYAt(i));
172 // LTemp.SetXAt(i, dWindowTotX / static_cast<double>(nTmpWindow));
173 // LTemp.SetYAt(i, pLineIn->dGetYAt(i));
174 break;
175
176 case EAST:
177 case WEST:
178 // Don't apply the filter in the X direction
179 LTemp[i] = CGeom2DPoint(pLineIn->dGetXAt(i), dWindowTotY / nTmpWindow);
180 // LTemp.SetXAt(i, pLineIn->dGetXAt(i));
181 // LTemp.SetYAt(i, dWindowTotY / static_cast<double>(nTmpWindow));
182 break;
183 }
184 }
185
186 else
187 {
188 // For all other PtVTemp values, calc Savitzky-Golay weighted values for both X and Y
189 for (int j = 0; j < m_nCoastSmoothingWindowSize; j++)
190 {
191 int const k = i + m_VnSavGolIndexCoast[j + 1];
192
193 if ((k >= 0) && (k < nSize)) // Skip points that do not exist, note starts from 1
194 {
195 double dX = LTemp.dGetXAt(i);
196 dX += m_VdSavGolFCRWCoast[j + 1] * pLineIn->dGetXAt(k);
197 // LTemp.SetXAt(i, dX);
198
199 double dY = LTemp.dGetYAt(i);
200 dY += m_VdSavGolFCRWCoast[j + 1] * pLineIn->dGetYAt(k);
201
202 LTemp[i] = CGeom2DPoint(dX, dY);
203 // LTemp.SetYAt(i, dY);
204 }
205 }
206 }
207 }
208
209 // Return the smoothed CGeomLine
210 return LTemp;
211}
212
213//===============================================================================================================================
215//===============================================================================================================================
217{
218 // Note that m_nCoastSmoothingWindowSize must be odd (have already checked this)
219 int const nHalfWindow = m_nCoastSmoothingWindowSize / 2;
220 double const dHalfWindow = nHalfWindow;
221
222 // Make a copy of the unsmoothed CGeomLine
223 int const nSize = pLineIn->nGetSize();
224 CGeomLine LTemp;
225 LTemp = *pLineIn;
226
227 // Apply the running mean smoothing filter, with a variable window size at both ends of the line
228 for (int i = 0; i < nSize; i++)
229 {
230 // Don't smooth intervention cells
231 CGeom2DPoint const PtThis(pLineIn->dGetXAt(i), pLineIn->dGetYAt(i));
232 CGeom2DIPoint const PtiThis = PtiExtCRSToGridRound(&PtThis);
233 int nXThis = tMin(PtiThis.nGetX(), m_nXGridSize - 1);
234 int nYThis = tMin(PtiThis.nGetY(), m_nYGridSize - 1);
235
236 // Safety checks
237 nXThis = tMax(nXThis, 0);
238 nYThis = tMax(nYThis, 0);
239
240 if (bIsInterventionCell(nXThis, nYThis))
241 {
242 LTemp[i] = pLineIn->pPtGetAt(i);
243 continue;
244 }
245
246 // bool bNearStartEdge = false, bNearEndEdge = false;
247 // int consTant = 0;
248 double nTmpWindow = 0;
249 double dWindowTotX = 0, dWindowTotY = 0;
250
251 if (i < nHalfWindow)
252 {
253 for (int j = 0; j <= i; j++)
254 {
255 // // For points at both ends of the coastline, use a smaller window
256 double const weight = (dHalfWindow - tAbs(i - j)) / dHalfWindow;
257 dWindowTotX += pLineIn->dGetXAt(j) * weight;
258 dWindowTotY += pLineIn->dGetYAt(j) * weight;
259 nTmpWindow += weight;
260 }
261 }
262
263 else if (i >= nSize - nHalfWindow)
264 {
265 for (int j = nSize - 1; j >= i; j--)
266 {
267 double const weight = (dHalfWindow - tAbs(i - j)) / dHalfWindow;
268 dWindowTotX += pLineIn->dGetXAt(j) * weight;
269 dWindowTotY += pLineIn->dGetYAt(j) * weight;
270 nTmpWindow += weight;
271 }
272 } // namespace name
273
274 else
275 {
276 for (int j = i - nHalfWindow; j < i + nHalfWindow; j++)
277 {
278 double const weight = (dHalfWindow - tAbs(i - j)) / dHalfWindow;
279 dWindowTotX += pLineIn->dGetXAt(j) * weight;
280 dWindowTotY += pLineIn->dGetYAt(j) * weight;
281 nTmpWindow += weight;
282 }
283 }
284
285 // if (bNearStartEdge)
286 // {
287 // // We are near the start edge
288 // switch (nStartEdge)
289 // {
290 // case NORTH:
291 // // Don't apply the filter in the y direction
292 // LTemp.SetXAt(i, dWindowTotX / static_cast<double>(nTmpWindow));
293 // break;
294 // case SOUTH:
295 // // Don't apply the filter in the y direction
296 // LTemp.SetXAt(i, dWindowTotX / static_cast<double>(nTmpWindow));
297 // break;
298
299 // case EAST:
300 // // Don't apply the filter in the x direction
301 // LTemp.SetYAt(i, dWindowTotY / static_cast<double>(nTmpWindow));
302 // break;
303 // case WEST:
304 // // Don't apply the filter in the x direction
305 // LTemp.SetYAt(i, dWindowTotY / static_cast<double>(nTmpWindow));
306 // break;
307 // }
308 // }
309 // else if (bNearEndEdge)
310 // {
311 // // We are near the end edge
312 // switch (nEndEdge)
313 // {
314 // case NORTH:
315 // // Don't apply the filter in the y direction
316 // LTemp.SetXAt(i, dWindowTotX / static_cast<double>(nTmpWindow));
317 // break;
318 // case SOUTH:
319 // // Don't apply the filter in the y direction
320 // LTemp.SetXAt(i, dWindowTotX / static_cast<double>(nTmpWindow));
321 // break;
322
323 // case EAST:
324 // // Don't apply the filter in the x direction
325 // LTemp.SetYAt(i, dWindowTotY / static_cast<double>(nTmpWindow));
326 // break;
327 // case WEST:
328 // // Don't apply the filter in the x direction
329 // LTemp.SetYAt(i, dWindowTotY / static_cast<double>(nTmpWindow));
330 // break;
331 // }
332 // }
333 // else
334 // {
335 // // Not near any edge, apply both x and y filters
336 LTemp[i] = CGeom2DPoint(dWindowTotX / nTmpWindow, dWindowTotY / nTmpWindow);
337 // LTemp.SetXAt(i, dWindowTotX / static_cast<double>(nTmpWindow));
338 // LTemp.SetYAt(i, dWindowTotY / static_cast<double>(nTmpWindow));
339 // }
340 }
341
342 // Return the smoothed CGeomLine
343 return LTemp;
344}
345
346//===============================================================================================================================
348//===============================================================================================================================
349vector<double> CSimulation::dVSmoothProfileSlope(vector<double>* pdVSlope) const
350{
351 // Make a copy of the unsmoothed profile slope vector
352 int const nSize = static_cast<int>(pdVSlope->size());
353 vector<double> dVSmoothed = *pdVSlope;
354
355 // Note that m_nProfileSmoothWindow must be odd (have already checked this)
356 int const nHalfWindow = m_nProfileSmoothWindow / 2;
357
358 // Apply the running mean smoothing filter, with a variable window size at both ends of the line
359 for (int i = 0; i < nSize; i++)
360 {
361 int nTmpWindow = 0;
362 double dWindowTot = 0;
363
364 for (int j = -nHalfWindow; j < m_nProfileSmoothWindow - nHalfWindow; j++)
365 {
366 // For points at both ends of the profile, use a smaller window
367 int const k = i + j;
368
369 if ((k < 0) || (k >= nSize))
370 continue;
371
372 dWindowTot += pdVSlope->at(k);
373 nTmpWindow++;
374 }
375
376 dVSmoothed[i] = dWindowTot / static_cast<double>(nTmpWindow);
377
378 // If necessary, constrain the slope as in SCAPE
379 if (dVSmoothed[i] >= 0)
380 dVSmoothed[i] = tMin(dVSmoothed[i], m_dProfileMaxSlope);
381
382 else
383 dVSmoothed[i] = tMax(dVSmoothed[i], -m_dProfileMaxSlope);
384 }
385
386 // Return the smoothed vector
387 return dVSmoothed;
388}
389
390//===============================================================================================================================
392//===============================================================================================================================
393void CSimulation::CalcSavitzkyGolay(double dFilterCoeffsArray[], int const nWindowSize, int const nLeft, int const nRight, int const nDerivOrder, int const nSmoothPolyOrder)
394{
395 // Some sanity checks
396 if ((nWindowSize < nLeft + nRight + 1) || (nLeft < 0) || (nRight < 0) || (nDerivOrder > nSmoothPolyOrder) || (nSmoothPolyOrder > static_cast<int>(SAVGOL_POLYNOMIAL_MAX_ORDER)) || (nLeft + nRight < nSmoothPolyOrder))
397 {
398 cerr << ERR << "Error in arguments to CalcSavitzkyGolay" << endl;
399 return;
400 }
401
402 // Initialise arrays (including index 0 for tidiness)
403 int nIndexArray[SAVGOL_POLYNOMIAL_MAX_ORDER + 2];
404 Matrix dMatrix;
405 double dSolutionArray[SAVGOL_POLYNOMIAL_MAX_ORDER + 2];
406
407 for (int i = 0; i <= SAVGOL_POLYNOMIAL_MAX_ORDER + 1; i++)
408 {
409 for (int j = 0; j <= SAVGOL_POLYNOMIAL_MAX_ORDER + 1; j++)
410 dMatrix[i][j] = 0;
411
412 dSolutionArray[i] = 0;
413 nIndexArray[i] = 0;
414 }
415
416 for (int ipj = 0; ipj <= 2 * nSmoothPolyOrder; ipj++)
417 {
418 // Set up the equations for the desired least squares fit
419 double dSum = 0;
420
421 if (ipj == 0)
422 dSum = 1;
423
424 for (int k = 1; k <= nRight; k++)
425 dSum += pow(k, ipj);
426
427 for (int k = 1; k <= nLeft; k++)
428 dSum += pow(-k, ipj);
429
430 int const mm = tMin(ipj, 2 * nSmoothPolyOrder - ipj);
431 int imj = -mm;
432
433 do
434 {
435 dMatrix[1 + (ipj + imj) / 2][1 + (ipj - imj) / 2] = dSum;
436 imj += 2;
437 } while (imj <= mm);
438 }
439
440 // Solve them using LU decomposition
441 int nDCode = 0, nICode = 0;
442 LUDecomp(dMatrix, nSmoothPolyOrder + 1, SAVGOL_POLYNOMIAL_MAX_ORDER + 1, nIndexArray, &nDCode, &nICode);
443
444 // Right-hand side vector is unit vector, depending on which derivative we want
445 dSolutionArray[nDerivOrder + 1] = 1;
446
447 // Backsubstitute, giving one row of the inverse matrix
448 LULinearSolve(dMatrix, nSmoothPolyOrder + 1, nIndexArray, dSolutionArray);
449
450 // Zero the output array (it may be bigger than the number of coefficients). Again include index 0 for tidiness
451 // for (int n = 0; n < SAVGOL_POLYNOMIAL_MAX_ORDER+1; n++)
452 // for (int n = 0; n <= nWindowSize; n++)
453 // dFilterCoeffsArray[n] = 0;
454
455 for (int n = -nLeft; n <= nRight; n++)
456 {
457 // Each Savitzky-Golay coefficient is the dot product of powers of an integer with the inverse matrix row
458 double dSum = dSolutionArray[1];
459 double dFac = 1;
460
461 for (int m = 1; m <= nSmoothPolyOrder; m++)
462 {
463 dFac *= n;
464 dSum += dSolutionArray[m + 1] * dFac;
465 }
466
467 // Store in wrap-around order
468 int const nInd = ((nWindowSize - n) % nWindowSize) + 1;
469 dFilterCoeffsArray[nInd] = dSum;
470 }
471}
472
473namespace
474{
475//===============================================================================================================================
477//===============================================================================================================================
478void LUDecomp(Matrix A, int const N, int const np, int nIndexArray[], int* nDCode, int* nICode)
479{
480 if (N >= np)
481 {
482 // cerr << ERR << "in LUDecomp" << endl;
483 return;
484 }
485
486 double const TINY = 1e-12;
487 double AMAX, DUM, SUM;
488 double* VV = new double[np];
489 int I, IMAX = 0, J, K;
490
491 *nDCode = 1;
492 *nICode = 0;
493
494 for (I = 1; I <= N; I++)
495 {
496 AMAX = 0.0;
497
498 for (J = 1; J <= N; J++)
499 if (tAbs(A[I][J]) > AMAX)
500 AMAX = tAbs(A[I][J]);
501
502 if (AMAX < TINY)
503 {
504 *nICode = 1;
505 delete[] VV;
506 return;
507 }
508
509 VV[I] = 1.0 / AMAX;
510 }
511
512 for (J = 1; J <= N; J++)
513 {
514 for (I = 1; I < J; I++)
515 {
516 SUM = A[I][J];
517
518 for (K = 1; K < I; K++)
519 SUM -= A[I][K] * A[K][J];
520
521 A[I][J] = SUM;
522 }
523
524 AMAX = 0.0;
525
526 for (I = J; I <= N; I++)
527 {
528 SUM = A[I][J];
529
530 for (K = 1; K < J; K++)
531 SUM -= A[I][K] * A[K][J];
532
533 A[I][J] = SUM;
534 DUM = VV[I] * tAbs(SUM);
535
536 if (DUM >= AMAX)
537 {
538 IMAX = I;
539 AMAX = DUM;
540 }
541 }
542
543 if (J != IMAX)
544 {
545 for (K = 1; K <= N; K++)
546 {
547 DUM = A[IMAX][K];
548 A[IMAX][K] = A[J][K];
549 A[J][K] = DUM;
550 }
551
552 *nDCode = -(*nDCode);
553 VV[IMAX] = VV[J];
554 }
555
556 nIndexArray[J] = IMAX;
557
558 if (tAbs(A[J][J]) < TINY)
559 A[J][J] = TINY;
560
561 if (J != N)
562 {
563 DUM = 1.0 / A[J][J];
564
565 for (I = J + 1; I <= N; I++)
566 A[I][J] *= DUM;
567 }
568 }
569
570 delete[] VV;
571}
572} // namespace
573
574namespace
575{
576//===============================================================================================================================
578//===============================================================================================================================
579void LULinearSolve(Matrix const A, int const N, int const nIndexArray[], double B[])
580{
581 int II = 0;
582 double SUM;
583
584 for (int I = 1; I <= N; I++)
585 {
586 int const LL = nIndexArray[I];
587 SUM = B[LL];
588 B[LL] = B[I];
589
590 if (II != 0)
591 for (int J = II; J < I; J++)
592 SUM -= A[I][J] * B[J];
593
594 else if (! bFPIsEqual(SUM, 0.0, TOLERANCE))
595 II = I;
596
597 B[I] = SUM;
598 }
599
600 for (int I = N; I > 0; I--)
601 {
602 SUM = B[I];
603
604 if (I < N)
605 for (int J = I + 1; J <= N; J++)
606 SUM -= A[I][J] * B[J];
607
608 B[I] = SUM / A[I][I];
609 }
610}
611} // namespace
Contains CGeom2DPoint definitions.
Contains CGeom2DIPoint definitions.
int nGetSize(void) const
Definition 2d_shape.cpp:53
void Resize(int const)
Resizes the vector which represents this 2D shape.
Definition 2d_shape.cpp:47
Geometry class used to represent 2D point objects with integer coordinates.
Definition 2di_point.h:25
int nGetY(void) const
Returns the CGeom2DIPoint object's integer Y coordinate.
Definition 2di_point.cpp:51
int nGetX(void) const
Returns the CGeom2DIPoint object's integer X coordinate.
Definition 2di_point.cpp:45
Geometry class used to represent 2D point objects with floating-point coordinates.
Definition 2d_point.h:25
Geometry class used to represent 2D vector line objects.
Definition line.h:28
CGeom2DPoint * pPtGetAt(int const)
Returns the point at a given place in the line.
Definition line.cpp:66
double dGetYAt(int const)
Returns the Y value at a given place in the line.
Definition line.cpp:60
double dGetXAt(int const)
Returns the X value at a given place in the line.
Definition line.cpp:54
void CalcSavitzkyGolayCoeffs(void)
Calculates the Savitzky-Golay smoothing coefficients for a given size of smoothing window....
static void CalcSavitzkyGolay(double[], int const, int const, int const, int const, int const)
CalcSavitzkyGolay uses LULinearSolve and LUDecomp. It returns dFilterCoeffsArray[nWindowSize],...
CGeomLine LSmoothCoastRunningMean(CGeomLine *) const
Does running-mean smoothing of a CGeomLine coastline vector (is in external CRS coordinates)
int m_nXGridSize
The size of the grid in the x direction.
Definition simulation.h:477
CGeom2DIPoint PtiExtCRSToGridRound(CGeom2DPoint const *) const
Transforms a pointer to a CGeom2DPoint in the external CRS to the equivalent CGeom2DIPoint in the ras...
int m_nYGridSize
The size of the grid in the y direction.
Definition simulation.h:480
void KeepWithinValidGrid(int &, int &) const
Constrains the supplied point (in the grid CRS) to be a valid cell within the raster grid.
int m_nCoastSmoothingWindowSize
The size of the window used for coast smoothing. Must be an odd number.
Definition simulation.h:489
int m_nSavGolCoastPoly
The order of the coastline profile smoothing polynomial if Savitzky-Golay smoothing is used (usually ...
Definition simulation.h:492
vector< double > dVSmoothProfileSlope(vector< double > *) const
Does running-mean smoothing of the slope of a coastline-normal profile.
vector< double > m_VdSavGolFCRWCoast
Savitzky-Golay filter coefficients for the coastline vector(s)
CGeomLine LSmoothCoastSavitzkyGolay(CGeomLine *, int const, int const) const
Does smoothing of a CGeomLine coastline vector (is in external CRS coordinates) using a Savitzky-Gola...
bool bIsWithinValidGrid(int const, int const) const
Checks whether the supplied point (an x-y pair, in the grid CRS) is within the raster grid,...
bool bIsInterventionCell(int const, int const) const
Returns true if the cell is an intervention.
Definition utils.cpp:3066
vector< int > m_VnSavGolIndexCoast
Savitzky-Golay shift index for the coastline vector(s)
double m_dProfileMaxSlope
Maximum slope on coastline-normal profiles.
Definition simulation.h:918
int m_nProfileSmoothWindow
The size of the window used for running-mean coast-normal profile smoothing (must be odd)
Definition simulation.h:504
This file contains global definitions for CoastalME.
T tMin(T a, T b)
Definition cme.h:1175
double const TOLERANCE
Definition cme.h:725
int const SAVGOL_POLYNOMIAL_MAX_ORDER
Definition cme.h:388
string const ERR
Definition cme.h:805
bool bFPIsEqual(const T d1, const T d2, const T dEpsilon)
Definition cme.h:1213
T tMax(T a, T b)
Definition cme.h:1162
int const SOUTH
Definition cme.h:403
int const EAST
Definition cme.h:401
T tAbs(T a)
Definition cme.h:1187
int const NORTH
Definition cme.h:399
int const WEST
Definition cme.h:405
Contains CGeomLine definitions.
Contains CSimulation definitions.
double Matrix[SAVGOL_POLYNOMIAL_MAX_ORDER+2][SAVGOL_POLYNOMIAL_MAX_ORDER+2]