A library for working with phylogenetic and population genetic data.
v0.27.0
utils/formats/svg/helper.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_FORMATS_SVG_HELPER_H_
2 #define GENESIS_UTILS_FORMATS_SVG_HELPER_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2020 Lucas Czech and HITS gGmbH
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lucas.czech@h-its.org>
23  Exelixis Lab, Heidelberg Institute for Theoretical Studies
24  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
25 */
26 
36 
37 #include <algorithm>
38 #include <cmath>
39 #include <ostream>
40 #include <sstream>
41 #include <string>
42 #include <vector>
43 
44 namespace genesis {
45 namespace utils {
46 
47 // =================================================================================================
48 // Svg Point
49 // =================================================================================================
50 
51 struct SvgPoint
52 {
53  explicit SvgPoint( double x = 0.0, double y = 0.0 )
54  : x(x)
55  , y(y)
56  {}
57 
58  double x;
59  double y;
60 };
61 
62 // =================================================================================================
63 // Svg Size
64 // =================================================================================================
65 
66 struct SvgSize
67 {
68  explicit SvgSize( double width = 0.0, double height = 0.0 )
69  : width(width)
70  , height(height)
71  {}
72 
73  double width;
74  double height;
75 };
76 
77 // =================================================================================================
78 // Svg Margin
79 // =================================================================================================
80 
81 struct SvgMargin
82 {
83  explicit SvgMargin()
84  : SvgMargin( 0.0, 0.0, 0.0, 0.0 )
85  {}
86 
87  explicit SvgMargin( double all )
88  : SvgMargin( all, all, all, all )
89  {}
90 
91  explicit SvgMargin( double top_bottom, double right_left )
92  : SvgMargin( top_bottom, right_left, top_bottom, right_left )
93  {}
94 
95  explicit SvgMargin( double top, double right_left, double bottom )
96  : SvgMargin( top, right_left, bottom, right_left )
97  {}
98 
99  explicit SvgMargin( double top, double right, double bottom, double left )
100  : top(top)
101  , right(right)
102  , bottom(bottom)
103  , left(left)
104  {}
105 
106  double top;
107  double right;
108  double bottom;
109  double left;
110 };
111 
112 // =================================================================================================
113 // Svg (Bounding) Box
114 // =================================================================================================
115 
116 struct SvgBox
117 {
118  SvgBox() = default;
119 
121  : top_left(top_left)
123  {
124  // Make it fool-proof.
125  if( bottom_right.x < top_left.x ) {
127  }
128  if( bottom_right.y < top_left.y ) {
130  }
131  }
132 
133  SvgBox( SvgPoint top_left_v, double width, double height )
134  : top_left(top_left_v)
136  {
137  // Allow negative size.
138  if( width < 0.0 ) {
140  }
141  if( height < 0.0 ) {
143  }
144  }
145 
146  double width() const
147  {
148  return bottom_right.x - top_left.x;
149  }
150 
151  double height() const
152  {
153  return bottom_right.y - top_left.y;
154  }
155 
156  SvgSize size() const
157  {
158  return SvgSize( width(), height() );
159  }
160 
161  bool empty() const
162  {
163  // If everything is zero, this either is an uninitialized default box, or we are at the
164  // big bang, where everything is condensed into one point. Either way, this means there
165  // is no bounding box, as the singularity does not have a dimension.
166  return top_left.x == 0.0 && top_left.y == 0.0 &&
167  bottom_right.x == 0.0 && bottom_right.y == 0.0;
168  }
169 
170  static SvgBox combine( SvgBox const& lhs, SvgBox const& rhs )
171  {
172  // If any of the two boxes is empty, return the other one.
173  // (If both are empty, this also returns an empty box.)
174  if( lhs.empty() ) {
175  return rhs;
176  }
177  if( rhs.empty() ) {
178  return lhs;
179  }
180 
181  return {
182  SvgPoint(
183  std::min( lhs.top_left.x, rhs.top_left.x ),
184  std::min( lhs.top_left.y, rhs.top_left.y )
185  ),
186  SvgPoint(
187  std::max( lhs.bottom_right.x, rhs.bottom_right.x ),
188  std::max( lhs.bottom_right.y, rhs.bottom_right.y )
189  )
190  };
191  }
192 
195 
196 };
197 
198 // =================================================================================================
199 // Svg Drawing Options
200 // =================================================================================================
201 
203 {
204  double offset_x = 0.0;
205  double offset_y = 0.0;
206 };
207 
208 // =================================================================================================
209 // Svg Helper Functions
210 // =================================================================================================
211 
212 inline std::string svg_comment( std::string const& content )
213 {
214  return "<!-- " + content + " -->";
215 }
216 
217 template< typename T >
218 std::string svg_attribute(
219  std::string const& name,
220  T const& value,
221  std::string const& unit = ""
222 ) {
223  std::stringstream ss;
224  ss << " " << name << "=\"" << value << unit << "\"";
225  return ss.str();
226 }
227 
240 inline std::string svg_arc(
241  double center_x, double center_y, double radius, double start_angle, double end_angle
242 ) {
243  std::string large_arc;
244  if( start_angle > end_angle ) {
245  large_arc = ( end_angle - start_angle <= utils::PI ? "1" : "0" );
246  } else {
247  large_arc = ( end_angle - start_angle <= utils::PI ? "0" : "1" );
248  }
249 
250  double start_x = center_x + ( radius * std::cos( end_angle ));
251  double start_y = center_y + ( radius * std::sin( end_angle ));
252  double end_x = center_x + ( radius * std::cos( start_angle ));
253  double end_y = center_y + ( radius * std::sin( start_angle ));
254 
255  std::ostringstream os;
256  os << "M " << start_x << " " << start_y << " ";
257  os << "A " << radius << " " << radius << " " << 0 << " " << large_arc << " " << 0 << " ";
258  os << end_x << " " << end_y;
259  return os.str();
260 }
261 
262 inline std::string svg_data_uri(
263  std::string const& media_type,
264  std::string const& content,
265  bool encode_base64 = false
266 ) {
267  return "data:" + media_type + (
268  encode_base64
269  ? ( ";base64," + base64_encode( content ))
270  : ( "," + content )
271  );
272 }
273 
274 // template< typename T >
275 // std::string svg_style(
276 // std::string const& name,
277 // T const& value,
278 // std::string const& unit = ""
279 // ) {
280 // std::stringstream ss;
281 // ss << name << ":\"" << value << unit << "\" ";
282 // return ss.str();
283 // }
284 
285 } // namespace utils
286 } // namespace genesis
287 
288 #endif // include guard
genesis::utils::SvgMargin::bottom
double bottom
Definition: utils/formats/svg/helper.hpp:108
genesis::placement::swap
void swap(Sample &lhs, Sample &rhs)
Definition: sample.cpp:104
genesis::utils::svg_data_uri
std::string svg_data_uri(std::string const &media_type, std::string const &content, bool encode_base64=false)
Definition: utils/formats/svg/helper.hpp:262
genesis::utils::SvgPoint::x
double x
Definition: utils/formats/svg/helper.hpp:58
genesis::utils::SvgBox::combine
static SvgBox combine(SvgBox const &lhs, SvgBox const &rhs)
Definition: utils/formats/svg/helper.hpp:170
genesis::utils::SvgPoint::y
double y
Definition: utils/formats/svg/helper.hpp:59
genesis::utils::SvgMargin::SvgMargin
SvgMargin(double top, double right_left, double bottom)
Definition: utils/formats/svg/helper.hpp:95
genesis::utils::svg_comment
std::string svg_comment(std::string const &content)
Definition: utils/formats/svg/helper.hpp:212
common.hpp
genesis::utils::base64_encode
std::string base64_encode(std::vector< std::uint8_t > const &input, size_t line_length)
Definition: base64.cpp:258
genesis::utils::SvgBox::SvgBox
SvgBox()=default
genesis::utils::SvgMargin::SvgMargin
SvgMargin(double all)
Definition: utils/formats/svg/helper.hpp:87
genesis::utils::SvgMargin::top
double top
Definition: utils/formats/svg/helper.hpp:106
genesis::utils::SvgBox::top_left
SvgPoint top_left
Definition: utils/formats/svg/helper.hpp:193
genesis::utils::SvgDrawingOptions::offset_y
double offset_y
Definition: utils/formats/svg/helper.hpp:205
genesis::utils::SvgBox
Definition: utils/formats/svg/helper.hpp:116
genesis::utils::SvgDrawingOptions::offset_x
double offset_x
Definition: utils/formats/svg/helper.hpp:204
genesis::utils::SvgBox::bottom_right
SvgPoint bottom_right
Definition: utils/formats/svg/helper.hpp:194
genesis::utils::SvgMargin
Definition: utils/formats/svg/helper.hpp:81
genesis::utils::SvgBox::width
double width() const
Definition: utils/formats/svg/helper.hpp:146
genesis::utils::SvgPoint
Definition: utils/formats/svg/helper.hpp:51
genesis::utils::SvgBox::size
SvgSize size() const
Definition: utils/formats/svg/helper.hpp:156
genesis::utils::SvgBox::SvgBox
SvgBox(SvgPoint top_left_v, double width, double height)
Definition: utils/formats/svg/helper.hpp:133
genesis::utils::SvgMargin::SvgMargin
SvgMargin()
Definition: utils/formats/svg/helper.hpp:83
genesis::utils::SvgBox::empty
bool empty() const
Definition: utils/formats/svg/helper.hpp:161
genesis::utils::SvgMargin::SvgMargin
SvgMargin(double top, double right, double bottom, double left)
Definition: utils/formats/svg/helper.hpp:99
genesis::utils::PI
constexpr double PI
Make the world go round.
Definition: common.hpp:55
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::utils::SvgBox::height
double height() const
Definition: utils/formats/svg/helper.hpp:151
genesis::utils::SvgMargin::right
double right
Definition: utils/formats/svg/helper.hpp:107
genesis::utils::svg_attribute
std::string svg_attribute(std::string const &name, T const &value, std::string const &unit="")
Definition: utils/formats/svg/helper.hpp:218
genesis::utils::SvgSize
Definition: utils/formats/svg/helper.hpp:66
base64.hpp
genesis::utils::SvgSize::width
double width
Definition: utils/formats/svg/helper.hpp:73
genesis::utils::SvgSize::SvgSize
SvgSize(double width=0.0, double height=0.0)
Definition: utils/formats/svg/helper.hpp:68
genesis::utils::SvgMargin::SvgMargin
SvgMargin(double top_bottom, double right_left)
Definition: utils/formats/svg/helper.hpp:91
genesis::utils::SvgSize::height
double height
Definition: utils/formats/svg/helper.hpp:74
genesis::utils::SvgDrawingOptions
Definition: utils/formats/svg/helper.hpp:202
genesis::utils::SvgBox::SvgBox
SvgBox(SvgPoint top_left, SvgPoint bottom_right)
Definition: utils/formats/svg/helper.hpp:120
genesis::utils::SvgMargin::left
double left
Definition: utils/formats/svg/helper.hpp:109
genesis::utils::svg_arc
std::string svg_arc(double center_x, double center_y, double radius, double start_angle, double end_angle)
Create an arc to use in an SvgPath.
Definition: utils/formats/svg/helper.hpp:240
genesis::utils::SvgPoint::SvgPoint
SvgPoint(double x=0.0, double y=0.0)
Definition: utils/formats/svg/helper.hpp:53