izzi
SVG SUBSET C++ API
Loading...
Searching...
No Matches
a60-svg.h
Go to the documentation of this file.
1// svg API -*- mode: C++ -*-
2
3// Copyright (C) 2019-2025 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_H
17#define MiL_SVG_H 1
18
19#include <cstddef>
20#include <cmath>
21#include <algorithm>
22#include <array>
23#include <tuple>
24#include <string>
25#include <vector>
26#include <set>
27#include <unordered_map>
28#include <sstream>
29
30/**
31 * Scalable Vector Graphics (SVG) namespace
32 */
33namespace svg {
34
35/// Base string types.
36using std::string;
37using strings = std::vector<string>;
39using vvstrings = std::vector<strings>;
40
41// Utility function, like regex_replace.
42inline void
43string_replace(std::string& target, const std::string& match,
44 const std::string& replace)
45{
46 size_t pos = 0;
47 while((pos = target.find(match, pos)) != std::string::npos)
48 {
49 target.replace(pos, match.length(), replace);
50 pos += replace.length();
51 }
52}
53
54
55/// Base integer type: positive and negative, signed integral value.
56using ushort = unsigned short;
57using uint = unsigned int;
58using ulong = unsigned long;
59using ssize_type = int;
60
61/// Base floating point type.
62using space_type = double;
63
64/// Point (x,y) in 2D space.
65using point_2t = std::tuple<space_type, space_type>;
66
67/// Point (x,y) in 2D space with weight n.
68using point_2tn = std::tuple<point_2t, ssize_type>;
69
70
71/// Convert point_2t to string.
72string
74{
75 auto [ x, y ] = p;
76 std::ostringstream oss;
77 oss << x << ',' << y;
78 return oss.str();
79}
80
81/// Split range, so one dimension of (x,y) cartesian plane.
82using vspace = std::vector<double>;
83
84/// Latitude and Longitude Ranges.
85using srange = std::set<point_2t>;
86using vrange = std::vector<point_2t>;
87using vvranges = std::vector<vrange>;
88
89
90/// Decompose/split 2D ranges to 1D spaces, perhaps with scaling.
91void
92split_vrange(const vrange& cpoints, vspace& xpoints, vspace& ypoints,
93 const double xscale = 1, const double yscale = 1)
94{
95 for (const auto& [x, y] : cpoints)
96 {
97 xpoints.push_back(x / xscale);
98 ypoints.push_back(y / yscale);
99 }
100}
101
102
103/// Union two ranges.
104vrange
105union_vrange(const vrange& r1, const vrange& r2)
106{
107 vrange vr;
108 vr.insert(vr.end(), r1.begin(), r1.end());
109 vr.insert(vr.end(), r2.begin(), r2.end());
110 return vr;
111}
112
113
114/// Simplify sorted vrange by removing interior duplicates.
115vrange
117{
118 // Transform range to the simplest expression, where multiple points
119 // without significant vertical change are coalesed to starting
120 // control point and ending control point.
121 vrange simplevr;
122 point_2t last = { -1.0, -1.0 };
123 double duprangep(false);
124 for (const point_2t& pt : vr)
125 {
126 auto [ x, y] = pt;
127 if (y != get<1>(last))
128 {
129 if (duprangep == true)
130 {
131 simplevr.push_back(last);
132 duprangep = false;
133 }
134 simplevr.push_back(pt);
135 }
136 else
137 duprangep = true;
138 last = pt;
139 }
140 return simplevr;
141}
142
143
144/// For each dimension of vrnage, find min/max and return (xmax, ymax)
145/// NB: Assumes zero is min.
147max_vrange(vspace& xpoints, vspace& ypoints, const uint pown)
148{
149 point_2t rangemaxx = { 0, 0 };
150 if (!xpoints.empty() && !ypoints.empty())
151 {
152 sort(xpoints.begin(), xpoints.end());
153 sort(ypoints.begin(), ypoints.end());
154
155 // For x axis, need to insert padding iff axes are scaled down
156 // and/or have values with truncated significant digits.
157 const bool padp(true);
158 if (padp)
159 {
160 const double sigd = pow(10, pown);
161
162 const double dx = xpoints.back();
163 double ix = std::round(dx * sigd) / sigd;
164 if (ix > dx)
165 xpoints.push_back(ix);
166
167 const double dy = ypoints.back();
168 uint iy = std::round(dy * sigd) / sigd;
169 if (iy > dy)
170 ypoints.push_back(iy);
171 }
172
173 // Find combined ranges, assume zero start.
174 rangemaxx = std::make_tuple(xpoints.back(), ypoints.back());
175 }
176 return rangemaxx;
177}
178
179
180/// Just the range info, none of the temporary objects.
182max_vrange(const vrange& points, const uint pown,
183 const double xscale = 1, const double yscale = 1)
184{
185 vspace pointsx;
186 vspace pointsy;
187 split_vrange(points, pointsx, pointsy, xscale, yscale);
188 point_2t ret = max_vrange(pointsx, pointsy, pown);
189 return ret;
190}
191
192
193/// Truncate double to double with pown signifigant digits.
194vspace
195narrow_vspace(const vspace& points, uint pown)
196{
197 const double sigd = pow(10, pown);
198 vspace npoints;
199 for (const double& d : points)
200 {
201 double dn(d);
202 if (dn > 0)
203 {
204 uint itrunc(dn * sigd);
205 npoints.push_back(itrunc / sigd);
206 }
207 else
208 npoints.push_back(dn);
209 }
210 return npoints;
211}
212
213
214/// Scale value from min to max on range (nfloor, nceil).
215double
217 const ssize_type max,
218 const ssize_type nfloor, const ssize_type nceil)
219{
220 double rmultp(nceil - nfloor);
221 double valnum(value - min);
222 double valdenom(max - min);
223 double weightn = (rmultp * (valnum / valdenom)) + nfloor;
224 return weightn;
225}
226
227
228/// Find cartesian distance between two 2D points.
229space_type
231{
232 auto [ x1, y1 ] = p1;
233 auto [ x2, y2 ] = p2;
234 auto distancex = (x2 - x1) * (x2 - x1);
235 auto distancey = (y2 - y1) * (y2 - y1);
236 space_type distance = sqrt(distancex + distancey);
237 return distance;
238}
239
240
241// Does point p1 of radius r1 intersect point p2 with radius r2?
242// https://developer.mozilla.org x 2D_collision_detection
243bool
244detect_collision(const point_2t& p1, const int r1, const point_2t& p2,
245 const int r2)
246{
247 bool ret(false);
248 if (distance_cartesian(p1, p2) < r1 + r2)
249 ret = true;
250 return ret;
251}
252
253
254/// Resolution of output display device.
255double&
257{
258 static double dpi(96.0);
259 return dpi;
260}
261
262
263/// Conversion between point size to pixels given dpi density.
264double
265pt_to_px(const uint i = 1)
266{
267 // 1pt is equal to exactly 1/72th of an inch.
268 // On a 72dpi output device (display), this is 1 (aka 72 * 1/72).
269 // On a 90dpi output device (display), this is 1.25 (aka 90 * 1/72).
270 // On a 96dpi output device (display), this is 1.33 (aka 96 * 1/72).
271 // constexpr double dpimult = (get_dpi() / 72);
272
273 // Or 18 pt -> 13.5 px -> 1.33
274 // Or 30 pt -> 22.5 px -> 1.33
275 constexpr double dpimult = 1.33;
276 return std::lround(i * dpimult);
277}
278
279
280/// Approximate pixel height of type of point size @sz.
281constexpr double
283{ return 0.58 * sz; }
284
285
286/// Approximate pixel height of type of point size @sz.
287constexpr double
289{ return 0.94 * sz; }
290
291
292/**
293 * SVG Constants
294 */
295namespace constants {
296
297/// Formatting character constants.
298constexpr char space(' ');
299constexpr char quote('"');
300constexpr char hyphen('-');
301constexpr char comma(',');
302constexpr char tab('\t');
303constexpr char newline('\n');
304
305
306/**
307 Numeric constants.
308 pi = double(22)/double(7);
309 pi = 3.14159265358979323846
310*/
311constexpr double pi(3.14159265358979323846);
312
313} // namespace constants
314
315/// Inject nested namepace constants into svg namespace with alias k.
316namespace k = constants;
317
318} // namespace svg
319
320
321#include "a60-svg-color.h" // color, color_qi, color_qf
323#include "a60-svg-color-band.h"
324#include "a60-svg-base-types.h" // area, style, filter, transform, typography
325#include "a60-svg-constants.h"
326#include "a60-svg-elements.h"
328#include "a60-svg-render-state.h"
331#include "a60-svg-sequences.h"
332
333#endif
constexpr double pi(3.14159265358979323846)
constexpr char quote('"')
constexpr char comma(',')
constexpr char newline('\n')
constexpr char space(' ')
Formatting character constants.
constexpr char tab('\t')
constexpr char hyphen('-')
@ 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:56
vrange find_vrange_change_points(const vrange &vr)
Simplify sorted vrange by removing interior duplicates.
Definition a60-svg.h:116
bool detect_collision(const point_2t &p1, const int r1, const point_2t &p2, const int r2)
Definition a60-svg.h:244
vspace narrow_vspace(const vspace &points, uint pown)
Truncate double to double with pown signifigant digits.
Definition a60-svg.h:195
vrange union_vrange(const vrange &r1, const vrange &r2)
Union two ranges.
Definition a60-svg.h:105
std::set< point_2t > srange
Latitude and Longitude Ranges.
Definition a60-svg.h:85
double scale_value_on_range(const ssize_type value, const ssize_type min, const ssize_type max, const ssize_type nfloor, const ssize_type nceil)
Scale value from min to max on range (nfloor, nceil).
Definition a60-svg.h:216
int ssize_type
Definition a60-svg.h:59
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:43
double pt_to_px(const uint i=1)
Conversion between point size to pixels given dpi density.
Definition a60-svg.h:265
double space_type
Base floating point type.
Definition a60-svg.h:62
unsigned long ulong
Definition a60-svg.h:58
std::vector< strings > vvstrings
Definition a60-svg.h:39
std::vector< vrange > vvranges
Definition a60-svg.h:87
std::vector< point_2t > vrange
Definition a60-svg.h:86
point_2t max_vrange(vspace &xpoints, vspace &ypoints, const uint pown)
For each dimension of vrnage, find min/max and return (xmax, ymax) NB: Assumes zero is min.
Definition a60-svg.h:147
std::tuple< point_2t, ssize_type > point_2tn
Point (x,y) in 2D space with weight n.
Definition a60-svg.h:68
constexpr double char_width_to_px(const uint sz)
Approximate pixel height of type of point size @sz.
Definition a60-svg.h:282
std::vector< double > vspace
Split range, so one dimension of (x,y) cartesian plane.
Definition a60-svg.h:82
strings vstrings
Definition a60-svg.h:38
constexpr double char_height_to_px(const uint sz)
Approximate pixel height of type of point size @sz.
Definition a60-svg.h:288
void split_vrange(const vrange &cpoints, vspace &xpoints, vspace &ypoints, const double xscale=1, const double yscale=1)
Decompose/split 2D ranges to 1D spaces, perhaps with scaling.
Definition a60-svg.h:92
double & get_dpi()
Resolution of output display device.
Definition a60-svg.h:256
unsigned int uint
Definition a60-svg.h:57
space_type distance_cartesian(const point_2t &p1, const point_2t &p2)
Find cartesian distance between two 2D points.
Definition a60-svg.h:230
std::tuple< space_type, space_type > point_2t
Point (x,y) in 2D space.
Definition a60-svg.h:65
std::vector< string > strings
Definition a60-svg.h:37