This commit is contained in:
tovjemam 2025-09-26 11:00:11 +02:00
commit d508045ec3
20 changed files with 502 additions and 0 deletions

6
.clang-format Normal file
View File

@ -0,0 +1,6 @@
BasedOnStyle: Microsoft
DerivePointerAlignment: false
PointerAlignment: Left
IndentWidth: 4 # spaces per indent level
TabWidth: 4 # width of a tab character
UseTab: Never # options: Never, ForIndentation, Alwayss

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.cache/
build/

17
CMakeLists.txt Normal file
View File

@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.10)
project(CppDrawing)
set(CMAKE_CXX_STANDARD 20)
add_executable(drawing
"contexts/pgm_drawing_context.cpp"
"math/transforms.cpp"
"primitives/line.cpp"
"primitives/rectangle.cpp"
"primitives/circle.cpp"
"main.cpp"
"input_file.cpp"
)
target_include_directories(drawing PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

45
bitmap.hpp Normal file
View File

@ -0,0 +1,45 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <span>
#include <vector>
struct Color
{
uint8_t l{};
};
class Bitmap
{
public:
Bitmap(size_t width, size_t height, const 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];
};
private:
size_t m_width, m_height;
std::vector<Color> m_data;
};

View File

@ -0,0 +1,14 @@
#pragma once
#include "math/vector.hpp"
class DrawingContext
{
public:
virtual void DrawLine(const math::Vector& p0, const math::Vector& p1) = 0;
virtual void DrawRectangle(const math::Vector& pos, const math::Vector& size, float angle) = 0;
virtual void DrawCircle(const math::Vector& center, float radius) = 0;
virtual void Flush() = 0;
virtual ~DrawingContext() = 0;
};

View File

@ -0,0 +1,60 @@
#include "pgm_drawing_context.hpp"
#include <cmath>
PgmDrawingContext::PgmDrawingContext(const std::filesystem::path& path, size_t width, size_t height)
: m_bitmap(width, height, Color{0xFF})
{
}
void PgmDrawingContext::DrawLine(const math::Vector& p0, const math::Vector& p1)
{
RasterizeLine(static_cast<int>(p0.x), static_cast<int>(p0.y), static_cast<int>(p1.x), static_cast<int>(p1.y));
}
void PgmDrawingContext::DrawRectangle(const math::Vector& pos, const math::Vector& size, float angle)
{
const float sina = std::sin(angle);
const float cosa = std::cos(angle);
const math::Vector bX{cosa, sina};
const math::Vector bY{-sina, cosa};
const auto& pD = pos;
const auto pA = pD + bY * size.y;
const auto pB = pA + bX * size.x;
const auto pC = pD + bX * size.x;
PgmDrawingContext::DrawLine(pA, pB);
PgmDrawingContext::DrawLine(pB, pC);
PgmDrawingContext::DrawLine(pC, pD);
PgmDrawingContext::DrawLine(pD, pA);
}
void PgmDrawingContext::DrawCircle(const math::Vector& center, float radius)
{
}
void PgmDrawingContext::RasterizeLine(int x0, int y0, int x1, int y1)
{
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
int err = dx + dy, e2; /* error value e_xy */
for (;;)
{ /* loop */
m_bitmap[y0][x0].l = 0x00;
if (x0 == x1 && y0 == y1)
break;
e2 = 2 * err;
if (e2 >= dy)
{
err += dy;
x0 += sx;
} /* e_xy+e_x > 0 */
if (e2 <= dx)
{
err += dx;
y0 += sy;
} /* e_xy+e_y < 0 */
}
}

View File

@ -0,0 +1,25 @@
#pragma once
#include "bitmap.hpp"
#include "drawing_context.hpp"
#include <cstddef>
#include <filesystem>
class PgmDrawingContext : public DrawingContext
{
public:
PgmDrawingContext(const std::filesystem::path& path, size_t width, size_t height);
void DrawLine(const math::Vector& p0, const math::Vector& p1) override;
void DrawRectangle(const math::Vector& pos, const math::Vector& size, float angle) override;
void DrawCircle(const math::Vector& center, float radius) override;
void Flush() override;
~PgmDrawingContext() override = default;
private:
Bitmap m_bitmap;
void RasterizeLine(int x0, int y0, int x1, int y1);
};

2
input_file.cpp Normal file
View File

@ -0,0 +1,2 @@
#include "input_file.hpp"

17
input_file.hpp Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include <filesystem>
#include <fstream>
#include "drawing_context.hpp"
class InputFile
{
public:
InputFile(const std::filesystem::path& path);
void Parse(DrawingContext& ctx);
private:
std::ifstream m_file;
};

8
main.cpp Normal file
View File

@ -0,0 +1,8 @@
#include <iostream>
#include "pgm_drawing_context.hpp"
int main()
{
std::cout << "sjeta" << std::endl;
}

20
math/transforms.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "transforms.hpp"
#include <cmath>
math::Vector math::RotatePoint(const Vector& center, float angle, const Vector& p)
{
const float sina = std::sin(angle);
const float cosa = std::cos(angle);
const Vector p1 = p - center;
return Vector(p1.x * cosa - p1.y * sina, p1.x * sina + p1.y * cosa) + center;
}
math::Vector math::ScalePoint(const Vector& center, float factor, const Vector& p)
{
return ((p - center) * factor) + center;
}
float math::RotateAngle(float originalAngle, float rotationAngle)
{
return std::fmodf(originalAngle + rotationAngle, PI * 2.0f);
}

15
math/transforms.hpp Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include "vector.hpp"
namespace math
{
constexpr float PI = 3.14159265358979323846f;
Vector RotatePoint(const Vector& center, float angle, const Vector& p);
Vector ScalePoint(const Vector& center, float factor, const Vector& p);
float RotateAngle(float originalAngle, float rotationAngle);
} // namespace math

62
math/vector.hpp Normal file
View File

@ -0,0 +1,62 @@
#pragma once
#include <cstddef>
namespace math
{
class Vector
{
public:
Vector() : x{0.0f}, y{0.0f}
{
}
Vector(float x, float y) : x{x}, y{y}
{
}
// float& operator[](size_t idx) { return m_v[idx]; }
// const float& operator[](size_t idx) const { return m_v[idx]; }
Vector operator+(const Vector& other) const
{
return Vector(x + other.x, y + other.y);
}
Vector& operator+=(const Vector& other)
{
x += other.x;
y += other.y;
return *this;
}
Vector operator-(const Vector& other) const
{
return Vector(x - other.x, y - other.y);
}
Vector& operator-=(const Vector& other)
{
x -= other.x;
y -= other.y;
return *this;
}
Vector operator*(float factor) const
{
return Vector(x * factor, y * factor);
}
Vector& operator*=(float factor)
{
x *= factor;
y *= factor;
return *this;
}
public:
float x, y;
};
} // namespace math

24
primitives/circle.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "circle.hpp"
#include "math/transforms.hpp"
#include "contexts/drawing_context.hpp"
void primitives::Circle::Translate(const math::Vector& offset)
{
m_center += offset;
}
void primitives::Circle::Rotate(const math::Vector& center, float angle)
{
m_center = math::RotatePoint(center, angle, m_center);
}
void primitives::Circle::Scale(const math::Vector& center, float factor)
{
m_center = math::ScalePoint(center, factor, m_center);
m_radius *= factor;
}
void primitives::Circle::Draw(DrawingContext& ctx)
{
ctx.DrawCircle(m_center, m_radius);
}

38
primitives/circle.hpp Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include "primitive.hpp"
namespace primitives
{
class Circle : public Primitive
{
public:
Circle(const math::Vector& center, float radius) : m_center(center), m_radius(radius)
{
}
const math::Vector& GetCenter() const
{
return m_center;
}
float GetRadius() const
{
return m_radius;
}
void Translate(const math::Vector& offset) override;
void Rotate(const math::Vector& center, float angle) override;
void Scale(const math::Vector& center, float factor) override;
void Draw(DrawingContext& ctx) override;
~Circle() override = default;
private:
math::Vector m_center;
float m_radius;
};
} // namespace primitives

26
primitives/line.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "line.hpp"
#include "math/transforms.hpp"
#include "contexts/drawing_context.hpp"
void primitives::Line::Translate(const math::Vector& offset)
{
m_p0 += offset;
m_p1 += offset;
}
void primitives::Line::Rotate(const math::Vector& center, float angle)
{
m_p0 = math::RotatePoint(center, angle, m_p0);
m_p1 = math::RotatePoint(center, angle, m_p1);
}
void primitives::Line::Scale(const math::Vector& center, float factor)
{
m_p0 = math::ScalePoint(center, factor, m_p0);
m_p1 = math::ScalePoint(center, factor, m_p1);
}
void primitives::Line::Draw(DrawingContext& ctx)
{
ctx.DrawLine(m_p0, m_p1);
}

27
primitives/line.hpp Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include "math/vector.hpp"
#include "primitive.hpp"
namespace primitives
{
class Line : public Primitive
{
public:
Line(const math::Vector& p0, const math::Vector& p1) : m_p0(p0), m_p1(p1)
{
}
void Translate(const math::Vector& offset) override;
void Rotate(const math::Vector& center, float angle) override;
void Scale(const math::Vector& center, float factor) override;
void Draw(DrawingContext& ctx) override;
private:
math::Vector m_p0;
math::Vector m_p1;
};
} // namespace primitives

24
primitives/primitive.hpp Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include "math/vector.hpp"
class DrawingContext;
namespace primitives
{
class Primitive
{
public:
Primitive() = default;
virtual void Translate(const math::Vector& offset) = 0;
virtual void Rotate(const math::Vector& center, float angle) = 0;
virtual void Scale(const math::Vector& center, float factor) = 0;
virtual void Draw(DrawingContext& ctx) = 0;
virtual ~Primitive() = 0;
};
} // namespace primitives

25
primitives/rectangle.cpp Normal file
View File

@ -0,0 +1,25 @@
#include "rectangle.hpp"
#include "math/transforms.hpp"
#include "contexts/drawing_context.hpp"
void primitives::Rectangle::Translate(const math::Vector& offset)
{
m_pos += offset;
}
void primitives::Rectangle::Rotate(const math::Vector& center, float angle)
{
m_pos = math::RotatePoint(center, angle, m_pos);
m_angle = math::RotateAngle(m_angle, angle);
}
void primitives::Rectangle::Scale(const math::Vector& center, float factor)
{
m_pos = math::ScalePoint(center, factor, m_pos);
m_size *= factor;
}
void primitives::Rectangle::Draw(DrawingContext& ctx)
{
ctx.DrawRectangle(m_pos, m_size, m_angle);
}

45
primitives/rectangle.hpp Normal file
View File

@ -0,0 +1,45 @@
#pragma once
#include "math/vector.hpp"
#include "primitive.hpp"
namespace primitives
{
class Rectangle : public Primitive
{
public:
Rectangle(const math::Vector& pos, const math::Vector& size) : m_pos(pos), m_size(size), m_angle(0.0f)
{
}
const math::Vector& GetPosition() const
{
return m_pos;
}
const math::Vector& GetSize() const
{
return m_size;
}
const float GetAngle() const
{
return m_angle;
}
void Translate(const math::Vector& offset) override;
void Rotate(const math::Vector& center, float angle) override;
void Scale(const math::Vector& center, float factor) override;
void Draw(DrawingContext& ctx) override;
~Rectangle() override = default;
private:
math::Vector m_pos;
math::Vector m_size;
float m_angle;
};
} // namespace primitives