Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tikzgeom.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31# ifndef TIKZGEOM_H
32# define TIKZGEOM_H
33
34# include <algorithm>
35# include <array>
36# include <cmath>
37# include <cstddef>
38# include <iomanip>
39# include <map>
40# include <ostream>
41# include <sstream>
42# include <string>
43# include <unordered_set>
44# include <type_traits>
45# include <utility>
46# include <variant>
47# include <vector>
48
49# include "line.H"
50# include "point.H"
51# include "polygon.H"
52
53namespace Aleph
54{
86 {
87 std::string tikz_style_name;
88 std::string draw_color = "black";
89 std::string fill_color;
90 std::string pattern;
91 std::string pattern_color;
92 std::string text_color;
93 std::string text_anchor;
94 std::string text_placement;
95 std::string extra_options;
96 std::string text_font_command;
97
98 double line_width_mm = -1.0;
99 double opacity = -1.0;
100
101 bool dashed = false;
102 bool dotted = false;
103 bool thick = false;
104 bool with_arrow = false;
105 bool fill = false;
106 };
107
123
140
150 {
151 std::vector<Point> vertices;
152 bool closed = false;
153 };
154
156 inline Tikz_Style make_tikz_draw_style(const std::string & draw_color)
157 {
158 Tikz_Style s;
159 s.draw_color = draw_color;
160 return s;
161 }
162
164 inline Tikz_Style make_tikz_fill_style(const std::string & draw_color,
165 const std::string & fill_color)
166 {
167 Tikz_Style s;
168 s.draw_color = draw_color;
169 s.fill_color = fill_color;
170 s.fill = true;
171 return s;
172 }
173
184 {
185 public:
186 static constexpr int Layer_Background = -100;
187 static constexpr int Layer_Default = 0;
188 static constexpr int Layer_Foreground = 100;
189 static constexpr int Layer_Overlay = 1000;
190
192 using Object = std::variant<Point, Polar_Point, Segment, Triangle,
197
198 private:
207
208 struct Mapping
209 {
210 double sx = 1.0;
211 double sy = 1.0;
212 double dx = 0.0;
213 double dy = 0.0;
214 bool has_x_range = false;
215 bool has_y_range = false;
216 };
217
226
227 double wide_ = 0.0;
228 double height_ = 0.0;
229 double xoffset_ = 0.0;
230 double yoffset_ = 0.0;
231
234 bool with_grid_ticks_ = false;
236 bool with_auto_legend_ = false;
237 double point_radius_mm_ = 1.0;
238 double clip_padding_mm_ = -1.0;
239 double grid_step_x_ = 1.0;
240 double grid_step_y_ = 1.0;
241 double tick_size_mm_ = 1.5;
242 double legend_x_mm_ = 3.0;
243 double legend_y_mm_ = 3.0;
245
248 {
249 Tikz_Style s;
250 s.draw_color = "gray";
251 s.with_arrow = true;
252 return s;
253 }();
254
256 {
257 Tikz_Style s;
258 s.draw_color = "gray!40";
259 s.dotted = true;
260 s.line_width_mm = 0.2;
261 return s;
262 }();
263
265 {
266 std::string label;
268 };
269
270 std::vector<Legend_Entry> legend_entries_;
271 std::map<std::string, Tikz_Style> tikz_style_defs_;
272
273 std::vector<Styled_Object> objects_;
274 size_t next_order_ = 0;
275
276 [[nodiscard]] static std::string fmt_double(const double v)
277 {
278 std::ostringstream ss;
279 ss << std::fixed << std::setprecision(3) << v;
280
281 std::string out = ss.str();
282 if (const auto dot_pos = out.find('.'); dot_pos != std::string::npos)
283 {
284 while (not out.empty() and out.back() == '0')
285 out.pop_back();
286 if (not out.empty() and out.back() == '.')
287 out.pop_back();
288 }
289
290 if (out == "-0")
291 out = "0";
292
293 return out;
294 }
295
296 static void append_option(std::string & opts, const std::string & opt)
297 {
298 if (opt.empty())
299 return;
300 if (not opts.empty())
301 opts += ",";
302 opts += opt;
303 }
304
305 [[nodiscard]] static std::string draw_options(const Tikz_Style & style,
306 const bool allow_fill = false)
307 {
308 std::string opts;
309
310 if (not style.tikz_style_name.empty())
312
313 if (not style.draw_color.empty())
314 append_option(opts, "draw=" + style.draw_color);
315
316 if (allow_fill and style.fill)
317 {
318 if (not style.fill_color.empty())
319 append_option(opts, "fill=" + style.fill_color);
320 else if (not style.draw_color.empty())
321 append_option(opts, "fill=" + style.draw_color);
322
323 if (not style.pattern.empty())
324 {
325 append_option(opts, "pattern=" + style.pattern);
326 if (not style.pattern_color.empty())
327 append_option(opts, "pattern color=" + style.pattern_color);
328 }
329 }
330
331 if (style.line_width_mm > 0.0)
332 append_option(opts, "line width=" + fmt_double(style.line_width_mm) + "mm");
333
334 if (style.opacity >= 0.0)
335 append_option(opts, "opacity=" + fmt_double(style.opacity));
336
337 if (style.dashed)
338 append_option(opts, "dashed");
339 if (style.dotted)
340 append_option(opts, "dotted");
341 if (style.thick)
342 append_option(opts, "thick");
343 if (style.with_arrow)
344 append_option(opts, "->");
345
346 if (not style.extra_options.empty())
348
349 return opts;
350 }
351
352 [[nodiscard]] static std::string point_options(const Tikz_Style & style)
353 {
354 std::string opts;
355 if (not style.tikz_style_name.empty())
357
358 if (not style.fill_color.empty())
359 append_option(opts, "fill=" + style.fill_color);
360 else if (not style.draw_color.empty())
361 append_option(opts, "fill=" + style.draw_color);
362
363 if (style.opacity >= 0.0)
364 append_option(opts, "opacity=" + fmt_double(style.opacity));
365
366 if (not style.extra_options.empty())
368
369 return opts;
370 }
371
372 [[nodiscard]] static std::string text_options(const Tikz_Style & style)
373 {
374 std::string opts;
375 if (not style.tikz_style_name.empty())
377
378 if (not style.text_color.empty())
379 append_option(opts, "text=" + style.text_color);
380 else if (not style.draw_color.empty())
381 append_option(opts, "text=" + style.draw_color);
382
383 if (style.opacity >= 0.0)
384 append_option(opts, "opacity=" + fmt_double(style.opacity));
385
386 if (not style.text_anchor.empty())
387 append_option(opts, "anchor=" + style.text_anchor);
388 if (not style.text_placement.empty())
390
391 if (not style.extra_options.empty())
393
394 return opts;
395 }
396
398 {
399 const Geom_Number a2 = e.get_a() * e.get_a();
400 const Geom_Number b2 = e.get_b() * e.get_b();
401 const Geom_Number c2 = e.get_cos() * e.get_cos();
402 const Geom_Number s2 = e.get_sin() * e.get_sin();
403 return square_root(a2 * c2 + b2 * s2);
404 }
405
407 {
408 const Geom_Number a2 = e.get_a() * e.get_a();
409 const Geom_Number b2 = e.get_b() * e.get_b();
410 const Geom_Number c2 = e.get_cos() * e.get_cos();
411 const Geom_Number s2 = e.get_sin() * e.get_sin();
412 return square_root(a2 * s2 + b2 * c2);
413 }
414
415 static Geom_Box make_box(const Geom_Number & xmin,
416 const Geom_Number & xmax,
417 const Geom_Number & ymin,
418 const Geom_Number & ymax)
419 {
421 box.xmin = xmin;
422 box.xmax = xmax;
423 box.ymin = ymin;
424 box.ymax = ymax;
425 box.initialized = true;
426 return box;
427 }
428
429 static void merge_box(Geom_Box & dst, const Geom_Box & src)
430 {
431 if (not src.initialized)
432 return;
433
434 if (not dst.initialized)
435 {
436 dst = src;
437 return;
438 }
439
440 dst.xmin = std::min(dst.xmin, src.xmin);
441 dst.xmax = std::max(dst.xmax, src.xmax);
442 dst.ymin = std::min(dst.ymin, src.ymin);
443 dst.ymax = std::max(dst.ymax, src.ymax);
444 }
445
446 static Geom_Box bbox_of(const Point & p)
447 {
448 return make_box(p.get_x(), p.get_x(), p.get_y(), p.get_y());
449 }
450
452 {
453 return bbox_of(Point(pp));
454 }
455
456 static Geom_Box bbox_of(const Segment & s)
457 {
460 }
461
462 static Geom_Box bbox_of(const Triangle & t)
463 {
466 }
467
468 static Geom_Box bbox_of(const Ellipse & e)
469 {
472 }
473
475 {
478 const Point & c = e.get_center();
479 return make_box(c.get_x() - ex, c.get_x() + ex,
480 c.get_y() - ey, c.get_y() + ey);
481 }
482
483 static Geom_Box bbox_of(const Text & t)
484 {
487 }
488
489 static Geom_Box bbox_of(const Polygon & poly)
490 {
491 if (poly.size() == 0)
492 return {};
493
495 for (Polygon::Vertex_Iterator it(poly); it.has_curr(); it.next_ne())
496 {
497 const Point p = it.get_current_vertex().to_point();
498 merge_box(box, bbox_of(p));
499 }
500 return box;
501 }
502
503 static Geom_Box bbox_of(const Regular_Polygon & poly)
504 {
505 if (poly.size() == 0)
506 return {};
507
509 for (size_t i = 0; i < poly.size(); ++i)
510 merge_box(box, bbox_of(poly.get_vertex(i)));
511 return box;
512 }
513
514 static Geom_Box bbox_of(const Rectangle & r)
515 {
516 return make_box(r.get_xmin(), r.get_xmax(), r.get_ymin(), r.get_ymax());
517 }
518
519 static Geom_Box bbox_of(const LineEq & l)
520 {
521 const auto x0 = Geom_Number(0);
522 const auto x1 = Geom_Number(1);
523 const Geom_Number y0 = l(x0);
524 const Geom_Number y1 = l(x1);
525 return make_box(std::min(x0, x1), std::max(x0, x1),
526 std::min(y0, y1), std::max(y0, y1));
527 }
528
530 {
532 merge_box(box, bbox_of(b.p0));
533 merge_box(box, bbox_of(b.p1));
534 merge_box(box, bbox_of(b.p2));
535 return box;
536 }
537
539 {
541 merge_box(box, bbox_of(b.p0));
542 merge_box(box, bbox_of(b.p1));
543 merge_box(box, bbox_of(b.p2));
544 merge_box(box, bbox_of(b.p3));
545 return box;
546 }
547
549 {
551 for (const auto & p : pl.vertices)
552 merge_box(box, bbox_of(p));
553 return box;
554 }
555
557 {
559 for (const auto & entry: objects_)
560 {
561 merge_box(box, std::visit(
562 [](const auto & val) { return bbox_of(val); }, entry.object));
563 }
564
565 return box;
566 }
567
569 {
570 return std::max(point_radius_mm_, clip_padding_mm_ > 0.0 ? clip_padding_mm_ : 0.0);
571 }
572
573 [[nodiscard]] static std::string escape_latex(const std::string & text)
574 {
575 std::string escaped;
576 escaped.reserve(text.size() + 8);
577 for (const char ch: text)
578 switch (ch)
579 {
580 case '\\': escaped += "\\textbackslash{}";
581 break;
582 case '{': escaped += "\\{";
583 break;
584 case '}': escaped += "\\}";
585 break;
586 case '$': escaped += "\\$";
587 break;
588 case '%': escaped += "\\%";
589 break;
590 case '#': escaped += "\\#";
591 break;
592 case '&': escaped += "\\&";
593 break;
594 case '_': escaped += "\\_";
595 break;
596 case '^': escaped += "\\^{}";
597 break;
598 case '~': escaped += "\\~{}";
599 break;
600 default: escaped.push_back(ch);
601 break;
602 }
603 return escaped;
604 }
605
606 [[nodiscard]] Mapping compute_mapping(const Geom_Box & box, const bool squarize) const
607 {
608 Mapping map;
609
610 if (not box.initialized)
611 {
612 map.dx = wide_ / 2.0;
613 map.dy = height_ / 2.0;
614 return map;
615 }
616
617 const Geom_Number x_range = box.xmax - box.xmin;
618 const Geom_Number y_range = box.ymax - box.ymin;
619
620 map.has_x_range = x_range != 0;
621 map.has_y_range = y_range != 0;
622
623 const double xr = map.has_x_range ? geom_number_to_double(x_range) : 0.0;
624 const double yr = map.has_y_range ? geom_number_to_double(y_range) : 0.0;
625
626 if (map.has_x_range)
627 map.sx = wide_ / xr;
628 if (map.has_y_range)
629 map.sy = height_ / yr;
630
632 {
633 const double s = std::min(map.sx, map.sy);
634 map.sx = s;
635 map.sy = s;
636
637 const double used_w = xr * s;
638 const double used_h = yr * s;
639 map.dx = (wide_ - used_w) / 2.0;
640 map.dy = (height_ - used_h) / 2.0;
641 }
642 else
643 {
644 map.dx = 0.0;
645 map.dy = 0.0;
646 }
647
648 if (not map.has_x_range)
649 map.dx = wide_ / 2.0;
650 if (not map.has_y_range)
651 map.dy = height_ / 2.0;
652
653 return map;
654 }
655
656 static double map_x(const Geom_Number & x,
657 const Geom_Box & box, const Mapping & map)
658 {
659 if (not map.has_x_range)
660 return map.dx;
661
662 return map.dx + geom_number_to_double(x - box.xmin) * map.sx;
663 }
664
665 static double map_y(const Geom_Number & y,
666 const Geom_Box & box, const Mapping & map)
667 {
668 if (not map.has_y_range)
669 return map.dy;
670
671 return map.dy + geom_number_to_double(y - box.ymin) * map.sy;
672 }
673
674 static std::pair<double, double>
675 map_point(const Point & p, const Geom_Box & box, const Mapping & map)
676 {
677 return {map_x(p.get_x(), box, map), map_y(p.get_y(), box, map)};
678 }
679
680 static double map_x_length(const Geom_Number & dx, const Mapping & map)
681 {
682 if (not map.has_x_range)
683 return 0.0;
684 return std::fabs(geom_number_to_double(dx)) * map.sx;
685 }
686
687 static double map_y_length(const Geom_Number & dy, const Mapping & map)
688 {
689 if (not map.has_y_range)
690 return 0.0;
691 return std::fabs(geom_number_to_double(dy)) * map.sy;
692 }
693
694 template <typename Out>
695 void draw_point(const Point & p, const Tikz_Style & style, Out & output,
696 const Geom_Box & box, const Mapping & map) const
697 {
698 const auto [x, y] = map_point(p, box, map);
699 output << " \\fill";
700 if (const std::string opts = point_options(style); not opts.empty())
701 output << "[" << opts << "]";
702
703 output << " (" << x << "," << y << ") "
704 << "circle[radius=" << point_radius_mm_ << "mm];" << std::endl;
705 }
706
707 template <typename Out>
709 const std::vector<Point> & vertices,
710 const bool closed,
711 const Tikz_Style & style,
712 const Geom_Box & box, const Mapping & map) const
713 {
714 if (vertices.empty())
715 return;
716
717 if (vertices.size() == 1)
718 {
719 draw_point(vertices.front(), style, output, box, map);
720 return;
721 }
722
723 output << " \\draw";
724 if (const std::string opts = draw_options(style, closed); not opts.empty())
725 output << "[" << opts << "]";
726 output << " ";
727
728 for (size_t i = 0; i < vertices.size(); ++i)
729 {
730 const auto [x, y] = map_point(vertices[i], box, map);
731 if (i == 0)
732 output << "(" << x << "," << y << ")";
733 else
734 output << " -- (" << x << "," << y << ")";
735 }
736
737 if (closed)
738 output << " -- cycle";
739 output << ";" << std::endl;
740 }
741
742 template <typename Out>
743 void draw_segment(const Segment & s, const Tikz_Style & style, Out & output,
744 const Geom_Box & box, const Mapping & map) const
745 {
746 draw_polyline(output, {s.get_src_point(), s.get_tgt_point()}, false, style, box, map);
747 }
748
749 template <typename Out>
750 void draw_triangle(const Triangle & t, const Tikz_Style & style, Out & output,
751 const Geom_Box & box, const Mapping & map) const
752 {
753 draw_polyline(output, {t.get_p1(), t.get_p2(), t.get_p3()}, true, style, box, map);
754 }
755
756 template <typename Out>
757 void draw_ellipse(const Ellipse & e, const Tikz_Style & style, Out & output,
758 const Geom_Box & box, const Mapping & map) const
759 {
760 const auto [cx, cy] = map_point(e.get_center(), box, map);
761 const double rx = map_x_length(e.get_hradius(), map);
762 const double ry = map_y_length(e.get_vradius(), map);
763
764 if (rx == 0.0 or ry == 0.0)
765 {
766 draw_point(e.get_center(), style, output, box, map);
767 return;
768 }
769
770 output << " \\draw";
771 if (const std::string opts = draw_options(style, true); not opts.empty())
772 output << "[" << opts << "]";
773 output << " (" << cx << "," << cy << ") "
774 << "ellipse [x radius=" << rx << ", y radius=" << ry << "];"
775 << std::endl;
776 }
777
778 template <typename Out>
779 static void draw_rotated_ellipse(const RotatedEllipse & e, const Tikz_Style & style,
780 Out & output, const Geom_Box & box,
781 const Mapping & map)
782 {
783 constexpr size_t sample_count = 96;
784 constexpr double two_pi = 2.0 * 3.14159265358979323846;
785
786 output << " \\draw";
787 if (const std::string opts = draw_options(style, true); not opts.empty())
788 output << "[" << opts << "]";
789 output << " ";
790
791 for (size_t i = 0; i <= sample_count; ++i)
792 {
793 const double t = two_pi * static_cast<double>(i) /
794 static_cast<double>(sample_count);
795
796 const Geom_Number cos_t = std::cos(t);
797 const Geom_Number sin_t = std::sin(t);
798
799 const Geom_Number local_x = e.get_a() * cos_t;
800 const Geom_Number local_y = e.get_b() * sin_t;
801
802 const Geom_Number world_x = e.get_center().get_x() +
803 local_x * e.get_cos() - local_y * e.get_sin();
804 const Geom_Number world_y = e.get_center().get_y() +
805 local_x * e.get_sin() + local_y * e.get_cos();
806
807 const auto [x, y] = map_point(Point(world_x, world_y), box, map);
808
809 if (i == 0)
810 output << "(" << x << "," << y << ")";
811 else
812 output << " -- (" << x << "," << y << ")";
813 }
814 output << " -- cycle;" << std::endl;
815 }
816
817 template <typename Out>
818 static void draw_text(const Text & t, const Tikz_Style & style, Out & output,
819 const Geom_Box & box, const Mapping & map)
820 {
821 const auto [x, y] = map_point(t.get_point(), box, map);
822
823 output << " \\node[inner sep=1pt";
824 if (const std::string opts = text_options(style); not opts.empty())
825 output << "," << opts;
826 output << "] at (" << x << "," << y << ") {";
827
828 if (not style.text_font_command.empty())
829 output << style.text_font_command << " ";
830
831 output << escape_latex(t.get_str()) << "};" << std::endl;
832 }
833
834 template <typename Out>
835 void draw_polygon(const Polygon & poly, const Tikz_Style & style, Out & output,
836 const Geom_Box & box, const Mapping & map) const
837 {
838 std::vector<Point> vertices;
839 vertices.reserve(poly.size());
840 for (Polygon::Vertex_Iterator it(poly); it.has_curr(); it.next_ne())
841 vertices.push_back(it.get_current_vertex().to_point());
842
843 draw_polyline(output, vertices, poly.is_closed(), style, box, map);
844 }
845
846 template <typename Out>
847 void draw_regular_polygon(const Regular_Polygon & poly, const Tikz_Style & style,
848 Out & output, const Geom_Box & box,
849 const Mapping & map) const
850 {
851 std::vector<Point> vertices;
852 vertices.reserve(poly.size());
853 for (size_t i = 0; i < poly.size(); ++i)
854 vertices.push_back(poly.get_vertex(i));
855
856 draw_polyline(output, vertices, true, style, box, map);
857 }
858
859 template <typename Out>
860 void draw_rectangle(const Rectangle & r, const Tikz_Style & style, Out & output,
861 const Geom_Box & box, const Mapping & map) const
862 {
863 std::vector<Point> vertices;
864 vertices.reserve(4);
865 const std::array<Point, 4> corners = r.corners();
866 for (const Point & p: corners)
867 vertices.push_back(p);
868 draw_polyline(output, vertices, true, style, box, map);
869 }
870
871 template <typename Out>
872 void draw_line_eq(const LineEq & l, const Tikz_Style & style, Out & output,
873 const Geom_Box & box, const Mapping & map) const
874 {
875 if (not box.initialized)
876 return;
877
878 std::vector<Point> clipped;
879 clipped.reserve(4);
880
881 const auto append_if_new = [&](const Point & p)
882 {
883 for (const Point & existing: clipped)
884 if (existing == p)
885 return;
886 clipped.push_back(p);
887 };
888
889 const auto y_in_range = [&](const Geom_Number & y)
890 {
891 return box.ymin <= y and y <= box.ymax;
892 };
893 const auto x_in_range = [&](const Geom_Number & x)
894 {
895 return box.xmin <= x and x <= box.xmax;
896 };
897
898 if (const Geom_Number y_left = l(box.xmin); y_in_range(y_left))
900
901 if (const Geom_Number y_right = l(box.xmax); y_in_range(y_right))
903
904 if (l.m != Geom_Number(0))
905 {
906 if (const Geom_Number x_bottom = (box.ymin - l.y0) / l.m; x_in_range(x_bottom))
908
909 if (const Geom_Number x_top = (box.ymax - l.y0) / l.m; x_in_range(x_top))
911 }
912
913 if (clipped.size() < 2)
914 return;
915
916 size_t best_i = 0;
917 size_t best_j = 1;
918 Geom_Number best_d2 = clipped[0].distance_squared_to(clipped[1]);
919 for (size_t i = 0; i < clipped.size(); ++i)
920 for (size_t j = i + 1; j < clipped.size(); ++j)
921 {
922 const Geom_Number d2 = clipped[i].distance_squared_to(clipped[j]);
923 if (d2 > best_d2)
924 {
925 best_d2 = d2;
926 best_i = i;
927 best_j = j;
928 }
929 }
930
932 }
933
934 template <typename Out>
936 const Tikz_Style & style, Out & output,
937 const Geom_Box & box, const Mapping & map)
938 {
939 const auto [x0, y0] = map_point(b.p0, box, map);
940 const auto [x1, y1] = map_point(b.p1, box, map);
941 const auto [x2, y2] = map_point(b.p2, box, map);
942
943 output << " \\draw";
944 if (const std::string opts = draw_options(style, false); not opts.empty())
945 output << "[" << opts << "]";
946 output << " (" << x0 << "," << y0 << ") .. controls ("
947 << x1 << "," << y1 << ") .. (" << x2 << "," << y2 << ");"
948 << std::endl;
949 }
950
951 template <typename Out>
953 const Tikz_Style & style, Out & output,
954 const Geom_Box & box, const Mapping & map)
955 {
956 const auto [x0, y0] = map_point(b.p0, box, map);
957 const auto [x1, y1] = map_point(b.p1, box, map);
958 const auto [x2, y2] = map_point(b.p2, box, map);
959 const auto [x3, y3] = map_point(b.p3, box, map);
960
961 output << " \\draw";
962 if (const std::string opts = draw_options(style, false); not opts.empty())
963 output << "[" << opts << "]";
964 output << " (" << x0 << "," << y0 << ") .. controls ("
965 << x1 << "," << y1 << ") and (" << x2 << "," << y2
966 << ") .. (" << x3 << "," << y3 << ");"
967 << std::endl;
968 }
969
970 [[nodiscard]] static const char * layer_name(const int layer)
971 {
972 if (layer <= Layer_Background)
973 return "background";
974 if (layer >= Layer_Overlay)
975 return "overlay";
976 if (layer >= Layer_Foreground)
977 return "foreground";
978 return "main";
979 }
980
981 template <typename Out>
983 const Geom_Box & box, const Mapping & map) const
984 {
985 if (not with_coordinate_grid_ or not box.initialized)
986 return;
987
988 if (grid_step_x_ <= 0.0 or grid_step_y_ <= 0.0)
989 return;
990
991 const std::string opts = draw_options(grid_style_, false);
992 const double xmin = geom_number_to_double(box.xmin);
993 const double xmax = geom_number_to_double(box.xmax);
994 const double ymin = geom_number_to_double(box.ymin);
995 const double ymax = geom_number_to_double(box.ymax);
996
997 const double sx = grid_step_x_;
998 const double sy = grid_step_y_;
999 const int nx0 = static_cast<int>(std::ceil(xmin / sx));
1000 const int nx1 = static_cast<int>(std::floor(xmax / sx));
1001 const int ny0 = static_cast<int>(std::ceil(ymin / sy));
1002 const int ny1 = static_cast<int>(std::floor(ymax / sy));
1003
1004 for (int i = nx0; i <= nx1; ++i)
1005 {
1006 const Geom_Number x = Geom_Number(static_cast<double>(i) * sx);
1007 const double xm = map_x(x, box, map);
1008 output << " \\draw";
1009 if (not opts.empty())
1010 output << "[" << opts << "]";
1011 output << " (" << xm << ",0) -- (" << xm << "," << height_ << ");"
1012 << std::endl;
1013 }
1014
1015 for (int i = ny0; i <= ny1; ++i)
1016 {
1017 const auto y = Geom_Number(static_cast<double>(i) * sy);
1018 const double ym = map_y(y, box, map);
1019 output << " \\draw";
1020 if (not opts.empty())
1021 output << "[" << opts << "]";
1022 output << " (0," << ym << ") -- (" << wide_ << "," << ym << ");"
1023 << std::endl;
1024 }
1025
1027 return;
1028
1029 const std::string tick_opts = draw_options(axis_style_, false);
1030 const bool has_x_axis = map.has_y_range and box.ymin <= 0 and 0 <= box.ymax;
1031 const bool has_y_axis = map.has_x_range and box.xmin <= 0 and 0 <= box.xmax;
1032 const double y_axis_mm = has_x_axis ? map_y(Geom_Number(0), box, map) : -1.0;
1033 const double x_axis_mm = has_y_axis ? map_x(Geom_Number(0), box, map) : -1.0;
1034
1035 if (has_x_axis)
1036 for (int i = nx0; i <= nx1; ++i)
1037 {
1038 const auto x = Geom_Number(static_cast<double>(i) * sx);
1039 const double xm = map_x(x, box, map);
1040 output << " \\draw";
1041 if (not tick_opts.empty())
1042 output << "[" << tick_opts << "]";
1043 output << " (" << xm << "," << (y_axis_mm - tick_size_mm_ / 2.0)
1044 << ") -- (" << xm << "," << (y_axis_mm + tick_size_mm_ / 2.0) << ");"
1045 << std::endl;
1046 }
1047
1048 if (has_y_axis)
1049 for (int i = ny0; i <= ny1; ++i)
1050 {
1051 const auto y = Geom_Number(static_cast<double>(i) * sy);
1052 const double ym = map_y(y, box, map);
1053 output << " \\draw";
1054 if (not tick_opts.empty())
1055 output << "[" << tick_opts << "]";
1056 output << " (" << (x_axis_mm - tick_size_mm_ / 2.0) << "," << ym
1057 << ") -- (" << (x_axis_mm + tick_size_mm_ / 2.0) << "," << ym << ");"
1058 << std::endl;
1059 }
1060 }
1061
1062 [[nodiscard]] std::vector<Legend_Entry> collect_legend_entries() const
1063 {
1064 std::vector<Legend_Entry> entries = legend_entries_;
1066 return entries;
1067
1068 std::unordered_set<std::string> seen;
1069 for (const auto & [label, style]: entries)
1070 seen.insert(label);
1071
1072 for (const auto & obj: objects_)
1073 {
1074 std::string color = obj.style.draw_color;
1075 if (color.empty() and not obj.style.fill_color.empty())
1076 color = obj.style.fill_color;
1077 if (color.empty())
1078 continue;
1079 if (seen.contains(color))
1080 continue;
1081
1084 legend_style.fill_color = obj.style.fill_color;
1085 legend_style.fill = obj.style.fill;
1086 legend_style.pattern = obj.style.pattern;
1087 legend_style.pattern_color = obj.style.pattern_color;
1088 entries.push_back({color, legend_style});
1089 seen.insert(color);
1090 }
1091
1092 return entries;
1093 }
1094
1095 template <typename Out>
1096 void draw_legend(Out & output) const
1097 {
1098 const std::vector<Legend_Entry> entries = collect_legend_entries();
1099 if (entries.empty())
1100 return;
1101
1102 for (size_t i = 0; i < entries.size(); ++i)
1103 {
1104 const double y = height_ - legend_y_mm_ - static_cast<double>(i) * legend_entry_step_mm_;
1105 const double x0 = legend_x_mm_;
1106 const double x1 = legend_x_mm_ + 7.0;
1107 const std::string opts = draw_options(entries[i].style, true);
1108
1109 output << " \\draw";
1110 if (not opts.empty())
1111 output << "[" << opts << "]";
1112 output << " (" << x0 << "," << y << ") -- (" << x1 << "," << y << ");"
1113 << std::endl;
1114
1115 output << " \\node[anchor=west] at (" << (x1 + 1.2) << "," << y
1116 << ") {" << escape_latex(entries[i].label) << "};" << std::endl;
1117 }
1118 }
1119
1120 template <typename Out>
1122 {
1123 if (tikz_style_defs_.empty())
1124 return;
1125
1126 for (const auto & [name, style]: tikz_style_defs_)
1127 {
1128 std::string opts = draw_options(style, true);
1129 if (const std::string txt = text_options(style); not txt.empty())
1131 output << " \\tikzset{" << name << "/.style={" << opts << "}}" << std::endl;
1132 }
1133 }
1134
1135 template <typename Out>
1137 const Geom_Box & box, const Mapping & map) const
1138 {
1139 if (not with_cartesian_axis_ or not box.initialized)
1140 return;
1141
1142 const std::string opts = draw_options(axis_style_, false);
1143
1144 if (map.has_y_range and box.ymin <= 0 and 0 <= box.ymax)
1145 {
1146 const double y0 = map_y(Geom_Number(0), box, map);
1147 output << " \\draw";
1148 if (not opts.empty())
1149 output << "[" << opts << "]";
1150 output << " (0," << y0 << ") -- (" << wide_ << "," << y0 << ");"
1151 << std::endl;
1152 }
1153
1154 if (map.has_x_range and box.xmin <= 0 and 0 <= box.xmax)
1155 {
1156 const double x0 = map_x(Geom_Number(0), box, map);
1157 output << " \\draw";
1158 if (not opts.empty())
1159 output << "[" << opts << "]";
1160 output << " (" << x0 << ",0) -- (" << x0 << "," << height_ << ");"
1161 << std::endl;
1162 }
1163 }
1164
1165 template <typename Out>
1166 void draw_object(const Styled_Object & entry, Out & output,
1167 const Geom_Box & box, const Mapping & map) const
1168 {
1169 std::visit([&]<typename T0>(const T0 & value)
1170 {
1171 using T = std::decay_t<T0>;
1172 if constexpr (std::is_same_v<T, Point>)
1173 draw_point(value, entry.style, output, box, map);
1174 else if constexpr (std::is_same_v<T, Polar_Point>)
1175 draw_point(Point(value), entry.style, output, box, map);
1176 else if constexpr (std::is_same_v<T, Segment>)
1177 draw_segment(value, entry.style, output, box, map);
1178 else if constexpr (std::is_same_v<T, Triangle>)
1179 draw_triangle(value, entry.style, output, box, map);
1180 else if constexpr (std::is_same_v<T, Ellipse>)
1181 draw_ellipse(value, entry.style, output, box, map);
1182 else if constexpr (std::is_same_v<T, RotatedEllipse>)
1183 draw_rotated_ellipse(value, entry.style, output, box, map);
1184 else if constexpr (std::is_same_v<T, Text>)
1185 draw_text(value, entry.style, output, box, map);
1186 else if constexpr (std::is_same_v<T, Polygon>)
1187 draw_polygon(value, entry.style, output, box, map);
1188 else if constexpr (std::is_same_v<T, Regular_Polygon>)
1189 draw_regular_polygon(value, entry.style, output, box, map);
1190 else if constexpr (std::is_same_v<T, Rectangle>)
1191 draw_rectangle(value, entry.style, output, box, map);
1192 else if constexpr (std::is_same_v<T, LineEq>)
1193 draw_line_eq(value, entry.style, output, box, map);
1194 else if constexpr (std::is_same_v<T, Tikz_Quadratic_Bezier>)
1195 draw_quadratic_bezier(value, entry.style, output, box, map);
1196 else if constexpr (std::is_same_v<T, Tikz_Cubic_Bezier>)
1197 draw_cubic_bezier(value, entry.style, output, box, map);
1198 else if constexpr (std::is_same_v<T, Tikz_Polyline>)
1199 draw_polyline(output, value.vertices, value.closed,
1200 entry.style, box, map);
1201 },
1202 entry.object);
1203 }
1204
1205 public:
1215 Tikz_Plane(const double & wide, const double & height,
1216 const double & xoffset = 0.0, const double & yoffset = 0.0)
1217 : wide_(wide), height_(height), xoffset_(xoffset), yoffset_(yoffset)
1218 {
1220 << "Tikz_Plane width and height must be greater than zero";
1221 }
1222
1224 [[nodiscard]] const double &get_wide() const { return wide_; }
1226 [[nodiscard]] const double &get_height() const { return height_; }
1228 [[nodiscard]] const double &get_xoffset() const { return xoffset_; }
1230 [[nodiscard]] const double &get_yoffset() const { return yoffset_; }
1232 [[nodiscard]] const double &get_point_radius_mm() const { return point_radius_mm_; }
1234 [[nodiscard]] const double &get_clip_padding_mm() const { return clip_padding_mm_; }
1236 [[nodiscard]] size_t size() const { return objects_.size(); }
1237
1240
1242 [[nodiscard]] const Tikz_Style &get_axis_style() const { return axis_style_; }
1244 [[nodiscard]] const Tikz_Style &get_grid_style() const { return grid_style_; }
1245
1249 void set_default_style(const Tikz_Style & style)
1250 {
1251 default_style_ = style;
1252 }
1253
1257 void set_axis_style(const Tikz_Style & style)
1258 {
1259 axis_style_ = style;
1260 }
1261
1265 void set_grid_style(const Tikz_Style & style)
1266 {
1267 grid_style_ = style;
1268 }
1269
1275 void set_point_radius_mm(const double & radius_mm)
1276 {
1277 ah_domain_error_if(radius_mm <= 0) << "point radius must be greater than zero";
1279 }
1280
1285 void set_clip_padding_mm(const double & padding_mm)
1286 {
1288 }
1289
1292 {
1293 with_cartesian_axis_ = true;
1294 }
1295
1298 {
1299 with_cartesian_axis_ = false;
1300 }
1301
1303 void put_coordinate_grid(const double step_x = 1.0,
1304 const double step_y = 1.0,
1305 const bool draw_ticks = true)
1306 {
1307 ah_domain_error_if(step_x <= 0.0 or step_y <= 0.0)
1308 << "Grid steps must be greater than zero";
1309 with_coordinate_grid_ = true;
1313 }
1314
1317 {
1318 with_coordinate_grid_ = false;
1319 }
1320
1322 void enable_native_tikz_layers(const bool enabled = true)
1323 {
1324 with_native_layers_ = enabled;
1325 }
1326
1328 void enable_auto_legend(const bool enabled = true)
1329 {
1330 with_auto_legend_ = enabled;
1331 }
1332
1334 void add_legend_entry(const std::string & label, const Tikz_Style & style)
1335 {
1336 legend_entries_.push_back({label, style});
1337 }
1338
1341 {
1342 legend_entries_.clear();
1343 }
1344
1346 void register_tikz_style(const std::string & name, const Tikz_Style & style)
1347 {
1348 ah_domain_error_if(name.empty()) << "Style name cannot be empty";
1349 tikz_style_defs_[name] = style;
1350 }
1351
1354 {
1355 tikz_style_defs_.clear();
1356 }
1357
1359 void clear()
1360 {
1361 objects_.clear();
1362 next_order_ = 0;
1363 }
1364
1366 void put(const Object & obj)
1367 {
1369 }
1370
1372 void put(const Object & obj, const Tikz_Style & style, const int layer)
1373 {
1374 objects_.push_back(Styled_Object{obj, style, layer, next_order_++});
1375 }
1376
1383 void draw(std::ostream & output, const bool squarize = true) const
1384 {
1385 const Geom_Box box = compute_box();
1386 const Mapping map = compute_mapping(box, squarize);
1387
1388 output << std::fixed << std::setprecision(6);
1389 output << "% Requires: \\usepackage{tikz}" << std::endl;
1391 {
1392 output << "\\pgfdeclarelayer{background}" << std::endl
1393 << "\\pgfdeclarelayer{foreground}" << std::endl
1394 << "\\pgfdeclarelayer{overlay}" << std::endl;
1395 }
1396 output << "\\begin{tikzpicture}[x=1mm,y=1mm]" << std::endl;
1398 output << " \\pgfsetlayers{background,main,foreground,overlay}" << std::endl;
1400 output << " % " << objects_.size() << " geometric objects in plane" << std::endl;
1401 output << " \\begin{scope}[shift={(" << xoffset_ << "mm," << yoffset_ << "mm)}]"
1402 << std::endl;
1403 const double clip_padding = effective_clip_padding_mm();
1404 output << " \\clip (" << -clip_padding << "," << -clip_padding << ") rectangle ("
1405 << (wide_ + clip_padding) << "," << (height_ + clip_padding) << ");"
1406 << std::endl;
1407
1410
1411 std::vector<size_t> order(objects_.size());
1412 for (size_t i = 0; i < objects_.size(); ++i)
1413 order[i] = i;
1414
1415 std::stable_sort(order.begin(), order.end(),
1416 [&](const size_t lhs, const size_t rhs)
1417 {
1418 if (objects_[lhs].layer != objects_[rhs].layer)
1419 return objects_[lhs].layer < objects_[rhs].layer;
1420 return objects_[lhs].order < objects_[rhs].order;
1421 });
1422
1424 {
1425 const char *current = nullptr;
1426 for (const size_t idx: order)
1427 {
1428 const char *target = layer_name(objects_[idx].layer);
1429 if (current == nullptr or std::string(current) != target)
1430 {
1431 if (current != nullptr)
1432 output << " \\end{pgfonlayer}" << std::endl;
1433 output << " \\begin{pgfonlayer}{" << target << "}" << std::endl;
1434 current = target;
1435 }
1436 draw_object(objects_[idx], output, box, map);
1437 }
1438 if (current != nullptr)
1439 output << " \\end{pgfonlayer}" << std::endl;
1440 }
1441 else
1442 for (const size_t idx: order)
1443 draw_object(objects_[idx], output, box, map);
1444
1446
1447 output << " \\end{scope}" << std::endl;
1448 output << "\\end{tikzpicture}" << std::endl;
1449 }
1450 };
1451
1453 template <typename Geom,
1454 typename = std::enable_if_t<
1455 std::is_constructible_v<Tikz_Plane::Object, std::decay_t<Geom>>>>
1456 inline void put_in_plane(Tikz_Plane & plane, const Geom & geom_obj)
1457 {
1459 }
1460
1462 template <typename Geom,
1463 typename = std::enable_if_t<
1464 std::is_constructible_v<Tikz_Plane::Object, std::decay_t<Geom>>>>
1465 inline void put_in_plane(Tikz_Plane & plane, const Geom & geom_obj,
1466 const Tikz_Style & style,
1467 const int layer = Tikz_Plane::Layer_Default)
1468 {
1469 plane.put(Tikz_Plane::Object(geom_obj), style, layer);
1470 }
1471
1474 const Point & p0,
1475 const Point & p1,
1476 const Point & p2,
1477 const size_t subdivisions = 64,
1478 const Tikz_Style & style = {},
1479 const int layer = Tikz_Plane::Layer_Default)
1480 {
1481 ah_domain_error_if(subdivisions == 0) << "Need at least 1 subdivision";
1482
1483 Tikz_Polyline curve;
1484 curve.vertices.reserve(subdivisions + 1);
1485 for (size_t i = 0; i <= subdivisions; ++i)
1486 {
1488 const Geom_Number s = Geom_Number(1) - t;
1489 const Geom_Number x = s * s * p0.get_x() +
1490 Geom_Number(2) * s * t * p1.get_x() +
1491 t * t * p2.get_x();
1492 const Geom_Number y = s * s * p0.get_y() +
1493 Geom_Number(2) * s * t * p1.get_y() +
1494 t * t * p2.get_y();
1495 curve.vertices.emplace_back(x, y);
1496 }
1497
1498 put_in_plane(plane, curve, style, layer);
1499 }
1500
1503 const Point & p0,
1504 const Point & p1,
1505 const Point & p2,
1506 const Point & p3,
1507 const size_t subdivisions = 64,
1508 const Tikz_Style & style = {},
1509 const int layer = Tikz_Plane::Layer_Default)
1510 {
1511 ah_domain_error_if(subdivisions == 0) << "Need at least 1 subdivision";
1512
1513 Tikz_Polyline curve;
1514 curve.vertices.reserve(subdivisions + 1);
1515 for (size_t i = 0; i <= subdivisions; ++i)
1516 {
1518 const Geom_Number s = Geom_Number(1) - t;
1519 const Geom_Number s2 = s * s;
1520 const Geom_Number t2 = t * t;
1521 const Geom_Number x = s2 * s * p0.get_x() +
1522 Geom_Number(3) * s2 * t * p1.get_x() +
1523 Geom_Number(3) * s * t2 * p2.get_x() +
1524 t2 * t * p3.get_x();
1525 const Geom_Number y = s2 * s * p0.get_y() +
1526 Geom_Number(3) * s2 * t * p1.get_y() +
1527 Geom_Number(3) * s * t2 * p2.get_y() +
1528 t2 * t * p3.get_y();
1529 curve.vertices.emplace_back(x, y);
1530 }
1531
1532 put_in_plane(plane, curve, style, layer);
1533 }
1534
1537 Tikz_Plane & plane,
1538 const Point & p0,
1539 const Point & p1,
1540 const Point & p2,
1541 const Tikz_Style & style = {},
1542 const int layer = Tikz_Plane::Layer_Default)
1543 {
1544 put_in_plane(plane, Tikz_Quadratic_Bezier{p0, p1, p2}, style, layer);
1545 }
1546
1549 Tikz_Plane & plane,
1550 const Point & p0,
1551 const Point & p1,
1552 const Point & p2,
1553 const Point & p3,
1554 const Tikz_Style & style = {},
1555 const int layer = Tikz_Plane::Layer_Default)
1556 {
1557 put_in_plane(plane, Tikz_Cubic_Bezier{p0, p1, p2, p3}, style, layer);
1558 }
1559
1562 Tikz_Plane & plane,
1563 const Point & point,
1564 const std::string & label,
1565 const std::string & placement = "above",
1566 const Tikz_Style & style = make_tikz_draw_style("black"),
1567 const int layer = Tikz_Plane::Layer_Overlay)
1568 {
1569 Tikz_Style label_style = style;
1571 put_in_plane(plane, Text(point, label), label_style, layer);
1572 }
1573} // namespace Aleph
1574
1575# endif // TIKZGEOM_H
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
An axis-aligned ellipse.
Definition point.H:2006
const Geom_Number & get_vradius() const
Gets the vertical radius.
Definition point.H:2080
const Point & get_center() const
Gets the center point of the ellipse.
Definition point.H:2076
Point highest_point() const
Gets the highest point on the ellipse boundary.
Definition point.H:2159
Point rightmost_point() const
Gets the rightmost point on the ellipse boundary.
Definition point.H:2177
const Geom_Number & get_hradius() const
Gets the horizontal radius.
Definition point.H:2078
Point leftmost_point() const
Gets the leftmost point on the ellipse boundary.
Definition point.H:2171
Point lowest_point() const
Gets the lowest point on the ellipse boundary.
Definition point.H:2165
Represents a point with rectangular coordinates in a 2D plane.
Definition point.H:229
const Geom_Number & get_x() const noexcept
Gets the x-coordinate value.
Definition point.H:457
const Geom_Number & get_y() const noexcept
Gets the y-coordinate value.
Definition point.H:466
Polar representation of a 2D point.
Definition point.H:726
A general (irregular) 2D polygon defined by a sequence of vertices.
Definition polygon.H:246
const bool & is_closed() const
Check if the polygon is closed.
Definition polygon.H:473
const size_t & size() const
Get the number of vertices.
Definition polygon.H:477
An axis-aligned rectangle.
Definition point.H:1737
A regular polygon defined by center, side length, and vertex count.
Definition polygon.H:1132
Point get_vertex(const size_t &i) const
Get the i-th vertex of the polygon.
Definition polygon.H:1197
const size_t & size() const
Get the number of vertices.
Definition polygon.H:1178
An ellipse with arbitrary rotation.
Definition point.H:2404
const Geom_Number & get_b() const
Gets the semi-axis 'b' (local y-axis radius).
Definition point.H:2537
const Geom_Number & get_sin() const
Gets the sine of the rotation angle.
Definition point.H:2541
const Geom_Number & get_a() const
Gets the semi-axis 'a' (local x-axis radius).
Definition point.H:2535
const Geom_Number & get_cos() const
Gets the cosine of the rotation angle.
Definition point.H:2539
const Point & get_center() const
Gets the center point.
Definition point.H:2533
Represents a line segment between two points.
Definition point.H:827
const Point & rightmost_point() const noexcept
Gets the endpoint with the largest x-coordinate.
Definition point.H:906
const Point & highest_point() const noexcept
Gets the endpoint with the largest y-coordinate.
Definition point.H:879
const Point & lowest_point() const noexcept
Gets the endpoint with the smallest y-coordinate.
Definition point.H:888
const Point & leftmost_point() const noexcept
Gets the endpoint with the smallest x-coordinate.
Definition point.H:897
const Point & get_tgt_point() const noexcept
Gets the target point of the segment.
Definition point.H:921
const Point & get_src_point() const noexcept
Gets the source point of the segment.
Definition point.H:915
Represents a text string positioned at a 2D point.
Definition point.H:2739
Point lowest_point() const
Gets the lowest point (the anchor point).
Definition point.H:2784
Point highest_point() const
Gets the highest point (the anchor point).
Definition point.H:2778
Point rightmost_point() const
Gets the rightmost point (the anchor point).
Definition point.H:2796
const std::string & get_str() const
Gets the text string.
Definition point.H:2775
const Point & get_point() const
Gets the position point of the text.
Definition point.H:2769
Point leftmost_point() const
Gets the leftmost point (the anchor point).
Definition point.H:2790
2D TikZ canvas storing geometry objects and emitting LaTeX output.
Definition tikzgeom.H:184
static Geom_Number rotated_x_extent(const RotatedEllipse &e)
Definition tikzgeom.H:397
void set_axis_style(const Tikz_Style &style)
Configure the style used to draw Cartesian axes.
Definition tikzgeom.H:1257
void draw_object(const Styled_Object &entry, Out &output, const Geom_Box &box, const Mapping &map) const
Definition tikzgeom.H:1166
static std::pair< double, double > map_point(const Point &p, const Geom_Box &box, const Mapping &map)
Definition tikzgeom.H:675
Mapping compute_mapping(const Geom_Box &box, const bool squarize) const
Definition tikzgeom.H:606
static Geom_Box bbox_of(const Ellipse &e)
Definition tikzgeom.H:468
static std::string draw_options(const Tikz_Style &style, const bool allow_fill=false)
Definition tikzgeom.H:305
bool with_native_layers_
Definition tikzgeom.H:235
void draw_regular_polygon(const Regular_Polygon &poly, const Tikz_Style &style, Out &output, const Geom_Box &box, const Mapping &map) const
Definition tikzgeom.H:847
std::variant< Point, Polar_Point, Segment, Triangle, Ellipse, RotatedEllipse, Text, Polygon, Regular_Polygon, Rectangle, LineEq, Tikz_Quadratic_Bezier, Tikz_Cubic_Bezier, Tikz_Polyline > Object
Runtime set of supported objects.
Definition tikzgeom.H:196
double tick_size_mm_
Definition tikzgeom.H:241
std::vector< Legend_Entry > collect_legend_entries() const
Definition tikzgeom.H:1062
void draw(std::ostream &output, const bool squarize=true) const
Emit a complete tikzpicture with all inserted objects.
Definition tikzgeom.H:1383
void remove_coordinate_grid()
Disable coordinate grid rendering.
Definition tikzgeom.H:1316
void set_clip_padding_mm(const double &padding_mm)
Configure clip expansion around frame borders.
Definition tikzgeom.H:1285
void draw_point(const Point &p, const Tikz_Style &style, Out &output, const Geom_Box &box, const Mapping &map) const
Definition tikzgeom.H:695
void put_cartesian_axis()
Enable Cartesian axes drawing (only when 0 lies in range).
Definition tikzgeom.H:1291
static constexpr int Layer_Default
Definition tikzgeom.H:187
static Geom_Box make_box(const Geom_Number &xmin, const Geom_Number &xmax, const Geom_Number &ymin, const Geom_Number &ymax)
Definition tikzgeom.H:415
void clear_tikz_styles()
Clear all registered \tikzset style definitions.
Definition tikzgeom.H:1353
void clear()
Remove all inserted objects from the plane.
Definition tikzgeom.H:1359
static std::string fmt_double(const double v)
Definition tikzgeom.H:276
static const char * layer_name(const int layer)
Definition tikzgeom.H:970
const double & get_wide() const
Plane width in millimeters.
Definition tikzgeom.H:1224
static void append_option(std::string &opts, const std::string &opt)
Definition tikzgeom.H:296
const double & get_height() const
Plane height in millimeters.
Definition tikzgeom.H:1226
void put(const Object &obj, const Tikz_Style &style, const int layer)
Insert an object with explicit style/layer.
Definition tikzgeom.H:1372
double grid_step_y_
Definition tikzgeom.H:240
void draw_tikzset_styles(Out &output) const
Definition tikzgeom.H:1121
static constexpr int Layer_Foreground
Definition tikzgeom.H:188
static std::string text_options(const Tikz_Style &style)
Definition tikzgeom.H:372
Tikz_Plane(const double &wide, const double &height, const double &xoffset=0.0, const double &yoffset=0.0)
Construct a TikZ plane with fixed frame size.
Definition tikzgeom.H:1215
double point_radius_mm_
Definition tikzgeom.H:237
static void draw_text(const Text &t, const Tikz_Style &style, Out &output, const Geom_Box &box, const Mapping &map)
Definition tikzgeom.H:818
void enable_auto_legend(const bool enabled=true)
Enable auto-legend generation from style colors.
Definition tikzgeom.H:1328
static double map_y(const Geom_Number &y, const Geom_Box &box, const Mapping &map)
Definition tikzgeom.H:665
void enable_native_tikz_layers(const bool enabled=true)
Enable native PGF layers (\pgfdeclarelayer).
Definition tikzgeom.H:1322
void draw_polyline(Out &output, const std::vector< Point > &vertices, const bool closed, const Tikz_Style &style, const Geom_Box &box, const Mapping &map) const
Definition tikzgeom.H:708
void draw_cartesian_axis(Out &output, const Geom_Box &box, const Mapping &map) const
Definition tikzgeom.H:1136
bool with_cartesian_axis_
Definition tikzgeom.H:232
Geom_Box compute_box() const
Definition tikzgeom.H:556
static std::string point_options(const Tikz_Style &style)
Definition tikzgeom.H:352
size_t size() const
Number of currently inserted objects.
Definition tikzgeom.H:1236
Tikz_Style grid_style_
Definition tikzgeom.H:255
void put_coordinate_grid(const double step_x=1.0, const double step_y=1.0, const bool draw_ticks=true)
Enable coordinate grid/ticks with user step sizes.
Definition tikzgeom.H:1303
static Geom_Box bbox_of(const Polar_Point &pp)
Definition tikzgeom.H:451
bool with_coordinate_grid_
Definition tikzgeom.H:233
static Geom_Box bbox_of(const Tikz_Cubic_Bezier &b)
Definition tikzgeom.H:538
void draw_legend(Out &output) const
Definition tikzgeom.H:1096
const double & get_yoffset() const
Vertical scope offset in millimeters.
Definition tikzgeom.H:1230
static constexpr int Layer_Background
Definition tikzgeom.H:186
static double map_x_length(const Geom_Number &dx, const Mapping &map)
Definition tikzgeom.H:680
Tikz_Style default_style_
Definition tikzgeom.H:246
static std::string escape_latex(const std::string &text)
Definition tikzgeom.H:573
void set_point_radius_mm(const double &radius_mm)
Configure point marker radius.
Definition tikzgeom.H:1275
void draw_rectangle(const Rectangle &r, const Tikz_Style &style, Out &output, const Geom_Box &box, const Mapping &map) const
Definition tikzgeom.H:860
static double map_x(const Geom_Number &x, const Geom_Box &box, const Mapping &map)
Definition tikzgeom.H:656
static void draw_cubic_bezier(const Tikz_Cubic_Bezier &b, const Tikz_Style &style, Out &output, const Geom_Box &box, const Mapping &map)
Definition tikzgeom.H:952
double legend_x_mm_
Definition tikzgeom.H:242
const Tikz_Style & get_default_style() const
Default style used by put(obj) and non-styled put_in_plane.
Definition tikzgeom.H:1239
void put(const Object &obj)
Insert an object with default style on default layer.
Definition tikzgeom.H:1366
static Geom_Number rotated_y_extent(const RotatedEllipse &e)
Definition tikzgeom.H:406
static void draw_rotated_ellipse(const RotatedEllipse &e, const Tikz_Style &style, Out &output, const Geom_Box &box, const Mapping &map)
Definition tikzgeom.H:779
static Geom_Box bbox_of(const Polygon &poly)
Definition tikzgeom.H:489
static Geom_Box bbox_of(const LineEq &l)
Definition tikzgeom.H:519
void draw_polygon(const Polygon &poly, const Tikz_Style &style, Out &output, const Geom_Box &box, const Mapping &map) const
Definition tikzgeom.H:835
static Geom_Box bbox_of(const Triangle &t)
Definition tikzgeom.H:462
std::vector< Legend_Entry > legend_entries_
Definition tikzgeom.H:270
void set_grid_style(const Tikz_Style &style)
Configure the style used to draw coordinate grids.
Definition tikzgeom.H:1265
const Tikz_Style & get_axis_style() const
Style used for Cartesian axes when enabled.
Definition tikzgeom.H:1242
void draw_coordinate_grid(Out &output, const Geom_Box &box, const Mapping &map) const
Definition tikzgeom.H:982
static Geom_Box bbox_of(const Segment &s)
Definition tikzgeom.H:456
static Geom_Box bbox_of(const Point &p)
Definition tikzgeom.H:446
void draw_triangle(const Triangle &t, const Tikz_Style &style, Out &output, const Geom_Box &box, const Mapping &map) const
Definition tikzgeom.H:750
double grid_step_x_
Definition tikzgeom.H:239
static Geom_Box bbox_of(const Tikz_Quadratic_Bezier &b)
Definition tikzgeom.H:529
static Geom_Box bbox_of(const Tikz_Polyline &pl)
Definition tikzgeom.H:548
void register_tikz_style(const std::string &name, const Tikz_Style &style)
Register a reusable \tikzset style for the rendered picture.
Definition tikzgeom.H:1346
static double map_y_length(const Geom_Number &dy, const Mapping &map)
Definition tikzgeom.H:687
void add_legend_entry(const std::string &label, const Tikz_Style &style)
Add a legend entry to be rendered in the top-left corner.
Definition tikzgeom.H:1334
Tikz_Style axis_style_
Definition tikzgeom.H:247
static Geom_Box bbox_of(const Rectangle &r)
Definition tikzgeom.H:514
static void merge_box(Geom_Box &dst, const Geom_Box &src)
Definition tikzgeom.H:429
std::vector< Styled_Object > objects_
Definition tikzgeom.H:273
static Geom_Box bbox_of(const Regular_Polygon &poly)
Definition tikzgeom.H:503
static void draw_quadratic_bezier(const Tikz_Quadratic_Bezier &b, const Tikz_Style &style, Out &output, const Geom_Box &box, const Mapping &map)
Definition tikzgeom.H:935
const Tikz_Style & get_grid_style() const
Style used for coordinate grids when enabled.
Definition tikzgeom.H:1244
double legend_y_mm_
Definition tikzgeom.H:243
void draw_segment(const Segment &s, const Tikz_Style &style, Out &output, const Geom_Box &box, const Mapping &map) const
Definition tikzgeom.H:743
void clear_legend()
Remove user-provided legend entries.
Definition tikzgeom.H:1340
void draw_line_eq(const LineEq &l, const Tikz_Style &style, Out &output, const Geom_Box &box, const Mapping &map) const
Definition tikzgeom.H:872
static Geom_Box bbox_of(const Text &t)
Definition tikzgeom.H:483
double effective_clip_padding_mm() const
Definition tikzgeom.H:568
void set_default_style(const Tikz_Style &style)
Configure the default style for subsequent non-styled inserts.
Definition tikzgeom.H:1249
static constexpr int Layer_Overlay
Definition tikzgeom.H:189
const double & get_clip_padding_mm() const
Clip expansion around the frame; <= 0 means auto (point radius).
Definition tikzgeom.H:1234
const double & get_point_radius_mm() const
Radius used to draw point primitives (millimeters).
Definition tikzgeom.H:1232
double legend_entry_step_mm_
Definition tikzgeom.H:244
static Geom_Box bbox_of(const RotatedEllipse &e)
Definition tikzgeom.H:474
void draw_ellipse(const Ellipse &e, const Tikz_Style &style, Out &output, const Geom_Box &box, const Mapping &map) const
Definition tikzgeom.H:757
std::map< std::string, Tikz_Style > tikz_style_defs_
Definition tikzgeom.H:271
const double & get_xoffset() const
Horizontal scope offset in millimeters.
Definition tikzgeom.H:1228
double clip_padding_mm_
Definition tikzgeom.H:238
void remove_cartesian_axis()
Disable Cartesian axes drawing.
Definition tikzgeom.H:1297
A non-degenerate triangle defined by three points.
Definition point.H:1478
const Point & get_p3() const
Gets the third vertex.
Definition point.H:1591
const Point & get_p2() const
Gets the second vertex.
Definition point.H:1589
const Point & rightmost_point() const
Gets the vertex with the largest x-coordinate.
Definition point.H:1580
const Point & lowest_point() const
Gets the vertex with the smallest y-coordinate.
Definition point.H:1560
const Point & get_p1() const
Gets the first vertex.
Definition point.H:1587
const Point & highest_point() const
Gets the vertex with the largest y-coordinate.
Definition point.H:1550
const Point & leftmost_point() const
Gets the vertex with the smallest x-coordinate.
Definition point.H:1570
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_y1_function > > y1(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4103
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_y0_function > > y0(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4102
bool squarize
Definition graphpic.C:259
2D infinite line representation using slope-intercept form.
static mpfr_t y
Definition mpfr_mul_d.c:3
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
void put_in_plane(Tikz_Plane &plane, const Geom &geom_obj)
Insert any supported geometry type in a Tikz_Plane.
Definition tikzgeom.H:1456
void put_cubic_bezier_native_in_plane(Tikz_Plane &plane, const Point &p0, const Point &p1, const Point &p2, const Point &p3, const Tikz_Style &style={}, const int layer=Tikz_Plane::Layer_Default)
Insert a cubic Bézier using native TikZ controls syntax.
Definition tikzgeom.H:1548
void put_quadratic_bezier_native_in_plane(Tikz_Plane &plane, const Point &p0, const Point &p1, const Point &p2, const Tikz_Style &style={}, const int layer=Tikz_Plane::Layer_Default)
Insert a quadratic Bézier using native TikZ controls syntax.
Definition tikzgeom.H:1536
void put_cubic_bezier_in_plane(Tikz_Plane &plane, const Point &p0, const Point &p1, const Point &p2, const Point &p3, const size_t subdivisions=64, const Tikz_Style &style={}, const int layer=Tikz_Plane::Layer_Default)
Approximate and insert a cubic Bézier as an open polyline.
Definition tikzgeom.H:1502
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
Geom_Number square_root(const Geom_Number &x)
Square root of x (wrapper over mpfr).
Definition point.H:205
double geom_number_to_double(const Geom_Number &n)
Converts a Geom_Number to its double precision representation.
Definition point.H:122
void put_quadratic_bezier_in_plane(Tikz_Plane &plane, const Point &p0, const Point &p1, const Point &p2, const size_t subdivisions=64, const Tikz_Style &style={}, const int layer=Tikz_Plane::Layer_Default)
Approximate and insert a quadratic Bézier as an open polyline.
Definition tikzgeom.H:1473
mpq_class Geom_Number
Numeric type used by the geometry module.
Definition point.H:115
void put_point_label_in_plane(Tikz_Plane &plane, const Point &point, const std::string &label, const std::string &placement="above", const Tikz_Style &style=make_tikz_draw_style("black"), const int layer=Tikz_Plane::Layer_Overlay)
Insert a point label with configurable placement (above, etc.).
Definition tikzgeom.H:1561
Tikz_Style make_tikz_draw_style(const std::string &draw_color)
Create a basic draw style with a custom color.
Definition tikzgeom.H:156
Tikz_Style make_tikz_fill_style(const std::string &draw_color, const std::string &fill_color)
Create a basic fill style with custom draw/fill colors.
Definition tikzgeom.H:164
static long & color(typename GT::Node *p)
2D point and geometric utilities.
2D polygon representation and geometric operations.
2D infinite line in slope-intercept form.
Definition line.H:126
Iterator over the vertices of a polygon.
Definition polygon.H:489
Represents a cubic Bézier curve for native TikZ rendering.
Definition tikzgeom.H:134
Point p3
End point.
Definition tikzgeom.H:138
Point p1
First control point.
Definition tikzgeom.H:136
Point p2
Second control point.
Definition tikzgeom.H:137
Point p0
Start point.
Definition tikzgeom.H:135
Definition tikzgeom.H:265
Tikz_Style style
Definition tikzgeom.H:267
std::string label
Definition tikzgeom.H:266
An object with its associated style, layer, and insertion order.
Definition tikzgeom.H:220
Tikz_Style style
The style used to render the object.
Definition tikzgeom.H:222
int layer
The rendering layer.
Definition tikzgeom.H:223
Object object
The geometric object.
Definition tikzgeom.H:221
size_t order
Insertion order within the layer.
Definition tikzgeom.H:224
An open or closed polyline for TikZ rendering.
Definition tikzgeom.H:150
std::vector< Point > vertices
Ordered vertices.
Definition tikzgeom.H:151
bool closed
Whether to close the polyline.
Definition tikzgeom.H:152
Represents a quadratic Bézier curve for native TikZ rendering.
Definition tikzgeom.H:118
Point p1
Control point.
Definition tikzgeom.H:120
Point p0
Start point.
Definition tikzgeom.H:119
Style descriptor for TikZ primitives.
Definition tikzgeom.H:86
std::string text_anchor
TikZ node anchor (anchor=<value>)
Definition tikzgeom.H:93
std::string fill_color
TikZ fill color (fill=<color>)
Definition tikzgeom.H:89
bool with_arrow
Add ->
Definition tikzgeom.H:104
std::string pattern
TikZ pattern (e.g. north east lines)
Definition tikzgeom.H:90
double opacity
opacity=<value> in [0,1], when >= 0
Definition tikzgeom.H:99
bool thick
Add thick
Definition tikzgeom.H:103
std::string extra_options
Raw extra options appended as-is.
Definition tikzgeom.H:95
std::string text_color
TikZ text color (text=<color>)
Definition tikzgeom.H:92
bool fill
Fill closed shapes (polygon/triangle/ellipse)
Definition tikzgeom.H:105
std::string text_placement
TikZ placement (above, below left, ...)
Definition tikzgeom.H:94
std::string tikz_style_name
Optional named style (from \tikzset)
Definition tikzgeom.H:87
double line_width_mm
line width=<value>mm when > 0
Definition tikzgeom.H:98
bool dashed
Add dashed
Definition tikzgeom.H:101
std::string draw_color
TikZ draw color (draw=<color>)
Definition tikzgeom.H:88
bool dotted
Add dotted
Definition tikzgeom.H:102
std::string text_font_command
e.g. \\small, \\footnotesize
Definition tikzgeom.H:96
std::string pattern_color
TikZ pattern color (pattern color=<color>)
Definition tikzgeom.H:91
gsl_rng * r
DynList< int > l
ofstream output
Definition writeHeap.C:215