67 using namespace utils;
87 assert( !
tree().empty() );
107 size_t max_text_len = 0;
109 for(
auto const& node :
tree().
nodes() ) {
111 auto const& node_data = node.data<LayoutNodeData>();
112 auto const& prnt_data =
tree().
node_at( node_data.parent_index ).
data<LayoutNodeData>();
114 auto const node_spreading = 2.0 *
utils::PI * node_data.spreading * max_spreading;
115 auto const prnt_spreading = 2.0 *
utils::PI * prnt_data.spreading * max_spreading;
117 auto const node_x = node_data.distance *
radius * cos( node_spreading );
118 auto const node_y = node_data.distance *
radius * sin( node_spreading );
121 auto edge_ptr =
edge_between( node,
tree().node_at( node_data.parent_index ) );
125 auto const& edge_data = edge_ptr->data<LayoutEdgeData>();
128 auto spreading_stroke = edge_data.spreading_stroke;
129 auto distance_stroke = edge_data.distance_stroke;
134 auto start_a = prnt_spreading;
135 auto end_a = node_spreading;
136 if( prnt_spreading > node_spreading ) {
141 auto const dist_start_x = prnt_data.distance *
radius * cos( node_spreading );
142 auto const dist_start_y = prnt_data.distance *
radius * sin( node_spreading );
145 tree_lines << SvgPath(
146 {
svg_arc( 0, 0, prnt_data.distance *
radius, start_a, end_a ) },
148 SvgFill( SvgFill::Type::kNone )
150 tree_lines << SvgLine(
151 dist_start_x, dist_start_y,
157 if( ! edge_data.shape.empty() ) {
158 auto const shape_x = ( dist_start_x + node_x ) / 2.0;
159 auto const shape_y = ( dist_start_y + node_y ) / 2.0;
161 auto es = edge_data.shape;
162 es.transform.append( SvgTransform::Translate( shape_x, shape_y ));
163 edge_shapes << std::move( es );
175 auto label_dist = node_data.distance *
radius;
185 taxa_lines << SvgLine(
187 label_dist * cos( node_spreading ),
188 label_dist * sin( node_spreading ),
189 node_data.spacer_stroke
194 if( node_data.name !=
"" ) {
199 label.text = node_data.name;
200 label.alignment_baseline = SvgText::AlignmentBaseline::kMiddle;
203 label.transform.append( SvgTransform::Translate(
204 ( label_dist + 10 ) * cos( node_spreading ),
205 ( label_dist + 10 ) * sin( node_spreading )
211 node_data.spreading * max_spreading > 0.25 &&
212 node_data.spreading * max_spreading <= 0.75
215 label.anchor = SvgText::Anchor::kEnd;
216 label.transform.append( SvgTransform::Rotate(
217 360 * node_data.spreading * max_spreading + 180
221 label.transform.append( SvgTransform::Rotate(
222 360 * node_data.spreading * max_spreading
226 taxa_names << std::move( label );
227 max_text_len = std::max( max_text_len, node_data.name.size() );
231 if( ! node_data.shape.empty() ) {
232 auto ns = node_data.shape;
233 ns.transform.append( SvgTransform::Translate( node_x, node_y ));
234 node_shapes << std::move( ns );
240 tree_lines.reverse();
243 auto const marg = std::max( 30.0, max_text_len *
text_template().font.size );
244 doc.margin = SvgMargin( marg );
247 doc << std::move( tree_lines );
248 if( ! taxa_lines.empty() ) {
249 doc << std::move( taxa_lines );
251 if( ! taxa_names.empty() ) {
252 doc << std::move( taxa_names );
254 if( ! edge_shapes.empty() ) {
255 doc << std::move( edge_shapes );
257 if( ! node_shapes.empty() ) {
258 doc << std::move( node_shapes );