This commit is contained in:
tovjemam 2025-12-03 21:25:21 +01:00
parent f84394fc0e
commit 9e103519d0
4 changed files with 45 additions and 81 deletions

View File

@ -14,16 +14,8 @@
InputFile::InputFile(const std::filesystem::path& path) : m_file(path), m_cmdsProcessed(0)
{
if (m_file.bad())
{
throw std::runtime_error("Cannot open " + path.string() + " for reading");
}
}
// istream >> operator for math::Vector
static std::istream& operator>>(std::istream& is, math::Vector& vec)
{
return is >> vec.x >> vec.y;
if (!m_file)
throw std::runtime_error(std::format("Cannot open {} for reading", path.string()));
}
// command name -> command handler map
@ -53,12 +45,6 @@ const char* GetTypeName<float>()
return "float";
}
template <>
const char* GetTypeName<math::Vector>()
{
return "vector";
}
template <>
const char* GetTypeName<std::string>()
{
@ -78,7 +64,7 @@ static T ReadVal(std::istream& is)
T v;
is >> v;
if (is.bad())
if (!is)
throw std::runtime_error(std::format("Could not parse {} from stream", GetTypeName<T>()));
return v;
@ -166,7 +152,7 @@ shapes::Group InputFile::Parse()
auto cmd = cmds.find(cmdName);
if (cmd == cmds.end())
throw std::runtime_error("Unknown command: " + cmdName);
throw std::runtime_error(std::format("Unknown command: {}", cmdName));
cmd->second(iss);
++m_cmdsProcessed;

View File

@ -2,64 +2,37 @@
#include <cstddef>
#include <cstdint>
#include <span>
#include <vector>
class Color
using Color = uint8_t;
namespace colors
{
public:
Color() : l{0} {}
Color(uint8_t l) : l{l} {}
uint8_t l{}; // luminence
void Blend(const Color& src, uint8_t alpha)
{
l = BlendChannel(l, src.l, alpha);
// l = alpha;
}
private:
static uint8_t BlendChannel(uint8_t a, uint8_t b, uint8_t alpha)
{
return static_cast<uint8_t>(
(static_cast<int>(a) * (255 - static_cast<int>(alpha)) + static_cast<int>(b) * static_cast<int>(alpha)) /
255);
}
};
constexpr Color BLACK{0};
constexpr Color WHITE{1};
} // namespace colors
class Bitmap
{
public:
Bitmap(size_t width, size_t height, const Color& clearColor)
Bitmap(size_t width, size_t height, Color clearColor)
: m_width(width), m_height(height), m_data(width * height, clearColor)
{
}
// std::span<Color> operator[](size_t row)
// {
// return {&m_data[row * m_width], m_width};
// };
// std::span<const Color> operator[](size_t row) const
// {
// return {&m_data[row * m_width], m_width};
// };
Color* operator[](size_t row) { return &m_data[row * m_width]; };
const Color* operator[](size_t row) const { return &m_data[row * m_width]; };
std::span<Color> operator[](size_t row) { return {&m_data[row * m_width], m_width}; };
std::span<const Color> operator[](size_t row) const { return {&m_data[row * m_width], m_width}; };
size_t GetWidth() const { return m_width; }
size_t GetHeight() const { return m_height; }
void Put(int x, int y, const Color& color, uint8_t alpha)
void SetPixel(int x, int y, Color color)
{
if (x < 0 || y < 0 || x >= m_width || y >= m_height)
return; // out of bounds
return; // out of bounds, ignore
(*this)[y][x].Blend(color, alpha);
(*this)[y][x] = color;
}
private:

View File

@ -3,7 +3,7 @@
#include <fstream>
#include <stdexcept>
PgmRenderer::PgmRenderer(size_t width, size_t height) : m_bitmap(width, height, Color{0xFF}) {}
PgmRenderer::PgmRenderer(size_t width, size_t height) : m_bitmap(width, height, colors::WHITE) {}
void PgmRenderer::DrawLine(const math::Vector& p0, const math::Vector& p1)
{
@ -47,13 +47,13 @@ void PgmRenderer::Save(const std::filesystem::path& path)
file << "P2" << std::endl;
file << "# KIV/CPP" << std::endl;
file << m_bitmap.GetWidth() << ' ' << m_bitmap.GetHeight() << std::endl;
file << 255 << std::endl;
file << 1 << std::endl;
for (size_t y = 0; y < m_bitmap.GetHeight(); ++y)
{
for (size_t x = 0; x < m_bitmap.GetWidth(); ++x)
{
file << static_cast<int>(m_bitmap[y][x].l) << ' ';
file << static_cast<int>(m_bitmap[y][x]) << ' ';
}
file << std::endl;
@ -62,9 +62,7 @@ void PgmRenderer::Save(const std::filesystem::path& path)
void PgmRenderer::RasterizeLine(int x0, int y0, int x1, int y1)
{
// TODO: fix
const Color lineColor{0x00};
float w = 2.0f;
int w = 2; // thickness
int dx = abs(x1 - x0);
int dy = abs(y1 - y0);
@ -90,7 +88,7 @@ void PgmRenderer::RasterizeLine(int x0, int y0, int x1, int y1)
{
for (int j = -w / 2; j <= w / 2; j++)
{
m_bitmap.Put(x0 + i * ox, y0 + j * oy, lineColor, 0xFF);
m_bitmap.SetPixel(x0 + i * ox, y0 + j * oy, colors::BLACK);
}
}
@ -112,10 +110,7 @@ void PgmRenderer::RasterizeLine(int x0, int y0, int x1, int y1)
void PgmRenderer::RasterizeCircle(int cx, int cy, int r)
{
// TODO: fix
const Color circleColor{0x00};
float w = 2.0f;
int w = 2; // thickness
int r_outer = r + w / 2;
int r_inner = r - w / 2;
@ -129,7 +124,7 @@ void PgmRenderer::RasterizeCircle(int cx, int cy, int r)
int dist2 = x * x + y * y;
if (dist2 <= r_outer * r_outer && dist2 >= r_inner * r_inner)
{
m_bitmap.Put(cx + x, cy + y, circleColor, 0xFF);
m_bitmap.SetPixel(cx + x, cy + y, colors::BLACK);
}
}
}

View File

@ -1,33 +1,40 @@
#include "svg_renderer.hpp"
#include "math/constants.hpp"
#include <format>
#include <fstream>
SvgRenderer::SvgRenderer(size_t width, size_t height) : m_width{width}, m_height{height}
{
// white bg
m_out << " <rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\" />" << std::endl;
m_out << R"SVG( <rect width="100%" height="100%" fill="#FFFFFF" />)SVG" << std::endl;
}
void SvgRenderer::DrawLine(const math::Vector& p0, const math::Vector& p1)
{
m_out << " <line x1=\"" << p0.x << "\" y1=\"" << p0.y << "\" x2=\"" << p1.x << "\" y2=\"" << p1.y << "\" "
<< "stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"round\" />" << std::endl;
m_out
<< std::format(
R"SVG( <line x1="{}" y1="{}" x2="{}" y2="{}" stroke="#000000" stroke-width="2" stroke-linecap="round" />)SVG",
p0.x, p0.y, p1.x, p1.y)
<< std::endl;
}
void SvgRenderer::DrawRectangle(const math::Vector& pos, const math::Vector& size, float angle)
{
float angleDeg = angle * math::RAD_TO_DEG;
m_out << " <rect x=\"" << pos.x << "\" y=\"" << pos.y << "\" width=\"" << size.x << "\" height=\"" << size.y
<< "\" fill=\"none\" stroke=\"#000000\" stroke-width=\"2\" stroke-linejoin=\"round\" transform=\"rotate("
<< angleDeg << ", " << pos.x << ", " << pos.y << ")\" />" << std::endl;
m_out
<< std::format(
R"SVG( <rect x="{0}" y="{1}" width="{2}" height="{3}" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" transform="rotate({4}, {0}, {1})" />)SVG",
pos.x, pos.y, size.x, size.y, angleDeg)
<< std::endl;
}
void SvgRenderer::DrawCircle(const math::Vector& center, float radius)
{
m_out << " <circle cx=\"" << center.x << "\" cy=\"" << center.y << "\" r=\"" << radius
<< "\" fill=\"none\" stroke=\"#000000\" stroke-width=\"2\" />" << std::endl;
m_out << std::format(R"SVG( <circle cx="{}" cy="{}" r="{}" fill="none" stroke="#000000" stroke-width="2" />)SVG",
center.x, center.y, radius)
<< std::endl;
}
void SvgRenderer::Save(const std::filesystem::path& path)
@ -38,9 +45,12 @@ void SvgRenderer::Save(const std::filesystem::path& path)
{
throw std::runtime_error{"Cannot open file for writing: " + path.string()};
}
file << "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" << m_width << "\" height=\"" << m_height
<< "\" viewBox=\"0 0 " << m_width << " " << m_height << "\" role=\"img\" aria-label=\"KIV/CPP\">" << std::endl;
file
<< std::format(
R"SVG(<svg xmlns="http://www.w3.org/2000/svg" width="{0}" height="{1}" viewBox="0 0 {0} {1}" role="img" aria-label="KIV/CPP">)SVG",
m_width, m_height)
<< std::endl;
file << m_out.str();