CoastalME (Coastal Modelling Environment)
Simulates the long-term behaviour of complex coastlines
Loading...
Searching...
No Matches
create_polygons.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 <iostream>
27using std::endl;
28
29// #include <string>
30// using std::to_string;
31
32#include <stack>
33using std::stack;
34
35// #include <algorithm>
36// using std::remove;
37
38#include "cme.h"
39#include "simulation.h"
40#include "coast.h"
41#include "2d_point.h"
42#include "2di_point.h"
43
44//===============================================================================================================================
46//===============================================================================================================================
48{
49 // Global polygon count TODO 044
51
52 // Do this for each coast
53 for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
54 {
55 int nNode = -1;
56 int nNextProfile = -1;
57 int nPolygon = -1;
58
59 for (int i = 0; i < static_cast<int>(m_pVCoastPolygon.size()); i++)
60 delete m_pVCoastPolygon[i];
61
62 m_pVCoastPolygon.clear();
63
64 // Do this for every point on the coastline (except the last point)
65 int const nCoastSize = m_VCoast[nCoast].nGetCoastlineSize();
66
67 for (int nCoastPoint = 0; nCoastPoint < nCoastSize - 1; nCoastPoint++)
68 {
69 if (!m_VCoast[nCoast].bIsProfileAtCoastPoint(nCoastPoint))
70 continue;
71
72 // OK, this coast point is the start of a coastline-normal profile
73 CGeomProfile* pThisProfile = m_VCoast[nCoast].pGetProfileAtCoastPoint(nCoastPoint);
74
75 if (pThisProfile->bOKIncStartAndEndOfCoast())
76 {
77 // This profile is OK, so we will start a polygon here and extend it down-coast (i.e. along the coast in the direction of increasing coastline point numbers)
78 int const nThisProfile = pThisProfile->nGetCoastID();
79
80 // This will be the coast ID number of the polygon, and also the polygon's along-coast sequence
81 nPolygon++;
82
83 // Now get a pointer to the next (down-coast) profile
84 CGeomProfile* pNextProfile = pThisProfile->pGetDownCoastAdjacentProfile();
85
86 bool bNextProfileIsOK = false;
87
88 do
89 {
90 // if (pNextProfile == NULL) // TODO THIS GIVES CPPCHECK ERROR
91 // {
92 // LogStream << m_ulIter << ": nThisProfile = " << nThisProfile << " invalid down-coast adjacent profile, trying next down-coast adjacent profile" << endl;
93 //
94 // // Try the next-after-next profile
95 // CGeomProfile* pNextNextProfile = pNextProfile->pGetDownCoastAdjacentProfile();
96 // pNextProfile = pNextNextProfile;
97 // continue;
98 // }
99
100 // Get the ID of the next (down-coast) profile
101 nNextProfile = pNextProfile->nGetCoastID();
102
103 // Is the next profile OK?
104 bNextProfileIsOK = pNextProfile->bOKIncStartAndEndOfCoast();
105
106 if (!bNextProfileIsOK)
107 {
108 // Nope, the next profile is not OK
109 // LogStream << m_ulIter << ": down-coast adjacent profile = " << nNextProfile << " is not OK" << endl;
110
111 // So try the following profile
112 CGeomProfile* pNextNextProfile = pNextProfile->pGetDownCoastAdjacentProfile();
113 pNextProfile = pNextNextProfile;
114 }
115
116 } while (!bNextProfileIsOK);
117
118 // LogStream << "Profile " << pNextProfile->nGetCoastID() << " is OK" << endl;
119
120 // Get the coast point at which this next profile starts
121 int const nNextProfileCoastPoint = pNextProfile->nGetCoastPoint();
122
123 // Calculate half the along-coast distance (in coast points) between this profile and the next (i.e. down-coast) profile
124 int const nDist = (nNextProfileCoastPoint - nCoastPoint) / 2;
125
126 // OK, set the node point in the coast object. We do this now, instead of earlier on, since some profiles (i.e. polygon boundaries) may have been marked as invalid
127 int const nNodePoint = nCoastPoint + nDist;
128 m_VCoast[nCoast].SetPolygonNode(nNodePoint, ++nNode);
129
130 // Get the grid CRS coordinates of the coast node
131 CGeom2DIPoint const PtiNode = *m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nNodePoint);
132
133 // // DEBUG CODE ===================
134 // if ((m_ulIter == 18) && (nThisProfile == 29))
135 // std::cerr << endl;
136 // // DEBUG CODE ===================
137
138 // Get some defaults (assuming for now that this polygon is not approximately triangular i.e. both normals do not meet)
139 int nNextProfileEnd = pNextProfile->nGetProfileSize() - 1;
140 int nThisProfileEnd = pThisProfile->nGetProfileSize() - 1;
141 bool bMeetsAtAPoint = false;
142 CGeom2DPoint PtCoastwardTip;
143
144 // // DEBUG CODE =============================================================================================
145 // CGeom2DPoint PtNextEndTmp = *pNextProfile->pPtGetPointInProfile(nNextProfileEnd);
146 // double dXTmp = dExtCRSXToGridX(PtNextEndTmp.dGetX());
147 // double dYTmp = dExtCRSYToGridY(PtNextEndTmp.dGetY());
148 // assert(bIsWithinValidGrid(dXTmp, dYTmp));
149 //
150 // CGeom2DPoint PtThisEndTmp = *pThisProfile->pPtGetPointInProfile(nThisProfileEnd);
151 // dXTmp = dExtCRSXToGridX(PtThisEndTmp.dGetX());
152 // dYTmp = dExtCRSYToGridY(PtThisEndTmp.dGetY());
153 // assert(bIsWithinValidGrid(dXTmp, dYTmp));
154 // // DEBUG CODE =============================================================================================
155
156 // Now check to see if the two normals do meet i.e. if they are coincident
157 if (pThisProfile->bFindProfileInCoincidentProfiles(nNextProfile))
158 {
159 // Yes they do meet
160 bMeetsAtAPoint = true;
161 int nTmpThisProfileEnd;
162 int nTmpNextProfileEnd;
163
164 // Find the most coastward point at which this normal and the previous normal touch. If they do not touch, the polygon requires a 'joining line'
165 pThisProfile->GetMostCoastwardSharedLineSegment(nNextProfile, nTmpThisProfileEnd, nTmpNextProfileEnd);
166
167 if (nTmpThisProfileEnd == -1)
168 {
169 LogStream << m_ulIter << ": " << ERR << "profile " << nNextProfile << " should be coincident with profile " << nThisProfile << " but was not found" << endl;
171 }
172
173 // Safety check: make sure that nThisProfileEnd is no bigger than pThisProfile->nGetProfileSize()-1, and the same for nNextProfileEnd
174 nThisProfileEnd = tMin(nThisProfileEnd, nTmpThisProfileEnd);
175 nNextProfileEnd = tMin(nNextProfileEnd, nTmpNextProfileEnd);
176
177 PtCoastwardTip = *pThisProfile->pPtGetPointInProfile(nThisProfileEnd);
178 }
179
180 // Create the vector in which to store the polygon's boundary (external CRS). Note that these points are not in sequence
181 vector<CGeom2DPoint> PtVBoundary;
182
183 // Start appending points: begin by appending the points in this normal, in reverse order
184 for (int i = nThisProfileEnd; i >= 0; i--)
185 {
186 CGeom2DPoint const PtThis = *pThisProfile->pPtGetPointInProfile(i);
187 PtVBoundary.push_back(PtThis);
188 }
189
190 // Next add coast points: from the start point of this normal, moving down-coast as far as the down-coast norma
191 for (int i = nCoastPoint; i <= nNextProfileCoastPoint; i++)
192 {
193 CGeom2DPoint const PtThis = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(i);
194 PtVBoundary.push_back(PtThis);
195 }
196
197 // Append the points in the down-coast (next) normal
198 for (int i = 0; i <= nNextProfileEnd; i++)
199 {
200 CGeom2DPoint const PtThis = *pNextProfile->pPtGetPointInProfile(i);
201 PtVBoundary.push_back(PtThis);
202 }
203
204 // Finally, append the end point of this normal
205 CGeom2DPoint const PtThis = *pThisProfile->pPtGetPointInProfile(nThisProfileEnd);
206 PtVBoundary.push_back(PtThis);
207
208 // Now identify the 'anti-node', this is the seaward point 'opposite' the polygon's coastal node
209 CGeom2DIPoint PtiAntiNode;
210
211 if (bMeetsAtAPoint)
212 PtiAntiNode = PtiExtCRSToGridRound(&PtCoastwardTip);
213
214 else
215 {
216 CGeom2DPoint const PtAvg = PtAverage(pThisProfile->pPtGetPointInProfile(nThisProfileEnd), pNextProfile->pPtGetPointInProfile(nNextProfileEnd));
217 PtiAntiNode = PtiExtCRSToGridRound(&PtAvg);
218 }
219
220 // Is this a start-of-coast or an end-of-coast polygon?
221 bool bStartCoast = false;
222 bool bEndCoast = false;
223
224 if (pThisProfile->bStartOfCoast())
225 bStartCoast = true;
226
227 if (pNextProfile->bEndOfCoast())
228 bEndCoast = true;
229
230 // Create the coast polygon object and get a pointer to it. TODO 044 the first parameter (global ID) will need to change when considering multiple coasts
231 CGeomCoastPolygon* pPolygon = m_VCoast[nCoast].pPolyCreatePolygon(nThisProfile, nPolygon, nNodePoint, &PtiNode, &PtiAntiNode, nThisProfile, nNextProfile, &PtVBoundary, nThisProfileEnd + 1, nNextProfileEnd + 1, bStartCoast, bEndCoast);
232
233 // And store this pointer for simulation-wide access, in along-coast sequence
234 m_pVCoastPolygon.push_back(pPolygon);
235
236 // Save the profile-end vertices (but omit the last one if the profiles meet at a point)
237 pPolygon->AppendVertex(pThisProfile->pPtiGetStartPoint());
238 pPolygon->AppendVertex(pThisProfile->pPtiGetEndPoint());
239 pPolygon->AppendVertex(pNextProfile->pPtiGetStartPoint());
240
241 if (!bMeetsAtAPoint)
242 pPolygon->AppendVertex(pNextProfile->pPtiGetEndPoint());
243
244 // // DEBUG CODE =================================================================================
245 // LogStream << m_ulIter << ": vertices for polygon = " << nPolygon << " (m_nNumPolygonGlobal = " << m_nNumPolygonGlobal << ")" << endl;
246 // for (int n = 0; n < pPolygon->nGetNumVertices(); n++)
247 // LogStream << "[" << pPolygon->PtiGetVertex(n).nGetX() << "][" << pPolygon->PtiGetVertex(n).nGetY() << "]\t";
248 // LogStream << endl;
249 // // DEBUG CODE =================================================================================
250
251 // TEST
252 assert(nPolygon < m_VCoast[nCoast].nGetNumPolygons());
253
254 // Now rasterize the polygon boundaries: first, the coastline. This is necessary so that sand/coarse sediment derived from platform erosion of the coast cells is correctly added to the containing polygon's unconsolidated sediment
255 for (int i = nCoastPoint; i <= nNextProfileCoastPoint; i++)
256 {
257 CGeom2DIPoint const PtiToMark = *m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(i);
258 m_pRasterGrid->m_Cell[PtiToMark.nGetX()][PtiToMark.nGetY()].SetCoastAndPolygonID(nCoast, nPolygon);
259 }
260
261 // Do the down-coast normal profile (does the whole length, including any shared line segments. So some cells are marked twice, however this is not a problem)
262 int nCellsInProfile = pNextProfile->nGetNumCellsInProfile();
263
264 for (int i = 0; i < nCellsInProfile; i++)
265 {
266 CGeom2DIPoint const PtiToMark = *pNextProfile->pPtiGetCellInProfile(i);
267 m_pRasterGrid->m_Cell[PtiToMark.nGetX()][PtiToMark.nGetY()].SetCoastAndPolygonID(nCoast, nPolygon);
268 }
269
270 // Do this normal profile (again does the whole length, including any shared line segments)
271 nCellsInProfile = pThisProfile->nGetNumCellsInProfile();
272
273 for (int i = 0; i < nCellsInProfile; i++)
274 {
275 CGeom2DIPoint const PtiToMark = *pThisProfile->pPtiGetCellInProfile(i);
276 m_pRasterGrid->m_Cell[PtiToMark.nGetX()][PtiToMark.nGetY()].SetCoastAndPolygonID(nCoast, nPolygon);
277 }
278
279 // If the polygon doesn't meet at a point at its seaward end, also need to rasterize the 'joining line'
280 if (!bMeetsAtAPoint)
281 {
282 CGeom2DIPoint const PtiDownCoastNormalEnd = *pNextProfile->pPtiGetEndPoint(); // Grid CRS
283 CGeom2DIPoint const PtiUpCoastNormalEnd = *pThisProfile->pPtiGetEndPoint(); // Grid CRS
284
285 RasterizePolygonJoiningLine(nCoast, &PtiUpCoastNormalEnd, &PtiDownCoastNormalEnd, nPolygon);
286
287 // pPolygon->SetNotPointed();
288 }
289
290 // }
291
292 // nNextProfile = nThisProfile;
293 nCoastPoint = nNextProfileCoastPoint - 1;
294
296
297 if (bEndCoast)
298 break;
299 }
300 }
301 }
302
303 return RTN_OK;
304}
305
306//===============================================================================================================================
308//===============================================================================================================================
309void CSimulation::RasterizePolygonJoiningLine(int nCoast, CGeom2DIPoint const* pPt1, CGeom2DIPoint const* pPt2, int const nPoly)
310{
311 // The start point of the line (grid CRS)
312 int const nXStart = pPt1->nGetX();
313 int const nYStart = pPt1->nGetY();
314
315 // The end point of the line (grid CRS)
316 int const nXEnd = pPt2->nGetX();
317 int const nYEnd = pPt2->nGetY();
318
319 // Safety check, in case the two points are identical (can happen due to rounding errors)
320 if ((nXStart == nXEnd) && (nYStart == nYEnd))
321 return;
322
323 // Interpolate between cells by a simple DDA line algorithm, see http://en.wikipedia.org/wiki/Digital_differential_analyzer_(graphics_algorithm) Note that Bresenham's algorithm gave occasional gaps
324 double dXInc = nXEnd - nXStart;
325 double dYInc = nYEnd - nYStart;
326 double const dLength = tMax(tAbs(dXInc), tAbs(dYInc));
327
328 dXInc /= dLength;
329 dYInc /= dLength;
330
331 double dX = nXStart;
332 double dY = nYStart;
333
334 // Process each interpolated point
335 for (int m = 0; m <= nRound(dLength); m++)
336 {
337 int nX = nRound(dX);
338 int nY = nRound(dY);
339
340 // Safety check
341 if (!bIsWithinValidGrid(nX, nY))
342 KeepWithinValidGrid(nXStart, nYStart, nX, nY);
343
344 // TEST
345 assert(nPoly < m_VCoast[0].nGetNumPolygons());
346
347 // Mark this point on the raster grid
348 m_pRasterGrid->m_Cell[nX][nY].SetCoastAndPolygonID(nCoast, nPoly);
349
350 // And increment for next time
351 dX += dXInc;
352 dY += dYInc;
353 }
354}
355
356//===============================================================================================================================
358//===============================================================================================================================
360{
361 // // DEBUG CODE =================================================================================
362 // vector<CGeom2DIPoint> VPtiCentroids;
363 // vector<int> VnID;
364 //
365 // // Do this for each coast
366 // for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
367 // {
368 // // Do this for every coastal polygon
369 // for (int nPoly = 0; nPoly < m_VCoast[nCoast].nGetNumPolygons(); nPoly++)
370 // {
371 // CGeomCoastPolygon* pPolygon = m_VCoast[nCoast].pGetPolygon(nPoly);
372 //
373 // int nPolyID = pPolygon->nGetCoastID();
374 // VnID.push_back(nPolyID);
375 //
376 // CGeom2DIPoint PtiStart = pPolygon->PtiGetFillStartPoint();
377 // VPtiCentroids.push_back(PtiStart);
378 // }
379 // }
380 //
381 // string strOutFile = m_strOutPath;
382 // strOutFile += "00_polygon_flood_fill_start_point_";
383 // strOutFile += to_string(m_ulIter);
384 // strOutFile += ".tif";
385 //
386 // GDALDriver* pDriver = GetGDALDriverManager()->GetDriverByName("gtiff");
387 // GDALDataset* pDataSet = pDriver->Create(strOutFile.c_str(), m_nXGridSize, m_nYGridSize, 1, GDT_Float64, m_papszGDALRasterOptions);
388 // pDataSet->SetProjection(m_strGDALBasementDEMProjection.c_str());
389 // pDataSet->SetGeoTransform(m_dGeoTransform);
390 //
391 // int nn = 0;
392 // double* pdRaster = new double[m_nXGridSize * m_nYGridSize];
393 // for (int nY = 0; nY < m_nYGridSize; nY++)
394 // {
395 // for (int nX = 0; nX < m_nXGridSize; nX++)
396 // {
397 // pdRaster[nn] = INT_NODATA;
398 //
399 // for (int n = 0; n < static_cast<int>(VPtiCentroids.size()); n++)
400 // {
401 // if ((VPtiCentroids[n].nGetX() == nX) && (VPtiCentroids[n].nGetY() == nY))
402 // {
403 // pdRaster[nn] = VnID[n];
404 // LogStream << m_ulIter << ": cell-by-cell fill start point for polygon " << VnID[n] << " is [" << nX << "][" << nY << "]" << endl;
405 // break;
406 // }
407 // }
408 // nn++;
409 // }
410 // }
411 //
412 // GDALRasterBand* pBand = pDataSet->GetRasterBand(1);
413 // pBand->SetNoDataValue(m_dMissingValue);
414 // int nRet = pBand->RasterIO(GF_Write, 0, 0, m_nXGridSize, m_nYGridSize, pdRaster, m_nXGridSize, m_nYGridSize, GDT_Float64, 0, 0, NULL);
415 //
416 // if (nRet == CE_Failure)
417 // LogStream << nRet << endl;
418 //
419 // GDALClose(pDataSet);
420 // delete[] pdRaster;
421 // // DEBUG CODE ===========================================================================================================
422
423 // Do this for each coast
424 for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
425 {
426 // Do this for every coastal polygon, in along-coast sequence
427 int const nPolygons = m_VCoast[nCoast].nGetNumPolygons();
428
429 for (int nPoly = 0; nPoly < nPolygons; nPoly++)
430 {
431 int nCellsInPolygon = 0;
432 double dTotDepth = 0;
433 double dStoredUnconsFine = 0;
434 double dStoredUnconsSand = 0;
435 double dStoredUnconsCoarse = 0;
436 double dStoredConsFine = 0;
437 double dStoredConsSand = 0;
438 double dStoredConsCoarse = 0;
439 double dSedimentInputFine = 0;
440 double dSedimentInputSand = 0;
441 double dSedimentInputCoarse = 0;
442
443 CGeomCoastPolygon* pPolygon = m_VCoast[nCoast].pGetPolygon(nPoly);
444 int const nPolyID = pPolygon->nGetCoastID(); // TODO 044
445
446 // LogStream << m_ulIter << ": in MarkPolygonCells() nPoly = " << nPoly << " nPolyID = " << nPolyID << endl;
447
448 // Create an empty stack
449 stack<CGeom2DIPoint> PtiStack;
450
451 // // Since the polygon's vector boundary does not coincide exactly with the polygon's raster boundary, and the point-in-polygon check gives an indeterminate result if the point is exactly on the polygon's boundary, for safety we must construct a vector 'inner buffer' which is smaller than, and inside, the vector boundary TODO *** STILL NEEDED?
452 // int nHand = m_VCoast[nCoast].nGetSeaHandedness();
453 // int nSize = pPolygon->nGetBoundarySize();
454 // vector<CGeom2DPoint> PtVInnerBuffer;
455 //
456 // for (int i = 0; i < nSize-1; i++)
457 // {
458 // int j = i + 1;
459 // if (i == nSize-2) // We must ignore the duplicated node point
460 // j = 0;
461 //
462 // CGeom2DPoint PtThis = *pPolygon->pPtGetBoundaryPoint(i);
463 // CGeom2DPoint PtNext = *pPolygon->pPtGetBoundaryPoint(j);
464 //
465 // // Safety check
466 // if (PtThis == PtNext)
467 // continue;
468 //
469 // CGeom2DPoint PtBuffer = PtGetPerpendicular(&PtThis, &PtNext, m_dCellSide, nHand);
470 //
471 // PtVInnerBuffer.push_back(PtBuffer);
472 // }
473
474 // // DEBUG CODE ==============================================================================================
475 // LogStream << endl << m_ulIter << ": coast " << nCoast << ", polygon " << nPoly << endl;
476 // LogStream << "Boundary\t\t\tBuffer" << endl;
477 // for (int i = 0; i < pPolygon->nGetBoundarySize()-1; i++)
478 // LogStream << "{" << pPolygon->pPtGetBoundaryPoint(i)->dGetX() << ", " << pPolygon->pPtGetBoundaryPoint(i)->dGetY() << "}\t{" << PtVInnerBuffer[i].dGetX() << ", " << PtVInnerBuffer[i].dGetY() << "}" << endl;
479 // LogStream << endl;
480 // // DEBUG CODE ==============================================================================================
481
482 // Use the centroid as the start point for the cell-by-cell fill procedure
483 CGeom2DIPoint const PtiStart = pPolygon->PtiGetFillStartPoint();
484
485 // // Is the centroid within the inner buffer?
486 // if (! bIsWithinPolygon(&PtStart, &PtVInnerBuffer))
487 // {
488 // // No, it is not: the polygon must be a concave polygon. So keep looking for a point which is definitely inside the polygon, using an alternative method
489 // PtStart = PtFindPointInPolygon(&PtVInnerBuffer, pPolygon->nGetPointInPolygonSearchStartPoint());
490 // }
491 //
492 // // Safety check (PtFindPointInPolygon() returns CGeom2DPoint(DBL_NODATA, DBL_NODATA) if it cannot find a valid start point)
493 // if (bFPIsEqual(PtStart.dGetX(), DBL_NODATA, TOLERANCE))
494 // {
495 // LogStream << m_ulIter << ": " << ERR << "could not find a cell-by-cell fill start point for coast " << nCoast << ", polygon " << nPoly << endl;
496 // break;
497 // }
498
499 // We have a cell-by-cell fill start point which is definitely within the polygon so push this point onto the stack
500 // CGeom2DIPoint PtiStart;
501 // PtiStart.SetX(nRound(PtStart.dGetX())); // Grid CRS
502 // PtiStart.SetY(nRound(PtStart.dGetY())); // Grid CRS
503
504 PtiStack.push(PtiStart);
505
506 // LogStream << m_ulIter << ": filling polygon " << nPoly << " from [" << PtiStart.nGetX() << "][" << PtiStart.nGetY() << "] = {" << dGridCentroidXToExtCRSX(PtiStart.nGetX()) << ", " << dGridCentroidYToExtCRSY(PtiStart.nGetY()) << "}" << endl;
507
508 // Then do the cell-by-cell fill: loop until there are no more cell coordinates on the stack
509 while (!PtiStack.empty())
510 {
511 CGeom2DIPoint const Pti = PtiStack.top();
512 PtiStack.pop();
513
514 int nX = Pti.nGetX();
515 int const nY = Pti.nGetY();
516
517 while ((nX >= 0) && (m_pRasterGrid->m_Cell[nX][nY].nGetPolygonID() == INT_NODATA))
518 nX--;
519
520 nX++;
521
522 bool bSpanAbove = false;
523 bool bSpanBelow = false;
524
525 while ((nX < m_nXGridSize) && (m_pRasterGrid->m_Cell[nX][nY].nGetPolygonID() == INT_NODATA))
526 {
527 // assert(nPolyID < m_VCoast[nCoast].nGetNumPolygons());
528
529 // Mark the cell as being in this polygon and this coast
530 m_pRasterGrid->m_Cell[nX][nY].SetCoastAndPolygonID(nCoast, nPolyID);
531
532 // LogStream << "Marked [" << nX << "][" << nY << "] = {" << dGridCentroidXToExtCRSX(nX) << ", " << dGridCentroidYToExtCRSY(nY) << "}" << endl;
533
534 // Increment the running totals for this polygon
535 // dCliffCollapseErosionFine += m_pRasterGrid->m_Cell[nX][nY].dGetThisIterCliffCollapseErosionFine();
536 // dCliffCollapseErosionSand += m_pRasterGrid->m_Cell[nX][nY].dGetThisIterCliffCollapseErosionSand();
537 // dCliffCollapseErosionCoarse += m_pRasterGrid->m_Cell[nX][nY].dGetThisIterCliffCollapseErosionCoarse();
538 // dCliffCollapseTalusSand += m_pRasterGrid->m_Cell[nX][nY].dGetThisIterCliffCollapseSandTalusDeposition();
539 // dCliffCollapseTalusCoarse += m_pRasterGrid->m_Cell[nX][nY].dGetThisIterCliffCollapseCoarseTalusDeposition();
540
541 // Get the number of the highest layer with non-zero thickness
542 int const nThisLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopNonZeroLayerAboveBasement();
543
544 // Safety check
545 if ((nThisLayer != NO_NONZERO_THICKNESS_LAYERS) && (nThisLayer != INT_NODATA))
546 {
547 // Increment some more running totals for this polygon TODO 066 should this be for ALL layers above the basement?
548 dStoredUnconsFine += m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->dGetFineDepth();
549 dStoredUnconsSand += m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->dGetSandDepth();
550 dStoredUnconsCoarse += m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->dGetCoarseDepth();
551
552 dStoredConsFine += m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetConsolidatedSediment()->dGetFineDepth();
553 dStoredConsSand += m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetConsolidatedSediment()->dGetSandDepth();
554 dStoredConsCoarse += m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetConsolidatedSediment()->dGetCoarseDepth();
555
556 // Add to the start-iteration total of suspended fine sediment within polygons
557 m_dStartIterSuspFineInPolygons += m_pRasterGrid->m_Cell[nX][nY].dGetSuspendedSediment();
558
559 // Add to the total of sediment derived from sediment input events
560 dSedimentInputFine += m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->dGetFineSedimentInputDepth();
561 dSedimentInputSand += m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->dGetSandSedimentInputDepth();
562 dSedimentInputCoarse += m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->dGetCoarseSedimentInputDepth();
563 }
564
565 nCellsInPolygon++;
566 dTotDepth += m_pRasterGrid->m_Cell[nX][nY].dGetSeaDepth();
567
568 if ((!bSpanAbove) && (nY > 0) && (m_pRasterGrid->m_Cell[nX][nY - 1].nGetPolygonID() == INT_NODATA))
569 {
570 PtiStack.push(CGeom2DIPoint(nX, nY - 1));
571 bSpanAbove = true;
572 }
573
574 else if (bSpanAbove && (nY > 0) && (m_pRasterGrid->m_Cell[nX][nY - 1].nGetPolygonID() != INT_NODATA))
575 {
576 bSpanAbove = false;
577 }
578
579 if ((!bSpanBelow) && (nY < m_nYGridSize - 1) && (m_pRasterGrid->m_Cell[nX][nY + 1].nGetPolygonID() == INT_NODATA))
580 {
581 PtiStack.push(CGeom2DIPoint(nX, nY + 1));
582 bSpanBelow = true;
583 }
584
585 else if (bSpanBelow && (nY < m_nYGridSize - 1) && (m_pRasterGrid->m_Cell[nX][nY + 1].nGetPolygonID() != INT_NODATA))
586 {
587 bSpanBelow = false;
588 }
589
590 nX++;
591 }
592 }
593
594 // Store this polygon's stored unconsolidated sediment depths
595 pPolygon->SetPreExistingUnconsFine(dStoredUnconsFine);
596 pPolygon->SetPreExistingUnconsSand(dStoredUnconsSand);
597 pPolygon->SetPreExistingUnconsCoarse(dStoredUnconsCoarse);
598
599 // Store this polygon's values for unconsolidated sediment derived from sediment input event(s)
600 pPolygon->SetSedimentInputUnconsFine(dSedimentInputFine);
601 pPolygon->SetSedimentInputUnconsSand(dSedimentInputSand);
602 pPolygon->SetSedimentInputUnconsCoarse(dSedimentInputCoarse);
603
604 // Store this polygon's stored consolidated sediment depths
605 pPolygon->SetPreExistingConsFine(dStoredConsFine);
606 pPolygon->SetPreExistingConsSand(dStoredConsSand);
607 pPolygon->SetPreExistingConsCoarse(dStoredConsCoarse);
608
609 // Store the number of cells in the interior of the polygon
610 pPolygon->SetNumCellsInPolygon(nCellsInPolygon);
611 // LogStream << m_ulIter << ": in MarkPolygonCells() N cells = " << nCellsInPolygon << " in polygon " << nPolyID << endl;
612
613 // Calculate the total volume of seawater on the polygon (m3) and store it
614 double const dSeaVolume = dTotDepth * m_dCellSide;
615 pPolygon->SetSeawaterVolume(dSeaVolume);
616 }
617 }
618
619 // // DEBUG CODE ===========================================================================================================
620 // if (m_ulIter == 109)
621 // {
622 // string strOutFile = m_strOutPath + "00_polygon_fill_";
623 // strOutFile += to_string(m_ulIter);
624 // strOutFile += ".tif";
625 //
626 // GDALDriver* pDriver = GetGDALDriverManager()->GetDriverByName("gtiff");
627 // GDALDataset* pDataSet = pDriver->Create(strOutFile.c_str(), m_nXGridSize, m_nYGridSize, 1, GDT_Float64, m_papszGDALRasterOptions);
628 // pDataSet->SetProjection(m_strGDALBasementDEMProjection.c_str());
629 // pDataSet->SetGeoTransform(m_dGeoTransform);
630 // double* pdRaster = new double[m_nXGridSize * m_nYGridSize];
631 // int n = 0;
632 //
633 // int nNumPoly = m_VCoast[0].nGetNumPolygons();
634 // vector<int> nVPerPoly(nNumPoly, 0);
635 // int nNotInPoly = 0;
636 //
637 // for (int nY = 0; nY < m_nYGridSize; nY++)
638 // {
639 // for (int nX = 0; nX < m_nXGridSize; nX++)
640 // {
641 // int nID = m_pRasterGrid->m_Cell[nX][nY].nGetPolygonID();
642 // if (nID == INT_NODATA)
643 // nNotInPoly++;
644 // else
645 // nVPerPoly[nID]++;
646 //
647 // pdRaster[n++] = nID;
648 // }
649 // }
650 //
651 // GDALRasterBand* pBand = pDataSet->GetRasterBand(1);
652 // pBand->SetNoDataValue(m_dMissingValue);
653 // int nRet = pBand->RasterIO(GF_Write, 0, 0, m_nXGridSize, m_nYGridSize, pdRaster, m_nXGridSize, m_nYGridSize, GDT_Float64, 0, 0, NULL);
654 // if (nRet == CE_Failure)
655 // return;
656 //
657 // GDALClose(pDataSet);
658 // delete[] pdRaster;
659 //
660 // for (int nn = 0; nn < nNumPoly; nn++)
661 // LogStream << m_ulIter << ": polygon " << nn << " has " << nVPerPoly[nn] << " cells" << endl;
662 // LogStream << m_ulIter << " Number of cells not in any polygon = " << nNotInPoly << endl;
663 // LogStream << "==================" << endl;
664 // }
665 // // DEBUG CODE ===========================================================================================================
666}
667
668//===============================================================================================================================
670//===============================================================================================================================
672{
673 // Do this for every coast
674 for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
675 {
676 int const nNumPolygons = m_VCoast[nCoast].nGetNumPolygons();
677
678 // // DEBUG CODE =================
679 // for (int m = 0; m < m_VCoast[nCoast].nGetNumProfiles(); m++)
680 // {
681 // CGeomProfile* pProfile = m_VCoast[nCoast].pGetProfile(m);
682 //
683 // LogStream << m << "\t" << pProfile->nGetCoastID() << "\t" << pProfile->nGetGlobalID() << "\t";
684 //
685 // int nPointsInProfile = pProfile->nGetProfileSize();
686 //
687 // for (int nPoint = 0; nPoint < nPointsInProfile; nPoint++)
688 // {
689 // CGeom2DPoint Pt = *pProfile->pPtGetPointInProfile(nPoint);
690 // LogStream << "{" << Pt.dGetX() << ", " << Pt.dGetY() << "}";
691 // }
692 // LogStream << endl;
693 // }
694 // // DEBUG CODE =================
695
696 // Do this for every coastal polygon, in along-coast sequence
697 for (int nn = 0; nn < nNumPolygons; nn++)
698 {
699 CGeomCoastPolygon* pThisPolygon = m_VCoast[nCoast].pGetPolygon(nn);
700 int const nThisPolygon = pThisPolygon->nGetCoastID();
701
702 vector<int> nVUpCoastAdjacentPolygon;
703 vector<int> nVDownCoastAdjacentPolygon;
704
705 vector<double> dVUpCoastBoundaryShare;
706 vector<double> dVDownCoastBoundaryShare;
707
708 // First deal with down-coast adjacent polygons
709 if (pThisPolygon->bIsCoastEndPolygon())
710 {
711 // We are at the end of the coastline, no other polygon is adjacent to the down-coast profile of the end-of-coast polygon
712 nVDownCoastAdjacentPolygon.push_back(INT_NODATA);
713 dVDownCoastBoundaryShare.push_back(1);
714
715 // Store in the polygon
716 pThisPolygon->SetDownCoastAdjacentPolygons(&nVDownCoastAdjacentPolygon);
717 pThisPolygon->SetDownCoastAdjacentPolygonBoundaryShares(&dVDownCoastBoundaryShare);
718 }
719
720 else
721 {
722 // We are not at the end of the coastline, so there is at least one other polygon adjacent to the down-coast profile of this polygon
723 int const nDownCoastProfile = pThisPolygon->nGetDownCoastProfile();
724 int const nPointsInProfile = pThisPolygon->nGetNumPointsUsedDownCoastProfile();
725
726 double dDownCoastTotBoundaryLen = 0;
727
728 CGeomProfile* pProfile = m_VCoast[nCoast].pGetProfile(nDownCoastProfile);
729
730 for (int nPoint = 0; nPoint < nPointsInProfile - 1; nPoint++)
731 {
732 CGeom2DPoint const PtStart = *pProfile->pPtGetPointInProfile(nPoint);
733 CGeom2DPoint const PtEnd = *pProfile->pPtGetPointInProfile(nPoint + 1);
734
735 // Calculate the length of this segment of the normal profile. Note that it should not be zero, since we checked for duplicate points when creating profiles
736 double const dDistBetween = dGetDistanceBetween(&PtStart, &PtEnd);
737
738 // Find out which polygon is adjacent to each line segment of the polygon's down-coast profile boundary. The basic approach used is to count the number of coincident profiles in each line segment, and (because we are going down-coast) add this number to 'this' polygon's number. However, some of these coincident profiles may be invalid, so we must count only the valid co-incident profiles
739 int const nNumCoinc = pProfile->nGetNumCoincidentProfilesInLineSegment(nPoint);
740
741 // Safety check
742 if (nNumCoinc < 0)
743 continue;
744
745 int nNumValidCoinc = 0;
746
747 for (int nCoinc = 0; nCoinc < nNumCoinc; nCoinc++)
748 {
749 int const nProf = pProfile->nGetCoincidentProfileForLineSegment(nPoint, nCoinc);
750
751 // Safety check
752 if (nProf == -1)
753 continue;
754
755 CGeomProfile const* pProf = m_VCoast[nCoast].pGetProfile(nProf);
756
757 if (pProf->bProfileOK())
758 nNumValidCoinc++;
759 }
760
761 // First stab at calculating the number of the adjacent polygon
762 int nAdj = nThisPolygon + nNumValidCoinc;
763
764 // However, if 'this' polygon is close to the end of the coastline, we get polygon numbers greater than the number of polygons i.e. beyond the end of the coastline. If this happens, set the adjacent polygon to 'off-edge'
765 if (nAdj >= nNumPolygons)
766 nAdj = INT_NODATA;
767
768 // Safety check: is this adjacent polygon already present in the list of down-coast adjacent polygons?
769 if (pThisPolygon->bDownCoastIsAlreadyPresent(nAdj))
770 continue;
771
772 // Not already present
773 nVDownCoastAdjacentPolygon.push_back(nAdj);
774
775 dDownCoastTotBoundaryLen += dDistBetween;
776 dVDownCoastBoundaryShare.push_back(dDistBetween);
777 }
778
779 // Calculate the down-coast boundary share
780 for (unsigned int n = 0; n < dVDownCoastBoundaryShare.size(); n++)
781 {
782 // Safety check
783 if (bFPIsEqual(dDownCoastTotBoundaryLen, 0.0, TOLERANCE))
784 {
785 nVDownCoastAdjacentPolygon.pop_back();
786 dVDownCoastBoundaryShare.pop_back();
787 continue;
788 }
789
790 dVDownCoastBoundaryShare[n] /= dDownCoastTotBoundaryLen;
791 }
792
793 // Store in the polygon
794 pThisPolygon->SetDownCoastAdjacentPolygons(&nVDownCoastAdjacentPolygon);
795 pThisPolygon->SetDownCoastAdjacentPolygonBoundaryShares(&dVDownCoastBoundaryShare);
796 }
797
798 // Now deal with up-coast adjacent polygons
799 if (pThisPolygon->bIsCoastStartPolygon())
800 {
801 // We are at the start of the coastline, no other polygon is adjacent to the up-coast profile of the start-of-coast polygon
802 nVUpCoastAdjacentPolygon.push_back(INT_NODATA);
803 dVUpCoastBoundaryShare.push_back(1);
804
805 // Store in the polygon
806 pThisPolygon->SetUpCoastAdjacentPolygons(&nVUpCoastAdjacentPolygon);
807 pThisPolygon->SetUpCoastAdjacentPolygonBoundaryShares(&dVUpCoastBoundaryShare);
808 }
809
810 else
811 {
812 // We are not at the start of the coastline, so there is at least one other polygon adjacent to the up-coast profile of this polygon
813 int const nUpCoastProfile = pThisPolygon->nGetUpCoastProfile();
814 int const nPointsInProfile = pThisPolygon->nGetNumPointsUsedUpCoastProfile();
815
816 double dUpCoastTotBoundaryLen = 0;
817
818 CGeomProfile* pProfile = m_VCoast[nCoast].pGetProfile(nUpCoastProfile);
819
820 for (int nPoint = 0; nPoint < nPointsInProfile - 1; nPoint++)
821 {
822 CGeom2DPoint const PtStart = *pProfile->pPtGetPointInProfile(nPoint);
823 CGeom2DPoint const PtEnd = *pProfile->pPtGetPointInProfile(nPoint + 1);
824
825 // Safety check
826 if (PtStart == PtEnd)
827 // Should never get here, since we checked for duplicate points when creating profiles
828 continue;
829
830 // Calculate the length of this segment of the normal profile
831 double const dDistBetween = dGetDistanceBetween(&PtStart, &PtEnd);
832
833 // Find out which polygon is adjacent to each line segment of the polygon's up-coast profile boundary. The basic approach used is to count the number of coincident profiles in each line segment, and (because we are going up-coast) subtract this number from 'this' polygon's number. However, some of these coincident profiles may be invalid, so we must count only the valid co-incident profiles
834 int const nNumCoinc = pProfile->nGetNumCoincidentProfilesInLineSegment(nPoint);
835
836 // Safety check
837 if (nNumCoinc < 0)
838 continue;
839
840 int nNumValidCoinc = 0;
841
842 for (int nCoinc = 0; nCoinc < nNumCoinc; nCoinc++)
843 {
844 int const nProf = pProfile->nGetCoincidentProfileForLineSegment(nPoint, nCoinc);
845
846 // Safety check
847 if (nProf == -1)
848 continue;
849
850 CGeomProfile const* pProf = m_VCoast[nCoast].pGetProfile(nProf);
851
852 if (pProf->bProfileOK())
853 nNumValidCoinc++;
854 }
855
856 // First stab at calculating the number of the adjacent polygon
857 int nAdj = nThisPolygon - nNumValidCoinc;
858
859 // However, if 'this' polygon is close to the start of the coastline, we get polygon numbers below zero i.e. beyond the start of the coastline. If this happens, set the adjacent polygon to 'off-edge'
860 if (nAdj < 0)
861 nAdj = INT_NODATA;
862
863 // Safety check: is this adjacent polygon already present in the list of up-coast adjacent polygons?
864 if (pThisPolygon->bUpCoastIsAlreadyPresent(nAdj))
865 continue;
866
867 // Not already present
868 nVUpCoastAdjacentPolygon.push_back(nAdj);
869
870 dUpCoastTotBoundaryLen += dDistBetween;
871 dVUpCoastBoundaryShare.push_back(dDistBetween);
872 }
873
874 // Calculate the up-coast boundary share
875 for (unsigned int n = 0; n < dVUpCoastBoundaryShare.size(); n++)
876 {
877 // Safety check
878 if (bFPIsEqual(dUpCoastTotBoundaryLen, 0.0, TOLERANCE))
879 {
880 nVUpCoastAdjacentPolygon.pop_back();
881 dVUpCoastBoundaryShare.pop_back();
882 continue;
883 }
884
885 dVUpCoastBoundaryShare[n] /= dUpCoastTotBoundaryLen;
886 }
887
888 // Store in the polygon
889 pThisPolygon->SetUpCoastAdjacentPolygons(&nVUpCoastAdjacentPolygon);
890 pThisPolygon->SetUpCoastAdjacentPolygonBoundaryShares(&dVUpCoastBoundaryShare);
891 }
892
893 // Finally, calculate the distance between the coast node and the antinode of the polygon
894 double const dPolygonSeawardLen = dGetDistanceBetween(pThisPolygon->pPtiGetNode(), pThisPolygon->pPtiGetAntiNode());
895
896 // And store it
897 pThisPolygon->SetLength(dPolygonSeawardLen);
898
899 // // DEBUG CODE ======================================================================================================================
900 // assert(dVUpCoastBoundaryShare.size() == nVUpCoastAdjacentPolygon.size());
901 // assert(dVDownCoastBoundaryShare.size() == nVDownCoastAdjacentPolygon.size());
902 //
903 // LogStream << m_ulIter << ": polygon = " << nPoly << (pPolygon->bIsPointed() ? " IS TRIANGULAR" : "") << endl;
904 // LogStream << m_ulIter << ": coast " << nCoast << " polygon " << nThisPolygon << endl;
905 //
906 // int nUpCoastProfile = pThisPolygon->nGetUpCoastProfile();
907 // CGeomProfile* pUpCoastProfile = m_VCoast[0].pGetProfile(nUpCoastProfile);
908 // int nUpCoastProfileCells = pUpCoastProfile->nGetNumCellsInProfile();
909 //
910 // int nDownCoastProfile = pThisPolygon->nGetDownCoastProfile();
911 // CGeomProfile* pDownCoastProfile = m_VCoast[0].pGetProfile(nDownCoastProfile);
912 // int nDownCoastProfileCells = pDownCoastProfile->nGetNumCellsInProfile();
913 //
914 // LogStream << "\tUp-coast profile = " << nUpCoastProfile << " down-coast profile = " << nDownCoastProfile << endl;
915 // LogStream << "\tN cells in up-coast profile = " << nUpCoastProfileCells << " N cells in down-coast profile = " << nDownCoastProfileCells << endl;
916 //
917 // LogStream << "\tThere are " << nVUpCoastAdjacentPolygon.size() << " UP-COAST adjacent polygon(s) = ";
918 // for (unsigned int n = 0; n < nVUpCoastAdjacentPolygon.size(); n++)
919 // LogStream << nVUpCoastAdjacentPolygon[n] << " ";
920 // LogStream << endl;
921 //
922 // LogStream << "\tThere are " << nVDownCoastAdjacentPolygon.size() << " DOWN-COAST adjacent polygon(s) = ";
923 // for (unsigned int n = 0; n < nVDownCoastAdjacentPolygon.size(); n++)
924 // LogStream << nVDownCoastAdjacentPolygon[n] << " ";
925 // LogStream << endl;
926 //
927 // double dUpCoastTotBoundaryLen = 0;
928 // LogStream << "\tUP-COAST boundary share(s) = ";
929 // for (unsigned int n = 0; n < dVUpCoastBoundaryShare.size(); n++)
930 // {
931 // dUpCoastTotBoundaryLen += dVUpCoastBoundaryShare[n];
932 // LogStream << dVUpCoastBoundaryShare[n] << " ";
933 // }
934 // LogStream << endl;
935 // LogStream << "\tTotal UP-COAST boundary length = " << dUpCoastTotBoundaryLen << endl;
936 //
937 // double dDownCoastTotBoundaryLen = 0;
938 // LogStream << "\tDOWN-COAST boundary share(s) = ";
939 // for (unsigned int n = 0; n < dVDownCoastBoundaryShare.size(); n++)
940 // {
941 // dDownCoastTotBoundaryLen += dVDownCoastBoundaryShare[n];
942 // LogStream << dVDownCoastBoundaryShare[n] << " ";
943 // }
944 // LogStream << endl;
945 // LogStream << "\tTotal DOWN-COAST boundary length = " << dDownCoastTotBoundaryLen << endl;
946 // // DEBUG CODE ======================================================================================================================
947 }
948 }
949
950 // // DEBUG CODE =================================================================================
951 // for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
952 // {
953 // int nNumPoly = m_VCoast[nCoast].nGetNumPolygons();
954 // for (int nPoly = 0; nPoly < nNumPoly; nPoly++)
955 // {
956 // CGeomCoastPolygon const* pPolygon = m_VCoast[nCoast].pGetPolygon(nPoly);
957 //
958 // int nNumUpCoastPolygons = pPolygon->nGetNumUpCoastAdjacentPolygons();
959 // LogStream << "Polygon " << nPoly << " up-coast polygon(s) = ";
960 // for (int nAdj = 0; nAdj < nNumUpCoastPolygons; nAdj++)
961 // {
962 // int nAdjPoly = pPolygon->nGetUpCoastAdjacentPolygon(nAdj);
963 // LogStream << nAdjPoly;
964 // if (nAdjPoly > nNumPoly-1)
965 // LogStream << "***";
966 // }
967 //
968 // int nNumDownCoastPolygons = pPolygon->nGetNumDownCoastAdjacentPolygons();
969 // LogStream << " down-coast polygon(s) = ";
970 // for (int nAdj = 0; nAdj < nNumDownCoastPolygons; nAdj++)
971 // {
972 // int nAdjPoly = pPolygon->nGetDownCoastAdjacentPolygon(nAdj);
973 // LogStream << nAdjPoly;
974 // if (nAdjPoly > nNumPoly-1)
975 // LogStream << "***";
976 // }
977 // LogStream << endl;
978 // }
979 // }
980 // // DEBUG CODE =================================================================================
981
982 return RTN_OK;
983}
984
985//===============================================================================================================================
987//===============================================================================================================================
988bool CSimulation::bIsWithinPolygon(CGeom2DPoint const* pPtStart, vector<CGeom2DPoint> const* pPtPoints)
989{
990 bool bOddNodes = false;
991
992 int const nPolyCorners = static_cast<int>(pPtPoints->size());
993 int j = nPolyCorners - 1;
994
995 double const dX = pPtStart->dGetX();
996 double const dY = pPtStart->dGetY();
997
998 for (int i = 0; i < nPolyCorners; i++)
999 {
1000 double const dCorneriX = pPtPoints->at(i).dGetX();
1001 double const dCorneriY = pPtPoints->at(i).dGetY();
1002 double const dCornerjX = pPtPoints->at(j).dGetX();
1003 double const dCornerjY = pPtPoints->at(j).dGetY();
1004
1005 if ((dCorneriY < dY && dCornerjY >= dY) || (dCornerjY < dY && dCorneriY >= dY))
1006 {
1007 if (dCorneriX + (dY - dCorneriY) / (dCornerjY - dCorneriY) * (dCornerjX - dCorneriX) < dX)
1008 {
1009 bOddNodes = !bOddNodes;
1010 }
1011 }
1012
1013 j = i;
1014 }
1015
1016 return bOddNodes;
1017}
1018
1019//===============================================================================================================================
1021//===============================================================================================================================
1022CGeom2DPoint CSimulation::PtFindPointInPolygon(vector<CGeom2DPoint> const* pPtPoints, int const nStartPoint)
1023{
1024 int const nPolySize = static_cast<int>(pPtPoints->size());
1025 int nOffSet = 0;
1026 CGeom2DPoint PtStart;
1027
1028 do
1029 {
1030 // Choose three consecutive points from the polygon
1031 vector<CGeom2DPoint> nVTestPoints;
1032
1033 for (int n = 0; n < 3; n++)
1034 {
1035 int nIndex = n + nStartPoint + nOffSet;
1036
1037 if (nIndex > nPolySize - 1)
1038 nIndex -= nPolySize;
1039
1040 // Safety check
1041 if (nIndex < 0)
1043
1044 nVTestPoints.push_back(pPtPoints->at(nIndex));
1045 }
1046
1047 // Increment ready for next time
1048 nOffSet++;
1049
1050 // Safety check
1051 if (nOffSet >= (nPolySize + 3))
1053
1054 // Check if the halfway point between the first and the third point is inside the polygon
1055 PtStart = PtAverage(&nVTestPoints[0], &nVTestPoints[2]);
1056 } while (!bIsWithinPolygon(&PtStart, pPtPoints));
1057
1058 return PtStart;
1059}
Contains CGeom2DPoint definitions.
Contains CGeom2DIPoint definitions.
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
double dGetY(void) const
Returns the CGeom2DPoint object's double Y coordinate.
Definition 2d_point.cpp:53
double dGetX(void) const
Returns the CGeom2DPoint object's double X coordinate.
Definition 2d_point.cpp:47
Geometry class used for coast polygon objects.
bool bIsCoastStartPolygon(void) const
Is this polygon the coast-start polygon?
int nGetNumPointsUsedDownCoastProfile(void) const
Return the number of points in the down-coast profile.
CGeom2DIPoint * pPtiGetAntiNode(void)
Get the anti-node (raster grid CRS) which is at other (seaward) end of the polygon from the node.
bool bIsCoastEndPolygon(void) const
Is this polygon the coast-end polygon?
void SetSedimentInputUnconsSand(double const)
Set the value of sand sediment on the polygon derived from sediment input events(s)
void SetPreExistingUnconsFine(double const)
Set the value of pre-existing unconsolidated fine sediment stored on this polygon.
void SetSedimentInputUnconsFine(double const)
Set the value of fine sediment on the polygon derived from sediment input events(s)
void SetPreExistingConsFine(double const)
Set the value of pre-existing consolidated fine sediment stored on this polygon.
void SetPreExistingUnconsSand(double const)
Set the value of pre-existing unconsolidated sand sediment stored on this polygon.
void SetSeawaterVolume(const double)
Set the volume of seawater in the coast polygon.
bool bUpCoastIsAlreadyPresent(int const)
Searches the list of up-coast adjacent polygons for a given polygon number.
int nGetNumPointsUsedUpCoastProfile(void) const
Return the number of points in the up-coast profile.
CGeom2DIPoint PtiGetFillStartPoint(void)
void SetSedimentInputUnconsCoarse(double const)
Set the value of coarse sediment on the polygon derived from sediment input events(s)
void SetDownCoastAdjacentPolygonBoundaryShares(vector< double > const *)
Sets the boundary shares for all down-coast adjacent polygons.
int nGetUpCoastProfile(void) const
Return the number of the up-coast profile.
void SetLength(double const)
Sets the polygon's length.
void SetPreExistingConsCoarse(double const)
Set the value of pre-existing consolidated coarse sediment stored on this polygon.
void SetPreExistingUnconsCoarse(double const)
Set the value of pre-existing unconsolidated coarse sediment stored on this polygon.
void AppendVertex(CGeom2DIPoint const *)
Appends the point cordinates (grid CRS) for a polygon vertex.
void SetDownCoastAdjacentPolygons(vector< int > const *)
Sets all down-coast adjacent polygons.
void SetUpCoastAdjacentPolygonBoundaryShares(vector< double > const *)
Sets the boundary shares for all up-coast adjacent polygons.
void SetUpCoastAdjacentPolygons(vector< int > const *)
Sets all up-coast adjacent polygons.
void SetPreExistingConsSand(double const)
Set the value of pre-existing consolidated sand sediment stored on this polygon.
int nGetDownCoastProfile(void) const
Return the number of the down-coast profile.
int nGetCoastID(void) const
Get the coast ID, this is the same as the down-coast sequence of polygons.
bool bDownCoastIsAlreadyPresent(int const)
Searches the list of down-coast adjacent polygons for a given polygon number.
void SetNumCellsInPolygon(int const)
Set the number of cells in the polygon.
CGeom2DIPoint * pPtiGetNode(void)
Get the grid coordinates of the cell on which the node sits.
int nGetNumCoincidentProfilesInLineSegment(int const)
Returns the count of coincident profiles in a specified line segment, or -1 if the line segment does ...
bool bFindProfileInCoincidentProfiles(int const)
Returns true if the given profile number is one of the coincident profiles of the a specified line se...
int nGetCoincidentProfileForLineSegment(int const, int const) const
Returns the numbers of coincident profiles.
void GetMostCoastwardSharedLineSegment(int const, int &, int &)
Finds the number of the most coastward line segment for which the two profiles are coincident,...
Geometry class used to represent coast profile objects.
Definition profile.h:37
int nGetCoastPoint(void) const
Returns the coast point at which the profile starts.
Definition profile.cpp:87
CGeomProfile * pGetDownCoastAdjacentProfile(void) const
Definition profile.cpp:478
CGeom2DIPoint * pPtiGetCellInProfile(int const)
Returns a single cell in the profile.
Definition profile.cpp:511
int nGetNumCellsInProfile(void) const
Returns the number of cells in the profile.
Definition profile.cpp:525
bool bProfileOK(void) const
Returns true if this is a problem-free profile, and is not a start-of-coast or an end-of-coast profil...
Definition profile.cpp:219
CGeom2DIPoint * pPtiGetEndPoint(void)
Returns a pointer to the location of the cell (grid CRS) on which the profile ends.
Definition profile.cpp:105
CGeom2DPoint * pPtGetPointInProfile(int const)
Returns a single point in the profile.
Definition profile.cpp:357
bool bOKIncStartAndEndOfCoast(void) const
Returns true if this is a problem-free profile (however it could be a start-of-coast or an end-of-coa...
Definition profile.cpp:254
int nGetCoastID(void) const
Returns the profile's coast ID.
Definition profile.cpp:75
int nGetProfileSize(void) const
Returns the number of points in the profile.
Definition profile.cpp:350
CGeom2DIPoint * pPtiGetStartPoint(void)
Returns a pointer to the location of the cell (grid CRS) on which the profile starts.
Definition profile.cpp:93
bool bStartOfCoast(void) const
Returns the switch to indicate whether this is a start-of-coast profile.
Definition profile.cpp:117
bool bEndOfCoast(void) const
Returns the switch to indicate whether this is an end-of-coast profile.
Definition profile.cpp:129
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
CGeom2DIPoint PtiExtCRSToGridRound(CGeom2DPoint const *) const
ofstream LogStream
vector< CRWCoast > m_VCoast
The coastline objects.
vector< CGeomCoastPolygon * > m_pVCoastPolygon
Pointers to coast polygon objects, in down-coast sequence TODO 044 Will need to use global polygon ID...
int m_nYGridSize
The size of the grid in the y direction.
Definition simulation.h:460
static double dGetDistanceBetween(CGeom2DPoint const *, CGeom2DPoint const *)
Returns the distance (in external CRS) between two points.
static CGeom2DPoint PtAverage(CGeom2DPoint const *, CGeom2DPoint const *)
double m_dStartIterSuspFineInPolygons
Depth (m) of fine suspended sediment at the start of the simulation (only cells in polygons)
Definition simulation.h:991
void KeepWithinValidGrid(int &, int &) const
int nCreateAllPolygons(void)
Create polygons, and mark the polygon boundaries on the raster grid.
void RasterizePolygonJoiningLine(int const, CGeom2DIPoint const *, CGeom2DIPoint const *, int const)
Puts a polygon 'joining line' (the line which is the seaward boundary of the polygon,...
static CGeom2DPoint PtFindPointInPolygon(vector< CGeom2DPoint > const *, int const)
Finds a point in a polygon: is guaranteed to succeed, as every strictly closed polygon has at least o...
void MarkPolygonCells(void)
Marks cells of the raster grid that are within each coastal polygon. The cell-by-cell fill (aka 'floo...
bool bIsWithinValidGrid(int const, int const) const
unsigned long m_ulIter
The number of the current iteration (time step)
Definition simulation.h:598
int m_nNumPolygonGlobal
Number of global (all coasts) polygons.
Definition simulation.h:523
double m_dCellSide
Length of a cell side (in external CRS units)
Definition simulation.h:658
int nDoPolygonSharedBoundaries(void)
For between-polygon potential sediment routing: find which are the adjacent polygons,...
static bool bIsWithinPolygon(CGeom2DPoint const *, vector< CGeom2DPoint > const *)
Determines whether a point is within a polygon: however if the point is exactly on the edge of the po...
This file contains global definitions for CoastalME.
int const NO_NONZERO_THICKNESS_LAYERS
Definition cme.h:770
int const INT_NODATA
Definition cme.h:476
T tMin(T a, T b)
Definition cme.h:1259
double const TOLERANCE
Definition cme.h:814
string const ERR
Definition cme.h:896
bool bFPIsEqual(const T d1, const T d2, const T dEpsilon)
Definition cme.h:1297
T tMax(T a, T b)
Definition cme.h:1246
int const RTN_ERR_BAD_MULTILINE
Definition cme.h:743
int const RTN_OK
Definition cme.h:695
double const DBL_NODATA
Definition cme.h:827
T tAbs(T a)
Definition cme.h:1271
Contains CRWCoast definitions.
Contains CSimulation definitions.
int nRound(double const d)
Version of the above that returns an int.