This repository has been archived on 2024-01-28. You can view files and clone it, but cannot push or open issues/pull-requests.
ecg-prog-filtered/u02/src/star_tool.cpp

93 lines
2.6 KiB
C++

// SPDX-License-Identifier: LGPL-3.0-or-later
#include "star_tool.h"
#include "bresenham_line_tool.h"
#include <cmath>
#include <iostream>
#include <util.h>
/*
* 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<std::pair<float, float>>
regular_polygon_mod(int n, std::function<float(int)> 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<std::pair<float, float>> 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<std::pair<float, float>> 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<std::pair<float, float>> points =
star(spikes, radius_factor * r, r, x0, y0, angle);
for (size_t 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;
}