izzi
SVG SUBSET C++ API
Loading...
Searching...
No Matches
a60-svg-base-types.h
Go to the documentation of this file.
1// svg base -*- mode: C++ -*-
2
3// Copyright (C) 2014-2024 Benjamin De Kosnik <b.dekosnik@gmail.com>
4
5// This file is part of the alpha60-MiL SVG library. This library is
6// free software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the Free
8// Software Foundation; either version 3, or (at your option) any
9// later version.
10
11// This library is distributed in the hope that it will be useful, but
12// WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15
16#ifndef MiL_SVG_BASE_TYPES_H
17#define MiL_SVG_BASE_TYPES_H 1
18
19
20#include <map>
21#include <ostream>
22#include <fstream>
23#include <cstdint>
24//#include <compare>
25
26
27namespace svg {
28
29/// Measurement abstraction for absolute (not relative) measurements.
30enum class unit
31 {
32 meter, m, ///< Meter
33 centimeter, cm, ///< Centimeter
34 millimeter, mm, ///< Milliimeter
35 inch, in, ///< Inch
36 pixel, px, ///< Pixel where 1 pixel x 96 PPI = .26 mm
37 point, pt ///< Point where 1 pixel x 1/72 dpi x 96 PPI = .26 mm
38 };
39
40const string
42{
43 using enum_map_type = std::map<unit, std::string>;
44
45 static enum_map_type enum_map;
46 if (enum_map.empty())
47 {
48 enum_map[unit::meter] = "m";
49 enum_map[unit::m] = "m";
50 enum_map[unit::centimeter] = "cm";
51 enum_map[unit::cm] = "cm";
52 enum_map[unit::millimeter] = "mm";
53 enum_map[unit::mm] = "mm";
54 enum_map[unit::inch] = "in";
55 enum_map[unit::in] = "in";
56 enum_map[unit::pixel] = "px";
57 enum_map[unit::px] = "px";
58 enum_map[unit::point] = "pt";
59 enum_map[unit::pt] = "pt";
60 }
61 return enum_map[e];
62}
63
64
65/**
66 Area/Page/Canvas/Drawing area description.
67 Size, origin location in 2D (x,y), heigh, width
68
69 ANSI Letter mm == (unit::millimeter, 215.9, 279.4);
70 ANSI Letter pixels == (unit::pixel, 765, 990);
71
72 ISO A4 mm == (unit::millimeter, 210, 297);
73 ISO A4 pixels == (unit::pixel, 744.09, 1052.36);
74
75 720p pixels == (unit::pixel, 1280, 720);
76 1080p pixels == (unit::pixel, 1920, 1080);
77
78 SVG coordinate system is (0,0) is top leftmost.
79*/
80template<typename T1 = svg::space_type>
81struct area
82{
83 using atype = T1;
84 using unit = svg::unit;
85
88
89 /// Given @param rdenom scaling factor and SVG canvas area by @obj,
90 /// compute max effective segment size given number of segments @rdenom.
91 /// NB: if rdenom is two then this is a max radius value centered
92 /// on the page/frame.
93 inline constexpr double
94 max_segment_size_n(const uint rdenom = 2) const
95 {
96 double leastside = std::min(_M_height, _M_width);
97 return leastside / rdenom;
98 }
99
100 /// Convenience function for finding center.
101 inline constexpr point_2t
103 { return std::make_tuple(_M_width / 2, _M_height / 2); }
104
105 /// Landscape, aka largest side is horizontal.
106 area
108 {
109 atype lg = 0, sm = 0;
110 if (_M_width >= _M_height)
111 {
112 lg = _M_width;
113 sm = _M_height;
114 }
115 else
116 {
117 lg = _M_height;
118 sm = _M_width;
119 }
120 atype twidth = lg;
121 atype theight = sm;
122 return area(twidth, theight);
123 }
124
125 /// Portrait, aka largest side is vertical.
126 area
128 {
129 atype lg = 0, sm = 0;
130 if (_M_width >= _M_height)
131 {
132 lg = _M_width;
133 sm = _M_height;
134 }
135 else
136 {
137 lg = _M_height;
138 sm = _M_width;
139 }
140 atype twidth = sm;
141 atype theight = lg;
142 return area(twidth, theight);
143 }
144};
145
146
147/// Datum consolidating style preferences.
148struct style
149{
152
156
157 // auto operator<=>(const style&) const = default;
158
159 /// Convenience function to set all colors at once.
160 void
162 {
163 _M_fill_color = klr;
164 _M_stroke_color = klr;
165 }
166};
167
168
169/// Marker shape.
170enum class marker_shape
171 {
172 none = 0, ///< No marker
173 circle, ///< Circle, Round
174 triangle, ///< Triangle
175 square, ///< Square
176 hexagon, ///< Hexagon
177 octahedron, ///< Octahedron (8) 3D
178 icosahedron, ///< Icosahedron
179 sunburst, ///< Sunburst
180 x, ///< Crossed Lines
181 blob, ///< Organic Blob form
182 lauburu, ///< Lauburu Curve
183 wave ///< Wave
184 };
185
186const string
188{
189 using enum_map_type = std::map<marker_shape, std::string>;
190
191 static enum_map_type enum_map;
192 if (enum_map.empty())
193 {
194 enum_map[marker_shape::none] = "none";
195 enum_map[marker_shape::circle] = "circle";
196 enum_map[marker_shape::triangle] = "triangle";
197 enum_map[marker_shape::square] = "square";
198 enum_map[marker_shape::hexagon] = "hexagon";
199 enum_map[marker_shape::octahedron] = "octahedron";
200 enum_map[marker_shape::icosahedron] = "icosahedron";
201 enum_map[marker_shape::sunburst] = "sunburst";
202 enum_map[marker_shape::x] = "x";
203 enum_map[marker_shape::blob] = "blob";
204 enum_map[marker_shape::lauburu] = "lauburu";
205 enum_map[marker_shape::wave] = "wave";
206
207 }
208 return enum_map[e];
209}
210
211
212/// Additional path/line/polyline stroke styles.
213/// NB: https://yuanchuan.dev/fun-with-stroke-dasharray
215{
216 /// Marker string pointing to definitions elements.
217 /// For graph_mode 1, this means the SVG equivalent of CSS elements:
218 /// marker-start, marker-mid, marker-end
220
221 /// Marker shapes.
222 /// For graph_mode 2, this means the marker_shape of the mark
224
225 /// Marker repetitions, if any. Default is zero, no repitition, single marker.
227
228 /// Line dash vs. space configuration.
229 /// Options are single value, like 2, meaning 2 sized dash 2 sized space.
230 /// Or, double values with size of dash followed by size of space.
231 /// Or, more elaborate patterns of on, off
232 /// https://developer.mozilla.org/en-US/docs/Web/CSS/stroke-dasharray
233 string dasharray;
234
235 /// Starting offset for line dashes.
236 /// https://developer.mozilla.org/en-US/docs/Web/CSS/stroke-dashoffset
238
239 /// Shape of end of line segments in line dashes.
240 /// SVG Values are: butt, round, square.
241 /// https://developer.mozilla.org/en-US/docs/Web/CSS/stroke-linecap
242 string linecap;
243
245
246 /// Create dash array variations with exponentially-increasing spaces.
247 /// dasharray 1 = solid line
248 /// dasharray 2 = 1 == 2 2
249 /// dasharray 3 = 2 == 2 4
250 /// dasharray 4 = 3 == 2 6
251 /// @param lsize is style._M_stroke_size
252 static string
253 create_dasharray_n(const uint lsize, const uint n)
254 {
255 using std::to_string;
256 string da;
257 if (n > 1)
258 {
259 const uint da_sz = lsize + 1;
260 da = to_string(da_sz) + k::space + to_string(da_sz * (n - 1));
261 }
262 return da;
263 }
264};
265
266
267const string
269{
270 const string space("; ");
271 std::ostringstream stream;
272 stream << k::space;
273 stream << "style=" << k::quote;
274 stream << "fill:" << color_qi::to_string(s._M_fill_color) << space;
275 stream << "fill-opacity:" << s._M_fill_opacity << space;
276 stream << "stroke:" << color_qi::to_string(s._M_stroke_color) << space;
277 stream << "stroke-opacity:" << s._M_stroke_opacity << space;
278 stream << "stroke-width:" << s._M_stroke_size << k::quote;
279 return stream.str();
280}
281
282
283/// Datum consolidating transform possibilities.
284/// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform
286{
287 static string
288 matrix(double a, double b, double c, double d, double e, double f)
289 {
290 std::ostringstream stream;
291 stream << "matrix(" << a << k::comma << b << k::comma << c << k::comma
292 << d << k::comma << e << k::comma << f << k::comma << ")";
293 return stream.str();
294 }
295
296 static string
297 rotate(int deg)
298 {
299 std::ostringstream stream;
300 stream << "rotate(" << deg << ")";
301 return stream.str();
302 }
303
304 static string
305 rotate(int deg, int x, int y)
306 {
307 std::ostringstream stream;
308 stream << "rotate(" << deg << k::comma << x << k::comma << y << ")";
309 return stream.str();
310 }
311
312 static string
313 scale(double factor)
314 {
315 std::ostringstream stream;
316 stream << "scale(" << factor << ")";
317 return stream.str();
318 }
319
320 static string
321 scale(double factor1, double factor2)
322 {
323 std::ostringstream stream;
324 stream << "scale(" << factor1 << k::comma << factor2 << ")";
325 return stream.str();
326 }
327
328 static string
329 skew_x(double factor)
330 {
331 std::ostringstream stream;
332 stream << "skewX(" << factor << ")";
333 return stream.str();
334 }
335
336 static string
337 skew_y(double factor)
338 {
339 std::ostringstream stream;
340 stream << "skewY(" << factor << ")";
341 return stream.str();
342 }
343
344 static string
345 translate(int x, int y)
346 {
347 std::ostringstream stream;
348 stream << "translate(" << x << k::comma << y << ")";
349 return stream.str();
350 }
351};
352
353
354/**
355 Character rendering, type, fonts, styles.
356
357 Expect to keep changing the output, so use this abstraction to set
358 styling defaults, so that one can just assign types instead of doing
359 a bunch of search-and-replace operations when changing type
360 characteristics.
361
362 SVG Fonts
363 https://developer.mozilla.org/docs/Web/SVG/Tutorial/SVG_fonts
364*/
366{
367 /// Text alignment.
368 enum class align
369 {
370 left, ///< Left-most part of text block
371 center, ///< Center part of text block
372 right, ///< Right part of text block
381 };
382
383 /// How to align text to a given point.
384 enum class anchor
385 {
386 start, ///< Start the text block at point.
387 middle, ///< Center the middle of the text block at point.
388 end, ///< End the text block at point.
389 inherit ///< Enclosing object or group
390 };
391
392 /// How to align text to the dominant-baseline.
393 /// https://developer.mozilla.org/docs/Web/SVG/Attribute/dominant-baseline
408
409 /// Weight as per CSS property.
410 enum class weight
411 {
413 light, ///< CSS 300
414 normal, ///< CSS 400
415 medium, ///< CSS 500
418 };
419
420 /// Face style variant.
421 /// https://developer.mozilla.org/docs/Web/CSS/font-style
422 enum class property
423 {
424 normal, ///< Book
425 italic ///< Italic
426 };
427
428 // Find all installed fonts on linux with `fc-list`
429 std::string _M_face; // System font name
430 space_type _M_size; // Display size
432
433 // Style attributes for text
434 // font-weight, transform,
435 // https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font-face
440 property _M_p;
441
442 // Compile time expression.
444 use_style(const style s) const
445 { return { _M_face, _M_size, s, _M_anchor, _M_align, _M_baseline, _M_w, _M_p }; }
446
447 const std::string
448 to_string(const align a) const
449 {
450 using enum_map_type = std::map<align, std::string>;
451
452 static enum_map_type enum_map;
453 if (enum_map.empty())
454 {
455 enum_map[align::left] = "left";
456 enum_map[align::center] = "center";
457 enum_map[align::right] = "right";
458 enum_map[align::justify] = "justify";
459 enum_map[align::justifyall] = "justify-all";
460 enum_map[align::start] = "start";
461 enum_map[align::end] = "end";
462 enum_map[align::inherit] = "inherit";
463 enum_map[align::matchparent] = "match-parent";
464 enum_map[align::initial] = "initial";
465 enum_map[align::unset] = "unset";
466 }
467 return enum_map[a];
468 }
469
470 const std::string
471 to_string(const anchor a) const
472 {
473 using enum_map_type = std::map<anchor, std::string>;
474
475 static enum_map_type enum_map;
476 if (enum_map.empty())
477 {
478 enum_map[anchor::start] = "start";
479 enum_map[anchor::middle] = "middle";
480 enum_map[anchor::end] = "end";
481 enum_map[anchor::inherit] = "inherit";
482 }
483 return enum_map[a];
484 }
485
486 const std::string
487 to_string(const weight w) const
488 {
489 using enum_map_type = std::map<weight, std::string>;
490
491 static enum_map_type enum_map;
492 if (enum_map.empty())
493 {
494 enum_map[weight::xlight] = "200";
495 enum_map[weight::light] = "300";
496 enum_map[weight::normal] = "400";
497 enum_map[weight::medium] = "500";
498 enum_map[weight::bold] = "600";
499 enum_map[weight::xbold] = "700";
500 }
501 return enum_map[w];
502 }
503
504 const std::string
505 to_string(const baseline b) const
506 {
507 using enum_map_type = std::map<baseline, std::string>;
508
509 static enum_map_type enum_map;
510 if (enum_map.empty())
511 {
512 enum_map[baseline::none] = "";
513 enum_map[baseline::automatic] = "auto";
514 enum_map[baseline::ideographic] = "ideographic";
515 enum_map[baseline::alphabetic] = "alphabetic";
516 enum_map[baseline::hanging] = "hanging";
517 enum_map[baseline::mathematical] = "mathematical";
518 enum_map[baseline::central] = "central";
519 enum_map[baseline::middle] = "middle";
520 enum_map[baseline::text_after_edge] = "text-after-edge";
521 enum_map[baseline::text_before_edge] = "text-before-edge";
522 enum_map[baseline::text_top] = "text-top";
523 }
524 return enum_map[b];
525 }
526
527 const std::string
528 to_string(const property p) const
529 {
530 using enum_map_type = std::map<property, std::string>;
531
532 static enum_map_type enum_map;
533 if (enum_map.empty())
534 {
535 enum_map[property::normal] = "normal";
536 enum_map[property::italic] = "italic";
537 }
538 return enum_map[p];
539 }
540
541 const std::string
543 {
544 const string name("__name");
545 const string size("__size");
546 const string anchor("__anchor");
547 const string align("__align");
548 const string len("__lentype");
549
550 std::string strip1 = \
551 R"(font-family="__name" font-size="__size__lentype" text-anchor="__anchor" text-align="__align" )";
552
553 string_replace(strip1, name, _M_face);
554 string_replace(strip1, size, std::to_string(_M_size));
557 string_replace(strip1, len, svg::to_string(utype));
558
559 const std::string weight("__weight");
560 const std::string property("__prop");
561
562 std::string strip2 = \
563 R"(font-weight="__weight" font-style="__prop")";
564
567
568 // Add dominant baseline only if necessary.
569 string stripb;
571 {
572 stripb += "dominant-baseline=";
573 stripb += k::quote;
574 stripb += to_string(_M_baseline);
575 stripb += k::quote;
576 stripb += k::space;
577 }
578 return strip1 + stripb + strip2;
579 }
580};
581
582} // namespace svg
583
584#endif
unit
Measurement abstraction for absolute (not relative) measurements.
@ px
Pixel where 1 pixel x 96 PPI = .26 mm.
@ cm
Centimeter.
@ mm
Milliimeter.
@ pt
Point where 1 pixel x 1/72 dpi x 96 PPI = .26 mm.
unsigned short ushort
Base integer type: positive and negative, signed integral value.
Definition a60-svg.h:57
const string to_string(const unit e)
void string_replace(std::string &target, const std::string &match, const std::string &replace)
Definition a60-svg.h:44
double space_type
Base floating point type.
Definition a60-svg.h:63
marker_shape
Marker shape.
@ lauburu
Lauburu Curve.
@ octahedron
Octahedron (8) 3D.
@ circle
Circle, Round.
@ icosahedron
Icosahedron.
@ blob
Organic Blob form.
unsigned int uint
Definition a60-svg.h:58
std::tuple< space_type, space_type > point_2t
Point (x,y) in 2D space, space_type defaults to double.
Definition izzi-points.h:22
constexpr point_2t center_point() const
Convenience function for finding center.
area to_portrait() const
Portrait, aka largest side is vertical.
area to_landscape() const
Landscape, aka largest side is horizontal.
constexpr double max_segment_size_n(const uint rdenom=2) const
Given.
Color quantified as integral RGB components in the range [0,255]. aka like Scalar in OpenCV.
static string to_string(color_qi s)
Additional path/line/polyline stroke styles. NB: https://yuanchuan.dev/fun-with-stroke-dasharray.
string dashoffset
Starting offset for line dashes. https://developer.mozilla.org/en-US/docs/Web/CSS/stroke-dashoffset.
static string create_dasharray_n(const uint lsize, const uint n)
Create dash array variations with exponentially-increasing spaces. dasharray 1 = solid line dasharray...
ushort marker_reps
Marker repetitions, if any. Default is zero, no repitition, single marker.
string dasharray
Line dash vs. space configuration. Options are single value, like 2, meaning 2 sized dash 2 sized spa...
marker_shape marker_form
Marker shapes. For graph_mode 2, this means the marker_shape of the mark.
string linecap
Shape of end of line segments in line dashes. SVG Values are: butt, round, square....
string marker_defs
Marker string pointing to definitions elements. For graph_mode 1, this means the SVG equivalent of CS...
Datum consolidating style preferences.
color_qi _M_fill_color
color_qi _M_stroke_color
void set_colors(const color_qi &klr)
Convenience function to set all colors at once.
Datum consolidating transform possibilities. https://developer.mozilla.org/en-US/docs/Web/SVG/Attribu...
static string translate(int x, int y)
static string matrix(double a, double b, double c, double d, double e, double f)
static string skew_y(double factor)
static string rotate(int deg, int x, int y)
static string skew_x(double factor)
static string scale(double factor)
static string rotate(int deg)
static string scale(double factor1, double factor2)
const std::string to_string(const baseline b) const
baseline
How to align text to the dominant-baseline. https://developer.mozilla.org/docs/Web/SVG/Attribute/domi...
@ none
Ignore this attribute.
const std::string to_string(const align a) const
const std::string to_string(const anchor a) const
const std::string to_string(const property p) const
align
Text alignment.
@ right
Right part of text block.
@ left
Left-most part of text block.
@ center
Center part of text block.
const std::string to_string(const weight w) const
anchor
How to align text to a given point.
@ middle
Center the middle of the text block at point.
@ inherit
Enclosing object or group.
@ end
End the text block at point.
@ start
Start the text block at point.
property
Face style variant. https://developer.mozilla.org/docs/Web/CSS/font-style.
weight
Weight as per CSS property.
typography use_style(const style s) const
const std::string add_attribute(const svg::unit utype=svg::unit::pixel) const