Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -----------------------------------------------------------------------
- svg.h
- -----------------------------------------------------------------------
- #pragma once
- #include <cstdint>
- #include <iostream>
- #include <memory>
- #include <string>
- #include <vector>
- namespace svg {
- struct Point {
- Point() = default;
- Point(double x, double y) : x(x)
- , y(y) {}
- double x = 0;
- double y = 0;
- };
- struct RenderContext {
- RenderContext(std::ostream& out) : out(out) {}
- RenderContext(std::ostream& out, int indent_step, int indent = 0) : out(out)
- , indent_step(indent_step)
- , indent(indent) {}
- RenderContext Indented() const {
- return {out,
- indent_step,
- indent + indent_step};
- }
- void RenderIndent() const {
- for (int i = 0; i < indent; ++i) {
- out.put(' ');
- }
- }
- std::ostream& out;
- int indent_step = 0;
- int indent = 0;
- };
- class Object {
- public:
- void Render(const RenderContext& context) const;
- virtual ~Object() = default;
- private:
- virtual void RenderObject(const RenderContext& context) const = 0;
- };
- class Circle final : public Object {
- public:
- Circle& SetCenter(Point center);
- Circle& SetRadius(double radius);
- private:
- Point center_;
- double radius_ = 1.0;
- void RenderObject(const RenderContext& context) const override;
- };
- class Polyline final : public Object {
- public:
- Polyline& AddPoint(Point point);
- private:
- std::vector<Point> points_;
- void RenderObject(const RenderContext& context) const override;
- };
- class Text final : public Object{
- public:
- Text& SetPosition(Point pos);
- Text& SetOffset(Point offset);
- Text& SetFontSize(uint32_t size);
- Text& SetFontFamily(std::string font_family);
- Text& SetFontWeight(std::string font_weight);
- Text& SetData(std::string data);
- private:
- Point position_;
- Point offset_;
- std::string font_family_;
- std::string font_weight_;
- uint32_t font_size_ = 1;
- std::string data_;
- static std::string delete_spaces(const std::string& str);
- static std::string uniq_symbols(const std::string& str);
- void RenderObject(const RenderContext& context) const override;
- };
- class ObjectContainer {
- public:
- virtual ~ObjectContainer() = default;
- template<typename Obj>
- void Add(Obj obj);
- virtual void AddPtr(std::unique_ptr<Object> &&) = 0;
- protected:
- std::vector<std::unique_ptr<Object>> objects_;
- };
- template<typename Obj>
- void ObjectContainer::Add(Obj obj) {
- objects_.emplace_back(std::make_unique<Obj>(std::move(obj)));
- }
- class Drawable {
- public:
- virtual void Draw(ObjectContainer& container) const = 0;
- virtual ~Drawable() = default;
- };
- class Document : public ObjectContainer {
- public:
- void AddPtr(std::unique_ptr<Object>&& obj) override {
- objects_.emplace_back(std::move(obj));
- }
- void Render(std::ostream& out) const;
- };
- }//end namespace svg
- -----------------------------------------------------------------------
- svg.cpp
- -----------------------------------------------------------------------
- #include "svg.h"
- namespace svg {
- using namespace std::literals;
- void Object::Render(const RenderContext& context) const {
- context.RenderIndent();
- RenderObject(context);
- context.out << std::endl;
- }
- // ---------- Circle ------------------
- Circle& Circle::SetCenter(Point center) {
- center_ = center;
- return *this;
- }
- Circle& Circle::SetRadius(double radius) {
- radius_ = radius;
- return *this;
- }
- void Circle::RenderObject(const RenderContext& context) const {
- std::ostream& out = context.out;
- out << R"(<circle cx=")"
- << center_.x << R"(" cy=")"
- << center_.y << R"(" )"
- << R"(r=")"
- << radius_ << R"(" )" << "/>"sv;
- }
- // ---------- Polyline ------------------
- Polyline& Polyline::AddPoint(Point point) {
- points_.emplace_back(point);
- return *this;
- }
- void Polyline::RenderObject(const RenderContext& context) const {
- std::ostream& out = context.out;
- out << R"(<polyline points=")";
- for (size_t i = 0; i < points_.size(); ++i) {
- out << points_[i].x << ","sv << points_[i].y;
- if (i+1 != points_.size()) {
- out << " "sv;
- }
- }
- out << R"(")" << " />"sv;
- }
- // ---------- Text ------------------
- Text& Text::SetPosition(Point pos) {
- position_ = pos;
- return *this;
- }
- Text& Text::SetOffset(Point offset) {
- offset_ = offset;
- return *this;
- }
- Text& Text::SetFontSize(uint32_t size) {
- font_size_ = size;
- return *this;
- }
- Text& Text::SetFontFamily(std::string font_family) {
- font_family_ = std::move(font_family);
- return *this;
- }
- Text& Text::SetFontWeight(std::string font_weight) {
- font_weight_ = std::move(font_weight);
- return *this;
- }
- Text& Text::SetData(std::string data) {
- data_ = std::move(data);
- return *this;
- }
- std::string Text::delete_spaces(const std::string& str) {
- if (str.empty()) {
- return {};
- } else {
- auto left = str.find_first_not_of(' ');
- auto right = str.find_last_not_of(' ');
- return str.substr(left, right - left + 1);
- }
- }
- std::string Text::uniq_symbols(const std::string& str) {
- std::string out;
- for (char ch : str) {
- if (ch == '"') {
- out += """sv;
- continue;
- } else if (ch == '`' || ch == '\'') {
- out += "'"sv;
- continue;
- } else if (ch == '<') {
- out += "<"sv;
- continue;
- } else if (ch == '>') {
- out += ">"sv;
- continue;
- } else if (ch == '&') {
- out += "&"sv;
- continue;
- } else {
- }
- out += ch;
- }
- return out;
- }
- void Text::RenderObject(const RenderContext& context) const {
- std::ostream& out = context.out;
- out << R"(<text x=")"
- << position_.x << R"(" y=")"
- << position_.y << R"(" )"
- << R"(dx=")"
- << offset_.x << R"(" dy=")"
- << offset_.y << R"(" )"
- << R"(font-size=")"
- << font_size_ << R"(")";
- if (!font_family_.empty()) {
- out << R"( font-family=")" << font_family_ << R"(")";
- }
- if (!font_weight_.empty()) {
- out << R"( font-weight=")" << font_weight_ << R"(")";
- }
- out << ">"sv << delete_spaces(uniq_symbols(data_)) << "</text>"sv;
- }
- // ---------- Document ------------------
- void Document::Render(std::ostream& out) const {
- int indent = 2;
- int indent_step = 2;
- RenderContext context(out, indent_step, indent);
- const std::string_view xml = R"(<?xml version="1.0" encoding="UTF-8" ?>)";
- const std::string_view svg = R"(<svg xmlns="http://www.w3.org/2000/svg" version="1.1">)";
- out << xml << "\n"sv << svg << "\n"sv;
- for (const auto& object : objects_) {
- object->Render(context);
- }
- out << "</svg>"sv;
- }
- }//end namespace svg
- -----------------------------------------------------------------------
- main.cpp
- -----------------------------------------------------------------------
- #define _USE_MATH_DEFINES
- #include "svg.h"
- #include <cmath>
- using namespace std::literals;
- using namespace svg;
- template <typename DrawableIterator>
- void DrawPicture(DrawableIterator begin, DrawableIterator end, svg::ObjectContainer& target) {
- for (auto it = begin; it != end; ++it) {
- (*it)->Draw(target);
- }
- }
- template <typename Container>
- void DrawPicture(const Container& container, svg::ObjectContainer& target) {
- using namespace std;
- DrawPicture(begin(container), end(container), target);
- }
- namespace shapes {
- class Triangle : public svg::Drawable {
- public:
- Triangle(svg::Point p1, svg::Point p2, svg::Point p3)
- : p1_(p1)
- , p2_(p2)
- , p3_(p3) {}
- void Draw(svg::ObjectContainer& container) const override {
- container.Add(svg::Polyline().AddPoint(p1_).AddPoint(p2_).AddPoint(p3_).AddPoint(p1_));
- }
- private:
- svg::Point p1_, p2_, p3_;
- };
- class Star : public svg::Drawable {
- public:
- Star(svg::Point center, double outer_rad, double inner_rad, int num_rays) {
- polyline_ = CreateStar(center,
- outer_rad,
- inner_rad,
- num_rays);
- }
- void Draw(svg::ObjectContainer& container) const override {
- container.Add(polyline_);
- }
- private:
- svg::Polyline polyline_;
- svg::Polyline CreateStar(svg::Point center, double outer_rad, double inner_rad, int num_rays) {
- using namespace svg;
- Polyline polyline;
- for (int i = 0; i <= num_rays; ++i) {
- double angle = 2 * M_PI * (i % num_rays) / num_rays;
- polyline.AddPoint({center.x + outer_rad * sin(angle), center.y - outer_rad * cos(angle)});
- if (i == num_rays) {
- break;
- }
- angle += M_PI / num_rays;
- polyline.AddPoint({center.x + inner_rad * sin(angle), center.y - inner_rad * cos(angle)});
- }
- return polyline;
- }
- };
- class Snowman : public svg::Drawable {
- public:
- Snowman(svg::Point head_point, double radius) : head_(head_point)
- , radius_(radius){}
- void Draw(svg::ObjectContainer& container) const override {
- using namespace svg;
- Circle head;
- head.SetCenter(head_).SetRadius(radius_);
- Circle middle;
- middle.SetCenter({ head_.x, head_.y + radius_ * 2 }).SetRadius(radius_ * 1.5);
- Circle down;
- down.SetCenter({ head_.x, head_.y + radius_ * 5 }).SetRadius(radius_ * 2);
- container.Add(down);
- container.Add(middle);
- container.Add(head);
- }
- private:
- svg::Point head_;
- double radius_;
- };
- }//end namespace shapes
- int main() {
- using namespace svg;
- using namespace shapes;
- using namespace std;
- vector<unique_ptr<svg::Drawable>> picture;
- picture.emplace_back(make_unique<Triangle>(Point{100, 20}, Point{120, 50}, Point{80, 40}));
- picture.emplace_back(make_unique<Star>(Point{50.0, 20.0}, 10.0, 4.0, 5));
- picture.emplace_back(make_unique<Snowman>(Point{30, 20}, 10.0));
- svg::Document doc;
- DrawPicture(picture, doc);
- doc.Render(cout);
- }
Advertisement
Add Comment
Please, Sign In to add comment