// SPDX-License-Identifier: LGPL-3.0-or-later #include "star_tool.h" #include "bresenham_line_tool.h" #include #include #include /* * The implementation is modeled after one in Haskell * I created for EMI in the winter semester 2022/2023 * to output SVGs of regular polygons varied in different ways. * It can be found here: * https://git.sbruder.de/simon/emi5/src/branch/master/genstar/Main.hs */ std::vector> regular_polygon_mod(int n, std::function rf, int x, int y, float base_angle) { if (n < 3) { std::cerr << "Polygons must have at least 3 vertices (regular_polygon_mod " "was called with n=" << n << ")." << std::endl; return {}; } std::vector> points = {}; for (int step = 0; step < n; step++) { const float angle = base_angle + (step * 2.0 * atan(1) * 4.0) / n; const float r = rf(step); // Changed from Haskell implementation: // It behaves like the unit circle, // in that it starts at (1, 0) instead of (0, 1). points.push_back({round(x + r * cosf(angle)), round(y + r * sinf(angle))}); } return points; } std::vector> star(int n, float r1, float r2, int x, int y, float base_angle) { return regular_polygon_mod( n * 2, [r1, r2](int i) { return i % 2 == 0 ? r2 : r1; }, x, y, base_angle); } star_tool::star_tool(canvas_buffer &canvas, int spikes) : tool_base(canvas) { set_spikes(spikes); } void star_tool::draw(int x0, int y0, int x1, int y1) { const int r = round(std::sqrt(std::pow((x1 - x0), 2) + std::pow((y1 - y0), 2))); const float angle = atan2(y1 - y0, x1 - x0); bresenham_line_tool *blt = new bresenham_line_tool(canvas); const std::vector> points = star(spikes, radius_factor * r, r, x0, y0, angle); for (int i = 1; i <= points.size(); i++) { blt->draw(round(points[i - 1].first), round(points[i - 1].second), round(points[i % points.size()].first), round(points[i % points.size()].second)); } } void star_tool::set_text(std::stringstream &stream) { stream << "Tool: Star (" << spikes << " spikes)"; } void star_tool::set_spikes(int spikes) { this->spikes = spikes; switch (spikes) { case 3: shape = TS_STAR_3; break; case 4: shape = TS_STAR_4; break; // 5 is default, handled at the end case 6: shape = TS_STAR_6; break; case 5: default: shape = TS_STAR_5; break; } } void star_tool::set_radius_factor(int radius_factor) { this->radius_factor = radius_factor; }