From 00d3a4f105c8040828b461dada9769315146dd77 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 17 May 2019 19:59:26 +1000 Subject: [PATCH] added full rational class --- global/rational.cpp | 366 ++++++++++++++++++++++++++++++++++++++ global/rational.h | 60 ++++++- nodes/nodeio.cpp | 10 ++ nodes/nodeio.h | 20 +++ nodes/nodes/nodeblock.cpp | 47 ++++- nodes/nodes/nodeblock.h | 21 ++- 6 files changed, 511 insertions(+), 13 deletions(-) diff --git a/global/rational.cpp b/global/rational.cpp index 66fc7b288..a1a45b6fd 100644 --- a/global/rational.cpp +++ b/global/rational.cpp @@ -1,2 +1,368 @@ #include "rational.h" +rational::rational(const int &numerator) : + numerator_(numerator), + denominator_(1) +{ + if (numerator_ == 0) { + denominator_ = 0; + } +} + +rational::rational(const int &numerator, const int &denominator) : + numerator_(numerator), + denominator_(denominator) +{ + if (denominator_ != 0) { + + if (numerator_ != 0) { + FixSigns(); + Reduce(); + } else { + denominator_ = 0; + } + + } else { + numerator_ = 0; + } +} + +rational::rational(const AVRational &r) : + numerator_(r.num), + denominator_(r.den) +{ +} + +rational::rational(const rational &r) : + numerator_(r.numerator_), + denominator_(r.denominator_) +{ +} + +const rational &rational::operator=(const rational &r) +{ + if (this != &r) { + numerator_ = r.numerator_; + denominator_ = r.denominator_; + } + + return *this; +} + +const rational &rational::operator+=(const rational &r) +{ + if (numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { + numerator_ = 0; + denominator_ = 0; + } else { + if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { + // The other rational == 0, no addition needs to be done + } else { + if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) + { + numerator_ = r.numerator_; + denominator_ = r.denominator_; + } + else + { + numerator_ = (numerator_ * r.denominator_) + (r.numerator_ * denominator_); + denominator_ = denominator_ * r.denominator_; + FixSigns(); + Reduce(); + } + } + } + return *this; +} + +const rational &rational::operator-=(const rational &r) +{ + if(numerator_ * denominator_ == 0 && r.numerator_ * r.numerator_ == 0) { + numerator_ = 0; + denominator_ = 0; + } else { + if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { + + } else { + if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { + numerator_ = -(r.numerator_); + denominator_ = r.denominator_; + } else { + numerator_ = (numerator_ * r.denominator_) - (r.numerator_ * denominator_); + numerator_ = denominator_ * r.denominator_; + FixSigns(); + Reduce(); + } + } + } + return *this; +} + +const rational &rational::operator/=(const rational &r) +{ + numerator_ = numerator_ * r.denominator_; + denominator_ = denominator_ * r.numerator_; + FixSigns(); + Reduce(); + return *this; +} + +const rational &rational::operator*=(const rational &r) +{ + numerator_ = numerator_ * r.numerator_; + denominator_ = denominator_ * r.denominator_; + FixSigns(); + Reduce(); + return *this; +} + +rational rational::operator+(const rational &r) const +{ + rational result(*this); + result += r; + return result; +} + +rational rational::operator-(const rational &r) const +{ + rational result(*this); + result -= r; + return result; +} + +rational rational::operator/(const rational &r) const +{ + rational result(*this); + result /= r; + return result; +} + +rational rational::operator*(const rational &r) const +{ + rational result(*this); + result *= r; + return result; +} + +bool rational::operator<(const rational &r) const +{ + if (numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { + return false; + } else { + if (numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { + if(numerator_ * denominator_ < 0) + return true; + else + return false; + } + else { + if (numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { + if (r.numerator_ * r.denominator_ < 0) { + return false; + } else { + return true; + } + } else { + return ((numerator_ * r.denominator_) < (denominator_ * r.numerator_)); + } + } + } +} + +bool rational::operator<=(const rational &r) const +{ + if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { + return true; + } else { + if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { + if(numerator_ * denominator_ < 0) { + return true; + } else { + return false; + } + } else { + if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { + if(r.numerator_ * r.denominator_ < 0) { + return false; + } else { + return true; + } + } else { + return ((numerator_ * r.denominator_) <= (denominator_ * r.numerator_)); + } + } + } +} + +bool rational::operator>(const rational &r) const +{ + if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { + return false; + } else { + if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { + if(numerator_ * denominator_ > 0) { + return true; + } else { + return false; + } + } else { + if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { + if(r.numerator_ * r.denominator_ > 0) { + return false; + } else { + return true; + } + } else { + return ((numerator_ * r.denominator_) > (denominator_ * r.numerator_)); + } + } + } +} + +bool rational::operator>=(const rational &r) const +{ + if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { + return true; + } else { + if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { + if(numerator_ * denominator_ > 0) { + return true; + } else { + return false; + } + } else { + if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { + if(r.numerator_ * r.denominator_ > 0) { + return false; + } else { + return true; + } + } else { + return ((numerator_ * r.denominator_) >= (denominator_ * r.numerator_)); + } + } + } +} + +bool rational::operator==(const rational &r) const +{ + return (numerator_ == r.numerator_ && denominator_ == r.denominator_); +} + +bool rational::operator!=(const rational &r) const +{ + return (numerator_ != r.numerator_) || (denominator_ != r.denominator_); +} + +const rational &rational::operator++() +{ + numerator_ += denominator_; + return *this; +} + +rational rational::operator++(int) +{ + rational tmp = *this; + numerator_ += denominator_; + return tmp; +} + +const rational &rational::operator--() +{ + numerator_ -= denominator_; + return *this; +} + +rational rational::operator--(int) +{ + rational tmp; + numerator_ -= denominator_; + return tmp; +} + +const rational &rational::operator+() const +{ + return *this; +} + +rational rational::operator-() const +{ + return rational(numerator_, -denominator_); +} + +bool rational::operator!() const +{ + return !numerator_; +} + +void rational::FixSigns() +{ + // Ensures denominator is always positive (while numerator can be positive or negative) + if(denominator_ < 0) { + denominator_ = -denominator_; + numerator_ = -numerator_; + } + + // Ensures if either are zero, they're both zero + if(numerator_ == 0 || denominator_ == 0) { + numerator_ = 0; + denominator_ = 0; + } +} + +void rational::Reduce() +{ + int d = 1; + + if(denominator_ != 0 && numerator_ != 0) { + d = GreatestCommonDenominator(numerator_, denominator_); + } + + if(d > 1) { + numerator_ /= d; + denominator_ /= d; + } +} + +int rational::GreatestCommonDenominator(const int& x, const int& y) +{ + if (y == 0) { + return x; + } else { + int tmp = x % y; + return GreatestCommonDenominator(y, tmp); + } +} + +std::ostream &operator<<(std::ostream &out, const rational &value) +{ + out << value.numerator_; + if(value.denominator_ != 1) + { + out << '/' << value.denominator_; + return out; + } + return out; +} + +std::istream &operator>>(std::istream &in, rational &value) +{ + in >> value.numerator_; + value.denominator_ = 1; + + char ch; + in.get(ch); + + if(!in.eof()) + { + if(ch == '/') + { + in >> value.denominator_; + value.FixSigns(); + value.Reduce(); + } + else + in.putback(ch); + } + return in; +} diff --git a/global/rational.h b/global/rational.h index b02b0caca..84c7c27d4 100644 --- a/global/rational.h +++ b/global/rational.h @@ -1,14 +1,62 @@ #ifndef RATIONAL_H #define RATIONAL_H +// Adapted from https://github.com/angularadam/Qt-Class-rational used in compliance with the GNU General Public License + +#include #include -namespace olive { - /** - * Rational type for timeline values. Currently we just use FFmpeg's AVRational for ease but we can change this - * later if we want. - */ - using rational = AVRational; +class rational { +public: + // Constructors + rational(const int& numerator = 0); + rational(const int& numerator, const int& denominator); + rational(const AVRational& r); // Auto-convert from an FFmpeg AVRational + rational(const rational& r); + + // Assignment Operators + const rational& operator=(const rational& r); + const rational& operator+=(const rational& r); + const rational& operator-=(const rational& r); + const rational& operator/=(const rational& r); + const rational& operator*=(const rational& r); + + // Math Operators + rational operator+(const rational& r) const; + rational operator-(const rational& r) const; + rational operator/(const rational& r) const; + rational operator*(const rational& r) const; + + // Relational and Equality Operators + bool operator<(const rational &r) const; + bool operator<=(const rational &r) const; + bool operator>(const rational &r) const; + bool operator>=(const rational &r) const; + bool operator==(const rational &r) const; + bool operator!=(const rational &r) const; + + //Unary operators + const rational& operator++(); //prefix + rational operator++(int); //postfix + const rational& operator--(); //prefix + rational operator--(int); //postfix + const rational& operator+() const; + rational operator-() const; + bool operator!() const; + + // IO + friend std::ostream& operator<<(std::ostream &out, const rational& value); + friend std::istream& operator>>(std::istream &in, rational& value); + + // Convert to double + double ToDouble() const; +private: + int numerator_; + int denominator_; + + void FixSigns(); + void Reduce(); + int GreatestCommonDenominator(const int &x, const int &y); }; #endif // RATIONAL_H diff --git a/nodes/nodeio.cpp b/nodes/nodeio.cpp index 4e82a52a1..6f31ee53e 100644 --- a/nodes/nodeio.cpp +++ b/nodes/nodeio.cpp @@ -136,6 +136,11 @@ bool NodeIO::IsKeyframable() return keyframable_; } +QVariant NodeIO::GetValue() +{ + return GetValueAt(0); +} + QVariant NodeIO::GetValueAt(double timecode) { if (FieldCount() == 0) { @@ -147,6 +152,11 @@ QVariant NodeIO::GetValueAt(double timecode) return Field(0)->GetValueAt(timecode); } +void NodeIO::SetValue(const QVariant &value) +{ + SetValueAt(0, value); +} + void NodeIO::SetValueAt(double timecode, const QVariant &value) { if (FieldCount() == 0) { diff --git a/nodes/nodeio.h b/nodes/nodeio.h index 215e6cc47..7e99c1076 100644 --- a/nodes/nodeio.h +++ b/nodes/nodeio.h @@ -174,6 +174,16 @@ public: */ bool IsKeyframable(); + /** + * @brief Get value + * + * A convenience value for a parameters that doesn't keyframe. Equivalent to GetValueAt(0) where the parameter + * doesn't keyframe so the 0 is ignored. + * + * @param value + */ + QVariant GetValue(); + /** * @brief Get value at a given timecode * @@ -193,6 +203,16 @@ public: */ virtual QVariant GetValueAt(double timecode); + /** + * @brief Set value + * + * A convenience value for a parameters that doesn't keyframe. Equivalent to SetValueAt(0, value) where the parameter + * doesn't keyframe so the 0 is ignored. + * + * @param value + */ + void SetValue(const QVariant& value); + /** * @brief SetValueAt * diff --git a/nodes/nodes/nodeblock.cpp b/nodes/nodes/nodeblock.cpp index fc0ca9472..063d70cf0 100644 --- a/nodes/nodes/nodeblock.cpp +++ b/nodes/nodes/nodeblock.cpp @@ -5,14 +5,42 @@ NodeBlock::NodeBlock(NodeGraph *graph) : { previous_block_ = new NodeIO(this, "prev_block", tr("Previous"), true, false); previous_block_->AddAcceptedNodeInput(olive::nodes::kBlock); - + previous_block_->SetValue(0); AddParameter(previous_block_); next_block_ = new NodeIO(this, "next_block", tr("Next"), true, false); - previous_block_->SetOutputDataType(olive::nodes::kBlock); + next_block_->SetOutputDataType(olive::nodes::kBlock); + next_block_->SetValue(0); AddParameter(next_block_); } +rational NodeBlock::track_in() +{ + rational in_point; + + NodeBlock* previous = previous_block(); + while (previous != nullptr) { + in_point += previous->length(); + } + + return in_point; +} + +rational NodeBlock::track_out() +{ + return track_in() + length(); +} + +const rational &NodeBlock::length() +{ + return length_; +} + +void NodeBlock::set_length(const rational &l) +{ + length_ = l; +} + QString NodeBlock::name() { return tr("Block"); @@ -25,5 +53,20 @@ QString NodeBlock::id() NodeBlock *NodeBlock::previous_block() { + return reinterpret_cast(previous_block_->GetValue().value()); +} +void NodeBlock::set_previous_block(NodeBlock *p) +{ + previous_block_->SetValue(reinterpret_cast(p)); +} + +NodeBlock *NodeBlock::next_block() +{ + return reinterpret_cast(next_block_->GetValue().value()); +} + +void NodeBlock::set_next_block(NodeBlock *p) +{ + next_block_->SetValue(reinterpret_cast(p)); } diff --git a/nodes/nodes/nodeblock.h b/nodes/nodes/nodeblock.h index 8d70adecd..f57e452e9 100644 --- a/nodes/nodes/nodeblock.h +++ b/nodes/nodes/nodeblock.h @@ -15,20 +15,31 @@ class NodeBlock : public Node public: NodeBlock(NodeGraph* graph); - const olive::rational& track_in(); - const olive::rational& track_out(); + rational track_in(); + rational track_out(); - const olive::rational& length(); - void set_length(const olive::rational& l); + const rational& length(); + void set_length(const rational& l); virtual QString name() override; virtual QString id() override; + /** + * @brief Retrieves the NodeBlock connected to the "Previous" parameter + */ NodeBlock* previous_block(); + void set_previous_block(NodeBlock* p); + + /** + * @brief Retrieves the NodeBlock connected to the "Next" parameter + */ NodeBlock* next_block(); + void set_next_block(NodeBlock* p); + + private: - olive::rational length_; + rational length_; NodeIO* previous_block_; NodeIO* next_block_;