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/sweep_line_tool.cpp

103 lines
2.7 KiB
C++

// SPDX-License-Identifier: LGPL-3.0-or-later
#include "sweep_line_tool.h"
#include "dda_line_tool.h"
#include "util.h"
#include <cmath>
#include <iostream>
#include <vector>
// Calculate the inverse of the DDA function.
int dda_inv(int x0, int y0, float m, int y) {
// This uses the regular function that is the basis of DDA
//
// y_i = y_0 + m·(x_i - x_0)
//
// but rearranges it to be the inverse function:
//
// y_i = y_0 + m·(x_i - x_0)
// ⇔ y_i - y_0 + x_0·m = x_i·m
// ⇔ x_i = (y_i - y_0)/m + x_0
//
// This returns a valid x coordinate on the line
// starting from (x0, y0) with the slope m.
// Handle special case of flat line
if (m == 0)
return x0;
else
return round((y - y0) / m + x0);
}
sweep_line_tool::sweep_line_tool(canvas_buffer &canvas) : tool_base(canvas) {
shape = TS_NONE;
is_draggable = false;
}
void sweep_line_tool::draw_interval(int b1, int b2, int y) {
for (int x = std::min(b1, b2); x <= std::max(b1, b2); x++) {
canvas.set_pixel(x, y);
}
}
void sweep_line_tool::draw() { draw(10, 10, 90, 30, 30, 90); }
void sweep_line_tool::draw(int, int) { draw(); }
void sweep_line_tool::draw(int x0, int y0, int x1, int y1, int x2, int y2) {
/*
* Terminology:
*
* (x0, y0)
* +
* | \
* | \ m_1
* |first\
* | pass \
* m_shared |---------+ (x1, y1)
* |second /
* |pass /
* | / m_2
* | /
* +
* (x2, y2)
*/
// Sort triangle points (in place) so that y0 < y1 < y2
sort_triangle_points(x0, y0, x1, y1, x2, y2);
// Slope of the side limiting the first pass (only)
float m_1 = slope(x0, y0, x1, y1);
// Slope of the side limiting the second pass (only)
float m_2 = slope(x1, y1, x2, y2);
// Slope of the side limiting both passes
float m_shared = slope(x0, y0, x2, y2);
// First pass
if (y0 == y1) {
// If the first two points are on the same height, only draw one line.
// This is only needed for the first interval,
// because in the case that y1 == y2,
// the problematic line would have already been handled in the first pass.
draw_interval(x0, x1, y0);
} else {
for (int y = y0; y <= y1; y++) {
int b1 = dda_inv(x0, y0, m_1, y);
int b2 = dda_inv(x0, y0, m_shared, y);
draw_interval(b1, b2, y);
}
}
// Second pass
// it can start iterating at y1 + 1,
// because y1 is already included in the first pass.
for (int y = y1 + 1; y <= y2; y++) {
int b1 = dda_inv(x1, y1, m_2, y);
int b2 = dda_inv(x0, y0, m_shared, y);
draw_interval(b1, b2, y);
}
}
void sweep_line_tool::set_text(std::stringstream &stream) {
stream << "Tool: Sweep-Line";
}