@@ -176,6 +176,27 @@ namespace OrthoTree
176176 struct IsStdOptional <std::optional<U>> : std::true_type
177177 {};
178178
179+ template <size_t ... Is, class F >
180+ constexpr void static_for_impl (std::index_sequence<Is...>, F&& f) noexcept
181+ {
182+ (f (static_cast <uint32_t >(std::integral_constant<size_t , Is>{})), ...);
183+ }
184+
185+ template <size_t N, class F >
186+ constexpr void static_for (F&& f) noexcept
187+ {
188+ if constexpr (N < 16 )
189+ {
190+ static_for_impl (std::make_index_sequence<N>{}, std::forward<F>(f));
191+ }
192+ else
193+ {
194+ constexpr uint32_t uintN = static_cast <uint32_t >(N);
195+ for (uint32_t i = 0 ; i < uintN; ++i)
196+ f (i);
197+ }
198+ }
199+
179200 template <typename T>
180201 inline constexpr bool IsStdOptionalV = IsStdOptional<T>::value;
181202
@@ -1882,11 +1903,10 @@ namespace OrthoTree
18821903 constexpr std::optional<BoxPickResult> Hit (const Vector& center, const Vector& halfSize) const noexcept
18831904 {
18841905 Vector minDifference, maxDifference;
1885- for (dim_t dimensionID = 0 ; dimensionID < DIMENSION_NO; ++dimensionID)
1886- minDifference[dimensionID] = center[dimensionID] - halfSize[dimensionID] - m_origin[dimensionID];
1887-
1888- for (dim_t dimensionID = 0 ; dimensionID < DIMENSION_NO; ++dimensionID)
1889- maxDifference[dimensionID] = center[dimensionID] + halfSize[dimensionID] - m_origin[dimensionID];
1906+ detail::static_for<DIMENSION_NO>(
1907+ [&](dim_t dimensionID) noexcept { minDifference[dimensionID] = center[dimensionID] - halfSize[dimensionID] - m_origin[dimensionID]; });
1908+ detail::static_for<DIMENSION_NO>(
1909+ [&](dim_t dimensionID) noexcept { maxDifference[dimensionID] = center[dimensionID] + halfSize[dimensionID] - m_origin[dimensionID]; });
18901910
18911911 return HitTest<isConeToleranceConsidered>(minDifference, maxDifference);
18921912 }
@@ -1895,11 +1915,10 @@ namespace OrthoTree
18951915 constexpr std::optional<BoxPickResult> Hit (const TBox& box) const noexcept
18961916 {
18971917 Vector minDifference, maxDifference;
1898- for (dim_t dimensionID = 0 ; dimensionID < DIMENSION_NO; ++dimensionID)
1899- minDifference[dimensionID] = AD::GetBoxMinC (box, dimensionID) - m_origin[dimensionID];
1900-
1901- for (dim_t dimensionID = 0 ; dimensionID < DIMENSION_NO; ++dimensionID)
1902- maxDifference[dimensionID] = AD::GetBoxMaxC (box, dimensionID) - m_origin[dimensionID];
1918+ detail::static_for<DIMENSION_NO>(
1919+ [&](dim_t dimensionID) noexcept { minDifference[dimensionID] = AD::GetBoxMinC (box, dimensionID) - m_origin[dimensionID]; });
1920+ detail::static_for<DIMENSION_NO>(
1921+ [&](dim_t dimensionID) noexcept { maxDifference[dimensionID] = AD::GetBoxMaxC (box, dimensionID) - m_origin[dimensionID]; });
19031922
19041923 return HitTest<isConeToleranceConsidered>(minDifference, maxDifference);
19051924 }
@@ -1908,37 +1927,52 @@ namespace OrthoTree
19081927 constexpr BoxRayHitTester () = default;
19091928
19101929 template <bool isConeToleranceConsidered = true >
1911- constexpr std::optional<BoxPickResult> HitTest (const Vector& minDifference, const Vector& maxDifference) const
1930+ constexpr std::optional<BoxPickResult> HitTest (const Vector& minDifference, const Vector& maxDifference) const noexcept
19121931 {
19131932 // plane distances
19141933 std::array<Vector, 2 > pd;
1915- for (dim_t dimensionID = 0 ; dimensionID < DIMENSION_NO; ++dimensionID)
1916- pd[0 ][dimensionID] = minDifference[dimensionID] * m_inverseDirection[dimensionID];
1917-
1918- for (dim_t dimensionID = 0 ; dimensionID < DIMENSION_NO; ++dimensionID)
1919- pd[1 ][dimensionID] = maxDifference[dimensionID] * m_inverseDirection[dimensionID];
1934+ detail::static_for<DIMENSION_NO>(
1935+ [&](dim_t dimensionID) noexcept { pd[0 ][dimensionID] = minDifference[dimensionID] * m_inverseDirection[dimensionID]; });
1936+ detail::static_for<DIMENSION_NO>(
1937+ [&](dim_t dimensionID) noexcept { pd[1 ][dimensionID] = maxDifference[dimensionID] * m_inverseDirection[dimensionID]; });
19201938
1921- // NaN is eliminated in std::fmax/fmin, and returns the non-NaN.
19221939 std::optional pickResult =
19231940 BoxPickResult{ .enterDistance = -std::numeric_limits<Geometry>::max (), .exitDistance = std::numeric_limits<Geometry>::max () };
19241941
1925- for (dim_t dimensionID = 0 ; dimensionID < DIMENSION_NO; ++dimensionID)
1942+ // Find the largest entering distance and the smallest exiting distance. fmax/fmin handles NaN correctly.
1943+ if (m_hasNaNComponent)
19261944 {
1927- pickResult->enterDistance = std::fmax (pickResult->enterDistance , pd[m_signInfo[dimensionID]][dimensionID]);
1928- pickResult->exitDistance = std::fmin (pickResult->exitDistance , pd[1 - m_signInfo[dimensionID]][dimensionID]);
1945+ detail::static_for<DIMENSION_NO>([&](dim_t dimensionID) noexcept {
1946+ pickResult->enterDistance = std::fmax (pickResult->enterDistance , pd[m_signInfo[dimensionID]][dimensionID]);
1947+ });
1948+ detail::static_for<DIMENSION_NO>([&](dim_t dimensionID) noexcept {
1949+ pickResult->exitDistance = std::fmin (pickResult->exitDistance , pd[1 - m_signInfo[dimensionID]][dimensionID]);
1950+ });
19291951 }
1952+ else
1953+ {
1954+ detail::static_for<DIMENSION_NO>([&](dim_t dimensionID) noexcept {
1955+ pickResult->enterDistance = std::max (pickResult->enterDistance , pd[m_signInfo[dimensionID]][dimensionID]);
1956+ });
1957+ detail::static_for<DIMENSION_NO>([&](dim_t dimensionID) noexcept {
1958+ pickResult->exitDistance = std::min (pickResult->exitDistance , pd[1 - m_signInfo[dimensionID]][dimensionID]);
1959+ });
1960+ }
1961+
1962+ // enterDistance/exitDistance is not Nan from here
19301963
1964+ // Apply tolerance
19311965 auto exitTolerance = Geometry{};
19321966 if constexpr (isConeToleranceConsidered)
19331967 {
1934- exitTolerance = std::fmax (Geometry (0 ), pickResult->exitDistance ) * m_toleranceIncrement + m_minTolerance;
1968+ exitTolerance = std::max (Geometry (0 ), pickResult->exitDistance ) * m_toleranceIncrement + m_minTolerance;
19351969
1936- pickResult->enterDistance -= Geometry (0.5 ) * (std::fmax (Geometry (0 ), pickResult->enterDistance ) * m_toleranceIncrement + m_minTolerance);
1937- pickResult->exitDistance += Geometry (0.5 ) * (std::fmax (Geometry (0 ), pickResult->exitDistance ) * m_toleranceIncrement + m_minTolerance);
1970+ pickResult->enterDistance -= Geometry (0.5 ) * (std::max (Geometry (0 ), pickResult->enterDistance ) * m_toleranceIncrement + m_minTolerance);
1971+ pickResult->exitDistance += Geometry (0.5 ) * (std::max (Geometry (0 ), pickResult->exitDistance ) * m_toleranceIncrement + m_minTolerance);
19381972 }
19391973 else
19401974 { // Numerical inaccuracies could cause false-miss
1941- exitTolerance = Geometry (0.5 ) * std::fmax (Geometry (1 ), pickResult->exitDistance ) * std::numeric_limits<Geometry>::epsilon ();
1975+ exitTolerance = Geometry (0.5 ) * std::max (Geometry (1 ), pickResult->exitDistance ) * std::numeric_limits<Geometry>::epsilon ();
19421976
19431977 pickResult->enterDistance -= exitTolerance;
19441978 pickResult->exitDistance += exitTolerance;
@@ -1952,7 +1986,7 @@ namespace OrthoTree
19521986 }
19531987
19541988 // Ray origin inside the box case
1955- pickResult->enterDistance = std::fmax (Geometry (0 ), pickResult->enterDistance );
1989+ pickResult->enterDistance = std::max (Geometry (0 ), pickResult->enterDistance );
19561990
19571991 // Handle zero direction components
19581992 if (m_hasNaNComponent)
0 commit comments