Skip to content

Commit f0a8f2b

Browse files
authored
Merge pull request #1599 from falbrechtskirchinger/rounding
Add `iround()` and round PointF->PointInt by default
2 parents 70cb872 + d712cf5 commit f0a8f2b

10 files changed

Lines changed: 58 additions & 17 deletions

File tree

libs/common/include/Point.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#pragma once
66

7+
#include "helpers/mathFuncs.h"
78
#include <algorithm>
89
#include <cstdint>
910
#include <limits>
@@ -21,12 +22,27 @@ struct Point //-V690
2122
using ElementType = T;
2223
static_assert(std::is_arithmetic<ElementType>::value, "Requires an arithmetic type");
2324

25+
struct Truncate_t
26+
{
27+
constexpr explicit Truncate_t() = default;
28+
};
29+
30+
static constexpr Truncate_t Truncate{};
31+
2432
T x, y;
2533
constexpr Point() noexcept : x(getInvalidValue()), y(getInvalidValue()) {}
2634
constexpr Point(const T x, const T y) noexcept : x(x), y(y) {}
27-
template<typename U>
35+
template<typename U, std::enable_if_t<!(std::is_integral<T>::value && std::is_floating_point<U>::value), int> = 0>
2836
constexpr explicit Point(const Point<U>& pt) noexcept : x(static_cast<T>(pt.x)), y(static_cast<T>(pt.y))
2937
{}
38+
/// Convert floating-point to integer by truncating
39+
template<typename U, std::enable_if_t<std::is_integral<T>::value && std::is_floating_point<U>::value, int> = 0>
40+
constexpr explicit Point(Truncate_t, const Point<U>& pt) noexcept : x(static_cast<T>(pt.x)), y(static_cast<T>(pt.y))
41+
{}
42+
/// Convert floating-point to integer with rounding (default behavior)
43+
template<typename U, std::enable_if_t<std::is_integral<T>::value && std::is_floating_point<U>::value, int> = 0>
44+
constexpr explicit Point(const Point<U>& pt) noexcept : x(helpers::iround<T>(pt.x)), y(helpers::iround<T>(pt.y))
45+
{}
3046
constexpr Point(const Point&) = default;
3147
constexpr Point& operator=(const Point&) = default;
3248

libs/common/include/helpers/mathFuncs.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#pragma once
66

7+
#include "RTTR_Assert.h"
8+
#include <cmath>
79
#include <type_traits>
810

911
namespace helpers {
@@ -79,4 +81,18 @@ constexpr T inverseLerp(const T startVal, const T endVal, const T value) noexcep
7981
{
8082
return (value - startVal) / (endVal - startVal);
8183
}
84+
85+
// TODO can be constexpr in C++20
86+
/// Arithmetically round floating point values to integers
87+
template<typename IntType, typename FloatType,
88+
std::enable_if_t<std::is_integral<IntType>::value && std::is_floating_point<FloatType>::value, int> = 0>
89+
IntType iround(const FloatType val) noexcept
90+
{
91+
RTTR_Assert(std::isfinite(val));
92+
93+
if(std::is_unsigned<IntType>::value)
94+
RTTR_Assert_Msg(!(val < 0), "Floating-point value must not be negative when casting to unsigned integer type.");
95+
96+
return static_cast<IntType>(std::lround(val));
97+
}
8298
} // namespace helpers

libs/s25main/FrameCounter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
// SPDX-License-Identifier: GPL-2.0-or-later
44

55
#include "FrameCounter.h"
6+
#include "helpers/mathFuncs.h"
67
#include "helpers/win32_nanosleep.h" // IWYU pragma: keep
78
#include <algorithm>
8-
#include <cmath>
99

1010
//-V:clock::time_point:813
1111

@@ -36,7 +36,7 @@ unsigned FrameCounter::getCurFrameRate() const
3636
if(timeDiff == clock::duration::zero())
3737
return 0;
3838
using dSeconds = std::chrono::duration<double>;
39-
return std::lround(curNumFrames_ / std::chrono::duration_cast<dSeconds>(timeDiff).count());
39+
return helpers::iround<unsigned>(curNumFrames_ / std::chrono::duration_cast<dSeconds>(timeDiff).count());
4040
}
4141

4242
FrameTimer::FrameTimer(int targetFramerate, unsigned maxLagFrames, clock::time_point curTime)

libs/s25main/TerrainRenderer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,7 @@ void TerrainRenderer::PrepareWaysPoint(PreparedRoads& sorted_roads, const GameWo
886886
const Position& offset) const
887887
{
888888
const WorldDescription& desc = gwViewer.GetWorld().GetDescription();
889-
Position startPos = Position(GetVertexPos(pt)) + offset;
889+
Position startPos = Position(Position::Truncate, GetVertexPos(pt)) + offset;
890890

891891
Visibility visibility = gwViewer.GetVisibility(pt);
892892

@@ -902,7 +902,7 @@ void TerrainRenderer::PrepareWaysPoint(PreparedRoads& sorted_roads, const GameWo
902902
const Direction targetDir = toDirection(dir);
903903
MapPoint ta = gwViewer.GetNeighbour(pt, targetDir);
904904

905-
Position endPos = Position(GetVertexPos(ta)) + offset;
905+
Position endPos = Position(Position::Truncate, GetVertexPos(ta)) + offset;
906906
Position diff = startPos - endPos;
907907

908908
// Gehen wir über einen Kartenrand (horizontale Richung?)

libs/s25main/controls/ctrlProgress.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
#include "CollisionDetection.h"
77
#include "Loader.h"
88
#include "WindowManager.h"
9+
#include "helpers/mathFuncs.h"
910
#include "ogl/FontStyle.h"
1011
#include "ogl/glFont.h"
11-
#include <cmath>
1212

1313
ctrlProgress::ctrlProgress(Window* parent, const unsigned id, const DrawPoint& pos, const Extent& size,
1414
const TextureColor tc, unsigned short button_minus, unsigned short button_plus,
@@ -140,8 +140,8 @@ bool ctrlProgress::Msg_LeftDown(const MouseCoords& mc)
140140
Extent progressSize = GetSize() - Extent((GetSize().y + 1) * 2, 8) - padding_ * 2u;
141141
if(IsPointInRect(mc.GetPos(), Rect(progressOrigin, progressSize)))
142142
{
143-
position = static_cast<uint16_t>(
144-
std::lround(static_cast<double>((mc.pos.x - progressOrigin.x) * maximum) / progressSize.x));
143+
position =
144+
helpers::iround<uint16_t>(static_cast<double>((mc.pos.x - progressOrigin.x) * maximum) / progressSize.x);
145145

146146
if(GetParent())
147147
GetParent()->Msg_ProgressChange(GetID(), position);

libs/s25main/controls/ctrlTable.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
#include "ctrlScrollBar.h"
99
#include "driver/KeyEvent.h"
1010
#include "driver/MouseCoords.h"
11+
#include "helpers/mathFuncs.h"
1112
#include "ogl/glFont.h"
1213
#include "s25util/StringConversion.h"
1314
#include "s25util/strAlgos.h"
1415
#include <algorithm>
15-
#include <cmath>
1616
#include <numeric>
1717
#include <sstream>
1818

@@ -465,7 +465,7 @@ void ctrlTable::ResetButtonWidths()
465465
for(unsigned i = 0; i < columns_.size(); ++i)
466466
{
467467
auto* button = GetCtrl<ctrlButton>(i + 1);
468-
button->SetWidth(std::lround(columns_[i].width * sizeFactor));
468+
button->SetWidth(helpers::iround<unsigned>(columns_[i].width * sizeFactor));
469469
button->SetPos(btPos);
470470
btPos.x += button->GetSize().x;
471471
}

libs/s25main/ingameWindows/iwConnecting.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
#include "controls/ctrlPercent.h"
99
#include "controls/ctrlText.h"
1010
#include "desktops/dskGameLobby.h"
11+
#include "helpers/mathFuncs.h"
1112
#include "iwMsgbox.h"
1213
#include "network/GameClient.h"
1314
#include "gameData/const_gui_ids.h"
1415
#include "s25util/colors.h"
15-
#include <cmath>
1616

1717
namespace {
1818
enum
@@ -92,7 +92,7 @@ void iwConnecting::CI_NextConnectState(const ConnectState cs)
9292

9393
void iwConnecting::CI_MapPartReceived(uint32_t bytesReceived, uint32_t bytesTotal)
9494
{
95-
downloadProgress_ = static_cast<unsigned short>(std::lround(bytesReceived * 100. / bytesTotal));
95+
downloadProgress_ = helpers::iround<unsigned short>(bytesReceived * 100. / bytesTotal);
9696
}
9797

9898
void iwConnecting::setStatus(const std::string& status)

libs/s25main/network/GameServer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "commonDefines.h"
1717
#include "files.h"
1818
#include "helpers/containerUtils.h"
19+
#include "helpers/mathFuncs.h"
1920
#include "helpers/random.h"
2021
#include "network/CreateServerInfo.h"
2122
#include "network/GameMessages.h"
@@ -36,7 +37,6 @@
3637
#include <boost/filesystem.hpp>
3738
#include <boost/nowide/convert.hpp>
3839
#include <boost/nowide/fstream.hpp>
39-
#include <cmath>
4040
#include <helpers/chronoIO.h>
4141
#include <iomanip>
4242
#include <iterator>
@@ -763,7 +763,7 @@ void GameServer::ExecuteNWF()
763763
using MsDouble = duration<double, std::milli>;
764764
double newNWFLen =
765765
framesinfo.nwf_length * framesinfo.gf_length / duration_cast<MsDouble>(framesinfo.gfLengthReq);
766-
newInfo.nextNWF = lastNWF + std::max(1l, std::lround(newNWFLen));
766+
newInfo.nextNWF = lastNWF + std::max(1u, helpers::iround<unsigned>(newNWFLen));
767767
}
768768
SendNWFDone(newInfo);
769769
}

libs/s25main/world/GameWorld.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "figures/nofPassiveSoldier.h"
1818
#include "figures/nofScout_Free.h"
1919
#include "helpers/containerUtils.h"
20+
#include "helpers/mathFuncs.h"
2021
#include "helpers/reverse.h"
2122
#include "lua/LuaInterfaceGame.h"
2223
#include "notifications/BuildingNote.h"
@@ -37,7 +38,6 @@
3738
#include "gameData/MilitaryConsts.h"
3839
#include "gameData/TerrainDesc.h"
3940
#include <algorithm>
40-
#include <cmath>
4141
#include <functional>
4242
#include <set>
4343
#include <stdexcept>
@@ -1357,8 +1357,8 @@ void GameWorld::PlaceAndFixWater()
13571357
}
13581358
}
13591359
if(minHumidity)
1360-
curNodeResource = Resource(
1361-
ResourceType::Water, waterEverywhere ? 7 : static_cast<uint8_t>(std::lround(minHumidity * 7. / 100.)));
1360+
curNodeResource =
1361+
Resource(ResourceType::Water, waterEverywhere ? 7 : helpers::iround<uint8_t>(minHumidity * 7. / 100.));
13621362
else
13631363
curNodeResource = Resource(ResourceType::Nothing, 0);
13641364

tests/common/testPoint.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,12 @@ BOOST_AUTO_TEST_CASE(ProdOfComponents)
283283
Point<float> ptF(256.5, 256.5);
284284
BOOST_TEST(prodOfComponents(ptF) == 256.5f * 256.5f);
285285
}
286+
287+
BOOST_AUTO_TEST_CASE(ConvertFloatToIntPoints)
288+
{
289+
BOOST_TEST(Point<int>(Point<float>(1.5f, 3.4f)) == Point<int>(2, 3));
290+
BOOST_TEST(Point<int>(Point<int>::Truncate, Point<float>(1.5f, 3.4f)) == Point<int>(1, 3));
291+
292+
BOOST_TEST(Point<int>(Point<float>(-1.5f, -3.4f)) == Point<int>(-2, -3));
293+
BOOST_TEST(Point<int>(Point<int>::Truncate, Point<float>(-1.5f, -3.4f)) == Point<int>(-1, -3));
294+
}

0 commit comments

Comments
 (0)