mirror of
https://gitlab.com/square-game-liberation-front/F.E.I.S.git
synced 2025-02-28 15:30:32 +01:00
More tests, getting stuck on the fraction to Decimal conversion ...
This commit is contained in:
parent
6adf48cb77
commit
65388c8335
@ -14,9 +14,7 @@ bool is_expressible_as_240th(const Fraction& beat) {
|
|||||||
|
|
||||||
nlohmann::ordered_json beat_to_best_form(const Fraction& beat) {
|
nlohmann::ordered_json beat_to_best_form(const Fraction& beat) {
|
||||||
if (is_expressible_as_240th(beat)) {
|
if (is_expressible_as_240th(beat)) {
|
||||||
return nlohmann::ordered_json(
|
return nlohmann::ordered_json(static_cast<std::uint64_t>(240 * beat));
|
||||||
(240 * convert_to_u64(beat.numerator())) / convert_to_u64(beat.denominator())
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return beat_to_fraction_tuple(beat);
|
return beat_to_fraction_tuple(beat);
|
||||||
};
|
};
|
||||||
|
@ -18,6 +18,8 @@ namespace better {
|
|||||||
std::optional<Hakus> hakus;
|
std::optional<Hakus> hakus;
|
||||||
Notes notes;
|
Notes notes;
|
||||||
|
|
||||||
|
bool operator==(const Chart&) const = default;
|
||||||
|
|
||||||
nlohmann::ordered_json dump_to_memon_1_0_0(
|
nlohmann::ordered_json dump_to_memon_1_0_0(
|
||||||
const nlohmann::ordered_json& fallback_timing_object
|
const nlohmann::ordered_json& fallback_timing_object
|
||||||
) const;
|
) const;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "better_beats.hpp"
|
#include "better_beats.hpp"
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ namespace better {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Position::Position(std::uint64_t x, std::uint64_t y) : x(x), y(y) {
|
Position::Position(std::uint64_t x, std::uint64_t y) : x(x), y(y) {
|
||||||
if (x > 3 or y > 2) {
|
if (x > 3 or y > 3) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Attempted to create Position from invalid coordinates : ";
|
ss << "Attempted to create Position from invalid coordinates : ";
|
||||||
ss << *this;
|
ss << *this;
|
||||||
@ -37,7 +38,7 @@ namespace better {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<< (std::ostream& out, const Position& pos) {
|
std::ostream& operator<< (std::ostream& out, const Position& pos) {
|
||||||
out << fmt::format("(x: {}, y: {})", pos.x, pos.y);
|
out << fmt::to_string(pos);
|
||||||
return out;
|
return out;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,6 +53,11 @@ namespace better {
|
|||||||
return position;
|
return position;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, const TapNote& t) {
|
||||||
|
out << fmt::to_string(t);
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
nlohmann::ordered_json TapNote::dump_to_memon_1_0_0() const {
|
nlohmann::ordered_json TapNote::dump_to_memon_1_0_0() const {
|
||||||
return {
|
return {
|
||||||
{"n", position.index()},
|
{"n", position.index()},
|
||||||
@ -142,6 +148,11 @@ namespace better {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, const LongNote& l) {
|
||||||
|
out << fmt::to_string(l);
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
nlohmann::ordered_json LongNote::dump_to_memon_1_0_0() const {
|
nlohmann::ordered_json LongNote::dump_to_memon_1_0_0() const {
|
||||||
return {
|
return {
|
||||||
{"n", position.index()},
|
{"n", position.index()},
|
||||||
@ -230,6 +241,11 @@ namespace better {
|
|||||||
return this->get_time_bounds().second;
|
return this->get_time_bounds().second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, const Note& n) {
|
||||||
|
out << fmt::to_string(n);
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
nlohmann::ordered_json Note::dump_to_memon_1_0_0() const {
|
nlohmann::ordered_json Note::dump_to_memon_1_0_0() const {
|
||||||
return std::visit([](const auto& n){return n.dump_to_memon_1_0_0();}, this->note);
|
return std::visit([](const auto& n){return n.dump_to_memon_1_0_0();}, this->note);
|
||||||
}
|
}
|
||||||
@ -242,7 +258,7 @@ namespace better {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto duration = load_memon_1_0_0_beat(json["l"], resolution);
|
const auto duration = load_memon_1_0_0_beat(json["l"], resolution);
|
||||||
const auto tail_index = json["n"].get<std::uint64_t>();
|
const auto tail_index = json["p"].get<std::uint64_t>();
|
||||||
return LongNote{
|
return LongNote{
|
||||||
time,
|
time,
|
||||||
position,
|
position,
|
||||||
@ -261,7 +277,7 @@ namespace better {
|
|||||||
json["l"].get<std::uint64_t>(),
|
json["l"].get<std::uint64_t>(),
|
||||||
resolution,
|
resolution,
|
||||||
};
|
};
|
||||||
const auto tail_index = json["n"].get<std::uint64_t>();
|
const auto tail_index = json["p"].get<std::uint64_t>();
|
||||||
if (duration > 0) {
|
if (duration > 0) {
|
||||||
return LongNote{
|
return LongNote{
|
||||||
time,
|
time,
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
#include <json.hpp>
|
#include <json.hpp>
|
||||||
|
|
||||||
#include "special_numeric_types.hpp"
|
#include "special_numeric_types.hpp"
|
||||||
@ -46,6 +48,7 @@ namespace better {
|
|||||||
Position get_position() const;
|
Position get_position() const;
|
||||||
|
|
||||||
bool operator==(const TapNote&) const = default;
|
bool operator==(const TapNote&) const = default;
|
||||||
|
friend std::ostream& operator<<(std::ostream& out, const TapNote& pos);
|
||||||
|
|
||||||
nlohmann::ordered_json dump_to_memon_1_0_0() const;
|
nlohmann::ordered_json dump_to_memon_1_0_0() const;
|
||||||
private:
|
private:
|
||||||
@ -66,6 +69,7 @@ namespace better {
|
|||||||
std::uint64_t get_tail_angle() const;
|
std::uint64_t get_tail_angle() const;
|
||||||
|
|
||||||
bool operator==(const LongNote&) const = default;
|
bool operator==(const LongNote&) const = default;
|
||||||
|
friend std::ostream& operator<<(std::ostream& out, const LongNote& pos);
|
||||||
|
|
||||||
nlohmann::ordered_json dump_to_memon_1_0_0() const;
|
nlohmann::ordered_json dump_to_memon_1_0_0() const;
|
||||||
int tail_as_6_notation() const;
|
int tail_as_6_notation() const;
|
||||||
@ -92,6 +96,7 @@ namespace better {
|
|||||||
auto visit(T& visitor) const {return std::visit(visitor, this->note);};
|
auto visit(T& visitor) const {return std::visit(visitor, this->note);};
|
||||||
|
|
||||||
bool operator==(const Note&) const = default;
|
bool operator==(const Note&) const = default;
|
||||||
|
friend std::ostream& operator<<(std::ostream& out, const Note& pos);
|
||||||
|
|
||||||
nlohmann::ordered_json dump_to_memon_1_0_0() const;
|
nlohmann::ordered_json dump_to_memon_1_0_0() const;
|
||||||
|
|
||||||
@ -109,3 +114,57 @@ namespace better {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct fmt::formatter<better::Position>: formatter<string_view> {
|
||||||
|
// parse is inherited from formatter<string_view>.
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const better::Position& pos, FormatContext& ctx) {
|
||||||
|
return format_to(
|
||||||
|
ctx.out(),
|
||||||
|
"(x: {}, y: {})",
|
||||||
|
pos.get_x(),
|
||||||
|
pos.get_y()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct fmt::formatter<better::TapNote>: formatter<string_view> {
|
||||||
|
// parse is inherited from formatter<string_view>.
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const better::TapNote& t, FormatContext& ctx) {
|
||||||
|
return format_to(
|
||||||
|
ctx.out(),
|
||||||
|
"TapNote(time: {}, position: {})",
|
||||||
|
t.get_time(),
|
||||||
|
t.get_position()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct fmt::formatter<better::LongNote>: formatter<string_view> {
|
||||||
|
// parse is inherited from formatter<string_view>.
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const better::LongNote& l, FormatContext& ctx) {
|
||||||
|
return format_to(
|
||||||
|
ctx.out(),
|
||||||
|
"LongNote(time: {}, position: {}, duration: {}, tail tip: {})",
|
||||||
|
l.get_time(),
|
||||||
|
l.get_position(),
|
||||||
|
l.get_duration(),
|
||||||
|
l.get_tail_tip()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct fmt::formatter<better::Note>: formatter<string_view> {
|
||||||
|
// parse is inherited from formatter<string_view>.
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const better::Note& n, FormatContext& ctx) {
|
||||||
|
const auto visitor = [&](const auto& n){return format_to(ctx.out(), "{}", n);};
|
||||||
|
return n.visit(visitor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@ -1,38 +1,39 @@
|
|||||||
#include "better_notes.hpp"
|
#include "better_notes.hpp"
|
||||||
|
|
||||||
#include <SFML/System/Time.hpp>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "json.hpp"
|
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
|
#include <json.hpp>
|
||||||
|
|
||||||
namespace better {
|
namespace better {
|
||||||
std::pair<Notes::iterator, bool> Notes::insert(const Note& note) {
|
std::pair<Notes::container::iterator, bool> Notes::insert(const Note& note) {
|
||||||
auto conflicting_note = end();
|
auto conflicting_note = notes.end();
|
||||||
in(
|
notes.in(
|
||||||
note.get_time_bounds(),
|
note.get_time_bounds(),
|
||||||
[&](const Notes::iterator& it){
|
[&](const Notes::container::iterator& it){
|
||||||
if (
|
if (
|
||||||
it->second.get_position() == note.get_position()
|
it->second.get_position() == note.get_position()
|
||||||
and conflicting_note == end()
|
and conflicting_note == notes.end()
|
||||||
) {
|
) {
|
||||||
conflicting_note = it;
|
conflicting_note = it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (conflicting_note != end()) {
|
if (conflicting_note != notes.end()) {
|
||||||
return {conflicting_note, false};
|
return {conflicting_note, false};
|
||||||
} else {
|
} else {
|
||||||
auto it = interval_tree::insert({note.get_time_bounds(), note});
|
auto it = notes.insert({note.get_time_bounds(), note});
|
||||||
return {it, true};
|
return {it, true};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void Notes::overwriting_insert(const Note& note) {
|
void Notes::overwriting_insert(const Note& note) {
|
||||||
std::vector<better::Note> conflicting_notes = {};
|
std::vector<better::Note> conflicting_notes = {};
|
||||||
in(
|
notes.in(
|
||||||
note.get_time_bounds(),
|
note.get_time_bounds(),
|
||||||
[&](const Notes::const_iterator& it) {
|
[&](const Notes::container::const_iterator& it) {
|
||||||
if (it->second.get_position() == note.get_position()) {
|
if (it->second.get_position() == note.get_position()) {
|
||||||
conflicting_notes.push_back(it->second);
|
conflicting_notes.push_back(it->second);
|
||||||
}
|
}
|
||||||
@ -41,15 +42,15 @@ namespace better {
|
|||||||
for (const auto& conflict : conflicting_notes) {
|
for (const auto& conflict : conflicting_notes) {
|
||||||
erase(conflict);
|
erase(conflict);
|
||||||
}
|
}
|
||||||
interval_tree::insert({note.get_time_bounds(), note});
|
notes.insert({note.get_time_bounds(), note});
|
||||||
};
|
};
|
||||||
|
|
||||||
Notes::const_iterator Notes::find(const Note& note) const {
|
Notes::container::const_iterator Notes::find(const Note& note) const {
|
||||||
auto conflicting_note = interval_tree::end();
|
auto conflicting_note = notes.end();
|
||||||
in(
|
notes.in(
|
||||||
note.get_time_bounds(),
|
note.get_time_bounds(),
|
||||||
[&](Notes::const_iterator it){
|
[&](Notes::container::const_iterator it){
|
||||||
if (it->second == note and conflicting_note == end()) {
|
if (it->second == note and conflicting_note == notes.end()) {
|
||||||
conflicting_note = it;
|
conflicting_note = it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,12 +59,12 @@ namespace better {
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool Notes::contains(const Note& note) const {
|
bool Notes::contains(const Note& note) const {
|
||||||
return find(note) != cend();
|
return find(note) != notes.cend();
|
||||||
};
|
};
|
||||||
|
|
||||||
void Notes::erase(const Note& note) {
|
void Notes::erase(const Note& note) {
|
||||||
auto it = find(note);
|
auto it = find(note);
|
||||||
interval_tree::erase(it);
|
notes.erase(it);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -91,9 +92,9 @@ namespace better {
|
|||||||
const auto collision_end = timing.beats_at(timing.time_at(end_beat) + sf::seconds(1));
|
const auto collision_end = timing.beats_at(timing.time_at(end_beat) + sf::seconds(1));
|
||||||
|
|
||||||
bool found_collision = false;
|
bool found_collision = false;
|
||||||
in(
|
notes.in(
|
||||||
{collision_start, collision_end},
|
{collision_start, collision_end},
|
||||||
[&](const Notes::const_iterator& it){
|
[&](const Notes::container::const_iterator& it){
|
||||||
if (it->second.get_position() == note.get_position()) {
|
if (it->second.get_position() == note.get_position()) {
|
||||||
if (it->second != note) {
|
if (it->second != note) {
|
||||||
found_collision = true;
|
found_collision = true;
|
||||||
@ -105,24 +106,24 @@ namespace better {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Notes Notes::between(const Interval<Fraction>& bounds) {
|
Notes Notes::between(const Interval<Fraction>& bounds) {
|
||||||
auto its = in(bounds.start, bounds.end);
|
auto its = notes.in(bounds.start, bounds.end);
|
||||||
Notes res;
|
Notes res;
|
||||||
res.interval_tree::insert(*its.begin(), *its.end());
|
res.notes.insert(*its.begin(), *its.end());
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::size_t Notes::count_between(const Interval<Fraction>& bounds) {
|
std::size_t Notes::count_between(const Interval<Fraction>& bounds) {
|
||||||
std::size_t count = 0;
|
std::size_t count = 0;
|
||||||
in(
|
notes.in(
|
||||||
{bounds.start, bounds.end},
|
{bounds.start, bounds.end},
|
||||||
[&](const Notes::const_iterator& it){count++;}
|
[&](const Notes::container::const_iterator& it){count++;}
|
||||||
);
|
);
|
||||||
return count;
|
return count;
|
||||||
};
|
};
|
||||||
|
|
||||||
nlohmann::ordered_json Notes::dump_to_memon_1_0_0() const {
|
nlohmann::ordered_json Notes::dump_to_memon_1_0_0() const {
|
||||||
auto json_notes = nlohmann::ordered_json::array();
|
auto json_notes = nlohmann::ordered_json::array();
|
||||||
for (const auto& [_, note] : *this) {
|
for (const auto& [_, note] : notes) {
|
||||||
json_notes.push_back(note.dump_to_memon_1_0_0());
|
json_notes.push_back(note.dump_to_memon_1_0_0());
|
||||||
}
|
}
|
||||||
return json_notes;
|
return json_notes;
|
||||||
|
@ -15,14 +15,15 @@
|
|||||||
#include "special_numeric_types.hpp"
|
#include "special_numeric_types.hpp"
|
||||||
|
|
||||||
namespace better {
|
namespace better {
|
||||||
class Notes : public interval_tree<Fraction, Note> {
|
class Notes {
|
||||||
public:
|
public:
|
||||||
|
using container = interval_tree<Fraction, Note>;
|
||||||
// try to insert a note, the boolean is true on success
|
// try to insert a note, the boolean is true on success
|
||||||
std::pair<iterator, bool> insert(const Note& note);
|
std::pair<container::iterator, bool> insert(const Note& note);
|
||||||
// insert a note, erasing any other note it collides with
|
// insert a note, erasing any other note it collides with
|
||||||
void overwriting_insert(const Note& note);
|
void overwriting_insert(const Note& note);
|
||||||
// returns at iterator to a note exactly equal, if found
|
// returns at iterator to a note exactly equal, if found
|
||||||
const_iterator find(const Note& note) const;
|
container::const_iterator find(const Note& note) const;
|
||||||
bool contains(const Note& note) const;
|
bool contains(const Note& note) const;
|
||||||
void erase(const Note& note);
|
void erase(const Note& note);
|
||||||
|
|
||||||
@ -40,5 +41,10 @@ namespace better {
|
|||||||
|
|
||||||
static Notes load_from_memon_1_0_0(const nlohmann::json& json, std::uint64_t resolution = 240);
|
static Notes load_from_memon_1_0_0(const nlohmann::json& json, std::uint64_t resolution = 240);
|
||||||
static Notes load_from_memon_legacy(const nlohmann::json& json, std::uint64_t resolution);
|
static Notes load_from_memon_legacy(const nlohmann::json& json, std::uint64_t resolution);
|
||||||
|
|
||||||
|
bool operator==(const Notes&) const = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
interval_tree<Fraction, Note> notes;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -77,6 +77,8 @@ namespace better {
|
|||||||
static Timing load_from_memon_1_0_0(const nlohmann::json& json);
|
static Timing load_from_memon_1_0_0(const nlohmann::json& json);
|
||||||
static Timing load_from_memon_legacy(const nlohmann::json& metadata);
|
static Timing load_from_memon_legacy(const nlohmann::json& metadata);
|
||||||
|
|
||||||
|
bool operator==(const Timing&) const = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Decimal offset;
|
Decimal offset;
|
||||||
double offset_as_double;
|
double offset_as_double;
|
||||||
|
@ -439,7 +439,7 @@ void EditorState::display_playback_status() {
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::TextDisabled("Beats :");
|
ImGui::TextDisabled("Beats :");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::TextUnformatted(fmt::format("{:.3f}", current_exact_beats().get_d()).c_str());
|
ImGui::TextUnformatted(fmt::format("{:.3f}", static_cast<double>(current_exact_beats())).c_str());
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (music) {
|
if (music) {
|
||||||
ImGui::TextDisabled("Music File Offset :");
|
ImGui::TextDisabled("Music File Offset :");
|
||||||
|
@ -8,7 +8,7 @@ void NotesClipboard::copy(const better::Notes& notes) {
|
|||||||
contents.clear();
|
contents.clear();
|
||||||
if (not notes.empty()) {
|
if (not notes.empty()) {
|
||||||
const auto offset = notes.cbegin()->second.get_time();
|
const auto offset = notes.cbegin()->second.get_time();
|
||||||
const auto shift = shifter(-offset);
|
const auto shift = shifter(-1 * offset);
|
||||||
for (const auto& [_, note] : notes) {
|
for (const auto& [_, note] : notes) {
|
||||||
contents.insert(note.visit(shift));
|
contents.insert(note.visit(shift));
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
#include "special_numeric_types.hpp"
|
#include "special_numeric_types.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
Fraction::Fraction(const Decimal& d) {
|
Fraction::Fraction(const Decimal& d) {
|
||||||
@ -15,15 +18,11 @@ Fraction::Fraction(const Decimal& d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Fraction::operator std::int64_t() const {
|
Fraction::operator std::int64_t() const {
|
||||||
const auto a = convert_to_i64(value.get_num());
|
return convert_to_i64(floor_fraction(*this).numerator());
|
||||||
const auto b = convert_to_i64(value.get_den());
|
|
||||||
return a / b;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Fraction::operator std::uint64_t() const {
|
Fraction::operator std::uint64_t() const {
|
||||||
const auto a = convert_to_u64(value.get_num());
|
return convert_to_u64(floor_fraction(*this).numerator());
|
||||||
const auto b = convert_to_u64(value.get_den());
|
|
||||||
return a / b;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Fraction::operator double() const {
|
Fraction::operator double() const {
|
||||||
@ -190,4 +189,32 @@ Fraction floor_beats(Fraction beats, std::uint64_t denominator) {
|
|||||||
beats *= denominator;
|
beats *= denominator;
|
||||||
const auto nearest = floor_fraction(beats);
|
const auto nearest = floor_fraction(beats);
|
||||||
return nearest / Fraction{denominator};
|
return nearest / Fraction{denominator};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Decimal convert_to_decimal(const Fraction& f, unsigned int decimal_places) {
|
||||||
|
const auto abs_f = f > 0 ? f : -1 * f;
|
||||||
|
std::int64_t precision = 0;
|
||||||
|
if (abs_f > 1) {
|
||||||
|
const std::int64_t numerator_digits = mpz_sizeinbase(f.numerator().get_mpz_t(), 10);
|
||||||
|
const std::int64_t denominator_digits = mpz_sizeinbase(f.denominator().get_mpz_t(), 10);
|
||||||
|
if (numerator_digits == denominator_digits) {
|
||||||
|
precision = decimal_places;
|
||||||
|
} else {
|
||||||
|
precision = numerator_digits - denominator_digits + decimal_places + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const auto first_non_zero_place = -static_cast<std::int64_t>(std::log10(static_cast<double>(abs_f)));
|
||||||
|
if (decimal_places < first_non_zero_place) {
|
||||||
|
return Decimal{0};
|
||||||
|
} else {
|
||||||
|
precision = decimal_places - first_non_zero_place;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decimal::Context c{precision};
|
||||||
|
if (f < 0) {
|
||||||
|
return -1 * Decimal{convert_to_u64((-1 * f).numerator())}.div(convert_to_u64(f.denominator()), c);
|
||||||
|
} else {
|
||||||
|
return Decimal{convert_to_u64(f.numerator())}.div(convert_to_u64(f.denominator()), c);
|
||||||
|
}
|
||||||
|
}
|
@ -42,11 +42,22 @@ public:
|
|||||||
friend Fraction operator%(Fraction a, const Fraction& b);
|
friend Fraction operator%(Fraction a, const Fraction& b);
|
||||||
friend std::strong_ordering operator<=>(const Fraction& lhs, const Fraction& rhs);
|
friend std::strong_ordering operator<=>(const Fraction& lhs, const Fraction& rhs);
|
||||||
friend std::ostream& operator<<(std::ostream& os, const Fraction& obj);
|
friend std::ostream& operator<<(std::ostream& os, const Fraction& obj);
|
||||||
|
friend struct fmt::formatter<Fraction>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mpq_class value;
|
mpq_class value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct fmt::formatter<Fraction>: formatter<string_view> {
|
||||||
|
// parse is inherited from formatter<string_view>.
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const Fraction& c, FormatContext& ctx) {
|
||||||
|
return formatter<string_view>::format(c.value.get_str(), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const auto mpz_uint64_max = mpz_class(fmt::format("{}", UINT64_MAX));
|
const auto mpz_uint64_max = mpz_class(fmt::format("{}", UINT64_MAX));
|
||||||
const auto mpz_int64_min = mpz_class(fmt::format("{}", INT64_MIN));
|
const auto mpz_int64_min = mpz_class(fmt::format("{}", INT64_MIN));
|
||||||
const auto mpz_int64_max = mpz_class(fmt::format("{}", INT64_MAX));
|
const auto mpz_int64_max = mpz_class(fmt::format("{}", INT64_MAX));
|
||||||
@ -62,6 +73,8 @@ Fraction convert_to_fraction(const Decimal& d);
|
|||||||
Fraction round_beats(Fraction beats, std::uint64_t denominator = 240);
|
Fraction round_beats(Fraction beats, std::uint64_t denominator = 240);
|
||||||
Fraction floor_beats(Fraction beats, std::uint64_t denominator = 240);
|
Fraction floor_beats(Fraction beats, std::uint64_t denominator = 240);
|
||||||
|
|
||||||
|
Decimal convert_to_decimal(const Fraction& f, unsigned int decimal_places);
|
||||||
|
|
||||||
// Stolen from :
|
// Stolen from :
|
||||||
// https://github.com/progrock-libraries/kickstart/blob/master/source/library/kickstart/main_library/core/ns%E2%96%B8language/operations/intpow.hpp#L36
|
// https://github.com/progrock-libraries/kickstart/blob/master/source/library/kickstart/main_library/core/ns%E2%96%B8language/operations/intpow.hpp#L36
|
||||||
// Essentially this is Horner's rule adapted to calculating a power, so that the
|
// Essentially this is Horner's rule adapted to calculating a power, so that the
|
||||||
|
26
src/tests/doctest/decimals.cpp
Normal file
26
src/tests/doctest/decimals.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <doctest.h>
|
||||||
|
|
||||||
|
#include "../../special_numeric_types.hpp"
|
||||||
|
|
||||||
|
TEST_CASE("Decimals") {
|
||||||
|
SUBCASE("can be constructed from") {
|
||||||
|
SUBCASE("integers, exactly") {
|
||||||
|
CHECK(Decimal{1} == Decimal{"1"});
|
||||||
|
CHECK(Decimal{-2} == Decimal{"-2"});
|
||||||
|
}
|
||||||
|
SUBCASE("strings, exactly") {
|
||||||
|
CHECK(Decimal{"0.0001"} == Decimal{1} / Decimal{10000});
|
||||||
|
}
|
||||||
|
SUBCASE("fractions, rounded to a given number of decimal places") {
|
||||||
|
CHECK(convert_to_decimal({1,3}, 3) == Decimal{"0.333"});
|
||||||
|
CHECK(convert_to_decimal({-1,3}, 3) == Decimal{"-0.333"});
|
||||||
|
CHECK(convert_to_decimal({1,7}, 5) == Decimal{"0.14286"});
|
||||||
|
CHECK(convert_to_decimal({123456,1000}, 1) == Decimal{"123.5"});
|
||||||
|
CHECK(convert_to_decimal({1234,1000}, 1) == Decimal{"1.2"});
|
||||||
|
CHECK(convert_to_decimal({1000,1234}, 1) == Decimal{"0.8"});
|
||||||
|
CHECK(convert_to_decimal({1,777}, 1) == Decimal{"0.0"});
|
||||||
|
CHECK(convert_to_decimal({1,777}, 5) == Decimal{"0.00129"});
|
||||||
|
CHECK(convert_to_decimal({1,777}, 3) == Decimal{"0.001"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,7 @@ TEST_CASE("Fractions") {
|
|||||||
SUBCASE("can be cast to") {
|
SUBCASE("can be cast to") {
|
||||||
SUBCASE("std::int64_t, returing the integral part") {
|
SUBCASE("std::int64_t, returing the integral part") {
|
||||||
CHECK(static_cast<std::int64_t>(Fraction{1,2}) == INT64_C(0));
|
CHECK(static_cast<std::int64_t>(Fraction{1,2}) == INT64_C(0));
|
||||||
|
CHECK(static_cast<std::int64_t>(Fraction{2,3}) == INT64_C(0));
|
||||||
CHECK(static_cast<std::int64_t>(Fraction{-5,2}) == INT64_C(-2));
|
CHECK(static_cast<std::int64_t>(Fraction{-5,2}) == INT64_C(-2));
|
||||||
CHECK(static_cast<std::int64_t>(Fraction{"-9223372036854775808/1"}) == INT64_MIN);
|
CHECK(static_cast<std::int64_t>(Fraction{"-9223372036854775808/1"}) == INT64_MIN);
|
||||||
CHECK(static_cast<std::int64_t>(Fraction{"9223372036854775807/1"}) == INT64_MAX);
|
CHECK(static_cast<std::int64_t>(Fraction{"9223372036854775807/1"}) == INT64_MAX);
|
||||||
|
@ -2,6 +2,7 @@ doctest_tests = executable(
|
|||||||
'doctest_tests',
|
'doctest_tests',
|
||||||
'main.cpp',
|
'main.cpp',
|
||||||
'fractions.cpp',
|
'fractions.cpp',
|
||||||
|
'decimals.cpp',
|
||||||
'../../special_numeric_types.cpp',
|
'../../special_numeric_types.cpp',
|
||||||
include_sources['fmt'],
|
include_sources['fmt'],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
15
src/tests/rapidcheck/generators.cpp
Normal file
15
src/tests/rapidcheck/generators.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "generators.hpp"
|
||||||
|
#include "rapidcheck/gen/Arbitrary.hpp"
|
||||||
|
|
||||||
|
namespace rc {
|
||||||
|
template <>
|
||||||
|
Gen<Fraction> gen::positive() {
|
||||||
|
return gen::apply([](const Fraction& a, unsigned int b, unsigned int c) {
|
||||||
|
return a + Fraction{std::min(b, c), std::max(b, c)};
|
||||||
|
},
|
||||||
|
gen::construct<Fraction>(gen::inRange<unsigned int>(0,100)),
|
||||||
|
gen::inRange<unsigned int>(1,10),
|
||||||
|
gen::inRange<unsigned int>(1,10)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
@ -1,9 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
#include <rapidcheck.h>
|
#include <rapidcheck.h>
|
||||||
#include <rapidcheck/gen/Arbitrary.h>
|
#include <rapidcheck/gen/Arbitrary.h>
|
||||||
#include <rapidcheck/gen/Numeric.h>
|
#include <rapidcheck/gen/Numeric.h>
|
||||||
|
|
||||||
|
#include "../../better_note.hpp"
|
||||||
#include "../../better_notes.hpp"
|
#include "../../better_notes.hpp"
|
||||||
|
#include "../../better_timing.hpp"
|
||||||
#include "../../variant_visitor.hpp"
|
#include "../../variant_visitor.hpp"
|
||||||
|
#include "rapidcheck/gen/Exec.h"
|
||||||
|
|
||||||
namespace rc {
|
namespace rc {
|
||||||
template<>
|
template<>
|
||||||
@ -18,34 +23,19 @@ namespace rc {
|
|||||||
template<>
|
template<>
|
||||||
struct Arbitrary<Fraction> {
|
struct Arbitrary<Fraction> {
|
||||||
static Gen<Fraction> arbitrary() {
|
static Gen<Fraction> arbitrary() {
|
||||||
return gen::apply([](const Fraction& a, const Fraction& b) {
|
return gen::apply([](const Fraction& a, unsigned int b, unsigned int c) {
|
||||||
return a + b;
|
return a + Fraction{std::min(b, c), std::max(b, c)};
|
||||||
},
|
},
|
||||||
gen::cast<Fraction>(
|
gen::construct<Fraction>(gen::inRange<unsigned int>(0,100)),
|
||||||
gen::nonNegative<unsigned>()
|
gen::inRange<unsigned int>(0,10),
|
||||||
),
|
gen::inRange<unsigned int>(1,10)
|
||||||
gen::construct<Fraction>(
|
|
||||||
gen::nonNegative<unsigned>(),
|
|
||||||
gen::positive<unsigned>()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Gen<Fraction> positive() {
|
|
||||||
return gen::apply([](const Fraction& a, const Fraction& b) {
|
|
||||||
return a + b;
|
|
||||||
},
|
|
||||||
gen::cast<Fraction>(
|
|
||||||
gen::nonNegative<unsigned>()
|
|
||||||
),
|
|
||||||
gen::construct<Fraction>(
|
|
||||||
gen::positive<unsigned>(),
|
|
||||||
gen::positive<unsigned>()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
Gen<Fraction> gen::positive();
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct Arbitrary<better::TapNote> {
|
struct Arbitrary<better::TapNote> {
|
||||||
static Gen<better::TapNote> arbitrary() {
|
static Gen<better::TapNote> arbitrary() {
|
||||||
@ -59,16 +49,29 @@ namespace rc {
|
|||||||
template<>
|
template<>
|
||||||
struct Arbitrary<better::LongNote> {
|
struct Arbitrary<better::LongNote> {
|
||||||
static Gen<better::LongNote> arbitrary() {
|
static Gen<better::LongNote> arbitrary() {
|
||||||
const auto pos = *gen::arbitrary<better::Position>();
|
return gen::apply(
|
||||||
const auto tail_6_notation = *gen::inRange<unsigned int>(0, 6);
|
[](
|
||||||
const auto tail_pos = better::convert_6_notation_to_position(pos, tail_6_notation);
|
const Fraction& time,
|
||||||
return gen::construct<better::LongNote>(
|
const better::Position& position,
|
||||||
|
const Fraction& duration,
|
||||||
|
unsigned int tail_6_notation
|
||||||
|
){
|
||||||
|
const auto tail_tip = better::convert_6_notation_to_position(
|
||||||
|
position, tail_6_notation
|
||||||
|
);
|
||||||
|
return better::LongNote{
|
||||||
|
time,
|
||||||
|
position,
|
||||||
|
duration,
|
||||||
|
tail_tip,
|
||||||
|
};
|
||||||
|
},
|
||||||
gen::arbitrary<Fraction>(),
|
gen::arbitrary<Fraction>(),
|
||||||
gen::just(pos),
|
gen::arbitrary<better::Position>(),
|
||||||
gen::positive<Fraction>(),
|
gen::positive<Fraction>(),
|
||||||
gen::just(tail_pos)
|
gen::inRange<unsigned int>(0, 6)
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@ -84,32 +87,51 @@ namespace rc {
|
|||||||
template<>
|
template<>
|
||||||
struct Arbitrary<better::Notes> {
|
struct Arbitrary<better::Notes> {
|
||||||
static Gen<better::Notes> arbitrary() {
|
static Gen<better::Notes> arbitrary() {
|
||||||
const auto raw_note = *
|
return gen::exec([](){
|
||||||
gen::tuple(
|
const auto raw_notes = *gen::container<std::vector<std::tuple<better::Position, Fraction, Fraction>>>(gen::tuple(
|
||||||
gen::arbitrary<better::Position>(),
|
gen::arbitrary<better::Position>(),
|
||||||
gen::positive<Fraction>(),
|
gen::positive<Fraction>(),
|
||||||
gen::arbitrary<Fraction>()
|
gen::arbitrary<Fraction>()
|
||||||
)
|
));
|
||||||
;
|
std::array<Fraction, 16> last_note_end = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||||
std::vector<std::tuple<better::Position, Fraction, Fraction>> raw_notes = {raw_note};
|
better::Notes result;
|
||||||
std::array<Fraction, 16> last_note_end = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
for (const auto& [position, delay, duration]: raw_notes) {
|
||||||
better::Notes result;
|
if (duration > 0) {
|
||||||
for (const auto& [position, delay, duration]: raw_notes) {
|
const auto tail_6_notation = *gen::inRange<unsigned int>(0, 6);
|
||||||
if (duration > 0) {
|
const auto tail_tip = better::convert_6_notation_to_position(position, tail_6_notation);
|
||||||
const auto tail_6_notation = *gen::inRange<unsigned int>(0, 6);
|
auto& end = last_note_end[position.index()];
|
||||||
const auto tail_tip = better::convert_6_notation_to_position(position, tail_6_notation);
|
const auto time = end + delay;
|
||||||
auto& end = last_note_end[position.index()];
|
end += delay + duration;
|
||||||
const auto time = end + delay;
|
result.insert(better::LongNote{time, position, duration, tail_tip});
|
||||||
end += delay + duration;
|
} else {
|
||||||
result.insert(better::LongNote{time, position, duration, tail_tip});
|
auto& end = last_note_end[position.index()];
|
||||||
} else {
|
const auto time = end + delay;
|
||||||
auto& end = last_note_end[position.index()];
|
end += delay;
|
||||||
const auto time = end + delay;
|
result.insert(better::TapNote{time, position});
|
||||||
end += delay;
|
}
|
||||||
result.insert(better::TapNote{time, position});
|
|
||||||
}
|
}
|
||||||
}
|
return result;
|
||||||
return gen::just(result);
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Arbitrary<Decimal> {
|
||||||
|
static Gen<Decimal> arbitrary() {
|
||||||
|
return gen::apply([](unsigned int a)
|
||||||
|
gen::construct<better::Note>(gen::arbitrary<better::TapNote>()),
|
||||||
|
gen::construct<better::Note>(gen::arbitrary<better::LongNote>())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Arbitrary<better::Timing> {
|
||||||
|
static Gen<better::Timing> arbitrary() {
|
||||||
|
return gen::oneOf(
|
||||||
|
gen::construct<better::Note>(gen::arbitrary<better::TapNote>()),
|
||||||
|
gen::construct<better::Note>(gen::arbitrary<better::LongNote>())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -1,26 +1,44 @@
|
|||||||
#include <rapidcheck.h>
|
#include <rapidcheck.h>
|
||||||
|
#include <rapidcheck/Check.h>
|
||||||
|
#include <rapidcheck/Classify.h>
|
||||||
|
#include <rapidcheck/Log.h>
|
||||||
|
|
||||||
#include "generators.hpp"
|
#include "generators.hpp"
|
||||||
|
|
||||||
#include "../../better_note.hpp"
|
#include "../../better_note.hpp"
|
||||||
|
#include "../../better_notes.hpp"
|
||||||
|
#include "../../better_timing.hpp"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
|
|
||||||
rc::check(
|
rc::check(
|
||||||
"A Note survives being converted to json and back",
|
"A Note survives being converted to json and back",
|
||||||
[](const better::Note& n) {
|
[](const better::Note& n) {
|
||||||
const auto j = n.dump_to_memon_1_0_0();
|
const auto j = n.dump_to_memon_1_0_0();
|
||||||
|
RC_LOG("json dump : "+j.dump());
|
||||||
const auto n_recovered = better::Note::load_from_memon_1_0_0(j);
|
const auto n_recovered = better::Note::load_from_memon_1_0_0(j);
|
||||||
RC_ASSERT(n_recovered == n);
|
RC_ASSERT(n_recovered == n);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
rc::check(
|
rc::check(
|
||||||
"A set of Notes survive being converted to json and back",
|
"A set of Notes survives being converted to json and back",
|
||||||
[](const better::Notes& ns) {
|
[](const better::Notes& original) {
|
||||||
const auto j = ns.dump_to_memon_1_0_0();
|
const auto j = original.dump_to_memon_1_0_0();
|
||||||
RC_TAG(j.dump());
|
RC_LOG("json dump : "+j.dump());
|
||||||
const auto n_recovered = better::Notes::load_from_memon_1_0_0(j);
|
const auto recovered = better::Notes::load_from_memon_1_0_0(j);
|
||||||
RC_ASSERT(n_recovered == ns);
|
RC_ASSERT(original == recovered);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
rc::check(
|
||||||
|
"A Timing object survives being converted to json and back",
|
||||||
|
[](const better::Timing& original) {
|
||||||
|
const auto j = original.dump_to_memon_1_0_0();
|
||||||
|
RC_LOG("json dump : "+j.dump());
|
||||||
|
const auto recovered = better::Timing::load_from_memon_1_0_0(j);
|
||||||
|
RC_ASSERT(original == recovered);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
rapidcheck_tests = executable(
|
rapidcheck_tests = executable(
|
||||||
'rapidcheck_tests',
|
'rapidcheck_tests',
|
||||||
|
'generators.cpp',
|
||||||
'main.cpp',
|
'main.cpp',
|
||||||
'../../better_beats.cpp',
|
'../../better_beats.cpp',
|
||||||
'../../better_note.cpp',
|
'../../better_note.cpp',
|
||||||
|
@ -102,23 +102,23 @@ void LinearView::update(
|
|||||||
while (next_beat_line_y < y) {
|
while (next_beat_line_y < y) {
|
||||||
if (next_beat % 4 == 0) {
|
if (next_beat % 4 == 0) {
|
||||||
beat_line.setFillColor(sf::Color::White);
|
beat_line.setFillColor(sf::Color::White);
|
||||||
beat_line.setPosition({timeline_x, static_cast<float>(next_beat_line_y.get_d())});
|
beat_line.setPosition({timeline_x, static_cast<float>(static_cast<double>(next_beat_line_y))});
|
||||||
view.draw(beat_line);
|
view.draw(beat_line);
|
||||||
|
|
||||||
ss.str(std::string());
|
ss.str(std::string());
|
||||||
const Fraction measure = next_beat / 4;
|
const Fraction measure = next_beat / 4;
|
||||||
ss << static_cast<int>(measure.get_d());
|
ss << static_cast<int>(static_cast<double>(measure));
|
||||||
beat_number.setString(ss.str());
|
beat_number.setString(ss.str());
|
||||||
sf::FloatRect textRect = beat_number.getLocalBounds();
|
sf::FloatRect textRect = beat_number.getLocalBounds();
|
||||||
beat_number.setOrigin(
|
beat_number.setOrigin(
|
||||||
textRect.left + textRect.width,
|
textRect.left + textRect.width,
|
||||||
textRect.top + textRect.height / 2.f);
|
textRect.top + textRect.height / 2.f);
|
||||||
beat_number.setPosition({40.f, static_cast<float>(next_beat_line_y.get_d())});
|
beat_number.setPosition({40.f, static_cast<float>(static_cast<double>(next_beat_line_y))});
|
||||||
view.draw(beat_number);
|
view.draw(beat_number);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
beat_line.setFillColor(sf::Color(255, 255, 255, 127));
|
beat_line.setFillColor(sf::Color(255, 255, 255, 127));
|
||||||
beat_line.setPosition({timeline_x, static_cast<float>(next_beat_line_y.get_d())});
|
beat_line.setPosition({timeline_x, static_cast<float>(static_cast<double>(next_beat_line_y))});
|
||||||
view.draw(beat_line);
|
view.draw(beat_line);
|
||||||
}
|
}
|
||||||
next_beat += 1;
|
next_beat += 1;
|
||||||
@ -140,15 +140,15 @@ void LinearView::update(
|
|||||||
auto draw_note = VariantVisitor {
|
auto draw_note = VariantVisitor {
|
||||||
[&, this](const better::TapNote& tap_note){
|
[&, this](const better::TapNote& tap_note){
|
||||||
float note_x = timeline_x + note_width * (tap_note.get_position().index() + 0.5f);
|
float note_x = timeline_x + note_width * (tap_note.get_position().index() + 0.5f);
|
||||||
float note_y = static_cast<float>(beats_to_pixels_absolute.transform(tap_note.get_time()).get_d());
|
float note_y = static_cast<double>(beats_to_pixels_absolute.transform(tap_note.get_time()));
|
||||||
const auto note_seconds = timing.time_at(tap_note.get_time());
|
const auto note_seconds = timing.time_at(tap_note.get_time());
|
||||||
const auto first_colliding_beat = timing.beats_at(note_seconds - sf::milliseconds(500));
|
const auto first_colliding_beat = timing.beats_at(note_seconds - sf::milliseconds(500));
|
||||||
const auto collision_zone_y = beats_to_pixels_absolute.transform(first_colliding_beat);
|
const auto collision_zone_y = beats_to_pixels_absolute.transform(first_colliding_beat);
|
||||||
const auto last_colliding_beat = timing.beats_at(note_seconds + sf::milliseconds(500));
|
const auto last_colliding_beat = timing.beats_at(note_seconds + sf::milliseconds(500));
|
||||||
const auto collision_zone_height = beats_to_pixels_proportional.transform(last_colliding_beat - first_colliding_beat);
|
const auto collision_zone_height = beats_to_pixels_proportional.transform(last_colliding_beat - first_colliding_beat);
|
||||||
note_collision_zone.setSize({collizion_zone_width, static_cast<float>(collision_zone_height.get_d())});
|
note_collision_zone.setSize({collizion_zone_width, static_cast<float>(static_cast<double>(collision_zone_height))});
|
||||||
Toolbox::set_local_origin_normalized(note_collision_zone, 0.5f, 0.f);
|
Toolbox::set_local_origin_normalized(note_collision_zone, 0.5f, 0.f);
|
||||||
note_collision_zone.setPosition(note_x, static_cast<float>(collision_zone_y.get_d()));
|
note_collision_zone.setPosition(note_x, static_cast<float>(static_cast<double>(collision_zone_y)));
|
||||||
this->view.draw(note_collision_zone);
|
this->view.draw(note_collision_zone);
|
||||||
tap_note_rect.setPosition(note_x, note_y);
|
tap_note_rect.setPosition(note_x, note_y);
|
||||||
this->view.draw(tap_note_rect);
|
this->view.draw(tap_note_rect);
|
||||||
@ -159,19 +159,19 @@ void LinearView::update(
|
|||||||
},
|
},
|
||||||
[&, this](const better::LongNote& long_note){
|
[&, this](const better::LongNote& long_note){
|
||||||
float note_x = timeline_x + note_width * (long_note.get_position().index() + 0.5f);
|
float note_x = timeline_x + note_width * (long_note.get_position().index() + 0.5f);
|
||||||
float note_y = static_cast<float>(beats_to_pixels_absolute.transform(long_note.get_time()).get_d());
|
float note_y = static_cast<double>(beats_to_pixels_absolute.transform(long_note.get_time()));
|
||||||
const auto note_start_seconds = timing.time_at(long_note.get_time());
|
const auto note_start_seconds = timing.time_at(long_note.get_time());
|
||||||
const auto first_colliding_beat = timing.beats_at(note_start_seconds - sf::milliseconds(500));
|
const auto first_colliding_beat = timing.beats_at(note_start_seconds - sf::milliseconds(500));
|
||||||
const auto collision_zone_y = beats_to_pixels_absolute.transform(first_colliding_beat);
|
const auto collision_zone_y = beats_to_pixels_absolute.transform(first_colliding_beat);
|
||||||
const auto note_end_seconds = timing.time_at(long_note.get_end());
|
const auto note_end_seconds = timing.time_at(long_note.get_end());
|
||||||
const auto last_colliding_beat = timing.beats_at(note_end_seconds + sf::milliseconds(500));
|
const auto last_colliding_beat = timing.beats_at(note_end_seconds + sf::milliseconds(500));
|
||||||
const auto collision_zone_height = beats_to_pixels_proportional.transform(last_colliding_beat - first_colliding_beat);
|
const auto collision_zone_height = beats_to_pixels_proportional.transform(last_colliding_beat - first_colliding_beat);
|
||||||
note_collision_zone.setSize({collizion_zone_width, static_cast<float>(collision_zone_height.get_d())});
|
note_collision_zone.setSize({collizion_zone_width, static_cast<float>(static_cast<double>(collision_zone_height))});
|
||||||
Toolbox::set_local_origin_normalized(note_collision_zone, 0.5f, 0.f);
|
Toolbox::set_local_origin_normalized(note_collision_zone, 0.5f, 0.f);
|
||||||
note_collision_zone.setPosition(note_x, static_cast<float>(collision_zone_y.get_d()));
|
note_collision_zone.setPosition(note_x, static_cast<float>(static_cast<double>(collision_zone_y)));
|
||||||
this->view.draw(note_collision_zone);
|
this->view.draw(note_collision_zone);
|
||||||
const auto long_note_rect_height = beats_to_pixels_proportional.transform(long_note.get_duration());
|
const auto long_note_rect_height = beats_to_pixels_proportional.transform(long_note.get_duration());
|
||||||
long_note_rect.setSize({long_note_rect_width, static_cast<float>(long_note_rect_height.get_d())});
|
long_note_rect.setSize({long_note_rect_width, static_cast<float>(static_cast<double>(long_note_rect_height))});
|
||||||
Toolbox::set_local_origin_normalized(long_note_rect, 0.5f, 0.f);
|
Toolbox::set_local_origin_normalized(long_note_rect, 0.5f, 0.f);
|
||||||
long_note_rect.setPosition(note_x, note_y);
|
long_note_rect.setPosition(note_x, note_y);
|
||||||
this->view.draw(long_note_rect);
|
this->view.draw(long_note_rect);
|
||||||
@ -212,9 +212,9 @@ void LinearView::update(
|
|||||||
if (pixel_interval.intersects({0, y})) {
|
if (pixel_interval.intersects({0, y})) {
|
||||||
selection.setSize({
|
selection.setSize({
|
||||||
selection_width,
|
selection_width,
|
||||||
static_cast<float>(pixel_interval.width().get_d()),
|
static_cast<float>(static_cast<double>(pixel_interval.width())),
|
||||||
});
|
});
|
||||||
selection.setPosition(timeline_x, static_cast<float>(pixel_interval.start.get_d()));
|
selection.setPosition(timeline_x, static_cast<double>(pixel_interval.start));
|
||||||
view.draw(selection);
|
view.draw(selection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user