16#ifndef MiL_SVG_RENDER_BASICS_H
17#define MiL_SVG_RENDER_BASICS_H 1
31 const double pi(22/7);
32 double a1 = radius * radius * pi;
33 double ap = a1 * weight;
34 double rpa = std::sqrt(ap/pi);
42 double rpr = radius * weight;
50 const string xtransf =
"")
52 auto [
x, y ] = origin;
67 const double deg,
const point_2t rorigin,
68 const k::rrotation rr = k::rrotation::none)
70 auto [ rx, ry ] = rorigin;
73 if (rr == k::rrotation::cw)
78 if (rr == k::rrotation::ccw)
92 const typography typo,
const string xform =
"")
131 while ((pos = uriconv.find(
'&', pos)) != std::string::npos)
133 uriconv.replace(pos, 1,
"&");
137 string astart =
"<a href=";
142 astart += k::newline;
148 string afinish =
"</a>";
149 afinish += k::newline;
157 const string text,
const int tx,
const int ty)
167 const string text,
const int tx,
const int ty,
const double deg)
179 auto [
x, y ] = origin;
180 string textcut(
text);
181 while (textcut.size() > maxlen)
184 auto sppos = textcut.find_last_of(k::space, maxlen);
185 if (sppos == string::npos)
193 string namesubs = textcut.substr(0, sppos);
195 textcut = textcut.substr(sppos);
207 const uint lettingsz = 0)
209 const auto [
x, y ] = origin;
210 const double line_max = std::ceil(
double(
text.size()) / maxlen);
211 const uint lines(line_max);
214 string textcut(
text);
217 while (linen < lines)
221 auto xp =
x - ((sz + lettingsz) * (lines - linen - 1));
224 if (textcut.size() < maxlen)
225 epos = textcut.size();
229 auto sppos = textcut.find_last_of(k::space, maxlen);
230 if (sppos == string::npos)
240 string namesubs = textcut.substr(0, epos);
242 textcut = textcut.substr(epos);
244 xmin = std::min(xmin,
uint(xp));
253 const string filterstr =
"",
const string xform =
"")
255 auto [ width, height ] = a;
256 auto [
x, y ] = origin;
269 if (!filterstr.empty())
280 const string filterstr =
"",
const string xform =
"")
282 auto [ width, height ] = a;
283 auto [
x, y ] = origin;
297 const string filterstr =
"",
const string imgid =
"")
299 auto [ cx, cy ] = origin;
306 if (!filterstr.empty())
328 auto [
x, y ] = origin;
348 const string xform =
"",
const string imgid =
"")
351 auto [
x, y ] = origin;
371 const space_type radius,
const double blurspace,
374 const double opacity = 1)
376 using atype =
decltype(obj.
_M_area)::atype;
378 auto [ xd, yd ] = origin;
383 const double oring = radius + blurspace;
386 const double iring = radius - blurspace;
389 std::ostringstream oss;
390 oss <<
"x" << std::to_string(
x) << k::hyphen
391 <<
"y" << std::to_string(y) << k::hyphen
392 <<
"r" << std::to_string(radius) << k::hyphen
393 <<
"blurspace" << std::to_string(blurspace);
394 const string mangle(oss.str());
399 const string rgrado_name(
string(
"radialout") + k::hyphen + mangle);
419 const string rgradi_name(
string(
"radialin") + k::hyphen + mangle);
423 rgradi.
stop(
"100%", klr, opacity);
458 const string xttr =
"",
const string imgid =
"")
478 const string dasharray =
"")
480 auto [ xo, yo ] = origin;
481 auto [ xe, ye ] = end;
499 static std::mt19937_64 rg(std::random_device{}());
500 auto distr = std::uniform_real_distribution<>(0.0, 2 * 22/7);
501 auto disti = std::uniform_int_distribution<>(-3, 3);
502 auto [
x, y ] = origin;
505 g.
start_element(
"rays-" + std::to_string(nrays) +
"-" + std::to_string(r));
506 for (
uint i = 0; i < nrays; ++i)
508 double theta = distr(rg);
509 double rvary = disti(rg);
511 double xe =
x + (r + rvary) * std::cos(theta);
512 double ye = y + (r + rvary) * std::sin(theta);
536 polyline_element pl(points);
550 auto [ cx, cy ] = origin;
551 double x(cx + (r * std::cos(angler)));
552 double y(cy - (r * std::sin(angler)));
553 return std::make_tuple(
x, y);
562 double angler = (k::pi / 180.0) * ad;
572 angled = 360 - angled;
598 std::ostringstream ossa;
599 for (
uint i = 0; i < lpoints.size(); ++i)
601 auto [
x, y ] = lpoints[i];
606 ossa <<
"M" << k::space;
608 ossa <<
"L" << k::space;
621 const bool selfclosingtagp =
true,
const string xattr =
"")
650 const double r,
const uint pointsn,
651 const bool selfclosingtagp =
true,
const string xattr =
"")
654 const double angle(360.0/pointsn);
659 for (
uint i = 0; i < pointsn; ++i)
666 pointz.push_back(pointz.front());
669 const string id =
"polygon-n" + std::to_string(pointsn) +
"-r" + std::to_string(r);
678 const double r,
const uint pointsn,
const string title,
679 const string xattr =
"")
693 const int sweepflag = 1)
697 std::ostringstream oss;
698 oss <<
"M" << k::space <<
to_string(start) << k::space;
699 oss <<
"A" << k::space;
700 oss << std::to_string(r) << k::space << std::to_string(r) << k::space;
701 oss << 0 << k::space << arcflag << k::space << sweepflag << k::space;
712 const int arcflag = 0,
const int sweepflag = 0)
721 std::ostringstream oss;
722 oss <<
"M" << k::space <<
to_string(origin) << k::space;
723 oss <<
"L" << k::space <<
to_string(start) << k::space;
724 oss <<
"A" << k::space;
725 oss << std::to_string(r) << k::space << std::to_string(r) << k::space;
726 oss << 0 << k::space << arcflag << k::space << sweepflag << k::space;
728 oss <<
"L" << k::space <<
to_string(origin) << k::space;
738 const int arcflag = 0,
const int sweepflag = 0)
753 const int numCurves = 5 + std::rand() % 4,
754 const string tipstr =
"")
756 auto [ ox, oy ] = origin;
757 std::srand(std::time(0));
762 for (
int i = 0; i < numCurves; i++)
764 double angle = (2 * k::pi * i) / numCurves;
765 double variation = 0.5 + (std::rand() % 100) / 100.0;
766 double radius = size * variation;
768 double x = ox + radius * cos(angle);
769 double y = oy + radius * sin(angle);
770 points.push_back({
x, y});
773 double controlAngle = angle + k::pi / numCurves;
774 double controlRadius = size * (0.3 + 0.4 * (std::rand() % 100) / 100.0);
775 double cx = ox + controlRadius * cos(controlAngle);
776 double cy = oy + controlRadius * sin(controlAngle);
777 controlPoints.push_back({cx, cy});
781 std::stringstream data;
782 auto [ p0x, p0y ] = points[0];
783 data <<
"M" << p0x <<
"," << p0y << k::space;
786 for (
int i = 0; i < numCurves; i++)
788 int nextIdx = (i + 1) % numCurves;
791 auto [ cx, cy ] = controlPoints[nextIdx];
792 auto [ pix, piy ] = points[i];
793 auto [ pnx, pny ] = points[nextIdx];
796 double smoothX = (pix + pnx) / 2;
797 double smoothY = (piy + pny) / 2;
799 cx = cx * 0.6 + smoothX * 0.4;
800 cy = cy * 0.6 + smoothY * 0.4;
802 data <<
" Q" << cx <<
"," << cy <<
" " << pnx <<
"," << pny;
806 string pdata = data.str();
808 string id =
"blob-" + std::to_string(size);
827 const int len,
const int width,
828 const string xform =
"",
const string tipstr =
"")
832 const auto [ xo, yo ] = origin;
835 const double whalf(width / 2);
836 const int lenw = len - whalf;
837 const auto x = xo - whalf;
838 const auto y = yo - whalf;
840 std::ostringstream oss;
841 oss <<
"M" << k::space <<
x << k::comma << y << k::space;
844 oss <<
"H" << k::space <<
x - lenw << k::space;
845 oss <<
"V" << k::space << y + width << k::space;
846 oss <<
"H" << k::space <<
x << k::space;
849 oss <<
"V" << k::space << y + lenw + width << k::space;
850 oss <<
"H" << k::space <<
x + width << k::space;
851 oss <<
"V" << k::space << y + width << k::space;
854 oss <<
"H" << k::space <<
x + lenw + width << k::space;
855 oss <<
"V" << k::space << y << k::space;
856 oss <<
"H" << k::space <<
x + width << k::space;
859 oss <<
"V" << k::space << y - lenw << k::space;
860 oss <<
"H" << k::space <<
x << k::space;
861 oss <<
"V" << k::space << y << k::space;
863 const string pathdata = oss.str();
865 string id(
"center-mark-");
866 string attr(std::to_string(width) +
"-" + std::to_string(len));
890 const double amplitude,
const double decay,
891 const int cycles = 3,
892 const string tipstr =
"")
895 auto [ startX, startY ] = origin;
899 keyPoints.reserve(5);
902 keyPoints.emplace_back(startX, startY);
905 for (
int i = 1; i <= cycles * 4; ++i)
907 double t =
static_cast<double>(i) / (cycles * 4);
909 double x = startX + t * length;
910 double decayFactor = exp(-decay * t);
911 double y = startY - amplitude * decayFactor * sin(angle);
912 keyPoints.push_back({
x, y});
916 keyPoints.push_back({startX + length, startY + amplitude * 0.1});
917 keyPoints.push_back({startX, startY + amplitude * 0.1});
920 auto [ kp0x, kp0y ] = keyPoints[0];
921 string pdata = std::format(
"M{:.2f},{:.2f}", kp0x, kp0y);
922 for (
size_t i = 1; i < keyPoints.size() - 2; i += 2)
925 if (i + 1 < keyPoints.size())
927 auto [ kpix, kpiy ] = keyPoints[i];
928 auto [ kpnx, kpny ] = keyPoints[i + 1];
929 pdata += std::format(
" Q{:.2f},{:.2f} {:.2f},{:.2f}", kpix, kpiy, kpnx, kpny);
934 string id =
"sine-decay-" + std::to_string(length) + k::hyphen + std::to_string(cycles);
954 const string tipstr =
"")
956 auto [ ox, oy ] = origin;
960 string gid =
"sunburst-" + std::to_string(nrays) +
"-" + std::to_string(r);
965 double angledelta = 2 * k::pi / nrays;
966 for (
uint i = 0; i < nrays; ++i)
968 double angle = i * angledelta;
971 double xPos = r / 2 * std::cos(angle);
972 double yPos = r / 2 * std::sin(angle);
979 string xformrmega = xformrt + k::space + xformrr;
982 point_2t rcp = { -(rwidth / 2), -(r / 2)};
1000 double swirlFactor = 0.5,
int pointsPerSwirl = 8,
1001 const string tipstr =
"")
1003 using namespace std::numbers;
1004 const double pi = pi_v<double>;
1006 auto [ centerX, centerY ] = origin;
1009 const int swirls = 4;
1010 const double swirlAngle = 2 * pi / swirls;
1013 double startAngle = -pi / 4;
1014 double startX = centerX + size * std::cos(startAngle);
1015 double startY = centerY + size * std::sin(startAngle);
1017 std::string svgPath;
1018 svgPath = std::format(
"M{:.2f},{:.2f}", startX, startY);
1021 for (
int swirl = 0; swirl < swirls; ++swirl)
1023 double baseAngle = startAngle + swirl * swirlAngle;
1026 std::vector<std::pair<double, double>> points;
1028 for (
int i = 0; i <= pointsPerSwirl; ++i)
1030 double t =
static_cast<double>(i) / pointsPerSwirl;
1031 double angle = baseAngle + t * (3 * pi / 2);
1034 double radius = size * (1.0 - t * swirlFactor);
1036 double x = centerX + radius * std::cos(angle);
1037 double y = centerY + radius * std::sin(angle);
1038 points.emplace_back(
x, y);
1042 for (
size_t i = 1; i < points.size(); ++i)
1044 double prevX = points[i-1].first;
1045 double prevY = points[i-1].second;
1046 double currX = points[i].first;
1047 double currY = points[i].second;
1050 double midX = (prevX + currX) / 2;
1051 double midY = (prevY + currY) / 2;
1054 double offset = size * 0.1;
1055 double ctrlX = midX + offset * std::cos(baseAngle + pi/2);
1056 double ctrlY = midY + offset * std::sin(baseAngle + pi/2);
1058 svgPath += std::format(
" Q{:.2f},{:.2f} {:.2f},{:.2f}",
1059 ctrlX, ctrlY, currX, currY);
1065 string id =
"lauburu-" + std::to_string(size);
1075 p.add_title(tipstr);
1094 const uint hexn,
const bool cfillp,
1095 const style styl,
const string xform =
"")
1097 using std::to_string;
1100 string gbase =
"hexagon-honeycomb-";
1105 for (
const auto& phex : hexpoints)
1128 const uint hexn,
const bool cfillp,
const string s,
1129 const typography typo,
const string xform =
"")
1131 using std::to_string;
1134 string gbase =
"text-honeycomb-";
1140 auto [
x, y ] = origin;
1147 for (
uint i = 0; !s.empty() && i < hexpoints.size(); i++)
1149 const auto& p = hexpoints[i];
1150 const double d = hexangles[i];
1171 const string tipstr =
"")
1176 go.
start_element(
"polygon-oct-r-" + std::to_string(radius));
1187 const string tipstr =
"")
1189 auto [ centerX, centerY ] = origin;
1192 double phi = (1 + sqrt(5)) / 2;
1193 double vertices[12][3] =
1195 {0, 1, phi}, {0, 1, -phi}, {0, -1, phi}, {0, -1, -phi},
1196 {1, phi, 0}, {1, -phi, 0}, {-1, phi, 0}, {-1, -phi, 0},
1197 {phi, 0, 1}, {phi, 0, -1}, {-phi, 0, 1}, {-phi, 0, -1}
1201 double normalized[12][3];
1202 for (
int i = 0; i < 12; i++)
1204 double length = sqrt(vertices[i][0]*vertices[i][0] +
1205 vertices[i][1]*vertices[i][1] +
1206 vertices[i][2]*vertices[i][2]);
1207 normalized[i][0] = vertices[i][0] / length;
1208 normalized[i][1] = vertices[i][1] / length;
1209 normalized[i][2] = vertices[i][2] / length;
1213 int projX[12], projY[12];
1214 for (
int i = 0; i < 12; i++)
1216 projX[i] = centerX + radius * (normalized[i][0] * 0.707 - normalized[i][2] * 0.707);
1217 projY[i] = centerY + radius * (normalized[i][0] * 0.408 + normalized[i][1] * 0.816 + normalized[i][2] * 0.408);
1223 {0,2}, {0,4}, {0,6}, {0,8}, {0,10},
1224 {1,3}, {1,4}, {1,6}, {1,9}, {1,11},
1225 {2,5}, {2,7}, {2,8}, {2,10},
1226 {3,5}, {3,7}, {3,9}, {3,11},
1227 {4,6}, {4,8}, {4,9},
1228 {5,7}, {5,8}, {5,9},
1236 for (
int i = 0; i < 30; i++)
1238 int v1 = edges[i][0];
1239 int v2 = edges[i][1];
1240 point_2t p1 = { projX[v1], projY[v1] };
1241 point_2t p2 = { projX[v2], projY[v2] };
1246 if (!tipstr.empty())
1260 const auto [ awidth, aheight ] = a;
1271 double rheight = 80;
1276 svg_element obj(
"color_qis_" + std::to_string(klrs.size()) +
"_palette",
1280 auto x = rwidth, y = rheight;
1282 for (
const auto& klr : klrs)
1285 const style s = { klr, 1.0, klr, 0.0, 2 };
1292 x + xoffset, y - rheight / 2 + rspace, 90);
1294 if (xoffset + rwidth + rspace < awidth - rwidth - rspace)
1295 xoffset += rwidth + rspace;
1299 y += (rheight + rspace + rspace);
static constexpr const char * pair_finish_tag
void add_filter(const string id)
void add_data(const data &d)
Either serialize immediately (as below), or create data structure that adds data to data_vec and then...
void add_style(const style &sty)
void add_data(const data &d, const string dasharray="")
void finish_element()
SVG element end boilerplate.
const string offset_percentage(const ssize_type numer, const ssize_type denom)
void add_data(const data &d, string trans="")
void add_transform(const string s)
void start_element()
For groups of elements that have the same name.
static constexpr const char * pair_finish_tag
void add_data(const vrange &points)
void add_title(const string &t)
void add_data(const data &d)
Either serialize immediately (as below), or create data structure that adds data to data_vec and then...
void stop(const string off, const color &klr, const double opacity=1.0)
void add_data(const data &d, const string trans="", const unit utype=svg::unit::point)
Either serialize immediately (as below), or create data structure that adds data to data_vec and then...
static constexpr const char * pair_finish_tag
static constexpr const char * pair_finish_tag
void add_raw(const string &raw)
void add_fill(const string id)
void start(const string &desc="")
void add_element(const element_base &e)
static constexpr string finish_tag_hard
Abstract base class for all SVG Elements.
Circular gradients https://developer.mozilla.org/en-US/docs/Web/SVG/Element/radialGradient.
constexpr double pi(3.14159265358979323846)
constexpr char space(' ')
Formatting character constants.
double zero_angle_north_ccw(double angled)
Zero degrees is top, going clockwise (cw).
double scale_proportional_to_area(double radius, double weight)
line_element make_line(const point_2t origin, const point_2t end, style s, const string dasharray="")
Line primitive.
void point_to_ring_halo(svg_element &obj, const point_2t origin, const space_type radius, const double blurspace, const svg::color klr, const svg::color fadeklr=color::none, const double opacity=1)
Draws a ring centered at origin of radius r, with outer and inner radial gradient of blurspace in eac...
circle_element make_circle_marker(const point_2t origin, const style s, const space_type r, const string title, const string xform="", const string imgid="")
Make circle element with title and tooltip information.
rect_element make_rect(const point_2t origin, const style s, const area<> a, const string filterstr="", const string xform="")
Create rect_element at origin.
color
Color enumerated as types.
group_element make_text_honeycomb(const point_2t origin, const double r, const uint hexn, const bool cfillp, const string s, const typography typo, const string xform="")
Center rings of text in a hexagon pattern at this point.
void sized_text_r(element_base &obj, svg::typography typo, const int sz, const string text, const int tx, const int ty, const double deg)
Text at size, with a transformation=rotation.
path_element make_path_center_mark(const point_2t &origin, const style styl, const int len, const int width, const string xform="", const string tipstr="")
Plus or x tilt mark as closed path that can be filled.
void styled_text(element_base &obj, const string text, const point_2t origin, const typography typo, const string xform="")
Text at.
uint text_line_n(svg_element &obj, const point_2t origin, const string text, const svg::typography typo, const int sz, const uint maxlen)
Text of maxlen length, overflow goes on line below.
string make_path_data_from_points(const vrange &lpoints)
Make single path segment.
path_element make_path(const string &pathda, const style &styl, const string id="", const bool selfclosingtagp=true, const string xattr="")
Draw path given serialized path data. Can be used to make pinstripes, ie top and bottom line layers....
const string to_string(const unit e)
group_element make_sunburst(const point_2t origin, const style s, const space_type r=4, const uint nrays=10, const string tipstr="")
Rectangles of various sizes rotated from center point (x,y).
circle_element make_circle(const point_2t origin, const style s, const space_type r, const string xform="")
Make circle element.
rect_element make_rect_centered(const point_2t origin, const style s, const area<> a, const string filterstr="", const string xform="")
Create rect_element centered at origin.
text_element style_text_r(const string text, const point_2t origin, const typography &typo, const double deg, const point_2t rorigin, const k::rrotation rr=k::rrotation::none)
Text element at.
double zero_angle_north_cw(double angled)
Zero degrees is top, going clockwise (cw).
vrange radiate_hexagon_honeycomb(const point_2t origin, const double r, const uint n, const bool centerfilledp)
Compute set of points for a radial fill of hexograms centered at p.
double space_type
Base floating point type.
polygon_element make_polygon(const vrange &points, const style s)
Make polygon element.
group_element make_hexagon_honeycomb(const point_2t origin, const double r, const uint hexn, const bool cfillp, const style styl, const string xform="")
Center rings of hexagons at this point.
svg_element display_color_qis(const auto &klrs, const area<> a, const typography &typobase)
Make grid palette for display. NB.
rect_element make_rect_marker(const point_2t origin, const style s, const space_type r, const string title, const string filterstr="", const string imgid="")
Create rectangle element with title and tooltip information.
text_element style_text(const string text, const point_2t origin, const typography typo, const string xtransf="")
Text element at.
group_element make_octahedron(const point_2t, const style &, const double radius, const string tipstr="")
Make octahedron shape (8) in 2D simulated 3D @ret group element of polygon_elements.
path_element make_path_ripple(const point_2t origin, const style s, const double length, const double amplitude, const double decay, const int cycles=3, const string tipstr="")
Make waves.
path_element make_path_marker(const point_2t origin, const style s, const double r, const uint pointsn, const string title, const string xattr="")
Make a polygon marker for line graphs.
void styled_text_link(element_base &obj, const string text, const point_2t origin, const typography typo, const string uri)
Text at.
string make_path_arc_closed(const point_2t &origin, const point_2t &start, const point_2t &end, const space_type r, const int arcflag=0, const int sweepflag=0)
Make closed path between two points and the center of a circle of radius r. Points like: get_circumfe...
path_element make_path_blob(const point_2t origin, const style s, const double size, const int numCurves=5+std::rand() % 4, const string tipstr="")
Make blob shape.
std::vector< point_2t > vrange
path_element make_lauburu(const point_2t origin, const style s, const double size, double swirlFactor=0.5, int pointsPerSwirl=8, const string tipstr="")
Make lauburu.
path_element make_path_polygon(const point_2t origin, const style s, const double r, const uint pointsn, const bool selfclosingtagp=true, const string xattr="")
Center an polygon at this point. radius 4 is pixels to draw out from center point....
point_2t get_circumference_point_d(const double ad, const double r, const point_2t origin)
Angle in degrees.
void sized_text(element_base &obj, svg::typography typo, const int sz, const string text, const int tx, const int ty)
Text at size.
string make_path_arc_circumference(const point_2t &start, const point_2t &end, const space_type r, const int arcflag=0, const int sweepflag=1)
Make path segment between two points on a circumference of radius r. Points like: get_circumference_p...
polygon_element make_polygon_marker(const vrange &points, const style s, const string title, const string xttr="", const string imgid="")
Make polygon element.
void styled_text_r(element_base &obj, const string text, const point_2t origin, const typography typo, const double deg)
Text at.
group_element make_icosahedron(const point_2t origin, const style &s, const double radius, const string tipstr="")
Make icosahedron shape (20) in 2D simulated 3D.
uint text_line_n_r(svg_element &obj, const point_2t origin, const string text, const svg::typography typo, const uint sz, const uint maxlen, const uint lettingsz=0)
Text of maxlen length rotated, overflow goes on line below.
group_element make_line_rays(const point_2t origin, const style s, const space_type r=4, const uint nrays=10)
Lines radiating from center point (x,y).
polyline_element make_polyline(const vrange &points, const style s, const stroke_style sstyle={ })
Polyline primitive.
double scale_proportional_to_weight(double radius, double weight)
point_2t get_circumference_point_r(const double angler, const double r, const point_2t origin)
Angle in radians.
std::tuple< space_type, space_type > point_2t
Point (x,y) in 2D space, space_type defaults to double.
vspace get_honeycomb_angles(const point_2t origin, const vrange &hexagons, const bool degreesp=true)
Compute set of angles, given points for a radial fill of hexograms centered at p.
Additional path/line/polyline stroke styles. NB: https://yuanchuan.dev/fun-with-stroke-dasharray.
Datum consolidating style preferences.
@ central
For rotated text.
@ right
Right part of text block.
@ left
Left-most part of text block.
@ end
End the text block at point.
@ start
Start the text block at point.