3232#include < cassert>
3333#include < limits>
3434
35+ // ABELL
36+ #include < iostream>
37+
3538#include " viewshed_executor.h"
3639#include " progress.h"
3740
@@ -111,6 +114,7 @@ double doMax(int nXOffset, int nYOffset, double dfThisPrev, double dfLast,
111114
112115// / Constructor -- the viewshed algorithm executor
113116// / @param srcBand Source raster band
117+ // / @param sdBand Destination raster band
114118// / @param dstBand Destination raster band
115119// / @param nX X position of observer
116120// / @param nY Y position of observer
@@ -119,13 +123,30 @@ double doMax(int nXOffset, int nYOffset, double dfThisPrev, double dfLast,
119123// / @param opts Configuration options.
120124// / @param progress Reference to the progress tracker.
121125ViewshedExecutor::ViewshedExecutor (GDALRasterBand &srcBand,
126+ GDALRasterBand &sdBand,
122127 GDALRasterBand &dstBand, int nX, int nY,
123128 const Window &outExtent,
124129 const Window &curExtent, const Options &opts,
125130 Progress &progress)
126- : m_pool(4 ), m_srcBand(srcBand), m_dstBand(dstBand), oOutExtent(outExtent),
127- oCurExtent (curExtent), m_nX(nX - oOutExtent.xStart), m_nY(nY),
128- oOpts(opts), oProgress(progress),
131+ : m_pool(4 ), m_srcBand(srcBand), m_sdBand(sdBand), m_dstBand(dstBand),
132+ oOutExtent (outExtent), oCurExtent(curExtent),
133+ m_nX(nX - oOutExtent.xStart), m_nY(nY), oOpts(opts), oProgress(progress),
134+ m_dfMaxDistance2(opts.maxDistance * opts.maxDistance)
135+ {
136+ if (m_dfMaxDistance2 == 0 )
137+ m_dfMaxDistance2 = std::numeric_limits<double >::max ();
138+ m_srcBand.GetDataset ()->GetGeoTransform (m_adfTransform.data ());
139+ }
140+
141+ // No SD Band
142+ ViewshedExecutor::ViewshedExecutor (GDALRasterBand &srcBand,
143+ GDALRasterBand &dstBand, int nX, int nY,
144+ const Window &outExtent,
145+ const Window &curExtent, const Options &opts,
146+ Progress &progress)
147+ : m_pool(4 ), m_srcBand(srcBand), m_sdBand(m_srcBand), m_dstBand(dstBand),
148+ oOutExtent(outExtent), oCurExtent(curExtent),
149+ m_nX(nX - oOutExtent.xStart), m_nY(nY), oOpts(opts), oProgress(progress),
129150 m_dfMaxDistance2(opts.maxDistance * opts.maxDistance)
130151{
131152 if (m_dfMaxDistance2 == 0 )
@@ -162,17 +183,48 @@ double ViewshedExecutor::calcHeightAdjFactor()
162183// / dfCellVal Reference to the current cell height. Replace with observable height.
163184// / dfZ Minimum observable height at cell.
164185void ViewshedExecutor::setOutput (double &dfResult, double &dfCellVal,
165- double dfZ)
186+ double &dfSdCellVal, double dfZ, double dfSdZ )
166187{
167188 if (oOpts.outputMode != OutputMode::Normal)
168189 {
169190 dfResult += (dfZ - dfCellVal);
170191 dfResult = std::max (0.0 , dfResult);
192+ dfSdCellVal = std::max (dfSdCellVal, dfSdZ);
171193 }
172194 else
173- dfResult = (dfCellVal + oOpts.targetHeight < dfZ) ? oOpts.invisibleVal
174- : oOpts.visibleVal ;
175- dfCellVal = std::max (dfCellVal, dfZ);
195+ {
196+ /* *
197+ std::cerr << "cell height/dfz/dfsdz/sd = " <<
198+ (dfCellVal + oOpts.targetHeight) << "/" << dfZ << "/" << dfSdZ << "/" <<
199+ dfSdCellVal;
200+ **/
201+ if (dfZ <= dfCellVal + oOpts.targetHeight )
202+ {
203+ // std::cerr << " - visible!\n";
204+ dfResult = oOpts.visibleVal ;
205+ if (dfSdCellVal > 1 ) // Changing SD to height.
206+ dfSdCellVal = dfSdZ; // See-through case.
207+ else
208+ dfSdCellVal = dfCellVal; // Blocking case
209+ }
210+ else if (dfSdZ <= dfCellVal + oOpts.targetHeight )
211+ {
212+ // std::cerr << " - maybe visible!\n";
213+ dfResult = oOpts.maybeVisibleVal ;
214+ if (dfSdCellVal > 1 ) // Changing SD to height.
215+ dfSdCellVal = dfSdZ; // See-through case.
216+ else
217+ dfSdCellVal = dfCellVal; // Blocking case
218+ dfCellVal = dfZ;
219+ }
220+ else
221+ {
222+ // std::cerr << " - not visible!\n";
223+ dfResult = oOpts.invisibleVal ;
224+ dfCellVal = dfZ;
225+ dfSdCellVal = dfSdZ;
226+ }
227+ }
176228}
177229
178230// / Read a line of raster data.
@@ -199,9 +251,29 @@ bool ViewshedExecutor::readLine(int nLine, std::vector<Cell> &vThisLine)
199251 oOutExtent.xStart , nLine, oOutExtent.xSize (), 1 );
200252 return false ;
201253 }
202-
203254 for (size_t i = 0 ; i < line.size (); ++i)
204255 vThisLine[i].val = line[i];
256+
257+ int sdStatus = 0 ;
258+ double nodata = std::numeric_limits<double >::max ();
259+ {
260+ std::lock_guard g (iMutex);
261+ nodata = m_sdBand.GetNoDataValue ();
262+ sdStatus = m_sdBand.RasterIO (
263+ GF_Read, oOutExtent.xStart , nLine, oOutExtent.xSize (), 1 ,
264+ line.data (), oOutExtent.xSize (), 1 , GDT_Float64, 0 , 0 , nullptr );
265+ }
266+ if (sdStatus)
267+ {
268+ CPLError (CE_Failure, CPLE_AppDefined,
269+ " RasterIO error when reading SD band at position (%d,%d), "
270+ " size (%d,%d)" ,
271+ oOutExtent.xStart , nLine, oOutExtent.xSize (), 1 );
272+ return false ;
273+ }
274+ for (size_t i = 0 ; i < line.size (); ++i)
275+ vThisLine[i].sd = (line[i] == nodata ? 1000.0 : line[i]);
276+
205277 return true ;
206278}
207279
@@ -358,7 +430,6 @@ bool ViewshedExecutor::processFirstLine(std::vector<Cell> &vLastLine)
358430 pQueue->SubmitJob (
359431 [&, left = iLeft]()
360432 { processFirstLineLeft (m_nX - 1 , left - 1 , vThisLine); });
361-
362433 pQueue->SubmitJob (
363434 [&, right = iRight]()
364435 { processFirstLineRight (m_nX + 1 , right, vThisLine); });
@@ -390,7 +461,8 @@ void ViewshedExecutor::processFirstLineTopOrBottom(int iLeft, int iRight,
390461 if (oOpts.outputMode == OutputMode::Normal)
391462 c.result = oOpts.visibleVal ;
392463 else
393- setOutput (c.result , c.val , c.val );
464+ // ABELL - Check SD height here. Perhaps 0 if SD < 1?
465+ setOutput (c.result , c.val , c.sd , c.val , c.val );
394466 }
395467 for (int i = 0 ; i < iLeft; ++i)
396468 vThisLine[i].result = oOpts.outOfRangeVal ;
@@ -417,9 +489,12 @@ void ViewshedExecutor::processFirstLineLeft(int iStart, int iEnd,
417489 {
418490 Cell &c = vThisLine[iStart];
419491 if (oOpts.outputMode == OutputMode::Normal)
492+ {
420493 c.result = oOpts.visibleVal ;
494+ c.sd = c.val ; // Set the SD height to the height.
495+ }
421496 else
422- setOutput (c.result , c.val , c.val );
497+ setOutput (c.result , c.val , c.sd , c. val , c. val );
423498 iStart--;
424499 }
425500
@@ -429,7 +504,8 @@ void ViewshedExecutor::processFirstLineLeft(int iStart, int iEnd,
429504 Cell &c = vThisLine[iPixel];
430505 int nXOffset = std::abs (iPixel - m_nX);
431506 double dfZ = CalcHeightLine (nXOffset, vThisLine[iPixel + 1 ].val );
432- setOutput (c.result , c.val , dfZ);
507+ double dfSdZ = CalcHeightLine (nXOffset, vThisLine[iPixel + 1 ].sd );
508+ setOutput (c.result , c.val , c.sd , dfZ, dfSdZ);
433509 }
434510 // For cells outside of the [start, end) range, set the outOfRange value.
435511 for (int i = 0 ; i < iEnd + 1 ; ++i)
@@ -459,7 +535,8 @@ void ViewshedExecutor::processFirstLineRight(int iStart, int iEnd,
459535 if (oOpts.outputMode == OutputMode::Normal)
460536 c.result = oOpts.visibleVal ;
461537 else
462- setOutput (c.result , c.val , c.val );
538+ // ABELL Perhaps set the last value to zero if SD < 1.
539+ setOutput (c.result , c.val , c.sd , c.val , c.val );
463540 iStart++;
464541 }
465542
@@ -469,7 +546,8 @@ void ViewshedExecutor::processFirstLineRight(int iStart, int iEnd,
469546 Cell &c = vThisLine[iPixel];
470547 int nXOffset = std::abs (iPixel - m_nX);
471548 double dfZ = CalcHeightLine (nXOffset, vThisLine[iPixel - 1 ].val );
472- setOutput (c.result , c.val , dfZ);
549+ double dfSdZ = CalcHeightLine (nXOffset, vThisLine[iPixel - 1 ].sd );
550+ setOutput (c.result , c.val , c.sd , dfZ, dfSdZ);
473551 }
474552 // For cells outside of the [start, end) range, set the outOfRange value.
475553 for (int i = iEnd; i < oOutExtent.xSize (); ++i)
@@ -503,7 +581,8 @@ void ViewshedExecutor::processLineLeft(int nYOffset, int iStart, int iEnd,
503581 if (oOpts.outputMode == OutputMode::Normal)
504582 c.result = oOpts.visibleVal ;
505583 else
506- setOutput (c.result , c.val , c.val );
584+ // ABELL Perhaps set the last value to zero if SD < 1.
585+ setOutput (c.result , c.val , c.sd , c.val , c.val );
507586 iStart--;
508587 }
509588
@@ -512,17 +591,29 @@ void ViewshedExecutor::processLineLeft(int nYOffset, int iStart, int iEnd,
512591 {
513592 int nXOffset = std::abs (iPixel - m_nX);
514593 double dfZ;
594+ double dfSdZ;
515595 if (nXOffset == nYOffset)
516596 {
517597 if (nXOffset == 1 )
598+ {
518599 dfZ = vThisLine[iPixel].val ;
600+ dfSdZ = vThisLine[iPixel].val ; // ABELL - Check this.
601+ }
519602 else
603+ {
520604 dfZ = CalcHeightLine (nXOffset, vLastLine[iPixel + 1 ].val );
605+ dfSdZ = CalcHeightLine (nXOffset, vLastLine[iPixel + 1 ].sd );
606+ }
521607 }
522608 else
609+ {
523610 dfZ = oZcalc (nXOffset, nYOffset, vThisLine[iPixel + 1 ].val ,
524611 vLastLine[iPixel].val , vLastLine[iPixel + 1 ].val );
525- setOutput (vThisLine[iPixel].result , vThisLine[iPixel].val , dfZ);
612+ dfSdZ = oZcalc (nXOffset, nYOffset, vThisLine[iPixel + 1 ].sd ,
613+ vLastLine[iPixel].sd , vLastLine[iPixel + 1 ].sd );
614+ }
615+ setOutput (vThisLine[iPixel].result , vThisLine[iPixel].val ,
616+ vThisLine[iPixel].sd , dfZ, dfSdZ);
526617 }
527618
528619 // For cells outside of the [start, end) range, set the outOfRange value.
@@ -557,7 +648,8 @@ void ViewshedExecutor::processLineRight(int nYOffset, int iStart, int iEnd,
557648 if (oOpts.outputMode == OutputMode::Normal)
558649 c.result = oOpts.visibleVal ;
559650 else
560- setOutput (c.result , c.val , c.val );
651+ // ABELL - Here too.
652+ setOutput (c.result , c.val , c.sd , c.val , c.val );
561653 iStart++;
562654 }
563655
@@ -566,17 +658,29 @@ void ViewshedExecutor::processLineRight(int nYOffset, int iStart, int iEnd,
566658 {
567659 int nXOffset = std::abs (iPixel - m_nX);
568660 double dfZ;
661+ double dfSdZ;
569662 if (nXOffset == nYOffset)
570663 {
571664 if (nXOffset == 1 )
665+ {
572666 dfZ = vThisLine[iPixel].val ;
667+ dfSdZ = vThisLine[iPixel].val ; // ABELL - Here.
668+ }
573669 else
670+ {
574671 dfZ = CalcHeightLine (nXOffset, vLastLine[iPixel - 1 ].val );
672+ dfSdZ = CalcHeightLine (nXOffset, vLastLine[iPixel - 1 ].sd );
673+ }
575674 }
576675 else
676+ {
577677 dfZ = oZcalc (nXOffset, nYOffset, vThisLine[iPixel - 1 ].val ,
578678 vLastLine[iPixel].val , vLastLine[iPixel - 1 ].val );
579- setOutput (vThisLine[iPixel].result , vThisLine[iPixel].val , dfZ);
679+ dfSdZ = oZcalc (nXOffset, nYOffset, vThisLine[iPixel - 1 ].sd ,
680+ vLastLine[iPixel].sd , vLastLine[iPixel - 1 ].sd );
681+ }
682+ setOutput (vThisLine[iPixel].result , vThisLine[iPixel].val ,
683+ vThisLine[iPixel].sd , dfZ, dfSdZ);
580684 }
581685
582686 // For cells outside of the [start, end) range, set the outOfRange value.
@@ -613,11 +717,19 @@ bool ViewshedExecutor::processLine(int nLine, std::vector<Cell> &vLastLine)
613717 if (iLeft < iRight)
614718 {
615719 double dfZ;
720+ double dfSdZ;
616721 if (std::abs (nYOffset) == 1 )
722+ {
617723 dfZ = vThisLine[m_nX].val ;
724+ dfSdZ = vThisLine[m_nX].val ;
725+ }
618726 else
727+ {
619728 dfZ = CalcHeightLine (nYOffset, vLastLine[m_nX].val );
620- setOutput (vThisLine[m_nX].result , vThisLine[m_nX].val , dfZ);
729+ dfSdZ = CalcHeightLine (nYOffset, vLastLine[m_nX].sd );
730+ }
731+ setOutput (vThisLine[m_nX].result , vThisLine[m_nX].val ,
732+ vThisLine[m_nX].sd , dfZ, dfSdZ);
621733 }
622734 else
623735 vThisLine[m_nX].result = oOpts.outOfRangeVal ;
0 commit comments