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