initial commit
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
#include "fibonacci_line_pattern.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace radiantwave
|
||||
{
|
||||
|
||||
FibonacciLinePattern::FibonacciLinePattern(int peakWordCount, float maxWidthPixels,
|
||||
float spaceWidth, WidthFunction widthFunction)
|
||||
: maxWidthPixels_(maxWidthPixels),
|
||||
spaceWidth_(spaceWidth),
|
||||
widthFunction_(std::move(widthFunction))
|
||||
{
|
||||
// Build the Fibonacci numbers 1,1,2,3,5,8,... up to the peak, then cap the
|
||||
// oscillation with the peak itself so the widest line fills the screen.
|
||||
// E.g. peak 15 -> 1,1,2,3,5,8,13,15.
|
||||
sequence_.push_back(1);
|
||||
if (peakWordCount > 1)
|
||||
{
|
||||
sequence_.push_back(1);
|
||||
}
|
||||
int a = 1;
|
||||
int b = 1;
|
||||
while (true)
|
||||
{
|
||||
int next = a + b;
|
||||
if (next > peakWordCount)
|
||||
{
|
||||
break;
|
||||
}
|
||||
sequence_.push_back(next);
|
||||
a = b;
|
||||
b = next;
|
||||
}
|
||||
if (sequence_.back() < peakWordCount)
|
||||
{
|
||||
sequence_.push_back(peakWordCount);
|
||||
}
|
||||
}
|
||||
|
||||
int FibonacciLinePattern::nextLine(const std::vector<std::string> &words,
|
||||
std::vector<std::string> &out)
|
||||
{
|
||||
if (words.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Wrap to the start of the word list at line boundaries only. Never wrap
|
||||
// mid-line, so a line is always a contiguous slice of the source text and
|
||||
// the scroll reads word-for-word like the proclamation itself.
|
||||
if (wordIndex_ >= static_cast<int>(words.size()))
|
||||
{
|
||||
wordIndex_ = 0;
|
||||
}
|
||||
|
||||
int target = sequence_[sequenceIndex_];
|
||||
int placed = 0;
|
||||
float width = 0.0f;
|
||||
|
||||
while (placed < target && wordIndex_ < static_cast<int>(words.size()))
|
||||
{
|
||||
const std::string &word = words[wordIndex_];
|
||||
float wordWidth = widthFunction_(word);
|
||||
float added = wordWidth + (width > 0.0f ? spaceWidth_ : 0.0f);
|
||||
|
||||
// Always place the first word even if it alone exceeds the cap.
|
||||
if (placed > 0 && width + added > maxWidthPixels_)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
out.push_back(word);
|
||||
width += added;
|
||||
++placed;
|
||||
++wordIndex_;
|
||||
}
|
||||
|
||||
// Walk the oscillation up and down: ..., 3,2,1,1,2,3,...
|
||||
const int size = static_cast<int>(sequence_.size());
|
||||
sequenceIndex_ += direction_;
|
||||
if (sequenceIndex_ >= size)
|
||||
{
|
||||
sequenceIndex_ = size >= 2 ? size - 2 : 0;
|
||||
direction_ = -1;
|
||||
}
|
||||
else if (sequenceIndex_ < 0)
|
||||
{
|
||||
sequenceIndex_ = size >= 3 ? 2 : 0;
|
||||
direction_ = 1;
|
||||
}
|
||||
|
||||
return placed;
|
||||
}
|
||||
|
||||
} // namespace radiantwave
|
||||
Reference in New Issue
Block a user