shushus

Спринт 11. Множественное наследование.

Apr 6th, 2023
548
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.82 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. svg.h
  3. -----------------------------------------------------------------------
  4. #pragma once
  5. #define _USE_MATH_DEFINES
  6.  
  7. #include <cstdint>
  8. #include <iostream>
  9. #include <memory>
  10. #include <string>
  11. #include <vector>
  12. #include <optional>
  13. #include <cmath>
  14.  
  15. namespace svg {
  16.    
  17. using Color = std::string;
  18. inline const Color NoneColor{"none"};
  19.  
  20. enum class StrokeLineCap {
  21.     BUTT,
  22.     ROUND,
  23.     SQUARE,
  24. };
  25.    
  26. inline std::ostream &operator<<(std::ostream &out, StrokeLineCap stroke_line_cap) {
  27.     using namespace std::literals;
  28.     if (stroke_line_cap == StrokeLineCap::BUTT) {
  29.         out << "butt"sv;
  30.     } else if (stroke_line_cap == StrokeLineCap::ROUND) {
  31.         out << "round"sv;
  32.     } else if (stroke_line_cap == StrokeLineCap::SQUARE) {
  33.         out << "square"sv;
  34.     }
  35.     return out;
  36. }
  37.  
  38. enum class StrokeLineJoin {
  39.     ARCS,
  40.     BEVEL,
  41.     MITER,
  42.     MITER_CLIP,
  43.     ROUND,
  44. };
  45.    
  46. inline std::ostream &operator<<(std::ostream &out, StrokeLineJoin stroke_line_join) {
  47.     using namespace std::literals;
  48.     if (stroke_line_join == StrokeLineJoin::ARCS) {
  49.         out << "arcs"sv;
  50.     } else if (stroke_line_join == StrokeLineJoin::BEVEL) {
  51.         out << "bevel"sv;
  52.     } else if (stroke_line_join == StrokeLineJoin::MITER) {
  53.         out << "miter"sv;
  54.     } else if (stroke_line_join == StrokeLineJoin::MITER_CLIP) {
  55.         out << "miter-clip"sv;
  56.     } else if (stroke_line_join == StrokeLineJoin::ROUND) {
  57.         out << "round"sv;
  58.     }
  59.     return out;
  60. }
  61.    
  62. template<typename Owner>
  63. class PathProps {
  64. public:
  65.     Owner& SetFillColor(Color color) {
  66.         fill_color_ = std::move(color);
  67.         return AsOwner();
  68.     }
  69.  
  70.     Owner& SetStrokeColor(Color color) {
  71.         stroke_color_ = std::move(color);
  72.         return AsOwner();
  73.     }
  74.  
  75.     Owner& SetStrokeWidth(double width) {
  76.         stroke_width_ = width;
  77.         return AsOwner();
  78.     }
  79.  
  80.     Owner& SetStrokeLineCap(StrokeLineCap line_cap) {
  81.         stroke_line_cap_ = line_cap;
  82.         return AsOwner();
  83.     }
  84.  
  85.     Owner& SetStrokeLineJoin(StrokeLineJoin line_join) {
  86.         stroke_line_join_ = line_join;
  87.         return AsOwner();
  88.     }
  89.  
  90. protected:
  91.     ~PathProps() = default;
  92.  
  93.     void RenderAttrs(std::ostream &out) const {
  94.         using namespace std::literals;
  95.  
  96.         if (fill_color_ != std::nullopt) {
  97.             out << "fill=\""sv << fill_color_.value() << "\" "sv;
  98.         }
  99.         if (stroke_color_ != std::nullopt) {
  100.             out << "stroke=\""sv << stroke_color_.value() << "\" "sv;
  101.         }
  102.         if (stroke_width_ != std::nullopt) {
  103.             out << "stroke-width=\""sv << stroke_width_.value() << "\" "sv;
  104.         }
  105.         if (stroke_line_cap_ != std::nullopt) {
  106.             out << "stroke-linecap=\""sv << stroke_line_cap_.value() << "\" "sv;
  107.         }
  108.         if (stroke_line_join_ != std::nullopt) {
  109.             out << "stroke-linejoin=\""sv << stroke_line_join_.value() << "\" "sv;
  110.         }
  111.     }
  112.    
  113. private:
  114.     std::optional<Color> fill_color_;
  115.     std::optional<Color> stroke_color_;
  116.     std::optional<double> stroke_width_;
  117.     std::optional<StrokeLineCap> stroke_line_cap_;
  118.     std::optional<StrokeLineJoin> stroke_line_join_;
  119.    
  120.     Owner& AsOwner() {
  121.         return static_cast<Owner&>(*this);
  122.     }
  123. };
  124.    
  125. struct Point {
  126.     Point() = default;
  127.     Point(double x, double y) : x(x)
  128.                               , y(y) {}
  129.     double x = 0;
  130.     double y = 0;
  131. };
  132.  
  133. struct RenderContext {
  134.     RenderContext(std::ostream& out) : out(out) {}
  135.  
  136.     RenderContext(std::ostream& out, int indent_step, int indent = 0) : out(out)
  137.                                                                       , indent_step(indent_step)
  138.                                                                       , indent(indent) {}
  139.  
  140.     RenderContext Indented() const {
  141.         return {out,
  142.                 indent_step,
  143.                 indent + indent_step};
  144.     }
  145.  
  146.     void RenderIndent() const {
  147.         for (int i = 0; i < indent; ++i) {
  148.             out.put(' ');
  149.         }
  150.     }
  151.  
  152.     std::ostream& out;
  153.     int indent_step = 0;
  154.     int indent = 0;
  155. };
  156.  
  157. class Object {
  158. public:
  159.     void Render(const RenderContext& context) const;
  160.     virtual ~Object() = default;
  161.  
  162. private:
  163.     virtual void RenderObject(const RenderContext& context) const = 0;
  164. };
  165.  
  166. class Circle final : public Object, public PathProps<Circle> {
  167. public:
  168.     Circle& SetCenter(Point center);
  169.     Circle& SetRadius(double radius);
  170.  
  171. private:
  172.     Point center_;
  173.     double radius_ = 1.0;
  174.    
  175.     void RenderObject(const RenderContext& context) const override;
  176. };
  177.  
  178. class Polyline final : public Object, public PathProps<Polyline> {
  179. public:
  180.     Polyline& AddPoint(Point point);
  181. private:
  182.     std::vector<Point> points_;
  183.     void RenderObject(const RenderContext& context) const override;
  184. };
  185.  
  186. class Text final : public Object, public PathProps<Text> {
  187. public:
  188.     Text& SetPosition(Point pos);
  189.     Text& SetOffset(Point offset);
  190.     Text& SetFontSize(uint32_t size);
  191.     Text& SetFontFamily(std::string font_family);
  192.     Text& SetFontWeight(std::string font_weight);
  193.     Text& SetData(std::string data);
  194.  
  195. private:
  196.     Point position_;
  197.     Point offset_;
  198.     std::string font_family_;
  199.     std::string font_weight_;
  200.     uint32_t font_size_ = 1;
  201.     std::string data_;
  202.      
  203.     static std::string delete_spaces(const std::string& str);
  204.     static std::string uniq_symbols(const std::string& str);
  205.    
  206.     void RenderObject(const RenderContext& context) const override;
  207. };
  208.    
  209. class ObjectContainer {
  210. public:
  211.     virtual ~ObjectContainer() = default;
  212.  
  213.     template<typename Obj>
  214.     void Add(Obj obj);
  215.  
  216.     virtual void AddPtr(std::unique_ptr<Object> &&) = 0;
  217.  
  218. protected:
  219.     std::vector<std::unique_ptr<Object>> objects_;
  220. };
  221.    
  222. template<typename Obj>
  223. void ObjectContainer::Add(Obj obj) {
  224.     objects_.emplace_back(std::make_unique<Obj>(std::move(obj)));
  225. }
  226.    
  227. class Drawable {
  228. public:
  229.     virtual void Draw(ObjectContainer& container) const = 0;
  230.     virtual ~Drawable() = default;
  231. };
  232.  
  233. namespace shapes {  
  234. class Triangle : public Drawable {
  235. public:
  236.     Triangle(Point p1, Point p2, Point p3)
  237.         : p1_(p1)
  238.         , p2_(p2)
  239.         , p3_(p3) {}
  240.  
  241.     void Draw(ObjectContainer& container) const override {
  242.         container.Add(Polyline().AddPoint(p1_).AddPoint(p2_).AddPoint(p3_).AddPoint(p1_));
  243.     }
  244.  
  245. private:
  246.     Point p1_, p2_, p3_;
  247. };
  248.  
  249. class Star : public Drawable {
  250. public:
  251.     Star(Point center, double outer_rad, double inner_rad, int num_rays) {
  252.         polyline_ = CreateStar(center,
  253.                                outer_rad,
  254.                                inner_rad,
  255.                                num_rays);
  256.     }
  257.  
  258.     void Draw(ObjectContainer& container) const override {
  259.         container.Add(polyline_);
  260.     }
  261.  
  262. private:
  263.    
  264.     Polyline polyline_;
  265.    
  266.     Polyline CreateStar(Point center, double outer_rad, double inner_rad, int num_rays) {
  267.         using namespace svg;
  268.         Polyline polyline;
  269.         polyline.SetFillColor("red");
  270.         polyline.SetStrokeColor("black");
  271.         for (int i = 0; i <= num_rays; ++i) {
  272.             double angle = 2 * M_PI * (i % num_rays) / num_rays;
  273.             polyline.AddPoint({center.x + outer_rad * sin(angle), center.y - outer_rad * cos(angle)});
  274.             if (i == num_rays) {
  275.                 break;
  276.             }
  277.             angle += M_PI / num_rays;
  278.             polyline.AddPoint({center.x + inner_rad * sin(angle), center.y - inner_rad * cos(angle)});
  279.             }
  280.         return polyline;
  281.     }
  282. };
  283.  
  284. class Snowman : public Drawable {
  285. public:
  286.     Snowman(Point head_point, double radius) : head_(head_point)
  287.                                              , radius_(radius){}
  288.  
  289.     void Draw(ObjectContainer& container) const override {
  290.        
  291.         using namespace svg;
  292.         Circle head;
  293.         head.SetFillColor("rgb(240,240,240)");
  294.         head.SetStrokeColor("black");
  295.         head.SetCenter(head_).SetRadius(radius_);
  296.        
  297.         Circle middle;
  298.         middle.SetFillColor("rgb(240,240,240)");
  299.         middle.SetStrokeColor("black");
  300.         middle.SetCenter({ head_.x, head_.y + radius_ * 2 }).SetRadius(radius_ * 1.5);
  301.        
  302.         Circle down;
  303.         down.SetFillColor("rgb(240,240,240)");
  304.         down.SetStrokeColor("black");
  305.         down.SetCenter({ head_.x, head_.y + radius_ * 5 }).SetRadius(radius_ * 2);
  306.        
  307.         container.Add(down);
  308.         container.Add(middle);
  309.         container.Add(head);
  310.     }
  311.    
  312. private:
  313.     Point head_;
  314.     double radius_;
  315. };
  316. }//end namespace shapes
  317.    
  318. class Document : public ObjectContainer {
  319. public:
  320.    
  321.     void AddPtr(std::unique_ptr<Object>&& obj) override {
  322.         objects_.emplace_back(std::move(obj));
  323.     }
  324.     void Render(std::ostream& out) const;
  325. };
  326.  
  327. }//end namespace svg
  328. -----------------------------------------------------------------------
  329. svg.cpp
  330. -----------------------------------------------------------------------
  331. #include "svg.h"
  332.  
  333. namespace svg {
  334.  
  335. using namespace std::literals;
  336.  
  337. void Object::Render(const RenderContext& context) const {
  338.     context.RenderIndent();
  339.     RenderObject(context);
  340.     context.out << std::endl;
  341. }
  342.  
  343. // ---------- Circle ------------------
  344.  
  345. Circle& Circle::SetCenter(Point center)  {
  346.     center_ = center;
  347.     return *this;
  348. }
  349.  
  350. Circle& Circle::SetRadius(double radius)  {
  351.     radius_ = radius;
  352.     return *this;
  353. }
  354.  
  355. void Circle::RenderObject(const RenderContext& context) const {
  356.     std::ostream& out = context.out;
  357.  
  358.     out << "<circle cx=\""sv << center_.x
  359.         << "\" cy=\""sv << center_.y << "\" "sv;
  360.     out << "r=\""sv << radius_ << "\" "sv;
  361.    
  362.     RenderAttrs(context.out);
  363.     out << "/>"sv;
  364. }
  365.  
  366. // ---------- Polyline ------------------
  367.    
  368. Polyline& Polyline::AddPoint(Point point) {
  369.     points_.emplace_back(point);
  370.     return *this;
  371. }
  372.  
  373. void Polyline::RenderObject(const RenderContext& context) const {
  374.    
  375.     std::ostream& out = context.out;
  376.     out << "<polyline points=\"";
  377.    
  378.     for (size_t i = 0; i < points_.size(); ++i) {
  379.         out << points_[i].x << ","sv << points_[i].y;
  380.  
  381.         if (i+1 != points_.size()) {
  382.             out << " "sv;
  383.         }
  384.     }
  385.     out << "\" ";
  386.     RenderAttrs(context.out);
  387.     out << "/>";
  388. }
  389.  
  390. // ---------- Text ------------------
  391.    
  392. Text& Text::SetPosition(Point pos) {
  393.     position_ = pos;
  394.     return *this;
  395. }
  396.  
  397. Text& Text::SetOffset(Point offset) {
  398.     offset_ = offset;
  399.     return *this;
  400. }
  401.    
  402. Text& Text::SetFontSize(uint32_t size) {
  403.     font_size_ = size;
  404.     return *this;
  405. }
  406.  
  407. Text& Text::SetFontFamily(std::string font_family) {
  408.     font_family_ = std::move(font_family);
  409.     return *this;
  410. }
  411.  
  412. Text& Text::SetFontWeight(std::string font_weight) {
  413.     font_weight_ = std::move(font_weight);
  414.     return *this;
  415. }
  416.  
  417. Text& Text::SetData(std::string data) {
  418.     data_ = std::move(data);
  419.     return *this;
  420. }
  421.  
  422. std::string Text::delete_spaces(const std::string& str) {
  423.     if (str.empty()) {
  424.         return {};
  425.     } else {
  426.        
  427.         auto left = str.find_first_not_of(' ');
  428.         auto right = str.find_last_not_of(' ');
  429.         return str.substr(left, right - left + 1);  
  430.     }
  431. }
  432.  
  433. std::string Text::uniq_symbols(const std::string& str) {
  434.    
  435.     std::string out;
  436.  
  437.     for (char ch : str) {
  438.        
  439.         if (ch == '"') {
  440.             out += "&quot;"sv;
  441.             continue;
  442.            
  443.         } else if (ch == '`' || ch == '\'') {
  444.             out += "&apos;"sv;
  445.             continue;
  446.            
  447.         } else if (ch == '<') {
  448.             out += "&lt;"sv;
  449.             continue;
  450.            
  451.         } else if (ch == '>') {
  452.             out += "&gt;"sv;
  453.             continue;
  454.            
  455.         } else if (ch == '&') {
  456.             out += "&amp;"sv;
  457.             continue;
  458.            
  459.         } else {
  460.            
  461.         }
  462.        
  463.         out += ch;
  464.     }
  465.  
  466.     return out;
  467. }
  468.  
  469. void Text::RenderObject(const RenderContext& context) const {
  470.    
  471.     std::ostream& out = context.out;
  472.     out << "<text ";
  473.     RenderAttrs(context.out);
  474.     out << "x=\""
  475.         << position_.x << "\" y=\""
  476.         << position_.y << "\" "
  477.         << "dx=\""
  478.         << offset_.x << "\" dy=\""
  479.         << offset_.y << "\" "
  480.         << "font-size=\""
  481.         << font_size_ << "\" ";
  482.  
  483.     if (!font_family_.empty()) {
  484.         out << "font-family=\"" << font_family_ << "\" ";
  485.     }
  486.  
  487.     if (!font_weight_.empty()) {
  488.         out << "font-weight=\"" << font_weight_ << "\"";
  489.     }
  490.  
  491.     out << ">"sv << delete_spaces(uniq_symbols(data_)) << "</text>"sv;
  492.  
  493. }
  494.  
  495. // ---------- Document ------------------
  496.  
  497. void Document::Render(std::ostream& out) const {
  498.     int indent = 2;
  499.     int indent_step = 2;
  500.  
  501.     RenderContext context(out, indent_step, indent);
  502.  
  503.     const std::string_view xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"sv;
  504.     const std::string_view svg = "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"sv;
  505.  
  506.     out << xml << "\n"sv << svg << "\n"sv;
  507.  
  508.     for (const auto& object : objects_) {
  509.         object->Render(context);
  510.     }
  511.    
  512.     out << "</svg>"sv;
  513. }
  514.  
  515. }//end namespace svg
  516. -----------------------------------------------------------------------
  517. main.cpp
  518. -----------------------------------------------------------------------
  519. #include "svg.h"
  520.  
  521. using namespace std::literals;
  522. using namespace svg;
  523.  
  524. template <typename DrawableIterator>
  525. void DrawPicture(DrawableIterator begin, DrawableIterator end, svg::ObjectContainer& target) {
  526.     for (auto it = begin; it != end; ++it) {
  527.         (*it)->Draw(target);
  528.     }
  529. }
  530.  
  531. template <typename Container>
  532. void DrawPicture(const Container& container, svg::ObjectContainer& target) {
  533.     using namespace std;
  534.     DrawPicture(begin(container), end(container), target);
  535. }
  536.  
  537. int main() {
  538.     using namespace svg;
  539.     using namespace shapes;
  540.     using namespace std;
  541.  
  542.     vector<unique_ptr<svg::Drawable>> picture;
  543.     picture.emplace_back(make_unique<Triangle>(Point{100, 20}, Point{120, 50}, Point{80, 40}));
  544.     picture.emplace_back(make_unique<Star>(Point{50.0, 20.0}, 10.0, 4.0, 5));
  545.     picture.emplace_back(make_unique<Snowman>(Point{30, 20}, 10.0));
  546.  
  547.     svg::Document doc;
  548.     DrawPicture(picture, doc);
  549.  
  550.     const Text base_text =
  551.         Text()
  552.             .SetFontFamily("Verdana"s)
  553.             .SetFontSize(12)
  554.             .SetPosition({10, 100})
  555.             .SetData("Happy New Year!"s);
  556.     doc.Add(Text{base_text}
  557.                 .SetStrokeColor("yellow"s)
  558.                 .SetFillColor("yellow"s)
  559.                 .SetStrokeLineJoin(StrokeLineJoin::ROUND)
  560.                 .SetStrokeLineCap(StrokeLineCap::ROUND)
  561.                 .SetStrokeWidth(3));
  562.     doc.Add(Text{base_text}.SetFillColor("red"s));
  563.  
  564.     doc.Render(cout);
  565. }
Advertisement
Add Comment
Please, Sign In to add comment