A toolkit for working with phylogenetic data.
v0.20.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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-2018 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 
35 
36 #include <algorithm>
37 #include <ostream>
38 #include <sstream>
39 #include <string>
40 #include <vector>
41 
42 namespace genesis {
43 namespace utils {
44 
45 // =================================================================================================
46 // Svg Point
47 // =================================================================================================
48 
49 struct SvgPoint
50 {
51  explicit SvgPoint( double x = 0.0, double y = 0.0 )
52  : x(x)
53  , y(y)
54  {}
55 
56  double x;
57  double y;
58 };
59 
60 // =================================================================================================
61 // Svg Size
62 // =================================================================================================
63 
64 struct SvgSize
65 {
66  explicit SvgSize( double width = 0.0, double height = 0.0 )
67  : width(width)
68  , height(height)
69  {}
70 
71  double width;
72  double height;
73 };
74 
75 // =================================================================================================
76 // Svg Margin
77 // =================================================================================================
78 
79 struct SvgMargin
80 {
81  explicit SvgMargin()
82  : SvgMargin( 0.0, 0.0, 0.0, 0.0 )
83  {}
84 
85  explicit SvgMargin( double all )
86  : SvgMargin( all, all, all, all )
87  {}
88 
89  explicit SvgMargin( double top_bottom, double right_left )
90  : SvgMargin( top_bottom, right_left, top_bottom, right_left )
91  {}
92 
93  explicit SvgMargin( double top, double right_left, double bottom )
94  : SvgMargin( top, right_left, bottom, right_left )
95  {}
96 
97  explicit SvgMargin( double top, double right, double bottom, double left )
98  : top(top)
99  , right(right)
100  , bottom(bottom)
101  , left(left)
102  {}
103 
104  double top;
105  double right;
106  double bottom;
107  double left;
108 };
109 
110 // =================================================================================================
111 // Svg (Bounding) Box
112 // =================================================================================================
113 
114 struct SvgBox
115 {
116  SvgBox() = default;
117 
119  : top_left(top_left)
120  , bottom_right(bottom_right)
121  {
122  // Make it fool-proof.
123  if( bottom_right.x < top_left.x ) {
124  std::swap( bottom_right.x, top_left.x );
125  }
126  if( bottom_right.y < top_left.y ) {
127  std::swap( bottom_right.y, top_left.y );
128  }
129  }
130 
131  SvgBox( SvgPoint top_left_v, double width, double height )
132  : top_left(top_left_v)
133  , bottom_right( top_left.x + width, top_left.y + height )
134  {
135  // Allow negative size.
136  if( width < 0.0 ) {
138  }
139  if( height < 0.0 ) {
141  }
142  }
143 
144  double width() const
145  {
146  return bottom_right.x - top_left.x;
147  }
148 
149  double height() const
150  {
151  return bottom_right.y - top_left.y;
152  }
153 
154  SvgSize size() const
155  {
156  return SvgSize( width(), height() );
157  }
158 
159  bool empty() const
160  {
161  // If everything is zero, this either is an uninitialized default box, or we are at the
162  // big bang, where everything is condensed into one point. Either way, this means there
163  // is no bounding box, as the singularity does not have a dimension.
164  return top_left.x == 0.0 && top_left.y == 0.0 &&
165  bottom_right.x == 0.0 && bottom_right.y == 0.0;
166  }
167 
168  static SvgBox combine( SvgBox const& lhs, SvgBox const& rhs )
169  {
170  // If any of the two boxes is empty, return the other one.
171  // (If both are empty, this also returns an empty box.)
172  if( lhs.empty() ) {
173  return rhs;
174  }
175  if( rhs.empty() ) {
176  return lhs;
177  }
178 
179  return {
180  SvgPoint(
181  std::min( lhs.top_left.x, rhs.top_left.x ),
182  std::min( lhs.top_left.y, rhs.top_left.y )
183  ),
184  SvgPoint(
185  std::max( lhs.bottom_right.x, rhs.bottom_right.x ),
186  std::max( lhs.bottom_right.y, rhs.bottom_right.y )
187  )
188  };
189  }
190 
193 
194 };
195 
196 // =================================================================================================
197 // Svg Drawing Options
198 // =================================================================================================
199 
201 {
202  double offset_x = 0.0;
203  double offset_y = 0.0;
204 };
205 
206 // =================================================================================================
207 // Svg Helper Functions
208 // =================================================================================================
209 
210 inline std::string svg_comment( std::string const& content )
211 {
212  return "<!-- " + content + " -->";
213 }
214 
215 template< typename T >
216 std::string svg_attribute(
217  std::string const& name,
218  T const& value,
219  std::string const& unit = ""
220 ) {
221  std::stringstream ss;
222  ss << " " << name << "=\"" << value << unit << "\"";
223  return ss.str();
224 }
225 
238 inline std::string svg_arc(
239  double center_x, double center_y, double radius, double start_angle, double end_angle
240 ) {
241  std::string large_arc;
242  if( start_angle > end_angle ) {
243  large_arc = ( end_angle - start_angle <= utils::PI ? "1" : "0" );
244  } else {
245  large_arc = ( end_angle - start_angle <= utils::PI ? "0" : "1" );
246  }
247 
248  double start_x = center_x + ( radius * cos( end_angle ));
249  double start_y = center_y + ( radius * sin( end_angle ));
250  double end_x = center_x + ( radius * cos( start_angle ));
251  double end_y = center_y + ( radius * sin( start_angle ));
252 
253  std::ostringstream os;
254  os << "M " << start_x << " " << start_y << " ";
255  os << "A " << radius << " " << radius << " " << 0 << " " << large_arc << " " << 0 << " ";
256  os << end_x << " " << end_y;
257  return os.str();
258 }
259 
260 // template< typename T >
261 // std::string svg_style(
262 // std::string const& name,
263 // T const& value,
264 // std::string const& unit = ""
265 // ) {
266 // std::stringstream ss;
267 // ss << name << ":\"" << value << unit << "\" ";
268 // return ss.str();
269 // }
270 
271 } // namespace utils
272 } // namespace genesis
273 
274 #endif // include guard
static SvgBox combine(SvgBox const &lhs, SvgBox const &rhs)
SvgPoint(double x=0.0, double y=0.0)
void swap(SequenceSet &lhs, SequenceSet &rhs)
std::string svg_attribute(std::string const &name, T const &value, std::string const &unit="")
SvgMargin(double top, double right_left, double bottom)
SvgSize(double width=0.0, double height=0.0)
std::string svg_comment(std::string const &content)
constexpr double PI
Make the world go round.
Definition: common.hpp:49
SvgBox(SvgPoint top_left_v, double width, double height)
SvgMargin(double top, double right, double bottom, double left)
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.
SvgMargin(double top_bottom, double right_left)
SvgBox(SvgPoint top_left, SvgPoint bottom_right)