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