├── README.md ├── example ├── arrow.cpp ├── donut.cpp ├── geometry_boolean.cpp ├── skeleton_view.cpp └── svg.hpp └── include └── niji ├── algorithm ├── area.hpp ├── bounds.hpp ├── contains.hpp ├── generate_tangents.hpp ├── length.hpp └── winding.hpp ├── any_path.hpp ├── detail ├── coord_fn.hpp ├── enable_if_valid.hpp ├── path.hpp └── priority.hpp ├── geometry ├── box.hpp ├── detail │ ├── multi_geometry_render.hpp │ └── ring_render.hpp ├── linestring.hpp ├── polygon.hpp ├── render.hpp ├── ring.hpp └── segment.hpp ├── graphic ├── angular.hpp ├── arc.hpp ├── cross.hpp ├── ellipse.hpp ├── frame.hpp ├── rect.hpp └── spiral.hpp ├── group.hpp ├── make ├── composite.hpp ├── graphic.hpp └── lazy.hpp ├── path.hpp ├── path_fwd.hpp ├── path_ref.hpp ├── render.hpp ├── sink ├── any.hpp ├── cairo.hpp ├── d2d.hpp ├── debug.hpp ├── multi.hpp ├── nanovg.hpp ├── nvpr.hpp ├── qt.hpp ├── skia.hpp └── svg.hpp ├── support ├── bezier.hpp ├── box.hpp ├── command.hpp ├── common_point.hpp ├── constants.hpp ├── convert_geometry.hpp ├── deprecate.hpp ├── identifier.hpp ├── is_narrowing.hpp ├── just.hpp ├── numeric.hpp ├── point.hpp ├── traits.hpp ├── transform │ ├── affine.hpp │ ├── rotate.hpp │ ├── scale.hpp │ ├── skew.hpp │ ├── translate.hpp │ └── transpose.hpp ├── vector.hpp └── view.hpp └── view ├── affine.hpp ├── dash.hpp ├── detail ├── dash.hpp ├── offset_outline.hpp └── stroker.hpp ├── fork.hpp ├── identity.hpp ├── inverse.hpp ├── offset.hpp ├── outline ├── cap_style.hpp └── join_style.hpp ├── quadruple.hpp ├── repeat.hpp ├── rotate.hpp ├── scale.hpp ├── skew.hpp ├── stroke.hpp ├── tee.hpp ├── trace.hpp ├── transform.hpp ├── translate.hpp └── transpose.hpp /README.md: -------------------------------------------------------------------------------- 1 | niji 2 | ==== 3 | 4 | Generic 2D graphics library for C++14. 5 | 6 | ## Introduction 7 | 8 | Niji is a generic library for 2D graphical path manipulation, it provides containers, generators (graphics), adaptors (views) and algorithms for path, in a sense like STL/Boost.Range. 9 | 10 | On the other hand, niji doesn't have the ability to render these paths on its own, you can think it as a generic front-end for arbitrary graphic engines which can do the real rendering. 11 | 12 | ## Overview 13 | 14 | Niji can be divided into these submodules: 15 | 16 | - *core* - path fundamentals. 17 | - *container* - various path containers, e.g. `path`, `group`, etc. 18 | - *graphic* - common graphics, e.g. `ellipse`, `round_rect`, etc. 19 | - *geometry* - adapted geometry path for Boost.Geometry. 20 | - *view* - various path adaptors, e.g. `inverse`, `transform`, `stroke`, etc. 21 | - *make* - convenient path makers. 22 | - *algorithm* - path algorithms, e.g. `bounds`, `length`, etc. 23 | - *support* - traits, basic geometries, math... 24 | - *sink* - predefined backends, e.g. Skia, Direct2D, etc. 25 | 26 | ## Quick Example 27 | 28 | The following example shows how to output the path of a dashed ellipse: 29 | 30 | ```c++ 31 | using namespace niji; 32 | 33 | render(ellipse({100, 100}, 50) | views::dash({6, 2}), sink); 34 | ``` 35 | - all components reside in namespace `niji`. 36 | - `render(path, sink)` sends the path commands to sink. 37 | - `ellipse` is a predefined path generator. 38 | - `views::dash(pattern)` returns a path adaptor that generates dash lines. 39 | - `sink` is something that handles the path commands. 40 | 41 | ## Documentation 42 | - [Tutorial](https://github.com/jamboree/niji/wiki/Tutorial) 43 | - Reference 44 | 45 | ## Dependencies 46 | 47 | - [Boost](http://www.boost.org/) 48 | 49 | ## License 50 | 51 | Copyright (c) 2014-2018 Jamboree 52 | 53 | Distributed under the Boost Software License, Version 1.0. (See accompanying 54 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 55 | 56 | -------------------------------------------------------------------------------- /example/arrow.cpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "svg.hpp" 12 | 13 | template 14 | struct arrow 15 | { 16 | using point_type = niji::point; 17 | 18 | T r; 19 | 20 | explicit arrow(T r) : r(r) {} 21 | 22 | template 23 | void render(Sink& sink) const 24 | { 25 | using namespace niji::command; 26 | sink(move_to, point_type{}); 27 | sink(line_to, point_type{-r, -r}); 28 | sink(line_to, point_type{2 * r, 0}); 29 | sink(line_to, point_type{-r, r}); 30 | sink(end_closed); 31 | } 32 | }; 33 | 34 | int main() 35 | { 36 | using namespace niji; 37 | 38 | std::ofstream fout("arrow.svg"); 39 | svg::canvas canvas(fout, 500, 500); 40 | 41 | canvas.fill(svg::rgb()); 42 | canvas.draw(arrow(50) | views::translate(250, 250)); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /example/donut.cpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "svg.hpp" 15 | 16 | template 17 | auto donut(niji::point const& pt, T o, T i) 18 | { 19 | using namespace niji; 20 | 21 | return make_lazy([=] 22 | { 23 | return make_composite 24 | ( 25 | ellipse(pt, o) 26 | , ellipse(pt, i) | views::inverse 27 | ); 28 | }); 29 | } 30 | 31 | int main() 32 | { 33 | using namespace niji; 34 | 35 | std::ofstream fout("donut.svg"); 36 | svg::canvas canvas(fout, 500, 500); 37 | 38 | canvas.fill(svg::rgb()); 39 | canvas.draw(donut({250, 250}, 100, 60)); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /example/geometry_boolean.cpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | // Boost.Geometry (aka GGL, Generic Geometry Library) 8 | // Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands. 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "svg.hpp" 19 | 20 | int main() 21 | { 22 | using namespace niji; 23 | using point_type = boost::geometry::model::d2::point_xy; 24 | using polygon = boost::geometry::model::polygon; 25 | 26 | polygon green, blue; 27 | 28 | boost::geometry::read_wkt( 29 | "POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 3,5.3 2.6,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3)" 30 | "(4.0 2.0, 4.2 1.4, 4.8 1.9, 4.4 2.2, 4.0 2.0))", green); 31 | 32 | boost::geometry::read_wkt( 33 | "POLYGON((4.0 -0.5 , 3.5 1.0 , 2.0 1.5 , 3.5 2.0 , 4.0 3.5 , 4.5 2.0 , 6.0 1.5 , 4.5 1.0 , 4.0 -0.5))", blue); 34 | 35 | auto box = bounds(green); 36 | box.expand(bounds(blue)); 37 | 38 | views::affine trans; 39 | trans 40 | .translate(-box.min_corner.x, -box.min_corner.y) 41 | .scale(400.0 / box.width(), 400.0 / box.height()) 42 | .flip_y().translate(0, 400); 43 | 44 | std::deque output; 45 | auto output_svg = [&](auto file) 46 | { 47 | std::ofstream fout(file); 48 | svg::canvas canvas(fout, 400, 400); 49 | 50 | canvas.stroke({2, svg::rgb(153,204,0)}); 51 | canvas.fill({svg::rgb(153,204,0), 0.5}); 52 | canvas.draw(green | trans); 53 | 54 | canvas.stroke({2, svg::rgb(51,51,153)}); 55 | canvas.fill({svg::rgb(51,51,153), 0.3}); 56 | canvas.draw(blue | trans); 57 | 58 | svg::pen pen(4, svg::rgb(255,128,0)); 59 | pen.dash = {1, 7}; 60 | pen.cap = svg::cap_style::round; 61 | canvas.stroke(pen); 62 | svg::font font(10, "Arial"); 63 | int i = 0; 64 | for (auto const& g : output) 65 | { 66 | canvas.fill(nullptr); 67 | canvas.draw(g | trans); 68 | canvas.fill(svg::rgb()); 69 | auto pt = boost::geometry::return_centroid(g); 70 | canvas.text(trans(pt), std::to_string(i++), font); 71 | } 72 | }; 73 | 74 | boost::geometry::intersection(green, blue, output); 75 | output_svg("geometry_intersection.svg"); 76 | output.clear(); 77 | boost::geometry::union_(green, blue, output); 78 | output_svg("geometry_union.svg"); 79 | output.clear(); 80 | boost::geometry::difference(green, blue, output); 81 | output_svg("geometry_difference1.svg"); 82 | output.clear(); 83 | boost::geometry::difference(blue, green, output); 84 | output_svg("geometry_difference2.svg"); 85 | output.clear(); 86 | boost::geometry::sym_difference(blue, green, output); 87 | output_svg("geometry_sym_difference.svg"); 88 | 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /example/skeleton_view.cpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "svg.hpp" 13 | 14 | struct skeleton_view : niji::view 15 | { 16 | template 17 | struct adaptor 18 | { 19 | Sink& sink; 20 | 21 | template 22 | void operator()(Tag tag, Point const& pt) const 23 | { 24 | sink(tag, pt); 25 | } 26 | 27 | template 28 | void operator()(niji::quad_to_t, Point const& pt1, Point const& pt2) const 29 | { 30 | using namespace niji::command; 31 | sink(line_to, pt1); 32 | sink(line_to, pt2); 33 | } 34 | 35 | template 36 | void operator()(niji::cubic_to_t, Point const& pt1, Point const& pt2, Point const& pt3) const 37 | { 38 | using namespace niji::command; 39 | sink(line_to, pt1); 40 | sink(line_to, pt2); 41 | sink(line_to, pt3); 42 | } 43 | 44 | template 45 | void operator()(Tag tag) const 46 | { 47 | sink(tag); 48 | } 49 | }; 50 | 51 | template 52 | void render(Path const& path, Sink& sink) const 53 | { 54 | niji::render(path, adaptor{sink}); 55 | } 56 | 57 | template 58 | void inverse_render(Path const& path, Sink& sink) const 59 | { 60 | niji::inverse_render(path, adaptor{sink}); 61 | } 62 | }; 63 | 64 | constexpr skeleton_view skeleton = {}; 65 | 66 | int main() 67 | { 68 | using namespace niji; 69 | 70 | std::ofstream fout("skeleton_view.svg"); 71 | svg::canvas canvas(fout, 500, 500); 72 | 73 | path p; 74 | p.join_cubic({50, 50}, {150, 300}, {350, 0}, {500, 200}); 75 | 76 | canvas.stroke({2, svg::rgb()}); 77 | canvas.draw(p); 78 | 79 | canvas.stroke({2, svg::rgb(154, 206, 235)}); 80 | canvas.draw(p | skeleton); 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /example/svg.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef BOOST_NIJI_EXAMPLE_SVG_HPP_INCLUDED 8 | #define BOOST_NIJI_EXAMPLE_SVG_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace niji { namespace svg 23 | { 24 | struct rgb 25 | { 26 | std::uint8_t r, g, b; 27 | 28 | rgb() : r(), g(), b() {} 29 | 30 | rgb(std::uint8_t r, std::uint8_t g, std::uint8_t b) 31 | : r(r), g(g), b(b) 32 | {} 33 | }; 34 | 35 | struct paint 36 | { 37 | rgb color; 38 | double opacity; 39 | 40 | paint(rgb color, double opacity = 1.0) 41 | : color(color), opacity(opacity) 42 | {} 43 | }; 44 | 45 | enum class cap_style 46 | { 47 | butt, round, square 48 | }; 49 | 50 | enum class join_style 51 | { 52 | bevel, round, miter 53 | }; 54 | 55 | struct pen 56 | { 57 | double width; 58 | svg::paint paint; 59 | std::vector dash; 60 | double offset = 0; 61 | cap_style cap = cap_style::butt; 62 | join_style join = join_style::bevel; 63 | double miter_limit = 4.0; 64 | 65 | pen(double width, svg::paint const& paint) 66 | : width(width), paint(paint) 67 | {} 68 | }; 69 | 70 | enum class font_style 71 | { 72 | normal, italic, oblique 73 | }; 74 | 75 | enum font_weight 76 | { 77 | normal = 400, bold = 700 78 | }; 79 | 80 | struct font 81 | { 82 | double size; 83 | std::string family; 84 | font_style style; 85 | int weight; 86 | 87 | font(double size, std::string family = {}, font_style style = font_style::normal, int weight = font_weight::normal) 88 | : size(size), family(std::move(family)), style(style), weight(weight) 89 | {} 90 | }; 91 | 92 | void save_paint(std::ostream& out, paint const& p, char const* type) 93 | { 94 | auto c = p.color; 95 | out << type << "=\"rgb(" << unsigned(c.r) << ',' << unsigned(c.g) << ',' << unsigned(c.b) << ")\""; 96 | if (p.opacity < 1) 97 | out << ' ' << type << "-opacity=\"" << p.opacity << '\"'; 98 | } 99 | 100 | void save_pen(std::ostream& out, pen const& p) 101 | { 102 | char const* cap[] = {"butt", "round", "square"}; 103 | char const* join[] = {"bevel", "round", "miter"}; 104 | out << "stroke-width=\"" << p.width << "\" "; 105 | save_paint(out, p.paint, "stroke"); 106 | out << " stroke-linecap=\"" << cap[int(p.cap)] << '\"' 107 | << " stroke-linejoin=\"" << join[int(p.join)] << '\"'; 108 | if (p.join == join_style::miter) 109 | out << " stroke-miterlimit=\"" << p.miter_limit << '\"'; 110 | auto it = p.dash.begin(), end = p.dash.end(); 111 | if (it != end) 112 | { 113 | out << " stroke-dasharray=\"" << *it; 114 | while (++it != end) 115 | out << ',' << *it; 116 | out << '\"'; 117 | if (p.offset) 118 | out << " stroke-dashoffset=\"" << p.offset << '\"'; 119 | } 120 | } 121 | 122 | template 123 | struct basic_canvas 124 | { 125 | Ostream& out; 126 | 127 | basic_canvas(Ostream& out, unsigned x, unsigned y) 128 | : out(out) 129 | { 130 | fill(nullptr); 131 | stroke(nullptr); 132 | 133 | out << "" 134 | "" 135 | ""; 136 | } 137 | 138 | void fill(std::nullptr_t) 139 | { 140 | _brush = "fill=\"none\""; 141 | } 142 | 143 | void fill(paint const& b) 144 | { 145 | std::stringstream s; 146 | save_paint(s, b, "fill"); 147 | _brush = s.str(); 148 | } 149 | 150 | void stroke(std::nullptr_t) 151 | { 152 | _pen = "stroke=\"none\""; 153 | } 154 | 155 | void stroke(pen const& p) 156 | { 157 | std::stringstream s; 158 | save_pen(s, p); 159 | _pen = s.str(); 160 | } 161 | 162 | template 163 | void draw(Path const& path) 164 | { 165 | out << "(out)); 167 | out << "\" " << _brush << ' ' << _pen << " />"; 168 | } 169 | 170 | void text(dpoint const& pt, std::string const& str, font const& f) 171 | { 172 | out << "" << str << ""; 175 | } 176 | 177 | template 178 | void transform(transforms::affine const& trans, F&& f) 179 | { 180 | out << ""; 181 | f(*this); 182 | out << ""; 183 | } 184 | 185 | static void save_font(Ostream& out, font const& f) 186 | { 187 | char const* style[] = {"normal", "italic", "oblique"}; 188 | out << "font-size=\"" << f.size << '\"'; 189 | if (!f.family.empty()) 190 | out << " font-family=\"" << f.family << '\"'; 191 | out << " font-style=\"" << style[int(f.style)] << '\"'; 192 | out << " font-weight=\"" << f.weight << '\"'; 193 | } 194 | 195 | ~basic_canvas() 196 | { 197 | out << ""; 198 | } 199 | 200 | private: 201 | 202 | std::string _brush; 203 | std::string _pen; 204 | }; 205 | 206 | using canvas = basic_canvas; 207 | }} 208 | 209 | #endif 210 | -------------------------------------------------------------------------------- /include/niji/algorithm/area.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2018 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_ALGORITHM_AREA_HPP_INCLUDED 8 | #define NIJI_ALGORITHM_AREA_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // Reference: 16 | // http://ich.deanmcnamee.com/graphics/2016/03/30/CurveArea.html 17 | 18 | namespace niji { namespace detail 19 | { 20 | template 21 | struct area_sink 22 | { 23 | T line_sum = 0; 24 | T quad_sum = 0; 25 | T cubic_sum = 0; 26 | 27 | void operator()(move_to_t, point const& pt) 28 | { 29 | _first = _pt0 = pt; 30 | } 31 | 32 | void operator()(line_to_t, point const& pt1) 33 | { 34 | line_sum += vectors::cross(_pt0, pt1); 35 | _pt0 = pt1; 36 | } 37 | 38 | void operator()(quad_to_t, point const& pt1, point const& pt2) 39 | { 40 | quad_sum += 41 | 2 * pt1.x * (pt2.y - _pt0.y) + 42 | _pt0.x * (2 * pt1.y + pt2.y) - 43 | pt2.x * (_pt0.y + 2 * pt1.y); 44 | 45 | _pt0 = pt2; 46 | } 47 | 48 | void operator()(cubic_to_t, point const& pt1, point const& pt2, point const& pt3) 49 | { 50 | cubic_sum += 51 | 3 * pt1.x * (pt2.y + pt3.y - 2 * _pt0.y) + 52 | _pt0.x * (6 * pt1.y + 3 * pt2.y + pt3.y) - 53 | pt3.x * (_pt0.y + 3 * pt1.y + 6 * pt2.y) - 54 | 3 * pt2.x * (_pt0.y + pt1.y - 2 * pt3.y); 55 | 56 | _pt0 = pt3; 57 | } 58 | 59 | void operator()(end_open_t) {} 60 | 61 | void operator()(end_closed_t) 62 | { 63 | line_sum += vectors::cross(_pt0, _first); 64 | _pt0 = _first; 65 | } 66 | 67 | private: 68 | point _pt0, _first; 69 | }; 70 | }} 71 | 72 | namespace niji 73 | { 74 | template 75 | auto area(Path const& path) 76 | { 77 | using coord_t = path_coordinate_t; 78 | detail::area_sink accum; 79 | niji::render(path, accum); 80 | return accum.line_sum / 2 + accum.quad_sum / 6 + accum.cubic_sum / 20; 81 | } 82 | } 83 | 84 | #endif -------------------------------------------------------------------------------- /include/niji/algorithm/bounds.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_ALGORITHM_BOUNDS_HPP_INCLUDED 8 | #define NIJI_ALGORITHM_BOUNDS_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace niji { namespace detail 21 | { 22 | template 23 | struct bounds_sink 24 | { 25 | point min, max; 26 | 27 | bounds_sink() 28 | : min(boost::numeric::bounds::highest(), boost::numeric::bounds::highest()) 29 | , max(boost::numeric::bounds::lowest(), boost::numeric::bounds::lowest()) 30 | , _moving(true) 31 | {} 32 | 33 | void operator()(move_to_t, point const& pt) 34 | { 35 | _prev = pt; 36 | _moving = true; 37 | } 38 | 39 | void operator()(line_to_t, point const& pt) 40 | { 41 | line_start(); 42 | adjust(pt); 43 | } 44 | 45 | void operator()(quad_to_t, point const& pt1, point const& pt2) 46 | { 47 | line_start(); 48 | adjust_quad(_prev, pt1, pt2); 49 | } 50 | 51 | void operator()(cubic_to_t, point const& pt1, point const& pt2, point const& pt3) 52 | { 53 | line_start(); 54 | adjust_cubic(_prev, pt1, pt2, pt3); 55 | } 56 | 57 | void operator()(end_tag) {} 58 | 59 | private: 60 | void line_start() 61 | { 62 | if (_moving) 63 | { 64 | adjust_coord2<0>(_prev.x); 65 | adjust_coord2<1>(_prev.y); 66 | _moving = false; 67 | } 68 | } 69 | 70 | void adjust_quad(point const& a, point const& b, point const& c) 71 | { 72 | if (b.x < min.x || b.x > max.x) 73 | adjust_quad_coord<0>(a, b, c); 74 | else 75 | adjust_coord<0>(c.x); 76 | if (b.y < min.y || b.y > max.y) 77 | adjust_quad_coord<1>(a, b, c); 78 | else 79 | adjust_coord<1>(c.y); 80 | _prev = c; 81 | } 82 | 83 | void adjust_cubic(point const& a, point const& b, point const& c, point const& d) 84 | { 85 | if (b.x < min.x || b.x > max.x || c.x < min.x || c.x > max.x) 86 | adjust_cubic_coord<0>(a, b, c, d); 87 | if (b.y < min.y || b.y > max.y || c.y < min.y || c.y > max.y) 88 | adjust_cubic_coord<1>(a, b, c, d); 89 | adjust(d); 90 | } 91 | 92 | template 93 | void adjust_quad_coord(point const& a, point const& b, point const& c) 94 | { 95 | using boost::geometry::get; 96 | using boost::geometry::set; 97 | 98 | T aa = get(a), bb = get(b), cc = get(c); 99 | if (aa == bb || cc == bb) 100 | { 101 | adjust_coord(cc); 102 | return; 103 | } 104 | if (aa > bb) 105 | { 106 | if (cc < bb && cc < get(min)) 107 | { 108 | set(min, cc); 109 | return; 110 | } 111 | } 112 | else if (cc > bb && cc > get(max)) 113 | { 114 | set(max, cc); 115 | return; 116 | } 117 | T t; 118 | auto end = find_quad_extrema(aa, bb, cc, &t); 119 | if (&t != end) 120 | adjust_coord(bezier::quad_eval(aa, bb, cc, t)); 121 | } 122 | 123 | template 124 | void adjust_cubic_coord(point const& a, point const& b, point const& c, point const& d) 125 | { 126 | using boost::geometry::get; 127 | using boost::geometry::set; 128 | 129 | T aa = get(a), bb = get(b), cc = get(c), dd = get(d); 130 | T lo = aa, hi = dd; 131 | if (hi < lo) 132 | std::swap(hi, lo); 133 | if (lo <= bb && bb <= hi && lo <= cc && cc <= hi) 134 | return; 135 | 136 | T extrama[2]; 137 | auto end = find_cubic_extrema(aa, bb, cc, dd, extrama); 138 | for (auto it = extrama; it != end; ++it) 139 | adjust_coord(bezier::cubic_eval(aa, bb, cc, dd, *it)); 140 | } 141 | 142 | void adjust(point const& pt) 143 | { 144 | adjust_coord<0>(pt.x); 145 | adjust_coord<1>(pt.y); 146 | _prev = pt; 147 | } 148 | 149 | template 150 | void adjust_coord(T val) 151 | { 152 | using boost::geometry::get; 153 | using boost::geometry::set; 154 | 155 | if (val < get(min)) 156 | set(min, val); 157 | else if (val > get(max)) 158 | set(max, val); 159 | } 160 | 161 | // For init that max < min. 162 | template 163 | void adjust_coord2(T val) 164 | { 165 | using boost::geometry::get; 166 | using boost::geometry::set; 167 | 168 | if (val < get(min)) 169 | set(min, val); 170 | if (val > get(max)) 171 | set(max, val); 172 | } 173 | 174 | point _prev; 175 | bool _moving; 176 | }; 177 | }} 178 | 179 | namespace niji 180 | { 181 | template 182 | auto bounds(Path const& path) 183 | { 184 | using coord_t = path_coordinate_t; 185 | using point_t = point; 186 | detail::bounds_sink bounds; 187 | niji::render(path, bounds); 188 | return box(bounds.min, bounds.max); 189 | } 190 | } 191 | 192 | #endif -------------------------------------------------------------------------------- /include/niji/algorithm/generate_tangents.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_ALGORITHM_GENERATE_TANGENTS_HPP_INCLUDED 8 | #define NIJI_ALGORITHM_GENERATE_TANGENTS_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace niji { namespace detail 17 | { 18 | template 19 | struct tangents_sink 20 | { 21 | using point_t = point; 22 | using vector_t = vector; 23 | 24 | tangents_sink(T step, T offset, F& f) : _step(step), _offset(), _f(f) 25 | { 26 | using std::fmod; 27 | 28 | offset = fmod(offset, _step); 29 | if (offset < 0) 30 | offset += _step; 31 | _offset = _step - offset; 32 | } 33 | 34 | void operator()(move_to_t, point_t const& pt) 35 | { 36 | _first_pt = _prev_pt = pt; 37 | } 38 | 39 | void operator()(line_to_t, point_t const& pt) 40 | { 41 | vector_t v(pt - _prev_pt); 42 | T len(vectors::norm(v)); 43 | do_act(len, [&, u = v / len](T sum, T len) 44 | { 45 | _f(_prev_pt + u * sum, u); 46 | }); 47 | _prev_pt = pt; 48 | } 49 | 50 | void operator()(quad_to_t, point_t const& pt1, point_t const& pt2) 51 | { 52 | point_t pts[3] = {_prev_pt, pt1, pt2}; 53 | point_t chops[5]; 54 | T len(bezier::quad_length(_prev_pt, pt1, pt2)); 55 | do_act(len, [&](T sum, T len) 56 | { 57 | bezier::curve_bisect(NIJI_MAX_QUAD_SUBDIVIDE, sum, len, [&](T t) 58 | { 59 | bezier::chop_quad_at(pts, chops, t); 60 | return bezier::quad_length(chops[0], chops[1], chops[2]); 61 | }); 62 | _f(chops[2], vectors::unit(chops[2] - chops[1])); 63 | }); 64 | _prev_pt = pt2; 65 | } 66 | 67 | void operator()(cubic_to_t, point_t const& pt1, point_t const& pt2, point_t const& pt3) 68 | { 69 | point_t pts[4] = {_prev_pt, pt1, pt2, pt3}; 70 | point_t chops[7]; 71 | T len(bezier::cubic_length(_prev_pt, pt1, pt2, pt3)); 72 | do_act(len, [&](T sum, T len) 73 | { 74 | bezier::curve_bisect(NIJI_MAX_CUBIC_SUBDIVIDE, sum, len, [&](T t) 75 | { 76 | bezier::chop_cubic_at(pts, chops, t); 77 | return bezier::cubic_length(chops[0], chops[1], chops[2], chops[3]); 78 | }); 79 | _f(chops[3], vectors::unit(chops[3] - chops[2])); 80 | }); 81 | _prev_pt = pt3; 82 | } 83 | 84 | void operator()(end_open_t) {} 85 | 86 | void operator()(end_closed_t) 87 | { 88 | operator()(line_to_t{}, _first_pt); 89 | } 90 | 91 | private: 92 | template 93 | void do_act(T len, Actor&& act) 94 | { 95 | if (_offset > len) 96 | { 97 | _offset -= len; 98 | return; 99 | } 100 | act(_offset, len); 101 | T sum = _offset; 102 | _offset = 0; 103 | for ( ; ; ) 104 | { 105 | sum += _step; 106 | if (sum > len) 107 | { 108 | _offset = sum - len; 109 | return; 110 | } 111 | act(sum, len); 112 | } 113 | } 114 | 115 | T _step; 116 | T _offset; 117 | F& _f; 118 | point_t _prev_pt, _first_pt; 119 | }; 120 | }} 121 | 122 | namespace niji 123 | { 124 | template 125 | void generate_tangents(Path const& path, T const& step, T const& offset, F&& f) 126 | { 127 | using coord_t = path_coordinate_t; 128 | detail::tangents_sink sink(step, offset, f); 129 | niji::render(path, sink); 130 | } 131 | } 132 | 133 | #endif -------------------------------------------------------------------------------- /include/niji/algorithm/length.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_ALGORITHM_LENGTH_HPP_INCLUDED 8 | #define NIJI_ALGORITHM_LENGTH_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace niji { namespace detail 17 | { 18 | template 19 | struct length_sink 20 | { 21 | T sum = 0; 22 | 23 | void operator()(move_to_t, point const& pt) 24 | { 25 | _first = _prev = pt; 26 | } 27 | 28 | void operator()(line_to_t, point const& pt) 29 | { 30 | sum += vectors::norm(pt - _prev); 31 | _prev = pt; 32 | } 33 | 34 | void operator()(quad_to_t, point const& pt1, point const& pt2) 35 | { 36 | sum += bezier::quad_length(_prev, pt1, pt2); 37 | _prev = pt2; 38 | } 39 | 40 | void operator()(cubic_to_t, point const& pt1, point const& pt2, point const& pt3) 41 | { 42 | sum += bezier::cubic_length(_prev, pt1, pt2, pt3); 43 | _prev = pt3; 44 | } 45 | 46 | void operator()(end_open_t) {} 47 | 48 | void operator()(end_closed_t) 49 | { 50 | sum += vectors::norm(_first - _prev); 51 | _prev = _first; 52 | } 53 | 54 | private: 55 | point _prev, _first; 56 | }; 57 | }} 58 | 59 | namespace niji 60 | { 61 | template 62 | auto length(Path const& path) 63 | { 64 | using coord_t = path_coordinate_t; 65 | detail::length_sink accum; 66 | niji::render(path, accum); 67 | return accum.sum; 68 | } 69 | } 70 | 71 | #endif -------------------------------------------------------------------------------- /include/niji/algorithm/winding.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2016-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_ALGORITHM_WINDING_HPP_INCLUDED 8 | #define NIJI_ALGORITHM_WINDING_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace niji 16 | { 17 | template 18 | struct winding_sink 19 | { 20 | bool is_ccw = false; 21 | 22 | void operator()(move_to_t, point const& pt) 23 | { 24 | // _pts[0] & _pts[3] don't need to be set here 25 | _pts[1] = pt; 26 | _pts[2] = pt; 27 | _has_line = false; 28 | _has_turn = false; 29 | _first_is_min = true; 30 | is_ccw = false; 31 | } 32 | 33 | void operator()(line_to_t, point const& pt) 34 | { 35 | next(pt); 36 | } 37 | 38 | void operator()(quad_to_t, point const& pt1, point const& pt2) 39 | { 40 | next(pt1); 41 | next(pt2); 42 | } 43 | 44 | void operator()(cubic_to_t, point const& pt1, point const& pt2, point const& pt3) 45 | { 46 | next(pt1); 47 | next(pt2); 48 | next(pt3); 49 | } 50 | 51 | void operator()(end_open_t) {} 52 | 53 | void operator()(end_closed_t) 54 | { 55 | if (_has_turn) 56 | { 57 | auto p0 = _pts[_first_is_min ? 3 : 0]; 58 | is_ccw = vectors::is_ccw(_pts[1] - p0, _pts[2] - _pts[1]); 59 | } 60 | } 61 | 62 | private: 63 | void next(point const& pt) 64 | { 65 | if (pt.y < _pts[1].y) 66 | { 67 | _pts[0] = _pts[2 + _has_turn]; 68 | _pts[1] = pt; 69 | _has_turn = false; 70 | _first_is_min = false; 71 | } 72 | else if (_has_turn) 73 | _pts[3] = pt; 74 | else if (pt != _pts[1]) 75 | { 76 | _pts[2] = pt; 77 | _has_turn = _has_line; 78 | } 79 | _has_line = true; 80 | } 81 | 82 | bool _has_line; 83 | bool _has_turn; 84 | bool _first_is_min; 85 | point _pts[4]; 86 | }; 87 | 88 | template 89 | bool is_ccw(Path const& path) 90 | { 91 | using coord_t = path_coordinate_t; 92 | winding_sink sink; 93 | niji::render(path, sink); 94 | return sink.is_ccw; 95 | } 96 | } 97 | 98 | #endif -------------------------------------------------------------------------------- /include/niji/any_path.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_ANY_PATH_HPP_INCLUDED 8 | #define NIJI_ANY_PATH_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace niji 16 | { 17 | template 18 | class any_path 19 | { 20 | using sink_t = any_sink; 21 | 22 | template 23 | struct holder 24 | { 25 | Path path; 26 | 27 | void operator()(sink_t& sink, bool positive) const 28 | { 29 | if (positive) 30 | niji::render(path, sink); 31 | else 32 | niji::inverse_render(path, sink); 33 | } 34 | }; 35 | 36 | template 37 | using requires_valid = std::enable_if_t< 38 | !std::is_same::value 39 | && is_renderable::value, bool>; 40 | 41 | public: 42 | 43 | using point_type = Point; 44 | 45 | any_path() : _f([](sink_t&, bool){}) {} 46 | 47 | template> = true> 48 | any_path(Path&& path) 49 | : _f(holder>{std::forward(path)}) 50 | {} 51 | 52 | template> = true> 53 | any_path(std::reference_wrapper path) 54 | : _f(holder{path}) 55 | {} 56 | 57 | void render(sink_t sink) const 58 | { 59 | _f(sink, true); 60 | } 61 | 62 | void inverse_render(sink_t sink) const 63 | { 64 | _f(sink, false); 65 | } 66 | 67 | private: 68 | 69 | std::function _f; 70 | }; 71 | } 72 | 73 | #endif -------------------------------------------------------------------------------- /include/niji/detail/coord_fn.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_DETAIL_COORD_FN_HPP_INCLUDED 8 | #define NIJI_DETAIL_COORD_FN_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji { namespace detail 14 | { 15 | template 16 | struct coord_fn 17 | { 18 | template 19 | decltype(auto) operator()(Point const& pt) const 20 | { 21 | return boost::geometry::get(pt); 22 | } 23 | }; 24 | }} 25 | 26 | #endif -------------------------------------------------------------------------------- /include/niji/detail/enable_if_valid.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_DETAIL_ENABLE_IF_VALID_HPP_INCLUDED 8 | #define NIJI_DETAIL_ENABLE_IF_VALID_HPP_INCLUDED 9 | 10 | namespace niji { namespace detail 11 | { 12 | template 13 | struct enable_if_valid 14 | { 15 | using type = T; 16 | }; 17 | 18 | template 19 | using enable_if_valid_t = typename enable_if_valid::type; 20 | }} 21 | 22 | #endif -------------------------------------------------------------------------------- /include/niji/detail/priority.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_DETAIL_PRIORITY_HPP_INCLUDED 8 | #define NIJI_DETAIL_PRIORITY_HPP_INCLUDED 9 | 10 | namespace niji { namespace detail 11 | { 12 | template 13 | struct priority : priority {}; 14 | 15 | template<> 16 | struct priority<0> {}; 17 | }} 18 | 19 | #endif -------------------------------------------------------------------------------- /include/niji/geometry/box.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GEOMETRY_BOX_HPP_INCLUDED 8 | #define NIJI_GEOMETRY_BOX_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace niji 17 | { 18 | template<> 19 | struct geometry_render 20 | { 21 | template 22 | static void apply(Box const& box, Sink& sink) 23 | { 24 | using namespace command; 25 | using boost::geometry::get; 26 | using boost::geometry::make; 27 | using coord_t = typename boost::geometry::coordinate_type::type; 28 | using point_t = typename boost::geometry::point_type::type; 29 | 30 | coord_t x1 = get(box); 31 | coord_t y1 = get(box); 32 | coord_t x2 = get(box); 33 | coord_t y2 = get(box); 34 | sink(move_to, make(x1, y1)); 35 | sink(line_to, make(x2, y1)); 36 | sink(line_to, make(x2, y2)); 37 | sink(line_to, make(x1, y2)); 38 | sink(end_closed); 39 | } 40 | }; 41 | 42 | template<> 43 | struct geometry_render 44 | { 45 | template 46 | static void apply(Box const& box, Sink& sink) 47 | { 48 | using namespace command; 49 | using boost::geometry::get; 50 | using boost::geometry::make; 51 | using coord_t = typename boost::geometry::coordinate_type::type; 52 | using point_t = typename boost::geometry::point_type::type; 53 | 54 | coord_t x1 = get(box); 55 | coord_t y1 = get(box); 56 | coord_t x2 = get(box); 57 | coord_t y2 = get(box); 58 | sink(move_to, make(x1, y1)); 59 | sink(line_to, make(x1, y2)); 60 | sink(line_to, make(x2, y2)); 61 | sink(line_to, make(x2, y1)); 62 | sink(end_closed); 63 | } 64 | }; 65 | } 66 | 67 | #endif -------------------------------------------------------------------------------- /include/niji/geometry/detail/multi_geometry_render.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GEOMETRY_DETAIL_MULTI_GEOMETRY_ITERATE_HPP_INCLUDED 8 | #define NIJI_GEOMETRY_DETAIL_MULTI_GEOMETRY_ITERATE_HPP_INCLUDED 9 | 10 | #include 11 | 12 | namespace niji { namespace detail 13 | { 14 | template 15 | struct multi_geometry_render 16 | { 17 | template 18 | static void apply(MultiGeometry const& multi_geometry, Sink& sink) 19 | { 20 | for (auto const& geometry : multi_geometry) 21 | geometry_render::apply(geometry, sink); 22 | } 23 | }; 24 | }} 25 | 26 | #endif -------------------------------------------------------------------------------- /include/niji/geometry/detail/ring_render.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GEOMETRY_DETAIL_RING_ITERATE_HPP_INCLUDED 8 | #define NIJI_GEOMETRY_DETAIL_RING_ITERATE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace niji { namespace detail 17 | { 18 | template 19 | bool ring_render(Ring const& ring, Sink& sink) 20 | { 21 | using namespace command; 22 | using std::begin; 23 | using std::end; 24 | using range_t = std::conditional_t 25 | < 26 | boost::geometry::point_order::value == order 27 | , Ring const&, boost::reversed_range 28 | >; 29 | 30 | range_t range(ring); 31 | auto it(begin(range)), e(end(range)); 32 | 33 | if (it == e) 34 | return false; 35 | 36 | sink(move_to, *it); 37 | while (++it != e) 38 | sink(line_to, *it); 39 | sink(end_closed); 40 | return true; 41 | } 42 | }} 43 | 44 | #endif -------------------------------------------------------------------------------- /include/niji/geometry/linestring.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GEOMETRY_LINESTRING_HPP_INCLUDED 8 | #define NIJI_GEOMETRY_LINESTRING_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace niji 18 | { 19 | template<> 20 | struct geometry_render 21 | { 22 | template 23 | static void apply(Linestring const& linestring, Sink& sink) 24 | { 25 | using namespace command; 26 | using std::begin; 27 | using std::end; 28 | 29 | auto it(begin(linestring)), e(end(linestring)); 30 | 31 | if (it == e) 32 | return; 33 | 34 | sink(move_to, *it); 35 | while (++it != e) 36 | sink(line_to, *it); 37 | sink(end_open); 38 | } 39 | }; 40 | 41 | template<> 42 | struct geometry_render 43 | : geometry_render 44 | {}; 45 | 46 | template 47 | struct geometry_render 48 | : detail::multi_geometry_render 49 | {}; 50 | } 51 | 52 | #endif -------------------------------------------------------------------------------- /include/niji/geometry/polygon.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GEOMETRY_POLYGON_HPP_INCLUDED 8 | #define NIJI_GEOMETRY_POLYGON_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace niji 23 | { 24 | template 25 | struct geometry_render 26 | { 27 | template 28 | static void apply(Polygon const& polygon, Sink& sink) 29 | { 30 | if (detail::ring_render(boost::geometry::exterior_ring(polygon), sink)) 31 | { 32 | for (auto const& ring : boost::geometry::interior_rings(polygon)) 33 | detail::ring_render(ring, sink); 34 | } 35 | } 36 | }; 37 | 38 | template 39 | struct geometry_render 40 | : detail::multi_geometry_render 41 | {}; 42 | } 43 | 44 | #endif -------------------------------------------------------------------------------- /include/niji/geometry/render.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GEOMETRY_RENDER_HPP_INCLUDED 8 | #define NIJI_GEOMETRY_RENDER_HPP_INCLUDED 9 | 10 | #include 11 | 12 | namespace niji 13 | { 14 | template 15 | struct geometry_render; 16 | 17 | template 18 | struct multi_geometry_render 19 | { 20 | template 21 | static void apply(MultiGeometry const& multi_geometry, Sink& sink) 22 | { 23 | for (auto const& geometry : multi_geometry) 24 | geometry_render::apply(geometry, sink); 25 | } 26 | }; 27 | } 28 | 29 | #endif -------------------------------------------------------------------------------- /include/niji/geometry/ring.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GEOMETRY_RING_HPP_INCLUDED 8 | #define NIJI_GEOMETRY_RING_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace niji 17 | { 18 | template 19 | struct geometry_render 20 | { 21 | template 22 | static void apply(Ring const& ring, Sink& sink) 23 | { 24 | (void)detail::ring_render(ring, sink); 25 | } 26 | }; 27 | } 28 | 29 | #endif -------------------------------------------------------------------------------- /include/niji/geometry/segment.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GEOMETRY_SEGMENT_HPP_INCLUDED 8 | #define NIJI_GEOMETRY_SEGMENT_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace niji 17 | { 18 | template<> 19 | struct geometry_render 20 | { 21 | template 22 | static void apply(Segment const& segment, Sink& sink) 23 | { 24 | using namespace command; 25 | using boost::geometry::get; 26 | using boost::geometry::make; 27 | using coord_t = typename boost::geometry::coordinate_type::type; 28 | using point_t = typename boost::geometry::point_type::type; 29 | 30 | coord_t x1 = get<0, 0>(segment); 31 | coord_t y1 = get<0, 1>(segment); 32 | coord_t x2 = get<1, 0>(segment); 33 | coord_t y2 = get<1, 1>(segment); 34 | sink(move_to, make(x1, y1)); 35 | sink(line_to, make(x2, y2)); 36 | sink(end_open); 37 | } 38 | }; 39 | 40 | template<> 41 | struct geometry_render 42 | { 43 | template 44 | static void apply(Segment const& segment, Sink& sink) 45 | { 46 | using namespace command; 47 | using boost::geometry::get; 48 | using boost::geometry::make; 49 | using coord_t = typename boost::geometry::coordinate_type::type; 50 | using point_t = typename boost::geometry::point_type::type; 51 | 52 | coord_t x1 = get<0, 0>(segment); 53 | coord_t y1 = get<0, 1>(segment); 54 | coord_t x2 = get<1, 0>(segment); 55 | coord_t y2 = get<1, 1>(segment); 56 | sink(move_to, make(x2, y2)); 57 | sink(line_to, make(x1, y1)); 58 | sink(end_open); 59 | } 60 | }; 61 | } 62 | 63 | #endif -------------------------------------------------------------------------------- /include/niji/graphic/angular.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2018 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GRAPHIC_ANGULAR_HPP_INCLUDED 8 | #define NIJI_GRAPHIC_ANGULAR_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace niji 18 | { 19 | template 20 | struct angular 21 | { 22 | using point_type = point; 23 | 24 | using store_t = std::array; 25 | using param_t = std::conditional_t<(N > 1), store_t const&, T>; 26 | 27 | point_type origin; 28 | store_t r; 29 | store_t theta; // To turn side up, use radian = PI / n 30 | unsigned n; 31 | 32 | angular(std::size_t n, point_type const& pt, param_t r, param_t theta = {}) 33 | : origin(pt), r{r}, theta{theta}, n(n) 34 | {} 35 | 36 | template 37 | void render(Sink& sink) const 38 | { 39 | render_impl(sink, constants::two_pi()); 40 | } 41 | 42 | template 43 | void inverse_render(Sink& sink) const 44 | { 45 | render_impl(sink, -constants::two_pi()); 46 | } 47 | 48 | private: 49 | 50 | template 51 | void render_impl(Sink& sink, T da) const 52 | { 53 | using namespace command; 54 | using std::sin; 55 | using std::cos; 56 | 57 | if (n < 3) 58 | return; 59 | 60 | da /= n; 61 | 62 | std::array d(theta); 63 | for (T& di : d) 64 | di += constants::half_pi(); 65 | 66 | auto d1 = d[0]; 67 | auto r1 = r[0]; 68 | sink(move_to, point_type{origin.x + cos(d1) * r1, origin.y + sin(d1) * r1}); 69 | for (std::size_t i = 0; i != N; ++i) 70 | { 71 | auto di = d[i]; 72 | auto ri = r[i]; 73 | sink(line_to, point_type{origin.x + cos(di) * ri, origin.y + sin(di) * ri}); 74 | } 75 | 76 | auto fn = [&] 77 | { 78 | for (std::size_t i = 0; i != N; ++i) 79 | { 80 | auto di = d[i] += da; 81 | auto ri = r[i]; 82 | sink(line_to, point_type{origin.x + cos(di) * ri, origin.y + sin(di) * ri}); 83 | } 84 | }; 85 | 86 | unsigned m = n - 1, k = (m - 1) >> 2, i = 0; 87 | switch (m & 3u) 88 | { 89 | do 90 | { 91 | case 0: fn(); 92 | case 3: fn(); 93 | case 2: fn(); 94 | case 1: fn(); 95 | } while (i++ != k); 96 | } 97 | sink(end_closed); 98 | } 99 | }; 100 | } 101 | 102 | #endif -------------------------------------------------------------------------------- /include/niji/graphic/arc.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GRAPHIC_ARC_HPP_INCLUDED 8 | #define NIJI_GRAPHIC_ARC_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace niji 18 | { 19 | template 20 | struct arc 21 | { 22 | using point_type = point; 23 | using box_type = niji::box; 24 | 25 | box_type box; 26 | T start, sweep; 27 | 28 | arc(box_type const& box, T start, T sweep) 29 | : box(box), start(start), sweep(sweep) 30 | {} 31 | 32 | template 33 | void render(Sink& sink) const 34 | { 35 | render_impl(sink, start, start + sweep); 36 | } 37 | 38 | template 39 | void inverse_render(Sink& sink) const 40 | { 41 | render_impl(sink, start + sweep, start); 42 | } 43 | 44 | private: 45 | 46 | template 47 | void render_impl(Sink& sink, T start, T stop) const 48 | { 49 | using namespace command; 50 | using std::sin; 51 | using std::cos; 52 | 53 | transforms::affine affine; 54 | T rx = box.width() / 2, ry = box.height() / 2; 55 | affine.scale(rx, ry).translate(box.min_corner.x + rx, box.min_corner.y + ry); 56 | 57 | vector u(cos(start), sin(start)), v(cos(stop), sin(stop)); 58 | # if defined(NIJI_NO_CUBIC_APPROX) 59 | point pts[17]; 60 | auto it = pts, end = bezier::build_quad_arc(u, v, stop > start, &affine, pts); 61 | sink(move_to, *it++); 62 | for ( ; it != end; it += 2) 63 | sink(quad_to, *it, it[1]); 64 | # else 65 | point pts[13]; 66 | auto it = pts, end = bezier::build_cubic_arc(u, v, stop > start, &affine, pts); 67 | sink(move_to, *it++); 68 | for ( ; it != end; it += 3) 69 | sink(cubic_to, *it, it[1], it[2]); 70 | # endif 71 | sink(end_open); 72 | } 73 | }; 74 | } 75 | 76 | #endif -------------------------------------------------------------------------------- /include/niji/graphic/cross.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GRAPHIC_CROSS_HPP_INCLUDED 8 | #define NIJI_GRAPHIC_CROSS_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace niji 15 | { 16 | template 17 | struct cross 18 | { 19 | using point_type = point; 20 | 21 | point_type center; 22 | T r; 23 | 24 | cross(point_type const& center, T r) : center(center), r(r) {} 25 | 26 | template 27 | void render(Sink& sink) const 28 | { 29 | auto line = [&](vector v) 30 | { 31 | using namespace command; 32 | sink(move_to, center - v); 33 | sink(line_to, center + v); 34 | sink(end_open); 35 | }; 36 | line({r, 0}); 37 | line({0, r}); 38 | } 39 | 40 | template 41 | void inverse_render(Sink& sink) const 42 | { 43 | render(sink); 44 | } 45 | }; 46 | } 47 | 48 | #endif -------------------------------------------------------------------------------- /include/niji/graphic/ellipse.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2018 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GRAPHIC_ELLIPSE_HPP_INCLUDED 8 | #define NIJI_GRAPHIC_ELLIPSE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace niji 16 | { 17 | template 18 | struct ellipse 19 | { 20 | using point_type = point; 21 | 22 | point_type center; 23 | T rx, ry; 24 | 25 | ellipse(point_type const& pt, T r) 26 | : center(pt), rx(r), ry(r) 27 | {} 28 | 29 | ellipse(point_type const& pt, T rx, T ry) 30 | : center(pt), rx(rx), ry(ry) 31 | {} 32 | 33 | std::pair radius() const 34 | { 35 | return std::pair(rx, ry); 36 | } 37 | 38 | void radius(T r) 39 | { 40 | rx = r; 41 | ry = r; 42 | } 43 | 44 | void radius(T x, T y) 45 | { 46 | rx = x; 47 | ry = y; 48 | } 49 | 50 | template 51 | void render(Sink& sink) const 52 | { 53 | render_impl(sink, ry); 54 | } 55 | 56 | template 57 | void inverse_render(Sink& sink) const 58 | { 59 | render_impl(sink, -ry); 60 | } 61 | 62 | private: 63 | 64 | template 65 | void render_impl(Sink& sink, T ry) const 66 | { 67 | using namespace command; 68 | 69 | T x = center.x, y = center.y, 70 | x1 = x + rx, x2 = x - rx, 71 | y1 = y + ry, y2 = y - ry; 72 | 73 | sink(move_to, point_type{x1, y}); 74 | # if defined(NIJI_NO_CUBIC_APPROX) 75 | T sx = rx * constants::tan_pi_over_8(), 76 | sy = ry * constants::tan_pi_over_8(), 77 | mx = rx * constants::root2_over_2(), 78 | my = ry * constants::root2_over_2(), 79 | x3 = x + sx, x4 = x - sx, x5 = x + mx, x6 = x - mx, 80 | y3 = y + sy, y4 = y - sy, y5 = y + my, y6 = y - my; 81 | 82 | sink(quad_to, point_type{x1, y3}, point_type{x5, y5}); 83 | sink(quad_to, point_type{x3, y1}, point_type{x, y1}); 84 | sink(quad_to, point_type{x4, y1}, point_type{x6, y5}); 85 | sink(quad_to, point_type{x2, y3}, point_type{x2, y}); 86 | sink(quad_to, point_type{x2, y4}, point_type{x6, y6}); 87 | sink(quad_to, point_type{x4, y2}, point_type{x, y2}); 88 | sink(quad_to, point_type{x3, y2}, point_type{x5, y6}); 89 | sink(quad_to, point_type{x1, y4}, point_type{x1, y}); 90 | # else 91 | T sx = rx * constants::cubic_arc_factor(), 92 | sy = ry * constants::cubic_arc_factor(), 93 | x3 = x + sx, x4 = x - sx, y3 = y + sy, y4 = y - sy; 94 | 95 | sink(cubic_to, point_type{x1, y3}, point_type{x3, y1}, point_type{x, y1}); 96 | sink(cubic_to, point_type{x4, y1}, point_type{x2, y3}, point_type{x2, y}); 97 | sink(cubic_to, point_type{x2, y4}, point_type{x4, y2}, point_type{x, y2}); 98 | sink(cubic_to, point_type{x3, y2}, point_type{x1, y4}, point_type{x1, y}); 99 | # endif 100 | sink(end_closed); 101 | } 102 | }; 103 | } 104 | 105 | #endif -------------------------------------------------------------------------------- /include/niji/graphic/frame.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GRAPHIC_FRAME_HPP_INCLUDED 8 | #define NIJI_GRAPHIC_FRAME_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace niji 17 | { 18 | template 19 | struct frame 20 | { 21 | using point_type = point; 22 | using box_type = niji::box; 23 | 24 | box_type box; 25 | T border; 26 | 27 | frame(box_type const& box, T border) 28 | : box(box) 29 | , border(border) 30 | {} 31 | 32 | frame(point_type const& min, point_type const& max, T border) 33 | : box(min, max) 34 | , border(border) 35 | {} 36 | 37 | template 38 | void render(Sink& sink) const 39 | { 40 | render_impl(sink, border > 0); 41 | } 42 | 43 | template 44 | void inverse_render(Sink& sink) const 45 | { 46 | render_impl(sink, border < 0); 47 | } 48 | 49 | private: 50 | 51 | template 52 | void render_impl(Sink& sink, bool orient) const 53 | { 54 | box_type off(box); 55 | off.offset(border, border); 56 | if (orient) 57 | { 58 | niji::render(off, sink); 59 | niji::inverse_render(box, sink); 60 | } 61 | else 62 | { 63 | niji::render(box, sink); 64 | niji::inverse_render(off, sink); 65 | } 66 | } 67 | }; 68 | } 69 | 70 | #endif -------------------------------------------------------------------------------- /include/niji/graphic/spiral.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2018 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GRAPHIC_SPIRAL_HPP_INCLUDED 8 | #define NIJI_GRAPHIC_SPIRAL_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace niji 16 | { 17 | template 18 | struct spiral 19 | { 20 | using point_type = point; 21 | 22 | point_type origin; 23 | T r; 24 | int n; 25 | 26 | spiral(point_type const& pt, T r, int n) 27 | : origin(pt), r(r), n(n) 28 | {} 29 | 30 | template 31 | void render(Sink& sink) const 32 | { 33 | render_impl(sink, origin, r, n); 34 | } 35 | 36 | template 37 | void inverse_render(Sink& sink) const 38 | { 39 | render(sink); 40 | } 41 | 42 | private: 43 | 44 | template 45 | static void render_impl(Sink& sink, point_type const& o, T r, int n) 46 | { 47 | using namespace command; 48 | 49 | sink(move_to, o); 50 | # if defined(NIJI_NO_CUBIC_APPROX) 51 | r /= 16; 52 | 53 | T ds = r * constants::tan_pi_over_8(), 54 | dm = r * constants::root2_over_2(), 55 | dr = r, s = ds, m = dm; 56 | 57 | point_type pt; 58 | auto q1 = [&](T x, T y) 59 | { 60 | pt.reset(x, y); 61 | r += dr, s += ds, m += dm; 62 | }; 63 | auto q2 = [&](T x, T y) 64 | { 65 | sink(quad_to, o + pt, point_type{o.x + x, o.y + y}); 66 | r += dr, s += ds, m += dm; 67 | }; 68 | for (int i = 0; i != n; ++i) 69 | { 70 | q1(r, s), q2(m, m); 71 | q1(s, r), q2(0, r); 72 | q1(-s, r), q2(-m, m); 73 | q1(-r, s), q2(-r, 0); 74 | q1(-r, -s), q2(-m, -m); 75 | q1(-s, -r), q2(0, -r); 76 | q1(s, -r), q2(m, -m); 77 | q1(r, -s), q2(r, 0); 78 | } 79 | # else 80 | r /= 12; // the angle is near pi/6 81 | 82 | T ds = r * constants::cubic_arc_factor(), 83 | dr = r, s = ds; 84 | 85 | point_type pt1, pt2; 86 | auto c1 = [&](T x, T y) 87 | { 88 | pt1.reset(x, y); 89 | r += dr, s += ds; 90 | }; 91 | auto c2 = [&](T x, T y) 92 | { 93 | pt2.reset(x, y); 94 | r += dr, s += ds; 95 | }; 96 | auto c3 = [&](T x, T y) 97 | { 98 | sink(cubic_to, o + pt1, o + pt2, point_type{o.x + x, o.y + y}); 99 | r += dr, s += ds; 100 | }; 101 | for (int i = 0; i != n; ++i) 102 | { 103 | c1(r, s), c2(s, r), c3(0, r); 104 | c1(-s, r), c2(-r, s), c3(-r, 0); 105 | c1(-r, -s), c2(-s, -r), c3(0, -r); 106 | c1(s, -r), c2(r, -s), c3(r, 0); 107 | } 108 | # endif 109 | sink(end_open); 110 | } 111 | }; 112 | } 113 | 114 | #endif -------------------------------------------------------------------------------- /include/niji/group.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_GROUP_HPP_INCLUDED 8 | #define NIJI_GROUP_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace niji 15 | { 16 | template > 17 | class group : boost::container::deque 18 | { 19 | using base_type = boost::container::deque; 20 | 21 | public: 22 | 23 | using point_type = path_point_t; 24 | using path_type = Path; 25 | 26 | // Iterators 27 | //---------------------------------------------------------------------- 28 | using iterator = typename base_type::iterator; 29 | using base_type::const_iterator; 30 | using base_type::begin; 31 | using base_type::end; 32 | 33 | // Observers 34 | //---------------------------------------------------------------------- 35 | using base_type::front; 36 | using base_type::back; 37 | using base_type::size; 38 | using base_type::empty; 39 | using base_type::at; 40 | using base_type::operator[]; 41 | 42 | // Constructors 43 | //---------------------------------------------------------------------- 44 | explicit group(Alloc const& alloc = Alloc()) noexcept 45 | : base_type(alloc) 46 | {} 47 | 48 | // Modifiers 49 | //---------------------------------------------------------------------- 50 | using base_type::erase; 51 | using base_type::clear; 52 | 53 | iterator unstable_erase(iterator const& pos) 54 | { 55 | using std::swap; 56 | if (boost::next(pos) == base_type::end()) 57 | { 58 | base_type::pop_back(); 59 | return base_type::end(); 60 | } 61 | *pos = std::move(base_type::back()); 62 | base_type::pop_back(); 63 | return pos; 64 | } 65 | 66 | void swap(group& other) noexcept 67 | { 68 | base_type::swap(other); 69 | } 70 | 71 | template 72 | void add(T&& path) 73 | { 74 | base_type::emplace_back(std::forward(path)); 75 | } 76 | 77 | // Traverse 78 | //---------------------------------------------------------------------- 79 | template 80 | void render(Sink& sink) const 81 | { 82 | for (auto const& path : *this) 83 | niji::render(path, sink); 84 | } 85 | 86 | template 87 | void inverse_render(Sink& sink) const 88 | { 89 | for (auto const& path : *this) 90 | niji::inverse_render(path, sink); 91 | } 92 | 93 | template 94 | void serialize(Archive & ar, unsigned version) 95 | { 96 | ar & *static_cast(this); 97 | } 98 | }; 99 | } 100 | 101 | #endif -------------------------------------------------------------------------------- /include/niji/make/composite.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_MAKE_COMPOSITE_HPP_INCLUDED 8 | #define NIJI_MAKE_COMPOSITE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace niji 16 | { 17 | template 18 | struct composite_path 19 | { 20 | using point_type = 21 | common_point_t>...>; 22 | 23 | using unpack_sequence = std::make_index_sequence; 24 | 25 | composite_path(Paths&&... paths) 26 | : paths(std::forward(paths)...) 27 | {} 28 | 29 | template 30 | void render(Sink& sink) const 31 | { 32 | for_each([&sink](auto const& path) 33 | { 34 | niji::render(path, sink); 35 | }, unpack_sequence{}); 36 | } 37 | 38 | template 39 | void inverse_render(Sink& sink) const 40 | { 41 | for_each([&sink](auto const& path) 42 | { 43 | niji::inverse_render(path, sink); 44 | }, unpack_sequence{}); 45 | } 46 | 47 | private: 48 | 49 | template 50 | void for_each(F&& f, std::integer_sequence) const 51 | { 52 | std::initializer_list{(f(std::get(paths)), true)...}; 53 | } 54 | 55 | std::tuple paths; 56 | }; 57 | 58 | template 59 | inline composite_path make_composite(Paths&&... paths) 60 | { 61 | return {std::forward(paths)...}; 62 | } 63 | } 64 | 65 | #endif -------------------------------------------------------------------------------- /include/niji/make/graphic.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2017-2018 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_MAKE_GRAPHIC_HPP_INCLUDED 8 | #define NIJI_MAKE_GRAPHIC_HPP_INCLUDED 9 | 10 | #include 11 | 12 | namespace niji 13 | { 14 | template 15 | struct graphic_path 16 | { 17 | using point_type = Point; 18 | 19 | F f; 20 | 21 | // Either one of the 2 overloads should be viable. 22 | template 23 | auto render(Sink& sink) const -> decltype(f(sink, std::false_type{})) 24 | { 25 | f(sink, std::false_type{}); 26 | } 27 | 28 | template 29 | auto render(Sink& sink) const -> decltype(f(sink)) 30 | { 31 | f(sink); 32 | } 33 | 34 | // May be disabled. 35 | template 36 | auto inverse_render(Sink& sink) const -> decltype(f(sink, std::true_type{})) 37 | { 38 | f(sink, std::true_type{}); 39 | } 40 | }; 41 | 42 | template 43 | inline graphic_path make_graphic(F&& f) 44 | { 45 | return {std::forward(f)}; 46 | } 47 | } 48 | 49 | #endif -------------------------------------------------------------------------------- /include/niji/make/lazy.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_MAKE_LAZY_HPP_INCLUDED 8 | #define NIJI_MAKE_LAZY_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji 14 | { 15 | template 16 | struct lazy_path 17 | { 18 | using result_type = std::result_of_t; 19 | using point_type = path_point_t; 20 | 21 | F f; 22 | 23 | template 24 | void render(Sink& sink) const 25 | { 26 | niji::render(f(), sink); 27 | } 28 | 29 | template 30 | void inverse_render(Sink& sink) const 31 | { 32 | niji::inverse_render(f(), sink); 33 | } 34 | }; 35 | 36 | template 37 | inline lazy_path make_lazy(F&& f) 38 | { 39 | return {std::forward(f)}; 40 | } 41 | } 42 | 43 | #endif -------------------------------------------------------------------------------- /include/niji/path_fwd.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_PATH_FWD_HPP_INCLUDED 8 | #define NIJI_PATH_FWD_HPP_INCLUDED 9 | 10 | #include // for allocator 11 | 12 | namespace niji 13 | { 14 | template> 15 | class path; 16 | } 17 | 18 | #endif -------------------------------------------------------------------------------- /include/niji/path_ref.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_PATH_REF_HPP_INCLUDED 8 | #define NIJI_PATH_REF_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace niji 15 | { 16 | template 17 | class path_ref 18 | { 19 | using sink_t = any_sink; 20 | 21 | template 22 | using requires_valid = std::enable_if_t< 23 | !std::is_same::value 24 | && is_renderable::value, bool>; 25 | 26 | template 27 | static void f(void const* p, sink_t& sink, bool positive) 28 | { 29 | auto& path = *static_cast(p); 30 | if (positive) 31 | niji::render(path, sink); 32 | else 33 | niji::inverse_render(path, sink); 34 | } 35 | 36 | public: 37 | 38 | using point_type = Point; 39 | 40 | template = true> 41 | path_ref(Path const& path) 42 | : _p(&path), _f(f) 43 | {} 44 | 45 | void render(sink_t sink) const 46 | { 47 | _f(_p, sink, true); 48 | } 49 | 50 | void inverse_render(sink_t sink) const 51 | { 52 | _f(_p, sink, false); 53 | } 54 | 55 | private: 56 | 57 | void const* _p; 58 | void(*_f)(void const*, sink_t&, bool); 59 | }; 60 | } 61 | 62 | #endif -------------------------------------------------------------------------------- /include/niji/render.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_RENDER_HPP_INCLUDED 8 | #define NIJI_RENDER_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace niji { namespace detail 19 | { 20 | template 21 | inline auto render_dispatch(priority<1>, Path const& path, Sink& sink) -> decltype(path.render(sink)) 22 | { 23 | return path.render(sink); 24 | } 25 | 26 | template 27 | inline auto render_dispatch(priority<0>, Path const& path, Sink& sink) -> std::enable_if_t::value> 28 | { 29 | geometry_render, boost::geometry::counterclockwise>::apply(path, sink); 30 | } 31 | 32 | template 33 | inline auto render(Path const& path, Sink& sink) -> decltype(render_dispatch(priority<1>{}, path, sink)) 34 | { 35 | return render_dispatch(priority<1>{}, path, sink); 36 | } 37 | 38 | template 39 | inline auto inverse_render_dispatch(priority<2>, Path const& path, Sink& sink) -> decltype(path.inverse_render(sink)) 40 | { 41 | return path.inverse_render(sink); 42 | } 43 | 44 | template 45 | inline auto inverse_render_dispatch(priority<1>, Path const& path, Sink& sink) -> std::enable_if_t::value> 46 | { 47 | geometry_render, boost::geometry::clockwise>::apply(path, sink); 48 | } 49 | 50 | template 51 | inline auto inverse_render_dispatch(priority<0>, Path const& path, Sink& sink) -> decltype(render(path, sink)) 52 | { 53 | niji::path> tmp(path); 54 | tmp.inverse_render(sink); 55 | } 56 | 57 | template 58 | inline auto inverse_render(Path const& path, Sink& sink) -> decltype(inverse_render_dispatch(priority<2>{}, path, sink)) 59 | { 60 | return inverse_render_dispatch(priority<2>{}, path, sink); 61 | } 62 | 63 | template 64 | auto is_renderable_test(Path const& path, Sink& sink) -> enable_if_valid_t; 65 | 66 | std::false_type is_renderable_test(...); 67 | 68 | struct render_fn 69 | { 70 | template 71 | auto operator()(Path const& path, Sink&& sink) const -> decltype(render(path, sink)) 72 | { 73 | return render(path, sink); 74 | } 75 | }; 76 | 77 | struct inverse_render_fn 78 | { 79 | template 80 | auto operator()(Path const& path, Sink&& sink) const -> decltype(inverse_render(path, sink)) 81 | { 82 | return inverse_render(path, sink); 83 | } 84 | }; 85 | }} 86 | 87 | namespace niji 88 | { 89 | NIJI_IDENTIFIER(detail::render_fn, render); 90 | NIJI_IDENTIFIER(detail::inverse_render_fn, inverse_render); 91 | 92 | template 93 | struct is_renderable 94 | : decltype(detail::is_renderable_test(std::declval(), std::declval>())) 95 | {}; 96 | } 97 | 98 | #endif -------------------------------------------------------------------------------- /include/niji/sink/any.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SINK_ANY_HPP_INCLUDED 8 | #define NIJI_SINK_ANY_HPP_INCLUDED 9 | 10 | #include 11 | 12 | namespace niji { namespace any_sink_detail 13 | { 14 | template 15 | struct vtable 16 | { 17 | vtable(...) {} 18 | }; 19 | 20 | template 21 | struct vtable : vtable 22 | { 23 | template 24 | vtable(Gen gen) : vtable(gen), f(Gen::f) {} 25 | 26 | operator T*() const { return f; } 27 | 28 | T* f; 29 | }; 30 | 31 | template 32 | struct vgen 33 | { 34 | template 35 | static void f(void* p, Ts... ts) 36 | { 37 | (*static_cast(p))(std::forward(ts)...); 38 | } 39 | }; 40 | }} 41 | 42 | namespace niji 43 | { 44 | template 45 | struct any_sink 46 | { 47 | template 48 | any_sink(Sink& sink) 49 | : _sink(&sink) 50 | , _f(any_sink_detail::vgen()) 51 | {} 52 | 53 | template 54 | void operator()(Tag tag, Points const&... pts) const 55 | { 56 | _f(_sink, tag, pts...); 57 | } 58 | 59 | void* _sink; 60 | any_sink_detail::vtable 61 | < 62 | void(void*, move_to_t, Point const&) 63 | , void(void*, line_to_t, Point const&) 64 | , void(void*, quad_to_t, Point const&, Point const&) 65 | , void(void*, cubic_to_t, Point const&, Point const&, Point const&) 66 | , void(void*, end_open_t) 67 | , void(void*, end_closed_t) 68 | > _f; 69 | }; 70 | } 71 | 72 | #endif -------------------------------------------------------------------------------- /include/niji/sink/cairo.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SINK_CAIRO_HPP_INCLUDED 8 | #define NIJI_SINK_CAIRO_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace niji 16 | { 17 | struct cairo_sink 18 | { 19 | ::cairo_t* context; 20 | 21 | explicit cairo_sink(::cairo_t* context) 22 | : context(context) 23 | {} 24 | 25 | template 26 | void operator()(move_to_t, Point const& pt) 27 | { 28 | using boost::geometry::get; 29 | ::cairo_move_to(context, get<0>(pt), get<1>(pt)); 30 | } 31 | 32 | template 33 | void operator()(line_to_t, Point const& pt) 34 | { 35 | using boost::geometry::get; 36 | ::cairo_line_to(context, get<0>(pt), get<1>(pt)); 37 | } 38 | 39 | void operator()(quad_to_t, dpoint pt1, dpoint const& pt2) 40 | { 41 | dpoint pt0; 42 | ::cairo_get_current_point(context, &pt0.x, &pt0.y); 43 | pt1 *= 2.0; 44 | pt0 = (pt0 + pt1) / 3.0; 45 | pt1 = (pt2 + pt1) / 3.0; 46 | ::cairo_curve_to(context, pt0.x, pt0.y, pt1.x, pt1.y, pt2.x, pt2.y); 47 | } 48 | 49 | template 50 | void operator()(cubic_to_t, Point const& pt1, Point const& pt2, Point const& pt3) 51 | { 52 | using boost::geometry::get; 53 | ::cairo_curve_to(context, get<0>(pt1), get<1>(pt1), get<0>(pt2), get<1>(pt2), get<0>(pt3), get<1>(pt3)); 54 | } 55 | 56 | void operator()(end_open_t) {} 57 | 58 | void operator()(end_closed_t) 59 | { 60 | ::cairo_close_path(context); 61 | } 62 | }; 63 | } 64 | 65 | #endif -------------------------------------------------------------------------------- /include/niji/sink/d2d.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SINK_D2D_HPP_INCLUDED 8 | #define NIJI_SINK_D2D_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace niji 15 | { 16 | struct d2d_sink 17 | { 18 | ::ID2D1GeometrySink* geometry_sink; 19 | ::D2D1_FIGURE_BEGIN figure_begin; 20 | 21 | d2d_sink(::ID2D1GeometrySink* d2d_sink, ::D2D1_FIGURE_BEGIN figure_begin) 22 | : geometry_sink(d2d_sink), figure_begin(figure_begin) 23 | {} 24 | 25 | template 26 | static ::D2D1_POINT_2F cvt_point(Point const& pt) 27 | { 28 | using boost::geometry::get; 29 | ::D2D1_POINT_2F ret = {get<0>(pt), get<1>(pt)}; 30 | return ret; 31 | } 32 | 33 | template 34 | void operator()(move_to_t, Point const& pt) 35 | { 36 | geometry_sink->BeginFigure(cvt_point(pt), figure_begin); 37 | } 38 | 39 | template 40 | void operator()(line_to_t, Point const& pt) 41 | { 42 | geometry_sink->AddLine(cvt_point(pt)); 43 | } 44 | 45 | template 46 | void operator()(quad_to_t, Point const& pt1, Point const& pt2) 47 | { 48 | geometry_sink->AddQuadraticBezier( 49 | { 50 | cvt_point(pt1), cvt_point(pt2) 51 | }); 52 | } 53 | 54 | template 55 | void operator()(cubic_to_t, Point const& pt1, Point const& pt2, Point const& pt3) 56 | { 57 | using boost::geometry::get; 58 | geometry_sink->AddBezier( 59 | { 60 | cvt_point(pt1), cvt_point(pt2), cvt_point(pt3) 61 | }); 62 | } 63 | 64 | void operator()(end_open_t) 65 | { 66 | geometry_sink->EndFigure(::D2D1_FIGURE_END_OPEN); 67 | } 68 | 69 | void operator()(end_closed_t) 70 | { 71 | geometry_sink->EndFigure(::D2D1_FIGURE_END_CLOSED); 72 | } 73 | }; 74 | } 75 | 76 | #endif -------------------------------------------------------------------------------- /include/niji/sink/debug.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SINK_DEBUG_HPP_INCLUDED 8 | #define NIJI_SINK_DEBUG_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace niji 16 | { 17 | struct debug_sink 18 | { 19 | std::ostream& out; 20 | 21 | explicit debug_sink(std::ostream& out) 22 | : out(out) 23 | {} 24 | 25 | struct tag_str 26 | { 27 | char const* str; 28 | 29 | tag_str(move_to_t) 30 | : str("move_to") 31 | {} 32 | 33 | tag_str(line_to_t) 34 | : str("line_to") 35 | {} 36 | }; 37 | 38 | struct print_pt 39 | { 40 | std::ostream& out; 41 | 42 | explicit print_pt(std::ostream& out) 43 | : out(out) 44 | {} 45 | 46 | template 47 | void operator()(Point const& pt) 48 | { 49 | using boost::geometry::get; 50 | 51 | out << " (" << get<0>(pt) << ", " << get<1>(pt) << ')'; 52 | } 53 | }; 54 | 55 | template 56 | void operator()(tag_str tag, Point const& pt) 57 | { 58 | using boost::geometry::get; 59 | 60 | out << tag.str; 61 | (print_pt(out))(pt); 62 | out << std::endl; 63 | } 64 | 65 | template 66 | void operator()(quad_to_t, Point const& pt1, Point const& pt2) 67 | { 68 | out << "quad_to"; 69 | print_pt print(out); 70 | print(pt1), print(pt2); 71 | out << std::endl; 72 | } 73 | 74 | template 75 | void operator()(cubic_to_t, Point const& pt1, Point const& pt2, Point const& pt3) 76 | { 77 | out << "cubic_to"; 78 | print_pt print(out); 79 | print(pt1), print(pt2), print(pt3); 80 | out << std::endl; 81 | } 82 | 83 | void operator()(end_open_t) 84 | { 85 | out << "end_open\n"; 86 | } 87 | 88 | void operator()(end_closed_t) 89 | { 90 | out << "end_closed\n"; 91 | } 92 | }; 93 | } 94 | 95 | #endif -------------------------------------------------------------------------------- /include/niji/sink/multi.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompmultiing 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SINK_MULTI_HPP_INCLUDED 8 | #define NIJI_SINK_MULTI_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji 14 | { 15 | template 16 | struct multi_sink 17 | { 18 | using indices_t = std::make_index_sequence; 19 | 20 | std::tuple sinks; 21 | 22 | multi_sink(Sinks... sinks) 23 | : sinks(std::forward(sinks)...) 24 | {} 25 | 26 | template 27 | void operator()(Tag tag, Points const&... pts) const 28 | { 29 | dispatch(tag, pts..., indices_t{}); 30 | } 31 | 32 | private: 33 | template 34 | void dispatch(Tag tag, Points const&... pts, std::index_sequence) const 35 | { 36 | bool _[] = {(std::get(sinks)(tag, pts...), true)...}; 37 | (void)_; 38 | } 39 | }; 40 | 41 | template 42 | inline multi_sink make_multi_sink(Sinks&&... sinks) 43 | { 44 | return {std::forward(sinks)...}; 45 | } 46 | } 47 | 48 | #endif -------------------------------------------------------------------------------- /include/niji/sink/nanovg.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SINK_NANOVG_HPP_INCLUDED 8 | #define NIJI_SINK_NANOVG_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace niji 16 | { 17 | // This sink does not use winding, suitable for stroke-op. 18 | struct nanovg_sink 19 | { 20 | using point_t = point; 21 | 22 | ::NVGcontext* context; 23 | 24 | explicit nanovg_sink(::NVGcontext* context) 25 | : context(context) 26 | {} 27 | 28 | void operator()(move_to_t, point_t const& pt) 29 | { 30 | ::nvgMoveTo(context, pt.x, pt.y); 31 | } 32 | 33 | void operator()(line_to_t, point_t const& pt) 34 | { 35 | ::nvgLineTo(context, pt.x, pt.y); 36 | } 37 | 38 | void operator()(quad_to_t, point_t const& pt1, point_t const& pt2) 39 | { 40 | ::nvgQuadTo(context, pt1.x, pt1.y, pt2.x, pt2.y); 41 | } 42 | 43 | void operator()(cubic_to_t, point_t const& pt1, point_t const& pt2, point_t const& pt3) 44 | { 45 | ::nvgBezierTo(context, pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y); 46 | } 47 | 48 | void operator()(end_open_t) {} 49 | 50 | void operator()(end_closed_t) 51 | { 52 | ::nvgClosePath(context); 53 | } 54 | }; 55 | 56 | // This sink calculates winding on the fly, suitable for fill-op. 57 | struct nanovg_winding_sink 58 | { 59 | using point_t = point; 60 | 61 | ::NVGcontext* context; 62 | 63 | explicit nanovg_winding_sink(::NVGcontext* context) 64 | : context(context) 65 | {} 66 | 67 | void operator()(move_to_t tag, point_t const& pt) 68 | { 69 | _winding(tag, pt); 70 | ::nvgMoveTo(context, pt.x, pt.y); 71 | } 72 | 73 | void operator()(line_to_t tag, point_t const& pt) 74 | { 75 | _winding(tag, pt); 76 | ::nvgLineTo(context, pt.x, pt.y); 77 | } 78 | 79 | void operator()(quad_to_t tag, point_t const& pt1, point_t const& pt2) 80 | { 81 | _winding(tag, pt1, pt2); 82 | ::nvgQuadTo(context, pt1.x, pt1.y, pt2.x, pt2.y); 83 | } 84 | 85 | void operator()(cubic_to_t tag, point_t const& pt1, point_t const& pt2, point_t const& pt3) 86 | { 87 | _winding(tag, pt1, pt2, pt3); 88 | ::nvgBezierTo(context, pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y); 89 | } 90 | 91 | void operator()(end_open_t tag) { _winding(tag); } 92 | 93 | void operator()(end_closed_t tag) 94 | { 95 | _winding(tag); 96 | ::nvgClosePath(context); 97 | ::nvgPathWinding(context, _winding.is_ccw ? NVG_SOLID : NVG_HOLE); 98 | } 99 | 100 | private: 101 | 102 | winding_sink _winding; 103 | }; 104 | } 105 | 106 | #endif -------------------------------------------------------------------------------- /include/niji/sink/nvpr.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SINK_NVPR_HPP_INCLUDED 8 | #define NIJI_SINK_NVPR_HPP_INCLUDED 9 | 10 | // We don't include any GL binding here so that the user can choose 11 | // which binding he want to use. e.g. 12 | // #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace niji 19 | { 20 | struct nvpr_sink 21 | { 22 | using point_t = point; 23 | 24 | std::vector commands; 25 | std::vector points; 26 | 27 | void operator()(move_to_t, point_t const& pt) 28 | { 29 | commands.push_back(GLubyte(GL_MOVE_TO_NV)); 30 | points.push_back(pt); 31 | } 32 | 33 | void operator()(line_to_t, point_t const& pt) 34 | { 35 | commands.push_back(GLubyte(GL_LINE_TO_NV)); 36 | points.push_back(pt); 37 | } 38 | 39 | void operator()(quad_to_t, point_t const& pt1, point_t const& pt2) 40 | { 41 | commands.push_back(GLubyte(GL_QUADRATIC_CURVE_TO_NV)); 42 | points.push_back(pt1); 43 | points.push_back(pt2); 44 | } 45 | 46 | void operator()(cubic_to_t, point_t const& pt1, point_t const& pt2, point_t const& pt3) 47 | { 48 | commands.push_back(GLubyte(GL_CUBIC_CURVE_TO_NV)); 49 | points.push_back(pt1); 50 | points.push_back(pt2); 51 | points.push_back(pt3); 52 | } 53 | 54 | void operator()(end_open_t) {} 55 | 56 | void operator()(end_closed_t) 57 | { 58 | commands.push_back(GLubyte(GL_CLOSE_PATH_NV)); 59 | } 60 | 61 | void flush(GLuint path) 62 | { 63 | glPathCommandsNV 64 | ( 65 | path, 66 | GLsizei(commands.size()), 67 | commands.data(), 68 | GLsizei(points.size() << 1), 69 | GL_FLOAT, 70 | points.data() 71 | ); 72 | commands.clear(); 73 | points.clear(); 74 | } 75 | }; 76 | } 77 | 78 | #endif -------------------------------------------------------------------------------- /include/niji/sink/qt.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SINK_QT_HPP_INCLUDED 8 | #define NIJI_SINK_QT_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace niji 15 | { 16 | struct qt_sink 17 | { 18 | ::QPainterPath& path; 19 | 20 | explicit qt_sink(::QPainterPath& path) 21 | : path(path) 22 | {} 23 | 24 | template 25 | void operator()(move_to_t, Point const& pt) 26 | { 27 | using boost::geometry::get; 28 | path.moveTo(get<0>(pt), get<1>(pt)); 29 | } 30 | 31 | template 32 | void operator()(line_to_t, Point const& pt) 33 | { 34 | using boost::geometry::get; 35 | path.lineTo(get<0>(pt), get<1>(pt)); 36 | } 37 | 38 | template 39 | void operator()(quad_to_t, Point const& pt1, Point const& pt2) 40 | { 41 | using boost::geometry::get; 42 | path.quadTo(get<0>(pt1), get<1>(pt1), get<0>(pt2), get<1>(pt2)); 43 | } 44 | 45 | template 46 | void operator()(cubic_to_t, Point const& pt1, Point const& pt2, Point const& pt3) 47 | { 48 | using boost::geometry::get; 49 | path.cubicTo(get<0>(pt1), get<1>(pt1), get<0>(pt2), get<1>(pt2), get<0>(pt3), get<1>(pt3)); 50 | } 51 | 52 | void operator()(end_open_t) {} 53 | 54 | void operator()(end_closed_t) 55 | { 56 | path.closeSubpath(); 57 | } 58 | }; 59 | } 60 | 61 | #endif -------------------------------------------------------------------------------- /include/niji/sink/skia.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SINK_SKIA_HPP_INCLUDED 8 | #define NIJI_SINK_SKIA_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace niji 15 | { 16 | struct skia_sink 17 | { 18 | ::SkPath& path; 19 | 20 | explicit skia_sink(::SkPath& path) 21 | : path(path) 22 | {} 23 | 24 | template 25 | void operator()(move_to_t, Point const& pt) 26 | { 27 | using boost::geometry::get; 28 | path.moveTo(get<0>(pt), get<1>(pt)); 29 | } 30 | 31 | template 32 | void operator()(line_to_t, Point const& pt) 33 | { 34 | using boost::geometry::get; 35 | path.lineTo(get<0>(pt), get<1>(pt)); 36 | } 37 | 38 | template 39 | void operator()(quad_to_t, Point const& pt1, Point const& pt2) 40 | { 41 | using boost::geometry::get; 42 | path.quadTo(get<0>(pt1), get<1>(pt1), get<0>(pt2), get<1>(pt2)); 43 | } 44 | 45 | template 46 | void operator()(cubic_to_t, Point const& pt1, Point const& pt2, Point const& pt3) 47 | { 48 | using boost::geometry::get; 49 | path.cubicTo(get<0>(pt1), get<1>(pt1), get<0>(pt2), get<1>(pt2), get<0>(pt3), get<1>(pt3)); 50 | } 51 | 52 | void operator()(end_open_t) {} 53 | 54 | void operator()(end_closed_t) 55 | { 56 | path.close(); 57 | } 58 | }; 59 | } 60 | 61 | #endif -------------------------------------------------------------------------------- /include/niji/sink/svg.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SINK_SVG_HPP_INCLUDED 8 | #define NIJI_SINK_SVG_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace niji 15 | { 16 | template 17 | struct basic_svg_sink 18 | { 19 | Ostream& out; 20 | 21 | explicit basic_svg_sink(Ostream& out) 22 | : out(out) 23 | {} 24 | 25 | template 26 | void operator()(move_to_t, Point const& pt) 27 | { 28 | using boost::geometry::get; 29 | out << 'M' << get<0>(pt) << ',' << get<1>(pt); 30 | } 31 | 32 | template 33 | void operator()(line_to_t, Point const& pt) 34 | { 35 | using boost::geometry::get; 36 | out << 'L' << get<0>(pt) << ',' << get<1>(pt); 37 | } 38 | 39 | template 40 | void operator()(quad_to_t, Point const& pt1, Point const& pt2) 41 | { 42 | using boost::geometry::get; 43 | out << 'Q' << get<0>(pt1) << ',' << get<1>(pt1) 44 | << ' ' << get<0>(pt2) << ',' << get<1>(pt2); 45 | } 46 | 47 | template 48 | void operator()(cubic_to_t, Point const& pt1, Point const& pt2, Point const& pt3) 49 | { 50 | using boost::geometry::get; 51 | out << 'C' << get<0>(pt1) << ',' << get<1>(pt1) 52 | << ' ' << get<0>(pt2) << ',' << get<1>(pt2) 53 | << ' ' << get<0>(pt3) << ',' << get<1>(pt3); 54 | } 55 | 56 | void operator()(end_open_t) {} 57 | 58 | void operator()(end_closed_t) 59 | { 60 | out << 'Z'; 61 | } 62 | }; 63 | 64 | using svg_sink = basic_svg_sink; 65 | } 66 | 67 | #endif -------------------------------------------------------------------------------- /include/niji/support/box.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_BOX_HPP_INCLUDED 8 | #define NIJI_SUPPORT_BOX_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace niji 21 | { 22 | template 23 | struct box 24 | { 25 | using coordinate_type = 26 | typename boost::geometry::traits::coordinate_type::type; 27 | 28 | using point_type = Point; 29 | 30 | using coord_t = coordinate_type; 31 | 32 | Point min_corner, max_corner; 33 | 34 | box() {} 35 | 36 | box(coord_t x1, coord_t y1, coord_t x2, coord_t y2) 37 | : min_corner(boost::geometry::make(x1, y1)) 38 | , max_corner(boost::geometry::make(x2, y2)) 39 | {} 40 | 41 | box(Point const& min_corner, Point const& max_corner) 42 | : min_corner(min_corner) 43 | , max_corner(max_corner) 44 | {} 45 | 46 | template 47 | box(box const& other) 48 | : min_corner(convert_geometry(other.min_corner)) 49 | , max_corner(convert_geometry(other.max_corner)) 50 | {} 51 | 52 | template::value, bool> = true> 53 | box(Box const& other) 54 | { 55 | boost::geometry::convert(other, *this); 56 | } 57 | 58 | void reset(coord_t x1, coord_t y1, coord_t x2, coord_t y2) 59 | { 60 | min_corner = boost::geometry::make(x1, y1); 61 | max_corner = boost::geometry::make(x2, y2); 62 | } 63 | 64 | void reset(Point const& min, Point const& max) 65 | { 66 | min_corner = min; 67 | max_corner = max; 68 | } 69 | 70 | template 71 | void reset(Pt const& min, Pt const& max) 72 | { 73 | min_corner = convert_geometry(min); 74 | max_corner = convert_geometry(max); 75 | } 76 | 77 | coordinate_type width() const 78 | { 79 | return length<0>(); 80 | } 81 | 82 | coordinate_type height() const 83 | { 84 | return length<1>(); 85 | } 86 | 87 | template 88 | coordinate_type length() const 89 | { 90 | using boost::geometry::get; 91 | 92 | return get(max_corner) - get(min_corner); 93 | } 94 | 95 | bool empty() const 96 | { 97 | using boost::geometry::get; 98 | 99 | return get<0>(max_corner) == get<0>(min_corner) || 100 | get<1>(max_corner) == get<1>(min_corner); 101 | } 102 | 103 | bool invalid() 104 | { 105 | using boost::geometry::get; 106 | 107 | return get<0>(min_corner) > get<0>(max_corner) || 108 | get<1>(min_corner) > get<1>(max_corner); 109 | } 110 | 111 | void clear() 112 | { 113 | max_corner = Point(); 114 | min_corner = Point(); 115 | } 116 | 117 | void translate(vector const& v) 118 | { 119 | translate(v.x, v.y); 120 | } 121 | 122 | void translate(coord_t x, coord_t y) 123 | { 124 | using boost::geometry::get; 125 | using boost::geometry::set; 126 | 127 | set<0>(min_corner, get<0>(min_corner) + x); 128 | set<1>(min_corner, get<1>(min_corner) + y); 129 | set<0>(max_corner, get<0>(max_corner) + x); 130 | set<1>(max_corner, get<1>(max_corner) + y); 131 | } 132 | 133 | void correct() 134 | { 135 | using boost::geometry::get; 136 | using boost::geometry::set; 137 | 138 | if (get<0>(max_corner) < get<0>(min_corner)) 139 | { 140 | coordinate_type tmp(get<0>(min_corner)); 141 | set<0>(min_corner, get<0>(max_corner)); 142 | set<0>(max_corner, tmp); 143 | } 144 | if (get<1>(max_corner) < get<1>(min_corner)) 145 | { 146 | coordinate_type tmp(get<1>(min_corner)); 147 | set<1>(min_corner, get<1>(max_corner)); 148 | set<1>(max_corner, tmp); 149 | } 150 | } 151 | 152 | template 153 | box transformed(F&& f) const 154 | { 155 | box ret(f(min_corner), f(max_corner)); 156 | ret.correct(); 157 | return ret; 158 | } 159 | 160 | void offset(vector const& v) 161 | { 162 | offset(v.x, v.y); 163 | } 164 | 165 | void offset(coord_t x, coord_t y) 166 | { 167 | using boost::geometry::get; 168 | using boost::geometry::set; 169 | 170 | set<0>(min_corner, get<0>(min_corner) - x); 171 | set<1>(min_corner, get<1>(min_corner) - y); 172 | set<0>(max_corner, get<0>(max_corner) + x); 173 | set<1>(max_corner, get<1>(max_corner) + y); 174 | } 175 | 176 | void expand(box const& other) 177 | { 178 | using boost::geometry::get; 179 | 180 | expand_coord<0>(get<0>(other.min_corner), get<0>(other.max_corner)); 181 | expand_coord<1>(get<1>(other.min_corner), get<1>(other.max_corner)); 182 | } 183 | 184 | template 185 | void expand_coord(coord_t min, coord_t max) 186 | { 187 | using boost::geometry::get; 188 | using boost::geometry::set; 189 | 190 | auto min_ = get(min_corner); 191 | auto max_ = get(max_corner); 192 | if (min_ == max_) 193 | { 194 | set(min_corner, min); 195 | set(max_corner, max); 196 | return; 197 | } 198 | if (min < min_) 199 | set(min_corner, min); 200 | if (max > max_) 201 | set(max_corner, max); 202 | } 203 | 204 | bool clip(box const& other) 205 | { 206 | using boost::geometry::get; 207 | 208 | return 209 | clip_coord<0>(get<0>(other.min_corner), get<0>(other.max_corner)) 210 | && clip_coord<1>(get<1>(other.min_corner), get<1>(other.max_corner)); 211 | } 212 | 213 | template 214 | bool clip_coord(coord_t min, coord_t max) 215 | { 216 | using boost::geometry::get; 217 | using boost::geometry::set; 218 | 219 | auto min_ = get(min_corner); 220 | auto max_ = get(max_corner); 221 | if (min_ >= max) 222 | { 223 | set(max_corner, min_); 224 | return false; 225 | } 226 | if (max_ <= min) 227 | { 228 | set(min_corner, max_); 229 | return false; 230 | } 231 | if (min_ < min) 232 | set(min_corner, min); 233 | if (max < max_) 234 | set(max_corner, max); 235 | return true; 236 | } 237 | 238 | template 239 | Point const& corner() const 240 | { 241 | return *(&min_corner + N); 242 | } 243 | 244 | template 245 | Point& corner() 246 | { 247 | return *(&min_corner + N); 248 | } 249 | 250 | Point center() const 251 | { 252 | using boost::geometry::get; 253 | using boost::geometry::set; 254 | 255 | Point pt; 256 | set<0>(pt, (get<0>(min_corner) + get<0>(max_corner)) / 2); 257 | set<1>(pt, (get<1>(min_corner) + get<1>(max_corner)) / 2); 258 | return pt; 259 | } 260 | 261 | template 262 | void serialize(Archive& ar, unsigned version) 263 | { 264 | ar & min_corner & max_corner; 265 | } 266 | }; 267 | } 268 | 269 | namespace boost { namespace geometry { namespace traits 270 | { 271 | template 272 | struct tag> 273 | { 274 | using type = box_tag; 275 | }; 276 | 277 | template 278 | struct point_type> 279 | { 280 | using type = Point; 281 | }; 282 | 283 | template 284 | struct indexed_access, Index, Dimension> 285 | { 286 | using coordinate_type = typename boost::geometry::coordinate_type::type; 287 | 288 | static inline coordinate_type get(niji::box const& b) 289 | { 290 | return boost::geometry::get(b.template corner()); 291 | } 292 | 293 | static inline void set(niji::box& b, coordinate_type value) 294 | { 295 | boost::geometry::set(b.template corner(), value); 296 | } 297 | }; 298 | }}} 299 | 300 | #endif 301 | -------------------------------------------------------------------------------- /include/niji/support/command.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_COMMAND_HPP_INCLUDED 8 | #define NIJI_SUPPORT_COMMAND_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace niji 15 | { 16 | // the order is intentional 17 | enum end_tag : char 18 | { 19 | closed, 20 | open, 21 | poly NIJI_DEPRECATE_BY(closed) = closed, 22 | line NIJI_DEPRECATE_BY(open) = open 23 | }; 24 | 25 | template 26 | using end_tag_t = std::integral_constant; 27 | 28 | using end_closed_t = end_tag_t; 29 | using end_open_t = end_tag_t; 30 | 31 | using end_poly_t NIJI_DEPRECATE_BY(end_closed_t) = end_closed_t; 32 | using end_line_t NIJI_DEPRECATE_BY(end_open_t) = end_open_t; 33 | 34 | struct move_to_t {}; 35 | struct line_to_t {}; 36 | struct curve_to_t {}; 37 | 38 | template 39 | struct nth_curve_to_t : curve_to_t {}; 40 | 41 | using quad_to_t = nth_curve_to_t<2>; 42 | using cubic_to_t = nth_curve_to_t<3>; 43 | } 44 | 45 | namespace niji { namespace command 46 | { 47 | NIJI_IDENTIFIER(end_closed_t, end_closed); 48 | NIJI_IDENTIFIER(end_open_t, end_open); 49 | NIJI_IDENTIFIER(end_closed_t, end_poly NIJI_DEPRECATE_BY(end_closed)); 50 | NIJI_IDENTIFIER(end_open_t, end_line NIJI_DEPRECATE_BY(end_open)); 51 | NIJI_IDENTIFIER(move_to_t, move_to); 52 | NIJI_IDENTIFIER(line_to_t, line_to); 53 | NIJI_IDENTIFIER(quad_to_t, quad_to); 54 | NIJI_IDENTIFIER(cubic_to_t, cubic_to); 55 | }} 56 | 57 | #endif -------------------------------------------------------------------------------- /include/niji/support/common_point.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_COMMON_POINT_HPP_INCLUDED 8 | #define NIJI_SUPPORT_COMMON_POINT_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji { namespace detail 14 | { 15 | template 16 | struct is_all_same 17 | { 18 | template 19 | struct src 20 | { 21 | using type = T; 22 | }; 23 | 24 | static constexpr bool value = std::is_same< 25 | is_all_same, is_all_same::type...>>::value; 26 | }; 27 | 28 | template 29 | struct common_point_impl; 30 | 31 | template 32 | struct common_point_impl 33 | { 34 | using type = T; 35 | }; 36 | 37 | template 38 | struct common_point_impl 39 | { 40 | using type = 41 | point::type...>>; 43 | }; 44 | }} 45 | 46 | namespace niji 47 | { 48 | template 49 | struct common_point 50 | : detail::common_point_impl::value, Ts...> 51 | {}; 52 | 53 | template 54 | using common_point_t = typename common_point::type; 55 | } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /include/niji/support/constants.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2018 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_CONSTANTS_HPP_INCLUDED 8 | #define NIJI_SUPPORT_CONSTANTS_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace boost { namespace math { namespace constants 15 | { 16 | BOOST_DEFINE_MATH_CONSTANT(tan_pi_over_8, 4.142135623730950488016887242096980786e-01, "4.14213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641572735013846231e-01") 17 | BOOST_DEFINE_MATH_CONSTANT(root2_over_2, 7.071067811865475244008443621048490393e-01, "7.07106781186547524400844362104849039284835937688474036588339868995366239231053519425193767163820786367506923115e-01") 18 | BOOST_DEFINE_MATH_CONSTANT(cubic_arc_factor, 5.522847498307933984022516322795974381e-01, "5.52284749830793398402251632279597438092895833835930764235572983987643304616142718467183379103522096980018461641e-01") 19 | }}} 20 | 21 | namespace boost { namespace math { namespace constants { namespace detail 22 | { 23 | template 24 | struct sel_impl; 25 | 26 | template 27 | struct sel_impl 28 | { 29 | static BOOST_CONSTEXPR T apply(float const f, double const, long double const, const char*) 30 | { 31 | return f; 32 | } 33 | }; 34 | 35 | template 36 | struct sel_impl 37 | { 38 | static BOOST_CONSTEXPR T apply(float const, double const d, long double const, const char*) 39 | { 40 | return d; 41 | } 42 | }; 43 | 44 | template 45 | struct sel_impl 46 | { 47 | static BOOST_CONSTEXPR T apply(float const, double const, long double const ld, const char*) 48 | { 49 | return ld; 50 | } 51 | }; 52 | 53 | template 54 | struct sel_impl 55 | { 56 | static T apply(float const, double const, long double const, const char* p) 57 | { 58 | return boost::math::tools::convert_from_string(p); 59 | } 60 | }; 61 | 62 | template > 63 | struct sel 64 | : sel_impl::type::value> 65 | {}; 66 | }}}} 67 | 68 | #define NIJI_CONSTANT(T, val) ::boost::math::constants::detail::sel::apply(BOOST_JOIN(val, F), val, BOOST_JOIN(val, L), #val) 69 | #define NIJI_CONSTANTS_(_, T, i, val) BOOST_PP_COMMA_IF(i) NIJI_CONSTANT(T, val) 70 | #define NIJI_CONSTANTS(T, seq) BOOST_PP_SEQ_FOR_EACH_I(NIJI_CONSTANTS_, T, seq) 71 | 72 | namespace niji { namespace constants 73 | { 74 | using namespace ::boost::math::constants; 75 | }} 76 | 77 | #endif -------------------------------------------------------------------------------- /include/niji/support/convert_geometry.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_CONVERT_GEOMETRY_HPP_INCLUDED 8 | #define NIJI_SUPPORT_CONVERT_GEOMETRY_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji 14 | { 15 | template 16 | inline T const& convert_geometry(T const& src) 17 | { 18 | return src; 19 | } 20 | 21 | template 22 | inline typename std::enable_if::value, T>::type 23 | convert_geometry(U const& src) 24 | { 25 | T dst; 26 | boost::geometry::convert(src, dst); 27 | return dst; 28 | } 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/niji/support/deprecate.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_DEPRECATE_HPP_INCLUDED 8 | #define NIJI_SUPPORT_DEPRECATE_HPP_INCLUDED 9 | 10 | #define NIJI_DEPRECATE_BY(alter) [[deprecated("used '"#alter"' instead")]] 11 | 12 | #endif -------------------------------------------------------------------------------- /include/niji/support/identifier.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_IDENTIFIER_HPP_INCLUDED 8 | #define NIJI_SUPPORT_IDENTIFIER_HPP_INCLUDED 9 | 10 | #define NIJI_IDENTIFIER(type, var) constexpr type var 11 | 12 | #endif -------------------------------------------------------------------------------- /include/niji/support/is_narrowing.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2019 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_IS_NARROWING_HPP_INCLUDED 8 | #define NIJI_SUPPORT_IS_NARROWING_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji::detail 14 | { 15 | template 16 | auto is_narrowing_aux(int) -> enable_if_valid_t()}), std::false_type>; 17 | 18 | template 19 | std::true_type is_narrowing_aux(...); 20 | } 21 | 22 | namespace niji 23 | { 24 | template 25 | struct is_narrowing : std::bool_constant< 26 | std::is_scalar_v&& 27 | std::is_scalar_v&& 28 | decltype(detail::is_narrowing_aux(0))::value 29 | > {}; 30 | 31 | template 32 | struct is_narrowing : std::false_type {}; 33 | 34 | template 35 | constexpr bool is_narrowing_v = is_narrowing::value; 36 | } 37 | 38 | #endif -------------------------------------------------------------------------------- /include/niji/support/just.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_JUST_HPP_INCLUDED 8 | #define NIJI_SUPPORT_JUST_HPP_INCLUDED 9 | 10 | namespace niji 11 | { 12 | template 13 | struct just 14 | { 15 | using type = T; 16 | }; 17 | 18 | template 19 | using just_t = typename just::type; 20 | } 21 | 22 | #endif -------------------------------------------------------------------------------- /include/niji/support/numeric.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2018 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_NUMERIC_HPP_INCLUDED 8 | #define NIJI_SUPPORT_NUMERIC_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace niji { namespace numeric 15 | { 16 | struct one 17 | { 18 | template 19 | T&& operator*(T&& t) const 20 | { 21 | return std::forward(t); 22 | } 23 | }; 24 | 25 | struct zero 26 | { 27 | template 28 | T&& operator+(T&& t) const 29 | { 30 | return std::forward(t); 31 | } 32 | }; 33 | 34 | template 35 | inline T square_sum(T a, T b) 36 | { 37 | return a * a + b * b; 38 | } 39 | 40 | template::value, bool> = true> 41 | inline bool is_nearly_zero(T val) 42 | { 43 | static constexpr T nearly_zero = T(1) / (1 << 12); 44 | return val <= nearly_zero; 45 | } 46 | 47 | template 48 | inline int get_sign(T x) 49 | { 50 | return x < 0 ? -1 : (x > 0); 51 | } 52 | 53 | template 54 | inline bool between(T a, T b, T c) 55 | { 56 | assert(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0) 57 | || (is_nearly_zero(a) && is_nearly_zero(b) && is_nearly_zero(c))); 58 | return (a - b) * (c - b) <= 0; 59 | } 60 | 61 | template 62 | inline bool is_not_monotonic(T a, T b, T c) 63 | { 64 | T ab = a - b; 65 | T bc = b - c; 66 | if (ab < 0) 67 | bc = -bc; 68 | return ab == 0 || bc < 0; 69 | } 70 | 71 | template 72 | int valid_unit_divide(T numer, T denom, T& ratio) 73 | { 74 | using std::isnan; 75 | 76 | if (numer < 0) 77 | { 78 | numer = -numer; 79 | denom = -denom; 80 | } 81 | 82 | if (denom == 0 || numer == 0 || numer >= denom) 83 | return 0; 84 | 85 | T r = numer / denom; 86 | if (isnan(r)) 87 | return 0; 88 | 89 | assert(r >= 0 && r < 1); 90 | if (r == 0) // catch underflow if numer <<<< denom 91 | return 0; 92 | ratio = r; 93 | return 1; 94 | } 95 | 96 | template 97 | inline T interpolate(T a, T b, T t) 98 | { 99 | return a + (b - a) * t; 100 | } 101 | }} 102 | 103 | #endif -------------------------------------------------------------------------------- /include/niji/support/point.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2019 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_POINT_HPP_INCLUDED 8 | #define NIJI_SUPPORT_POINT_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace niji 21 | { 22 | template 23 | struct point 24 | { 25 | using coordinate_type = T; 26 | 27 | T x, y; 28 | 29 | point() : x(), y() {} 30 | 31 | point(T x, T y) : x(x), y(y) {} 32 | 33 | template && !is_narrowing_v, bool> = true> 34 | point(point const& other) : x(other.x), y(other.y) {} 35 | 36 | template, bool> = true> 37 | explicit point(point const& other) : x(static_cast(other.x)), y(static_cast(other.y)) {} 38 | 39 | #if 0 40 | template::value, bool> = true> 41 | point(Point const& other) 42 | : x(boost::geometry::get<0>(other)), y(boost::geometry::get<1>(other)) 43 | {} 44 | #endif 45 | 46 | void reset(T x2, T y2) 47 | { 48 | x = std::move(x2); 49 | y = std::move(y2); 50 | } 51 | 52 | template 53 | T const& coord() const 54 | { 55 | return *(&x + N); 56 | } 57 | 58 | template 59 | T& coord() 60 | { 61 | return *(&x + N); 62 | } 63 | 64 | template 65 | bool operator==(point const& other) const 66 | { 67 | return x == other.x && y == other.y; 68 | } 69 | 70 | template 71 | bool operator!=(point const& other) const 72 | { 73 | return !operator==(other); 74 | } 75 | 76 | point operator-() const 77 | { 78 | return point(-x, -y); 79 | } 80 | 81 | template 82 | point& operator+=(point const& other) 83 | { 84 | x += other.x; 85 | y += other.y; 86 | return *this; 87 | } 88 | 89 | template 90 | point& operator-=(point const& other) 91 | { 92 | x -= other.x; 93 | y -= other.y; 94 | return *this; 95 | } 96 | 97 | template::value, bool> = true> 98 | point& operator*=(U const& val) 99 | { 100 | x *= val; 101 | y *= val; 102 | return *this; 103 | } 104 | 105 | template 106 | point& operator*=(point const& other) 107 | { 108 | x *= other.x; 109 | y *= other.y; 110 | return *this; 111 | } 112 | 113 | template::value, bool> = true> 114 | point& operator/=(U const& val) 115 | { 116 | x /= val; 117 | y /= val; 118 | return *this; 119 | } 120 | 121 | template 122 | point& operator/=(point const& other) 123 | { 124 | x /= other.x; 125 | y /= other.y; 126 | return *this; 127 | } 128 | 129 | template 130 | void serialize(Archive& ar, unsigned version) 131 | { 132 | ar & x & y; 133 | } 134 | }; 135 | 136 | #define NIJI_DEFINE_POINT_OEPRATOR(op) \ 137 | template::value, bool> = true>\ 138 | inline point> operator op(point const& pt, U const& val)\ 139 | { \ 140 | return point>(pt.x op val, pt.y op val); \ 141 | } \ 142 | template::value, bool> = true>\ 143 | inline point> operator op(U const& val, point const& pt)\ 144 | { \ 145 | return point>(val op pt.x, val op pt.y); \ 146 | } \ 147 | template \ 148 | inline point> operator op(point const& lhs, point const& rhs)\ 149 | { \ 150 | return point>(lhs.x op rhs.x, lhs.y op rhs.y); \ 151 | } \ 152 | /***/ 153 | NIJI_DEFINE_POINT_OEPRATOR(+) 154 | NIJI_DEFINE_POINT_OEPRATOR(-) 155 | NIJI_DEFINE_POINT_OEPRATOR(*) 156 | NIJI_DEFINE_POINT_OEPRATOR(/) 157 | #undef NIJI_DEFINE_POINT_OEPRATOR 158 | 159 | using ipoint = point; 160 | using fpoint = point; 161 | using dpoint = point; 162 | } 163 | 164 | namespace niji::points 165 | { 166 | template 167 | inline point transform(point const& a, point const& b, F&& f) 168 | { 169 | return {f(a.x, b.x), f(a.y, b.y)}; 170 | } 171 | 172 | template 173 | inline point middle(point const& a, point const& b) 174 | { 175 | return transform(a, b, [](T a, T b) { return (a + b) / 2; }); 176 | } 177 | 178 | template 179 | inline point interpolate(point const& a, point const& b, T t) 180 | { 181 | return transform(a, b, [t](T a, T b) { return a + (b - a) * t; }); 182 | } 183 | } 184 | 185 | namespace boost::geometry::traits 186 | { 187 | template 188 | struct tag> 189 | { 190 | using type = point_tag; 191 | }; 192 | 193 | template 194 | struct coordinate_type> 195 | { 196 | using type = T; 197 | }; 198 | 199 | template 200 | struct coordinate_system> 201 | { 202 | using type = cs::cartesian; 203 | }; 204 | 205 | template 206 | struct dimension> 207 | : boost::mpl::int_<2> 208 | {}; 209 | 210 | template 211 | struct access, Dimension> 212 | { 213 | using point_type = niji::point; 214 | 215 | static inline T get(point_type const& p) 216 | { 217 | return p.template coord(); 218 | } 219 | 220 | static inline void set(point_type& p, T value) 221 | { 222 | p.template coord() = value; 223 | } 224 | }; 225 | } 226 | 227 | #endif -------------------------------------------------------------------------------- /include/niji/support/traits.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2019 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_TRAITS_HPP_INCLUDED 8 | #define NIJI_SUPPORT_TRAITS_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace niji 18 | { 19 | template 20 | using geometry_tag_t = typename boost::geometry::traits::tag::type; 21 | 22 | template 23 | struct is_geometry 24 | : std::bool_constant, void>::value> 25 | {}; 26 | 27 | template 28 | struct is_point 29 | : std::is_same, boost::geometry::point_tag> 30 | {}; 31 | 32 | template 33 | struct is_box 34 | : std::is_same, boost::geometry::box_tag> 35 | {}; 36 | 37 | template 38 | struct path_point 39 | { 40 | using type = typename Path::point_type; 41 | }; 42 | 43 | template 44 | struct path_point::value>> 45 | : boost::geometry::point_type 46 | {}; 47 | 48 | template 49 | using path_point_t = typename path_point::type; 50 | 51 | template 52 | struct path_coordinate 53 | { 54 | using type = typename 55 | boost::geometry::coordinate_type>::type; 56 | }; 57 | 58 | template 59 | using path_coordinate_t = typename path_coordinate::type; 60 | } 61 | 62 | #endif -------------------------------------------------------------------------------- /include/niji/support/transform/rotate.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_TRANSFORM_ROTATE_HPP_INCLUDED 8 | #define NIJI_SUPPORT_TRANSFORM_ROTATE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji { namespace transforms 14 | { 15 | template 16 | struct rotate 17 | { 18 | T sin, cos; 19 | 20 | explicit rotate(T radian) 21 | { 22 | reset(radian); 23 | } 24 | 25 | rotate(T sin, T cos) 26 | : sin(sin), cos(cos) 27 | {} 28 | 29 | void reset(T radian) 30 | { 31 | [](T radian, rotate& self) 32 | { 33 | using std::sin; 34 | using std::cos; 35 | 36 | self.sin = sin(radian); 37 | self.cos = cos(radian); 38 | }(radian, *this); 39 | } 40 | 41 | void reset(T sa2, T ca2) 42 | { 43 | sin = sa2; 44 | cos = ca2; 45 | } 46 | 47 | template 48 | point operator()(Point const& pt) const 49 | { 50 | using boost::geometry::get; 51 | auto x = get<0>(pt), y = get<1>(pt); 52 | return {x * cos - y * sin, x * sin + y * cos}; 53 | } 54 | }; 55 | }} 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /include/niji/support/transform/scale.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_TRANSFORM_SCALE_HPP_INCLUDED 8 | #define NIJI_SUPPORT_TRANSFORM_SCALE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji { namespace transforms 14 | { 15 | template 16 | struct scale 17 | { 18 | T x, y; 19 | 20 | explicit scale(T scale) 21 | : x(scale), y(scale) 22 | {} 23 | 24 | scale(T x, T y) 25 | : x(x), y(y) 26 | {} 27 | 28 | void reset(T scale) 29 | { 30 | x = y = scale; 31 | } 32 | 33 | void reset(T x2, T y2) 34 | { 35 | x = x2; 36 | y = y2; 37 | } 38 | 39 | template 40 | point operator()(Point const& pt) const 41 | { 42 | using boost::geometry::get; 43 | return {get<0>(pt) * x, get<1>(pt) * y}; 44 | } 45 | }; 46 | }} 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /include/niji/support/transform/skew.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_TRANSFORM_SKEW_HPP_INCLUDED 8 | #define NIJI_SUPPORT_TRANSFORM_SKEW_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji { namespace transforms 14 | { 15 | template 16 | struct skew 17 | { 18 | T x, y; 19 | 20 | skew(T x, T y) 21 | : x(x), y(y) 22 | {} 23 | 24 | void reset(T x2, T y2) 25 | { 26 | x = x2; 27 | y = y2; 28 | } 29 | 30 | template 31 | point operator()(Point const& pt) const 32 | { 33 | using boost::geometry::get; 34 | auto x2 = get<0>(pt), y2 = get<1>(pt); 35 | return {x2 + x * y2, y2 + y * x2}; 36 | } 37 | }; 38 | }} 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /include/niji/support/transform/translate.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.xt or copy at http://www.boost.org/LICENSE_1_0.xt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_TRANSFORM_TRANSLATE_HPP_INCLUDED 8 | #define NIJI_SUPPORT_TRANSFORM_TRANSLATE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji { namespace transforms 14 | { 15 | template 16 | struct translate 17 | { 18 | T x, y; 19 | 20 | translate(T x, T y) 21 | : x(x), y(y) 22 | {} 23 | 24 | explicit translate(point const& v) 25 | : x(v.x), y(v.y) 26 | {} 27 | 28 | void reset(T x2, T y2) 29 | { 30 | x = x2; 31 | y = y2; 32 | } 33 | 34 | template 35 | point operator()(Point const& pt) const 36 | { 37 | using boost::geometry::get; 38 | return {get<0>(pt) + x, get<1>(pt) + y}; 39 | } 40 | }; 41 | }} 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/niji/support/transform/transpose.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.xt or copy at http://www.boost.org/LICENSE_1_0.xt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_TRANSFORM_TRANSPOSE_HPP_INCLUDED 8 | #define NIJI_SUPPORT_TRANSFORM_TRANSPOSE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace niji { namespace transforms 15 | { 16 | struct transpose 17 | { 18 | template 19 | Point operator()(Point const& pt) const 20 | { 21 | using boost::geometry::get; 22 | return boost::geometry::make(get<1>(pt), get<0>(pt)); 23 | } 24 | }; 25 | }} 26 | 27 | #endif -------------------------------------------------------------------------------- /include/niji/support/vector.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2019 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_VECTOR_HPP_INCLUDED 8 | #define NIJI_SUPPORT_VECTOR_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace niji 16 | { 17 | template 18 | using vector = point; 19 | using ivector = vector; 20 | using fvector = vector; 21 | using dvector = vector; 22 | } 23 | 24 | namespace niji::vectors 25 | { 26 | template 27 | inline T norm_square(vector const& v) 28 | { 29 | return numeric::square_sum(v.x, v.y); 30 | } 31 | 32 | template 33 | inline T norm(vector const& v) 34 | { 35 | using std::sqrt; 36 | return sqrt(norm_square(v)); 37 | } 38 | 39 | template 40 | inline vector normal_cw(vector const& v) 41 | { 42 | return vector(v.y, -v.x); 43 | } 44 | 45 | template 46 | inline vector normal_ccw(vector const& v) 47 | { 48 | return vector(-v.y, v.x); 49 | } 50 | 51 | template 52 | inline vector unit(vector const& v) 53 | { 54 | return v / norm(v); 55 | } 56 | 57 | template 58 | inline typename std::common_type::type 59 | dot(vector const& a, vector const& b) 60 | { 61 | return a.x * b.x + a.y * b.y; 62 | } 63 | 64 | template 65 | inline typename std::common_type::type 66 | cross(vector const& a, vector const& b) 67 | { 68 | return a.x * b.y - a.y * b.x; 69 | } 70 | 71 | template 72 | inline bool is_ccw(vector const& from, vector const& to) 73 | { 74 | return from.x * to.y > from.y * to.x; 75 | } 76 | } 77 | 78 | namespace niji::vectors::traits 79 | { 80 | // 81 | // Default Implemetation 82 | // 83 | template 84 | struct is_degenerated; 85 | 86 | template 87 | struct is_degenerated::value>> 88 | { 89 | static bool apply(vector const& v) 90 | { 91 | static constexpr T nearly_zero(T(1) / (1 << 12)); 92 | return norm(v) <= nearly_zero; 93 | } 94 | }; 95 | 96 | template 97 | struct too_curvy; 98 | 99 | template 100 | struct too_curvy::value>> 101 | { 102 | static bool apply(vector const& v1, vector const& v2) 103 | { 104 | using std::sqrt; 105 | static T const limit((constants::root_two() * 5 + 1) / 10); 106 | return dot(v1, v2) <= limit * sqrt(norm_square(v1) * norm_square(v2)); 107 | } 108 | }; 109 | 110 | template 111 | struct too_pinchy; 112 | 113 | template 114 | struct too_pinchy::value>> 115 | { 116 | static bool apply(vector const& v1, vector const& v2) 117 | { 118 | using std::sqrt; 119 | static T const limit(std::numeric_limits::epsilon() * 256 - 1); 120 | return dot(v1, v2) <= limit * sqrt(norm_square(v1) * norm_square(v2)); 121 | } 122 | }; 123 | } 124 | 125 | namespace niji::vectors 126 | { 127 | template 128 | inline bool is_degenerated(vector const& v) 129 | { 130 | return traits::is_degenerated::apply(v); 131 | } 132 | 133 | template 134 | inline bool too_curvy(vector const& v1, vector const& v2) 135 | { 136 | return traits::too_curvy::apply(v1, v2); 137 | } 138 | 139 | template 140 | inline bool too_pinchy(vector const& v1, vector const& v2) 141 | { 142 | return traits::too_pinchy::apply(v1, v2); 143 | } 144 | } 145 | 146 | #endif -------------------------------------------------------------------------------- /include/niji/support/view.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_SUPPORT_VIEW_HPP_INCLUDED 8 | #define NIJI_SUPPORT_VIEW_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji 14 | { 15 | template 16 | struct path_adaptor 17 | { 18 | using point_type = typename std::decay_t:: 19 | template point_type>; 20 | 21 | Path path; 22 | View view; 23 | 24 | template 25 | void render(Sink& sink) const 26 | { 27 | view.render(path, sink); 28 | } 29 | 30 | template 31 | auto inverse_render(Sink& sink) const -> decltype(view.inverse_render(path, sink)) 32 | { 33 | return view.inverse_render(path, sink); 34 | } 35 | }; 36 | 37 | template 38 | struct view 39 | { 40 | template 41 | using point_type = typename path_point::type; 42 | }; 43 | 44 | template 45 | struct chained_view : view> 46 | { 47 | LHS lhs; 48 | RHS rhs; 49 | 50 | chained_view(LHS&& lhs, RHS&& rhs) 51 | : lhs(std::forward(lhs)), rhs(std::forward(rhs)) 52 | {} 53 | 54 | template 55 | void render(Path const& path, Sink& sink) const 56 | { 57 | niji::render(path | lhs | rhs, sink); 58 | } 59 | 60 | template 61 | void inverse_render(Path const& path, Sink& sink) const 62 | { 63 | niji::inverse_render(path | lhs | rhs, sink); 64 | } 65 | }; 66 | 67 | namespace detail 68 | { 69 | template 70 | std::true_type is_view_test(view const&); 71 | 72 | std::false_type is_view_test(...); 73 | } 74 | 75 | template 76 | struct is_view 77 | : decltype(detail::is_view_test(std::declval())) 78 | {}; 79 | 80 | template 81 | inline path_adaptor 82 | operator|(Path&& path, view&& d) 83 | { 84 | return {std::forward(path), static_cast(d)}; 85 | } 86 | 87 | template 88 | inline path_adaptor 89 | operator|(Path&& path, view const& d) 90 | { 91 | return {std::forward(path), static_cast(d)}; 92 | } 93 | } 94 | 95 | #endif -------------------------------------------------------------------------------- /include/niji/view/affine.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_AFFINE_HPP_INCLUDED 8 | #define NIJI_VIEW_AFFINE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji { namespace views 14 | { 15 | template 16 | using affine = transform_view>; 17 | }} 18 | 19 | #endif -------------------------------------------------------------------------------- /include/niji/view/dash.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2019 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_DASH_HPP_INCLUDED 8 | #define NIJI_VIEW_DASH_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace niji 19 | { 20 | template 21 | struct dash_view : view> 22 | { 23 | template 24 | using point_type = point; 25 | 26 | Pattern pattern; 27 | T offset; 28 | U weight; 29 | 30 | template 31 | struct adaptor 32 | { 33 | void operator()(move_to_t, point const& pt) 34 | { 35 | _dasher.move_to(pt); 36 | } 37 | 38 | void operator()(line_to_t, point const& pt) 39 | { 40 | _dasher.line_to(pt, _sink); 41 | } 42 | 43 | void operator()(quad_to_t, point const& pt1, point const& pt2) 44 | { 45 | _dasher.quad_to(pt1, pt2, _sink); 46 | } 47 | 48 | void operator()(cubic_to_t, point const& pt1, point const& pt2, point const& pt3) 49 | { 50 | _dasher.cubic_to(pt1, pt2, pt3, _sink); 51 | } 52 | 53 | void operator()(end_closed_t) 54 | { 55 | _dasher.close(_sink); 56 | } 57 | 58 | void operator()(end_open_t) 59 | { 60 | _dasher.cut(_sink); 61 | } 62 | 63 | using iterator_t = typename 64 | boost::range_iterator const>::type; 65 | 66 | Sink& _sink; 67 | detail::dasher _dasher; 68 | }; 69 | 70 | dash_view() = default; 71 | 72 | explicit dash_view(Pattern pattern, T offset = {}, U weight = {}) 73 | : pattern(std::forward(pattern)) 74 | , offset(offset), weight(weight) 75 | {} 76 | 77 | template 78 | void render(Path const& path, Sink& sink) const 79 | { 80 | auto i = std::begin(pattern), e = std::end(pattern); 81 | if (i != e) 82 | niji::render(path, adaptor{sink, {i, e, offset, weight}}); 83 | } 84 | 85 | template 86 | void inverse_render(Path const& path, Sink& sink) const 87 | { 88 | render(path, sink); 89 | } 90 | }; 91 | } 92 | 93 | namespace niji { namespace views 94 | { 95 | template const&, class U = numeric::one> 96 | inline auto dash(Pattern&& p, just_t offset = {}, U weight = {}) 97 | { 98 | return dash_view{std::forward(p), offset, weight}; 99 | } 100 | }} 101 | 102 | #endif -------------------------------------------------------------------------------- /include/niji/view/detail/dash.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_DETAIL_DASH_HPP_INCLUDED 8 | #define NIJI_VIEW_DETAIL_DASH_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace niji { namespace detail 20 | { 21 | template 22 | struct dasher 23 | { 24 | using point_t = point; 25 | using vector_t = vector; 26 | 27 | dasher(Iterator const& begin, Iterator const& end, T offset, U weight) 28 | : _begin(begin), _end(end), _it(begin) 29 | , _offset(), _weight(weight), _skip(), _gap() 30 | { 31 | using std::fmod; 32 | 33 | BOOST_ASSERT(begin != end); 34 | 35 | if (offset > 0) 36 | { 37 | for (T sum = 0; ; ) 38 | { 39 | sum += _weight * (*_it); 40 | if (sum >= offset) 41 | { 42 | _offset = sum - offset; 43 | if (++_it == end) 44 | _it = begin; 45 | else 46 | _skip = !_gap; 47 | break; 48 | } 49 | if (++_it == end) 50 | { 51 | _it = begin; 52 | _gap = false; 53 | offset = fmod(offset, sum); 54 | sum = 0; 55 | continue; 56 | } 57 | _gap = !_gap; 58 | } 59 | } 60 | } 61 | 62 | void move_to(point_t const& pt) 63 | { 64 | _first_pt = _prev_pt = pt; 65 | } 66 | 67 | template 68 | void line_to(point_t const& pt, Sink& sink) 69 | { 70 | vector_t v(pt - _prev_pt); 71 | T len(vectors::norm(v)); 72 | line_actor act{_path, {_prev_pt, pt}}; 73 | if (pre_act(act, len)) 74 | { 75 | flush(sink); 76 | post_act(act, len); 77 | } 78 | _prev_pt = pt; 79 | } 80 | 81 | template 82 | void quad_to(point_t const& pt1, point_t const& pt2, Sink& sink) 83 | { 84 | T len(bezier::quad_length(_prev_pt, pt1, pt2)); 85 | quad_actor act{_path, {_prev_pt, pt1, pt2}}; 86 | if (pre_act(act, len)) 87 | { 88 | flush(sink); 89 | post_act(act, len); 90 | } 91 | _prev_pt = pt2; 92 | } 93 | 94 | template 95 | void cubic_to(point_t const& pt1, point_t const& pt2, point_t const& pt3, Sink& sink) 96 | { 97 | T len(bezier::cubic_length(_prev_pt, pt1, pt2, pt3)); 98 | cubic_actor act{_path, {_prev_pt, pt1, pt2, pt3}}; 99 | if (pre_act(act, len)) 100 | { 101 | flush(sink); 102 | post_act(act, len); 103 | } 104 | _prev_pt = pt3; 105 | } 106 | 107 | template 108 | bool pre_act(Actor& act, T& len) 109 | { 110 | if (_offset) 111 | { 112 | if (_offset >= len) 113 | { 114 | _offset -= len; 115 | if (!_gap) 116 | act.join_end(true); 117 | return false; 118 | } 119 | act.join(_offset, len); 120 | len -= _offset, _offset = 0; 121 | if (!_gap) 122 | act.cut(); 123 | } 124 | return true; 125 | } 126 | 127 | template 128 | void post_act(Actor& act, T len) 129 | { 130 | T sum = 0; 131 | switch (_skip) 132 | { 133 | default: 134 | for ( ; ; ) 135 | { 136 | sum += _weight * (*_it); 137 | if (sum >= len) 138 | { 139 | _offset = sum - len; 140 | _gap = false; 141 | act.join_end(false); 142 | if (++_it == _end) 143 | _it = _begin; 144 | else 145 | _skip = true; 146 | return; 147 | } 148 | if (++_it == _end) 149 | { 150 | _it = _begin; 151 | continue; 152 | } 153 | act.join(sum, len); 154 | len -= sum, sum = 0; 155 | act.cut(); 156 | case true: 157 | sum += _weight * (*_it); 158 | if (++_it == _end) 159 | _it = _begin; 160 | if (sum >= len) 161 | { 162 | _offset = sum - len; 163 | _gap = true; 164 | _skip = false; 165 | return; 166 | } 167 | _path.cut(); 168 | act.join(sum, len); 169 | len -= sum, sum = 0; 170 | } 171 | } 172 | } 173 | 174 | struct line_actor 175 | { 176 | path& _path; 177 | point_t _pts[2]; 178 | point_t _chops[3]; 179 | 180 | void join_end(bool has_prev) 181 | { 182 | if (!has_prev) 183 | _path.join(_pts[0]); 184 | _path.join(_pts[1]); 185 | } 186 | 187 | void join(T sum, T len) 188 | { 189 | _chops[0] = _pts[0]; 190 | _chops[1] = points::interpolate(_pts[0], _pts[1], sum / len); 191 | _chops[2] = _pts[1]; 192 | std::copy(_chops + 1, _chops + 3, _pts); 193 | } 194 | 195 | void cut() 196 | { 197 | _path.join(_chops[0]); 198 | _path.join(_chops[1]); 199 | } 200 | }; 201 | 202 | struct quad_actor 203 | { 204 | path& _path; 205 | point_t _pts[3]; 206 | point_t _chops[5]; 207 | 208 | void join_end(bool has_prev) 209 | { 210 | if (!has_prev) 211 | _path.join(_pts[0]); 212 | _path.unsafe_quad_to(_pts[1], _pts[2]); 213 | } 214 | 215 | void join(T sum, T len) 216 | { 217 | bezier::curve_bisect(NIJI_MAX_QUAD_SUBDIVIDE, sum, len, [this](T t) 218 | { 219 | bezier::chop_quad_at(_pts, _chops, t); 220 | return bezier::quad_length(_chops[0], _chops[1], _chops[2]); 221 | }); 222 | std::copy(_chops + 2, _chops + 5, _pts); 223 | } 224 | 225 | void cut() 226 | { 227 | _path.join_quad(_chops[0], _chops[1], _chops[2]); 228 | } 229 | }; 230 | 231 | struct cubic_actor 232 | { 233 | path& _path; 234 | point_t _pts[4]; 235 | point_t _chops[7]; 236 | 237 | void join_end(bool has_prev) 238 | { 239 | if (!has_prev) 240 | _path.join(_pts[0]); 241 | _path.unsafe_cubic_to(_pts[1], _pts[2], _pts[3]); 242 | } 243 | 244 | void join(T sum, T len) 245 | { 246 | bezier::curve_bisect(NIJI_MAX_CUBIC_SUBDIVIDE, sum, len, [this](T t) 247 | { 248 | bezier::chop_cubic_at(_pts, _chops, t); 249 | return bezier::cubic_length(_chops[0], _chops[1], _chops[2], _chops[3]); 250 | }); 251 | std::copy(_chops + 3, _chops + 7, _pts); 252 | } 253 | 254 | void cut() 255 | { 256 | _path.join_cubic(_chops[0], _chops[1], _chops[2], _chops[3]); 257 | } 258 | }; 259 | 260 | template 261 | void close(Sink& sink) 262 | { 263 | line_to(_first_pt, sink); 264 | flush(sink); 265 | } 266 | 267 | template 268 | void cut(Sink& sink) 269 | { 270 | flush(sink); 271 | } 272 | 273 | template 274 | void flush(Sink& sink) 275 | { 276 | _path.render(sink); 277 | _path.clear(); 278 | } 279 | 280 | path _path; 281 | Iterator const _begin, _end; 282 | Iterator _it; 283 | point_t _prev_pt, _first_pt; 284 | T _offset; 285 | U _weight; 286 | bool _skip, _gap; 287 | }; 288 | }} 289 | 290 | #endif -------------------------------------------------------------------------------- /include/niji/view/detail/stroker.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2019 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_DETAIL_STROKER_HPP_INCLUDED 8 | #define NIJI_VIEW_DETAIL_STROKER_HPP_INCLUDED 9 | 10 | #include 11 | 12 | namespace niji { namespace detail 13 | { 14 | template 15 | struct stroker : offset_outline 16 | { 17 | using base = offset_outline; 18 | 19 | Capper const& _cap; 20 | 21 | stroker(T r, Joiner const& join, Capper const& cap) 22 | : base(r, join), _cap(cap) 23 | {} 24 | 25 | void degenerated_dot() 26 | { 27 | _cap(base::_outer, base::_prev_pt, base::vector_t(base::_r, 0), true); 28 | _cap(base::_outer, base::_prev_pt, base::vector_t(-base::_r, 0), true); 29 | } 30 | 31 | void move_to(typename base::point_t const& pt) 32 | { 33 | cut(false); 34 | base::move_to_no_cap(pt); 35 | } 36 | 37 | void cut(bool curr_is_line) 38 | { 39 | switch (base::_seg_count) 40 | { 41 | case -1: 42 | degenerated_dot(); 43 | case 0: 44 | return; 45 | } 46 | // cap the end 47 | _cap(base::_outer, base::_prev_pt, base::_prev_normal, curr_is_line); 48 | base::_outer.reverse_splice(base::_inner); 49 | 50 | // cap the start 51 | _cap(base::_outer, base::_first_pt, -base::_first_normal, base::_prev_is_line); 52 | base::_outer.close(); 53 | 54 | base::_inner.clear(); 55 | } 56 | 57 | void close(bool curr_is_line) 58 | { 59 | if (base::_seg_count < 1) 60 | { 61 | if (base::_seg_count == -1) 62 | degenerated_dot(); 63 | return; 64 | } 65 | base::close(curr_is_line); 66 | } 67 | }; 68 | }} 69 | 70 | #endif -------------------------------------------------------------------------------- /include/niji/view/fork.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_FORK_HPP_INCLUDED 8 | #define NIJI_VIEW_FORK_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace niji 16 | { 17 | template 18 | struct fork_view : view> 19 | { 20 | using indices_t = std::make_index_sequence; 21 | 22 | std::tuple branches; 23 | 24 | fork_view(Views... branches) 25 | : branches(std::forward(branches)...) 26 | {} 27 | 28 | template 29 | void render(Path const& path, Sink& sink) const 30 | { 31 | render_impl(niji::render, path, sink, indices_t{}); 32 | } 33 | 34 | template 35 | void inverse_render(Path const& path, Sink& sink) const 36 | { 37 | render_impl(niji::inverse_render, path, sink, indices_t{}); 38 | } 39 | 40 | private: 41 | template 42 | void render_impl(F f, Path const& path, Sink& sink, std::index_sequence) const 43 | { 44 | f(path, sink); 45 | bool _[] = {(f(path | std::get(branches), sink), true)...}; 46 | (void)_; 47 | } 48 | }; 49 | } 50 | 51 | namespace niji { namespace views 52 | { 53 | template 54 | inline fork_view fork(Views&&... branches) 55 | { 56 | return {std::forward(branches)...}; 57 | } 58 | }} 59 | 60 | #endif -------------------------------------------------------------------------------- /include/niji/view/identity.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_IDENTITY_HPP_INCLUDED 8 | #define NIJI_VIEW_IDENTITY_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji 14 | { 15 | struct identity_view : view 16 | { 17 | template 18 | static void render(Path const& path, Sink& sink) 19 | { 20 | niji::render(path, sink); 21 | } 22 | 23 | template 24 | static void inverse_render(Path const& path, Sink& sink) 25 | { 26 | niji::inverse_render(path, sink); 27 | } 28 | }; 29 | } 30 | 31 | namespace niji { namespace views 32 | { 33 | NIJI_IDENTIFIER(identity_view, identity); 34 | }} 35 | 36 | #endif -------------------------------------------------------------------------------- /include/niji/view/inverse.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_INVERSE_HPP_INCLUDED 8 | #define NIJI_VIEW_INVERSE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji 14 | { 15 | struct inverse_view : view 16 | { 17 | template 18 | static void render(Path const& path, Sink& sink) 19 | { 20 | niji::inverse_render(path, sink); 21 | } 22 | 23 | template 24 | static void inverse_render(Path const& path, Sink& sink) 25 | { 26 | niji::render(path, sink); 27 | } 28 | }; 29 | } 30 | 31 | namespace niji { namespace views 32 | { 33 | NIJI_IDENTIFIER(inverse_view, inverse); 34 | }} 35 | 36 | #endif -------------------------------------------------------------------------------- /include/niji/view/offset.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_OFFSET_HPP_INCLUDED 8 | #define NIJI_VIEW_OFFSET_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace niji 17 | { 18 | template 19 | struct offset_view : view> 20 | { 21 | template 22 | using point_type = point; 23 | 24 | T r; 25 | Joiner joiner; 26 | 27 | offset_view() : r() {} 28 | 29 | offset_view(T r, Joiner joiner) 30 | : r(r) 31 | , joiner(std::forward(joiner)) 32 | {} 33 | 34 | template 35 | struct adaptor 36 | { 37 | void operator()(move_to_t, point const& pt) 38 | { 39 | _outline.move_to(pt); 40 | } 41 | 42 | void operator()(line_to_t, point const& pt) 43 | { 44 | _outline.line_to(pt); 45 | } 46 | 47 | void operator()(quad_to_t, point const& pt1, point const& pt2) 48 | { 49 | _outline.quad_to(pt1, pt2); 50 | } 51 | 52 | void operator()(cubic_to_t, point const& pt1, point const& pt2, point const& pt3) 53 | { 54 | _outline.cubic_to(pt1, pt2, pt3); 55 | } 56 | 57 | void operator()(end_closed_t) 58 | { 59 | _outline.close(true); // TODO 60 | _outline.finish(_sink, _reversed); 61 | } 62 | 63 | void operator()(end_open_t) 64 | { 65 | _outline.finish(_sink, _reversed); 66 | } 67 | 68 | Sink& _sink; 69 | detail::offset_outline _outline; 70 | bool _reversed; 71 | }; 72 | 73 | template 74 | void render(Path const& path, Sink& sink) const 75 | { 76 | using adaptor_t = adaptor; 77 | if (r) 78 | niji::render(path, adaptor_t{sink, {r, joiner}, false}); 79 | } 80 | 81 | template 82 | void inverse_render(Path const& path, Sink& sink) const 83 | { 84 | using adaptor_t = adaptor; 85 | if (r) 86 | niji::render(path, adaptor_t{sink, {r, joiner, {}}, true}); 87 | } 88 | }; 89 | } 90 | 91 | namespace niji { namespace views 92 | { 93 | template 94 | inline offset_view 95 | offset(just_t r, Joiner&& j = {}) 96 | { 97 | return {r, std::forward(j)}; 98 | } 99 | }} 100 | 101 | #endif -------------------------------------------------------------------------------- /include/niji/view/outline/cap_style.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2018 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_OUTLINE_CAP_STYLE_HPP_INCLUDED 8 | #define NIJI_VIEW_OUTLINE_CAP_STYLE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace niji { namespace detail 17 | { 18 | template 19 | using cap_style_fn = std::function>&, point const&, vector const&, bool)>; 21 | }} 22 | 23 | namespace niji { namespace cap_styles 24 | { 25 | struct butt 26 | { 27 | template 28 | void operator() 29 | ( 30 | path>& path, point const& pt 31 | , vector const& normal, bool is_line 32 | ) const 33 | { 34 | path.join(pt + normal); 35 | path.join(pt - normal); 36 | } 37 | }; 38 | 39 | struct square 40 | { 41 | template 42 | void operator() 43 | ( 44 | path>& path, point pt 45 | , vector const& normal, bool is_line 46 | ) const 47 | { 48 | pt += vectors::normal_ccw(normal); 49 | path.join(pt + normal); 50 | path.join(pt - normal); 51 | } 52 | }; 53 | 54 | struct round 55 | { 56 | template 57 | struct rot 58 | { 59 | T const ca, sa, x0, y0; 60 | 61 | point operator()(T x, T y) const 62 | { 63 | return point(ca * x - y * sa + x0, ca * y + sa * x + y0); 64 | } 65 | }; 66 | 67 | template 68 | void operator() 69 | ( 70 | path>& path, point const& pt 71 | , vector const& normal, bool is_line 72 | ) const 73 | { 74 | # if defined(NIJI_NO_CUBIC_APPROX) 75 | T const s = constants::tan_pi_over_8(), 76 | m = constants::root2_over_2(); 77 | 78 | rot f = {normal.x, normal.y, pt.x, pt.y}; 79 | path.join(pt + normal); 80 | path.unsafe_quad_to(f(1, s), f(m, m)); 81 | path.unsafe_quad_to(f(s, 1), f(0, 1)); 82 | path.unsafe_quad_to(f(-s, 1), f(-m, m)); 83 | path.unsafe_quad_to(f(-1, s), f(-1, 0)); 84 | # else 85 | vector v(vectors::normal_ccw(normal)) 86 | , s(normal * constants::cubic_arc_factor()) 87 | , sn(vectors::normal_ccw(s)); 88 | point pt1(pt + normal), pt2(pt + v), pt3(pt - normal); 89 | path.join(pt1); 90 | path.unsafe_cubic_to(pt1 + sn, pt2 + s, pt2); 91 | path.unsafe_cubic_to(pt2 - s, pt3 + sn, pt3); 92 | # endif 93 | } 94 | }; 95 | }} 96 | 97 | namespace niji 98 | { 99 | template 100 | struct cap_style : detail::cap_style_fn 101 | { 102 | template 103 | cap_style(Capper capper = {}) 104 | : detail::cap_style_fn(capper) 105 | {} 106 | }; 107 | } 108 | 109 | #endif -------------------------------------------------------------------------------- /include/niji/view/outline/join_style.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2018 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_OUTLINE_JOIN_STYLE_HPP_INCLUDED 8 | #define NIJI_VIEW_OUTLINE_JOIN_STYLE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace niji { namespace detail 19 | { 20 | template 21 | inline 22 | void handle_inner_join 23 | ( 24 | path>& inner, point const& pt 25 | , vector const& former_normal, vector const& later_normal 26 | , T magnitude 27 | ) 28 | { 29 | #ifndef JAMBOREE 30 | //inner.join(pt); // See note from SkStrokerPriv.cpp:88 31 | inner.join(pt - later_normal); 32 | #else 33 | T num = vectors::norm_square(former_normal), 34 | den = vectors::dot(former_normal, vectors::normal_cw(later_normal)); 35 | auto v(vectors::normal_cw(former_normal - later_normal) * num / den); 36 | if (magnitude < vectors::norm_square(v - former_normal)) 37 | { 38 | inner.join(pt - former_normal); 39 | //inner.join(pt); 40 | inner.join(pt - later_normal); 41 | } 42 | else 43 | inner.join(pt + v); 44 | #endif 45 | } 46 | 47 | enum class angle_type 48 | { 49 | nearly180, 50 | sharp, 51 | shallow, 52 | nearly_line 53 | }; 54 | 55 | template 56 | inline angle_type get_angle_type(T dot) 57 | { 58 | // need more precise fixed normalization 59 | if (dot >= 0) // shallow or line 60 | return numeric::is_nearly_zero(1 - dot) ? angle_type::nearly_line : angle_type::shallow; 61 | else // sharp or 180 62 | return numeric::is_nearly_zero(1 + dot) ? angle_type::nearly180 : angle_type::sharp; 63 | } 64 | 65 | template 66 | using join_style_fn = std::function>&, path>&, point const& 68 | , vector const&, vector const&, T, bool, bool, T)>; 69 | }} 70 | 71 | namespace niji { namespace join_styles 72 | { 73 | struct bevel 74 | { 75 | template 76 | void operator() 77 | ( 78 | path>& outer, path>& inner, point const& pt 79 | , vector former_normal, vector later_normal 80 | , T r, bool prev_is_line, bool curr_is_line, T magnitude 81 | ) const 82 | { 83 | auto o = &outer, i = &inner; 84 | if (!vectors::is_ccw(former_normal, later_normal)) 85 | { 86 | o = &inner, i = &outer; 87 | former_normal = -former_normal; 88 | later_normal = -later_normal; 89 | } 90 | #if defined(JAMBOREE) 91 | o->join(pt + former_normal); 92 | #endif 93 | o->join(pt + later_normal); 94 | detail::handle_inner_join(*i, pt, former_normal, later_normal, magnitude); 95 | } 96 | }; 97 | 98 | struct round 99 | { 100 | template 101 | void operator() 102 | ( 103 | path>& outer, path>& inner, point const& pt 104 | , vector former_normal, vector later_normal 105 | , T r, bool prev_is_line, bool curr_is_line, T magnitude 106 | ) const 107 | { 108 | auto o = &outer, i = &inner; 109 | bool is_ccw = vectors::is_ccw(former_normal, later_normal); 110 | if (!is_ccw) 111 | { 112 | o = &inner, i = &outer; 113 | former_normal = -former_normal; 114 | later_normal = -later_normal; 115 | } 116 | transforms::affine affine; 117 | affine.scale(r).translate(pt.x, pt.y); 118 | # if defined(NIJI_NO_CUBIC_APPROX) 119 | point pts[17]; 120 | // ignore the 1st point which should be already in path 121 | auto it = pts + 1, end = bezier::build_quad_arc(former_normal / r, later_normal / r, is_ccw, &affine, pts); 122 | # else 123 | point pts[13]; 124 | // ignore the 1st point which should be already in path 125 | auto it = pts + 1, end = bezier::build_cubic_arc(former_normal / r, later_normal / r, is_ccw, &affine, pts); 126 | # endif 127 | # if defined(JAMBOREE) 128 | o->join(*pts); 129 | # endif 130 | # if defined(NIJI_NO_CUBIC_APPROX) 131 | for ( ; it != end; it += 2) 132 | o->unsafe_quad_to(*it, it[1]); 133 | # else 134 | for ( ; it != end; it += 3) 135 | o->unsafe_cubic_to(*it, it[1], it[2]); 136 | # endif 137 | detail::handle_inner_join(*i, pt, former_normal, later_normal, magnitude); 138 | } 139 | }; 140 | 141 | template 142 | struct miter 143 | { 144 | T inv_limit; 145 | 146 | miter() : inv_limit(T(1) / T(4)) {} 147 | 148 | explicit miter(T limit) 149 | : inv_limit(limit > 1? 1 / limit : 1) 150 | {} 151 | 152 | void operator() 153 | ( 154 | path>& outer, path>& inner, point const& pt 155 | , vector former_normal, vector later_normal 156 | , T r, bool prev_is_line, bool curr_is_line, T magnitude 157 | ) const 158 | { 159 | using detail::angle_type; 160 | 161 | T dot = vectors::dot(former_normal, later_normal) / (r * r); 162 | angle_type a = detail::get_angle_type(dot); 163 | 164 | if (a == angle_type::nearly_line) 165 | return; 166 | 167 | vector mid; 168 | auto o = &outer, i = &inner; 169 | auto do_miter = [&](bool do_miter) 170 | { 171 | #if defined(JAMBOREE) 172 | o->join(pt + former_normal); 173 | #endif 174 | switch (do_miter) 175 | { 176 | case true: 177 | if (prev_is_line) 178 | o->back() = pt + mid; 179 | else 180 | o->join(pt + mid); 181 | if (!curr_is_line) 182 | default: // do bevel 183 | o->join(pt + later_normal); 184 | } 185 | detail::handle_inner_join(*i, pt, former_normal, later_normal, magnitude); 186 | }; 187 | 188 | if (a == angle_type::nearly180) 189 | return do_miter(false); 190 | 191 | bool is_ccw = vectors::is_ccw(former_normal, later_normal); 192 | if (!is_ccw) 193 | { 194 | o = &inner, i = &outer; 195 | former_normal = -former_normal; 196 | later_normal = -later_normal; 197 | } 198 | 199 | // Before we enter the world of square-roots and divides, 200 | // check if we're trying to join an upright right angle 201 | // (common case for stroking rectangles). If so, special case 202 | // that (for speed an accuracy). 203 | // Note: we only need to check one normal if dot==0 204 | if (0 == dot && inv_limit <= constants::one_div_root_two()) 205 | { 206 | mid = former_normal + later_normal; 207 | return do_miter(true); 208 | } 209 | 210 | T sin_half_theta = sqrt((1 + dot) / 2); 211 | if (sin_half_theta < inv_limit) 212 | return do_miter(false); 213 | 214 | mid = former_normal + later_normal; 215 | mid = mid * r / (sin_half_theta * vectors::norm(mid)); 216 | do_miter(true); 217 | } 218 | }; 219 | }} 220 | 221 | namespace niji 222 | { 223 | template 224 | struct join_style : detail::join_style_fn 225 | { 226 | template 227 | join_style(Joiner joiner = {}) 228 | : detail::join_style_fn(joiner) 229 | {} 230 | }; 231 | } 232 | 233 | #endif -------------------------------------------------------------------------------- /include/niji/view/quadruple.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_QUADRUPLE_HPP_INCLUDED 8 | #define NIJI_VIEW_QUADRUPLE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace niji { namespace detail 19 | { 20 | template 21 | struct rot_quad 22 | { 23 | using coord_t = typename boost::geometry::coordinate_type::type; 24 | 25 | Point operator()(Point const& pt) const 26 | { 27 | using boost::geometry::get; 28 | return call(get<0>(pt), get<1>(pt), std::integral_constant()); 29 | } 30 | 31 | static Point call(coord_t x, coord_t y, std::integral_constant) 32 | { 33 | return boost::geometry::make(-y, x); 34 | } 35 | 36 | static Point call(coord_t x, coord_t y, std::integral_constant) 37 | { 38 | return boost::geometry::make(-x, -y); 39 | } 40 | 41 | static Point call(coord_t x, coord_t y, std::integral_constant) 42 | { 43 | return boost::geometry::make(y, -x); 44 | } 45 | }; 46 | }} 47 | 48 | namespace niji 49 | { 50 | struct quadruple_view : view 51 | { 52 | template 53 | static void render(Path const& path, Sink& sink) 54 | { 55 | render_impl(path, sink); 56 | } 57 | 58 | template 59 | static void inverse_render(Path const& path, Sink& sink) 60 | { 61 | render_impl(path | views::inverse, sink); 62 | } 63 | 64 | private: 65 | 66 | template 67 | static void render_impl(Path const& path, Sink& sink) 68 | { 69 | using point_t = path_point_t; 70 | 71 | niji::render(path, sink); 72 | niji::render(path | views::transform(detail::rot_quad()), sink); 73 | niji::render(path | views::transform(detail::rot_quad()), sink); 74 | niji::render(path | views::transform(detail::rot_quad()), sink); 75 | } 76 | }; 77 | } 78 | 79 | namespace niji { namespace views 80 | { 81 | NIJI_IDENTIFIER(quadruple_view, quadruple); 82 | }} 83 | 84 | #endif -------------------------------------------------------------------------------- /include/niji/view/repeat.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_REPEAT_HPP_INCLUDED 8 | #define NIJI_VIEW_REPEAT_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace niji 17 | { 18 | template 19 | struct repeat_view : view> 20 | { 21 | template 22 | using point_type = point>; 23 | 24 | std::size_t n; 25 | vector v; 26 | 27 | repeat_view(std::size_t n, vector const& v) 28 | : n(n), v(v) 29 | {} 30 | 31 | template 32 | void render(Path const& path, Sink& sink) const 33 | { 34 | render_impl(path, sink, n, v.x, v.y, views::identity); 35 | } 36 | 37 | template 38 | void inverse_render(Path const& path, Sink& sink) const 39 | { 40 | render_impl(path, sink, n, v.x, v.y, views::inverse); 41 | } 42 | 43 | private: 44 | 45 | template 46 | static void render_impl(Path const& path, Sink& sink, std::size_t n, T dx, T dy, View view) 47 | { 48 | using coord_t = path_coordinate_t; 49 | 50 | views::translate translate(0, 0); 51 | auto transformed = path | view | translate; 52 | 53 | for (std::size_t i = 0; i != n; ++i) 54 | { 55 | transformed.render(sink); 56 | translate.tx += dx; 57 | translate.ty += dy; 58 | } 59 | } 60 | }; 61 | 62 | template 63 | struct repeat2_view : view> 64 | { 65 | template 66 | using point_type = point>; 67 | 68 | std::size_t nx, ny; 69 | T dx, dy; 70 | 71 | repeat2_view(std::size_t nx, std::size_t ny, T dx, T dy) 72 | : nx(nx), ny(ny), dx(dx), dy(dy) 73 | {} 74 | 75 | template 76 | void render(Path const& path, Sink& sink) const 77 | { 78 | render_impl(path, sink, nx, ny, dx, dy, views::identity); 79 | } 80 | 81 | template 82 | void inverse_render(Path const& path, Sink& sink) const 83 | { 84 | render_impl(path, sink, nx, ny, dx, dy, views::inverse); 85 | } 86 | 87 | private: 88 | 89 | template 90 | static void render_impl(Path const& path, Sink& sink, std::size_t nx, std::size_t ny, T dx, T dy, View view) 91 | { 92 | using coord_t = path_coordinate_t; 93 | 94 | views::translate translate(0, 0); 95 | auto transformed = path | view | translate; 96 | 97 | for (std::size_t i = 0; i != ny; ++i) 98 | { 99 | for (std::size_t j = 0; j != nx; ++j) 100 | { 101 | transformed.render(sink); 102 | translate.tx += dx; 103 | } 104 | translate.tx = 0; 105 | translate.ty += dy; 106 | } 107 | } 108 | }; 109 | } 110 | 111 | namespace niji { namespace views 112 | { 113 | template 114 | inline repeat_view repeat(std::size_t n, vector> const& v) 115 | { 116 | return {n, v}; 117 | } 118 | 119 | template 120 | inline repeat2_view repeat(std::size_t nx, std::size_t ny, just_t dx, just_t dy) 121 | { 122 | return {nx, ny, dx, dy}; 123 | } 124 | }} 125 | 126 | #endif -------------------------------------------------------------------------------- /include/niji/view/rotate.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_ROTATE_HPP_INCLUDED 8 | #define NIJI_VIEW_ROTATE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji { namespace views 14 | { 15 | template 16 | using rotate = transform_view>; 17 | }} 18 | 19 | #endif -------------------------------------------------------------------------------- /include/niji/view/scale.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_SCALE_HPP_INCLUDED 8 | #define NIJI_VIEW_SCALE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji { namespace views 14 | { 15 | template 16 | using scale = transform_view>; 17 | }} 18 | 19 | #endif -------------------------------------------------------------------------------- /include/niji/view/skew.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_SKEW_HPP_INCLUDED 8 | #define NIJI_VIEW_SKEW_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji { namespace views 14 | { 15 | template 16 | using skew = transform_view>; 17 | }} 18 | 19 | #endif -------------------------------------------------------------------------------- /include/niji/view/stroke.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015-2018 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_STROKE_HPP_INCLUDED 8 | #define NIJI_VIEW_STROKE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace niji 18 | { 19 | template, class Capper = cap_style> 20 | struct stroke_view : view> 21 | { 22 | template 23 | using point_type = point; 24 | 25 | T r; 26 | Joiner joiner; 27 | Capper capper; 28 | 29 | stroke_view() : r() {} 30 | 31 | stroke_view(T r, Joiner joiner, Capper capper) 32 | : r(r) 33 | , joiner(std::forward(joiner)) 34 | , capper(std::forward(capper)) 35 | {} 36 | 37 | template 38 | struct adaptor 39 | { 40 | void operator()(move_to_t, point const& pt) 41 | { 42 | _stroker.move_to(pt); 43 | } 44 | 45 | void operator()(line_to_t, point const& pt) 46 | { 47 | _stroker.line_to(pt); 48 | } 49 | 50 | void operator()(quad_to_t, point const& pt1, point const& pt2) 51 | { 52 | _stroker.quad_to(pt1, pt2); 53 | } 54 | 55 | void operator()(cubic_to_t, point const& pt1, point const& pt2, point const& pt3) 56 | { 57 | _stroker.cubic_to(pt1, pt2, pt3); 58 | } 59 | 60 | void operator()(end_closed_t) 61 | { 62 | _stroker.close(true); // TODO 63 | _stroker.finish(_sink, _reversed); 64 | } 65 | 66 | void operator()(end_open_t) 67 | { 68 | _stroker.cut(true); // TODO 69 | _stroker.finish(_sink, _reversed); 70 | } 71 | 72 | Sink& _sink; 73 | detail::stroker, std::decay_t> _stroker; 74 | bool _reversed; 75 | }; 76 | 77 | template 78 | void render(Path const& path, Sink& sink) const 79 | { 80 | using adaptor_t = adaptor; 81 | if (r) 82 | niji::render(path, adaptor_t{sink, {r, joiner, capper}, false}); 83 | } 84 | 85 | template 86 | void inverse_render(Path const& path, Sink& sink) const 87 | { 88 | using adaptor_t = adaptor; 89 | if (r) 90 | niji::render(path, adaptor_t{sink, {r, joiner, capper}, true}); 91 | } 92 | }; 93 | } 94 | 95 | namespace niji { namespace views 96 | { 97 | template 98 | inline stroke_view 99 | stroke(just_t r, Joiner&& j = {}, Capper&& c = {}) 100 | { 101 | return {r, std::forward(j), std::forward(c)}; 102 | } 103 | }} 104 | 105 | #endif -------------------------------------------------------------------------------- /include/niji/view/tee.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2017 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_TEE_HPP_INCLUDED 8 | #define NIJI_VIEW_TEE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji 14 | { 15 | template 16 | struct tee_view : view> 17 | { 18 | RedirectSink sink; 19 | 20 | template 21 | struct adaptor 22 | { 23 | RedirectSink& _redirect; 24 | Sink& _sink; 25 | 26 | template 27 | void operator()(Tag tag, Points const&... pts) 28 | { 29 | _redirect(tag, pts...); 30 | _sink(tag, pts...); 31 | } 32 | }; 33 | 34 | explicit tee_view(RedirectSink sink) 35 | : sink(std::forward(sink)) 36 | {} 37 | 38 | template 39 | void render(Path const& path, Sink& sink_) const 40 | { 41 | niji::render(path, adaptor{sink, sink_}); 42 | } 43 | 44 | template 45 | void inverse_render(Path const& path, Sink& sink_) const 46 | { 47 | niji::inverse_render(path, adaptor{sink, sink_}); 48 | } 49 | }; 50 | } 51 | 52 | namespace niji { namespace views 53 | { 54 | template 55 | inline tee_view tee(RedirectSink&& sink) 56 | { 57 | return tee_view{std::forward(sink)}; 58 | } 59 | }} 60 | 61 | #endif -------------------------------------------------------------------------------- /include/niji/view/trace.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2017-2018 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_TRACE_HPP_INCLUDED 8 | #define NIJI_VIEW_TRACE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace niji 18 | { 19 | template 20 | struct trace_view : view> 21 | { 22 | template 23 | using point_type = point; 24 | 25 | Footprint footprint; 26 | T step; 27 | T offset; 28 | 29 | trace_view(Footprint footprint, T step, T offset = {}) 30 | : footprint(std::forward(footprint)), step(step), offset(offset) 31 | {} 32 | 33 | template 34 | void render(Path const& path, Sink& sink) const 35 | { 36 | using coord_t = path_coordinate_t; 37 | using point_t = point; 38 | using vector_t = vector; 39 | generate_tangents(path, step, offset, [&](point_t const& pt, vector_t const& u) 40 | { 41 | niji::render(footprint | views::rotate(u.y, u.x) | views::translate(pt), sink); 42 | }); 43 | } 44 | 45 | template 46 | void inverse_render(Path const& path, Sink& sink) const 47 | { 48 | using coord_t = path_coordinate_t; 49 | using point_t = point; 50 | using vector_t = vector; 51 | generate_tangents(path, step, offset, [&](point_t const& pt, vector_t const& u) 52 | { 53 | niji::inverse_render(footprint | views::rotate(u.y, u.x) | views::translate(pt), sink); 54 | }); 55 | } 56 | }; 57 | } 58 | 59 | namespace niji { namespace views 60 | { 61 | template 62 | inline trace_view trace(Footprint&& footprint, just_t step, T offset = {}) 63 | { 64 | return {std::forward(footprint), step, offset}; 65 | } 66 | }} 67 | 68 | #endif -------------------------------------------------------------------------------- /include/niji/view/transform.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_TRANSFORM_HPP_INCLUDED 8 | #define NIJI_VIEW_TRANSFORM_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji 14 | { 15 | template 16 | struct transform_view : view>, F 17 | { 18 | template 19 | using point_type = decltype(std::declval()(std::declval>())); 20 | 21 | using F::F; 22 | 23 | transform_view() = default; 24 | transform_view(F&& f) : F(std::move(f)) {} 25 | transform_view(F const& f) : F(f) {} 26 | 27 | template 28 | struct adaptor 29 | { 30 | template 31 | void operator()(Tag tag, Points const&... pts) const 32 | { 33 | _sink(tag, _f(pts)...); 34 | } 35 | 36 | Sink& _sink; 37 | F const& _f; 38 | }; 39 | 40 | template 41 | void render(Path const& path, Sink& sink) const 42 | { 43 | niji::render(path, adaptor{sink, *this}); 44 | } 45 | 46 | template 47 | void inverse_render(Path const& path, Sink& sink) const 48 | { 49 | niji::inverse_render(path, adaptor{sink, *this}); 50 | } 51 | }; 52 | } 53 | 54 | namespace niji { namespace views 55 | { 56 | template 57 | inline auto transform(F&& f) 58 | { 59 | return transform_view>{std::forward(f)}; 60 | } 61 | }} 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /include/niji/view/translate.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_TRANSLATE_HPP_INCLUDED 8 | #define NIJI_VIEW_TRANSLATE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji { namespace views 14 | { 15 | template 16 | using translate = transform_view>; 17 | }} 18 | 19 | #endif -------------------------------------------------------------------------------- /include/niji/view/transpose.hpp: -------------------------------------------------------------------------------- 1 | /*////////////////////////////////////////////////////////////////////////////// 2 | Copyright (c) 2015 Jamboree 3 | 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | //////////////////////////////////////////////////////////////////////////////*/ 7 | #ifndef NIJI_VIEW_TRANSPOSE_HPP_INCLUDED 8 | #define NIJI_VIEW_TRANSPOSE_HPP_INCLUDED 9 | 10 | #include 11 | #include 12 | 13 | namespace niji { namespace views 14 | { 15 | using transpose = transform_view; 16 | }} 17 | 18 | #endif --------------------------------------------------------------------------------