DGtal  0.6.devel
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Shapes.cpp
1 /* -*- mode: c++ -*- */
9 /*
10  * \@copyright This File is part of the Board library which is
11  * licensed under the terms of the GNU Lesser General Public Licence.
12  * See the LICENCE file for further details.
13  */
14 #include "Board/Rect.h"
15 #include "Board/Shapes.h"
16 #include "Board/Tools.h"
17 #include "Board/PSFonts.h"
18 #include <cmath>
19 #include <cstring>
20 #include <vector>
21 #include <sstream>
22 
23 #include <assert.h>
24 
25 #ifndef M_PI
26 #define M_PI 3.14159265358979323846 /* pi */
27 #endif
28 
29 #ifdef _MSC_VER
30 //#define NOMINMAX
31 //#include <windows.h>
32 #endif
33 
34 namespace {
35 const char * xFigDashStylesPS[] = {
36  " [] 0 sd ", // SolidStyle
37  " [1 1] 0 sd ", // DashStyle
38  " [1.5 4.5] 45 sd ", // DotStyle
39  " [4.5 2.3 1.5 2.3] 0 sd ", // DashDotStyle
40  " [4.5 2.0 1.5 1.5 1.5 2.0] 0 sd ", // DashDotDotStyle
41  " [4.5 1.8 1.5 1.4 1.5 1.4 1.5 1.8 ] 0 sd " // DashDotDotDotStyle
42 };
43 
44 const char * xFigDashStylesSVG[] = {
45  "", // SolidStyle
46  "stroke-dasharray:1,1;stroke-dashoffset:0", // DashStyle
47  "stroke-dasharray:1.5,4.5;stroke-dashoffset:45", // DotStyle
48  "stroke-dasharray:4.5,2.3,1.5,2.3;stroke-dashoffset:0", // DashDotStyle
49  "stroke-dasharray:4.5,2.0,1.5,1.5,1.5,2.0;stroke-dashoffset;0", // DashDotDotStyle
50  "stroke-dasharray:4.5,1.8,1.5,1.4,1.5,1.4,1.5,1.8;stroke-dashoffset:0" // DashDotDotDotStyle
51 };
52 
53 const char * xFigDashStylesTikZ[] = {
54  "", // SolidStyle
55  "dash pattern=on 1pt off 1pt,", // DashStyle
56  "dotted,", // DotStyle
57  "dashdotted,", // DashDotStyle
58  "dashdotdotted,", // DashDotDotStyle
59  "dash pattern=on 2pt off 3pt on 4pt off 4pt," // DashDotDotDotStyle
60 };
61 
62 #ifdef WITH_CAIRO
63 // cairo
64 cairo_line_cap_t cairoLineCap[] = {
65  CAIRO_LINE_CAP_BUTT,
66  CAIRO_LINE_CAP_ROUND,
67  CAIRO_LINE_CAP_SQUARE
68 };
69 
70 cairo_line_join_t cairoLineJoin[] = {
71  CAIRO_LINE_JOIN_MITER,
72  CAIRO_LINE_JOIN_ROUND,
73  CAIRO_LINE_JOIN_BEVEL
74 };
75 
76 #define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0]))
77 
78 const double cairoSolidStyle[] = {1, 0}; const double cairoSolidStyle_offset = 0;
79 const double cairoDashStyle[] = {1, 1}; const double cairoDashStyle_offset = 0;
80 const double cairoDotStyle[] = {1.5, 4.5}; const double cairoDotStyle_offset = 45;
81 const double cairoDashDotStyle[] = {4.5, 2.3, 1.5, 2.3}; const double cairoDashDotStyle_offset = 0;
82 const double cairoDashDotDotStyle[] = {4.5, 2.0, 1.5, 1.5, 1.5, 2.0}; const double cairoDashDotDotStyle_offset = 0;
83 const double cairoDashDotDotDotStyle[] = {4.5, 1.8, 1.5, 1.4, 1.5, 1.4, 1.5, 1.8}; const double cairoDashDotDotDotStyle_offset = 0;
84 // cairo
85 #endif
86 }
87 
88 //todo cairo: gouraudtriangle, text (?)
89 //todo cairo: group (?)
90 
91 namespace LibBoard {
92 
93 extern const char * XFigPostscriptFontnames[];
94 
95 bool
96 shapeGreaterDepth( const Shape *s1, const Shape *s2 )
97 {
98  return s1->depth() > s2->depth();
99 }
100 
101 const std::string Shape::_name("AbstractShape");
102 
103 const std::string &
104 Shape::name() const
105 {
106  return _name;
107 }
108 
109 std::string
110 Shape::svgProperties( const TransformSVG & transform ) const
111 {
112  static const char * capStrings[3] = { "butt", "round", "square" };
113  static const char * joinStrings[3] = { "miter", "round", "bevel" };
114  std::stringstream str;
115  if ( _penColor != DGtal::Color::None ) {
116  str << " fill=\"" << _fillColor.svg() << '"'
117  << " stroke=\"" << _penColor.svg() << '"'
118  << " stroke-width=\"" << transform.mapWidth( _lineWidth ) << "mm\""
119  << " style=\"stroke-linecap:" << capStrings[ _lineCap ]
120  << ";stroke-linejoin:" << joinStrings[ _lineJoin ];
121  if ( _lineStyle != SolidStyle )
122  str << ";" << xFigDashStylesSVG[ _lineStyle ];
123  str << '"'
124  << _fillColor.svgAlpha( " fill" )
125  << _penColor.svgAlpha( " stroke" );
126  } else {
127  str << " fill=\"" << _fillColor.svg() << '"'
128 // << " stroke=\"" << _fillColor.svg() << '"'
129 // << " stroke-width=\"0.5px\""
130  << " stroke=\"none\""
131  << " stroke-width=\"0\""
132  << " style=\"stroke-linecap:round;stroke-linejoin:round;"
133  << '"'
134  << _fillColor.svgAlpha( " fill" )
135  << _fillColor.svgAlpha( " stroke" );
136  }
137  return str.str();
138 }
139 
140 std::string
142 {
143  std::stringstream str;
144  str << _lineWidth << " slw ";
145  str << _lineCap << " slc ";
146  str << _lineJoin << " slj";
147  str << xFigDashStylesPS[ _lineStyle ];
148 
149  return str.str();
150 }
151 
152 #ifdef WITH_CAIRO
153 void
154 Shape::setCairoDashStyle(cairo_t *cr, LineStyle type) const
155 {
156  switch (type)
157  {
158  case SolidStyle:
159  cairo_set_dash (cr, cairoSolidStyle, ARRAY_SIZE(cairoSolidStyle), cairoSolidStyle_offset); break;
160  case DashStyle:
161  cairo_set_dash (cr, cairoDashStyle, ARRAY_SIZE(cairoDashStyle), cairoDashStyle_offset); break;
162  case DotStyle:
163  cairo_set_dash (cr, cairoDotStyle, ARRAY_SIZE(cairoDotStyle), cairoDotStyle_offset); break;
164  case DashDotStyle:
165  cairo_set_dash (cr, cairoDashDotStyle, ARRAY_SIZE(cairoDashDotStyle), cairoDashDotStyle_offset); break;
166  case DashDotDotStyle:
167  cairo_set_dash (cr, cairoDashDotDotStyle, ARRAY_SIZE(cairoDashDotDotStyle), cairoDashDotDotStyle_offset); break;
168  case DashDotDotDotStyle:
169  cairo_set_dash (cr, cairoDashDotDotDotStyle, ARRAY_SIZE(cairoDashDotDotDotStyle), cairoDashDotDotDotStyle_offset); break;
170 
171  default: // SolidStyle
172  cairo_set_dash (cr, cairoSolidStyle, ARRAY_SIZE(cairoSolidStyle), cairoSolidStyle_offset);
173  }
174 }
175 #endif
176 
177 std::string
178 Shape::tikzProperties( const TransformTikZ & transform ) const
179 {
180  static const char * capStrings[3] = { "" /* initial value "butt" */, "line cap=round,", "line cap=rect," };
181  static const char * joinStrings[3] = { "" /* initial value "miter" */, "line join=round", "line join=bevel" };
182 
183  std::stringstream str;
184  str << "fill=" << _fillColor.tikz() << ',';
185  str << "draw=" << _penColor.tikz() << ',';
186  str << "line width=" << transform.mapWidth( _lineWidth ) << "mm,";
187  str << xFigDashStylesTikZ[ _lineStyle ];
188  str << capStrings[ _lineCap ];
189  str << joinStrings[ _lineJoin ];
190 
191  return str.str();
192 }
193 
194 void
195 Shape::depth( int d )
196 {
197  _depth = d;
198 }
199 
200 void
201 Shape::shiftDepth( int shift )
202 {
203  _depth += shift;
204 }
205 
206 /*
207  * Dot
208  */
209 
210 const std::string Dot::_name("Dot");
211 
212 const std::string &
213 Dot::name() const
214 {
215  return _name;
216 }
217 
218 Point
219 Dot::center() const {
220  return Point( _x, _y );
221 }
222 
223 Dot &
224 Dot::rotate( double angle, const Point & rotCenter )
225 {
226  Point( _x, _y ).rotate( angle, rotCenter ).get( _x, _y );
227  return *this;
228 }
229 
230 Dot
231 Dot::rotated( double angle, const Point & rotCenter ) const
232 {
233  return Dot(*this).rotate( angle, rotCenter );
234 }
235 
236 Dot &
237 Dot::rotate( double )
238 {
239  return *this;
240 }
241 
242 Dot
243 Dot::rotated( double ) const
244 {
245  return *this;
246 }
247 
248 Dot &
249 Dot::translate( double dx, double dy )
250 {
251  _x += dx;
252  _y += dy;
253  return *this;
254 }
255 
256 Dot
257 Dot::translated( double dx, double dy ) const
258 {
259  return Dot(*this).translate( dx, dy );
260 }
261 
262 Shape &
263 Dot::scale( double , double )
264 {
265  return *this;
266 }
267 
268 Shape &
269 Dot::scale( double )
270 {
271  return *this;
272 }
273 
274 Dot
275 Dot::scaled( double , double ) const
276 {
277  return *this;
278 }
279 
280 Dot
281 Dot::scaled( double ) const
282 {
283  return *this;
284 }
285 
286 void
287 Dot::scaleAll( double s )
288 {
289  _x *= s;
290  _y *= s;
291 }
292 
293 void
294 Dot::flushPostscript( std::ostream & stream,
295  const TransformEPS & transform ) const
296 {
297  stream << "\n% Dot\n";
298  stream << postscriptProperties() << " "
299  << "n "
300  << transform.mapX( _x ) << " "
301  << transform.mapY( _y ) << " "
302  << "m "
303  << transform.mapX( _x ) << " "
304  << transform.mapY( _y ) << " "
305  << "l " << _penColor.postscript() << " srgb stroke" << std::endl;
306 }
307 
308 void
309 Dot::flushFIG( std::ostream & stream,
310  const TransformFIG & transform,
311  std::map<Color,int> & colormap ) const
312 {
313  stream << "2 1 0 ";
314  // Thickness
315  stream << ( _penColor.valid()?transform.mapWidth( _lineWidth ):0 ) << " ";
316  // Pen color
317  stream << colormap[ _penColor ] << " ";
318  // Fill color
319  stream << "0 ";
320  // Depth
321  stream << transform.mapDepth( _depth ) << " ";
322  // Pen style
323  stream << "-1 ";
324  // Area fill, style val, join style, cap style, radius, f_arrow, b_arrow
325  stream << "-1 0.000 " << _lineJoin << " " << _lineCap << " -1 0 0 ";
326  // Number of points
327  stream << "2\n";
328  stream << " ";
329  stream << static_cast<int>( transform.mapX( _x ) ) << " "
330  << static_cast<int>( transform.mapY( _y ) ) << " "
331  << static_cast<int>( transform.mapX( _x ) ) << " "
332  << static_cast<int>( transform.mapY( _y ) ) << std::endl;
333 }
334 
335 void
336 Dot::flushSVG( std::ostream & stream,
337  const TransformSVG & transform ) const
338 {
339  stream << "<line x1=\"" << transform.mapX( _x ) << "\""
340  << " y1=\"" << transform.mapY( _y ) << "\""
341  << " x2=\"" << transform.mapX( _x ) << "\""
342  << " y2=\"" << transform.mapY( _y ) << "\""
343  << svgProperties( transform )
344  << " />" << std::endl;
345 }
346 
347 #ifdef WITH_CAIRO
348 void
349 Dot::flushCairo( cairo_t *cr,
350  const TransformCairo & transform ) const
351 {
352  cairo_save (cr);
353 
354  cairo_set_source_rgba (cr, _penColor.red()/255.0, _penColor.green()/255.0, _penColor.blue()/255.0, 1.);
355 
356  cairo_move_to (cr, transform.mapX( _x ), transform.mapY( _y ));
357  cairo_line_to (cr, transform.mapX( _x ), transform.mapY( _y ));
358 
359  cairo_set_line_width (cr, _lineWidth);
360  cairo_set_line_cap (cr, cairoLineCap[_lineCap]);
361  cairo_set_line_join (cr, cairoLineJoin[_lineJoin]);
362  setCairoDashStyle (cr, _lineStyle);
363 
364  cairo_stroke (cr);
365 
366  cairo_restore (cr);
367 }
368 #endif
369 
370 void
371 Dot::flushTikZ( std::ostream & stream,
372  const TransformTikZ & /*transform*/ ) const
373 
374 {
375  // FIXME: unimplemented
376  stream << "% FIXME: Dot::flushTikZ unimplemented" << endl;
377 }
378 
379 Rect
380 Dot::boundingBox() const
381 {
382  return Rect( _x, _y, 0.0, 0.0 );
383 }
384 
385 Dot *
386 Dot::clone() const {
387  return new Dot(*this);
388 }
389 
390 /*
391  * Line
392  */
393 
394 const std::string Line::_name("Line");
395 
396 const std::string &
397 Line::name() const
398 {
399  return _name;
400 }
401 
402 Point
403 Line::center() const {
404  return 0.5 * Point( _x1 + _x2, _y1 + _y2 );
405 }
406 
407 Line &
408 Line::rotate( double angle, const Point & rotCenter )
409 {
410  Point( _x1, _y1 ).rotate( angle, rotCenter ).get( _x1, _y1 );
411  Point( _x2, _y2 ).rotate( angle, rotCenter ).get( _x2, _y2 );
412  return *this;
413 }
414 
415 Line &
416 Line::rotate( double angle )
417 {
418  return Line::rotate( angle, center() );
419 }
420 
421 Line
422 Line::rotated( double angle, const Point & rotCenter ) const
423 {
424  Line res(*this);
425  Point( _x1, _y1 ).rotate( angle, rotCenter ).get( res._x1, res._y1 );
426  Point( _x2, _y2 ).rotate( angle, rotCenter ).get( res._x2, res._y2 );
427  return res;
428 }
429 
430 Line
431 Line::rotated( double angle ) const
432 {
433  Line res(*this);
434  Point c = center();
435  Point( _x1, _y1 ).rotate( angle, c ).get( res._x1, res._y1 );
436  Point( _x2, _y2 ).rotate( angle, c ).get( res._x2, res._y2 );
437  return res;
438 }
439 
440 Line &
441 Line::translate( double dx, double dy )
442 {
443  _x1 += dx;
444  _x2 += dx;
445  _y1 += dy;
446  _y2 += dy;
447  return *this;
448 }
449 
450 Line
451 Line::translated( double dx, double dy ) const
452 {
453  Line res(*this);
454  res._x1 += dx;
455  res._x2 += dx;
456  res._y1 += dy;
457  res._y2 += dy;
458  return *this;
459 }
460 
461 Shape &
462 Line::scale( double sx, double sy )
463 {
464  Point c = center();
465  _x1 *= sx;
466  _x2 *= sx;
467  _y1 *= sy;
468  _y2 *= sy;
469  Point delta = c - center();
470  translate( delta.x, delta.y );
471  return *this;
472 }
473 
474 Shape &
475 Line::scale( double s )
476 {
477  scale( s, s );
478  return (*this);
479 }
480 
481 Line
482 Line::scaled( double sx, double sy ) const
483 {
484  Line res(*this);
485  Point c = center();
486  res._x1 *= sx;
487  res._x2 *= sx;
488  res._y1 *= sy;
489  res._y2 *= sy;
490  Point delta = c - res.center();
491  return res.translate( delta.x, delta.y );
492 }
493 
494 Line
495 Line::scaled( double s ) const
496 {
497  return Line::scaled( s , s );
498 }
499 
500 void
501 Line::scaleAll( double s )
502 {
503  _x1 *= s;
504  _y1 *= s;
505  _x2 *= s;
506  _y2 *= s;
507 }
508 
509 Line *
510 Line::clone() const {
511  return new Line(*this);
512 }
513 
514 void
515 Line::flushPostscript( std::ostream & stream,
516  const TransformEPS & transform ) const
517 {
518  stream << "\n% Line\n";
519  stream << postscriptProperties() << " "
520  << "n "
521  << transform.mapX( _x1 ) << " "
522  << transform.mapY( _y1 ) << " "
523  << "m "
524  << transform.mapX( _x2 ) << " "
525  << transform.mapY( _y2 ) << " "
526  << "l " << _penColor.postscript() << " srgb stroke" << std::endl;
527 }
528 
529 void
530 Line::flushFIG( std::ostream & stream,
531  const TransformFIG & transform,
532  std::map<DGtal::Color,int> & colormap ) const
533 {
534  stream << "2 1 ";
535  // Line style
536  stream << _lineStyle << " ";
537  // Thickness
538  stream << ( _penColor.valid()?transform.mapWidth( _lineWidth ):0 ) << " ";
539  // Pen color
540  stream << colormap[ _penColor ] << " ";
541  // Fill color
542  stream << "0 ";
543  // Depth
544  stream << transform.mapDepth( _depth ) << " ";
545  // Pen style
546  stream << "-1 ";
547  // Area fill, style val, join style, cap style, radius, f_arrow, b_arrow
548  stream << "-1 " << (_lineStyle?"4.000 ":"0.000 ") << _lineJoin << " " << _lineCap << " -1 0 0 ";
549  // Number of points
550  stream << "2\n";
551  stream << " ";
552  stream << static_cast<int>( transform.mapX( _x1 ) ) << " "
553  << static_cast<int>( transform.mapY( _y1 ) ) << " "
554  << static_cast<int>( transform.mapX( _x2 ) ) << " "
555  << static_cast<int>( transform.mapY( _y2 ) ) << std::endl;
556 }
557 
558 void
559 Line::flushSVG( std::ostream & stream,
560  const TransformSVG & transform ) const
561 {
562  stream << "<line x1=\"" << transform.mapX( _x1 ) << "\""
563  << " y1=\"" << transform.mapY( _y1 ) << "\""
564  << " x2=\"" << transform.mapX( _x2 ) << "\""
565  << " y2=\"" << transform.mapY( _y2 ) << "\""
566  << svgProperties( transform )
567  << " />" << std::endl;
568 }
569 
570 #ifdef WITH_CAIRO
571 void
572 Line::flushCairo( cairo_t *cr,
573  const TransformCairo & transform ) const
574 {
575  cairo_save (cr);
576 
577  cairo_set_source_rgba (cr, _penColor.red()/255.0, _penColor.green()/255.0, _penColor.blue()/255.0, 1.);
578 
579  cairo_move_to (cr, transform.mapX( _x1 ), transform.mapY( _y1 ));
580  cairo_line_to (cr, transform.mapX( _x2 ), transform.mapY( _y2 ));
581 
582  cairo_set_line_width (cr, _lineWidth);
583  cairo_set_line_cap (cr, cairoLineCap[_lineCap]);
584  cairo_set_line_join (cr, cairoLineJoin[_lineJoin]);
585  setCairoDashStyle (cr, _lineStyle);
586 
587  cairo_stroke (cr);
588 
589  cairo_restore (cr);
590 }
591 #endif
592 
593 void
594 Line::flushTikZ( std::ostream & stream,
595  const TransformTikZ & transform ) const
596 {
597  stream << "\\path[" << tikzProperties(transform) << "] ("
598  << transform.mapX( _x1 ) << ',' << transform.mapY( _y1 )
599  << ") -- ("
600  << transform.mapX( _x2 ) << ',' << transform.mapY( _y2 )
601  << ");" << std::endl;
602 }
603 
604 Rect
605 Line::boundingBox() const
606 {
607  Rect rect;
608  if ( _x1 > _x2 ) {
609  rect.width = _x1 - _x2;
610  rect.left = _x2;
611  } else {
612  rect.width = _x2 - _x1;
613  rect.left = _x1;
614  }
615  if ( _y1 > _y2 ) {
616  rect.top = _y1;
617  rect.height = _y1 - _y2;
618  } else {
619  rect.top = _y2;
620  rect.height = _y2 - _y1;
621  }
622  return rect;
623 }
624 
625 
626 
627 /*
628  * Image
629  */
630 
631 const std::string Image::_name("Image");
632 
633 const std::string &
634 Image::name() const
635 {
636  return _name;
637 }
638 
639 Image *
640 Image::clone() const {
641  return new Image(*this);
642 }
643 
644 void
645 Image::flushFIG( std::ostream & stream,
646  const TransformFIG & transform,
647  std::map<DGtal::Color,int> & colormap ) const
648 
649 {
650  stream << "2 5 ";
651  // Line style
652  stream << _lineStyle << " ";
653  // Thickness
654  stream << ( _penColor.valid()?transform.mapWidth( _lineWidth ):0 ) << " ";
655  // Pen color
656  stream << colormap[ _penColor ] << " ";
657  // Fill color
658  stream << "0 ";
659  // Depth
660  stream << transform.mapDepth( _depth ) << " "
661  << "-1 -1 0.000 0 0 -1 0 0 5" << std::endl <<" 0 "
662  << _filename << std::endl;
663  _path.flushFIG( stream, transform );
664  stream << std::endl;
665 }
666 
667 
668 
669 void
670 Image::flushSVG( std::ostream & stream,
671  const TransformSVG & transform ) const
672 {
673 
674  stream << "<image x=\"" << transform.mapX( _path[0].x ) << '"'
675  << " y=\"" << transform.mapY( _path[0].y ) << '"'
676  << " width=\"" << transform.scale( (_path[1] - _path[0]).norm() ) << '"'
677  << " height=\"" << transform.scale( (_path[0] - _path[3]).norm() ) << '"'
678  << " xlink:href=\""<< _filename << "\" >" << std::endl
679  << " <title>My image</title>"<<std::endl
680  << " </image>" << std::endl;
681 
682 
683 }
684 
685 #ifdef WITH_CAIRO
686 void
687 Image::flushCairo( cairo_t *cr,
688  const TransformCairo & transform ) const
689 {
690  int w, h;
691  cairo_surface_t *image;
692 
693  cairo_save (cr);
694 
695  image = cairo_image_surface_create_from_png (_filename.c_str());
696  assert(cairo_surface_status (image) == CAIRO_STATUS_SUCCESS);
697  w = cairo_image_surface_get_width (image);
698  h = cairo_image_surface_get_height (image);
699 
700  // tr
701  cairo_translate (cr, transform.mapX( _path[0].x ), transform.mapY( _path[0].y ));
702  //cairo_scale (cr, transform.scale( _path[1].x - _path[0].x )/w, transform.scale( _path[0].y - _path[3].y )/h);
703  cairo_scale (cr, transform.scale( (_path[1] - _path[0]).norm() )/w, transform.scale( (_path[0] - _path[3]).norm() )/h);
704  // tr
705 
706  cairo_set_source_surface (cr, image, 0, 0);
707  cairo_paint_with_alpha(cr, _alpha);
708  cairo_surface_destroy (image);
709 
710  cairo_restore (cr);
711 }
712 #endif
713 
714 void
715 Image::flushTikZ( std::ostream & stream,
716  const TransformTikZ & transform ) const
717 
718 {
719  stream << "\\node [below right=0pt] at ("
720  << transform.mapX( _path[0].x ) << "pt,"
721  << transform.mapY( _path[0].y ) << "pt) {\\pgfimage["
722  << "width=" << transform.scale( (_path[1] - _path[0]).norm() ) << "pt,"
723  << "height=" << transform.scale( (_path[0] - _path[3]).norm() ) << "pt,"
724  << "]{" << _filename << "}};" << endl;
725 }
726 
727 /*
728  * Arrow
729  */
730 
731 const std::string Arrow::_name("Arrow");
732 
733 const std::string &
734 Arrow::name() const
735 {
736  return _name;
737 }
738 
739 Arrow
740 Arrow::rotated( double angle, const Point & rotCenter ) const
741 {
742  Arrow res(*this);
743  Point( _x1, _y1 ).rotate( angle, rotCenter ).get( res._x1, res._y1 );
744  Point( _x2, _y2 ).rotate( angle, rotCenter ).get( res._x2, res._y2 );
745  return res;
746 }
747 
748 Arrow
749 Arrow::rotated( double angle ) const
750 {
751  Arrow res(*this);
752  Point c = center();
753  Point( _x1, _y1 ).rotate( angle, c ).get( res._x1, res._y1 );
754  Point( _x2, _y2 ).rotate( angle, c ).get( res._x2, res._y2 );
755  return res;
756 }
757 
758 Arrow
759 Arrow::translated( double dx, double dy ) const
760 {
761  Arrow res(*this);
762  res._x1 += dx;
763  res._x2 += dx;
764  res._y1 += dy;
765  res._y2 += dy;
766  return res;
767 }
768 
769 Arrow
770 Arrow::scaled( double sx, double sy ) const
771 {
772  Arrow res(*this);
773  Point c = center();
774  res._x1 *= sx;
775  res._x2 *= sx;
776  res._y1 *= sy;
777  res._y2 *= sy;
778  Point delta = c - res.center();
779  return static_cast<Arrow &>( res.translate( delta.x, delta.y ) );
780 }
781 
782 Arrow
783 Arrow::scaled( double s ) const
784 {
785  return Arrow::scaled( s, s );
786 }
787 
788 Arrow *
789 Arrow::clone() const {
790  return new Arrow(*this);
791 }
792 
793 void
794 Arrow::flushPostscript( std::ostream & stream,
795  const TransformEPS & transform ) const
796 {
797  double dx = _x1 - _x2;
798  double dy = _y1 - _y2;
799  double norm = sqrt( dx*dx + dy*dy );
800  dx /= norm;
801  dy /= norm;
802  dx *= 10*_lineWidth;
803  dy *= 10*_lineWidth;
804 
805  // double back_x = 0.8 * dx + _x2;
806  // double back_y = 0.8 * dy + _y2;
807 
808  double ndx1 = dx*cos(0.3)-dy*sin(0.3);
809  double ndy1 = dx*sin(0.3)+dy*cos(0.3);
810  double ndx2 = dx*cos(-0.3)-dy*sin(-0.3);
811  double ndy2 = dx*sin(-0.3)+dy*cos(-0.3);
812 
813  stream << "\n% Arrow\n";
814  stream << _penColor.postscript() << " srgb "
815  << postscriptProperties() << " "
816  << "n "
817  << transform.mapX( _x1 ) << " "
818  << transform.mapY( _y1 ) << " "
819  << "m "
820  << transform.mapX( _x2 + ( dx * cos(0.3) ) ) << " "
821  << transform.mapY( _y2 + ( dy * cos(0.3) ) ) << " "
822  << "l stroke" << std::endl;
823 
824  if ( filled() ) {
825  stream << "n "
826  << transform.mapX( _x2 ) + transform.scale( ndx1 ) << " "
827  << transform.mapY( _y2 ) + transform.scale( ndy1 ) << " "
828  << "m "
829  << transform.mapX( _x2 ) << " "
830  << transform.mapY( _y2 ) << " l "
831  << transform.mapX( _x2 ) + transform.scale( ndx2 ) << " "
832  << transform.mapY( _y2 ) + transform.scale( ndy2 ) << " ";
833  stream << "l cp " << _penColor.postscript() << " srgb fill" << std::endl;
834  }
835 
836  stream << "n "
837  << transform.mapX( _x2 ) + transform.scale( ndx1 ) << " "
838  << transform.mapY( _y2 ) + transform.scale( ndy1 ) << " "
839  << "m "
840  << transform.mapX( _x2 ) << " "
841  << transform.mapY( _y2 ) << " l "
842  << transform.mapX( _x2 ) + transform.scale( ndx2 ) << " "
843  << transform.mapY( _y2 ) + transform.scale( ndy2 ) << " l"
844  << " " << _penColor.postscript() << " srgb cp [] 0 sd stroke" << std::endl;
845 }
846 
847 void
848 Arrow::flushFIG( std::ostream & stream,
849  const TransformFIG & transform,
850  std::map<DGtal::Color,int> & colormap ) const
851 {
852  stream << "2 1 ";
853  // Line style
854  stream << _lineStyle << " ";
855  // Thickness
856  stream << ( _penColor.valid()?transform.mapWidth( _lineWidth ):0 ) << " ";
857  // Pen color
858  stream << colormap[ _penColor ] << " ";
859  // Fill color
860  stream << colormap[ _penColor ] << " ";
861  // Depth
862  stream << transform.mapDepth( _depth ) << " ";
863  // Pen style
864  stream << "-1 ";
865  // Area fill, style val, join style, cap style, radius, f_arrow, b_arrow
866  stream << "-1 " << (_lineStyle?"4.000 ":"0.000 ") << _lineJoin << " " << _lineCap << " -1 1 0 ";
867  // Number of points
868  stream << "2\n";
869  if ( filled() )
870  stream << " 1 1 1.00 60.00 120.00\n";
871  else
872  stream << " 1 0 1.00 60.00 120.00\n";
873  stream << " ";
874  stream << static_cast<int>( transform.mapX( _x1 ) ) << " "
875  << static_cast<int>( transform.mapY( _y1 ) ) << " "
876  << static_cast<int>( transform.mapX( _x2 ) ) << " "
877  << static_cast<int>( transform.mapY( _y2 ) ) << std::endl;
878 }
879 
880 void
881 Arrow::flushSVG( std::ostream & stream,
882  const TransformSVG & transform ) const
883 {
884  double dx = _x1 - _x2;
885  double dy = _y1 - _y2;
886  double norm = sqrt( dx*dx + dy*dy );
887  dx /= norm;
888  dy /= norm;
889  dx *= 10 * _lineWidth;
890  dy *= 10 * _lineWidth;
891 
892  // double back_x = 0.8 * dx + _x2;
893  // double back_y = 0.8 * dy + _y2;
894 
895  double ndx1 = dx*cos(0.3)-dy*sin(0.3);
896  double ndy1 = dx*sin(0.3)+dy*cos(0.3);
897  double ndx2 = dx*cos(-0.3)-dy*sin(-0.3);
898  double ndy2 = dx*sin(-0.3)+dy*cos(-0.3);
899 
900  stream << "<g>" << std::endl;
901  // The line
902  stream << " <path "
903  << "d=\"M " << transform.mapX( _x1 ) << " " << transform.mapY( _y1 )
904  << " L " << transform.mapX( _x2 + ( dx * cos(0.3) ) )
905  << " " << transform.mapY( _y2 + ( dy * cos(0.3) ) ) << " z\""
906  << " fill=\"none\" stroke=\"" << _penColor.svg() << "\""
907  << _penColor.svgAlpha( " stroke" );
908  if ( _lineStyle != SolidStyle )
909  stream << " style=\"" << xFigDashStylesSVG[ _lineStyle ] << '"';
910  stream << " stroke-width=\"" << transform.mapWidth( _lineWidth ) << "mm\" />";
911 
912  // The arrow
913  stream << " <polygon";
914  stream << " fill=\"" << _fillColor.svg() << "\"";
915  stream << " stroke=\"" << _penColor.svg() << "\""
916  << " stroke-width=\"" << transform.mapWidth( /* 0.33 * */ _lineWidth ) << "mm\""
917  << " style=\"stroke-linecap:butt;stroke-linejoin:miter\""
918  << _fillColor.svgAlpha( " fill" )
919  << _penColor.svgAlpha( " stroke" )
920  << " points=\""
921  << transform.mapX( _x2 ) + transform.scale( ndx1 ) << ","
922  << transform.mapY( _y2 ) - transform.scale( ndy1 ) << " "
923  << transform.mapX( _x2 ) << ","
924  << transform.mapY( _y2 ) << " "
925  << transform.mapX( _x2 ) + transform.scale( ndx2 ) << ","
926  << transform.mapY( _y2 ) - transform.scale( ndy2 ) << " "
927  << transform.mapX( _x2 ) + transform.scale( ndx1 ) << ","
928  << transform.mapY( _y2 ) - transform.scale( ndy1 ) << "\" />" << std::endl;
929  stream << "</g>" << std::endl;
930 }
931 
932 #ifdef WITH_CAIRO
933 void
934 Arrow::flushCairo( cairo_t *cr,
935  const TransformCairo & transform ) const
936 {
937  double dx = _x1 - _x2;
938  double dy = _y1 - _y2;
939  double norm = sqrt( dx*dx + dy*dy );
940  dx /= norm;
941  dy /= norm;
942  dx *= 10 * _lineWidth;
943  dy *= 10 * _lineWidth;
944 
945  // double back_x = 0.8 * dx + _x2;
946  // double back_y = 0.8 * dy + _y2;
947 
948  double ndx1 = dx*cos(0.3)-dy*sin(0.3);
949  double ndy1 = dx*sin(0.3)+dy*cos(0.3);
950  double ndx2 = dx*cos(-0.3)-dy*sin(-0.3);
951  double ndy2 = dx*sin(-0.3)+dy*cos(-0.3);
952 
953  cairo_save (cr);
954 
955  // The line
956  cairo_set_source_rgba (cr, _penColor.red()/255.0, _penColor.green()/255.0, _penColor.blue()/255.0, 1.);
957 
958  cairo_move_to (cr, transform.mapX( _x1 ), transform.mapY( _y1 ));
959  cairo_line_to (cr, transform.mapX( _x2 + ( dx * cos(0.3) ) ), transform.mapY( _y2 + ( dy * cos(0.3) ) ));
960 
961  cairo_set_line_width (cr, _lineWidth);
962  cairo_set_line_cap (cr, cairoLineCap[_lineCap]);
963  cairo_set_line_join (cr, cairoLineJoin[_lineJoin]);
964  setCairoDashStyle (cr, _lineStyle);
965 
966  cairo_stroke (cr);
967 
968  // The arrow
969  cairo_set_source_rgba (cr, _fillColor.red()/255.0, _fillColor.green()/255.0, _fillColor.blue()/255.0, 1.);
970 
971  cairo_move_to (cr, transform.mapX( _x2 ) + transform.scale( ndx1 ), transform.mapY( _y2 ) - transform.scale( ndy1 ));
972  cairo_line_to (cr, transform.mapX( _x2 ), transform.mapY( _y2 ));
973  cairo_line_to (cr, transform.mapX( _x2 ) + transform.scale( ndx2 ), transform.mapY( _y2 ) - transform.scale( ndy2 ));
974  cairo_close_path (cr);
975 
976  if ( filled() )
977  {
978  if ( _penColor != DGtal::Color::None )
979  cairo_fill_preserve (cr);
980  else
981  cairo_fill (cr);
982  }
983 
984  //
985 
986  if ( _penColor != DGtal::Color::None )
987  {
988  cairo_set_source_rgba (cr, _penColor.red()/255.0, _penColor.green()/255.0, _penColor.blue()/255.0, 1.);
989 
990  cairo_set_line_width (cr, _lineWidth);
991  cairo_set_line_cap (cr, cairoLineCap[ButtCap]);
992  cairo_set_line_join (cr, cairoLineJoin[MiterJoin]);
993  setCairoDashStyle (cr, SolidStyle);
994 
995  cairo_stroke (cr);
996  }
997 
998  cairo_restore (cr);
999 }
1000 #endif
1001 
1002 void
1003 Arrow::flushTikZ( std::ostream & stream,
1004  const TransformTikZ & transform ) const
1005 {
1006  //stream << "\\path[-triangle 45," << tikzProperties(transform) << "] (" // Requires \usetikzlibrary{arrows}
1007  stream << "\\path[-latex," << tikzProperties(transform) << "] ("
1008  << transform.mapX( _x1 ) << ',' << transform.mapY( _y1 )
1009  << ") -- ("
1010  << transform.mapX( _x2 ) << ',' << transform.mapY( _y2 )
1011  << ");" << std::endl;
1012 }
1013 
1014 /*
1015  * Ellipse
1016  */
1017 
1018 const std::string Ellipse::_name("Ellipse");
1019 
1020 const std::string &
1021 Ellipse::name() const
1022 {
1023  return _name;
1024 }
1025 
1026 Point
1027 Ellipse::center() const {
1028  return _center;
1029 }
1030 
1031 Ellipse &
1032 Ellipse::rotate( double angle, const Point & rotCenter )
1033 {
1034  Point c( _center );
1035  Point e = (c + Point( _xRadius, 0 )).rotate( _angle, c );
1036  Point rc = c.rotated( angle, rotCenter );
1037  Point re = e.rotated( angle, rotCenter );
1038  Point axis = re - rc;
1039  _angle = atan( axis.y / axis.x );
1040  _center = rc;
1041  return *this;
1042 }
1043 
1044 Ellipse
1045 Ellipse::rotated( double angle, const Point & rotCenter ) const
1046 {
1047  return Ellipse(*this).rotate( angle, rotCenter );
1048 }
1049 
1050 Ellipse &
1051 Ellipse::rotate( double angle )
1052 {
1053  return Ellipse::rotate( angle, center() );
1054 }
1055 
1056 Ellipse
1057 Ellipse::rotated( double angle ) const
1058 {
1059  return Ellipse(*this).rotate( angle, center() );
1060 }
1061 
1062 Ellipse &
1063 Ellipse::translate( double dx, double dy )
1064 {
1065  _center += Point( dx, dy );
1066  return *this;
1067 }
1068 
1069 Ellipse
1070 Ellipse::translated( double dx, double dy ) const
1071 {
1072  return Ellipse(*this).translate( dx, dy );
1073 }
1074 
1075 Shape &
1076 Ellipse::scale( double sx, double sy )
1077 {
1078  // Thanks to Freddie Exall for pointing an error with the first version
1079  // of this function, and for pointing to a fix as well!
1080  if ( _angle != 0 ) {
1081  double co = cos( _angle );
1082  double si = sin( _angle );
1083 
1084  // current transformation matrix
1085  double m00 = ( 1 / _xRadius ) * co;
1086  double m01 = ( 1 / _xRadius ) * si;
1087  double m10 = - ( 1 / _yRadius ) * si;
1088  double m11 = ( 1 / _yRadius ) * co;
1089 
1090  // Implicit function of ellipse at current
1091  // ax^2 + bxy + cy^2 = 1
1092  double a = ( m00 * m00 ) + ( m10 * m10 );
1093  double b = 2 * ( ( m00 * m01 ) + ( m10 * m11 ) );
1094  double c = ( m01 * m01 ) + ( m11 * m11 );
1095 
1096  // Scale coefficients ( x_new = sx * x, y_new = sy * y )
1097  a = a / ( sx * sx );
1098  b = b / ( sx * sy );
1099  c = c / ( sy * sy );
1100 
1101  if ( b == 0 ) {
1102  _angle = 0;
1103  } else if ( a == c ) {
1104  _angle = M_PI / 4;
1105  a += ( b / 2 );
1106  c -= ( b / 2 );
1107  } else {
1108  _angle = 0.5 * atan( b / ( a - c ) );
1109  double k = 1 + ( ( b * b ) / ( ( a - c ) * ( a - c ) ) );
1110  k = sqrt( k );
1111  k *= ( a - c );
1112  c += a;
1113  a = 0.5 * ( c + k );
1114  c = 0.5 * ( c - k );
1115  }
1116  _xRadius = 1 / sqrt( a );
1117  _yRadius = 1 / sqrt( c );
1118  } else {
1119  _xRadius = _xRadius * sx;
1120  _yRadius = _yRadius * sy;
1121  }
1122  return *this;
1123 }
1124 
1125 Shape &
1126 Ellipse::scale( double s )
1127 {
1128  return Ellipse::scale( s, s );
1129 }
1130 
1131 Ellipse
1132 Ellipse::scaled( double sx, double sy ) const
1133 {
1134  return static_cast<Ellipse &>( Ellipse(*this).scale( sx, sy ) );
1135 }
1136 
1137 Ellipse
1138 Ellipse::scaled( double s ) const
1139 {
1140  return static_cast<Ellipse &>( Ellipse(*this).scale( s, s ) );
1141 }
1142 
1143 void
1144 Ellipse::scaleAll( double s )
1145 {
1146  _xRadius *= s;
1147  _yRadius *= s;
1148  _center *= s;
1149 }
1150 
1151 Ellipse *
1152 Ellipse::clone() const {
1153  return new Ellipse(*this);
1154 }
1155 
1156 void
1157 Ellipse::flushPostscript( std::ostream & stream,
1158  const TransformEPS & transform ) const
1159 {
1160  double yScale = _yRadius / _xRadius;
1161  stream << "\n% Ellipse\n";
1162  if ( filled() ) {
1163  stream << "gs "
1164  << transform.mapX( _center.x ) << " " << transform.mapY( _center.y ) << " tr";
1165  if ( _angle != 0.0 ) stream << " " << (_angle*180/M_PI) << " rot ";
1166  if ( ! _circle ) stream << " " << 1.0 << " " << yScale << " sc";
1167  stream << " n " << transform.scale( _xRadius ) << " 0 m "
1168  << " 0 0 " << transform.scale( _xRadius ) << " 0.0 360.0 arc ";
1169  stream << " " << _fillColor.postscript() << " srgb";
1170  stream << " fill gr" << std::endl;
1171  }
1172 
1173  if ( _penColor != DGtal::Color::None ) {
1174  stream << postscriptProperties() << "\n";
1175  stream << "gs " << transform.mapX( _center.x ) << " " << transform.mapY( _center.y ) << " tr";
1176  if ( _angle != 0.0 ) stream << " " << (_angle*180/M_PI) << " rot ";
1177  if ( ! _circle ) stream << " " << 1.0 << " " << yScale << " sc";
1178  stream << " n " << transform.scale( _xRadius ) << " 0 m "
1179  << " 0 0 " << transform.scale( _xRadius ) << " 0.0 360.0 arc ";
1180  stream << " " << _penColor.postscript() << " srgb";
1181  stream << " stroke gr" << std::endl;
1182  }
1183 }
1184 
1185 void
1186 Ellipse::flushFIG( std::ostream & stream,
1187  const TransformFIG & transform,
1188  std::map<DGtal::Color,int> & colormap ) const
1189 {
1190  // Ellipse, Sub type, Line style, Thickness
1191  if ( _circle )
1192  stream << "1 3 " << _lineStyle << " ";
1193  else
1194  stream << "1 1 " << _lineStyle << " ";
1195  stream << ( _penColor.valid()?transform.mapWidth( _lineWidth ):0 ) << " ";
1196  // Pen color, Fill color
1197  stream << colormap[ _penColor ] << " " << colormap[ _fillColor ] << " ";
1198  // Depth, Pen style, Area fill, Style val, Direction, angle
1199  if ( filled() )
1200  stream << transform.mapDepth( _depth ) << " -1 20 " << (_lineStyle?"4.000 ":"0.000 ") << " 1 " << _angle << " ";
1201  else
1202  stream << transform.mapDepth( _depth ) << " -1 -1 " << (_lineStyle?"4.000 ":"0.000 ") << " 1 " << _angle << " ";
1203  stream << static_cast<int>( transform.mapX( _center.x ) ) << " "
1204  << static_cast<int>( transform.mapY( _center.y ) ) << " "
1205  << static_cast<int>( transform.scale( _xRadius ) ) << " "
1206  << static_cast<int>( transform.scale( _yRadius ) ) << " "
1207  << static_cast<int>( transform.mapX( _center.x ) ) << " "
1208  << static_cast<int>( transform.mapY( _center.y ) ) << " "
1209  << static_cast<int>( transform.mapX( _center.x ) + transform.scale( _xRadius ) ) << " "
1210  << static_cast<int>( transform.mapY( _center.y ) ) << "\n";
1211 }
1212 
1213 void
1214 Ellipse::flushSVG( std::ostream & stream,
1215  const TransformSVG & transform ) const
1216 {
1217  stream << "<ellipse cx=\"" << transform.mapX( _center.x ) << '"'
1218  << " cy=\"" << transform.mapY( _center.y ) << '"'
1219  << " rx=\"" << transform.scale( _xRadius ) << '"'
1220  << " ry=\"" << transform.scale( _yRadius ) << '"'
1221  << svgProperties( transform ) ;
1222  if ( _angle != 0.0 ) {
1223  stream << " transform=\"rotate( "
1224  << -(_angle*180/M_PI) << ", "
1225  << transform.mapX( _center.x ) << ", "
1226  << transform.mapY( _center.y ) << " )\" ";
1227  }
1228  stream << " />" << std::endl;
1229 }
1230 
1231 #ifdef WITH_CAIRO
1232 void
1233 Ellipse::flushCairo( cairo_t *cr,
1234  const TransformCairo & transform ) const
1235 {
1236  cairo_save (cr);
1237 
1238  cairo_set_source_rgba (cr, _fillColor.red()/255.0, _fillColor.green()/255.0, _fillColor.blue()/255.0, 1.);
1239 
1240  // tr
1241  cairo_translate (cr, transform.mapX( _center.x ), transform.mapY( _center.y ));
1242  if ( _angle != 0.0 )
1243  cairo_rotate (cr, _angle);
1244  cairo_scale (cr, transform.scale( _xRadius ), transform.scale( _yRadius ));
1245  // tr
1246 
1247  cairo_arc (cr, 0, 0, 1, 0, 2*M_PI);
1248 
1249  if ( filled() )
1250  {
1251  if ( _penColor != DGtal::Color::None )
1252  cairo_fill_preserve (cr);
1253  else
1254  cairo_fill (cr);
1255  }
1256 
1257  //
1258 
1259  if ( _penColor != DGtal::Color::None )
1260  {
1261  cairo_set_source_rgba (cr, _penColor.red()/255.0, _penColor.green()/255.0, _penColor.blue()/255.0, 1.);
1262 
1263  cairo_set_line_width (cr, _lineWidth);
1264  cairo_set_line_cap (cr, cairoLineCap[_lineCap]);
1265  cairo_set_line_join (cr, cairoLineJoin[_lineJoin]);
1266  setCairoDashStyle (cr, _lineStyle);
1267 
1268  cairo_stroke (cr);
1269  }
1270 
1271  cairo_restore (cr);
1272 }
1273 #endif
1274 
1275 void
1276 Ellipse::flushTikZ( std::ostream & stream,
1277  const TransformTikZ & transform ) const
1278 {
1279  // FIXME: unimplemented
1280  stream << "% FIXME: Ellipse::flushTikZ unimplemented" << endl;
1281  stream << "\\path[" << tikzProperties(transform) << "] ("
1282  << transform.mapX( _center.x ) << ','
1283  << transform.mapY( _center.y ) << ')'
1284  << " circle [x radius=" << transform.scale( _xRadius ) << ','
1285  << "y radius=" << transform.scale( _yRadius ) << ','
1286  << "rotate=" << -(_angle*180/M_PI)
1287  << "];"
1288  << std::endl;
1289 }
1290 
1291 Rect
1292 Ellipse::boundingBox() const
1293 {
1294  if ( _angle == 0.0 )
1295  return Rect( _center.x - _xRadius, _center.y + _yRadius,
1296  2 * _xRadius, 2 * _yRadius );
1297 
1298  double angleXmax = -atan( (_yRadius/_xRadius)*(tan(_angle) ) );
1299  double angleXmin = -atan( (_yRadius/_xRadius)*(tan(_angle) ) ) + M_PI;
1300  double angleYmax = atan( (_yRadius/_xRadius)*(1/tan(_angle) ) );
1301  double angleYmin = M_PI + atan( (_yRadius/_xRadius)*(1/tan(_angle) ) );
1302 
1303  if ( _angle < 0.0 ) {
1304  angleYmax += M_PI;
1305  angleYmin -= M_PI;
1306  }
1307 
1308  return Rect( _center.x + _xRadius*cos(angleXmin)*cos(_angle) - _yRadius*sin(angleXmin)*sin(_angle),
1309  _center.y + _xRadius*cos(angleYmax)*sin(_angle) + _yRadius*sin(angleYmax)*cos(_angle),
1310  ( _xRadius*cos(angleXmax)*cos(_angle) - _yRadius*sin(angleXmax)*sin(_angle) ) -
1311  ( _xRadius*cos(angleXmin)*cos(_angle) - _yRadius*sin(angleXmin)*sin(_angle) ),
1312  ( _xRadius*cos(angleYmax)*sin(_angle) + _yRadius*sin(angleYmax)*cos(_angle) ) -
1313  ( _xRadius*cos(angleYmin)*sin(_angle) + _yRadius*sin(angleYmin)*cos(_angle) ) );
1314 }
1315 
1316 /*
1317  * Circle
1318  */
1319 
1320 const std::string Circle::_name("Circle");
1321 
1322 const std::string &
1323 Circle::name() const
1324 {
1325  return _name;
1326 }
1327 
1328 Point
1329 Circle::center() const {
1330  return _center;
1331 }
1332 
1333 Circle &
1334 Circle::rotate( double angle, const Point & rotCenter )
1335 {
1336  if ( _circle ) {
1337  if ( rotCenter == _center ) return *this;
1338  _center.rotate( angle, rotCenter );
1339  return *this;
1340  }
1341  Ellipse::rotate( angle, rotCenter );
1342  return *this;
1343 }
1344 
1345 Circle
1346 Circle::rotated( double angle, const Point & rotCenter ) const
1347 {
1348  return Circle(*this).rotate( angle, rotCenter );
1349 }
1350 
1351 Circle &
1352 Circle::rotate( double angle )
1353 {
1354  if ( !_circle )
1355  Ellipse::rotate( angle );
1356  return *this;
1357 }
1358 
1359 Circle
1360 Circle::rotated( double angle ) const
1361 {
1362  return Circle(*this).rotate( angle );
1363 }
1364 
1365 Circle &
1366 Circle::translate( double dx, double dy )
1367 {
1368  _center += Point( dx, dy );
1369  return *this;
1370 }
1371 
1372 Circle
1373 Circle::translated( double dx, double dy ) const
1374 {
1375  return Circle(*this).translate( dx, dy );
1376 }
1377 
1378 Shape &
1379 Circle::scale( double sx, double sy )
1380 {
1381  return Ellipse::scale( sx, sy );
1382 }
1383 
1384 Shape &
1385 Circle::scale( double s )
1386 {
1387  return Ellipse::scale( s );
1388 }
1389 
1390 Circle
1391 Circle::scaled( double sx, double sy ) const
1392 {
1393  return static_cast<Circle &>( Circle(*this).scale( sx, sy ) );
1394 }
1395 
1396 Circle
1397 Circle::scaled( double s ) const
1398 {
1399  return static_cast<Circle &>( Circle(*this).scale( s, s ) );
1400 }
1401 
1402 void
1403 Circle::scaleAll( double s )
1404 {
1405  _center *= s;
1406  _xRadius *= s;
1407  _yRadius *= s;
1408 }
1409 
1410 Circle *
1411 Circle::clone() const {
1412  return new Circle(*this);
1413 }
1414 
1415 void
1416 Circle::flushSVG( std::ostream & stream,
1417  const TransformSVG & transform ) const
1418 {
1419  if ( ! _circle )
1420  Ellipse::flushSVG( stream, transform );
1421  else {
1422  stream << "<circle cx=\"" << transform.mapX( _center.x ) << '"'
1423  << " cy=\"" << transform.mapY( _center.y ) << '"'
1424  << " r=\"" << transform.scale( _xRadius ) << '"'
1425  << svgProperties( transform )
1426  << " />" << std::endl;
1427  }
1428 }
1429 
1430 #ifdef WITH_CAIRO
1431 void
1432 Circle::flushCairo( cairo_t *cr,
1433  const TransformCairo & transform ) const
1434 {
1435  if ( ! _circle )
1436  Ellipse::flushCairo( cr, transform );
1437  else
1438  {
1439  cairo_save (cr);
1440 
1441  cairo_set_source_rgba (cr, _fillColor.red()/255.0, _fillColor.green()/255.0, _fillColor.blue()/255.0, 1.);
1442 
1443  cairo_arc (cr, transform.mapX( _center.x ), transform.mapY( _center.y ), transform.scale( _xRadius ), 0, 2*M_PI);
1444 
1445  if ( filled() )
1446  {
1447  if ( _penColor != DGtal::Color::None )
1448  cairo_fill_preserve (cr);
1449  else
1450  cairo_fill (cr);
1451  }
1452 
1453  //
1454 
1455  if ( _penColor != DGtal::Color::None )
1456  {
1457  cairo_set_source_rgba (cr, _penColor.red()/255.0, _penColor.green()/255.0, _penColor.blue()/255.0, 1.);
1458 
1459  cairo_set_line_width (cr, _lineWidth);
1460  cairo_set_line_cap (cr, cairoLineCap[_lineCap]);
1461  cairo_set_line_join (cr, cairoLineJoin[_lineJoin]);
1462  setCairoDashStyle (cr, _lineStyle);
1463 
1464  cairo_stroke (cr);
1465  }
1466 
1467  cairo_restore (cr);
1468  }
1469 }
1470 #endif
1471 
1472 void
1473 Circle::flushTikZ( std::ostream & stream,
1474  const TransformTikZ & transform ) const
1475 {
1476  if ( ! _circle )
1477  Ellipse::flushTikZ( stream, transform );
1478  else {
1479  stream << "\\path[" << tikzProperties(transform) << "] ("
1480  << transform.mapX( _center.x ) << ','
1481  << transform.mapY( _center.y ) << ')'
1482  << " circle (" << transform.scale( _xRadius ) << ");"
1483  << std::endl;
1484  }
1485 }
1486 
1487 /*
1488  * Arc
1489  */
1490 
1491 const std::string Arc::_name("Arc");
1492 
1493 const std::string &
1494 Arc::name() const
1495 {
1496  return _name;
1497 }
1498 
1499 #ifdef WITH_CAIRO
1500 void
1501 Arc::flushCairo( cairo_t *cr,
1502  const TransformCairo & transform ) const
1503 {
1504  cairo_save (cr);
1505 
1506  cairo_set_source_rgba (cr, _fillColor.red()/255.0, _fillColor.green()/255.0, _fillColor.blue()/255.0, 1.);
1507 
1508  if (_negative) // important: here for Cairo we must inverse 'cairo_arc' and 'cairo_arc_negative' and change alpha with 2.*M_PI-alpha
1509  cairo_arc (cr, transform.mapX( _center.x ), transform.mapY( _center.y ), transform.scale( _xRadius ), 2.*M_PI-_angle1, 2.*M_PI-_angle2);
1510  else
1511  cairo_arc_negative (cr, transform.mapX( _center.x ), transform.mapY( _center.y ), transform.scale( _xRadius ), 2.*M_PI-_angle1, 2.*M_PI-_angle2);
1512 
1513  if ( filled() )
1514  {
1515  if ( _penColor != DGtal::Color::None )
1516  cairo_fill_preserve (cr);
1517  else
1518  cairo_fill (cr);
1519  }
1520 
1521  //
1522 
1523  if ( _penColor != DGtal::Color::None )
1524  {
1525  cairo_set_source_rgba (cr, _penColor.red()/255.0, _penColor.green()/255.0, _penColor.blue()/255.0, 1.);
1526 
1527  cairo_set_line_width (cr, _lineWidth);
1528  cairo_set_line_cap (cr, cairoLineCap[_lineCap]);
1529  cairo_set_line_join (cr, cairoLineJoin[_lineJoin]);
1530  setCairoDashStyle (cr, _lineStyle);
1531 
1532  cairo_stroke (cr);
1533  }
1534 
1535  cairo_restore (cr);
1536 }
1537 #endif
1538 
1539 void
1540 Arc::flushPostscript( std::ostream & stream,
1541  const TransformEPS & transform ) const
1542 {
1543 
1544 //The arc is generated by sweeping a line segment of length r, and tied at the point (x-coord y-coord), in a counter-clockwise direction from an angle _angle1 to an angle _angle2.
1545 //Thus, we have to swap _angle1 and _angle2 according to bool _negative
1546  double a1, a2;
1547  if (_negative == true)
1548  {
1549  a1 = _angle2;
1550  a2 = _angle1;
1551  }
1552  else
1553  {
1554  a1 = _angle1;
1555  a2 = _angle2;
1556  }
1557 
1558  stream << "\n% Arc\n";
1559  if ( filled() ) {
1560  stream << "gs "
1561  << transform.mapX( _center.x ) << " " << transform.mapY( _center.y ) << " "
1562  << transform.scale( _xRadius )<< " " << (a1*180/M_PI) << " "
1563  << (a2*180/M_PI) << " "<< "arc ";
1564  stream << " " << _fillColor.postscript() << " srgb";
1565  stream << " fill gr" << std::endl;
1566  }
1567 
1568  if ( _penColor != DGtal::Color::None ) {
1569 
1570  stream << "gs "
1571  << transform.mapX( _center.x ) << " " << transform.mapY( _center.y ) << " "
1572  << transform.scale( _xRadius )<< " " << (a1*180/M_PI) << " "
1573  << (a2*180/M_PI) << " "<< "arc ";
1574  _penColor.flushPostscript( stream );
1575  stream << " stroke gr" << std::endl;
1576  }
1577 }
1578 
1579 void
1580 Arc::flushSVG( std::ostream & stream,
1581  const TransformSVG & transform ) const
1582 {
1583 
1584 double fx = _center.x + _xRadius*std::cos(_angle1);
1585 double fy = _center.y + _xRadius*std::sin(_angle1);
1586 double lx = _center.x + _xRadius*std::cos(_angle2);
1587 double ly = _center.y + _xRadius*std::sin(_angle2);
1588 
1589 stream << "<path ";
1590 stream << svgProperties( transform ) << " ";
1591 //first point
1592 stream << "d='M " << transform.mapX( fx );
1593 stream << "," << transform.mapY( fy );
1594 //arc
1595 stream << " A " << transform.scale( _xRadius ) << " " << transform.scale( _xRadius );
1596 //something
1597 stream << " 0";
1598 //orientation and center position
1599 if (_negative)
1600 {
1601  if ( (std::cos(_angle1)*std::sin(_angle2) - std::sin(_angle1)*std::cos(_angle2))<0 )
1602  {
1603  stream << " 0 1";
1604  } else
1605  {
1606  stream << " 1 1";
1607  }
1608 } else
1609 {
1610  if ( (std::cos(_angle1)*std::sin(_angle2) - std::sin(_angle1)*std::cos(_angle2))<0 )
1611  {
1612  stream << " 1 0";
1613  } else
1614  {
1615  stream << " 0 0";
1616  }
1617 }
1618 //last point
1619 stream << " " << transform.mapX( lx );
1620 stream << "," << transform.mapY( ly );
1621 stream << "' />";
1622 
1623 }
1624 
1625 void
1626 Arc::flushTikZ( std::ostream & stream,
1627  const TransformTikZ & transform ) const
1628 {
1629  stream << "\\path[" << tikzProperties(transform) << "] ("
1630  << transform.mapX( _center.x ) << ',' << transform.mapY( _center.y ) << ')' // center
1631  << " +(" << -_angle1/M_PI*180. << ':' << transform.scale( _xRadius) << ')' // first point of arc
1632  << " arc (" << -_angle1/M_PI*180. << ':' << -_angle2/M_PI*180. + _negative * 360. << ':' << transform.scale( _xRadius ) << ");"
1633  << std::endl;
1634 }
1635 
1636 /*
1637  * Polyline
1638  */
1639 
1640 const std::string Polyline::_name("Polyline");
1641 
1642 const std::string &
1643 Polyline::name() const
1644 {
1645  return _name;
1646 }
1647 
1648 Polyline &
1649 Polyline::operator<<( const Point & p )
1650 {
1651  _path << p;
1652  return *this;
1653 }
1654 
1655 Point
1656 Polyline::center() const {
1657  return _path.center();
1658 }
1659 
1660 Polyline &
1661 Polyline::rotate( double angle, const Point & rotCenter )
1662 {
1663  _path.rotate( angle, rotCenter );
1664  return *this;
1665 }
1666 
1667 Polyline
1668 Polyline::rotated( double angle, const Point & rotCenter ) const
1669 {
1670  return Polyline(*this).rotate( angle, rotCenter );
1671 }
1672 
1673 Polyline &
1674 Polyline::rotate( double angle )
1675 {
1676  _path.rotate( angle, center() );
1677  return *this;
1678 }
1679 
1680 Polyline
1681 Polyline::rotated( double angle ) const
1682 {
1683  return Polyline(*this).rotate( angle, center() );
1684 }
1685 
1686 Polyline &
1687 Polyline::translate( double dx, double dy )
1688 {
1689  _path.translate( dx, dy );
1690  return *this;
1691 }
1692 
1693 Polyline
1694 Polyline::translated( double dx, double dy ) const
1695 {
1696  return Polyline(*this).translate( dx, dy );
1697 }
1698 
1699 Shape &
1700 Polyline::scale( double sx, double sy )
1701 {
1702  _path.scale( sx, sy );
1703  return *this;
1704 }
1705 
1706 Shape &
1707 Polyline::scale( double s )
1708 {
1709  Polyline::scale( s, s );
1710  return *this;
1711 }
1712 
1713 Polyline
1714 Polyline::scaled( double sx, double sy ) const
1715 {
1716  return static_cast<Polyline &>( Polyline(*this).scale( sx, sy ) );
1717 }
1718 
1719 Polyline
1720 Polyline::scaled( double s) const
1721 {
1722  return static_cast<Polyline &>( Polyline(*this).scale( s, s ) );
1723 }
1724 
1725 void
1726 Polyline::scaleAll( double s )
1727 {
1728  _path.scaleAll( s );
1729 }
1730 
1731 Polyline *
1732 Polyline::clone() const {
1733  return new Polyline(*this);
1734 }
1735 
1736 void
1737 Polyline::flushPostscript( std::ostream & stream,
1738  const TransformEPS & transform ) const
1739 {
1740  if ( _path.empty() ) return;
1741  stream << "\n% Polyline\n";
1742  if ( filled() ) {
1743  stream << "n ";
1744  _path.flushPostscript( stream, transform );
1745  stream << " ";
1746  _fillColor.flushPostscript( stream );
1747  stream << " " << postscriptProperties();
1748  stream << " fill" << std::endl;
1749  }
1750  if ( _penColor != DGtal::Color::None ) {
1751  stream << " " << postscriptProperties() << "\n";
1752  stream << "n ";
1753  _path.flushPostscript( stream, transform );
1754  stream << " ";
1755  _penColor.flushPostscript( stream );
1756  stream << " stroke" << std::endl;
1757  }
1758 }
1759 
1760 void
1761 Polyline::flushFIG( std::ostream & stream,
1762  const TransformFIG & transform,
1763  std::map<DGtal::Color,int> & colormap ) const
1764 {
1765  if ( _path.empty() )
1766  return;
1767  if ( _path.closed() )
1768  stream << "2 3 " << _lineStyle << " ";
1769  else
1770  stream << "2 1 " << _lineStyle << " ";
1771  // Thickness
1772  stream << ( _penColor.valid()?transform.mapWidth( _lineWidth ):0 ) << " ";
1773  // Pen color
1774  stream << colormap[ _penColor ] << " ";
1775  // Fill color
1776  stream << colormap[ _fillColor ] << " ";
1777  // Depth
1778  stream << transform.mapDepth( _depth ) << " ";
1779  // Pen style
1780  stream << "-1 ";
1781  // Area fill, style val, join style, cap style, radius, f_arrow, b_arrow
1782  if ( filled() )
1783  stream << "20 " << (_lineStyle?"4.000 ":"0.000 ") << _lineJoin << " " << _lineCap << " -1 0 0 ";
1784  else
1785  stream << "-1 " << (_lineStyle?"4.000 ":"0.000 ") << _lineJoin << " " << _lineCap << " -1 0 0 ";
1786  // Number of points
1787  stream << _path.size() + _path.closed() << std::endl;
1788  _path.flushFIG( stream << " ", transform );
1789  stream << std::endl;
1790 }
1791 
1792 void
1793 Polyline::flushSVG( std::ostream & stream,
1794  const TransformSVG & transform ) const
1795 {
1796  if ( _path.empty() )
1797  return;
1798  if ( _path.closed() )
1799  stream << "<polygon";
1800  else
1801  stream << "<polyline";
1802  stream << svgProperties( transform ) << std::endl;
1803  stream << " points=\"";
1804  _path.flushSVGPoints( stream, transform );
1805  stream << "\" />" << std::endl;
1806 }
1807 
1808 #ifdef WITH_CAIRO
1809 void
1810 Polyline::flushCairo( cairo_t *cr,
1811  const TransformCairo & transform ) const
1812 {
1813  if ( _path.empty() )
1814  return;
1815 
1816  cairo_save (cr);
1817 
1818  cairo_set_source_rgba (cr, _fillColor.red()/255.0, _fillColor.green()/255.0, _fillColor.blue()/255.0, 1.);
1819 
1820  _path.flushCairoPoints( cr, transform );
1821  if ( _path.closed() )
1822  cairo_close_path (cr);
1823 
1824  if ( filled() )
1825  {
1826  if ( _penColor != DGtal::Color::None )
1827  cairo_fill_preserve (cr);
1828  else
1829  cairo_fill (cr);
1830  }
1831 
1832  //
1833 
1834  if ( _penColor != DGtal::Color::None )
1835  {
1836  cairo_set_source_rgba (cr, _penColor.red()/255.0, _penColor.green()/255.0, _penColor.blue()/255.0, 1.);
1837 
1838  cairo_set_line_width (cr, _lineWidth);
1839  cairo_set_line_cap (cr, cairoLineCap[_lineCap]);
1840  cairo_set_line_join (cr, cairoLineJoin[_lineJoin]);
1841  setCairoDashStyle (cr, _lineStyle);
1842 
1843  cairo_stroke (cr);
1844  }
1845 
1846  cairo_restore (cr);
1847 }
1848 #endif
1849 
1850 void
1851 Polyline::flushTikZ( std::ostream & stream,
1852  const TransformTikZ & transform ) const
1853 {
1854  if ( _path.empty() )
1855  return;
1856 
1857  stream << "\\path[" << tikzProperties(transform) << "] ";
1858  //stream << svgProperties( transform ) << std::endl;
1859 
1860  _path.flushTikZPoints( stream, transform );
1861 
1862  if ( _path.closed() )
1863  stream << " -- cycle";
1864  stream << ";" << std::endl;
1865 }
1866 
1867 Rect
1868 Polyline::boundingBox() const
1869 {
1870  return _path.boundingBox();
1871 }
1872 
1873 /*
1874  * Rectangle
1875  */
1876 
1877 const std::string Rectangle::_name("Rectangle");
1878 
1879 const std::string &
1880 Rectangle::name() const
1881 {
1882  return _name;
1883 }
1884 
1885 Rectangle
1886 Rectangle::rotated( double angle, const Point & rotCenter ) const
1887 {
1888  return static_cast<Rectangle &>( Rectangle(*this).rotate( angle, rotCenter ) );
1889 }
1890 
1891 Rectangle
1892 Rectangle::rotated( double angle ) const
1893 {
1894  return static_cast<Rectangle &>( Rectangle(*this).rotate( angle, center() ) );
1895 }
1896 
1897 Rectangle
1898 Rectangle::translated( double dx, double dy ) const
1899 {
1900  return static_cast<Rectangle &>( Rectangle(*this).translate( dx, dy ) );
1901 }
1902 
1903 Rectangle
1904 Rectangle::scaled( double sx, double sy ) const
1905 {
1906  return static_cast<Rectangle &>( Rectangle(*this).scale( sx, sy ) );
1907 }
1908 
1909 Rectangle
1910 Rectangle::scaled( double s ) const
1911 {
1912  return static_cast<Rectangle &>( Rectangle(*this).scale( s, s ) );
1913 }
1914 
1915 void
1916 Rectangle::scaleAll( double s )
1917 {
1918  _path.scaleAll( s );
1919 }
1920 
1921 Rectangle *
1922 Rectangle::clone() const {
1923  return new Rectangle(*this);
1924 }
1925 
1926 void
1927 Rectangle::flushFIG( std::ostream & stream,
1928  const TransformFIG & transform,
1929  std::map<DGtal::Color,int> & colormap ) const
1930 {
1931  if ( _path[0].y != _path[1].y ) {
1932  Polyline::flushFIG( stream, transform, colormap );
1933  return;
1934  }
1935  if ( _path[0].x != _path[3].x ) {
1936  Polyline::flushFIG( stream, transform, colormap );
1937  return;
1938  }
1939  {
1940  double x1 = _path[1].x - _path[0].x;
1941  double y1 = _path[1].y - _path[0].y;
1942  double x2 = _path[3].x - _path[0].x;
1943  double y2 = _path[3].y - _path[0].y;
1944  if ( fabs(x1*x2 + y1*y2) > 0.01 ) {
1945  Polyline::flushFIG( stream, transform, colormap );
1946  return;
1947  }
1948  }
1949 
1950  stream << "2 2 " << _lineStyle << " ";
1951  // Thickness
1952  stream << ( _penColor.valid()?transform.mapWidth( _lineWidth ):0 ) << " ";
1953  // Pen color
1954  stream << colormap[ _penColor ] << " ";
1955  // Fill color
1956  stream << colormap[ _fillColor ] << " ";
1957  // Depth
1958  stream << transform.mapDepth( _depth ) << " ";
1959  // Pen style
1960  stream << "-1 ";
1961  // Area fill, style val, join style, cap style, radius, f_arrow, b_arrow, number of points
1962  if ( filled() )
1963  stream << "20 " << (_lineStyle?"4.000 ":"0.000 ") << _lineJoin << " " << _lineCap << " -1 0 0 5\n";
1964  else
1965  stream << "-1 " << (_lineStyle?"4.000 ":"0.000 ") << _lineJoin << " " << _lineCap << " -1 0 0 5\n";
1966  stream << " ";
1967  _path.flushFIG( stream, transform );
1968  stream << std::endl;
1969 }
1970 
1971 void
1972 Rectangle::flushSVG( std::ostream & stream,
1973  const TransformSVG & transform ) const
1974 {
1975  {
1976  double x1 = _path[1].x - _path[0].x;
1977  double y1 = _path[1].y - _path[0].y;
1978  double x2 = _path[3].x - _path[0].x;
1979  double y2 = _path[3].y - _path[0].y;
1980  if ( fabs(x1*x2 + y1*y2) > 0.01 ) {
1981  Polyline::flushSVG( stream, transform );
1982  return;
1983  }
1984  }
1985 
1986  if ( _path[0].y == _path[1].y ) {
1987  stream << "<rect x=\"" << transform.mapX( _path[0].x ) << '"'
1988  << " y=\"" << transform.mapY( _path[0].y ) << '"'
1989  << " width=\"" << transform.scale( _path[1].x - _path[0].x ) << '"'
1990  << " height=\"" << transform.scale( _path[0].y - _path[3].y ) << '"'
1991  << svgProperties( transform )
1992  << " />" << std::endl;
1993  } else {
1994  Point v = _path[1] - _path[0];
1995  v /= v.norm();
1996  double angle = ( _path[1].y > _path[0].y ) ? acos( v * Point(1,0) ) : -acos( v * Point( 1, 0 ) );
1997  angle = ( angle * 180 ) / M_PI;
1998  stream << "<rect x=\"" << transform.mapX( _path[0].x ) << '"'
1999  << " y=\"" << transform.mapY( _path[0].y ) << '"'
2000  << " width=\"" << transform.scale( (_path[1] - _path[0]).norm() ) << '"'
2001  << " height=\"" << transform.scale( (_path[0] - _path[3]).norm() ) << '"'
2002  << svgProperties( transform ) << ' '
2003  << " transform=\"rotate(" << -angle << ", "
2004  << transform.mapX( _path[0].x ) << ", " << transform.mapY( _path[0].y ) << ") \" "
2005  << " />" << std::endl;
2006  }
2007 }
2008 
2009 #ifdef WITH_CAIRO
2010 void
2011 Rectangle::flushCairo( cairo_t *cr,
2012  const TransformCairo & transform ) const
2013 {
2014  {
2015  double x1 = _path[1].x - _path[0].x;
2016  double y1 = _path[1].y - _path[0].y;
2017  double x2 = _path[3].x - _path[0].x;
2018  double y2 = _path[3].y - _path[0].y;
2019  if ( fabs(x1*x2 + y1*y2) > 0.01 ) {
2020  Polyline::flushCairo( cr, transform );
2021  return;
2022  }
2023  }
2024 
2025  cairo_save (cr);
2026 
2027  cairo_set_source_rgba (cr, _fillColor.red()/255.0, _fillColor.green()/255.0, _fillColor.blue()/255.0, 1.);
2028 
2029  if ( _path[0].y == _path[1].y )
2030  cairo_rectangle (cr, transform.mapX( _path[0].x ), transform.mapY( _path[0].y ), transform.scale( _path[1].x - _path[0].x ), transform.scale( _path[0].y - _path[3].y ));
2031  else
2032  {
2033  Point v = _path[1] - _path[0];
2034  v /= v.norm();
2035  double angle = ( _path[1].y > _path[0].y ) ? acos( v * Point(1,0) ) : -acos( v * Point( 1, 0 ) );
2036 
2037  // tr
2038  cairo_translate (cr, transform.mapX( _path[0].x )+transform.scale( _path[1].x - _path[0].x )/2., transform.mapY( _path[0].y )+transform.scale( _path[0].y - _path[3].y )/2.);
2039  cairo_rotate (cr, angle);
2040  // tr
2041 
2042  cairo_rectangle (cr, -transform.scale( _path[1].x - _path[0].x )/2., -transform.scale( _path[0].y - _path[3].y )/2., transform.scale( (_path[1] - _path[0]).norm() ), transform.scale( (_path[0] - _path[3]).norm() ));
2043  }
2044 
2045  if ( filled() )
2046  {
2047  if ( _penColor != DGtal::Color::None )
2048  cairo_fill_preserve (cr);
2049  else
2050  cairo_fill (cr);
2051  }
2052 
2053  //
2054 
2055  if ( _penColor != DGtal::Color::None )
2056  {
2057  cairo_set_source_rgba (cr, _penColor.red()/255.0, _penColor.green()/255.0, _penColor.blue()/255.0, 1.);
2058 
2059  cairo_set_line_width (cr, _lineWidth);
2060  cairo_set_line_cap (cr, cairoLineCap[_lineCap]);
2061  cairo_set_line_join (cr, cairoLineJoin[_lineJoin]);
2062  setCairoDashStyle (cr, _lineStyle);
2063 
2064  cairo_stroke (cr);
2065  }
2066 
2067  cairo_restore (cr);
2068 }
2069 #endif
2070 
2071 void
2072 Rectangle::flushTikZ( std::ostream & stream,
2073  const TransformTikZ & transform ) const
2074 {
2075  Polyline::flushTikZ( stream, transform );
2076  return;
2077 
2078  stream << "\\path[" << tikzProperties(transform) << "] ("
2079  << _path[0].x << ',' << _path[0].y << ')'
2080  << " rectangle ("
2081  << _path[1].x << ',' << _path[3].y << ");" << std::endl;
2082 /*
2083  if ( _path[0].y == _path[1].y ) {
2084  stream << "<rect x=\"" << transform.mapX( _path[0].x ) << '"'
2085  << " y=\"" << transform.mapY( _path[0].y ) << '"'
2086  << " width=\"" << transform.scale( _path[1].x - _path[0].x ) << '"'
2087  << " height=\"" << transform.scale( _path[0].y - _path[3].y ) << '"'
2088  << svgProperties( transform )
2089  << " />" << std::endl;
2090  } else {
2091  Point v = _path[1] - _path[0];
2092  v /= v.norm();
2093  double angle = ( _path[1].y > _path[0].y ) ? acos( v * Point(1,0) ) : -acos( v * Point( 1, 0 ) );
2094  angle = ( angle * 180 ) / M_PI;
2095  stream << "<rect x=\"" << transform.mapX( _path[0].x ) << '"'
2096  << " y=\"" << transform.mapY( _path[0].y ) << '"'
2097  << " width=\"" << transform.scale( (_path[1] - _path[0]).norm() ) << '"'
2098  << " height=\"" << transform.scale( (_path[0] - _path[3]).norm() ) << '"'
2099  << svgProperties( transform ) << ' '
2100  << " transform=\"rotate(" << -angle << ", "
2101  << transform.mapX( _path[0].x ) << ", " << transform.mapY( _path[0].y ) << ") \" "
2102  << " />" << std::endl;
2103  }
2104  */
2105 }
2106 
2107 /*
2108  * GouraudTriangle
2109  */
2110 
2111 const std::string GouraudTriangle::_name("GouraudTriangle");
2112 
2113 const std::string &
2114 GouraudTriangle::name() const
2115 {
2116  return _name;
2117 }
2118 
2119 GouraudTriangle::GouraudTriangle( const Point & p0, const DGtal::Color & color0,
2120  const Point & p1, const DGtal::Color & color1,
2121  const Point & p2, const DGtal::Color & color2,
2122  int subdivisions,
2123  int depthValue )
2124  : Polyline( std::vector<Point>(), true, DGtal::Color::None, DGtal::Color::None,
2125  0.0f, SolidStyle, ButtCap, MiterJoin, depthValue ),
2126  _color0( color0 ), _color1( color1 ), _color2( color2 ), _subdivisions( subdivisions ) {
2127  _path << p0;
2128  _path << p1;
2129  _path << p2;
2130 
2131  Shape::_fillColor.red( ( color0.red() + color1.red() + color2.red() ) / 3 );
2132  Shape::_fillColor.green( ( color0.green() + color1.green() + color2.green() ) / 3 );
2133  Shape::_fillColor.blue( ( color0.blue() + color1.blue() + color2.blue() ) / 3 );
2134 }
2135 
2136 GouraudTriangle::GouraudTriangle( const Point & p0, float brightness0,
2137  const Point & p1, float brightness1,
2138  const Point & p2, float brightness2,
2139  const DGtal::Color & fill,
2140  int subdivisions,
2141  int depthValue )
2142  : Polyline( std::vector<Point>(), true, DGtal::Color::None, DGtal::Color::None,
2143  0.0f, SolidStyle, ButtCap, MiterJoin, depthValue ),
2144  _color0( fill ), _color1( fill ), _color2( fill ), _subdivisions( subdivisions )
2145 {
2146  _path << p0;
2147  _path << p1;
2148  _path << p2;
2149  _color0.red( static_cast<unsigned char>( min( 255.0f, _color0.red() * brightness0 ) ) );
2150  _color0.green( static_cast<unsigned char>( min( 255.0f, _color0.green() * brightness0 ) ) );
2151  _color0.blue( static_cast<unsigned char>( min( 255.0f, _color0.blue() * brightness0 ) ) );
2152  _color1.red( static_cast<unsigned char>( min( 255.0f, _color1.red() * brightness1 ) ) );
2153  _color1.green( static_cast<unsigned char>( min( 255.0f, _color1.green() * brightness1 ) ) );
2154  _color1.blue( static_cast<unsigned char>( min( 255.0f, _color1.blue() * brightness1 ) ) );
2155  _color2.red( static_cast<unsigned char>( min( 255.0f, _color2.red() * brightness2 ) ) );
2156  _color2.green( static_cast<unsigned char>( min( 255.0f, _color2.green() * brightness2 ) ) );
2157  _color2.blue( static_cast<unsigned char>( min( 255.0f, _color2.blue() * brightness2 ) ) );
2158 
2159  Shape::_fillColor.red( ( _color0.red() + _color1.red() + _color2.red() ) / 3 );
2160  Shape::_fillColor.green( ( _color0.green() + _color1.green() + _color2.green() ) / 3 );
2161  Shape::_fillColor.blue( ( _color0.blue() + _color1.blue() + _color2.blue() ) / 3 );
2162 }
2163 
2164 Point
2165 GouraudTriangle::center() const {
2166  return ( _path[0] + _path[1] + _path[2] ) / 3.0;
2167 }
2168 
2169 GouraudTriangle &
2170 GouraudTriangle::rotate( double angle, const Point & rotCenter )
2171 {
2172  _path.rotate( angle, rotCenter );
2173  return *this;
2174 }
2175 
2176 GouraudTriangle
2177 GouraudTriangle::rotated( double angle, const Point & rotCenter ) const
2178 {
2179  return GouraudTriangle(*this).rotate( angle, rotCenter );
2180 }
2181 
2182 GouraudTriangle &
2183 GouraudTriangle::rotate( double angle )
2184 {
2185  return GouraudTriangle::rotate( angle, center() );
2186 }
2187 
2188 GouraudTriangle
2189 GouraudTriangle::rotated( double angle ) const
2190 {
2191  return GouraudTriangle(*this).rotate( angle, center() );
2192 }
2193 
2194 GouraudTriangle
2195 GouraudTriangle::translated( double dx, double dy ) const
2196 {
2197  return static_cast<GouraudTriangle &>( GouraudTriangle(*this).translate( dx, dy ) );
2198 }
2199 
2200 GouraudTriangle
2201 GouraudTriangle::scaled( double sx, double sy ) const
2202 {
2203  return static_cast<GouraudTriangle &>( GouraudTriangle(*this).scale( sx, sy ) );
2204 }
2205 
2206 GouraudTriangle
2207 GouraudTriangle::scaled( double s ) const
2208 {
2209  return static_cast<GouraudTriangle &>( GouraudTriangle(*this).scale( s, s ) );
2210 }
2211 
2212 void
2213 GouraudTriangle::scaleAll( double s )
2214 {
2215  _path.scaleAll( s );
2216 }
2217 
2218 GouraudTriangle *
2219 GouraudTriangle::clone() const {
2220  return new GouraudTriangle(*this);
2221 }
2222 
2223 void
2224 GouraudTriangle::flushPostscript( std::ostream & stream,
2225  const TransformEPS & transform ) const
2226 {
2227  if ( ! _subdivisions ) {
2228  Polyline::flushPostscript( stream, transform );
2229  return;
2230  }
2231  const Point & p0 = _path[0];
2232  const Point & p1 = _path[1];
2233  const Point & p2 = _path[2];
2234  Point p01( 0.5*(p0.x+p1.x), 0.5*(p0.y+p1.y) );
2235  DGtal::Color c01( (_color0.red() + _color1.red())/2,
2236  (_color0.green() + _color1.green())/2,
2237  (_color0.blue() + _color1.blue())/2 );
2238  Point p12( 0.5*(p1.x+p2.x), 0.5*(p1.y+p2.y) );
2239  DGtal::Color c12( (_color1.red() + _color2.red())/2,
2240  (_color1.green() + _color2.green())/2,
2241  (_color1.blue() + _color2.blue())/2 );
2242  Point p20( 0.5*(p2.x+p0.x), 0.5*(p2.y+p0.y) );
2243  DGtal::Color c20( (_color2.red() + _color0.red())/2,
2244  (_color2.green() + _color0.green())/2,
2245  (_color2.blue() + _color0.blue())/2 );
2246  GouraudTriangle( p0, _color0, p20, c20, p01, c01, _subdivisions - 1, _depth ).flushPostscript( stream, transform );
2247  GouraudTriangle( p1, _color1, p01, c01, p12, c12, _subdivisions - 1, _depth ).flushPostscript( stream, transform );
2248  GouraudTriangle( p2, _color2, p20, c20, p12, c12, _subdivisions - 1, _depth ).flushPostscript( stream, transform );
2249  GouraudTriangle( p01, c01, p12, c12, p20, c20, _subdivisions - 1, _depth ).flushPostscript( stream, transform );
2250 }
2251 
2252 void
2253 GouraudTriangle::flushFIG( std::ostream & stream,
2254  const TransformFIG & transform,
2255  std::map<DGtal::Color,int> & colormap ) const
2256 {
2257 
2258  DGtal::Color c( static_cast<unsigned char>((_color0.red() + _color1.red() + _color2.red() )/3.0),
2259  static_cast<unsigned char>((_color0.green() + _color1.green() + _color2.green())/3.0),
2260  static_cast<unsigned char>((_color0.blue() + _color1.blue() + _color2.blue())/3.0 ));
2261  Polyline( _path, DGtal::Color::None, c, 0.0f ).flushFIG( stream, transform, colormap );
2262 
2263  // if ( ! _subdivisions ) {
2264  // Polyline::flushFIG( stream, transform, colormap );
2265  // return;
2266  // }
2267 // TODO : Handle extended colormap through clustering...
2268 // const Point & p0 = _points[0];
2269 // const Point & p1 = _points[1];
2270 // const Point & p2 = _points[2];
2271 // Point p01( 0.5*(p0.x+p1.x), 0.5*(p0.y+p1.y) );
2272 // DGtal::Color c01( (_color0.red() + _color1.red())/2,
2273 // (_color0.green() + _color1.green())/2,
2274 // (_color0.blue() + _color1.blue())/2 );
2275 // Point p12( 0.5*(p1.x+p2.x), 0.5*(p1.y+p2.y) );
2276 // DGtal::Color c12( (_color1.red() + _color2.red())/2,
2277 // (_color1.green() + _color2.green())/2,
2278 // (_color1.blue() + _color2.blue())/2 );
2279 // Point p20( 0.5*(p2.x+p0.x), 0.5*(p2.y+p0.y) );
2280 // DGtal::Color c20( (_color2.red() + _color0.red())/2,
2281 // (_color2.green() + _color0.green())/2,
2282 // (_color2.blue() + _color0.blue())/2 );
2283 // GouraudTriangle( p0, _color0, p20, c20, p01, c01, _subdivisions - 1, _depth ).flushFIG( stream, transform, colormap );
2284 // GouraudTriangle( p1, _color1, p01, c01, p12, c12, _subdivisions - 1, _depth ).flushFIG( stream, transform, colormap );
2285 // GouraudTriangle( p2, _color2, p20, c20, p12, c12, _subdivisions - 1, _depth ).flushFIG( stream, transform, colormap );
2286 // GouraudTriangle( p01, c01, p12, c12, p20, c20, _subdivisions - 1, _depth ).flushFIG( stream, transform, colormap );
2287 }
2288 
2289 void
2290 GouraudTriangle::flushSVG( std::ostream & stream,
2291  const TransformSVG & transform ) const
2292 {
2293  if ( ! _subdivisions ) {
2294  Polyline::flushSVG( stream, transform );
2295  return;
2296  }
2297  const Point & p0 = _path[0];
2298  const Point & p1 = _path[1];
2299  const Point & p2 = _path[2];
2300  Point p01( 0.5*(p0.x+p1.x), 0.5*(p0.y+p1.y) );
2301  DGtal::Color c01( (_color0.red() + _color1.red())/2,
2302  (_color0.green() + _color1.green())/2,
2303  (_color0.blue() + _color1.blue())/2 );
2304  Point p12( 0.5*(p1.x+p2.x), 0.5*(p1.y+p2.y) );
2305  DGtal::Color c12( (_color1.red() + _color2.red())/2,
2306  (_color1.green() + _color2.green())/2,
2307  (_color1.blue() + _color2.blue())/2 );
2308  Point p20( 0.5*(p2.x+p0.x), 0.5*(p2.y+p0.y) );
2309  DGtal::Color c20( (_color2.red() + _color0.red())/2,
2310  (_color2.green() + _color0.green())/2,
2311  (_color2.blue() + _color0.blue())/2 );
2312  GouraudTriangle( p0, _color0, p20, c20, p01, c01,
2313  _subdivisions - 1, _depth ).flushSVG( stream, transform );
2314  GouraudTriangle( p1, _color1, p01, c01, p12, c12,
2315  _subdivisions - 1, _depth ).flushSVG( stream, transform );
2316  GouraudTriangle( p2, _color2, p20, c20, p12, c12,
2317  _subdivisions - 1, _depth ).flushSVG( stream, transform );
2318  GouraudTriangle( p01, c01, p12, c12, p20, c20,
2319  _subdivisions - 1, _depth ).flushSVG( stream, transform );
2320 }
2321 
2322 #ifdef WITH_CAIRO
2323 void
2324 GouraudTriangle::flushCairo( cairo_t * /*cr*/,
2325  const TransformCairo & /*transform*/ ) const
2326 {
2327 }
2328 #endif
2329 
2330 void
2331 GouraudTriangle::flushTikZ( std::ostream & stream,
2332  const TransformTikZ & /*transform*/ ) const
2333 {
2334  // FIXME: unimplemented
2335  stream << "% FIXME: GouraudTriangle::flushTikZ unimplemented" << endl;
2336 }
2337 
2338 /*
2339  * Triangle
2340  */
2341 
2342 const std::string Triangle::_name("Triangle");
2343 
2344 const std::string &
2345 Triangle::name() const
2346 {
2347  return _name;
2348 }
2349 
2350 Triangle
2351 Triangle::rotated( double angle ) const
2352 {
2353  return static_cast<Triangle &>( Triangle( *this ).rotate( angle ) );
2354 }
2355 
2356 Triangle
2357 Triangle::translated( double dx, double dy ) const
2358 {
2359  return static_cast<Triangle &>( Triangle( *this ).translate( dx, dy ) );
2360 }
2361 
2362 Triangle
2363 Triangle::scaled( double sx, double sy ) const
2364 {
2365  return static_cast<Triangle &>( Triangle( *this ).scale( sx, sy ) );
2366 }
2367 
2368 Triangle
2369 Triangle::scaled( double s ) const
2370 {
2371  return static_cast<Triangle &>( Triangle( *this ).scale( s ) );
2372 }
2373 
2374 Triangle *
2375 Triangle::clone() const {
2376  return new Triangle(*this);
2377 }
2378 
2379 /*
2380  * Text
2381  */
2382 
2383 const std::string Text::_name("Text");
2384 
2385 const std::string &
2386 Text::name() const
2387 {
2388  return _name;
2389 }
2390 
2391 Point
2392 Text::center() const {
2393  return _position;
2394 }
2395 
2396 Text &
2397 Text::rotate( double angle, const Point & rotCenter )
2398 {
2399  Point endPos = _position + Point( 10000 * cos( _angle ), 10000 * sin( _angle ) );
2400  _position.rotate( angle, rotCenter );
2401  endPos.rotate( angle, rotCenter );
2402  Point v = endPos - _position;
2403  v /= v.norm();
2404  if ( v.x >= 0 ) _angle = asin( v.y );
2405  else if ( v.y > 0 ) _angle = (M_PI/2.0) + acos( v.y );
2406  else _angle = (-M_PI/2.0) - acos( -v.y );
2407  return *this;
2408 }
2409 
2410 Text
2411 Text::rotated( double angle, const Point & rotCenter ) const
2412 {
2413  return Text(*this).rotate( angle, rotCenter );
2414 }
2415 
2416 Text &
2417 Text::rotate( double angle )
2418 {
2419  _angle += angle;
2420  if ( _angle < 0 )
2421  while ( _angle < M_PI ) _angle += 2 * M_PI;
2422  if ( _angle > 0 )
2423  while ( _angle > M_PI ) _angle -= 2 * M_PI;
2424  return *this;
2425 }
2426 
2427 Text
2428 Text::rotated( double angle ) const
2429 {
2430  return Text(*this).rotate( angle );
2431 }
2432 
2433 Text &
2434 Text::translate( double dx, double dy )
2435 {
2436  _position += Point( dx, dy );
2437  return *this;
2438 }
2439 
2440 Text
2441 Text::translated( double dx, double dy ) const
2442 {
2443  return static_cast<Text&>( Text(*this).translate( dx, dy ) );
2444 }
2445 
2446 Shape &
2447 Text::scale( double sx, double sy )
2448 {
2449  _xScale = sx;
2450  _yScale = sy;
2451  return *this;
2452 }
2453 
2454 Shape &
2455 Text::scale( double s )
2456 {
2457  _xScale = _yScale = s;
2458  return *this;
2459 }
2460 
2461 Text
2462 Text::scaled( double sx, double sy ) const
2463 {
2464  return static_cast<Text &>( Text(*this).scale( sx, sy ) );
2465 }
2466 
2467 Text
2468 Text::scaled( double s ) const
2469 {
2470  return static_cast<Text &>( Text(*this).scale( s, s ) );
2471 }
2472 
2473 void
2474 Text::scaleAll( double s )
2475 {
2476  _position *= s;
2477 }
2478 
2479 Text *
2480 Text::clone() const {
2481  return new Text(*this);
2482 }
2483 
2484 void
2485 Text::flushPostscript( std::ostream & stream,
2486  const TransformEPS & transform ) const
2487 {
2488  stream << "\n% Text\n";
2489  stream << "gs /" << PSFontNames[ _font ] << " ff " << _size << " scf sf";
2490  stream << " " << transform.mapX( _position.x ) << " " << transform.mapY( _position.y ) << " m";
2491  if ( _angle != 0.0 ) stream << " " << (_angle/M_PI)*180.0 << " rot ";
2492  stream << " (" << _text << ")"
2493  << " " << _penColor.postscript() << " srgb"
2494  << " sh gr" << std::endl;
2495 }
2496 
2497 void
2498 Text::flushFIG( std::ostream & stream,
2499  const TransformFIG & transform,
2500  std::map<Color,int> & colormap ) const
2501 {
2502  stream << "4 0 " ;
2503  // Color, depth, unused, Font
2504  stream << colormap[ _penColor ] << " " << transform.mapDepth( _depth ) << " -1 " << _font << " ";
2505  // Font size, Angle, Font flags
2506  stream << _size << " " << _angle << " 4 ";
2507  // Height
2508  stream << static_cast<int>( _size * 135 / 12.0 ) << " ";
2509  // Width
2510  stream << static_cast<int>( _text.size() * _size * 135 / 12.0 ) << " ";
2511  // x y
2512  stream << static_cast<int>( transform.mapX( _position.x ) ) << " "
2513  << static_cast<int>( transform.mapY( _position.y ) ) << " ";
2514  stream << _text << "\\001\n";
2515 }
2516 
2517 void
2518 Text::flushSVG( std::ostream & stream,
2519  const TransformSVG & transform ) const
2520 {
2521  if ( _angle != 0.0f ) {
2522  stream << "<g transform=\"translate("
2523  << transform.mapX( _position.x ) << ","
2524  << transform.mapY( _position.y ) << ")\" >"
2525  << "<g transform=\"rotate(" << (-_angle*180.0/M_PI) << ")\" >"
2526  << "<text x=\"0\" y=\"0\""
2527  << " font-family=\"" << ( _svgFont.length() ? _svgFont : PSFontNames[ _font ] ) << "\""
2528  << " font-size=\"" << _size << "\""
2529  << " fill=\"" << _penColor.svg() << "\""
2530  << _fillColor.svgAlpha( " fill" )
2531  << _penColor.svgAlpha( " stroke" )
2532  << ">"
2533  << _text
2534  << "</text></g></g>" << std::endl;
2535  } else {
2536  stream << "<text x=\"" << transform.mapX( _position.x )
2537  << "\" y=\"" << transform.mapY( _position.y ) << "\" "
2538  << " font-family=\"" << ( _svgFont.length() ? _svgFont : PSFontNames[ _font ] ) << "\""
2539  << " font-size=\"" << _size << "\""
2540  << " fill=\"" << _penColor.svg() << "\""
2541  << _fillColor.svgAlpha( " fill" )
2542  << _penColor.svgAlpha( " stroke" )
2543  << ">"
2544  << _text
2545  << "</text>" << std::endl;
2546  }
2547 }
2548 
2549 #ifdef WITH_CAIRO
2550 void
2551 Text::flushCairo( cairo_t * /*cr*/,
2552  const TransformCairo & /*transform*/ ) const
2553 {
2554 }
2555 #endif
2556 
2557 void
2558 Text::flushTikZ( std::ostream & stream,
2559  const TransformTikZ & transform ) const
2560 {
2561  // FIXME: honor font-size
2562 #define BOLD_FONT 0x01
2563 #define ITALIC_FONT 0x02
2564 #define MONOSPACE_FONT 0x04
2565 #define SANSSERIF_FONT 0x08
2566  char fontTraits[] = {
2567  0, // TimesRoman,
2568  ITALIC_FONT, // TimesItalic,
2569  BOLD_FONT, // TimesBold,
2570  BOLD_FONT | ITALIC_FONT, // TimesBoldItalic,
2571  SANSSERIF_FONT, // AvantGardeBook,
2572  SANSSERIF_FONT | ITALIC_FONT, // AvantGardeBookOblique,
2573  SANSSERIF_FONT, // AvantGardeDemi,
2574  SANSSERIF_FONT | ITALIC_FONT, // AvantGardeDemiOblique,
2575  0, // BookmanLight,
2576  ITALIC_FONT, // BookmanLightItalic,
2577  0, // BookmanDemi,
2578  ITALIC_FONT, // BookmanDemiItalic,
2579  MONOSPACE_FONT, // Courier,
2580  MONOSPACE_FONT | ITALIC_FONT, // CourierOblique,
2581  MONOSPACE_FONT | BOLD_FONT, // CourierBold,
2582  MONOSPACE_FONT | BOLD_FONT | ITALIC_FONT, // CourierBoldOblique,
2583  SANSSERIF_FONT, // Helvetica,
2584  SANSSERIF_FONT | ITALIC_FONT, // HelveticaOblique,
2585  SANSSERIF_FONT | BOLD_FONT, // HelveticaBold,
2586  SANSSERIF_FONT | BOLD_FONT | ITALIC_FONT, // HelveticaBoldOblique,
2587  SANSSERIF_FONT, // HelveticaNarrow,
2588  SANSSERIF_FONT | ITALIC_FONT, // HelveticaNarrowOblique,
2589  SANSSERIF_FONT | BOLD_FONT, // HelveticaNarrowBold,
2590  SANSSERIF_FONT | BOLD_FONT | ITALIC_FONT, // HelveticaNarrowBoldOblique,
2591  0, // NewCenturySchoolbookRoman,
2592  ITALIC_FONT, // NewCenturySchoolbookItalic,
2593  BOLD_FONT, // NewCenturySchoolbookBold,
2594  BOLD_FONT | ITALIC_FONT, // NewCenturySchoolbookBoldItalic,
2595  0, // PalatinoRoman,
2596  ITALIC_FONT, // PalatinoItalic,
2597  BOLD_FONT, // PalatinoBold,
2598  BOLD_FONT | ITALIC_FONT, // PalatinoBoldItalic,
2599  0, // Symbol,
2600  ITALIC_FONT, // ZapfChanceryMediumItalic,
2601  0 // ZapfDingbats
2602  };
2603 
2604  stream << "\\path[" << tikzProperties(transform) << "] ("
2605  << transform.mapX( _position.x ) << ',' << transform.mapY( _position.y )
2606  << ") node {"
2607  << (fontTraits[ _font ] & ITALIC_FONT ? "\\itshape " : "")
2608  << (fontTraits[ _font ] & BOLD_FONT ? "\\bfseries " : "")
2609  << (fontTraits[ _font ] & MONOSPACE_FONT ? "\\ttfamily " : "")
2610  << (fontTraits[ _font ] & SANSSERIF_FONT ? "\\sffamily " : "")
2611  << _text
2612  << "};" << std::endl;
2613 }
2614 
2615 Rect
2616 Text::boundingBox() const
2617 {
2618  return Rect( _position.x, _position.y, 0, 0 );
2619 }
2620 
2621 } // namespace LibBoard