Files
radiantwave/src/fibonacci_line_pattern.cpp
T
2026-08-07 14:51:41 -05:00

97 lines
2.5 KiB
C++

#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