CoastalME (Coastal Modelling Environment)
Simulates the long-term behaviour of complex coastlines
Loading...
Searching...
No Matches
locate_cliff_toe.cpp
Go to the documentation of this file.
1
13
14/* ==============================================================================================================================
15
16 This file is part of CoastalME, the Coastal Modelling Environment.
17
18 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.
19
20 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.
21
22 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.
23
24==============================================================================================================================*/
25#include <assert.h>
26
27#include <cmath>
28using std::sqrt;
29
30#include <cfloat>
31
32#include <cstdio>
33using std::size_t;
34
35#include <stdint.h>
36
37#include <sstream>
38using std::stringstream;
39
40#include <algorithm>
41using std::max;
42using std::min;
43
44#include <utility>
45using std::make_pair;
46using std::pair;
47
48#include "cme.h"
49#include "cell.h"
50#include "raster_grid.h"
51#include "simulation.h"
52#include "2di_point.h"
53#include "line.h"
54
55/*===============================================================================================================================
57===============================================================================================================================*/
59{
60 // First step: calculate slope at every cell throughout the grid
66
67 return RTN_OK;
68}
69
70/*===============================================================================================================================
72===============================================================================================================================*/
74{
75 for (int nX = 0; nX < m_nXGridSize; nX++)
76 {
77 for (int nY = 0; nY < m_nYGridSize; nY++)
78 {
79 // Now look at surounding cells
80 if ((nX > 0) && (nX < m_nXGridSize - 1) && (nY > 0) && (nY < m_nYGridSize - 1))
81 {
82 double const dElevLeft = m_pRasterGrid->m_Cell[nX - 1][nY].dGetSedimentTopElev();
83 double const dElevRight = m_pRasterGrid->m_Cell[nX + 1][nY].dGetSedimentTopElev();
84 double const dElevUp = m_pRasterGrid->m_Cell[nX][nY - 1].dGetSedimentTopElev();
85 double const dElevDown = m_pRasterGrid->m_Cell[nX][nY + 1].dGetSedimentTopElev();
86
87 // Calculate slope using finite difference method
88 double const dSlopeX = (dElevRight - dElevLeft) / (2.0 * m_dCellSide);
89 double const dSlopeY = (dElevDown - dElevUp) / (2.0 * m_dCellSide);
90 double const dSlope = sqrt(dSlopeX * dSlopeX + dSlopeY * dSlopeY);
91 m_pRasterGrid->m_Cell[nX][nY].SetSlope(dSlope);
92 }
93 }
94 }
95}
96
97/*===============================================================================================================================
99===============================================================================================================================*/
101{
102 for (int nX = 0; nX < m_nXGridSize; nX++)
103 {
104 for (int nY = 0; nY < m_nYGridSize; nY++)
105 {
106 double const dSlope = m_pRasterGrid->m_Cell[nX][nY].dGetSlope();
107 if (dSlope >= m_dCliffSlopeLimit)
108 {
109 m_pRasterGrid->m_Cell[nX][nY].SetAsCliff(true);
110 }
111 }
112 }
113}
114/*===============================================================================================================================
116===============================================================================================================================*/
117void CSimulation::nRemoveSmallCliffIslands(int const dMinCliffCellThreshold)
118{
119 // unsigned int m_nXGridSize = static_cast<unsigned int>(m_nXGridSize);
120 // unsigned int m_nYGridSize = static_cast<unsigned int>(m_nYGridSize);
121
122 // Create a 2D array to track which cells have been visited during flood fill
123 vector<vector<bool>> bVisited(static_cast<unsigned int>(m_nXGridSize), vector<bool>(static_cast<unsigned int>(m_nYGridSize), false));
124
125 // Vector to store cells that belong to small cliff islands to be removed
126 vector<pair<int, int>> VSmallIslandCells;
127
128 // Loop through all cells to find unvisited cliff cells
129 for (unsigned int nX = 0; nX < static_cast<unsigned int>(m_nXGridSize); nX++)
130 {
131 for (unsigned int nY = 0; nY < static_cast<unsigned int>(m_nYGridSize); nY++)
132 {
133 // Check if this is an unvisited cliff cell
134 if ((! bVisited[nX][nY]) && m_pRasterGrid->m_Cell[nX][nY].bIsCliff())
135 {
136 // Found the start of a new cliff region - use flood fill to find all connected cliff cells
137 vector<pair<int, int>> VCurrentCliffRegion;
138
139 // Stack for iterative flood fill algorithm
140 vector<pair<int, int>> VStack;
141 VStack.push_back(make_pair(nX, nY));
142
143 // Flood fill to find all connected cliff cells
144 while (! VStack.empty())
145 {
146 pair<int, int> const currentCell = VStack.back();
147 VStack.pop_back();
148
149 size_t const nCurX = static_cast<size_t>(currentCell.first);
150 size_t const nCurY = static_cast<size_t>(currentCell.second);
151
152 // Skip if already visited or out of bounds
153 if (nCurX >= static_cast<unsigned int>(m_nXGridSize) ||
154 nCurY >= static_cast<unsigned int>(m_nYGridSize) || bVisited[nCurX][nCurY] ||
155 (! m_pRasterGrid->m_Cell[nCurX][nCurY].bIsCliff()))
156 {
157 continue;
158 }
159
160 // Mark as visited and add to current cliff region
161 bVisited[nCurX][nCurY] = true;
162 VCurrentCliffRegion.push_back(make_pair(nCurX, nCurY));
163
164 // Add neighboring cells to stack (8-connectivity: N, NE, E, SE, S, SW, W, NW)
165 VStack.push_back(make_pair(nCurX - 1, nCurY)); // North
166 VStack.push_back(make_pair(nCurX - 1, nCurY + 1)); // Northeast
167 VStack.push_back(make_pair(nCurX, nCurY + 1)); // East
168 VStack.push_back(make_pair(nCurX + 1, nCurY + 1)); // Southeast
169 VStack.push_back(make_pair(nCurX + 1, nCurY)); // South
170 VStack.push_back(make_pair(nCurX + 1, nCurY - 1)); // Southwest
171 VStack.push_back(make_pair(nCurX, nCurY - 1)); // West
172 VStack.push_back(make_pair(nCurX - 1, nCurY - 1)); // Northwest
173 }
174
175 // Calculate area of this cliff region (number of cells * cell area)
176 int const dCliffRegionArea = static_cast<int>(VCurrentCliffRegion.size());
177
178 // If area is below threshold, mark all cells in this region for removal
179 if (dCliffRegionArea < dMinCliffCellThreshold)
180 {
181 VSmallIslandCells.insert(VSmallIslandCells.end(), VCurrentCliffRegion.begin(), VCurrentCliffRegion.end());
182 }
183 }
184 }
185 }
186
187 // Remove cliff designation from all small island cells
188 for (const auto &cell : VSmallIslandCells)
189 {
190 m_pRasterGrid->m_Cell[cell.first][cell.second].SetAsCliff(false);
191 }
192}
193
194/*===============================================================================================================================
196===============================================================================================================================*/
198{
199 // Clear previous cliff edges
200 m_VCliffEdge.clear();
201
202 // Find all possible cliff edge start points by scanning for cliff/non-cliff transitions
203 vector<CGeom2DIPoint> V2DIPossibleStartCell;
204 vector<bool> VbPossibleStartCellHandedness;
205 vector<int> VnSearchDirection;
206
207 // Scan all cells to find cliff toe edges by checking elevation patterns
208 for (int nX = 2; nX < m_nXGridSize - 2; nX++)
209 {
210 for (int nY = 2; nY < m_nYGridSize - 2; nY++)
211 {
212 if (m_pRasterGrid->m_Cell[nX][nY].bIsCliff())
213 {
214 // East direction (check if this is a seaward-facing cliff toe)
215 if (! m_pRasterGrid->m_Cell[nX][nY + 1].bIsCliff())
216 {
217 V2DIPossibleStartCell.push_back(CGeom2DIPoint(nX, nY));
218 VbPossibleStartCellHandedness.push_back(true);
219 VnSearchDirection.push_back(EAST);
220 }
221
222 // South direction
223 if (! m_pRasterGrid->m_Cell[nX + 1][nY].bIsCliff())
224 {
225 V2DIPossibleStartCell.push_back(CGeom2DIPoint(nX, nY));
226 VbPossibleStartCellHandedness.push_back(true);
227 VnSearchDirection.push_back(SOUTH);
228 }
229
230 // West direction
231 if (! m_pRasterGrid->m_Cell[nX][nY - 1].bIsCliff())
232 {
233 V2DIPossibleStartCell.push_back(CGeom2DIPoint(nX, nY));
234 VbPossibleStartCellHandedness.push_back(true);
235 VnSearchDirection.push_back(WEST);
236 }
237
238 // North direction
239 if (! m_pRasterGrid->m_Cell[nX - 1][nY].bIsCliff())
240 {
241 V2DIPossibleStartCell.push_back(CGeom2DIPoint(nX, nY));
242 VbPossibleStartCellHandedness.push_back(true);
243 VnSearchDirection.push_back(NORTH);
244 }
245 }
246 }
247 }
248
249 // Create a 2D array to track which cells have been used in cliff edge tracing
250 vector<vector<bool>> bUsedInCliffTrace(m_nXGridSize, vector<bool>(m_nYGridSize, false));
251
252 int nCliffEdgesTraced = 0;
253
254 // For each possible start point, attempt to trace a cliff edge
255 for (size_t nStartPoint = 0; nStartPoint < V2DIPossibleStartCell.size(); nStartPoint++)
256 {
257 int const nXStart = V2DIPossibleStartCell[nStartPoint].nGetX();
258 int const nYStart = V2DIPossibleStartCell[nStartPoint].nGetY();
259
260 // Skip if this cell has already been used in another cliff trace
261 if (bUsedInCliffTrace[nXStart][nYStart])
262 {
263 continue;
264 }
265
266 // Begin cliff edge tracing using wall following algorithm
267 vector<CGeom2DIPoint> VCliffEdge;
268 int nSearchDirection = VnSearchDirection[nStartPoint];
269
270 int nX = nXStart;
271 int nY = nYStart;
272 int nLength = 0;
273 const int nMaxLength = m_nXGridSize * m_nYGridSize; // Safety limit
274
275 do
276 {
277 // Add current point to cliff edge
278 VCliffEdge.push_back(CGeom2DIPoint(nX, nY));
279 bUsedInCliffTrace[nX][nY] = true;
280 nLength++;
281
282 // Find next cell using wall following algorithm (right-hand rule)
283 int nXSeaward;
284 int nYSeaward;
285 int nXStraightOn;
286 int nYStraightOn;
287 int nXAntiSeaward, nYAntiSeaward, nXGoBack, nYGoBack;
288
289 // Calculate candidate positions based on search direction
290 switch (nSearchDirection)
291 {
292 case NORTH:
293 nXSeaward = nX + 1;
294 nYSeaward = nY; // Right (East)
295 nXStraightOn = nX;
296 nYStraightOn = nY - 1; // Straight (North)
297 nXAntiSeaward = nX - 1;
298 nYAntiSeaward = nY; // Left (West)
299 nXGoBack = nX;
300 nYGoBack = nY + 1; // Back (South)
301
302 break;
303
304 case EAST:
305 nXSeaward = nX;
306 nYSeaward = nY + 1; // Right (South)
307 nXStraightOn = nX + 1;
308 nYStraightOn = nY; // Straight (East)
309 nXAntiSeaward = nX;
310 nYAntiSeaward = nY - 1; // Left (North)
311 nXGoBack = nX - 1;
312 nYGoBack = nY; // Back (West)
313
314 break;
315
316 case SOUTH:
317 nXSeaward = nX - 1;
318 nYSeaward = nY; // Right (West)
319 nXStraightOn = nX;
320 nYStraightOn = nY + 1; // Straight (South)
321 nXAntiSeaward = nX + 1;
322 nYAntiSeaward = nY; // Left (East)
323 nXGoBack = nX;
324 nYGoBack = nY - 1; // Back (North)
325
326 break;
327
328 case WEST:
329 nXSeaward = nX;
330 nYSeaward = nY - 1; // Right (North)
331 nXStraightOn = nX - 1;
332 nYStraightOn = nY; // Straight (West)
333 nXAntiSeaward = nX;
334 nYAntiSeaward = nY + 1; // Left (South)
335 nXGoBack = nX + 1;
336 nYGoBack = nY; // Back (East)
337
338 break;
339
340 default:
341 nXSeaward = nXStraightOn = nXAntiSeaward = nXGoBack = nX;
342 nYSeaward = nYStraightOn = nYAntiSeaward = nYGoBack = nY;
343
344 break;
345 }
346
347 // Try to move using wall following priority: seaward, straight, anti-seaward, back
348 bool bFoundNextCell = false;
349
350 // 1. Try seaward (right turn)
351 if (bIsWithinValidGrid(nXSeaward, nYSeaward) && m_pRasterGrid->m_Cell[nXSeaward][nYSeaward].bIsCliff())
352 {
353 nX = nXSeaward;
354 nY = nYSeaward;
355
356 // Update search direction (turn right)
357 switch (nSearchDirection)
358 {
359 case NORTH:
360 nSearchDirection = EAST;
361 break;
362
363 case EAST:
364 nSearchDirection = SOUTH;
365 break;
366
367 case SOUTH:
368 nSearchDirection = WEST;
369 break;
370
371 case WEST:
372 nSearchDirection = NORTH;
373 break;
374 }
375
376 bFoundNextCell = true;
377 }
378
379 // 2. Try straight ahead
380 else if (bIsWithinValidGrid(nXStraightOn, nYStraightOn) && m_pRasterGrid->m_Cell[nXStraightOn][nYStraightOn].bIsCliff())
381 {
382 nX = nXStraightOn;
383 nY = nYStraightOn;
384
385 // Direction stays the same
386 bFoundNextCell = true;
387 }
388
389 // 3. Try anti-seaward (left turn)
390 else if (bIsWithinValidGrid(nXAntiSeaward, nYAntiSeaward) && m_pRasterGrid->m_Cell[nXAntiSeaward][nYAntiSeaward].bIsCliff())
391 {
392 nX = nXAntiSeaward;
393 nY = nYAntiSeaward;
394
395 // Update search direction (turn left)
396 switch (nSearchDirection)
397 {
398 case NORTH:
399 nSearchDirection = WEST;
400 break;
401
402 case EAST:
403 nSearchDirection = NORTH;
404 break;
405
406 case SOUTH:
407 nSearchDirection = EAST;
408 break;
409
410 case WEST:
411 nSearchDirection = SOUTH;
412 break;
413 }
414
415 bFoundNextCell = true;
416 }
417
418 // 4. Try going back (U-turn)
419 else if (bIsWithinValidGrid(nXGoBack, nYGoBack) && m_pRasterGrid->m_Cell[nXGoBack][nYGoBack].bIsCliff())
420 {
421 nX = nXGoBack;
422 nY = nYGoBack;
423
424 // Update search direction (U-turn)
425 nSearchDirection = nGetOppositeDirection(nSearchDirection);
426 bFoundNextCell = true;
427 }
428
429 if (! bFoundNextCell)
430 {
431 break; // No valid next cell found, end this cliff edge trace
432 }
433
434 } while ((nX != nXStart || nY != nYStart) && nLength < nMaxLength);
435
436 // Only keep cliff edges that have a reasonable length
437 if (VCliffEdge.size() > 2)
438 {
439 nCliffEdgesTraced++;
440
441 // Convert grid coordinates to external CRS for smoothing
442 CGeomLine CliffEdgeExtCRS;
443 for (const auto &point : VCliffEdge)
444 {
445 CliffEdgeExtCRS.Append(dGridCentroidXToExtCRSX(point.nGetX()), dGridCentroidYToExtCRSY(point.nGetY()));
446 bUsedInCliffTrace[point.nGetX()][point.nGetY()] = true;
447 }
448
449 // Apply cliff edge specific smoothing
451 CliffEdgeExtCRS = LSmoothCoastRunningMean(&CliffEdgeExtCRS);
452
454 CliffEdgeExtCRS = LSmoothCoastSavitzkyGolay(&CliffEdgeExtCRS, 0, 0);
455
456 // Store the smoothed cliff edge in external CRS
457 m_VCliffEdge.push_back(CliffEdgeExtCRS);
458 }
459 }
460}
461
462/*===============================================================================================================================
464===============================================================================================================================*/
466{
467 vector<CGeomLine> ValidatedCliffEdges;
468
469 // Process each traced cliff edge
470 for (size_t nEdge = 0; nEdge < m_VCliffEdge.size(); nEdge++)
471 {
472 CGeomLine &CliffEdge = m_VCliffEdge[nEdge];
473
474 // Try validating in forward direction first
475 CGeomLine const ForwardValidated = nValidateCliffToeDirection(CliffEdge, false);
476
477 // If we got a very short result (broke early), try reverse direction
478 CGeomLine ReverseValidated;
479 if (ForwardValidated.nGetSize() < CliffEdge.nGetSize() * 0.2)
480 {
481 ReverseValidated = nValidateCliffToeDirection(CliffEdge, true);
482 }
483
484 // Use whichever result is longer
485 CGeomLine BestValidated;
486 if (ReverseValidated.nGetSize() > ForwardValidated.nGetSize())
487 {
488 BestValidated = ReverseValidated;
489 }
490 else
491 {
492 BestValidated = ForwardValidated;
493 }
494
495 // Only keep edges that have a reasonable length after validation
496 if (BestValidated.nGetSize() > 2)
497 {
498 ValidatedCliffEdges.push_back(BestValidated);
499 }
500 }
501
502 // Replace the original cliff edges with the validated ones
503 m_VCliffEdge = ValidatedCliffEdges;
504}
505
506
507/*===============================================================================================================================
509===============================================================================================================================*/
511{
512 CGeomLine ValidatedEdge;
513
514 int nConsecutiveFailures = 0;
515 int const nMaxConsecutiveFailures = 2;
516 int const nSize = CliffEdge.nGetSize();
517
518 // Check each point along the cliff edge
519 for (int i = 0; i < nSize - 1; i++)
520 {
521 // Determine which point to process based on direction
522 int const nPoint = bReverse ? (nSize - 1 - i) : i;
523 int const nNextPoint = bReverse ? (nSize - 2 - i) : (i + 1);
524
525 // Skip if we've gone beyond bounds
526 if (nNextPoint < 0 || nNextPoint >= nSize)
527 continue;
528
529 // Get current and next point in grid coordinates
530 int nX = static_cast<int>((CliffEdge.dGetXAt(nPoint) - m_dGeoTransform[0]) / m_dGeoTransform[1]);
531 int nY = static_cast<int>((CliffEdge.dGetYAt(nPoint) - m_dGeoTransform[3]) / m_dGeoTransform[5]);
532
533 int nNextX = static_cast<int>((CliffEdge.dGetXAt(nNextPoint) - m_dGeoTransform[0]) / m_dGeoTransform[1]);
534 int nNextY = static_cast<int>((CliffEdge.dGetYAt(nNextPoint) - m_dGeoTransform[3]) / m_dGeoTransform[5]);
535
536 // Ensure coordinates are within grid bounds
537 nX = max(0, min(m_nXGridSize - 1, nX));
538 nY = max(0, min(m_nYGridSize - 1, nY));
539 nNextX = max(0, min(m_nXGridSize - 1, nNextX));
540 nNextY = max(0, min(m_nYGridSize - 1, nNextY));
541
542 // Calculate direction of travel
543 int const nDirX = nNextX - nX;
544 int const nDirY = nNextY - nY;
545
546 // Get perpendicular directions (90 degrees to travel direction)
547 int const nLeftX = nX - nDirY; // Rotate direction 90 degrees counter-clockwise
548 int const nLeftY = nY + nDirX;
549 int const nRightX = nX + nDirY; // Rotate direction 90 degrees clockwise
550 int const nRightY = nY - nDirX;
551
552 bool bIsValidToe = true;
553
554 // Check if perpendicular cells are within bounds
555 if (bIsWithinValidGrid(nLeftX, nLeftY) && bIsWithinValidGrid(nRightX, nRightY))
556 {
557 bool const bLeftIsCliff = m_pRasterGrid->m_Cell[nLeftX][nLeftY].bIsCliff();
558 bool const bRightIsCliff = m_pRasterGrid->m_Cell[nRightX][nRightY].bIsCliff();
559
560 // One should be cliff and one should be not cliff for a valid cliff edge
561 if (bLeftIsCliff != bRightIsCliff)
562 {
563 // Get the elevation of these two adjacent cells
564 double const dLeftElev = m_pRasterGrid->m_Cell[nLeftX][nLeftY].dGetSedimentTopElev();
565 double const dRightElev = m_pRasterGrid->m_Cell[nRightX][nRightY].dGetSedimentTopElev();
566
567 // Determine which is the cliff side and which is the non-cliff side
568 double dCliffElev;
569 double dNonCliffElev;
570 if (bLeftIsCliff)
571 {
572 dCliffElev = dLeftElev;
573 dNonCliffElev = dRightElev;
574 }
575 else
576 {
577 dCliffElev = dRightElev;
578 dNonCliffElev = dLeftElev;
579 }
580
581 // If the non-cliff cell is higher than the cliff cell, this is not the toe
582 if (dNonCliffElev > dCliffElev)
583 {
584 bIsValidToe = false;
585 }
586 }
587 }
588
589 if (bIsValidToe)
590 {
591 // Reset consecutive failure counter
592 nConsecutiveFailures = 0;
593
594 // Add this point to the validated edge
595 ValidatedEdge.Append(CliffEdge.dGetXAt(nPoint), CliffEdge.dGetYAt(nPoint));
596 }
597 else
598 {
599 // Increment consecutive failure counter
600 nConsecutiveFailures++;
601
602 // If we haven't hit the threshold yet, still add the point
603 if (nConsecutiveFailures < nMaxConsecutiveFailures)
604 {
605 ValidatedEdge.Append(CliffEdge.dGetXAt(nPoint), CliffEdge.dGetYAt(nPoint));
606 }
607 else
608 {
609 // Too many consecutive failures - truncate here
610 break;
611 }
612 }
613 }
614
615 return ValidatedEdge;
616}
Contains CGeom2DIPoint definitions.
Contains CGeomCell definitions.
void Append(CGeom2DPoint const *)
Appends a point to this 2D shape.
Definition 2d_shape.cpp:67
int nGetSize(void) const
Definition 2d_shape.cpp:56
Geometry class used to represent 2D point objects with integer coordinates.
Definition 2di_point.h:29
Geometry class used to represent 2D vector line objects.
Definition line.h:32
double dGetYAt(int const)
Returns the Y value at a given place in the line.
Definition line.cpp:64
double dGetXAt(int const)
Returns the X value at a given place in the line.
Definition line.cpp:58
CGeomLine LSmoothCoastRunningMean(CGeomLine *) const
Does running-mean smoothing of a CGeomLine coastline vector (is in external CRS coordinates)
CGeomRasterGrid * m_pRasterGrid
Pointer to the raster grid object.
int m_nXGridSize
The size of the grid in the x direction.
Definition simulation.h:457
static int nGetOppositeDirection(int const)
Returns the opposite direction.
void nCalcSlopeAtAllCells(void)
int m_nYGridSize
The size of the grid in the y direction.
Definition simulation.h:460
int nLocateCliffToe(void)
double m_dGeoTransform[6]
GDAL geotransformation info (see http://www.gdal.org/classGDALDataset.html)
Definition simulation.h:697
vector< CGeomLine > m_VCliffEdge
The traced cliff edge lines (in external CRS)
void nTraceSeawardCliffEdge(void)
int m_nCliffEdgeSmooth
Which method to use for cliff edge smoothing.
Definition simulation.h:475
double dGridCentroidYToExtCRSY(int const) const
Given the integer Y-axis ordinate of a cell in the raster grid CRS, returns the external CRS Y-axis o...
Definition gis_utils.cpp:78
void nLocateCliffCell(void)
CGeomLine nValidateCliffToeDirection(CGeomLine &CliffEdge, bool bReverse)
void nRemoveSmallCliffIslands(int const)
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
double dGridCentroidXToExtCRSX(int const) const
Definition gis_utils.cpp:68
double m_dCliffSlopeLimit
Slope limit for cliff toe detection.
Definition simulation.h:484
double m_dCellSide
Length of a cell side (in external CRS units)
Definition simulation.h:658
void nValidateCliffToeEdges(void)
This file contains global definitions for CoastalME.
int const SMOOTH_SAVITZKY_GOLAY
Definition cme.h:783
int const SMOOTH_RUNNING_MEAN
Definition cme.h:782
int const SOUTH
Definition cme.h:501
int const EAST
Definition cme.h:499
int const RTN_OK
Definition cme.h:694
int const NORTH
Definition cme.h:497
int const WEST
Definition cme.h:503
Contains CGeomLine definitions.
Contains CGeomRasterGrid definitions.
Contains CSimulation definitions.