DGtal  0.6.devel
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Board.cpp
1 /* -*- mode: c++ -*- */
10 /*
11  * \@copyright This File is part of the Board library which is
12  * licensed under the terms of the GNU Lesser General Public Licence.
13  * See the LICENCE file for further details.
14  */
15 
16 
17 #include "Board.h"
18 #include "Board/Point.h"
19 #include "Board/Rect.h"
20 #include "Board/Shapes.h"
21 #include "Board/Tools.h"
22 #include "Board/PSFonts.h"
23 #include <fstream>
24 #include <iostream>
25 #include <iomanip>
26 #include <typeinfo>
27 #include <ctime>
28 #include <cstring>
29 #include <map>
30 #include <algorithm>
31 #include <cstdio>
32 
33 #ifdef WITH_CAIRO
34 // cairo
35 #include <cairo.h>
36 #include <cairo-pdf.h>
37 #include <cairo-ps.h>
38 #include <cairo-svg.h>
39 // cairo
40 #endif
41 
42 
43 #if defined( WIN32 )
44 #define _USE_MATH_DEFINES
45 #include <math.h>
46 #else
47 #include <cmath>
48 #endif //win32
49 
50 #ifdef _MSC_VER
51 //#define NOMINMAX
52 //#include <windows.h>
53 //#ifdef M_PI
54 //#undef M_PI
55 //#endif
56 //C++ exception specification ignored except
57 //to indicate a function is not __declspec(nothrow)
58 #pragma warning(disable : 4290)
59 #endif
60 
61 #ifdef _MSC_VER
62 #if defined( max )
63 #undef max
64 #define _HAS_MSVC_MAX_ true
65 #endif
66 #if defined( min )
67 #undef min
68 #define _HAS_MSVC_MIN_ true
69 #endif
70 #endif
71 
72 
73 namespace {
74  const float pageSizes[3][2] = { { 0.0f, 0.0f }, // BoundingBox
75  { 210.0f, 297.0f },
76  { 8.5f*25.4f, 11.0f*25.4f } };
77  const float ppmm = 720.0f / 254.0f;
78 }
79 
80 namespace LibBoard {
81 
82 const double Board::Degree = 3.14159265358979323846 / 180.0;
83 
85 {
88  lineWidth = 0.5;
93  fontSize = 11.0;
94  unitFactor = 1.0;
95 }
96 
97 Board::Board( const DGtal::Color & bgColor )
98  : _backgroundColor( bgColor )
99 {
100 }
101 
102 Board::Board( const Board & other )
103  : ShapeList( other ),
104  _state( other._state ),
105  _backgroundColor( other._backgroundColor )
106 {
107 }
108 
109 Board &
110 Board::operator=( const Board & other )
111 {
112  free();
113  if ( ! other._shapes.size() ) return (*this);
114  _shapes.resize( other._shapes.size(), 0 );
115  std::vector<Shape*>::iterator t = _shapes.begin();
116  std::vector<Shape*>::const_iterator i = other._shapes.begin();
117  std::vector<Shape*>::const_iterator end = other._shapes.end();
118  while ( i != end ) {
119  *t = (*i)->clone();
120  ++i; ++t;
121  }
122  return *this;
123 }
124 
125 Board &
126 Board::operator<<( const Shape & shape )
127 {
128  ShapeList::addShape( shape, _state.unitFactor );
129  return *this;
130 }
131 
132 Board &
133 Board::operator<<( Unit unit )
134 {
135  setUnit( unit );
136  return *this;
137 }
138 
139 Board::~Board()
140 {
141 
142 }
143 
144 void
145 Board::clear( const DGtal::Color & color )
146 {
147  ShapeList::clear();
148  _backgroundColor = color;
149 }
150 
151 
152 Shape &
153 Board::rotate( double angle, const Point & aCenter )
154 {
155  ShapeList::rotate( angle, aCenter );
156  _clippingPath.rotate( angle, aCenter );
157  return (*this);
158 }
159 
160 Shape &
161 Board::rotate( double angle )
162 {
163  ShapeList::rotate( angle );
164  _clippingPath.rotate( angle, center() );
165  return (*this);
166 }
167 
168 Shape &
169 Board::translate( double dx, double dy )
170 {
171  ShapeList::translate( dx, dy );
172  _clippingPath.translate( dx, dy );
173  return (*this);
174 }
175 
176 Shape &
177 Board::scale( double sx, double sy )
178 {
179  Point delta = _clippingPath.center() - center();
180  delta.x *= sx;
181  delta.y *= sy;
182  _clippingPath.scale( sx, sy );
183  ShapeList::scale( sx, sy );
184  delta = ( center() + delta ) - _clippingPath.center();
185  _clippingPath.translate( delta.x, delta.y );
186  return (*this);
187 }
188 
189 Shape &
190 Board::scale( double s )
191 {
192  Point delta = _clippingPath.center() - center();
193  delta *= s;
194  _clippingPath.scale( s );
195  ShapeList::scale( s );
196  delta = ( center() + delta ) - _clippingPath.center();
197  _clippingPath.translate( delta.x, delta.y );
198  return (*this);
199 }
200 
201 Board
202 Board::rotated( double angle, const Point & aCenter )
203 {
204  return static_cast<const Board &>( Board( *this ).rotate( angle, aCenter ) );
205 }
206 
207 Board
208 Board::rotated( double angle )
209 {
210  return static_cast<const Board &>( Board( *this ).rotate( angle ) );
211 }
212 
213 Board
214 Board::translated( double dx, double dy )
215 {
216  return static_cast<const Board &>( Board( *this ).translate( dx, dy ) );
217 }
218 
219 Board
220 Board::scaled( double sx, double sy )
221 {
222  return static_cast<const Board &>( Board( *this ).scale( sx, sy ) );
223 }
224 
225 Board
226 Board::scaled( double s )
227 {
228  return static_cast<const Board &>( Board( *this ).scale( s ) );
229 }
230 
231 
232 void
233 Board::setUnit( Unit unit )
234 {
235  switch ( unit ) {
236  case UPoint:
237  _state.unitFactor = 1.0;
238  break;
239  case UInche:
240  _state.unitFactor = 25.4f * ppmm;
241  break;
242  case UCentimeter:
243  _state.unitFactor = 10.0f * ppmm;
244  break;
245  case UMillimeter:
246  _state.unitFactor = ppmm;
247  break;
248  }
249 }
250 
251 void
252 Board::setUnit( double factor, Unit unit )
253 {
254  switch ( unit ) {
255  case UPoint:
256  _state.unitFactor = factor;
257  break;
258  case UInche:
259  _state.unitFactor = 720.0f * factor;
260  break;
261  case UCentimeter:
262  _state.unitFactor = 10.0f * ppmm * factor;
263  break;
264  case UMillimeter:
265  _state.unitFactor = ppmm * factor;
266  break;
267  }
268 }
269 
270 Board &
271 Board::setPenColorRGBi( unsigned char red,
272  unsigned char green,
273  unsigned char blue,
274  unsigned char alpha )
275 {
276  _state.penColor.setRGBi( red, green, blue, alpha );
277  return *this;
278 }
279 
280 Board &
281 Board::setPenColorRGBf( float red,
282  float green,
283  float blue,
284  float alpha )
285 {
286  _state.penColor.setRGBf( red, green, blue, alpha );
287  return *this;
288 }
289 
290 Board &
291 Board::setPenColor( const DGtal::Color & color )
292 {
293  _state.penColor = color;
294  return *this;
295 }
296 
297 Board &
298 Board::setFillColorRGBi( unsigned char red,
299  unsigned char green,
300  unsigned char blue,
301  unsigned char alpha )
302 {
303  _state.fillColor.setRGBi( red, green, blue, alpha );
304  return *this;
305 }
306 
307 Board &
308 Board::setFillColorRGBf( float red, float green, float blue, float alpha )
309 {
310  _state.fillColor.setRGBf( red, green, blue, alpha );
311  return *this;
312 }
313 
314 Board &
315 Board::setFillColor( const DGtal::Color & color )
316 {
317  _state.fillColor = color;
318  return *this;
319 }
320 
321 Board &
322 Board::setLineWidth( double width )
323 {
324  _state.lineWidth = width;
325  return *this;
326 }
327 
328 Board &
329 Board::setFont( const Fonts::Font font, double fontSize )
330 {
331  _state.font = font;
332  _state.fontSize = fontSize;
333  return *this;
334 }
335 
336 Board &
337 Board::setFontSize( double fontSize )
338 {
339  _state.fontSize = fontSize;
340  return *this;
341 }
342 
343 void
344 Board::backgroundColor( const DGtal::Color & color )
345 {
346  _backgroundColor = color;
347 }
348 
349 void
350 Board::drawDot( double x, double y, int depthValue )
351 {
352  if ( depthValue != -1 )
353  _shapes.push_back( new Dot( _state.unit(x), _state.unit(y),
354  _state.penColor, _state.lineWidth, depthValue ) );
355  else
356  _shapes.push_back( new Dot( _state.unit(x), _state.unit(y),
357  _state.penColor, _state.lineWidth, _nextDepth-- ) );
358 }
359 
360 void
361 Board::drawLine( double x1, double y1, double x2, double y2,
362  int depthValue /* = -1 */ )
363 {
364  if ( depthValue != -1 )
365  _shapes.push_back( new Line( _state.unit(x1), _state.unit(y1),
366  _state.unit(x2), _state.unit(y2),
367  _state.penColor, _state.lineWidth,
368  _state.lineStyle, _state.lineCap, _state.lineJoin, depthValue ) );
369  else
370  _shapes.push_back( new Line( _state.unit(x1), _state.unit(y1),
371  _state.unit(x2), _state.unit(y2),
372  _state.penColor, _state.lineWidth,
373  _state.lineStyle, _state.lineCap, _state.lineJoin, _nextDepth-- ) );
374 }
375 
376 void
377 Board::drawArrow( double x1, double y1, double x2, double y2,
378  bool filledArrow /* = false */,
379  int depthValue /* = -1 */ )
380 {
381  if ( depthValue != -1 )
382  _shapes.push_back( new Arrow( _state.unit(x1), _state.unit(y1),
383  _state.unit(x2), _state.unit(y2),
384  _state.penColor, filledArrow ? _state.penColor : DGtal::Color::None,
385  _state.lineWidth, _state.lineStyle, _state.lineCap, _state.lineJoin, depthValue ) );
386  else
387  _shapes.push_back( new Arrow( _state.unit(x1), _state.unit(y1),
388  _state.unit(x2), _state.unit(y2),
389  _state.penColor, filledArrow ? _state.penColor : DGtal::Color::None,
390  _state.lineWidth, _state.lineStyle, _state.lineCap, _state.lineJoin, _nextDepth-- ) );
391 }
392 
393 void
394 Board::drawRectangle( double x, double y,
395  double width, double height,
396  int depthValue /* = -1 */ )
397 {
398  int d = (depthValue != -1) ? depthValue : _nextDepth--;
399  _shapes.push_back( new Rectangle( _state.unit(x), _state.unit(y), _state.unit(width), _state.unit(height),
400  _state.penColor, _state.fillColor,
401  _state.lineWidth, _state.lineStyle, _state.lineCap, _state.lineJoin, d ) );
402 }
403 
404 void
405 Board::drawImage(std::string filename, double x, double y,
406  double width, double height,
407  int depthValue, double alpha /* = -1 */ )
408 {
409  int d = (depthValue != -1) ? depthValue : _nextDepth--;
410  _shapes.push_back( new Image( _state.unit(x), _state.unit(y), _state.unit(width), _state.unit(height),
411  filename, d, alpha ) );
412 }
413 
414 
415 void
416 Board::fillRectangle( double x, double y,
417  double width, double height,
418  int depthValue /* = -1 */ )
419 {
420  int d = (depthValue != -1) ? depthValue : _nextDepth--;
421  _shapes.push_back( new Rectangle( _state.unit(x), _state.unit(y), _state.unit(width), _state.unit(height),
422  DGtal::Color::None, _state.penColor,
423  0.0f, _state.lineStyle, _state.lineCap, _state.lineJoin,
424  d ) );
425 }
426 
427 void
428 Board::drawCircle( double x, double y, double radius,
429  int depthValue /* = -1 */ )
430 {
431  int d = (depthValue != -1) ? depthValue : _nextDepth--;
432  _shapes.push_back( new Circle( _state.unit(x), _state.unit(y), _state.unit(radius),
433  _state.penColor, _state.fillColor,
434  _state.lineWidth, _state.lineStyle, d ) );
435 }
436 
437 void
438 Board::drawArc(double x, double y, double radius, double angle1, double angle2,
439  bool neg, int depthValue /*= -1*/ ){
440  int d = (depthValue != -1) ? depthValue : _nextDepth--;
441  _shapes.push_back( new Arc( _state.unit(x), _state.unit(y), _state.unit(radius),
442  angle1, angle2, neg,_state.penColor,
443  DGtal::Color::None, _state.lineWidth, _state.lineStyle, d ) );
444 }
445 
446 
447 void
448 Board::fillCircle( double x, double y,
449  double radius,
450  int depthValue /* = -1 */ )
451 {
452  int d = (depthValue != -1) ? depthValue : _nextDepth--;
453  _shapes.push_back( new Circle( _state.unit(x), _state.unit(y), _state.unit(radius),
454  DGtal::Color::None, _state.penColor,
455  0.0f, _state.lineStyle, d ) );
456 }
457 
458 void
459 Board::drawEllipse( double x, double y,
460  double xRadius, double yRadius,
461  int depthValue /* = -1 */ )
462 {
463  int d = (depthValue != -1) ? depthValue : _nextDepth--;
464  _shapes.push_back( new Ellipse( _state.unit(x), _state.unit(y),
465  _state.unit(xRadius), _state.unit(yRadius),
466  _state.penColor,
467  _state.fillColor,
468  _state.lineWidth,
469  _state.lineStyle,
470  d ) );
471 }
472 
473 void
474 Board::fillEllipse( double x, double y,
475  double xRadius, double yRadius,
476  int depthValue /* = -1 */ )
477 {
478  int d = depthValue ? depthValue : _nextDepth--;
479  _shapes.push_back( new Ellipse( _state.unit(x), _state.unit(y), _state.unit(xRadius), _state.unit(yRadius),
481  _state.penColor,
482  0.0f,
483  _state.lineStyle,
484  d ) );
485 }
486 
487 void
488 Board::drawPolyline( const std::vector<Point> & points,
489  int depthValue /* = -1 */ )
490 {
491  int d = (depthValue != -1) ? depthValue : _nextDepth--;
492  std::vector<Point> v = points;
493  std::vector<Point>::iterator it = v.begin();
494  std::vector<Point>::iterator end = v.end();
495  while ( it != end ) {
496  (*it) = _state.unit( *it );
497  ++it;
498  }
499  _shapes.push_back( new Polyline( v, false, _state.penColor, _state.fillColor,
500  _state.lineWidth,
501  _state.lineStyle,
502  _state.lineCap,
503  _state.lineJoin,
504  d ) );
505 }
506 
507 void
508 Board::drawClosedPolyline( const std::vector<Point> & points,
509  int depthValue /* = -1 */ )
510 {
511  int d = (depthValue != -1) ? depthValue : _nextDepth--;
512  std::vector<Point> v = points;
513  std::vector<Point>::iterator it = v.begin();
514  std::vector<Point>::iterator end = v.end();
515  while ( it != end ) {
516  (*it) = _state.unit( *it );
517  ++it;
518  }
519  _shapes.push_back( new Polyline( v, true, _state.penColor, _state.fillColor,
520  _state.lineWidth,
521  _state.lineStyle,
522  _state.lineCap,
523  _state.lineJoin,
524  d ) );
525 }
526 
527 void
528 Board::fillPolyline( const std::vector<Point> & points,
529  int depthValue /* = -1 */ )
530 {
531  int d = (depthValue != -1) ? depthValue : _nextDepth--;
532  std::vector<Point> v = points;
533  std::vector<Point>::iterator it = v.begin();
534  std::vector<Point>::iterator end = v.end();
535  while ( it != end ) {
536  (*it) = _state.unit( *it );
537  ++it;
538  }
539  _shapes.push_back( new Polyline( v, true, DGtal::Color::None, _state.penColor,
540  0.0f,
541  _state.lineStyle,
542  _state.lineCap,
543  _state.lineJoin,
544  d ) );
545 }
546 
547 void
548 Board::drawTriangle( double x1, double y1,
549  double x2, double y2,
550  double x3, double y3,
551  int depthValue /* = -1 */ )
552 {
553  int d = (depthValue != -1) ? depthValue : _nextDepth--;
554  std::vector<Point> points;
555  points.push_back( Point( _state.unit(x1), _state.unit(y1) ) );
556  points.push_back( Point( _state.unit(x2), _state.unit(y2) ) );
557  points.push_back( Point( _state.unit(x3), _state.unit(y3) ) );
558  _shapes.push_back( new Polyline( points, true, _state.penColor, _state.fillColor,
559  _state.lineWidth,
560  _state.lineStyle,
561  _state.lineCap,
562  _state.lineJoin,
563  d ) );
564 }
565 
566 void
567 Board::drawTriangle( const Point & p1,
568  const Point & p2,
569  const Point & p3,
570  int depthValue /* = -1 */ )
571 {
572  int d = (depthValue != -1) ? depthValue : _nextDepth--;
573  std::vector<Point> points;
574  points.push_back( Point( _state.unit(p1.x), _state.unit(p1.y) ) );
575  points.push_back( Point( _state.unit(p2.x), _state.unit(p2.y) ) );
576  points.push_back( Point( _state.unit(p3.x), _state.unit(p3.y) ) );
577  _shapes.push_back( new Polyline( points, true, _state.penColor, _state.fillColor,
578  _state.lineWidth,
579  _state.lineStyle,
580  _state.lineCap,
581  _state.lineJoin,
582  d ) );
583 }
584 
585 void
586 Board::fillTriangle( double x1, double y1,
587  double x2, double y2,
588  double x3, double y3,
589  int depthValue /* = -1 */ )
590 {
591  int d = (depthValue != -1) ? depthValue : _nextDepth--;
592  std::vector<Point> points;
593  points.push_back( Point( _state.unit(x1), _state.unit(y1) ) );
594  points.push_back( Point( _state.unit(x2), _state.unit(y2) ) );
595  points.push_back( Point( _state.unit(x3), _state.unit(y3) ) );
596  _shapes.push_back( new Polyline( points, true, DGtal::Color::None, _state.penColor,
597  0.0f,
598  _state.lineStyle,
599  _state.lineCap,
600  _state.lineJoin,
601  d ) );
602 }
603 
604 void
605 Board::fillTriangle( const Point & p1,
606  const Point & p2,
607  const Point & p3,
608  int depthValue /* = -1 */ )
609 {
610  int d = (depthValue != -1) ? depthValue : _nextDepth--;
611  std::vector<Point> points;
612  points.push_back( Point( _state.unit(p1.x), _state.unit(p1.y) ) );
613  points.push_back( Point( _state.unit(p2.x), _state.unit(p2.y) ) );
614  points.push_back( Point( _state.unit(p3.x), _state.unit(p3.y) ) );
615  _shapes.push_back( new Polyline( points, true, DGtal::Color::None, _state.penColor,
616  0.0f,
617  _state.lineStyle,
618  _state.lineCap,
619  _state.lineJoin,
620  d ) );
621 }
622 
623 void
624 Board::fillGouraudTriangle( const Point & p1,
625  const DGtal::Color & color1,
626  const Point & p2,
627  const DGtal::Color & color2,
628  const Point & p3,
629  const DGtal::Color & color3,
630  unsigned char divisions,
631  int depthValue /* = -1 */ )
632 {
633  int d = (depthValue != -1) ? depthValue : _nextDepth--;
634  _shapes.push_back( new GouraudTriangle( Point( _state.unit(p1.x), _state.unit(p1.y) ), color1,
635  Point( _state.unit(p2.x), _state.unit(p2.y) ), color2,
636  Point( _state.unit(p3.x), _state.unit(p3.y) ), color3,
637  divisions, d ) );
638 }
639 
640 void
641 Board::fillGouraudTriangle( const Point & p1,
642  const float brightness1,
643  const Point & p2,
644  const float brightness2,
645  const Point & p3,
646  const float brightness3,
647  unsigned char divisions,
648  int depthValue /* = -1 */ )
649 {
650  DGtal::Color color1( _state.penColor );
651  DGtal::Color color2( _state.penColor );
652  DGtal::Color color3( _state.penColor );
653  color1.red( static_cast<unsigned char>( std::min( 255.0f, color1.red() * brightness1 ) ) );
654  color1.green( static_cast<unsigned char>( std::min( 255.0f, color1.green() * brightness1 ) ) );
655  color1.blue( static_cast<unsigned char>( std::min( 255.0f, color1.blue() * brightness1 ) ) );
656  color2.red( static_cast<unsigned char>( std::min( 255.0f, color2.red() * brightness2 ) ) );
657  color2.green( static_cast<unsigned char>( std::min( 255.0f, color2.green() * brightness2 ) ) );
658  color2.blue( static_cast<unsigned char>( std::min( 255.0f, color2.blue() * brightness2 ) ) );
659  color3.red( static_cast<unsigned char>( std::min( 255.0f, color3.red() * brightness3 ) ) );
660  color3.green( static_cast<unsigned char>( std::min( 255.0f, color3.green() * brightness3 ) ) );
661  color3.blue( static_cast<unsigned char>( std::min( 255.0f, color3.blue() * brightness3 ) ) );
662  fillGouraudTriangle( Point( _state.unit(p1.x), _state.unit(p1.y) ), color1,
663  Point( _state.unit(p2.x), _state.unit(p2.y) ), color2,
664  Point( _state.unit(p3.x), _state.unit(p3.y) ), color3,
665  divisions,
666  depthValue );
667 }
668 
669 void
670 Board::drawText( double x, double y, const char * text,
671  int depthValue /* = -1 */ )
672 {
673  int d = (depthValue != -1) ? depthValue : _nextDepth--;
674  _shapes.push_back( new Text( _state.unit(x), _state.unit(y), text,
675  _state.font, _state.fontSize, _state.penColor, d ) );
676 }
677 
678 void
679 Board::drawText( double x, double y, const std::string & str, int depthValue /* = -1 */ )
680 {
681  int d = (depthValue != -1) ? depthValue : _nextDepth--;
682  _shapes.push_back( new Text( _state.unit(x), _state.unit(y), str,
683  _state.font, _state.fontSize, _state.penColor, d ) );
684 }
685 
686 void
687 Board::drawBoundingBox( int depthValue /* = -1 */ )
688 {
689  int d = (depthValue != -1) ? depthValue : _nextDepth--;
690  Rect box = boundingBox();
691  _shapes.push_back( new Rectangle( _state.unit(box.left),
692  _state.unit(box.top),
693  _state.unit(box.width),
694  _state.unit(box.height),
695  _state.penColor,
696  _state.fillColor,
697  _state.lineWidth,
698  _state.lineStyle,
699  _state.lineCap,
700  _state.lineJoin,
701  d ) );
702 }
703 
704 void
705 Board::setClippingRectangle( double xLeft, double yTop,
706  double rectWidth, double rectHeight )
707 {
708  _clippingPath.clear();
709  _clippingPath << _state.unit( Point( xLeft, yTop ) );
710  _clippingPath << _state.unit( Point( xLeft + rectWidth, yTop ) );
711  _clippingPath << _state.unit( Point( xLeft + rectWidth, yTop - rectHeight) );
712  _clippingPath << _state.unit( Point( xLeft , yTop - rectHeight ) );
713 }
714 
715 void
716 Board::setClippingPath( const std::vector<Point> & points )
717 {
718  _clippingPath.clear();
719  std::vector<Point>::const_iterator it = points.begin();
720  std::vector<Point>::const_iterator end = points.end();
721  while ( it != end ) {
722  _clippingPath << _state.unit( *it );
723  ++it;
724  }
725 }
726 
727 void
728 Board::setClippingPath( const Path & path )
729 {
730  _clippingPath = path;
731  _clippingPath.setClosed( true );
732  if ( _clippingPath.size() > 1 ) {
733  if ( _clippingPath[0] == _clippingPath[ _clippingPath.size() - 1 ] )
734  _clippingPath.pop_back();
735  }
736  unsigned int n = _clippingPath.size();
737  for ( unsigned int i = 0; i < n; ++i ) {
738  _clippingPath[i] = _state.unit( _clippingPath[i] );
739  }
740 }
741 
742 
743 void
744 Board::addDuplicates( const Shape & shape,
745  unsigned int times,
746  double dx, double dy, double scaleValue )
747 {
748  Shape * s = shape.clone();
749  while ( times-- ) {
750  (*this) << (*s);
751  if ( scaleValue != 1.0 )
752  s->scale( scaleValue );
753  s->translate( dx, dy );
754  }
755  delete s;
756 }
757 
758 void
759 Board::addDuplicates( const Shape & shape,
760  unsigned int times,
761  double dx, double dy,
762  double scaleX, double scaleY,
763  double angle )
764 {
765  Shape * s = shape.clone();
766  while ( times-- ) {
767  (*this) << (*s);
768  if ( scaleX != 1.0 || scaleY != 1.0 ) s->scale( scaleX, scaleY );
769  if ( dx != 0.0 || dy != 0.0 ) s->translate( dx, dy );
770  if ( angle != 0.0 ) s->rotate( angle );
771  }
772  delete s;
773 }
774 
775 void
776 Board::saveEPS( std::ostream &out, PageSize size, double margin ) const
777 {
778  saveEPS( out, pageSizes[size][0], pageSizes[size][1], margin );
779 }
780 
781 void
782 Board::saveEPS( const char * filename, PageSize size, double margin ) const
783 {
784  saveEPS( filename, pageSizes[size][0], pageSizes[size][1], margin );
785 }
786 
787 
788 void
789 Board::saveEPS( const char * filename, double pageWidth, double pageHeight, double margin ) const
790 {
791  std::ofstream file( filename );
792  saveEPS(file, pageWidth, pageHeight, margin);
793  file.close();
794 }
795 
796 void
797 Board::saveEPS( std::ostream &out, double pageWidth, double pageHeight, double margin ) const
798 {
799  Rect box = boundingBox();
800  bool clipping = _clippingPath.size() > 2;
801  if ( clipping )
802  box = box && _clippingPath.boundingBox();
803 
804  TransformEPS transform;
805  transform.setBoundingBox( box, pageWidth, pageHeight, margin );
806 
807  out << "%!PS-Adobe-2.0 EPSF-2.0" << std::endl;
808  out << "%%Title: output.eps " << std::endl;
809  out << "%%Creator: Board library (Copyleft)2007 Sebastien Fourey" << std::endl;
810  {
811  time_t t = time(0);
812  char str_time[255];
813  secured_ctime( str_time, &t, 255 );
814  out << "%%CreationDate: " << str_time;
815  }
816  out << "%%BoundingBox: " << std::setprecision( 8 )
817  << transform.mapX( box.left ) << " "
818  << transform.mapY( box.top - box.height ) << " "
819  << transform.mapX( box.left + box.width ) << " "
820  << transform.mapY( box.top ) << std::endl;
821 
822  out << "%Magnification: 1.0000" << std::endl;
823  out << "%%EndComments" << std::endl;
824 
825  out << std::endl;
826  out << "/cp {closepath} bind def" << std::endl;
827  out << "/ef {eofill} bind def" << std::endl;
828  out << "/gr {grestore} bind def" << std::endl;
829  out << "/gs {gsave} bind def" << std::endl;
830  out << "/sa {save} bind def" << std::endl;
831  out << "/rs {restore} bind def" << std::endl;
832  out << "/l {lineto} bind def" << std::endl;
833  out << "/m {moveto} bind def" << std::endl;
834  out << "/rm {rmoveto} bind def" << std::endl;
835  out << "/n {newpath} bind def" << std::endl;
836  out << "/s {stroke} bind def" << std::endl;
837  out << "/sh {show} bind def" << std::endl;
838  out << "/slc {setlinecap} bind def" << std::endl;
839  out << "/slj {setlinejoin} bind def" << std::endl;
840  out << "/slw {setlinewidth} bind def" << std::endl;
841  out << "/srgb {setrgbcolor} bind def" << std::endl;
842  out << "/rot {rotate} bind def" << std::endl;
843  out << "/sc {scale} bind def" << std::endl;
844  out << "/sd {setdash} bind def" << std::endl;
845  out << "/ff {findfont} bind def" << std::endl;
846  out << "/sf {setfont} bind def" << std::endl;
847  out << "/scf {scalefont} bind def" << std::endl;
848  out << "/sw {stringwidth} bind def" << std::endl;
849  out << "/sd {setdash} bind def" << std::endl;
850  out << "/tr {translate} bind def" << std::endl;
851  out << " 0.5 setlinewidth" << std::endl;
852 
853  if ( clipping ) {
854  out << " newpath ";
855  _clippingPath.flushPostscript( out, transform );
856  out << " 0 slw clip " << std::endl;
857  }
858 
859  // Draw the background color if needed.
860  if ( _backgroundColor != DGtal::Color::None ) {
861  Rectangle r( box, DGtal::Color::None, _backgroundColor, 0.0f );
862  r.flushPostscript( out, transform );
863  }
864 
865  // Draw the shapes
866  std::vector< Shape* > shapes = _shapes;
867 
868  stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
869  std::vector< Shape* >::const_iterator i = shapes.begin();
870  std::vector< Shape* >::const_iterator end = shapes.end();
871 
872  while ( i != end ) {
873  (*i)->flushPostscript( out, transform );
874  ++i;
875  }
876  out << "showpage" << std::endl;
877  out << "%%Trailer" << std::endl;
878  out << "%EOF" << std::endl;
879 }
880 
881 
882 
883 void
884 Board::saveFIG( const char * filename, PageSize size, double margin, bool includeFIGHeader ) const
885 {
886  saveFIG( filename, pageSizes[size][0], pageSizes[size][1], margin, includeFIGHeader );
887 }
888 void
889 Board::saveFIG( std::ostream &out, PageSize size, double margin, bool includeFIGHeader ) const
890 {
891  saveFIG( out, pageSizes[size][0], pageSizes[size][1], margin, includeFIGHeader );
892 }
893 void
894 Board::saveFIG( const char * filename, double pageWidth, double pageHeight, double margin,
895  bool includeFIGHeader ) const
896 {
897  std::ofstream file( filename );
898  saveFIG( file, pageWidth, pageHeight, margin, includeFIGHeader);
899  file.close();
900 }
901 
902 void
903 Board::saveFIG( std::ostream &file, double pageWidth, double pageHeight, double margin, bool includeFIGHeader ) const
904 {
905 
906 
907  TransformFIG transform;
908  Rect box = boundingBox();
909  transform.setBoundingBox( box, pageWidth, pageHeight, margin );
910  transform.setDepthRange( *this );
911  if(includeFIGHeader){
912  file << "#FIG 3.2 Produced by the Board library (Copyleft)2007 Sebastien Fourey\n";
913  file << "Portrait\n";
914  file << "Center\n";
915  file << "Metric\n";
916  file << "A4\n";
917  file << "100.00\n";
918  file << "Single\n";
919  file << "-2\n";
920  file << "1200 2\n";
921  }else{
922  file << "\n";
923  }
924  std::map<DGtal::Color,int> colormap;
925  int maxColor = 32;
926 
927 
928  colormap[DGtal::Color(0,0,0)] = 0;
929  colormap[DGtal::Color(0,0,255)] = 1;
930  colormap[DGtal::Color(0,255,0)] = 2;
931  colormap[DGtal::Color(0,255,255)] = 0;
932  colormap[DGtal::Color(255,0,0)] = 4;
933  colormap[DGtal::Color(255,0,255)] = 0;
934  colormap[DGtal::Color(255,255,0)] = 6;
935  colormap[DGtal::Color(255,255,255)] = 7;
936 
937 
938  std::vector< Shape* > shapes = _shapes;
939  stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
940  std::vector< Shape* >::const_iterator i = shapes.begin();
941  std::vector< Shape* >::const_iterator end = shapes.end();
942  while ( i != end ) {
943  if ( colormap.find( (*i)->penColor() ) == colormap.end()
944  && (*i)->penColor().valid() )
945  colormap[ (*i)->penColor() ] = maxColor++;
946  if ( colormap.find( (*i)->fillColor() ) == colormap.end()
947  && (*i)->fillColor().valid() )
948  colormap[ (*i)->fillColor() ] = maxColor++;
949  ++i;
950  }
951 
952  if ( colormap.find( _backgroundColor ) == colormap.end()
953  && _backgroundColor.valid() )
954  colormap[ _backgroundColor ] = maxColor++;
955 
956  // Write the colormap
957  std::map<DGtal::Color,int>::const_iterator iColormap = colormap.begin();
958  std::map<DGtal::Color,int>::const_iterator endColormap = colormap.end();
959  char colorString[255];
960  while ( iColormap != endColormap ) {
961  secured_sprintf( colorString, 255,
962  "0 %d #%02x%02x%02x\n",
963  iColormap->second,
964  iColormap->first.red(),
965  iColormap->first.green(),
966  iColormap->first.blue() );
967  if ( iColormap->second >= 32 ) file << colorString;
968  ++iColormap;
969  }
970 
971  // Draw the background color if needed.
972  if ( _backgroundColor != DGtal::Color::None ) {
973  Rectangle r( box, DGtal::Color::None, _backgroundColor, 0.0f );
974  r.depth( std::numeric_limits<int>::max() );
975  r.flushFIG( file, transform, colormap );
976  }
977 
978  // Draw the shapes.
979  i = shapes.begin();
980  while ( i != end ) {
981  // notice << (*i)->name() << " " << (*i)->depth() << '\n';
982  (*i)->flushFIG( file, transform, colormap );
983  ++i;
984  }
985 }
986 
987 
988 void
989 Board::saveSVG( const char * filename, PageSize size, double margin ) const
990 {
991  saveSVG( filename, pageSizes[size][0], pageSizes[size][1], margin );
992 }
993 
994 void
995 Board::saveSVG( std::ostream &out, PageSize size, double margin ) const
996 {
997  saveSVG( out, pageSizes[size][0], pageSizes[size][1], margin );
998 }
999 
1000 
1001 void
1002 Board::saveSVG( const char * filename, double pageWidth, double pageHeight, double margin ) const
1003 {
1004  std::ofstream file( filename );
1005  saveSVG(file, pageWidth, pageHeight, margin);
1006  file.close();
1007 }
1008 
1009 
1010 
1011 void
1012 Board::saveSVG( std::ostream &file, double pageWidth, double pageHeight, double margin, string filename ) const
1013 {
1014 
1015  TransformSVG transform;
1016  Rect box = boundingBox();
1017  bool clipping = _clippingPath.size() > 2;
1018  if ( clipping )
1019  box = box && _clippingPath.boundingBox();
1020  transform.setBoundingBox( box, pageWidth, pageHeight, margin );
1021 
1022  file << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"no\"?>" << std::endl;
1023  file << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"" << std::endl;
1024  file << " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" << std::endl;
1025 
1026  if ( pageWidth > 0 && pageHeight > 0 ) {
1027  file << "<svg width=\""
1028  << pageWidth << "mm\" height=\""
1029  << pageHeight << "mm\" " << std::endl;
1030  file << " viewBox=\"0 0 "
1031  << pageWidth * ppmm << " "
1032  << pageHeight * ppmm << "\" " << std::endl;
1033  file << " xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" >" << std::endl;
1034  } else {
1035  file << "<svg width=\""
1036  << ( box.width / ppmm ) << "mm"
1037  << "\" height=\""
1038  << ( box.height / ppmm ) << "mm"
1039  << "\" " << std::endl;
1040  file << " viewBox=\"0 0 "
1041  << box.width << " "
1042  << box.height << "\" " << std::endl;
1043  file << " xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" >" << std::endl;
1044 
1045  }
1046 
1047  file << "<desc>" << filename
1048  << ", created with the Board library (Copyleft) 2007 Sebastien Fourey"
1049  << "</desc>" << std::endl;
1050 
1051  if ( clipping ) {
1052  file << "<g clip-rule=\"nonzero\">\n"
1053  << " <clipPath id=\"GlobalClipPath\">\n"
1054  << " <path clip-rule=\"evenodd\" d=\"";
1055  _clippingPath.flushSVGCommands( file, transform );
1056  file << "\" />\n";
1057  file << " </clipPath>\n";
1058  file << "<g clip-path=\"url(#GlobalClipPath)\">\n";
1059  }
1060 
1061  // Draw the background color if needed.
1062  if ( _backgroundColor != DGtal::Color::None ) {
1063  Rectangle r( box, DGtal::Color::None, _backgroundColor, 0.0 );
1064  r.flushSVG( file, transform );
1065  }
1066 
1067  // Draw the shapes.
1068  std::vector< Shape* > shapes = _shapes;
1069  stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
1070  std::vector< Shape* >::const_iterator i = shapes.begin();
1071  std::vector< Shape* >::const_iterator end = shapes.end();
1072  while ( i != end ) {
1073  (*i)->flushSVG( file, transform );
1074  ++i;
1075  }
1076 
1077  if ( clipping )
1078  file << "</g>\n</g>";
1079  file << "</svg>" << std::endl;
1080 
1081 }
1082 
1083 
1084 void
1085 Board::save( const char * filename, double pageWidth, double pageHeight, double margin ) const
1086 {
1087  const char * extension = filename + strlen( filename );
1088  while ( extension > filename && *extension != '.' )
1089  --extension;
1090  if ( !(strcmp( extension, ".eps" )) || !(strcmp( extension, ".EPS" )) ) {
1091  saveEPS( filename, pageWidth, pageHeight, margin );
1092  return;
1093  }
1094  if ( !(strcmp( extension, ".fig" )) || !(strcmp( extension, ".FIG" )) ) {
1095  saveFIG( filename, pageWidth, pageHeight, margin );
1096  return;
1097  }
1098  if ( !(strcmp( extension, ".svg" )) || !(strcmp( extension, ".SVG" )) ) {
1099  saveSVG( filename, pageWidth, pageHeight, margin );
1100  return;
1101  }
1102  if ( !(strcmp( extension, ".tikz" )) || !(strcmp( extension, ".TIKZ" )) ) {
1103  saveTikZ( filename, pageWidth, pageHeight, margin );
1104  return;
1105  }
1106 }
1107 
1108 void
1109 Board::save( const char * filename, PageSize size, double margin ) const
1110 {
1111  save( filename, pageSizes[size][0], pageSizes[size][1], margin );
1112 }
1113 
1114 #ifdef WITH_CAIRO
1115 void
1116 Board::saveCairo( const char * filename, CairoType type, PageSize size, double margin ) const
1117 {
1118  saveCairo( filename, type, pageSizes[size][0], pageSizes[size][1], margin );
1119 }
1120 void
1121 Board::saveCairo( const char * filename, CairoType type, double pageWidth, double pageHeight, double margin ) const
1122 {
1123  cairo_surface_t *surface;
1124  cairo_t *cr;
1125 
1126  double cairoWidth, cairoHeight;
1127 
1128  TransformCairo transform;
1129  Rect box = boundingBox();
1130 
1131  bool clipping = _clippingPath.size() > 2;
1132  if ( clipping )
1133  box = box && _clippingPath.boundingBox();
1134  transform.setBoundingBox( box, pageWidth, pageHeight, margin );
1135 
1136  if ( pageWidth > 0 && pageHeight > 0 )
1137  {
1138  cairoWidth = pageWidth;
1139  cairoHeight = pageHeight;
1140  }
1141  else
1142  {
1143  cairoWidth = box.width;
1144  cairoHeight = box.height;
1145  }
1146 
1147  switch (type)
1148  {
1149  case CairoPDF:
1150  surface = cairo_pdf_surface_create (filename, cairoWidth, cairoHeight); break;
1151  case CairoPS:
1152  surface = cairo_ps_surface_create (filename, cairoWidth, cairoHeight); break;
1153  case CairoEPS:
1154  surface = cairo_ps_surface_create (filename, cairoWidth, cairoHeight);
1155  cairo_ps_surface_set_eps(surface, true); break;
1156  case CairoSVG:
1157  surface = cairo_svg_surface_create (filename, cairoWidth, cairoHeight); break;
1158  case CairoPNG:
1159  default:
1160  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, (int)cairoWidth, (int)cairoHeight);
1161  }
1162 
1163  cr = cairo_create (surface);
1164 
1165  /* For 1.0 x 1.0 coordinate space */
1166  //cairo_scale (cr, cairoWidth, cairoHeight);
1167 
1168  //temp: http://zetcode.com/tutorials/cairographicstutorial/basicdrawing/
1169  //temp: http://www.graphviz.org/pub/scm/graphviz-cairo/plugin/cairo/gvrender_cairo.c
1170 
1171  // Draw the background color if needed.
1172  if ( _backgroundColor != DGtal::Color::None ) {
1173  Rectangle r( box, DGtal::Color::None, _backgroundColor, 0.0 );
1174  r.flushCairo( cr, transform );
1175  }
1176 
1177  // Draw the shapes.
1178  std::vector< Shape* > shapes = _shapes;
1179  stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
1180  std::vector< Shape* >::const_iterator i = shapes.begin();
1181  std::vector< Shape* >::const_iterator end = shapes.end();
1182  while ( i != end ) {
1183  (*i)->flushCairo( cr, transform );
1184  ++i;
1185  }
1186 
1187  if (type==CairoPNG)
1188  cairo_surface_write_to_png (surface, filename);
1189 
1190  cairo_destroy (cr);
1191  cairo_surface_destroy (surface);
1192 }
1193 #endif
1194 
1195 void
1196 Board::saveTikZ( const char * filename, PageSize size, double margin ) const
1197 {
1198  saveTikZ( filename, pageSizes[size][0], pageSizes[size][1], margin );
1199 }
1200 
1201 void
1202 Board::saveTikZ( std::ostream & out, PageSize size, double margin ) const
1203 {
1204  saveTikZ( out, pageSizes[size][0], pageSizes[size][1], margin );
1205 }
1206 
1207 void
1208 Board::saveTikZ( const char * filename, double pageWidth, double pageHeight, double margin ) const
1209 {
1210  std::ofstream file( filename );
1211  saveTikZ(file, pageHeight, pageHeight, margin);
1212  file.close();
1213 }
1214 
1215 void
1216 Board::saveTikZ( std::ostream &out, double pageWidth, double pageHeight, double margin ) const
1217 {
1218  TransformTikZ transform;
1219  Rect box = boundingBox();
1220  bool clipping = _clippingPath.size() > 2;
1221  if ( clipping )
1222  box = box && _clippingPath.boundingBox();
1223  transform.setBoundingBox( box, pageWidth, pageHeight, margin );
1224 
1225  out << "\\begin{tikzpicture}[anchor=south west,text depth=0,x={(1pt,0pt)},y={(0pt,-1pt)}]" << std::endl;
1226 
1227 /*
1228  if ( pageWidth > 0 && pageHeight > 0 ) {
1229  out << "<svg width=\""
1230  << pageWidth << "mm\" height=\""
1231  << pageHeight << "mm\" " << std::endl;
1232  out << " viewBox=\"0 0 "
1233  << pageWidth * ppmm << " "
1234  << pageHeight * ppmm << "\" " << std::endl;
1235  out << " xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" >" << std::endl;
1236  } else {
1237  out << "<svg width=\""
1238  << ( box.width / ppmm ) << "mm"
1239  << "\" height=\""
1240  << ( box.height / ppmm ) << "mm"
1241  << "\" " << std::endl;
1242  out << " viewBox=\"0 0 "
1243  << box.width << " "
1244  << box.height << "\" " << std::endl;
1245  out << " xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" >" << std::endl;
1246 
1247  }
1248 
1249  out << "<desc>" << filename
1250  << ", created with the Board library (Copyleft) 2007 Sebastien Fourey"
1251  << "</desc>" << std::endl;*/
1252 
1253  if ( clipping ) {
1254  out << "\\clip ";
1255  _clippingPath.flushSVGCommands( out, transform );
1256  out << "\n";
1257  }
1258 
1259  // Draw the background color if needed.
1260  if ( _backgroundColor != Color::None ) {
1261  Rectangle r( box, Color::None, _backgroundColor, 0.0 );
1262  r.flushTikZ( out, transform );
1263  }
1264 
1265  // Draw the shapes.
1266  std::vector< Shape* > shapes = _shapes;
1267  stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
1268  std::vector< Shape* >::const_iterator i = shapes.begin();
1269  std::vector< Shape* >::const_iterator end = shapes.end();
1270  while ( i != end ) {
1271  (*i)->flushTikZ( out, transform );
1272  ++i;
1273  }
1274 
1275  //if ( clipping )
1276  // out << "</g>\n</g>";
1277  out << "\\end{tikzpicture}" << std::endl;
1278 }
1279 
1280 
1281 } // namespace LibBoard;
1282 
1283