@@ -130,6 +130,10 @@ ViewshedExecutor::ViewshedExecutor(GDALRasterBand &srcBand,
130130{
131131 if (m_dfMaxDistance2 == 0 )
132132 m_dfMaxDistance2 = std::numeric_limits<double >::max ();
133+ if (opts.lowPitch != -90.0 )
134+ m_lowTanPitch = std::tan (oOpts.lowPitch * (2 * M_PI / 360.0 ));
135+ if (opts.highPitch != 90.0 )
136+ m_highTanPitch = std::tan (oOpts.highPitch * (2 * M_PI / 360.0 ));
133137 m_srcBand.GetDataset ()->GetGeoTransform (m_adfTransform.data ());
134138 int hasNoData = false ;
135139 m_noDataValue = m_srcBand.GetNoDataValue (&hasNoData);
@@ -427,7 +431,11 @@ void ViewshedExecutor::processFirstLineLeft(const LineLimits &ll,
427431 if (oOpts.outputMode == OutputMode::Normal)
428432 vResult[iStart] = oOpts.visibleVal ;
429433 else
434+ {
435+ maskLowPitch (*pThis, 1 , 0 );
430436 setOutput (vResult[iStart], *pThis, *pThis);
437+ }
438+ maskHighPitch (vResult[iStart], *pThis, 1 , 0 );
431439 iStart--;
432440 pThis--;
433441 }
@@ -437,7 +445,9 @@ void ViewshedExecutor::processFirstLineLeft(const LineLimits &ll,
437445 {
438446 int nXOffset = std::abs (iPixel - m_nX);
439447 double dfZ = CalcHeightLine (nXOffset, *(pThis + 1 ));
448+ maskLowPitch (dfZ, nXOffset, 0 );
440449 setOutput (vResult[iPixel], *pThis, dfZ);
450+ maskHighPitch (vResult[iPixel], dfZ, nXOffset, 0 );
441451 }
442452
443453 maskLineLeft (vResult, ll, m_nY);
@@ -615,7 +625,11 @@ void ViewshedExecutor::processFirstLineRight(const LineLimits &ll,
615625 if (oOpts.outputMode == OutputMode::Normal)
616626 vResult[iStart] = oOpts.visibleVal ;
617627 else
628+ {
629+ maskLowPitch (*pThis, 1 , 0 );
618630 setOutput (vResult[iStart], *pThis, *pThis);
631+ }
632+ maskHighPitch (vResult[iStart], *pThis, 1 , 0 );
619633 iStart++;
620634 pThis++;
621635 }
@@ -625,7 +639,9 @@ void ViewshedExecutor::processFirstLineRight(const LineLimits &ll,
625639 {
626640 int nXOffset = std::abs (iPixel - m_nX);
627641 double dfZ = CalcHeightLine (nXOffset, *(pThis - 1 ));
642+ maskLowPitch (dfZ, nXOffset, 0 );
628643 setOutput (vResult[iPixel], *pThis, dfZ);
644+ maskHighPitch (vResult[iPixel], dfZ, nXOffset, 0 );
629645 }
630646
631647 maskLineRight (vResult, ll, m_nY);
@@ -664,7 +680,11 @@ void ViewshedExecutor::processLineLeft(int nYOffset, LineLimits &ll,
664680 if (oOpts.outputMode == OutputMode::Normal)
665681 vResult[iStart] = oOpts.visibleVal ;
666682 else
683+ {
684+ maskLowPitch (*pThis, m_nX - iStart, nYOffset);
667685 setOutput (vResult[iStart], *pThis, *pThis);
686+ maskHighPitch (vResult[iStart], *pThis, m_nX - iStart, nYOffset);
687+ }
668688 iStart--;
669689 pThis--;
670690 pLast--;
@@ -685,7 +705,9 @@ void ViewshedExecutor::processLineLeft(int nYOffset, LineLimits &ll,
685705 else
686706 dfZ =
687707 oZcalc (nXOffset, nYOffset, *(pThis + 1 ), *pLast, *(pLast + 1 ));
708+ maskLowPitch (dfZ, nXOffset, nYOffset);
688709 setOutput (vResult[iPixel], *pThis, dfZ);
710+ maskHighPitch (vResult[iPixel], dfZ, nXOffset, nYOffset);
689711 }
690712
691713 maskLineLeft (vResult, ll, nLine);
@@ -724,7 +746,11 @@ void ViewshedExecutor::processLineRight(int nYOffset, LineLimits &ll,
724746 if (oOpts.outputMode == OutputMode::Normal)
725747 vResult[iStart] = oOpts.visibleVal ;
726748 else
749+ {
750+ maskLowPitch (*pThis, m_nX, nYOffset);
727751 setOutput (vResult[0 ], *pThis, *pThis);
752+ maskHighPitch (vResult[0 ], *pThis, m_nX, nYOffset);
753+ }
728754 iStart++;
729755 pThis++;
730756 pLast++;
@@ -745,7 +771,9 @@ void ViewshedExecutor::processLineRight(int nYOffset, LineLimits &ll,
745771 else
746772 dfZ =
747773 oZcalc (nXOffset, nYOffset, *(pThis - 1 ), *pLast, *(pLast - 1 ));
774+ maskLowPitch (dfZ, nXOffset, nYOffset);
748775 setOutput (vResult[iPixel], *pThis, dfZ);
776+ maskHighPitch (vResult[iPixel], dfZ, nXOffset, nYOffset);
749777 }
750778
751779 maskLineRight (vResult, ll, nLine);
@@ -802,7 +830,9 @@ bool ViewshedExecutor::processLine(int nLine, std::vector<double> &vLastLineVal)
802830 dfZ = vThisLineVal[m_nX];
803831 else
804832 dfZ = CalcHeightLine (nYOffset, vLastLineVal[m_nX]);
833+ maskLowPitch (dfZ, 0 , nYOffset);
805834 setOutput (vResult[m_nX], vThisLineVal[m_nX], dfZ);
835+ maskHighPitch (vResult[m_nX], dfZ, 0 , nYOffset);
806836 }
807837 else
808838 vResult[m_nX] = oOpts.outOfRangeVal ;
@@ -919,5 +949,28 @@ bool ViewshedExecutor::run()
919949 return true ;
920950}
921951
952+ void ViewshedExecutor::maskLowPitch (double &dfZ, int nXOffset, int nYOffset)
953+ {
954+ if (std::isnan (m_lowTanPitch))
955+ return ;
956+
957+ double dfDist = std::sqrt (nXOffset * nXOffset + nYOffset * nYOffset);
958+ double dfZmask = dfDist * m_lowTanPitch;
959+ if (dfZmask > dfZ)
960+ dfZ = dfZmask;
961+ }
962+
963+ void ViewshedExecutor::maskHighPitch (double &dfResult, double dfZ, int nXOffset,
964+ int nYOffset)
965+ {
966+ if (std::isnan (m_highTanPitch))
967+ return ;
968+
969+ double dfDist = std::sqrt (nXOffset * nXOffset + nYOffset * nYOffset);
970+ double dfZmask = dfDist * m_highTanPitch;
971+ if (dfZmask < dfZ)
972+ dfResult = oOpts.outOfRangeVal ;
973+ }
974+
922975} // namespace viewshed
923976} // namespace gdal
0 commit comments