167 строки
5.8 KiB
C++
167 строки
5.8 KiB
C++
/******************************************************************************
|
|
*
|
|
* Purpose: Implementation of ReflectanceCalculator class. Calculate
|
|
* reflectance values from radiance, for visual bands.
|
|
* Author: Bas Retsios, retsios@itc.nl
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2004, ITC
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#include "cpl_port.h" // Must be first.
|
|
|
|
#include "reflectancecalculator.h"
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
|
|
using namespace std;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
ReflectanceCalculator::ReflectanceCalculator(std::string sTimeStamp,
|
|
double rRTOA)
|
|
: m_rRTOA(rRTOA)
|
|
{
|
|
std::string sYear(sTimeStamp.substr(0, 4));
|
|
std::string sMonth(sTimeStamp.substr(4, 2));
|
|
std::string sDay(sTimeStamp.substr(6, 2));
|
|
std::string sHours(sTimeStamp.substr(8, 2));
|
|
std::string sMins(sTimeStamp.substr(10, 2));
|
|
|
|
m_iYear = atoi(sYear.c_str());
|
|
int iMonth = atoi(sMonth.c_str());
|
|
m_iDay = atoi(sDay.c_str());
|
|
for (int i = 1; i < iMonth; ++i)
|
|
m_iDay += iDaysInMonth(i, m_iYear);
|
|
int iHours = atoi(sHours.c_str());
|
|
int iMins = atoi(sMins.c_str());
|
|
|
|
m_rHours = iHours + iMins / 60.0;
|
|
}
|
|
|
|
ReflectanceCalculator::~ReflectanceCalculator()
|
|
{
|
|
}
|
|
|
|
double ReflectanceCalculator::rGetReflectance(double rRadiance, double rLat,
|
|
double rLon) const
|
|
{
|
|
double phi = rLat * M_PI / 180;
|
|
// double lam = rLon * M_PI / 180;
|
|
double rSunDist = rSunDistance();
|
|
double ReflectanceNumerator = rRadiance * rSunDist * rSunDist;
|
|
double zenithAngle = rZenithAngle(phi, rDeclination(), rHourAngle(rLon));
|
|
double ReflectanceDenominator = m_rRTOA * cos(zenithAngle * M_PI / 180);
|
|
double Reflectance = ReflectanceNumerator / ReflectanceDenominator;
|
|
return Reflectance;
|
|
}
|
|
|
|
double ReflectanceCalculator::rZenithAngle(double phi, double rDeclin,
|
|
double l_rHourAngle)
|
|
{
|
|
double rCosZen =
|
|
(sin(phi) * sin(rDeclin) + cos(phi) * cos(rDeclin) * cos(l_rHourAngle));
|
|
double zenithAngle = acos(rCosZen) * 180 / M_PI;
|
|
return zenithAngle;
|
|
}
|
|
|
|
double ReflectanceCalculator::rDeclination() const
|
|
{
|
|
double rJulianDay = m_iDay - 1;
|
|
double yearFraction = (rJulianDay + m_rHours / 24) / iDaysInYear(m_iYear);
|
|
double T = 2 * M_PI * yearFraction;
|
|
|
|
double declin = 0.006918 - 0.399912 * cos(T) + 0.070257 * sin(T) -
|
|
0.006758 * cos(2 * T) + 0.000907 * sin(2 * T) -
|
|
0.002697 * cos(3 * T) + 0.00148 * sin(3 * T);
|
|
return declin;
|
|
}
|
|
|
|
double ReflectanceCalculator::rHourAngle(double rLon) const
|
|
{
|
|
// In: rLon (in degrees)
|
|
// Out: hourAngle (in radians)
|
|
double rJulianDay = m_iDay - 1;
|
|
double yearFraction = (rJulianDay + m_rHours / 24) / iDaysInYear(m_iYear);
|
|
double T = 2 * M_PI * yearFraction;
|
|
|
|
double EOT2 = 229.18 * (0.000075 + 0.001868 * cos(T) - 0.032077 * sin(T));
|
|
double EOT3 = 229.18 * (-0.014615 * cos(2 * T) - 0.040849 * sin(2 * T));
|
|
double EOT = EOT2 + EOT3;
|
|
double TimeOffset = EOT + (4. * rLon);
|
|
// True solar time in minutes:
|
|
double TrueSolarTime = m_rHours * 60 + TimeOffset;
|
|
// Solar hour angle in degrees and in radians:
|
|
double HaDegr = (TrueSolarTime / 4. - 180.);
|
|
double hourAngle = HaDegr * M_PI / 180;
|
|
return hourAngle;
|
|
}
|
|
|
|
double ReflectanceCalculator::rSunDistance() const
|
|
{
|
|
int iJulianDay = m_iDay - 1;
|
|
double theta = 2 * M_PI * (iJulianDay - 3) / 365.25;
|
|
// rE0 is the inverse of the square of the sun-distance ratio
|
|
double rE0 = 1.000110 + 0.034221 * cos(theta) + 0.00128 * sin(theta) +
|
|
0.000719 * cos(2 * theta) + 0.000077 * sin(2 * theta);
|
|
// The calculated distance is expressed as a factor of the "average
|
|
// sun-distance" (on 1 Jan approx. 0.98, on 1 Jul approx. 1.01)
|
|
return 1 / sqrt(rE0);
|
|
}
|
|
|
|
int ReflectanceCalculator::iDaysInYear(int iYear)
|
|
{
|
|
bool fLeapYear = iDaysInMonth(2, iYear) == 29;
|
|
|
|
if (fLeapYear)
|
|
return 366;
|
|
else
|
|
return 365;
|
|
}
|
|
|
|
int ReflectanceCalculator::iDaysInMonth(int iMonth, int iYear)
|
|
{
|
|
int iDays;
|
|
|
|
if ((iMonth == 4) || (iMonth == 6) || (iMonth == 9) || (iMonth == 11))
|
|
iDays = 30;
|
|
else if (iMonth == 2)
|
|
{
|
|
iDays = 28;
|
|
if (iYear % 100 == 0) // century year
|
|
{
|
|
if (iYear % 400 == 0) // century leap year
|
|
++iDays;
|
|
}
|
|
else
|
|
{
|
|
if (iYear % 4 == 0) // normal leap year
|
|
++iDays;
|
|
}
|
|
}
|
|
else
|
|
iDays = 31;
|
|
|
|
return iDays;
|
|
}
|