A library for working with phylogenetic and population genetic data.
v0.32.0
utils/formats/svg/helper.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2022 Lucas Czech
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lczech@carnegiescience.edu>
20  Department of Plant Biology, Carnegie Institution For Science
21  260 Panama Street, Stanford, CA 94305, USA
22 */
23 
32 
34 
35 #include <algorithm>
36 #include <limits>
37 #include <ostream>
38 
39 namespace genesis {
40 namespace utils {
41 
42 // =================================================================================================
43 // Svg Helper Functions
44 // =================================================================================================
45 
46 // -------------------------------------------------------------
47 // svg_arc
48 // -------------------------------------------------------------
49 
50 std::string svg_arc(
51  double center_x, double center_y, double radius,
52  double start_angle, double end_angle,
53  bool wedge
54 ) {
55  std::string large_arc;
56  if( start_angle > end_angle ) {
57  large_arc = ( end_angle - start_angle <= utils::PI ? "1" : "0" );
58  } else {
59  large_arc = ( end_angle - start_angle <= utils::PI ? "0" : "1" );
60  }
61 
62  double start_x = center_x + ( radius * std::cos( end_angle ));
63  double start_y = center_y + ( radius * std::sin( end_angle ));
64  double end_x = center_x + ( radius * std::cos( start_angle ));
65  double end_y = center_y + ( radius * std::sin( start_angle ));
66 
67  std::ostringstream os;
68  if( wedge ) {
69  os << "M " << center_x << " " << center_y << " ";
70  os << "L " << start_x << " " << start_y << " ";
71  } else {
72  os << "M " << start_x << " " << start_y << " ";
73  }
74  os << "A " << radius << " " << radius << " ";
75  os << 0 << " " << large_arc << " " << 0 << " ";
76  os << end_x << " " << end_y;
77  if( wedge ) {
78  os << " L " << center_x << " " << center_y << " ";
79  }
80  return os.str();
81 }
82 
83 // -------------------------------------------------------------
84 // svg_bounding_box
85 // -------------------------------------------------------------
86 
88  std::vector<SvgPoint> const& points
89 ) {
90  if( points.size() == 0 ) {
91  return {};
92  // throw std::runtime_error(
93  // "Cannot calculate bounding box of Polyline without any points."
94  // );
95  }
96 
97  // Without transformations: Get the box around the points.
98  auto minmax_x = std::minmax_element(
99  points.begin(), points.end(),
100  []( SvgPoint lhs, SvgPoint rhs ){ return lhs.x < rhs.x; }
101  );
102  auto minmax_y = std::minmax_element(
103  points.begin(), points.end(),
104  []( SvgPoint lhs, SvgPoint rhs ){ return lhs.y < rhs.y; }
105  );
106  return {
107  SvgPoint( minmax_x.first->x, minmax_y.first->y ),
108  SvgPoint( minmax_x.second->x, minmax_y.second->y )
109  };
110 }
111 
113  std::vector<SvgPoint> const& points,
114  SvgTransform const& transform
115 ) {
116  if( points.size() == 0 ) {
117  return {};
118  // throw std::runtime_error(
119  // "Cannot calculate bounding box of Polyline without any points."
120  // );
121  }
122 
123  // Init the boundaries.
124  auto min_x = std::numeric_limits<double>::infinity();
125  auto max_x = - std::numeric_limits<double>::infinity();
126  auto min_y = std::numeric_limits<double>::infinity();
127  auto max_y = - std::numeric_limits<double>::infinity();
128 
129  // Transform all points individually, and capture their coordinates.
130  for( auto const& p : points ) {
131  auto const tr_point = transform.apply( p );
132  min_x = std::min( min_x, tr_point.x );
133  max_x = std::max( max_x, tr_point.x );
134  min_y = std::min( min_y, tr_point.y );
135  max_y = std::max( max_y, tr_point.y );
136  }
137  return {
138  SvgPoint( min_x, min_y ),
139  SvgPoint( max_x, max_y )
140  };
141 }
142 
143 } // namespace utils
144 } // namespace genesis
helper.hpp
genesis::utils::SvgTransform::apply
SvgPoint apply(SvgPoint const &p) const
Apply all transformations to a point, and return the new transformed coordinate.
Definition: attributes.cpp:363
genesis::utils::svg_arc
std::string svg_arc(double center_x, double center_y, double radius, double start_angle, double end_angle, bool wedge)
Create an arc to use in an SvgPath.
Definition: utils/formats/svg/helper.cpp:50
genesis::utils::SvgBox
Definition: utils/formats/svg/helper.hpp:127
genesis::utils::SvgPoint
Definition: utils/formats/svg/helper.hpp:57
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::SvgTransform
Definition: attributes.hpp:238
attributes.hpp
genesis::utils::svg_bounding_box
SvgBox svg_bounding_box(std::vector< SvgPoint > const &points)
Compute the bounding box of a set of points.
Definition: utils/formats/svg/helper.cpp:87