Skip to content

Commit

Permalink
Merge pull request #1599 from falbrechtskirchinger/rounding
Browse files Browse the repository at this point in the history
Add `iround()` and round PointF->PointInt by default
  • Loading branch information
Flamefire authored Jul 19, 2023
2 parents 70cb872 + d712cf5 commit f0a8f2b
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 17 deletions.
18 changes: 17 additions & 1 deletion libs/common/include/Point.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#pragma once

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

struct Truncate_t
{
constexpr explicit Truncate_t() = default;
};

static constexpr Truncate_t Truncate{};

T x, y;
constexpr Point() noexcept : x(getInvalidValue()), y(getInvalidValue()) {}
constexpr Point(const T x, const T y) noexcept : x(x), y(y) {}
template<typename U>
template<typename U, std::enable_if_t<!(std::is_integral<T>::value && std::is_floating_point<U>::value), int> = 0>
constexpr explicit Point(const Point<U>& pt) noexcept : x(static_cast<T>(pt.x)), y(static_cast<T>(pt.y))
{}
/// Convert floating-point to integer by truncating
template<typename U, std::enable_if_t<std::is_integral<T>::value && std::is_floating_point<U>::value, int> = 0>
constexpr explicit Point(Truncate_t, const Point<U>& pt) noexcept : x(static_cast<T>(pt.x)), y(static_cast<T>(pt.y))
{}
/// Convert floating-point to integer with rounding (default behavior)
template<typename U, std::enable_if_t<std::is_integral<T>::value && std::is_floating_point<U>::value, int> = 0>
constexpr explicit Point(const Point<U>& pt) noexcept : x(helpers::iround<T>(pt.x)), y(helpers::iround<T>(pt.y))
{}
constexpr Point(const Point&) = default;
constexpr Point& operator=(const Point&) = default;

Expand Down
16 changes: 16 additions & 0 deletions libs/common/include/helpers/mathFuncs.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#pragma once

#include "RTTR_Assert.h"
#include <cmath>
#include <type_traits>

namespace helpers {
Expand Down Expand Up @@ -79,4 +81,18 @@ constexpr T inverseLerp(const T startVal, const T endVal, const T value) noexcep
{
return (value - startVal) / (endVal - startVal);
}

// TODO can be constexpr in C++20
/// Arithmetically round floating point values to integers
template<typename IntType, typename FloatType,
std::enable_if_t<std::is_integral<IntType>::value && std::is_floating_point<FloatType>::value, int> = 0>
IntType iround(const FloatType val) noexcept
{
RTTR_Assert(std::isfinite(val));

if(std::is_unsigned<IntType>::value)
RTTR_Assert_Msg(!(val < 0), "Floating-point value must not be negative when casting to unsigned integer type.");

return static_cast<IntType>(std::lround(val));
}
} // namespace helpers
4 changes: 2 additions & 2 deletions libs/s25main/FrameCounter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later

#include "FrameCounter.h"
#include "helpers/mathFuncs.h"
#include "helpers/win32_nanosleep.h" // IWYU pragma: keep
#include <algorithm>
#include <cmath>

//-V:clock::time_point:813

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

FrameTimer::FrameTimer(int targetFramerate, unsigned maxLagFrames, clock::time_point curTime)
Expand Down
4 changes: 2 additions & 2 deletions libs/s25main/TerrainRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,7 @@ void TerrainRenderer::PrepareWaysPoint(PreparedRoads& sorted_roads, const GameWo
const Position& offset) const
{
const WorldDescription& desc = gwViewer.GetWorld().GetDescription();
Position startPos = Position(GetVertexPos(pt)) + offset;
Position startPos = Position(Position::Truncate, GetVertexPos(pt)) + offset;

Visibility visibility = gwViewer.GetVisibility(pt);

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

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

// Gehen wir über einen Kartenrand (horizontale Richung?)
Expand Down
6 changes: 3 additions & 3 deletions libs/s25main/controls/ctrlProgress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
#include "CollisionDetection.h"
#include "Loader.h"
#include "WindowManager.h"
#include "helpers/mathFuncs.h"
#include "ogl/FontStyle.h"
#include "ogl/glFont.h"
#include <cmath>

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

if(GetParent())
GetParent()->Msg_ProgressChange(GetID(), position);
Expand Down
4 changes: 2 additions & 2 deletions libs/s25main/controls/ctrlTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
#include "ctrlScrollBar.h"
#include "driver/KeyEvent.h"
#include "driver/MouseCoords.h"
#include "helpers/mathFuncs.h"
#include "ogl/glFont.h"
#include "s25util/StringConversion.h"
#include "s25util/strAlgos.h"
#include <algorithm>
#include <cmath>
#include <numeric>
#include <sstream>

Expand Down Expand Up @@ -465,7 +465,7 @@ void ctrlTable::ResetButtonWidths()
for(unsigned i = 0; i < columns_.size(); ++i)
{
auto* button = GetCtrl<ctrlButton>(i + 1);
button->SetWidth(std::lround(columns_[i].width * sizeFactor));
button->SetWidth(helpers::iround<unsigned>(columns_[i].width * sizeFactor));
button->SetPos(btPos);
btPos.x += button->GetSize().x;
}
Expand Down
4 changes: 2 additions & 2 deletions libs/s25main/ingameWindows/iwConnecting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
#include "controls/ctrlPercent.h"
#include "controls/ctrlText.h"
#include "desktops/dskGameLobby.h"
#include "helpers/mathFuncs.h"
#include "iwMsgbox.h"
#include "network/GameClient.h"
#include "gameData/const_gui_ids.h"
#include "s25util/colors.h"
#include <cmath>

namespace {
enum
Expand Down Expand Up @@ -92,7 +92,7 @@ void iwConnecting::CI_NextConnectState(const ConnectState cs)

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

void iwConnecting::setStatus(const std::string& status)
Expand Down
4 changes: 2 additions & 2 deletions libs/s25main/network/GameServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "commonDefines.h"
#include "files.h"
#include "helpers/containerUtils.h"
#include "helpers/mathFuncs.h"
#include "helpers/random.h"
#include "network/CreateServerInfo.h"
#include "network/GameMessages.h"
Expand All @@ -36,7 +37,6 @@
#include <boost/filesystem.hpp>
#include <boost/nowide/convert.hpp>
#include <boost/nowide/fstream.hpp>
#include <cmath>
#include <helpers/chronoIO.h>
#include <iomanip>
#include <iterator>
Expand Down Expand Up @@ -763,7 +763,7 @@ void GameServer::ExecuteNWF()
using MsDouble = duration<double, std::milli>;
double newNWFLen =
framesinfo.nwf_length * framesinfo.gf_length / duration_cast<MsDouble>(framesinfo.gfLengthReq);
newInfo.nextNWF = lastNWF + std::max(1l, std::lround(newNWFLen));
newInfo.nextNWF = lastNWF + std::max(1u, helpers::iround<unsigned>(newNWFLen));
}
SendNWFDone(newInfo);
}
Expand Down
6 changes: 3 additions & 3 deletions libs/s25main/world/GameWorld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "figures/nofPassiveSoldier.h"
#include "figures/nofScout_Free.h"
#include "helpers/containerUtils.h"
#include "helpers/mathFuncs.h"
#include "helpers/reverse.h"
#include "lua/LuaInterfaceGame.h"
#include "notifications/BuildingNote.h"
Expand All @@ -37,7 +38,6 @@
#include "gameData/MilitaryConsts.h"
#include "gameData/TerrainDesc.h"
#include <algorithm>
#include <cmath>
#include <functional>
#include <set>
#include <stdexcept>
Expand Down Expand Up @@ -1357,8 +1357,8 @@ void GameWorld::PlaceAndFixWater()
}
}
if(minHumidity)
curNodeResource = Resource(
ResourceType::Water, waterEverywhere ? 7 : static_cast<uint8_t>(std::lround(minHumidity * 7. / 100.)));
curNodeResource =
Resource(ResourceType::Water, waterEverywhere ? 7 : helpers::iround<uint8_t>(minHumidity * 7. / 100.));
else
curNodeResource = Resource(ResourceType::Nothing, 0);

Expand Down
9 changes: 9 additions & 0 deletions tests/common/testPoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,12 @@ BOOST_AUTO_TEST_CASE(ProdOfComponents)
Point<float> ptF(256.5, 256.5);
BOOST_TEST(prodOfComponents(ptF) == 256.5f * 256.5f);
}

BOOST_AUTO_TEST_CASE(ConvertFloatToIntPoints)
{
BOOST_TEST(Point<int>(Point<float>(1.5f, 3.4f)) == Point<int>(2, 3));
BOOST_TEST(Point<int>(Point<int>::Truncate, Point<float>(1.5f, 3.4f)) == Point<int>(1, 3));

BOOST_TEST(Point<int>(Point<float>(-1.5f, -3.4f)) == Point<int>(-2, -3));
BOOST_TEST(Point<int>(Point<int>::Truncate, Point<float>(-1.5f, -3.4f)) == Point<int>(-1, -3));
}

0 comments on commit f0a8f2b

Please sign in to comment.