shushus

Спринт 11. Абстрактные классы. Разработка SVG-библиотеки.

Mar 26th, 2023
720
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.45 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. svg.h
  3. -----------------------------------------------------------------------
  4. #pragma once
  5.  
  6. #include <cstdint>
  7. #include <iostream>
  8. #include <memory>
  9. #include <string>
  10. #include <vector>
  11.  
  12. namespace svg {
  13. struct Point {
  14.     Point() = default;
  15.     Point(double x, double y) : x(x)
  16.                               , y(y) {}
  17.     double x = 0;
  18.     double y = 0;
  19. };
  20.  
  21. struct RenderContext {
  22.     RenderContext(std::ostream& out) : out(out) {}
  23.  
  24.     RenderContext(std::ostream& out, int indent_step, int indent = 0) : out(out)
  25.                                                                       , indent_step(indent_step)
  26.                                                                       , indent(indent) {}
  27.  
  28.     RenderContext Indented() const {
  29.         return {out,
  30.                 indent_step,
  31.                 indent + indent_step};
  32.     }
  33.  
  34.     void RenderIndent() const {
  35.         for (int i = 0; i < indent; ++i) {
  36.             out.put(' ');
  37.         }
  38.     }
  39.  
  40.     std::ostream& out;
  41.     int indent_step = 0;
  42.     int indent = 0;
  43. };
  44.  
  45. class Object {
  46. public:
  47.     void Render(const RenderContext& context) const;
  48.     virtual ~Object() = default;
  49.  
  50. private:
  51.     virtual void RenderObject(const RenderContext& context) const = 0;
  52. };
  53.  
  54. class Circle final : public Object {
  55. public:
  56.     Circle& SetCenter(Point center);
  57.     Circle& SetRadius(double radius);
  58.  
  59. private:
  60.     Point center_;
  61.     double radius_ = 1.0;
  62.    
  63.     void RenderObject(const RenderContext& context) const override;
  64. };
  65.  
  66. class Polyline final : public Object {
  67. public:
  68.     Polyline& AddPoint(Point point);
  69. private:
  70.     std::vector<Point> points_;
  71.     void RenderObject(const RenderContext& context) const override;
  72. };
  73.  
  74. class Text final : public Object{
  75. public:
  76.     Text& SetPosition(Point pos);
  77.     Text& SetOffset(Point offset);
  78.     Text& SetFontSize(uint32_t size);
  79.     Text& SetFontFamily(std::string font_family);
  80.     Text& SetFontWeight(std::string font_weight);
  81.     Text& SetData(std::string data);
  82.  
  83. private:
  84.     Point position_;
  85.     Point offset_;
  86.     std::string font_family_;
  87.     std::string font_weight_;
  88.     uint32_t font_size_ = 1;
  89.     std::string data_;
  90.      
  91.     static std::string delete_spaces(const std::string& str);
  92.     static std::string uniq_symbols(const std::string& str);
  93.    
  94.     void RenderObject(const RenderContext& context) const override;
  95. };
  96.  
  97. class Document {
  98. public:
  99.     template <typename Obj>
  100.     void Add(Obj obj) {
  101.         objects_.emplace_back(std::make_unique<Obj>(std::move(obj)));
  102.     }
  103.    
  104.     void AddPtr(std::unique_ptr<Object>&& obj);
  105.     void Render(std::ostream& out) const;
  106.    
  107. private:
  108.     std::vector<std::unique_ptr<Object>> objects_;
  109. };
  110. }//end namespace svg
  111. -----------------------------------------------------------------------
  112. svg.cpp
  113. -----------------------------------------------------------------------
  114. #include "svg.h"
  115.  
  116. namespace svg {
  117.  
  118. using namespace std::literals;
  119.  
  120. void Object::Render(const RenderContext& context) const {
  121.     context.RenderIndent();
  122.     RenderObject(context);
  123.     context.out << std::endl;
  124. }
  125.  
  126. // ---------- Circle ------------------
  127.  
  128. Circle& Circle::SetCenter(Point center)  {
  129.     center_ = center;
  130.     return *this;
  131. }
  132.  
  133. Circle& Circle::SetRadius(double radius)  {
  134.     radius_ = radius;
  135.     return *this;
  136. }
  137.  
  138. void Circle::RenderObject(const RenderContext& context) const {
  139.     std::ostream& out = context.out;
  140.    
  141.     out << R"(<circle cx=")"
  142.        << center_.x << R"(" cy=")"
  143.        << center_.y << R"(" )"
  144.         << R"(r=")"
  145.        << radius_ << R"(" )" << "/>"sv;
  146. }
  147.  
  148. // ---------- Polyline ------------------
  149.    
  150. Polyline& Polyline::AddPoint(Point point) {
  151.     points_.emplace_back(point);
  152.     return *this;
  153. }
  154.  
  155. void Polyline::RenderObject(const RenderContext& context) const {
  156.    
  157.     std::ostream& out = context.out;
  158.     out << R"(<polyline points=")";
  159.  
  160.    for (size_t i = 0; i < points_.size(); ++i) {
  161.        out << points_[i].x << ","sv << points_[i].y;
  162.  
  163.        if (i+1 != points_.size()) {
  164.            out << " "sv;
  165.        }
  166.    }
  167.  
  168.    out << R"(")" << " />"sv;
  169. }
  170.  
  171. // ---------- Text ------------------
  172.    
  173. Text& Text::SetPosition(Point pos) {
  174.     position_ = pos;
  175.     return *this;
  176. }
  177.  
  178. Text& Text::SetOffset(Point offset) {
  179.     offset_ = offset;
  180.     return *this;
  181. }
  182.    
  183. Text& Text::SetFontSize(uint32_t size) {
  184.     font_size_ = size;
  185.     return *this;
  186. }
  187.  
  188. Text& Text::SetFontFamily(std::string font_family) {
  189.     font_family_ = std::move(font_family);
  190.     return *this;
  191. }
  192.  
  193. Text& Text::SetFontWeight(std::string font_weight) {
  194.     font_weight_ = std::move(font_weight);
  195.     return *this;
  196. }
  197.  
  198. Text& Text::SetData(std::string data) {
  199.     data_ = std::move(data);
  200.     return *this;
  201. }
  202.  
  203. std::string Text::delete_spaces(const std::string& str) {
  204.     if (str.empty()) {
  205.         return {};
  206.     } else {
  207.        
  208.         auto left = str.find_first_not_of(' ');
  209.         auto right = str.find_last_not_of(' ');
  210.         return str.substr(left, right - left + 1);  
  211.     }
  212. }
  213.  
  214. std::string Text::uniq_symbols(const std::string& str) {
  215.    
  216.     std::string out;
  217.  
  218.     for (char ch : str) {
  219.        
  220.         if (ch == '"') {
  221.             out += "&quot;"sv;
  222.             continue;
  223.            
  224.         } else if (ch == '`' || ch == '\'') {
  225.             out += "&apos;"sv;
  226.             continue;
  227.            
  228.         } else if (ch == '<') {
  229.             out += "&lt;"sv;
  230.             continue;
  231.            
  232.         } else if (ch == '>') {
  233.             out += "&gt;"sv;
  234.             continue;
  235.            
  236.         } else if (ch == '&') {
  237.             out += "&amp;"sv;
  238.             continue;
  239.            
  240.         } else {}
  241.        
  242.         out += ch;
  243.     }
  244.  
  245.     return out;
  246. }
  247.  
  248. void Text::RenderObject(const RenderContext& context) const {
  249.    
  250.     std::ostream& out = context.out;
  251.  
  252.     out << R"(<text x=")"
  253.        << position_.x << R"(" y=")"
  254.        << position_.y << R"(" )"
  255.         << R"(dx=")"
  256.        << offset_.x << R"(" dy=")"
  257.        << offset_.y << R"(" )"
  258.         << R"(font-size=")"
  259.        << font_size_ << R"(")";
  260.  
  261.     if (!font_family_.empty()) {
  262.         out << R"( font-family=")" << font_family_ << R"(")";
  263.     }
  264.  
  265.     if (!font_weight_.empty()) {
  266.         out << R"( font-weight=")" << font_weight_ << R"(")";
  267.     }
  268.  
  269.     out << ">"sv << delete_spaces(uniq_symbols(data_)) << "</text>"sv;
  270.    
  271. }
  272.  
  273. // ---------- Document ------------------
  274.    
  275. void Document::AddPtr(std::unique_ptr<Object> &&obj) {
  276.     objects_.emplace_back(std::move(obj));
  277. }
  278.  
  279. void Document::Render(std::ostream &out) const {
  280.     int indent = 2;
  281.     int indent_step = 2;
  282.  
  283.     RenderContext context(out, indent_step, indent);
  284.  
  285.     const std::string_view xml = R"(<?xml version="1.0" encoding="UTF-8" ?>)";
  286.     const std::string_view svg = R"(<svg xmlns="http://www.w3.org/2000/svg" version="1.1">)";
  287.  
  288.     out << xml << "\n"sv << svg << "\n"sv;
  289.  
  290.     for (const auto& object : objects_) {
  291.         object->Render(context);
  292.     }
  293.    
  294.     out << "</svg>"sv;
  295. }
  296.  
  297. }  // namespace svg
  298. -----------------------------------------------------------------------
  299. main.cpp
  300. -----------------------------------------------------------------------
  301. #define _USE_MATH_DEFINES
  302. #include "svg.h" // Объявления классов библиотеки должны быть расположены в файле svg.h
  303.  
  304. #include <cmath>
  305.  
  306. using namespace std::literals;
  307. using namespace svg;
  308.  
  309. Polyline CreateStar(Point center, double outer_rad, double inner_rad, int num_rays) {
  310.     Polyline polyline;
  311.     for (int i = 0; i <= num_rays; ++i) {
  312.         double angle = 2 * M_PI * (i % num_rays) / num_rays;
  313.         polyline.AddPoint({center.x + outer_rad * sin(angle), center.y - outer_rad * cos(angle)});
  314.         if (i == num_rays) {
  315.             break;
  316.         }
  317.         angle += M_PI / num_rays;
  318.         polyline.AddPoint({center.x + inner_rad * sin(angle), center.y - inner_rad * cos(angle)});
  319.     }
  320.     return polyline;
  321. }
  322.  
  323. int main() {
  324.     Document doc;
  325.     doc.Add(Circle().SetCenter({20, 20}).SetRadius(10));
  326.     doc.Add(Text()
  327.                 .SetFontFamily("Verdana"s)
  328.                 .SetPosition({35, 20})
  329.                 .SetOffset({0, 6})
  330.                 .SetFontSize(12)
  331.                 .SetFontWeight("bold"s)
  332.                 .SetData("Hello C++"s));
  333.     doc.Add(CreateStar({20, 50}, 10, 5, 5));
  334.     doc.Render(std::cout);
  335. }
Advertisement
Add Comment
Please, Sign In to add comment