shushus

Спринт 11. Интерфейсы.

Apr 6th, 2023
654
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.89 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 ObjectContainer {
  98. public:
  99.     virtual ~ObjectContainer() = default;
  100.  
  101.     template<typename Obj>
  102.     void Add(Obj obj);
  103.  
  104.     virtual void AddPtr(std::unique_ptr<Object> &&) = 0;
  105.  
  106. protected:
  107.     std::vector<std::unique_ptr<Object>> objects_;
  108. };
  109.    
  110. template<typename Obj>
  111. void ObjectContainer::Add(Obj obj) {
  112.     objects_.emplace_back(std::make_unique<Obj>(std::move(obj)));
  113. }
  114.    
  115. class Drawable {
  116. public:
  117.     virtual void Draw(ObjectContainer& container) const = 0;
  118.     virtual ~Drawable() = default;
  119. };
  120.  
  121. class Document : public ObjectContainer {
  122. public:
  123.    
  124.     void AddPtr(std::unique_ptr<Object>&& obj) override {
  125.         objects_.emplace_back(std::move(obj));
  126.     }
  127.     void Render(std::ostream& out) const;
  128. };
  129.  
  130. }//end namespace svg
  131. -----------------------------------------------------------------------
  132. svg.cpp
  133. -----------------------------------------------------------------------
  134. #include "svg.h"
  135.  
  136. namespace svg {
  137.  
  138. using namespace std::literals;
  139.  
  140. void Object::Render(const RenderContext& context) const {
  141.     context.RenderIndent();
  142.     RenderObject(context);
  143.     context.out << std::endl;
  144. }
  145.  
  146. // ---------- Circle ------------------
  147.  
  148. Circle& Circle::SetCenter(Point center)  {
  149.     center_ = center;
  150.     return *this;
  151. }
  152.  
  153. Circle& Circle::SetRadius(double radius)  {
  154.     radius_ = radius;
  155.     return *this;
  156. }
  157.  
  158. void Circle::RenderObject(const RenderContext& context) const {
  159.     std::ostream& out = context.out;
  160.    
  161.     out << R"(<circle cx=")"
  162.        << center_.x << R"(" cy=")"
  163.        << center_.y << R"(" )"
  164.         << R"(r=")"
  165.        << radius_ << R"(" )" << "/>"sv;
  166. }
  167.  
  168. // ---------- Polyline ------------------
  169.    
  170. Polyline& Polyline::AddPoint(Point point) {
  171.     points_.emplace_back(point);
  172.     return *this;
  173. }
  174.  
  175. void Polyline::RenderObject(const RenderContext& context) const {
  176.    
  177.     std::ostream& out = context.out;
  178.     out << R"(<polyline points=")";
  179.  
  180.    for (size_t i = 0; i < points_.size(); ++i) {
  181.        out << points_[i].x << ","sv << points_[i].y;
  182.  
  183.        if (i+1 != points_.size()) {
  184.            out << " "sv;
  185.        }
  186.    }
  187.  
  188.    out << R"(")" << " />"sv;
  189. }
  190.  
  191. // ---------- Text ------------------
  192.    
  193. Text& Text::SetPosition(Point pos) {
  194.     position_ = pos;
  195.     return *this;
  196. }
  197.  
  198. Text& Text::SetOffset(Point offset) {
  199.     offset_ = offset;
  200.     return *this;
  201. }
  202.    
  203. Text& Text::SetFontSize(uint32_t size) {
  204.     font_size_ = size;
  205.     return *this;
  206. }
  207.  
  208. Text& Text::SetFontFamily(std::string font_family) {
  209.     font_family_ = std::move(font_family);
  210.     return *this;
  211. }
  212.  
  213. Text& Text::SetFontWeight(std::string font_weight) {
  214.     font_weight_ = std::move(font_weight);
  215.     return *this;
  216. }
  217.  
  218. Text& Text::SetData(std::string data) {
  219.     data_ = std::move(data);
  220.     return *this;
  221. }
  222.  
  223. std::string Text::delete_spaces(const std::string& str) {
  224.     if (str.empty()) {
  225.         return {};
  226.     } else {
  227.        
  228.         auto left = str.find_first_not_of(' ');
  229.         auto right = str.find_last_not_of(' ');
  230.         return str.substr(left, right - left + 1);  
  231.     }
  232. }
  233.  
  234. std::string Text::uniq_symbols(const std::string& str) {
  235.    
  236.     std::string out;
  237.  
  238.     for (char ch : str) {
  239.        
  240.         if (ch == '"') {
  241.             out += "&quot;"sv;
  242.             continue;
  243.            
  244.         } else if (ch == '`' || ch == '\'') {
  245.             out += "&apos;"sv;
  246.             continue;
  247.            
  248.         } else if (ch == '<') {
  249.             out += "&lt;"sv;
  250.             continue;
  251.            
  252.         } else if (ch == '>') {
  253.             out += "&gt;"sv;
  254.             continue;
  255.            
  256.         } else if (ch == '&') {
  257.             out += "&amp;"sv;
  258.             continue;
  259.            
  260.         } else {
  261.            
  262.         }
  263.        
  264.         out += ch;
  265.     }
  266.  
  267.     return out;
  268. }
  269.  
  270. void Text::RenderObject(const RenderContext& context) const {
  271.    
  272.     std::ostream& out = context.out;
  273.  
  274.     out << R"(<text x=")"
  275.        << position_.x << R"(" y=")"
  276.        << position_.y << R"(" )"
  277.         << R"(dx=")"
  278.        << offset_.x << R"(" dy=")"
  279.        << offset_.y << R"(" )"
  280.         << R"(font-size=")"
  281.        << font_size_ << R"(")";
  282.  
  283.     if (!font_family_.empty()) {
  284.         out << R"( font-family=")" << font_family_ << R"(")";
  285.     }
  286.  
  287.     if (!font_weight_.empty()) {
  288.         out << R"( font-weight=")" << font_weight_ << R"(")";
  289.     }
  290.  
  291.     out << ">"sv << delete_spaces(uniq_symbols(data_)) << "</text>"sv;
  292.    
  293. }
  294.  
  295. // ---------- Document ------------------
  296.  
  297. void Document::Render(std::ostream& out) const {
  298.     int indent = 2;
  299.     int indent_step = 2;
  300.  
  301.     RenderContext context(out, indent_step, indent);
  302.  
  303.     const std::string_view xml = R"(<?xml version="1.0" encoding="UTF-8" ?>)";
  304.     const std::string_view svg = R"(<svg xmlns="http://www.w3.org/2000/svg" version="1.1">)";
  305.  
  306.     out << xml << "\n"sv << svg << "\n"sv;
  307.  
  308.     for (const auto& object : objects_) {
  309.         object->Render(context);
  310.     }
  311.    
  312.     out << "</svg>"sv;
  313. }
  314.  
  315. }//end namespace svg
  316. -----------------------------------------------------------------------
  317. main.cpp
  318. -----------------------------------------------------------------------
  319. #define _USE_MATH_DEFINES
  320. #include "svg.h"
  321.  
  322. #include <cmath>
  323.  
  324. using namespace std::literals;
  325. using namespace svg;
  326.  
  327. template <typename DrawableIterator>
  328. void DrawPicture(DrawableIterator begin, DrawableIterator end, svg::ObjectContainer& target) {
  329.     for (auto it = begin; it != end; ++it) {
  330.         (*it)->Draw(target);
  331.     }
  332. }
  333.  
  334. template <typename Container>
  335. void DrawPicture(const Container& container, svg::ObjectContainer& target) {
  336.     using namespace std;
  337.     DrawPicture(begin(container), end(container), target);
  338. }
  339.  
  340. namespace shapes {
  341.    
  342. class Triangle : public svg::Drawable {
  343. public:
  344.     Triangle(svg::Point p1, svg::Point p2, svg::Point p3)
  345.         : p1_(p1)
  346.         , p2_(p2)
  347.         , p3_(p3) {}
  348.  
  349.     void Draw(svg::ObjectContainer& container) const override {
  350.         container.Add(svg::Polyline().AddPoint(p1_).AddPoint(p2_).AddPoint(p3_).AddPoint(p1_));
  351.     }
  352.  
  353. private:
  354.     svg::Point p1_, p2_, p3_;
  355. };
  356.  
  357. class Star : public svg::Drawable {
  358. public:
  359.     Star(svg::Point center, double outer_rad, double inner_rad, int num_rays) {
  360.         polyline_ = CreateStar(center,
  361.                                outer_rad,
  362.                                inner_rad,
  363.                                num_rays);
  364.     }
  365.  
  366.     void Draw(svg::ObjectContainer& container) const override {
  367.         container.Add(polyline_);
  368.     }
  369.  
  370. private:
  371.    
  372.     svg::Polyline polyline_;
  373.    
  374.     svg::Polyline CreateStar(svg::Point center, double outer_rad, double inner_rad, int num_rays) {
  375.         using namespace svg;
  376.         Polyline polyline;
  377.         for (int i = 0; i <= num_rays; ++i) {
  378.             double angle = 2 * M_PI * (i % num_rays) / num_rays;
  379.             polyline.AddPoint({center.x + outer_rad * sin(angle), center.y - outer_rad * cos(angle)});
  380.             if (i == num_rays) {
  381.                 break;
  382.             }
  383.             angle += M_PI / num_rays;
  384.             polyline.AddPoint({center.x + inner_rad * sin(angle), center.y - inner_rad * cos(angle)});
  385.             }
  386.         return polyline;
  387.     }
  388. };
  389.  
  390. class Snowman : public svg::Drawable {
  391. public:
  392.     Snowman(svg::Point head_point, double radius) : head_(head_point)
  393.                                                   , radius_(radius){}
  394.  
  395.     void Draw(svg::ObjectContainer& container) const override {
  396.        
  397.         using namespace svg;
  398.         Circle head;
  399.         head.SetCenter(head_).SetRadius(radius_);
  400.        
  401.         Circle middle;
  402.         middle.SetCenter({ head_.x, head_.y + radius_ * 2 }).SetRadius(radius_ * 1.5);
  403.        
  404.         Circle down;
  405.         down.SetCenter({ head_.x, head_.y + radius_ * 5 }).SetRadius(radius_ * 2);
  406.        
  407.         container.Add(down);
  408.         container.Add(middle);
  409.         container.Add(head);
  410.     }
  411.    
  412. private:
  413.     svg::Point head_;
  414.     double radius_;
  415. };
  416.  
  417. }//end namespace shapes
  418.  
  419. int main() {
  420.     using namespace svg;
  421.     using namespace shapes;
  422.     using namespace std;
  423.  
  424.     vector<unique_ptr<svg::Drawable>> picture;
  425.  
  426.     picture.emplace_back(make_unique<Triangle>(Point{100, 20}, Point{120, 50}, Point{80, 40}));
  427.     picture.emplace_back(make_unique<Star>(Point{50.0, 20.0}, 10.0, 4.0, 5));
  428.     picture.emplace_back(make_unique<Snowman>(Point{30, 20}, 10.0));
  429.  
  430.     svg::Document doc;
  431.     DrawPicture(picture, doc);
  432.  
  433.     doc.Render(cout);
  434. }
Advertisement
Add Comment
Please, Sign In to add comment