/** * File: FracBase.cc * Copyright (C) 2025 Tyler Triplett * License: GNU GPL 3.0 or later <https://www.gnu.org/licenses/gpl-3.0.html> * * This is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <generators/FracBase.hh> #include <utils/safeJsonParse.hh> #include <cmath> namespace ty { FracBase::FracBase(const int& w, const int& h) : BaseGen(w, h) { } FracBase::~FracBase() { } std::vector<Setting> FracBase::getSettings() { return { {"zf", zoomFactor_}, {"rc", realCenter_}, {"ic", imagCenter_}, {"it", maxIter_}, }; } void FracBase::init(const json& j) { /// load settings from json const auto settings = getSettings(); for (const auto& v : settings) { const auto r = getJsonValues<double>(j, v.first); if (r) v.second = *r; } const auto [rangeX, rangeY] = scaleRange(); /// compute member variables maxIter_ = std::clamp(maxIter_, 0.0, iterLimit_); minX_ = realCenter_ - rangeX; minY_ = imagCenter_ - rangeY; scaleX_ = (2 * rangeX) / width_; scaleY_ = (2 * rangeY) / height_; } std::pair<double, double> FracBase::scaleRange() const { /// const double scaledRange = range_ / zoomFactor_; const double scaledRange = range_ / std::pow(2, zoomFactor_); const double doubleWidth = width_; const double doubleHeight = height_; if (width_ >= height_) { const double scaledNew = scaledRange * doubleWidth / doubleHeight; return std::make_pair(scaledNew, scaledRange); } else { const double scaledNew = scaledRange * doubleHeight / doubleWidth; return std::make_pair(scaledRange, scaledNew); } } Pixel FracBase::pixelFromIt(const int& it) const { const double t = static_cast<double>(it) / static_cast<double>(maxIter_); const unsigned char r = 9 * (1 - t) * t * t * t * uCharMax_; const unsigned char g = 15 * (1 - t) * (1 - t) * t * t * uCharMax_; const unsigned char b = 8.5 * (1 - t) * (1 - t) * (1 - t) * t * uCharMax_; return Pixel{r, g, b}; /// spared a constructor... } std::vector<unsigned char> FracBase::runGen() { const int size = width_ * height_ * 4; std::vector<unsigned char> image(size); for (int py = 0; py < height_; py++) { #pragma omp parallel for schedule(dynamic, 16) for (int px = 0; px < width_; px++) { const int iteration = computeIteration(px, py); const auto [r, g, b] = pixelFromIt(iteration); const int i = (py * width_ + px) * 4; image[i] = r; image[i + 1] = g; image[i + 2] = b; image[i + 3] = uCharMax_; } } return image; } Point FracBase::pixelTranslation(const int& px, const int& py) const { const double real = minX_ + px * scaleX_; const double imag = minY_ + py * scaleY_; return Point(real, imag); } int FracBase::computeIteration(const int& px, const int& py) const { const auto c = pixelTranslation(px, py); Point z(0.0, 0.0); int iteration = 0; while (abs(z) <= 2.0 && iteration < maxIter_) { z = nextZ(z, c); iteration++; } return iteration; } } /// ty