Loading...
Searching...
No Matches
TreeSVG.h
1/*
2
3MIT License
4
5Copyright (c) 2023 FMI Open Development / Markus Peura, first.last@fmi.fi
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26/*
27Part of Rack development has been done in the BALTRAD projects part-financed
28by the European Union (European Regional Development Fund and European
29Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30*/
31/*
32 * TreeSVG.h
33 *
34 * Created on: Jun 24, 2012
35 * Author: mpeura
36 */
37
38#ifndef DRAIN_TREE_SVG
39#define DRAIN_TREE_SVG
40
41#include <drain/image/AlignAnchorSVG.h>
42#include "drain/util/EnumFlags.h"
43#include "drain/util/FileInfo.h"
44#include "drain/util/Frame.h"
45#include "drain/util/SelectorXML.h"
46#include "drain/util/TreeXML.h"
47#include "TransformSVG.h"
48
49namespace drain {
50
51namespace image {
52
53class NodeSVG;
54
55typedef drain::UnorderedMultiTree<NodeSVG,false, NodeXML<>::path_t> TreeSVG;
56//typedef NodeXML<NodeSVG>::xml_tree_t TreeSVG;
57
58struct svg {
59
60 typedef float coord_t;
61
62 enum tag_t {
63 UNDEFINED=XML::UNDEFINED,
64 COMMENT=XML::COMMENT,
65 CTEXT=XML::CTEXT,
66 SCRIPT=XML::SCRIPT,
67 STYLE=XML::STYLE,
68 STYLE_SELECT=XML::STYLE_SELECT,
69 SVG=10,
70 CIRCLE, DESC, GROUP, LINE, IMAGE, METADATA, PATH, POLYGON, RECT, TEXT, TITLE, TSPAN };
71 // check CTEXT, maybe implement in XML
72
73};
74
75} // image::
76
77
79
80
81// template <>
82// const EnumDict<image::svg::tag_t>::dict_t EnumDict<image::svg::tag_t>::dict;
83DRAIN_ENUM_DICT(image::svg::tag_t);
84
85DRAIN_ENUM_OSTREAM(image::svg::tag_t)
86
87
88
89namespace image {
90
91class BBoxSVG : public drain::Box<svg::coord_t> {
92
93public:
94
95 inline
96 BBoxSVG(svg::coord_t x=0, svg::coord_t y=0, svg::coord_t width=0, svg::coord_t height=0) : drain::Box<svg::coord_t>(x, y, width, height) {
97 }
98
99 inline
100 BBoxSVG(const BBoxSVG & bbox) : drain::Box<svg::coord_t>(bbox) {
101 }
102
103
104 // New
105
106
107
108 // Future option - also other units!
109 /*
110 bool x_PERCENTAGE = false;
111 bool y_PERCENTAGE = false;
112 bool width_PERCENTAGE = false;
113 bool height_PERCENTAGE = false;
114 */
115};
116
117
118//typedef drain::StyleSelectorXML<NodeSVG> SelectSVG;
120
122
128// class NodeSVG: public svg, public NodeXML<svg::tag_t>, public AlignAnchorSVG {
129class NodeSVG: public NodeXML<svg::tag_t>, public AlignSVG, public AlignAnchorSVG {
130public:
131
133 static
134 std::string xlink;
135
137 static
138 std::string svg;
139
140 static
141 const drain::FileInfo fileInfo;
142
143
145 NodeSVG(svg::tag_t t = svg::UNDEFINED);
146
148 NodeSVG(const NodeSVG & node);
149
150 inline virtual
151 ~NodeSVG(){};
152
153 inline
154 bool isAbstract() const {
155 return typeIs(
156 svg::tag_t::STYLE,
157 svg::tag_t::DESC,
158 svg::tag_t::METADATA,
159 svg::tag_t::SCRIPT,
160 svg::tag_t::TITLE,
161 svg::tag_t::TSPAN
162 );
163 }
164
166 virtual inline
167 bool isSingular() const override final {
168 return false;
169 }
170
171
173 inline
174 NodeSVG & operator=(const NodeSVG & node){
175 if (!typeIsSet()){
176 setType(node.getType());
177 handleType();
178 //handleType(node.getNativeType());
179 }
180 XML::xmlAssignNode(*this, node);
181 return *this;
182 }
183
185 inline
186 NodeSVG & operator=(const std::initializer_list<Variable::init_pair_t > &l){
187 set(l);
188 return *this;
189 }
190
191 template <class T>
192 inline
193 NodeSVG & operator=(const T & arg){
194 set(arg);
195 //assign(arg);
196 return *this;
197 }
198
199 inline
200 NodeSVG & operator=(xml_tag_t type){
201 setType(type);
202 return *this;
203 }
204
205 // Dangerous, if XML has codes not registered by SVG?
206 /*
207 inline
208 NodeSVG & operator=(xml_tag_t type){
209 setType(type);
210 return *this;
211 }
212 */
213
214
215 /* Well, every graphic obj may have DESC and TITLE?
216 virtual
217 bool isSingular() const override final;
218 */
219
221 virtual
222 void setAttribute(const std::string & key, const std::string &value) override;
223
225 virtual
226 void setAttribute(const std::string & key, const char *value) override;
227
228
229
231 inline
232 const BBoxSVG & getBoundingBox() const {
233 return box;
234 }
235 // Consider also with conversion: getBoundingBox(Box<T> &b)
236
238 inline
240 return box;
241 }
242
244 template <typename T>
245 inline
247 setLocation(b);
248 setFrame(b);
249 // setAttribute("data:bbox", StringBuilder<' '>(b.x, b.y, b.getWidth(), b.getHeight()));
250 }
251
252 template <typename T>
253 inline
254 void setViewBox(const drain::Box<T> & bb){
255 setViewBox(bb.x, bb.y, bb.width, bb.height);
256 //set("viewBox", drain::StringBuilder<' '>(bb.x, bb.y, bb.width, bb.height));
257 // setAttribute("data:bbox", StringBuilder<' '>(b.x, b.y, b.getWidth(), b.getHeight()));
258 }
259
260 template <typename T>
261 inline
262 void setViewBox(T & x, T & y, T & width, T & height){
263 set("viewBox", drain::StringBuilder<' '>(x, y, width, height).str());
264 }
265
267 template <typename T>
268 inline
269 void setLocation(const drain::Point2D<T> & point){
270 box.x = point.x;
271 box.y = point.y;
272 }
273
278 template <typename T>
279 inline
280 void setLocation(const T & x, const T & y){
281 box.setLocation(x, y);
282 }
283
284 template <typename T>
285 inline
286 void setFrame(const drain::Frame2D<T> & frame){
287 box.width = frame.width;
288 box.height = frame.height;
289 }
290
295 template <typename T>
296 inline
297 void setFrame(const T & w, const T & h){
298 box.setArea(w, h);
299 }
300
301
306 template <typename T>
307 inline
308 void setWidth(T w){
309 box.width = w;
310 }
311
312 inline
313 svg::coord_t getWidth(){
314 return box.width;
315 }
316
318
321 template <typename T>
322 inline
323 void setMargin(T w){
324 link("data-margin", box.width);
325 box.width = w;
326 }
327
329
332 inline
333 svg::coord_t getMargin(){
334 return box.width;
335 }
336
337
342 template <typename T>
343 inline
344 void setHeight(T h){
345 if (typeIs(svg::TEXT)){
346 link("data-height", box.height);
347 }
348 box.height = h;
349 }
350
351 inline
352 svg::coord_t getHeight(){
353 return box.height;
354 }
355
357 void setFontSize(svg::coord_t size, svg::coord_t elemHeight = 0.0);
358
359 TransformSVG transform;
360
362
368 virtual
369 void specificAttributesToStream(std::ostream & ostr) const override;
370
371
372 void swapSVG(NodeSVG & node);
373
374protected:
375
376 virtual
377 void handleType() override final;
378
379
380 virtual
381 void updateAlign() override;
382
383 //drain::Box<coord_t> box;
384 BBoxSVG box;
385 // consider:
386 // bool x_PERCENTAGE = false;
387 // bool y_PERCENTAGE = false;
388 // svg:
389
390 // int radius = 0;
391
392};
393
394
395/*
396template <typename P, typename A,typename V>
397void NodeSVG::setAlign(const P & pos, const A & axis, const V &value){
398 alignments[p][a] = v;
399}
400*/
401
402
403// Utility
405
406public:
407
408 inline
409 NodePrinter(const NodeSVG & node){
410 std::stringstream sstr;
411 sstr << "<" << node.getTag();
412 if (::atoi(node.getId().c_str())==0){
413 sstr << " id=" << node.getId();
414 }
415 if (node.getName().isValid()){
416 sstr << " name=" << node.getName();
417 }
418 if (!node.getClasses().empty()){
419 sstr << " class=[" << node.getClasses() << ']';
420 }
421 sstr << '>';
422 id = sstr.str();
423 }
424
425 const std::string & str() const {
426 return id;
427 }
428
429
430protected:
431
432 std::string id;
433
434};
435
436
437//typedef NodeSVG::xml_tree_t TreeSVG;
438
439
440} // image::
441
442
443/*
444inline
445std::ostream & operator<<(std::ostream &ostr, const image::NodeSVG & node){
446 return node.nodeToStream(ostr);
447}
448*/
449
450
451template <>
452template <>
453class NodeXML<image::svg::tag_t>::Elem<image::svg::tag_t::RECT>{
454public:
455
456 inline
457 Elem(image::NodeSVG & node) : node(node = image::svg::tag_t::RECT), x(node["x"]), y(node["y"]), width(node["width"]), height(node["height"]){
458 };
459
461
464 FlexibleVariable & width;
465 FlexibleVariable & height;
466};
467
468
469
470template <>
471template <>
472class NodeXML<image::svg::tag_t>::Elem<image::svg::tag_t::CIRCLE>{
473public:
474
476
477 inline
478 Elem(image::NodeSVG & node) : node(node = image::svg::tag_t::CIRCLE), cx(node["cx"]), cy(node["cy"]), r(node["r"] = 0.0){
479 };
480
481 // Center point, x coord
482 FlexibleVariable & cx;
483 // Center point, y coord
484 FlexibleVariable & cy;
485 // Radius
487
488 // NodeXML<T> class could not access NodeSVG.box
489 // Elem(image::NodeSVG & node) : node(node = image::svg::tag_t::CIRCLE), cx(node.box.x), cy(node.box.y), r(node["r"]){
490
491};
492
493template <>
494template <>
495class NodeXML<image::svg::tag_t>::Elem<image::svg::tag_t::POLYGON>{
496public:
497
498 inline
499 Elem(image::NodeSVG & node) : node(node = image::svg::tag_t::POLYGON), points(node["points"]), writablePoints(node["points"]){
500 };
501
503
504 const FlexibleVariable & points;
505
506protected:
507
508 FlexibleVariable & writablePoints;
509
510public:
511
512 void clear(){
513 writablePoints.clear();
514 }
515
516 template <typename T>
517 inline
518 void append(const T &x, const T &y){
519 writablePoints << x << ',' << y << ' ';
520 }
521
522 template <typename T>
523 inline
524 void append(drain::Point2D<T> &p){
525 writablePoints << p.x << ',' << p.y << ' ';
526 }
527
528};
529
530
531} // drain::
532
533
534inline
535std::ostream & operator<<(std::ostream &ostr, const drain::image::NodeSVG & node){
536 return node.nodeToStream(ostr);
537}
538
539
540
541inline
542std::ostream & operator<<(std::ostream &ostr, const drain::image::TreeSVG & tree){
543 return drain::image::NodeSVG::docToStream(ostr, tree);
544}
545
546
547
548namespace drain {
549
550DRAIN_TYPENAME(image::NodeSVG);
551DRAIN_TYPENAME(image::svg::tag_t);
552
553
554template <>
555const NodeXML<image::svg::tag_t>::xml_default_elem_map_t NodeXML<image::svg::tag_t>::xml_default_elems;
556
557/*
558template <>
559template <typename K, typename V>
560image::TreeSVG & image::TreeSVG::operator=(std::initializer_list<std::pair<K,V> > args){
561 drain::Logger mout(__FILE__, __FUNCTION__);
562 mout.attention("initlist pair<K,V>: ", args);
563 data.set(args); // what about TreeSVG & arg
564 return *this;
565}
566*/
567
568
569template <> // referring to Tree<NodeSVG>
570template <> // referring to tparam T
571inline
572image::TreeSVG & image::TreeSVG::operator=(const std::string & arg){
573 XML::xmlAssignString(*this, arg);
574 return *this;
575}
576
577
578template <> // referring to Tree<NodeSVG>
579inline
580image::TreeSVG & image::TreeSVG::operator=(std::initializer_list<std::pair<const char *,const Variable> > l){
581//image::TreeSVG & image::TreeSVG::operator=(std::initializer_list<std::pair<const char *,const char *> > l){
582 return XML::xmlAssign(*this, l);
583}
584
585
586template <>
587template <class T>
588image::TreeSVG & image::TreeSVG::operator=(const T & arg){
589 return XML::xmlAssign(*this, arg);
590 /*
591 data.set(arg); // what about TreeSVG & arg
592 return *this;
593 */
594}
595
597
604template <> // for T - Tree class
605template <> // for K - operator() argument
606// inline
607image::TreeSVG & image::TreeSVG::operator()(const image::svg::tag_t & type);
608/*
609{
610 return XML::xmlSetType(*this, type);
611}
612*/
613
614
616template <> // for T (Tree class)
617template <> // for K (path elem arg)
618image::TreeSVG & image::TreeSVG::operator[](const image::svg::tag_t & type);
619
621template <> // for T (Tree class)
622template <> // for K (path elem arg)
623const image::TreeSVG & image::TreeSVG::operator[](const image::svg::tag_t & type) const ;
624
625
626template <>
627inline
628image::TreeSVG & image::TreeSVG::addChild(const image::TreeSVG::key_t & key){
629 return XML::xmlAddChild(*this, key);
630}
631
632
633template <> // for T (Tree class)
634template <> // for K (path elem arg)
635bool image::TreeSVG::hasChild(const image::svg::tag_t & type) const;
636
637
638/*
639template <>
640template <class K>
641const image::TreeSVG::key_t & image::TreeSVG::getKey(const K & key){
642 return EnumDict<K>::dict.getKey(key, false);
643}
644*/
645
646/* tested 2025/01/20 but caused problems with Hi5Tree("dataset2") etc.
647template <>
648template <typename K> // for K (path elem arg)
649const image::TreeSVG::key_t & image::TreeSVG::getKey(const K & key){
650 return EnumDict<K>::dict.getKey(key, false);
651}
652
653template <>
654template <> // for K (path elem arg)
655inline
656const image::TreeSVG::key_t & image::TreeSVG::getKey(const drain::StyleSelectorXML<image::NodeSVG> & selector){
657 return selector;
658}
659
660*/
661
662} // drain::
663
664#endif // DRAIN_TREE_SVG
665
Two-way mapping between strings and objects of template class T.
Definition Dictionary.h:63
Definition FileInfo.h:48
Something that has width and height.
Definition Frame.h:55
A "handle" for specialized element classes, i.e. with members like width , height or radius .
Definition TreeXML.h:92
Definition TreeXML.h:341
virtual std::ostream & nodeToStream(std::ostream &ostr, tag_display_mode mode=EMPTY_TAG) const override
Dumps info. Future option: outputs leading and ending tag.
Definition TreeXML.h:483
static std::ostream & docToStream(std::ostream &ostr, const V &tree)
Definition TreeXML.h:733
ref_t & link(const std::string &key, F &x)
Associates a map entry with a variable.
Definition ReferenceMap.h:84
Currently used only as CSS element selector.
Definition SelectorXML.h:50
Definition StringBuilder.h:58
VariableT is a final class applied through typedefs Variable, Reference and FlexibleVariable.
Definition VariableT.h:87
bool typeIsSet() const
Return true, if type is any of the arguments.
Definition XML.h:144
static T & xmlAssign(T &dst, const T &src)
Assign another tree structure to another.
Definition XML.h:616
const std::string & getId() const
Returns ID of this element. Hopefully a unique ID...
Definition TreeXML.h:142
static TX & xmlAssignString(TX &tree, const std::string &s)
When assigning a string, create new element unless the element itself is of type CTEXT.
Definition XML.h:732
static T & xmlAddChild(T &tree, const std::string &key)
Definition XML.h:782
static N & xmlAssignNode(N &dst, const N &src)
Assign tree node (data) to another.
Definition XML.h:661
std::string id
Some general-purpose.
Definition TreeXML.h:95
Definition TreeSVG.h:91
Definition TreeSVG.h:404
Definition TreeSVG.h:129
void setBoundingBox(const drain::Box< T > &b)
Set position (x,y), width and height of an object.
Definition TreeSVG.h:246
void setLocation(const T &x, const T &y)
Definition TreeSVG.h:280
virtual void setAttribute(const std::string &key, const std::string &value) override
Set attribute value, handling units in string arguments, like in "50%" or "640px".
Definition TreeSVG.cpp:241
const BBoxSVG & getBoundingBox() const
Get position (x,y), width and height of an object.
Definition TreeSVG.h:232
NodeSVG & operator=(const NodeSVG &node)
Copy data from a node. (Does not copy subtree.)
Definition TreeSVG.h:174
static std::string xlink
In opening SVG tag, referred to by attribute "xmlns:xlink".
Definition TreeSVG.h:134
void setMargin(T w)
Set margin of a TEXT element (non-standard).
Definition TreeSVG.h:323
void setWidth(T w)
Definition TreeSVG.h:308
NodeSVG & operator=(const std::initializer_list< Variable::init_pair_t > &l)
Copy data from a node. (Does not copy subtree.)
Definition TreeSVG.h:186
virtual void specificAttributesToStream(std::ostream &ostr) const override
Write transform, in addition to XML::ClassList.
Definition TreeSVG.cpp:344
svg::coord_t getMargin()
Get margin of a TEXT element (non-standard).
Definition TreeSVG.h:333
void setFontSize(svg::coord_t size, svg::coord_t elemHeight=0.0)
Sets font size and also text elem "height".
Definition TreeSVG.cpp:250
void setHeight(T h)
Definition TreeSVG.h:344
virtual bool isSingular() const override final
If true, render always as single elem (without child elems)
Definition TreeSVG.h:167
void setLocation(const drain::Point2D< T > &point)
Set position (x,y) of an object.
Definition TreeSVG.h:269
BBoxSVG & getBoundingBox()
Get position (x,y), width and height of an object.
Definition TreeSVG.h:239
void setFrame(const T &w, const T &h)
Definition TreeSVG.h:297
static std::string svg
In opening SVG tag, referred to by attributes "xmlns" and "xmlns:svg".
Definition TreeSVG.h:138
Definition TransformSVG.h:90
Definition DataSelector.cpp:1277
DRAIN_TYPENAME(void)
Add a specialization for each type of those you want to support.
Something that has coordinates (x,y) and dimensions (width, height).
Definition Frame.h:221
Definition Point.h:48
Adapter designed for NodeSVG.
Definition AlignAnchorSVG.h:161
User-friendly programming interface for alignment considering two elements.
Definition AlignSVG.h:222
Definition TreeSVG.h:58