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