1+ /* =========================================================================
2+ * This file is part of six.sicd-c++
3+ * =========================================================================
4+ *
5+ * (C) Copyright 2021, Maxar Technologies, Inc.
6+ *
7+ * six.sicd-c++ is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU Lesser General Public License as published by
9+ * the Free Software Foundation; either version 3 of the License, or
10+ * (at your option) any later version.
11+ *
12+ * This program is distributed in the hope that it will be useful,
13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+ * GNU Lesser General Public License for more details.
16+ *
17+ * You should have received a copy of the GNU Lesser General Public
18+ * License along with this program; If not,
19+ * see <http://www.gnu.org/licenses/>.
20+ *
21+ */
122#include " six/sicd/ComplexToAMP8IPHS8I.h"
223
324#include < math.h>
1132namespace six {
1233namespace sicd {
1334
14- ComplexToAMP8IPHS8I::ComplexToAMP8IPHS8I (const six::AmplitudeTable *pAmplitudeTable) {
35+ /* !
36+ * Get the phase of a complex value.
37+ * @param v complex value
38+ * @return phase between [0, 2PI]
39+ */
40+ inline double GetPhase (const std::complex <double >& v)
41+ {
42+ double phase = std::arg (v);
43+ if (phase < 0.0 ) phase += M_PI * 2.0 ; // Wrap from [0, 2PI]
44+ return phase;
45+ }
1546
47+ ComplexToAMP8IPHS8I::ComplexToAMP8IPHS8I (const six::AmplitudeTable *pAmplitudeTable)
48+ {
1649 // Be careful with indexing so that we don't wrap-around in the loops.
17- for (uint16_t i = 0 ; i <= UINT8_MAX; i++) {
50+ for (uint16_t i = 0 ; i <= UINT8_MAX; i++)
51+ {
1852 // AmpPhase -> Complex
1953 ImageData::AMP8I_PHS8I_t v;
2054 v.first = gsl::narrow<uint8_t >(i);
@@ -36,12 +70,15 @@ ComplexToAMP8IPHS8I::ComplexToAMP8IPHS8I(const six::AmplitudeTable *pAmplitudeTa
3670 assert (p0 == 0 );
3771 assert (p1 > p0);
3872 phase_delta = p1 - p0;
39- for (size_t i = 0 ; i <= UINT8_MAX; i++) {
40- double y, x;
41- math::SinCos (p0 + gsl::narrow_cast<double >(i) * phase_delta, y, x);
73+ for (size_t i = 0 ; i <= UINT8_MAX; i++)
74+ {
75+ long double y, x;
76+ math::SinCos (p0 + gsl::narrow_cast<long double >(i) * phase_delta, y, x);
4277 phase_directions[i] = { x, y };
4378 }
4479}
80+ ComplexToAMP8IPHS8I::ComplexToAMP8IPHS8I (const six::AmplitudeTable& amplitudeTable) : ComplexToAMP8IPHS8I(&litudeTable) {}
81+ ComplexToAMP8IPHS8I::ComplexToAMP8IPHS8I () : ComplexToAMP8IPHS8I(nullptr /* pAmplitudeTable*/ ) {}
4582
4683/* !
4784 * Find the nearest element given an iterator range.
@@ -52,39 +89,35 @@ ComplexToAMP8IPHS8I::ComplexToAMP8IPHS8I(const six::AmplitudeTable *pAmplitudeTa
5289 * @return index of nearest value within the iterator range.
5390 */
5491template <typename TIter>
55- static uint8_t nearest (const TIter& begin, const TIter& end, double value) {
92+ static uint8_t nearest (const TIter& begin, const TIter& end, long double value)
93+ {
5694 auto it = std::lower_bound (begin, end, value);
57- if (it == begin) return uint8_t ( 0 ) ;
95+ if (it == begin) return 0 ;
5896 auto prev_it = std::prev (it);
5997 auto nearest = (it == end || value - *prev_it <= *it - value) ? prev_it : it;
6098 assert (std::distance (begin, nearest) <= std::numeric_limits<uint8_t >::max ());
6199 return static_cast <uint8_t >(std::distance (begin, nearest));
62100}
63101
64- ImageData::AMP8I_PHS8I_t ComplexToAMP8IPHS8I::nearest_neighbor (const std::complex <double > &v) const {
102+ ImageData::AMP8I_PHS8I_t ComplexToAMP8IPHS8I::nearest_neighbor (const std::complex <float > &v) const
103+ {
65104 ImageData::AMP8I_PHS8I_t ans;
66105
67106 // Phase is determined via arithmetic because it's equally spaced.
68107 // There's an intentional conversion to zero when we cast 256 -> uint8. That wrap around
69108 // handles cases that are close to 2PI.
70- ans.second = static_cast <uint8_t >(std::round (GetPhase (v) / phase_delta));
109+ ans.second = gsl::narrow_cast <uint8_t >(std::round (GetPhase (v) / phase_delta));
71110
72111 // We have to do a 1D nearest neighbor search for magnitude.
73112 // But it's not the magnitude of the input complex value - it's the projection of
74113 // the complex value onto the ray of candidate magnitudes at the selected phase.
75114 // I.e. dot product.
76- const std:: complex < double > direction = phase_directions[ans.second ];
77- const double projection = direction.real () * v.real () + direction.imag () * v.imag ();
115+ auto && direction = phase_directions[ans.second ];
116+ const auto projection = direction.real () * gsl::narrow_cast< long double >( v.real ()) + direction.imag () * gsl::narrow_cast< long double >( v.imag () );
78117 // assert(std::abs(projection - std::abs(v)) < 1e-5); // TODO ???
79118 ans.first = nearest (magnitudes.begin (), magnitudes.end (), projection);
80119 return ans;
81120}
82121
83-
84- double ComplexToAMP8IPHS8I::GetPhase (const std::complex <double > &v) {
85- double phase = std::arg (v);
86- if (phase < 0.0 ) phase += M_PI * 2.0 ; // Wrap from [0, 2PI]
87- return phase;
88- }
89122}
90123}
0 commit comments