From 16fa0b630556524e53e5bfaf6d43c0305f0a78af Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Sun, 3 Sep 2023 11:55:38 +0800 Subject: [PATCH 01/17] not ready --- src/naive_svg.hpp | 81 ++++++++++++++++++++++++-------------- src/pybind11_naive_svg.cpp | 20 +++++++++- 2 files changed, 69 insertions(+), 32 deletions(-) diff --git a/src/naive_svg.hpp b/src/naive_svg.hpp index ba8e900..a71b102 100644 --- a/src/naive_svg.hpp +++ b/src/naive_svg.hpp @@ -321,35 +321,27 @@ struct SVG static std::string html_escape(const std::string &text) { - const static std::vector escapes = { - "&", """, "'", "<", ">"}; - std::map replace; - for (size_t pos = 0; pos != text.size(); ++pos) { - const char c = text[pos]; - if (c == '&') { - replace[pos] = 0; - } else if (c == '\"') { - replace[pos] = 1; - } else if (c == '\'') { - replace[pos] = 2; - } else if (c == '<') { - replace[pos] = 3; - } else if (c == '>') { - replace[pos] = 4; - } - } - if (replace.empty()) { - return text; - } std::string buffer; - buffer.reserve(text.size() + 6 * replace.size()); - // TODO - for (size_t pos = 0; pos != text.size(); ++pos) { - auto itr = replace.find(text[pos]); - if (itr == replace.end()) { - buffer.append(&text[pos], 1); - } else { - buffer.append(escapes[itr->second]); + for (char c : text) { + switch (c) { + case '&': + buffer.append("&"); + break; + case '\"': + buffer.append("""); + break; + case '\'': + buffer.append("'"); + break; + case '<': + buffer.append("<"); + break; + case '>': + buffer.append(">"); + break; + default: + buffer.push_back(c); + break; } } return buffer; @@ -388,12 +380,34 @@ struct SVG SETUP_FLUENT_API(SVG, Color, grid_color) SETUP_FLUENT_API(SVG, Color, background) - Polygon &add_polygon(const std::vector &points) + Polyline &add(const Polyline &polyline) { - auto ptr = new Polygon(points); + auto ptr = new Polyline({}); + *ptr = polyline; + elements_.push_back({ELEMENT::POLYLINE, (void *)ptr}); + return *ptr; + } + Polygon &add(const Polygon &polygon) + { + auto ptr = new Polygon({}); + *ptr = polygon; elements_.push_back({ELEMENT::POLYGON, (void *)ptr}); return *ptr; } + Circle &add(const Circle &circle) + { + auto ptr = new Circle(circle.center()); + *ptr = circle; + elements_.push_back({ELEMENT::CIRCLE, (void *)ptr}); + return *ptr; + } + Text &add(const Text &text) + { + auto ptr = new Text(text.position(), ""); + *ptr = text; + elements_.push_back({ELEMENT::TEXT, (void *)ptr}); + return *ptr; + } Polyline &add_polyline(const std::vector &points) { @@ -402,6 +416,13 @@ struct SVG return *ptr; } + Polygon &add_polygon(const std::vector &points) + { + auto ptr = new Polygon(points); + elements_.push_back({ELEMENT::POLYGON, (void *)ptr}); + return *ptr; + } + Circle &add_circle(const PointType ¢er, double r = 1.0) { auto ptr = new Circle(center, r); diff --git a/src/pybind11_naive_svg.cpp b/src/pybind11_naive_svg.cpp index 516cf9f..a23185c 100644 --- a/src/pybind11_naive_svg.cpp +++ b/src/pybind11_naive_svg.cpp @@ -21,10 +21,26 @@ using rvp = py::return_value_policy; using RowVectorsNx2 = Eigen::Matrix; +// TODO, 各个类型的 from/to_json +// svg 的 load/dump +// svg extra attributes + CUBAO_INLINE void bind_naive_svg(py::module &m) { - py::class_(m, "Polyline", py::module_local()) // - // + // https://github.com/gagan-bansal/geojson2svg + // https://milevski.co/geojson2svg/demo/lands.svg + // 还是转化到 ENU 下,更好。radius 的尺度是一致的, stroke 也更好调 + py::class_( + m, "Polyline", + py::module_local()) // + // .def(py::init([](const Eigen::Ref &points) { + // std::vector _(points.rows()); + // Eigen::Map(&_[0], + // points.rows(), 2) = points; return new + // SVG::Polyline(_); + // }), "points"_a) + // ; py::class_(m, "Polygon", py::module_local()) // From 097512348608d6a053ec5e687eba6203534ca470 Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Sun, 3 Sep 2023 12:20:29 +0800 Subject: [PATCH 02/17] good --- src/naive_svg.hpp | 4 +- src/pybind11_naive_svg.cpp | 91 +++++++++++++++++++++++++++++++------- 2 files changed, 78 insertions(+), 17 deletions(-) diff --git a/src/naive_svg.hpp b/src/naive_svg.hpp index a71b102..ebccd0b 100644 --- a/src/naive_svg.hpp +++ b/src/naive_svg.hpp @@ -32,8 +32,8 @@ namespace cubao #ifndef SETUP_FLUENT_API_FOR_SVG_ELEMENT #define SETUP_FLUENT_API_FOR_SVG_ELEMENT(KlassType) \ SETUP_FLUENT_API(KlassType, Color, stroke) \ - SETUP_FLUENT_API(KlassType, Color, fill) \ - SETUP_FLUENT_API(KlassType, double, stroke_width) + SETUP_FLUENT_API(KlassType, double, stroke_width) \ + SETUP_FLUENT_API(KlassType, Color, fill) #endif struct SVG diff --git a/src/pybind11_naive_svg.cpp b/src/pybind11_naive_svg.cpp index a23185c..2241d6e 100644 --- a/src/pybind11_naive_svg.cpp +++ b/src/pybind11_naive_svg.cpp @@ -30,24 +30,85 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) // https://github.com/gagan-bansal/geojson2svg // https://milevski.co/geojson2svg/demo/lands.svg // 还是转化到 ENU 下,更好。radius 的尺度是一致的, stroke 也更好调 - py::class_( - m, "Polyline", - py::module_local()) // - // .def(py::init([](const Eigen::Ref &points) { - // std::vector _(points.rows()); - // Eigen::Map(&_[0], - // points.rows(), 2) = points; return new - // SVG::Polyline(_); - // }), "points"_a) - // + +#define SETUP_FLUENT_API_PYBIND(Klass, VarType, VarName) \ + .def(#VarName, [](const Klass &self) { return self.VarName(); }) \ + .def( \ + #VarName, \ + [](Klass &self, const VarType &v) { return self.VarName(v); }, \ + rvp::reference_internal) + + using Color = SVG::Color; + py::class_(m, "Color", + py::module_local()) // + .def(py::init(), "rgb"_a = -1) + .def(py::init(), "r"_a, "g"_a, "b"_a, + "a"_a = -1.f) + .def("r", [](const Color &self) { return self.r(); }) + .def( + "r", [](Color &self, int r) { return self.r(r); }, + rvp::reference_internal) // + SETUP_FLUENT_API_PYBIND(Color, int, g) + SETUP_FLUENT_API_PYBIND(Color, int, b) + SETUP_FLUENT_API_PYBIND(Color, float, a) + .def("invalid", &Color::invalid) + .def("to_string", &Color::to_string) + .def_static("parse", + [](const std::string &text) { + int i = text.size() - 6; + if (i < 0) { + return Color(); + } + return Color( + std::stoi(text.substr(i, 2), nullptr, 16), + std::stoi(text.substr(i + 2, 2), nullptr, 16), + std::stoi(text.substr(i + 4, 2), nullptr, 16)); + }) + // + ; + + using Polyline = SVG::Polyline; + py::class_(m, "Polyline", + py::module_local()) // + .def(py::init([](const Eigen::Ref &points) { + std::vector _(points.rows()); + Eigen::Map(&_[0][0], points.rows(), 2) = points; + return new SVG::Polyline(_); + }), + "points"_a) + // + SETUP_FLUENT_API_PYBIND(Polyline, Color, stroke) + SETUP_FLUENT_API_PYBIND(Polyline, double, stroke_width) + SETUP_FLUENT_API_PYBIND(Polyline, Color, fill) + // ; - py::class_(m, "Polygon", py::module_local()) // - // + using Polygon = SVG::Polygon; + py::class_<>(m, "Polygon", py::module_local()) // + // + // + .def(py::init([](const Eigen::Ref &points) { + std::vector _(points.rows()); + Eigen::Map(&_[0][0], points.rows(), 2) = points; + return new SVG::Polygon(_); + }), + "points"_a) // + SETUP_FLUENT_API_PYBIND(Polygon, Color, stroke) + SETUP_FLUENT_API_PYBIND(Polygon, double, stroke_width) + SETUP_FLUENT_API_PYBIND(Polygon, Color, fill) + // ; - py::class_(m, "Circle", py::module_local()) // - // + + using Circle = SVG::Circle; + py::class_(m, "Circle", py::module_local()) // + .def(py::init([](const Eigen::Vector2d ¢er, double r) { + return new SVG::Circle({center[0], center[1]}, r); + }), + "center"_a, "r"_a = 1.0) // + SETUP_FLUENT_API_PYBIND(Circle, Color, stroke) + SETUP_FLUENT_API_PYBIND(Circle, double, stroke_width) + SETUP_FLUENT_API_PYBIND(Circle, Color, fill) + // ; py::class_(m, "Text", py::module_local()) // // From c32c2570876e0c53724a89e77795cba6c526f14c Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Sun, 3 Sep 2023 12:25:36 +0800 Subject: [PATCH 03/17] good --- src/naive_svg.hpp | 5 +++-- src/pybind11_naive_svg.cpp | 29 ++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/naive_svg.hpp b/src/naive_svg.hpp index ebccd0b..2eb5eb4 100644 --- a/src/naive_svg.hpp +++ b/src/naive_svg.hpp @@ -244,9 +244,10 @@ struct SVG struct Text : Element { - Text(const PointType &p, const std::string &text, int fontsize = 10.0) + Text(const PointType &position, const std::string &text, + int fontsize = 10.0) { - points_ = {p}; + points_ = {position}; text_ = text; fontsize_ = fontsize; fill_ = COLOR::BLACK; diff --git a/src/pybind11_naive_svg.cpp b/src/pybind11_naive_svg.cpp index 2241d6e..98a2340 100644 --- a/src/pybind11_naive_svg.cpp +++ b/src/pybind11_naive_svg.cpp @@ -81,12 +81,13 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(Polyline, double, stroke_width) SETUP_FLUENT_API_PYBIND(Polyline, Color, fill) // + .def("to_string", &Polyline::to_string) + // ; using Polygon = SVG::Polygon; - py::class_<>(m, "Polygon", py::module_local()) // - // - // + py::class_(m, "Polygon", py::module_local()) // + // .def(py::init([](const Eigen::Ref &points) { std::vector _(points.rows()); Eigen::Map(&_[0][0], points.rows(), 2) = points; @@ -97,6 +98,9 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(Polygon, double, stroke_width) SETUP_FLUENT_API_PYBIND(Polygon, Color, fill) // + .def("to_string", &Polygon::to_string) + // + ; using Circle = SVG::Circle; @@ -109,9 +113,24 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(Circle, double, stroke_width) SETUP_FLUENT_API_PYBIND(Circle, Color, fill) // + .def("to_string", &Circle::to_string) + // ; - py::class_(m, "Text", py::module_local()) // - // + + using Text = SVG::Text; + py::class_(m, "Text", py::module_local()) // + .def(py::init([](const Eigen::Vector2d &position, + const std::string &text, double fontsize) { + return new SVG::Text({position[0], position[1]}, text, + fontsize); + }), + "position"_a, "text"_a, "fontsize"_a = 10.0) // + SETUP_FLUENT_API_PYBIND(Circle, Color, stroke) + SETUP_FLUENT_API_PYBIND(Circle, double, stroke_width) + SETUP_FLUENT_API_PYBIND(Circle, Color, fill) + // + .def("to_string", &Text::to_string) + // ; py::class_(m, "SVG", py::module_local()) From 37e1b83c85cde9fc444afa7add49c9f5c2cf7c63 Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Sun, 3 Sep 2023 12:31:22 +0800 Subject: [PATCH 04/17] from/to numpy --- src/pybind11_naive_svg.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/pybind11_naive_svg.cpp b/src/pybind11_naive_svg.cpp index 98a2340..1e6e6ab 100644 --- a/src/pybind11_naive_svg.cpp +++ b/src/pybind11_naive_svg.cpp @@ -77,6 +77,22 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) }), "points"_a) // + .def("to_numpy", + [](const Polyline &self) -> RowVectorsNx2 { + auto &points = self.points(); + return Eigen::Map(&points[0][0], + points.size(), 2); + }) + .def( + "from_numpy", + [](Polyline &self, + const Eigen::Ref &points) -> Polyline & { + std::vector _(points.rows()); + Eigen::Map(&_[0][0], points.rows(), 2) = points; + return self.points(_); + }, + rvp::reference_internal) // + // SETUP_FLUENT_API_PYBIND(Polyline, Color, stroke) SETUP_FLUENT_API_PYBIND(Polyline, double, stroke_width) SETUP_FLUENT_API_PYBIND(Polyline, Color, fill) From a3d83fa8d87d25be43d69506a2b880206d248a98 Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Sun, 3 Sep 2023 12:42:09 +0800 Subject: [PATCH 05/17] good --- src/pybind11_naive_svg.cpp | 54 +++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/src/pybind11_naive_svg.cpp b/src/pybind11_naive_svg.cpp index 1e6e6ab..cab5f61 100644 --- a/src/pybind11_naive_svg.cpp +++ b/src/pybind11_naive_svg.cpp @@ -110,6 +110,22 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) return new SVG::Polygon(_); }), "points"_a) // + // + .def("to_numpy", + [](const Polygon &self) -> RowVectorsNx2 { + auto &points = self.points(); + return Eigen::Map(&points[0][0], + points.size(), 2); + }) + .def( + "from_numpy", + [](Polygon &self, + const Eigen::Ref &points) -> Polygon & { + std::vector _(points.rows()); + Eigen::Map(&_[0][0], points.rows(), 2) = points; + return self.points(_); + }, + rvp::reference_internal) // SETUP_FLUENT_API_PYBIND(Polygon, Color, stroke) SETUP_FLUENT_API_PYBIND(Polygon, double, stroke_width) SETUP_FLUENT_API_PYBIND(Polygon, Color, fill) @@ -125,6 +141,21 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) return new SVG::Circle({center[0], center[1]}, r); }), "center"_a, "r"_a = 1.0) // + + .def("center", + [](const Circle &self) -> Eigen::Vector2d { + auto &c = self.center(); + return Eigen::Vector2d(c[0], c[1]); + }) + .def( + "center", + [](Circle &self, const Eigen::Vector2d ¢er) -> Circle & { + return self.center({center[0], center[1]}); + }, + rvp::reference_internal) SETUP_FLUENT_API_PYBIND(Circle, double, x) + SETUP_FLUENT_API_PYBIND(Circle, double, y) + SETUP_FLUENT_API_PYBIND(Circle, double, r) + // SETUP_FLUENT_API_PYBIND(Circle, Color, stroke) SETUP_FLUENT_API_PYBIND(Circle, double, stroke_width) SETUP_FLUENT_API_PYBIND(Circle, Color, fill) @@ -141,9 +172,26 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) fontsize); }), "position"_a, "text"_a, "fontsize"_a = 10.0) // - SETUP_FLUENT_API_PYBIND(Circle, Color, stroke) - SETUP_FLUENT_API_PYBIND(Circle, double, stroke_width) - SETUP_FLUENT_API_PYBIND(Circle, Color, fill) + // + .def("position", + [](const Text &self) -> Eigen::Vector2d { + auto &p = self.position(); + return Eigen::Vector2d(p[0], p[1]); + }) + .def( + "position", + [](Text &self, const Eigen::Vector2d &position) -> Text & { + return self.position({position[0], position[1]}); + }, + rvp::reference_internal) + // + SETUP_FLUENT_API_PYBIND(Text, std::string, text) + SETUP_FLUENT_API_PYBIND(Text, std::vector, lines) + SETUP_FLUENT_API_PYBIND(Text, double, fontsize) + // + SETUP_FLUENT_API_PYBIND(Text, Color, stroke) + SETUP_FLUENT_API_PYBIND(Text, double, stroke_width) + SETUP_FLUENT_API_PYBIND(Text, Color, fill) // .def("to_string", &Text::to_string) // From 06a9e6689de5e5397918c33915c6ac9659d992b4 Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Sun, 3 Sep 2023 13:12:56 +0800 Subject: [PATCH 06/17] make unique --- src/naive_svg.hpp | 61 ++++++++++++++++++++++++++++---------- src/pybind11_naive_svg.cpp | 50 +++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 16 deletions(-) diff --git a/src/naive_svg.hpp b/src/naive_svg.hpp index 2eb5eb4..25c8cb6 100644 --- a/src/naive_svg.hpp +++ b/src/naive_svg.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -33,7 +34,8 @@ namespace cubao #define SETUP_FLUENT_API_FOR_SVG_ELEMENT(KlassType) \ SETUP_FLUENT_API(KlassType, Color, stroke) \ SETUP_FLUENT_API(KlassType, double, stroke_width) \ - SETUP_FLUENT_API(KlassType, Color, fill) + SETUP_FLUENT_API(KlassType, Color, fill) \ + SETUP_FLUENT_API(KlassType, std::string, attrs) #endif struct SVG @@ -94,6 +96,7 @@ struct SVG write(ss); return ss.str(); } + Color clone() const { return *this; } private: int r_{-1}, g_{-1}, b_{-1}; @@ -127,6 +130,7 @@ struct SVG Color stroke_{COLOR::BLACK}; double stroke_width_{1.0}; Color fill_{COLOR::NONE}; + std::string attrs_; }; struct Polyline : Element @@ -149,6 +153,9 @@ struct SVG out << pt[0] << "," << pt[1] << " "; } out << "'"; + if (!attrs_.empty()) { + out << " " << attrs_; + } out << " />"; } std::string to_string() const @@ -157,6 +164,8 @@ struct SVG write(ss); return ss.str(); } + + Polyline clone() const { return *this; } }; struct Polygon : Element @@ -178,6 +187,9 @@ struct SVG out << pt[0] << "," << pt[1] << " "; } out << "'"; + if (!attrs_.empty()) { + out << " " << attrs_; + } out << " />"; } std::string to_string() const @@ -186,6 +198,8 @@ struct SVG write(ss); return ss.str(); } + + Polygon clone() const { return *this; } }; struct Circle : Element @@ -228,8 +242,11 @@ struct SVG << " cx='" << x() << "' cy='" << y() << "'" // << " style='stroke:" << stroke_ // << ";stroke-width:" << stroke_width_ // - << ";fill:" << fill_ << "'" // - << " />"; + << ";fill:" << fill_ << "'"; + if (!attrs_.empty()) { + out << " " << attrs_; + } + out << " />"; } std::string to_string() const { @@ -238,6 +255,8 @@ struct SVG return ss.str(); } + Circle clone() const { return *this; } + protected: double r_{1.0}; }; @@ -280,16 +299,6 @@ struct SVG SETUP_FLUENT_API(Text, double, fontsize) SETUP_FLUENT_API_FOR_SVG_ELEMENT(Text) - // // text-anchor="start" - // - friend std::ostream &operator<<(std::ostream &out, const SVG::Text &e); void write(std::ostream &out) const @@ -298,8 +307,11 @@ struct SVG << " x='" << x() << "' y='" << y() << "'" // << " fill='" << fill_ << "'" // << " font-size='" << fontsize_ << "'" // - << " font-family='monospace'" // - << ">" << html_escape(text_); + << " font-family='monospace'"; + if (!attrs_.empty()) { + out << " " << attrs_; + } + out << ">" << html_escape(text_); if (!lines_.empty()) { double fontsize = fontsize_ / 5.0; for (auto &line : lines_) { @@ -320,6 +332,8 @@ struct SVG return ss.str(); } + Text clone() const { return *this; } + static std::string html_escape(const std::string &text) { std::string buffer; @@ -371,7 +385,22 @@ struct SVG } } - SVG clone() const {} + // disable shallow copy + private: + SVG(const SVG &) = default; + SVG &operator=(const SVG &) = default; + SVG(SVG &&) = delete; + SVG &operator=(SVG &&) = delete; + // implement deep copy + public: + std::unique_ptr clone() const + { + std::unique_ptr ptr( + new SVG(*this)); // std::make_unique(*this); + // for (auto &pair: copy.elements_) + // elements_ + return ptr; + } SETUP_FLUENT_API(SVG, double, width) SETUP_FLUENT_API(SVG, double, height) diff --git a/src/pybind11_naive_svg.cpp b/src/pybind11_naive_svg.cpp index cab5f61..5a2bc93 100644 --- a/src/pybind11_naive_svg.cpp +++ b/src/pybind11_naive_svg.cpp @@ -53,6 +53,16 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(Color, float, a) .def("invalid", &Color::invalid) .def("to_string", &Color::to_string) + + .def("__copy__", + [](const Color &self, py::dict) -> Color { + // always deepcopy (maybe not good?) + return self.clone(); + }) + .def( + "__deepcopy__", + [](const Color &self, py::dict) -> Color { return self.clone(); }, + "memo"_a) .def_static("parse", [](const std::string &text) { int i = text.size() - 6; @@ -64,6 +74,7 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) std::stoi(text.substr(i + 2, 2), nullptr, 16), std::stoi(text.substr(i + 4, 2), nullptr, 16)); }) + // ; @@ -96,8 +107,19 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(Polyline, Color, stroke) SETUP_FLUENT_API_PYBIND(Polyline, double, stroke_width) SETUP_FLUENT_API_PYBIND(Polyline, Color, fill) + SETUP_FLUENT_API_PYBIND(Polyline, std::string, attrs) // .def("to_string", &Polyline::to_string) + .def("__copy__", + [](const Polyline &self, py::dict) -> Polyline { + return self.clone(); + }) + .def( + "__deepcopy__", + [](const Polyline &self, py::dict) -> Polyline { + return self.clone(); + }, + "memo"_a) // ; @@ -129,8 +151,19 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(Polygon, Color, stroke) SETUP_FLUENT_API_PYBIND(Polygon, double, stroke_width) SETUP_FLUENT_API_PYBIND(Polygon, Color, fill) + SETUP_FLUENT_API_PYBIND(Polygon, std::string, attrs) // .def("to_string", &Polygon::to_string) + .def("__copy__", + [](const Polygon &self, py::dict) -> Polygon { + return self.clone(); + }) + .def( + "__deepcopy__", + [](const Polygon &self, py::dict) -> Polygon { + return self.clone(); + }, + "memo"_a) // ; @@ -159,8 +192,16 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(Circle, Color, stroke) SETUP_FLUENT_API_PYBIND(Circle, double, stroke_width) SETUP_FLUENT_API_PYBIND(Circle, Color, fill) + SETUP_FLUENT_API_PYBIND(Circle, std::string, attrs) // .def("to_string", &Circle::to_string) + .def( + "__copy__", + [](const Circle &self, py::dict) -> Circle { return self.clone(); }) + .def( + "__deepcopy__", + [](const Circle &self, py::dict) -> Circle { return self.clone(); }, + "memo"_a) // ; @@ -192,8 +233,17 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(Text, Color, stroke) SETUP_FLUENT_API_PYBIND(Text, double, stroke_width) SETUP_FLUENT_API_PYBIND(Text, Color, fill) + SETUP_FLUENT_API_PYBIND(Text, std::string, attrs) // .def("to_string", &Text::to_string) + .def("__copy__", + [](const Text &self, py::dict) -> Text { return self.clone(); }) + .def( + "__deepcopy__", + [](const Text &self, py::dict) -> Text { return self.clone(); }, + "memo"_a) + // + .def_static("html_escape", &Text::html_escape, "text"_a) // ; From 9803be6620cb2baf7f0d65db11405260cd9bc3b5 Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Sun, 3 Sep 2023 13:32:13 +0800 Subject: [PATCH 07/17] clone --- src/naive_svg.hpp | 85 ++++++++++++++++++++++++++++++++++++-- src/pybind11_naive_svg.cpp | 11 +++++ 2 files changed, 92 insertions(+), 4 deletions(-) diff --git a/src/naive_svg.hpp b/src/naive_svg.hpp index 25c8cb6..1d0199e 100644 --- a/src/naive_svg.hpp +++ b/src/naive_svg.hpp @@ -395,10 +395,20 @@ struct SVG public: std::unique_ptr clone() const { - std::unique_ptr ptr( - new SVG(*this)); // std::make_unique(*this); - // for (auto &pair: copy.elements_) - // elements_ + // auto ptr = std::make_unique(*this); + std::unique_ptr ptr(new SVG(*this)); + for (auto &pair : elements_) { + const auto type = pair.first; + if (type == ELEMENT::POLYGON) { + ptr->add(*(Polygon *)pair.second); + } else if (type == ELEMENT::POLYLINE) { + ptr->add(*(Polyline *)pair.second); + } else if (type == ELEMENT::CIRCLE) { + ptr->add(*(Circle *)pair.second); + } else if (type == ELEMENT::TEXT) { + ptr->add(*(Text *)pair.second); + } + } return ptr; } @@ -468,6 +478,73 @@ struct SVG return *ptr; } + size_t num_elements() const { return elements_.size(); } + + bool empty() const { return elements_.empty(); } + + void pop() + { + auto del = elements_.back(); + elements_.pop_back(); + if (del.first == ELEMENT::POLYLINE) { + delete (Polyline *)del.second; + } else if (del.first == ELEMENT::POLYGON) { + delete (Polygon *)del.second; + } else if (del.first == ELEMENT::CIRCLE) { + delete (Circle *)del.second; + } else if (del.first == ELEMENT::TEXT) { + delete (Text *)del.second; + } + } + + bool is_polyline(int index) const + { + return elements_.at(index % elements_.size()).first == + ELEMENT::POLYLINE; + } + bool is_polygon(int index) const + { + return elements_.at(index % elements_.size()).first == ELEMENT::POLYGON; + } + bool is_circle(size_t index) const + { + return elements_.at(index % elements_.size()).first == ELEMENT::CIRCLE; + } + bool is_text(size_t index) const + { + return elements_.at(index % elements_.size()).first == ELEMENT::TEXT; + } + + Polyline *as_polyline(int index) + { + if (!is_polyline(index)) { + return nullptr; + } + return (Polyline *)elements_.at(index % elements_.size()).second; + } + Polygon *as_polygon(int index) + { + if (!is_polygon(index)) { + return nullptr; + } + return (Polygon *)elements_.at(index % elements_.size()).second; + } + Circle *as_circle(int index) + { + if (!is_circle(index)) { + return nullptr; + } + return (Circle *)elements_.at(index % elements_.size()).second; + } + Text *as_text(int index) + { + if (!is_circle(index)) { + return nullptr; + } + return (Text *)elements_.at(index % elements_.size()).second; + } + // const version + void write(std::ostream &out) const { out << " Color { // always deepcopy (maybe not good?) @@ -110,6 +111,7 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(Polyline, std::string, attrs) // .def("to_string", &Polyline::to_string) + .def("clone", &Polyline::clone) .def("__copy__", [](const Polyline &self, py::dict) -> Polyline { return self.clone(); @@ -154,6 +156,7 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(Polygon, std::string, attrs) // .def("to_string", &Polygon::to_string) + .def("clone", &Polygon::clone) .def("__copy__", [](const Polygon &self, py::dict) -> Polygon { return self.clone(); @@ -195,6 +198,7 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(Circle, std::string, attrs) // .def("to_string", &Circle::to_string) + .def("clone", &Circle::clone) .def( "__copy__", [](const Circle &self, py::dict) -> Circle { return self.clone(); }) @@ -236,6 +240,7 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(Text, std::string, attrs) // .def("to_string", &Text::to_string) + .def("clone", &Text::clone) .def("__copy__", [](const Text &self, py::dict) -> Text { return self.clone(); }) .def( @@ -250,6 +255,12 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) py::class_(m, "SVG", py::module_local()) .def(py::init(), "width"_a, "height"_a) // + .def("clone", &SVG::clone) + .def("__copy__", [](const SVG &self, py::dict) { return self.clone(); }) + .def( + "__deepcopy__", + [](const SVG &self, py::dict) { return self.clone(); }, "memo"_a) + // ; } } // namespace cubao From fbe80e2b6ec9a258b1cf60bbc8f8832d2c6aa8af Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Sun, 3 Sep 2023 13:41:23 +0800 Subject: [PATCH 08/17] update --- src/pybind11_naive_svg.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/pybind11_naive_svg.cpp b/src/pybind11_naive_svg.cpp index ceca578..3008184 100644 --- a/src/pybind11_naive_svg.cpp +++ b/src/pybind11_naive_svg.cpp @@ -261,6 +261,41 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) "__deepcopy__", [](const SVG &self, py::dict) { return self.clone(); }, "memo"_a) // + SETUP_FLUENT_API_PYBIND(SVG, double, width) // + SETUP_FLUENT_API_PYBIND(SVG, double, height) // + SETUP_FLUENT_API_PYBIND(SVG, double, grid_step) // + SETUP_FLUENT_API_PYBIND(SVG, std::vector, grid_x) // + SETUP_FLUENT_API_PYBIND(SVG, std::vector, grid_y) // + SETUP_FLUENT_API_PYBIND(SVG, Color, grid_color) // + SETUP_FLUENT_API_PYBIND(SVG, Color, background) // + // + .def("add", py::overload_cast(&SVG::add, py::const_), + "polyline"_a, rvp::reference_internal) + .def("add", py::overload_cast(&SVG::add, py::const_), + "polygon"_a, rvp::reference_internal) + .def("add", py::overload_cast(&SVG::add, py::const_), + "circle"_a, rvp ::reference_internal) + .def("add", py::overload_cast(&SVG::add, py::const_), + "text"_a, rvp::reference_internal) + // + .def( + "add_polyline", + [](SVG &self, const Eigen::Ref &points) { + std::vector _(points.rows()); + Eigen::Map(&_[0][0], points.rows(), 2) = points; + return self.add_polyline(_); + }, + "points"_a, rvp::rerefence_internal) + .def( + "add_polygon", + [](SVG &self, const Eigen::Ref &points) { + std::vector _(points.rows()); + Eigen::Map(&_[0][0], points.rows(), 2) = points; + return self.add_polygon(_); + }, + "points"_a, rvp::rerefence_internal) + // + // ; } } // namespace cubao From 7461485ad84542643886f89724e61e5c06e3c34f Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Sun, 3 Sep 2023 22:23:40 +0800 Subject: [PATCH 09/17] not ready --- src/naive_svg.hpp | 63 +++++++++++++++++++++++++------------- src/pybind11_naive_svg.cpp | 52 +++++++++++++++++++++++++------ 2 files changed, 83 insertions(+), 32 deletions(-) diff --git a/src/naive_svg.hpp b/src/naive_svg.hpp index 1d0199e..587c574 100644 --- a/src/naive_svg.hpp +++ b/src/naive_svg.hpp @@ -113,18 +113,6 @@ struct SVG struct Element { - void fit_into(double xmin, double xmax, double ymin, double ymax, // - double width, double height) - { - // fit bbox[xmin:xmax, ymin:ymax] into viewBox[0:width, 0:height] - double xspan = xmax - xmin; - double yspan = ymax - ymin; - for (auto &pt : points_) { - pt[0] = (pt[0] - xmin) / xspan * width; - pt[1] = (pt[1] - ymin) / yspan * height; - } - } - protected: std::vector points_; Color stroke_{COLOR::BLACK}; @@ -499,19 +487,31 @@ struct SVG bool is_polyline(int index) const { + if (elements_.empty()) { + return false; + } return elements_.at(index % elements_.size()).first == ELEMENT::POLYLINE; } bool is_polygon(int index) const { + if (elements_.empty()) { + return false; + } return elements_.at(index % elements_.size()).first == ELEMENT::POLYGON; } bool is_circle(size_t index) const { + if (elements_.empty()) { + return false; + } return elements_.at(index % elements_.size()).first == ELEMENT::CIRCLE; } bool is_text(size_t index) const { + if (elements_.empty()) { + return false; + } return elements_.at(index % elements_.size()).first == ELEMENT::TEXT; } @@ -538,12 +538,32 @@ struct SVG } Text *as_text(int index) { - if (!is_circle(index)) { + if (!is_text(index)) { return nullptr; } return (Text *)elements_.at(index % elements_.size()).second; } // const version + const Polyline *as_polyline(int index) const + { + return const_cast( + const_cast(this)->as_polyline(index)); + } + const Polygon *as_polygon(int index) const + { + return const_cast( + const_cast(this)->as_polygon(index)); + } + const Circle *as_circle(int index) const + { + return const_cast( + const_cast(this)->as_circle(index)); + } + const Text *as_text(int index) const + { + return const_cast( + const_cast(this)->as_text(index)); + } void write(std::ostream &out) const { @@ -594,19 +614,18 @@ struct SVG out << "\n"; } - void save(std::string path) const + std::string to_string() const { - std::ofstream file(path); - write(file); - file.close(); + std::stringstream ss; + write(ss); + return ss.str(); } - void fit_to_bbox(double xmin, double xmax, double ymin, double ymax) + void save(const std::string &path) const { - for (auto &pair : elements_) { - ((Element *)pair.second) - ->fit_into(xmin, ymax, ymin, ymax, width_, height_); - } + std::ofstream file(path); + write(file); + file.close(); } private: diff --git a/src/pybind11_naive_svg.cpp b/src/pybind11_naive_svg.cpp index 3008184..22b79fe 100644 --- a/src/pybind11_naive_svg.cpp +++ b/src/pybind11_naive_svg.cpp @@ -35,7 +35,9 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) .def(#VarName, [](const Klass &self) { return self.VarName(); }) \ .def( \ #VarName, \ - [](Klass &self, const VarType &v) { return self.VarName(v); }, \ + [](Klass &self, const VarType &v) -> Klass & { \ + return self.VarName(v); \ + }, \ rvp::reference_internal) using Color = SVG::Color; @@ -269,14 +271,14 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) SETUP_FLUENT_API_PYBIND(SVG, Color, grid_color) // SETUP_FLUENT_API_PYBIND(SVG, Color, background) // // - .def("add", py::overload_cast(&SVG::add, py::const_), + .def("add", py::overload_cast(&SVG::add), "polyline"_a, rvp::reference_internal) - .def("add", py::overload_cast(&SVG::add, py::const_), - "polygon"_a, rvp::reference_internal) - .def("add", py::overload_cast(&SVG::add, py::const_), - "circle"_a, rvp ::reference_internal) - .def("add", py::overload_cast(&SVG::add, py::const_), - "text"_a, rvp::reference_internal) + .def("add", py::overload_cast(&SVG::add), "polygon"_a, + rvp::reference_internal) + .def("add", py::overload_cast(&SVG::add), "circle"_a, + rvp ::reference_internal) + .def("add", py::overload_cast(&SVG::add), "text"_a, + rvp::reference_internal) // .def( "add_polyline", @@ -285,7 +287,7 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) Eigen::Map(&_[0][0], points.rows(), 2) = points; return self.add_polyline(_); }, - "points"_a, rvp::rerefence_internal) + "points"_a, rvp::reference_internal) .def( "add_polygon", [](SVG &self, const Eigen::Ref &points) { @@ -293,7 +295,37 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) Eigen::Map(&_[0][0], points.rows(), 2) = points; return self.add_polygon(_); }, - "points"_a, rvp::rerefence_internal) + "points"_a, rvp::reference_internal) + .def( + "add_circle", + [](SVG &self, const Eigen::Vector2d ¢er, double r) { + return self.add_circle({center[0], center[1]}, r); + }, + "center"_a, "r"_a = 1.0, rvp::reference_internal) + .def( + "add_text", + [](SVG &self, const Eigen::Vector2d &position, + const std::string &text, double fontsize) { + return self.add_text({position[0], position[1]}, text, + fontsize); + }, + "position"_a, "text"_a, "fontsize"_a = 10.0, + rvp::reference_internal) + // + .def("num_elements", &SVG::num_elements) + .def("empty", &SVG::empty) + .def("pop", &SVG::pop) + // + .def("is_polyline", &SVG::is_polyline) + .def("is_polygon", &SVG::is_polygon) + .def("is_circle", &SVG::is_circle) + .def("is_text", &SVG::is_text) + // + .def("as_polyline", py::overload_cast(&SVG::as_polyline), + "index"_a) + .def("as_polygon", py::overload_cast(&SVG::as_polygon), "index"_a) + .def("as_circle", py::overload_cast(&SVG::as_circle), "index"_a) + .def("as_text", py::overload_cast(&SVG::as_text), "index"_a) // // ; From 36d15645bafa70e1448b2a04dfccf1e7bce09edc Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Sun, 3 Sep 2023 22:45:07 +0800 Subject: [PATCH 10/17] not ready --- src/pybind11_naive_svg.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/pybind11_naive_svg.cpp b/src/pybind11_naive_svg.cpp index 22b79fe..70490a9 100644 --- a/src/pybind11_naive_svg.cpp +++ b/src/pybind11_naive_svg.cpp @@ -273,12 +273,12 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) // .def("add", py::overload_cast(&SVG::add), "polyline"_a, rvp::reference_internal) - .def("add", py::overload_cast(&SVG::add), "polygon"_a, - rvp::reference_internal) - .def("add", py::overload_cast(&SVG::add), "circle"_a, - rvp ::reference_internal) - .def("add", py::overload_cast(&SVG::add), "text"_a, - rvp::reference_internal) + .def("add", py::overload_cast(&SVG::add), // + "polygon"_a, rvp::reference_internal) + .def("add", py::overload_cast(&SVG::add), // + "circle"_a, rvp ::reference_internal) + .def("add", py::overload_cast(&SVG::add), // + "text"_a, rvp::reference_internal) // .def( "add_polyline", @@ -322,10 +322,13 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) .def("is_text", &SVG::is_text) // .def("as_polyline", py::overload_cast(&SVG::as_polyline), - "index"_a) - .def("as_polygon", py::overload_cast(&SVG::as_polygon), "index"_a) - .def("as_circle", py::overload_cast(&SVG::as_circle), "index"_a) - .def("as_text", py::overload_cast(&SVG::as_text), "index"_a) + "index"_a, rvp::reference_internal) + .def("as_polygon", py::overload_cast(&SVG::as_polygon), "index"_a, + rvp::reference_internal) + .def("as_circle", py::overload_cast(&SVG::as_circle), "index"_a, + rvp::reference_internal) + .def("as_text", py::overload_cast(&SVG::as_text), "index"_a, + rvp::reference_internal) // // ; From 5beee6886af640c88bcd9e21a4f40083c6927cc0 Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Sun, 3 Sep 2023 22:55:08 +0800 Subject: [PATCH 11/17] good --- .vscode/settings.json | 67 ++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 5 +++ src/naive_svg.hpp | 8 ++++- src/pybind11_naive_svg.cpp | 4 +-- 4 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9328a22 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,67 @@ +{ + "files.associations": { + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "array": "cpp", + "atomic": "cpp", + "strstream": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "cfenv": "cpp", + "chrono": "cpp", + "cinttypes": "cpp", + "codecvt": "cpp", + "complex": "cpp", + "condition_variable": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "forward_list": "cpp", + "list": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "any": "cpp", + "filesystem": "cpp", + "functional": "cpp", + "optional": "cpp", + "ratio": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "fstream": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "memory": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "numeric": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "regex": "cpp", + "utility": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "valarray": "cpp" + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt index efe9c3a..3e0579d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,14 @@ cmake_minimum_required(VERSION 3.4...3.18) project(naive_svg) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_CXX_STANDARD 14) + include_directories(headers/include) +set(PYBIND11_CPP_STANDARD -std=c++14) add_subdirectory(pybind11) file(GLOB SRCS src/*.cpp) pybind11_add_module(_naive_svg ${SRCS}) diff --git a/src/naive_svg.hpp b/src/naive_svg.hpp index 587c574..3a9785e 100644 --- a/src/naive_svg.hpp +++ b/src/naive_svg.hpp @@ -569,7 +569,11 @@ struct SVG { out << ""; + "xmlns:xlink='http://www.w3.org/1999/xlink'"; + if (!attrs_.empty()) { + out << " " << attrs_; + } + out << ">"; if (!background_.invalid()) { out << "\n\t view_box_; // grid double grid_step_{-1.0}; std::vector grid_x_, grid_y_; // low, high, step @@ -645,6 +658,17 @@ struct SVG std::string attrs_; // elements std::vector> elements_; + + int __index(int index) const + { + if (index < 0) { + index += elements_.size(); + } + if (0 <= index && index < elements_.size()) { + return index; + } + return -1; + } }; inline std::ostream &operator<<(std::ostream &out, const SVG::Color &c) diff --git a/src/pybind11_naive_svg.cpp b/src/pybind11_naive_svg.cpp index 49d81d1..d9adee8 100644 --- a/src/pybind11_naive_svg.cpp +++ b/src/pybind11_naive_svg.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "cubao_inline.hpp" #include "naive_svg.hpp" @@ -21,10 +22,6 @@ using rvp = py::return_value_policy; using RowVectorsNx2 = Eigen::Matrix; -// TODO, 各个类型的 from/to_json -// svg 的 load/dump -// svg extra attributes - CUBAO_INLINE void bind_naive_svg(py::module &m) { // https://github.com/gagan-bansal/geojson2svg @@ -45,14 +42,10 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) py::module_local()) // .def(py::init(), "rgb"_a = -1) .def(py::init(), "r"_a, "g"_a, "b"_a, - "a"_a = -1.f) - .def("r", [](const Color &self) { return self.r(); }) - .def( - "r", [](Color &self, int r) { return self.r(r); }, - rvp::reference_internal) // - SETUP_FLUENT_API_PYBIND(Color, int, g) - SETUP_FLUENT_API_PYBIND(Color, int, b) - SETUP_FLUENT_API_PYBIND(Color, float, a) + "a"_a = -1.f) SETUP_FLUENT_API_PYBIND(Color, int, r) + SETUP_FLUENT_API_PYBIND(Color, int, g) + SETUP_FLUENT_API_PYBIND(Color, int, b) + SETUP_FLUENT_API_PYBIND(Color, float, a) .def("invalid", &Color::invalid) .def("to_string", &Color::to_string) @@ -78,6 +71,8 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) std::stoi(text.substr(i + 4, 2), nullptr, 16)); }) + // + .def("__repr__", [](const Color &self) { return self.to_string(); }) // ; @@ -263,14 +258,16 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) "__deepcopy__", [](const SVG &self, py::dict) { return self.clone(); }, "memo"_a) // - SETUP_FLUENT_API_PYBIND(SVG, double, width) // - SETUP_FLUENT_API_PYBIND(SVG, double, height) // - SETUP_FLUENT_API_PYBIND(SVG, double, grid_step) // - SETUP_FLUENT_API_PYBIND(SVG, std::vector, grid_x) // - SETUP_FLUENT_API_PYBIND(SVG, std::vector, grid_y) // - SETUP_FLUENT_API_PYBIND(SVG, Color, grid_color) // - SETUP_FLUENT_API_PYBIND(SVG, Color, background) // - // + SETUP_FLUENT_API_PYBIND(SVG, double, width) // + SETUP_FLUENT_API_PYBIND(SVG, double, height) // + SETUP_FLUENT_API_PYBIND(SVG, std::vector, view_box) // + SETUP_FLUENT_API_PYBIND(SVG, double, grid_step) // + SETUP_FLUENT_API_PYBIND(SVG, std::vector, grid_x) // + SETUP_FLUENT_API_PYBIND(SVG, std::vector, grid_y) // + SETUP_FLUENT_API_PYBIND(SVG, Color, grid_color) // + SETUP_FLUENT_API_PYBIND(SVG, Color, background) // + SETUP_FLUENT_API_PYBIND(SVG, std::string, attrs) // + // .def("add", py::overload_cast(&SVG::add), "polyline"_a, rvp::reference_internal) .def("add", py::overload_cast(&SVG::add), // @@ -282,7 +279,8 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) // .def( "add_polyline", - [](SVG &self, const Eigen::Ref &points) { + [](SVG &self, + const Eigen::Ref &points) -> Polyline & { std::vector _(points.rows()); Eigen::Map(&_[0][0], points.rows(), 2) = points; return self.add_polyline(_); @@ -290,7 +288,8 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) "points"_a, rvp::reference_internal) .def( "add_polygon", - [](SVG &self, const Eigen::Ref &points) { + [](SVG &self, + const Eigen::Ref &points) -> Polygon & { std::vector _(points.rows()); Eigen::Map(&_[0][0], points.rows(), 2) = points; return self.add_polygon(_); @@ -298,14 +297,14 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) "points"_a, rvp::reference_internal) .def( "add_circle", - [](SVG &self, const Eigen::Vector2d ¢er, double r) { + [](SVG &self, const Eigen::Vector2d ¢er, double r) -> Circle & { return self.add_circle({center[0], center[1]}, r); }, "center"_a, py::kw_only(), "r"_a = 1.0, rvp::reference_internal) .def( "add_text", [](SVG &self, const Eigen::Vector2d &position, - const std::string &text, double fontsize) { + const std::string &text, double fontsize) -> Text & { return self.add_text({position[0], position[1]}, text, fontsize); }, @@ -330,6 +329,8 @@ CUBAO_INLINE void bind_naive_svg(py::module &m) .def("as_text", py::overload_cast(&SVG::as_text), "index"_a, rvp::reference_internal) // + .def("to_string", &SVG::to_string) + .def("dump", &SVG::dump, "path"_a) // ; } diff --git a/tests/test_basic.py b/tests/test_basic.py index 20b7cc3..009264f 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -1,15 +1,53 @@ -from naive_svg import SVG, Circle, Polygon, Polyline, Text, add +from naive_svg import SVG, Circle, Color, Polygon, Polyline, Text, add def test_add(): assert add(1, 2) == 3 +def test_color(): + assert Color().to_string() == "none" + assert Color(0xFF0000).to_string() == "rgb(255,0,0)" + assert Color(0xFF0000).a(0.5).to_string() == "rgba(255,0,0,0.5)" + c = Color(0x00FF00) + assert c.r() == 0 + assert c.g() == 255 + assert c.b() == 0 + assert c.a() == -1.0 + assert c.r(155) == c + assert c.b(155).b() == 155 + assert c.to_string() == "rgb(155,255,155)" + + def test_svg(): svg = SVG(100, 100) print(svg) + c = svg.add_circle([40, 30], r=50) + text = svg.to_string() + print(text) + assert "rgb(0,0,0)" in text + + c.stroke(Color(0xFF0000)) + text = svg.to_string() + print(text) + assert "rgb(255,0,0)" in text + + c.fill(Color(0x00FF00).a(0.2)) + + svg.add_polyline([[0, 0], [30, 40], [40, 30], [50, 0]]) + assert svg.is_circle(0) + assert not svg.is_circle(1) + assert svg.is_polyline(1) + + text = svg.to_string() + print(text) + print(Polyline) print(Polygon) print(Circle) print(Text) + + +test_color() +test_svg() From f91da9d024e85b214938f5b4c990da735143994c Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Sun, 3 Sep 2023 23:50:59 +0800 Subject: [PATCH 13/17] fix --- src/naive_svg.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/naive_svg.hpp b/src/naive_svg.hpp index 40fffda..5b16eca 100644 --- a/src/naive_svg.hpp +++ b/src/naive_svg.hpp @@ -474,6 +474,9 @@ struct SVG void pop() { + if (elements_.empty()) { + return; + } auto del = elements_.back(); elements_.pop_back(); if (del.first == ELEMENT::POLYLINE) { From 998ca6b7716900ed8739839d98104a1aaa31762a Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Mon, 4 Sep 2023 00:03:58 +0800 Subject: [PATCH 14/17] ready --- src/naive_svg.hpp | 10 +++++----- tests/test_basic.py | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/naive_svg.hpp b/src/naive_svg.hpp index 5b16eca..e1072f3 100644 --- a/src/naive_svg.hpp +++ b/src/naive_svg.hpp @@ -506,7 +506,7 @@ struct SVG } return elements_.at(index).first == ELEMENT::POLYGON; } - bool is_circle(size_t index) const + bool is_circle(int index) const { index = __index(index); if (index < 0) { @@ -514,7 +514,7 @@ struct SVG } return elements_.at(index).first == ELEMENT::CIRCLE; } - bool is_text(size_t index) const + bool is_text(int index) const { index = __index(index); if (index < 0) { @@ -577,7 +577,7 @@ struct SVG { out << " Date: Mon, 4 Sep 2023 00:06:11 +0800 Subject: [PATCH 15/17] ready --- README.md | 2 +- mkdocs.yml | 2 +- setup.py | 4 ++-- src/naive_svg.hpp | 4 ++-- tests/test_basic.py | 15 +++------------ 5 files changed, 9 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 8fc8c15..edb613b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # naive-svg -Online document: **[readthedocs](http://naive-svg.readthedocs.io/)** +Online document: **[readthedocs](http://pybind11-naive-svg.readthedocs.io/)** diff --git a/mkdocs.yml b/mkdocs.yml index f8fd99b..fce66a8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,5 +1,5 @@ site_name: naive-svg -site_url: https://naive-svg.readthedocs.io +site_url: https://pybind11-naive-svg.readthedocs.io site_description: naive svg writer site_author: district10 diff --git a/setup.py b/setup.py index 71f8fd2..49fab40 100644 --- a/setup.py +++ b/setup.py @@ -127,10 +127,10 @@ def build_extension(self, ext: CMakeExtension) -> None: # logic and declaration, and simpler if you include description/version in a file. setup( name="naive_svg", - version="0.0.1", + version="0.0.2", author="tzx", author_email="dvorak4tzx@gmail.com", - url="https://naive-svg.readthedocs.io", + url="https://pybind11-naive-svg.readthedocs.io", description="naive svg writer", long_description=open("README.md", encoding="utf-8").read(), long_description_content_type="text/markdown", diff --git a/src/naive_svg.hpp b/src/naive_svg.hpp index e1072f3..bf3b56a 100644 --- a/src/naive_svg.hpp +++ b/src/naive_svg.hpp @@ -578,8 +578,8 @@ struct SVG out << " Date: Mon, 4 Sep 2023 00:14:20 +0800 Subject: [PATCH 16/17] fix --- tests/test_basic.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/test_basic.py b/tests/test_basic.py index ed248ec..ccea1cf 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -24,6 +24,7 @@ def test_svg(): print(svg) c = svg.add_circle([40, 30], r=50) + assert isinstance(c, Circle) text = svg.to_string() print(text) assert "rgb(0,0,0)" in text @@ -39,13 +40,23 @@ def test_svg(): assert svg.is_circle(0) assert not svg.is_circle(1) assert svg.is_polyline(1) - svg.as_polyline(1).stroke(Color(0xFFAA00)) + p = svg.as_polyline(1) + assert isinstance(p, Polyline) + p.stroke(Color(0xFFAA00)) svg.grid_step(10.0) svg.view_box([20, 20, 40, 40]) - svg.add_text([30, 40], text="hello") + t = svg.add_text([30, 40], text="hello") + assert isinstance(t, Text) + + polygon = ( + svg.add_polygon([[20, 20], [20, 30], [40, 30], [40, 20], [20, 20]]) + .stroke(Color(0x0000FF)) + .fill(Color(0xFF0000).a(0.1)) + ) + assert isinstance(polygon, Polygon) text = svg.to_string() print(text) - assert not svg.is_circle(10) \ No newline at end of file + assert not svg.is_circle(10) From f3d0fb67e8b111e6f99319f906373caea4917bc4 Mon Sep 17 00:00:00 2001 From: TANG ZHIXIONG Date: Mon, 4 Sep 2023 00:19:55 +0800 Subject: [PATCH 17/17] update docs --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index edb613b..1dd94e3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # naive-svg +Upgrated version of [svg.hpp](https://github.com/cubao/naive-svg/blob/master/svg.hpp). + Online document: **[readthedocs](http://pybind11-naive-svg.readthedocs.io/)**