1 /* -*- mode: c++ -*- */
2 /**
3 * @file Board.cpp
4 * @author Sebastien Fourey (GREYC)
5 * @date Aug 2007
6 *
7 * @brief
8 * \@copyright
9 * This source code is part of the Board project, a C++ library whose
10 * purpose is to allow simple drawings in EPS, FIG or SVG files.
11 * Copyright (C) 2007 Sebastien Fourey <http://foureys.users.greyc.fr/>
12 *
13 * This program is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as published
15 * by the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details
22 *
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 */
26
27 #include "Board.h"
28 #include "board/Point.h"
29 #include "board/Rect.h"
30 #include "board/Shapes.h"
31 #include "board/Tools.h"
32 #include "board/PSFonts.h"
33 #include <fstream>
34 #include <iostream>
35 #include <iomanip>
36 #include <typeinfo>
37 #include <ctime>
38 #include <cstring>
39 #include <map>
40 #include <algorithm>
41 #include <cstdio>
42 #include <algorithm>
43
44 #if defined( max )
45 #undef max
46 #endif
47
48 namespace {
49
50 const float pageSizes[][2] = { { 0.0f, 0.0f }, // BoundingBox
51 { 841.0f, 1189.0f }, // A0
52 { 594.0f, 841.0f }, // A1
53 { 420.0f, 594.0f }, // A2
54 { 297.0f, 420.0f }, // A3
55 { 210.0f, 297.0f }, // A4
56 { 148.0f, 210.0f }, // A5
57 { 105.0f, 148.0f }, // A6
58 { 74.0f, 105.0f }, // A7
59 { 52.0f, 74.0f }, // A8
60 { 37.0f, 52.0f }, // A9
61 { 26.0f, 37.0f }, // A10
62 { 8.5f*25.4f, 11.0f*25.4f }, // Letter
63 { 8.5f*25.4f, 14.0f*25.4f }, // Legal
64 { 7.2f*25.4f, 10.5f*25.4f } // Executive
65 };
66
67 const float ppmm = 72.0f / 25.4f;
68 }
69
70 namespace LibBoard {
71
72 const double Board::Degree = 3.14159265358979323846 / 180.0;
73
State()74 Board::State::State()
75 {
76 penColor = Color::Black;
77 fillColor = Color::Null;
78 lineWidth = 0.5;
79 lineStyle = Shape::SolidStyle;
80 lineCap = Shape::ButtCap;
81 lineJoin = Shape::MiterJoin;
82 font = Fonts::TimesRoman;
83 fontSize = 11.0;
84 }
85
Board(const Color & backgroundColor)86 Board::Board( const Color & backgroundColor )
87 : _backgroundColor( backgroundColor )
88 {
89 }
90
Board(const Board & other)91 Board::Board( const Board & other )
92 : ShapeList( other ),
93 _state( other._state ),
94 _backgroundColor( other._backgroundColor )
95 {
96 }
97
98 Board &
operator =(const Board & other)99 Board::operator=( const Board & other )
100 {
101 free();
102 if ( ! other._shapes.size() ) return (*this);
103 _shapes.resize( other._shapes.size(), 0 );
104 std::vector<Shape*>::iterator t = _shapes.begin();
105 std::vector<Shape*>::const_iterator i = other._shapes.begin();
106 std::vector<Shape*>::const_iterator end = other._shapes.end();
107 while ( i != end ) {
108 *t = (*i)->clone();
109 ++i; ++t;
110 }
111 return *this;
112 }
113
114 Board &
operator <<(const Shape & shape)115 Board::operator<<( const Shape & shape )
116 {
117 ShapeList::addShape( shape, 1.0 );
118 return *this;
119 }
120
~Board()121 Board::~Board()
122 {
123 }
124
125 void
clear(const Color & color)126 Board::clear( const Color & color )
127 {
128 ShapeList::clear();
129 _backgroundColor = color;
130 }
131
132 Board &
rotate(double angle,const Point & center)133 Board::rotate( double angle, const Point & center )
134 {
135 ShapeList::rotate( angle, center );
136 _clippingPath.rotate( angle, center );
137 return (*this);
138 }
139
140 Board &
rotate(double angle)141 Board::rotate( double angle )
142 {
143 ShapeList::rotate( angle );
144 _clippingPath.rotate( angle, center() );
145 return (*this);
146 }
147
148 Board &
translate(double dx,double dy)149 Board::translate( double dx, double dy )
150 {
151 ShapeList::translate( dx, dy );
152 _clippingPath.translate( dx, dy );
153 return (*this);
154 }
155
156 Board &
scale(double sx,double sy)157 Board::scale( double sx, double sy )
158 {
159 if ( _clippingPath.size() ) {
160 Point delta = _clippingPath.center() - center();
161 delta.x *= sx;
162 delta.y *= sy;
163 _clippingPath.scale( sx, sy );
164 ShapeList::scale( sx, sy );
165 delta = ( center() + delta ) - _clippingPath.center();
166 _clippingPath.translate( delta.x, delta.y );
167 } else {
168 ShapeList::scale( sx, sy );
169 }
170 return (*this);
171 }
172
173 Board &
scale(double s)174 Board::scale( double s )
175 {
176 if ( _clippingPath.size() ) {
177 Point delta = _clippingPath.center() - center();
178 delta *= s;
179 _clippingPath.scale( s );
180 ShapeList::scale( s );
181 delta = ( center() + delta ) - _clippingPath.center();
182 _clippingPath.translate( delta.x, delta.y );
183 } else {
184 ShapeList::scale( s );
185 }
186 return (*this);
187 }
188
189 Board
rotated(double angle,const Point & center)190 Board::rotated( double angle, const Point & center )
191 {
192 return static_cast<const Board &>( Board( *this ).rotate( angle, center ) );
193 }
194
195 Board
rotated(double angle)196 Board::rotated( double angle )
197 {
198 return static_cast<const Board &>( Board( *this ).rotate( angle ) );
199 }
200
201 Board
translated(double dx,double dy)202 Board::translated( double dx, double dy )
203 {
204 return static_cast<const Board &>( Board( *this ).translate( dx, dy ) );
205 }
206
207 Board
scaled(double sx,double sy)208 Board::scaled( double sx, double sy )
209 {
210 return static_cast<const Board &>( Board( *this ).scale( sx, sy ) );
211 }
212
213 Board
scaled(double s)214 Board::scaled( double s )
215 {
216 return static_cast<const Board &>( Board( *this ).scale( s ) );
217 }
218
219 Board &
setPenColorRGBi(unsigned char red,unsigned char green,unsigned char blue,unsigned char alpha)220 Board::setPenColorRGBi( unsigned char red,
221 unsigned char green,
222 unsigned char blue,
223 unsigned char alpha )
224 {
225 _state.penColor.setRGBi( red, green, blue, alpha );
226 return *this;
227 }
228
229 Board &
setPenColorRGBf(float red,float green,float blue,float alpha)230 Board::setPenColorRGBf( float red,
231 float green,
232 float blue,
233 float alpha )
234 {
235 _state.penColor.setRGBf( red, green, blue, alpha );
236 return *this;
237 }
238
239 Board &
setPenColor(const Color & color)240 Board::setPenColor( const Color & color )
241 {
242 _state.penColor = color;
243 return *this;
244 }
245
246 Board &
setFillColorRGBi(unsigned char red,unsigned char green,unsigned char blue,unsigned char alpha)247 Board::setFillColorRGBi( unsigned char red,
248 unsigned char green,
249 unsigned char blue,
250 unsigned char alpha )
251 {
252 _state.fillColor.setRGBi( red, green, blue, alpha );
253 return *this;
254 }
255
256 Board &
setFillColorRGBf(float red,float green,float blue,float alpha)257 Board::setFillColorRGBf( float red, float green, float blue, float alpha )
258 {
259 _state.fillColor.setRGBf( red, green, blue, alpha );
260 return *this;
261 }
262
263 Board &
setFillColor(const Color & color)264 Board::setFillColor( const Color & color )
265 {
266 _state.fillColor = color;
267 return *this;
268 }
269
270 Board &
setLineWidth(double width)271 Board::setLineWidth( double width )
272 {
273 _state.lineWidth = width;
274 return *this;
275 }
276
277 Board &
setFont(const Fonts::Font font,double fontSize)278 Board::setFont( const Fonts::Font font, double fontSize )
279 {
280 _state.font = font;
281 _state.fontSize = fontSize;
282 return *this;
283 }
284
285 Board &
setFontSize(double fontSize)286 Board::setFontSize( double fontSize )
287 {
288 _state.fontSize = fontSize;
289 return *this;
290 }
291
292 void
backgroundColor(const Color & color)293 Board::backgroundColor( const Color & color )
294 {
295 _backgroundColor = color;
296 }
297
298 void
drawDot(double x,double y,int depth)299 Board::drawDot( double x, double y, int depth )
300 {
301 if ( depth != -1 )
302 _shapes.push_back( new Dot( x, y, _state.penColor, _state.lineWidth, depth ) );
303 else
304 _shapes.push_back( new Dot( x, y, _state.penColor, _state.lineWidth, _nextDepth-- ) );
305 }
306
307 void
drawLine(double x1,double y1,double x2,double y2,int depth)308 Board::drawLine( double x1, double y1, double x2, double y2,
309 int depth /* = -1 */ )
310 {
311 if ( depth != -1 )
312 _shapes.push_back( new Line( x1, y1,
313 x2, y2,
314 _state.penColor, _state.lineWidth,
315 _state.lineStyle, _state.lineCap,
316 _state.lineJoin, depth ) );
317 else
318 _shapes.push_back( new Line( x1, y1,
319 x2, y2,
320 _state.penColor, _state.lineWidth,
321 _state.lineStyle, _state.lineCap,
322 _state.lineJoin, _nextDepth-- ) );
323 }
324
325 void
drawLine(Point p,Point q,int depth)326 Board::drawLine( Point p, Point q, int depth /* = -1 */ )
327 {
328 if ( depth != -1 )
329 _shapes.push_back( new Line( p.x, p.y,
330 q.x, q.y,
331 _state.penColor, _state.lineWidth,
332 _state.lineStyle, _state.lineCap,
333 _state.lineJoin, depth ) );
334 else
335 _shapes.push_back( new Line( p.x, p.y,
336 q.x, q.y,
337 _state.penColor, _state.lineWidth,
338 _state.lineStyle, _state.lineCap,
339 _state.lineJoin, _nextDepth-- ) );
340 }
341
342 void
drawArrow(double x1,double y1,double x2,double y2,int depth)343 Board::drawArrow( double x1, double y1, double x2, double y2, int depth /* = -1 */ )
344 {
345 if ( depth != -1 )
346 _shapes.push_back( new Arrow( x1, y1,
347 x2, y2,
348 _state.penColor,
349 _state.fillColor,
350 _state.lineWidth, _state.lineStyle,
351 _state.lineCap, _state.lineJoin, depth ) );
352 else
353 _shapes.push_back( new Arrow( x1, y1,
354 x2, y2,
355 _state.penColor,
356 _state.fillColor,
357 _state.lineWidth, _state.lineStyle,
358 _state.lineCap, _state.lineJoin,
359 _nextDepth-- ) );
360 }
361
362 void
drawArrow(Point p,Point q,int depth)363 Board::drawArrow( Point p, Point q, int depth /* = -1 */ )
364 {
365 if ( depth != -1 )
366 _shapes.push_back( new Arrow( p.x, p.y,
367 q.x, q.y,
368 _state.penColor,
369 _state.fillColor,
370 _state.lineWidth, _state.lineStyle,
371 _state.lineCap, _state.lineJoin, depth ) );
372 else
373 _shapes.push_back( new Arrow( p.x, p.y,
374 q.x, q.y,
375 _state.penColor,
376 _state.fillColor,
377 _state.lineWidth, _state.lineStyle,
378 _state.lineCap, _state.lineJoin,
379 _nextDepth-- ) );
380 }
381
382 void
drawRectangle(double left,double top,double width,double height,int depth)383 Board::drawRectangle( double left, double top,
384 double width, double height,
385 int depth /* = -1 */ )
386 {
387 int d = (depth!=-1) ? depth : _nextDepth--;
388 _shapes.push_back( new Rectangle( left,
389 top,
390 width,
391 height,
392 _state.penColor, _state.fillColor,
393 _state.lineWidth, _state.lineStyle,
394 _state.lineCap, _state.lineJoin, d ) );
395 }
396
397 void
drawRectangle(const Rect & r,int depth)398 Board::drawRectangle(const Rect & r, int depth)
399 {
400 int d = (depth!=-1) ? depth : _nextDepth--;
401 _shapes.push_back( new Rectangle( r.left,
402 r.top,
403 r.width,
404 r.height,
405 _state.penColor, _state.fillColor,
406 _state.lineWidth, _state.lineStyle,
407 _state.lineCap, _state.lineJoin, d ) );
408 }
409
410 void
fillRectangle(double left,double top,double width,double height,int depth)411 Board::fillRectangle( double left, double top,
412 double width, double height,
413 int depth /* = -1 */ )
414 {
415 int d = (depth!=-1) ? depth : _nextDepth--;
416 _shapes.push_back( new Rectangle( left,
417 top,
418 width,
419 height,
420 Color::Null, _state.penColor,
421 0.0f, _state.lineStyle,
422 _state.lineCap, _state.lineJoin,
423 d ) );
424 }
425
426 void
fillRectangle(const Rect & r,int depth)427 Board::fillRectangle(const Rect & r, int depth)
428 {
429 int d = (depth!=-1) ? depth : _nextDepth--;
430 _shapes.push_back( new Rectangle( r.left,
431 r.top,
432 r.width,
433 r.height,
434 Color::Null, _state.penColor,
435 0.0f, _state.lineStyle,
436 _state.lineCap, _state.lineJoin,
437 d ) );
438 }
439
440 void
drawCircle(double x,double y,double radius,int depth)441 Board::drawCircle( double x, double y, double radius,
442 int depth /* = -1 */ )
443 {
444 int d = (depth!=-1) ? depth : _nextDepth--;
445 _shapes.push_back( new Circle( x, y,
446 radius,
447 _state.penColor, _state.fillColor,
448 _state.lineWidth, _state.lineStyle, d ) );
449 }
450
451 void
fillCircle(double x,double y,double radius,int depth)452 Board::fillCircle( double x, double y, double radius,
453 int depth /* = -1 */ )
454 {
455 int d = (depth!=-1) ? depth : _nextDepth--;
456 _shapes.push_back( new Circle( x, y, radius,
457 Color::Null, _state.penColor,
458 0.0f, _state.lineStyle, d ) );
459 }
460
461 void
drawEllipse(double x,double y,double xRadius,double yRadius,int depth)462 Board::drawEllipse( double x, double y,
463 double xRadius, double yRadius,
464 int depth /* = -1 */ )
465 {
466 int d = (depth!=-1) ? depth : _nextDepth--;
467 _shapes.push_back( new Ellipse( x, y,
468 xRadius, yRadius,
469 _state.penColor,
470 _state.fillColor,
471 _state.lineWidth,
472 _state.lineStyle,
473 d ) );
474 }
475
476 void
fillEllipse(double x,double y,double xRadius,double yRadius,int depth)477 Board::fillEllipse( double x, double y,
478 double xRadius, double yRadius,
479 int depth /* = -1 */ )
480 {
481 int d = depth ? depth : _nextDepth--;
482 _shapes.push_back( new Ellipse( x, y,
483 xRadius, yRadius,
484 Color::Null,
485 _state.penColor,
486 0.0f,
487 _state.lineStyle,
488 d ) );
489 }
490
491 void
drawPolyline(const std::vector<Point> & points,int depth)492 Board::drawPolyline( const std::vector<Point> & points,
493 int depth /* = -1 */ )
494 {
495 int d = (depth!=-1) ? depth : _nextDepth--;
496 _shapes.push_back( new Polyline( points,
497 false,
498 _state.penColor,
499 _state.fillColor,
500 _state.lineWidth,
501 _state.lineStyle,
502 _state.lineCap,
503 _state.lineJoin,
504 d ) );
505 }
506
507 void
drawClosedPolyline(const std::vector<Point> & points,int depth)508 Board::drawClosedPolyline( const std::vector<Point> & points,
509 int depth /* = -1 */ )
510 {
511 int d = (depth!=-1) ? depth : _nextDepth--;
512 _shapes.push_back( new Polyline( points, true, _state.penColor, _state.fillColor,
513 _state.lineWidth,
514 _state.lineStyle,
515 _state.lineCap,
516 _state.lineJoin,
517 d ) );
518 }
519
520 void
fillPolyline(const std::vector<Point> & points,int depth)521 Board::fillPolyline( const std::vector<Point> & points,
522 int depth /* = -1 */ )
523 {
524 int d = (depth!=-1) ? depth : _nextDepth--;
525 _shapes.push_back( new Polyline( points, true, Color::Null, _state.penColor,
526 0.0f,
527 _state.lineStyle,
528 _state.lineCap,
529 _state.lineJoin,
530 d ) );
531 }
532
533 void
drawTriangle(double x1,double y1,double x2,double y2,double x3,double y3,int depth)534 Board::drawTriangle( double x1, double y1,
535 double x2, double y2,
536 double x3, double y3,
537 int depth /* = -1 */ )
538 {
539 int d = (depth!=-1) ? depth : _nextDepth--;
540 std::vector<Point> points;
541 points.push_back( Point( x1, y1 ) );
542 points.push_back( Point( x2, y2 ) );
543 points.push_back( Point( x3, y3 ) );
544 _shapes.push_back( new Polyline( points, true, _state.penColor, _state.fillColor,
545 _state.lineWidth,
546 _state.lineStyle,
547 _state.lineCap,
548 _state.lineJoin,
549 d ) );
550 }
551
552 void
drawTriangle(const Point & p1,const Point & p2,const Point & p3,int depth)553 Board::drawTriangle( const Point & p1,
554 const Point & p2,
555 const Point & p3,
556 int depth /* = -1 */ )
557 {
558 int d = (depth!=-1) ? depth : _nextDepth--;
559 std::vector<Point> points;
560 points.push_back( Point( p1.x, p1.y ) );
561 points.push_back( Point( p2.x, p2.y ) );
562 points.push_back( Point( p3.x, p3.y ) );
563 _shapes.push_back( new Polyline( points, true,
564 _state.penColor, _state.fillColor,
565 _state.lineWidth,
566 _state.lineStyle,
567 _state.lineCap,
568 _state.lineJoin,
569 d ) );
570 }
571
572 void
fillTriangle(double x1,double y1,double x2,double y2,double x3,double y3,int depth)573 Board::fillTriangle( double x1, double y1,
574 double x2, double y2,
575 double x3, double y3,
576 int depth /* = -1 */ )
577 {
578 int d = (depth!=-1) ? depth : _nextDepth--;
579 std::vector<Point> points;
580 points.push_back( Point( x1, y1 ) );
581 points.push_back( Point( x2, y2 ) );
582 points.push_back( Point( x3, y3 ) );
583 _shapes.push_back( new Polyline( points, true, Color::Null, _state.penColor,
584 0.0f,
585 _state.lineStyle,
586 _state.lineCap,
587 _state.lineJoin,
588 d ) );
589 }
590
591 void
fillTriangle(const Point & p1,const Point & p2,const Point & p3,int depth)592 Board::fillTriangle( const Point & p1,
593 const Point & p2,
594 const Point & p3,
595 int depth /* = -1 */ )
596 {
597 int d = (depth!=-1) ? depth : _nextDepth--;
598 std::vector<Point> points;
599 points.push_back( Point( p1.x, p1.y ) );
600 points.push_back( Point( p2.x, p2.y ) );
601 points.push_back( Point( p3.x, p3.y ) );
602 _shapes.push_back( new Polyline( points, true, Color::Null, _state.penColor,
603 0.0f,
604 _state.lineStyle,
605 _state.lineCap,
606 _state.lineJoin,
607 d ) );
608 }
609
610 void
fillGouraudTriangle(const Point & p1,const Color & color1,const Point & p2,const Color & color2,const Point & p3,const Color & color3,unsigned char divisions,int depth)611 Board::fillGouraudTriangle( const Point & p1,
612 const Color & color1,
613 const Point & p2,
614 const Color & color2,
615 const Point & p3,
616 const Color & color3,
617 unsigned char divisions,
618 int depth /* = -1 */ )
619 {
620 int d = (depth!=-1) ? depth : _nextDepth--;
621 _shapes.push_back( new GouraudTriangle( p1, color1,
622 p2, color2,
623 p3, color3,
624 divisions, d ) );
625 }
626
627 void
fillGouraudTriangle(const Point & p1,const float brightness1,const Point & p2,const float brightness2,const Point & p3,const float brightness3,unsigned char divisions,int depth)628 Board::fillGouraudTriangle( const Point & p1,
629 const float brightness1,
630 const Point & p2,
631 const float brightness2,
632 const Point & p3,
633 const float brightness3,
634 unsigned char divisions,
635 int depth /* = -1 */ )
636 {
637 Color color1( _state.penColor );
638 Color color2( _state.penColor );
639 Color color3( _state.penColor );
640 color1.red( static_cast<unsigned char>( std::min( 255.0f, color1.red() * brightness1 ) ) );
641 color1.green( static_cast<unsigned char>( std::min( 255.0f, color1.green() * brightness1 ) ) );
642 color1.blue( static_cast<unsigned char>( std::min( 255.0f, color1.blue() * brightness1 ) ) );
643 color2.red( static_cast<unsigned char>( std::min( 255.0f, color2.red() * brightness2 ) ) );
644 color2.green( static_cast<unsigned char>( std::min( 255.0f, color2.green() * brightness2 ) ) );
645 color2.blue( static_cast<unsigned char>( std::min( 255.0f, color2.blue() * brightness2 ) ) );
646 color3.red( static_cast<unsigned char>( std::min( 255.0f, color3.red() * brightness3 ) ) );
647 color3.green( static_cast<unsigned char>( std::min( 255.0f, color3.green() * brightness3 ) ) );
648 color3.blue( static_cast<unsigned char>( std::min( 255.0f, color3.blue() * brightness3 ) ) );
649 fillGouraudTriangle( p1, color1,
650 p2, color2,
651 p3, color3,
652 divisions,
653 depth );
654 }
655
656 void
drawText(double x,double y,const char * text,int depth)657 Board::drawText( double x, double y, const char * text, int depth /* = -1 */ )
658 {
659 int d = (depth!=-1) ? depth : _nextDepth--;
660 _shapes.push_back( new Text( x, y, text,
661 _state.font, _state.fontSize,
662 _state.penColor, d ) );
663 }
664
drawText(Point p,const char * text,int depth)665 void Board::drawText( Point p, const char *text, int depth )
666 {
667 int d = (depth!=-1) ? depth : _nextDepth--;
668 _shapes.push_back( new Text( p, text, _state.font, _state.fontSize, _state.penColor, d ) );
669 }
670
671 void
drawText(double x,double y,const std::string & str,int depth)672 Board::drawText( double x, double y, const std::string & str, int depth /* = -1 */ )
673 {
674 int d = (depth!=-1) ? depth : _nextDepth--;
675 _shapes.push_back( new Text( x,
676 y,
677 str,
678 _state.font,
679 _state.fontSize,
680 _state.penColor, d ) );
681 }
682
drawText(Point p,const std::string & str,int depth)683 void Board::drawText( Point p, const std::string & str, int depth )
684 {
685 int d = (depth!=-1) ? depth : _nextDepth--;
686 _shapes.push_back( new Text( p,
687 str,
688 _state.font,
689 _state.fontSize,
690 _state.penColor, d ) );
691 }
692
693 void
drawBoundingBox(LineWidthFlag lineWidthFlag,int depth)694 Board::drawBoundingBox( LineWidthFlag lineWidthFlag, int depth )
695 {
696 int d = (depth!=-1) ? depth : _nextDepth--;
697 Rect bbox = boundingBox(lineWidthFlag);
698 _shapes.push_back( new Rectangle( bbox.left,
699 bbox.top,
700 bbox.width,
701 bbox.height,
702 _state.penColor,
703 _state.fillColor,
704 _state.lineWidth,
705 _state.lineStyle,
706 _state.lineCap,
707 _state.lineJoin,
708 d ) );
709 }
710
711 void
setClippingRectangle(double x,double y,double width,double height)712 Board::setClippingRectangle( double x, double y, double width, double height )
713 {
714 _clippingPath.clear();
715 _clippingPath << Point( x, y );
716 _clippingPath << Point( x + width, y );
717 _clippingPath << Point( x + width, y - height );
718 _clippingPath << Point( x , y - height );
719 }
720
721 void
setClippingRectangle(const Rect & rect)722 Board::setClippingRectangle( const Rect & rect)
723 {
724 setClippingRectangle(rect.left,rect.top,rect.width,rect.height);
725 }
726
727 void
setClippingPath(const std::vector<Point> & points)728 Board::setClippingPath( const std::vector<Point> & points )
729 {
730 _clippingPath.clear();
731 std::vector<Point>::const_iterator it = points.begin();
732 std::vector<Point>::const_iterator end = points.end();
733 while ( it != end ) {
734 _clippingPath << *it ;
735 ++it;
736 }
737 }
738
739 void
setClippingPath(const Path & path)740 Board::setClippingPath( const Path & path )
741 {
742 _clippingPath = path;
743 _clippingPath.setClosed( true );
744 if ( _clippingPath.size() > 1 ) {
745 if ( _clippingPath[0] == _clippingPath[ _clippingPath.size() - 1 ] )
746 _clippingPath.pop_back();
747 }
748 }
749
750 void
addDuplicates(const Shape & shape,std::size_t times,double dx,double dy,double scale)751 Board::addDuplicates( const Shape & shape, std::size_t times, double dx, double dy, double scale )
752 {
753 Shape * s = shape.clone();
754 while ( times-- ) {
755 (*this) << (*s);
756 if ( scale != 1.0 )
757 s->scale( scale );
758 s->translate( dx, dy );
759 }
760 delete s;
761 }
762
763 void
addDuplicates(const Shape & shape,std::size_t times,double dx,double dy,double scaleX,double scaleY,double angle)764 Board::addDuplicates( const Shape & shape,
765 std::size_t times,
766 double dx, double dy,
767 double scaleX, double scaleY,
768 double angle )
769 {
770 Shape * s = shape.clone();
771 while ( times-- ) {
772 (*this) << (*s);
773 if ( scaleX != 1.0 || scaleY != 1.0 ) s->scale( scaleX, scaleY );
774 if ( dx != 0.0 || dy != 0.0 ) s->translate( dx, dy );
775 if ( angle != 0.0 ) s->rotate( angle );
776 }
777 delete s;
778 }
779
780 void
saveEPS(const char * filename,PageSize size,double margin,Unit unit,const std::string & title) const781 Board::saveEPS( const char * filename, PageSize size, double margin, Unit unit, const std::string & title ) const
782 {
783 if ( size == BoundingBox ) {
784 if ( title == std::string() )
785 saveEPS( filename, 0.0, 0.0, margin, unit, filename );
786 else
787 saveEPS( filename, 0.0, 0.0, margin, unit, title );
788 } else {
789 if ( title == std::string() )
790 saveEPS( filename, pageSizes[size][0], pageSizes[size][1], toMillimeter(margin,unit), UMillimeter, filename );
791 else
792 saveEPS( filename, pageSizes[size][0], pageSizes[size][1], toMillimeter(margin,unit), UMillimeter, title );
793 }
794 }
795
796 void
saveEPS(std::ostream & out,PageSize size,double margin,Unit unit,const std::string & title) const797 Board::saveEPS(std::ostream & out, PageSize size, double margin, Unit unit, const std::string & title ) const
798 {
799 if ( size == BoundingBox ) {
800 saveEPS( out, 0.0, 0.0, margin, unit, title );
801 } else {
802 saveEPS( out, pageSizes[size][0], pageSizes[size][1], toMillimeter(margin,unit), UMillimeter, title );
803 }
804 }
805
806 void
saveEPS(std::ostream & out,double pageWidth,double pageHeight,double margin,Unit unit,const std::string & title) const807 Board::saveEPS( std::ostream & out, double pageWidth, double pageHeight, double margin, Unit unit, const std::string & title ) const
808 {
809 out << "%!PS-Adobe-2.0 EPSF-2.0" << std::endl;
810 out << "%%Title: " << title << std::endl;
811 out << "%%Creator: Board library (v" << _BOARD_VERSION_STRING_ << ") Copyleft 2007 Sebastien Fourey" << std::endl;
812 {
813 time_t t = time(0);
814 char str_time[255];
815 Tools::secured_ctime( str_time, &t, 255 );
816 out << "%%CreationDate: " << str_time;
817 }
818
819 Rect bbox = boundingBox(UseLineWidth);
820 bool clipping = _clippingPath.size() > 2;
821 if ( clipping ) {
822 bbox = bbox && _clippingPath.boundingBox();
823 }
824 TransformEPS transform;
825 if ( pageWidth == 0.0 && pageHeight == 0.0 ) { // Fit to bounding box using given unit.
826 transform.setBoundingBox( bbox,
827 toMillimeter(bbox.width,unit),
828 toMillimeter(bbox.height,unit),
829 -toMillimeter(margin,unit) );
830
831 Rect page = transform.pageBoundingBox();
832 out << "%%BoundingBox: "
833 << std::setprecision( 8 )
834 << page.left << " "
835 << page.bottom() << " "
836 << page.right() << " "
837 << page.top << std::endl;
838
839
840 } else {
841 transform.setBoundingBox( bbox,
842 toMillimeter(pageWidth,unit),
843 toMillimeter(pageHeight,unit),
844 toMillimeter(margin,unit) );
845 Rect page = transform.pageBoundingBox();
846 out << "%%BoundingBox: "
847 << std::setprecision( 8 )
848 << page.left << " "
849 << page.bottom() << " "
850 << page.right() << " "
851 << page.top << std::endl;
852 }
853
854
855 out << "%Magnification: 1.0000" << std::endl;
856 out << "%%EndComments" << std::endl;
857
858 out << "\n"
859 "/cp {closepath} bind def\n"
860 "/ef {eofill} bind def\n"
861 "/gr {grestore} bind def\n"
862 "/gs {gsave} bind def\n"
863 "/sa {save} bind def\n"
864 "/rs {restore} bind def\n"
865 "/l {lineto} bind def\n"
866 "/m {moveto} bind def\n"
867 "/rm {rmoveto} bind def\n"
868 "/n {newpath} bind def\n"
869 "/s {stroke} bind def\n"
870 "/sh {show} bind def\n"
871 "/slc {setlinecap} bind def\n"
872 "/slj {setlinejoin} bind def\n"
873 "/slw {setlinewidth} bind def\n"
874 "/srgb {setrgbcolor} bind def\n"
875 "/rot {rotate} bind def\n"
876 "/sc {scale} bind def\n"
877 "/sd {setdash} bind def\n"
878 "/ff {findfont} bind def\n"
879 "/sf {setfont} bind def\n"
880 "/scf {scalefont} bind def\n"
881 "/sw {stringwidth} bind def\n"
882 "/sd {setdash} bind def\n"
883 "/tr {translate} bind def\n"
884 " 0.5 setlinewidth\n";
885
886 if ( clipping ) {
887 out << " newpath ";
888 _clippingPath.flushPostscript( out, transform );
889 out << " 0 slw clip " << std::endl;
890 }
891
892 // Draw the background color if needed.
893 if ( _backgroundColor != Color::Null ) {
894 Rectangle r( bbox, Color::Null, _backgroundColor, 0.0f );
895 r.flushPostscript( out, transform );
896 }
897
898 // Draw the shapes
899 std::vector< Shape* > shapes = _shapes;
900
901 stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
902 std::vector< Shape* >::const_iterator i = shapes.begin();
903 std::vector< Shape* >::const_iterator end = shapes.end();
904
905 while ( i != end ) {
906 (*i)->flushPostscript( out, transform );
907 ++i;
908 }
909 out << "showpage" << std::endl;
910 out << "%%Trailer" << std::endl;
911 out << "%EOF" << std::endl;
912 }
913
914 void
saveEPS(const char * filename,double pageWidth,double pageHeight,double margin,Unit unit,const std::string & title) const915 Board::saveEPS( const char * filename, double pageWidth, double pageHeight, double margin, Unit unit, const std::string & title ) const
916 {
917 std::ofstream out(filename);
918 saveEPS(out,pageWidth,pageHeight,margin,unit,title);
919 out.close();
920 }
921
922 void
saveFIG(const char * filename,PageSize size,double margin,Unit unit) const923 Board::saveFIG( const char * filename, PageSize size, double margin, Unit unit ) const
924 {
925 if ( size == BoundingBox ) {
926 saveFIG( filename, 0.0, 0.0, margin, unit );
927 } else {
928 saveFIG( filename, pageSizes[size][0], pageSizes[size][1], toMillimeter(margin,unit), UMillimeter );
929 }
930 }
931
932 void
saveFIG(std::ostream & out,PageSize size,double margin,Unit unit) const933 Board::saveFIG( std::ostream & out, PageSize size, double margin, Unit unit ) const
934 {
935 if ( size == BoundingBox ) {
936 saveFIG( out, 0.0, 0.0, margin, unit );
937 } else {
938 saveFIG( out, pageSizes[size][0], pageSizes[size][1], toMillimeter(margin,unit), UMillimeter );
939 }
940 }
941
942 void
saveFIG(std::ostream & out,double pageWidth,double pageHeight,double margin,Unit unit) const943 Board::saveFIG( std::ostream & out, double pageWidth, double pageHeight, double margin, Unit unit ) const
944 {
945 Rect bbox = boundingBox(UseLineWidth);
946 TransformFIG transform;
947
948 if ( pageWidth == 0.0 && pageHeight == 0.0 ) {
949 transform.setBoundingBox( bbox,
950 toMillimeter(bbox.width,unit),
951 toMillimeter(bbox.height,unit),
952 -toMillimeter(margin,unit) );
953 } else {
954 transform.setBoundingBox( bbox,
955 toMillimeter(pageWidth,unit),
956 toMillimeter(pageHeight,unit),
957 toMillimeter(margin,unit) );
958 }
959
960 transform.setDepthRange( *this );
961
962 out << "#FIG 3.2 Produced by the Board library (v"
963 _BOARD_VERSION_STRING_
964 ") Copyleft 2007 Sebastien Fourey\n";
965 out << "Portrait\n"
966 "Center\n"
967 "Metric\n"
968 "A4\n"
969 "100.00\n"
970 "Single\n"
971 "-2\n"
972 "1200 2\n";
973
974 std::map<Color,int> colormap;
975 int maxColor = 32;
976
977
978 colormap[Color(0,0,0)] = 0;
979 colormap[Color(0,0,255)] = 1;
980 colormap[Color(0,255,0)] = 2;
981 colormap[Color(0,255,255)] = 0;
982 colormap[Color(255,0,0)] = 4;
983 colormap[Color(255,0,255)] = 0;
984 colormap[Color(255,255,0)] = 6;
985 colormap[Color(255,255,255)] = 7;
986
987
988 std::vector< Shape* > shapes = _shapes;
989 stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
990 std::vector< Shape* >::const_iterator i = shapes.begin();
991 std::vector< Shape* >::const_iterator end = shapes.end();
992 while ( i != end ) {
993 if ( colormap.find( (*i)->penColor() ) == colormap.end()
994 && (*i)->penColor().valid() )
995 colormap[ (*i)->penColor() ] = maxColor++;
996 if ( colormap.find( (*i)->fillColor() ) == colormap.end()
997 && (*i)->fillColor().valid() )
998 colormap[ (*i)->fillColor() ] = maxColor++;
999 ++i;
1000 }
1001
1002 if ( colormap.find( _backgroundColor ) == colormap.end()
1003 && _backgroundColor.valid() )
1004 colormap[ _backgroundColor ] = maxColor++;
1005
1006 // Write the colormap
1007 std::map<Color,int>::const_iterator iColormap = colormap.begin();
1008 std::map<Color,int>::const_iterator endColormap = colormap.end();
1009 char colorString[255];
1010 while ( iColormap != endColormap ) {
1011 secured_sprintf( colorString, 255,
1012 "0 %d #%02x%02x%02x\n",
1013 iColormap->second,
1014 iColormap->first.red(),
1015 iColormap->first.green(),
1016 iColormap->first.blue() );
1017 if ( iColormap->second >= 32 ) out << colorString;
1018 ++iColormap;
1019 }
1020
1021 // Draw the background color if needed.
1022 if ( _backgroundColor != Color::Null ) {
1023 Rectangle r( bbox, Color::Null, _backgroundColor, 0.0f );
1024 r.depth( std::numeric_limits<int>::max() );
1025 r.flushFIG( out, transform, colormap );
1026 }
1027
1028 // Draw the shapes.
1029 i = shapes.begin();
1030 while ( i != end ) {
1031 (*i)->flushFIG( out, transform, colormap );
1032 ++i;
1033 }
1034 }
1035
1036 void
saveFIG(const char * filename,double pageWidth,double pageHeight,double margin,Unit unit) const1037 Board::saveFIG( const char * filename, double pageWidth, double pageHeight, double margin, Unit unit ) const
1038 {
1039 std::ofstream out( filename );
1040 saveFIG(out,pageWidth,pageHeight,margin,unit);
1041 out.close();
1042 }
1043
1044 void
saveSVG(const char * filename,PageSize size,double margin,Unit unit) const1045 Board::saveSVG( const char * filename, PageSize size, double margin, Unit unit ) const
1046 {
1047 if ( size == BoundingBox ) {
1048 saveSVG( filename, 0.0, 0.0, margin, unit );
1049 } else {
1050 saveSVG( filename, pageSizes[size][0], pageSizes[size][1], toMillimeter(margin,unit), UMillimeter );
1051 }
1052 }
1053
1054 void
saveSVG(std::ostream & out,PageSize size,double margin,Unit unit) const1055 Board::saveSVG( std::ostream & out, PageSize size, double margin, Unit unit ) const
1056 {
1057 if ( size == BoundingBox ) {
1058 saveSVG( out, 0.0, 0.0, margin, unit );
1059 } else {
1060 saveSVG( out, pageSizes[size][0], pageSizes[size][1], toMillimeter(margin,unit), UMillimeter );
1061 }
1062 }
1063
1064 void
saveSVG(const char * filename,double pageWidth,double pageHeight,double margin,Unit unit) const1065 Board::saveSVG( const char * filename, double pageWidth, double pageHeight, double margin, Unit unit ) const
1066 {
1067 std::ofstream out( filename );
1068 saveSVG(out,pageWidth,pageHeight,margin,unit);
1069 out.close();
1070 }
1071
1072 void
saveSVG(std::ostream & out,double pageWidth,double pageHeight,double margin,Unit unit) const1073 Board::saveSVG( std::ostream & out, double pageWidth, double pageHeight, double margin, Unit unit ) const
1074 {
1075 Rect bbox = boundingBox(UseLineWidth);
1076 TransformSVG transform;
1077 bool clipping = _clippingPath.size() > 2;
1078 if ( clipping ) {
1079 bbox = bbox && _clippingPath.boundingBox();
1080 }
1081
1082 out << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"no\"?>" << std::endl;
1083 out << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"" << std::endl;
1084 out << " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" << std::endl;
1085
1086 if ( pageWidth == 0.0 && pageHeight == 0.0 ) {
1087 transform.setBoundingBox( bbox,
1088 toMillimeter(bbox.width,unit),
1089 toMillimeter(bbox.height,unit),
1090 -toMillimeter(margin,unit) );
1091 out << "<svg width=\""
1092 << toMillimeter(bbox.width+2*margin,unit) << "mm"
1093 << "\" height=\""
1094 << toMillimeter(bbox.height+2*margin,unit) << "mm"
1095 << "\" " << std::endl;
1096 out << " viewBox=\"0 0 "
1097 << toMillimeter(bbox.width+2*margin,unit) * ppmm << " "
1098 << toMillimeter(bbox.height+2*margin,unit) * ppmm << "\" " << std::endl;
1099 out << " xmlns=\"http://www.w3.org/2000/svg\""
1100 << " xmlns:xlink=\"http://www.w3.org/1999/xlink\""
1101 << " version=\"1.1\" >"
1102 << std::endl;
1103 } else {
1104 transform.setBoundingBox( bbox,
1105 toMillimeter(pageWidth,unit),
1106 toMillimeter(pageHeight,unit),
1107 toMillimeter(margin,unit) );
1108
1109 out << "<svg width=\""
1110 << toMillimeter(pageWidth,unit) << "mm\" height=\""
1111 << toMillimeter(pageHeight,unit) << "mm\" " << std::endl;
1112 out << " viewBox=\"0 0 "
1113 << toMillimeter(pageWidth,unit) * ppmm << " "
1114 << toMillimeter(pageHeight,unit) * ppmm << "\" " << std::endl;
1115 out << " xmlns=\"http://www.w3.org/2000/svg\""
1116 << " xmlns:xlink=\"http://www.w3.org/1999/xlink\""
1117 << " version=\"1.1\" >"
1118 << std::endl;
1119 }
1120
1121 out << "<desc>"
1122 "Drawing created with the Board library (v" << _BOARD_VERSION_STRING_ << ") Copyleft 2007 Sebastien Fourey"
1123 "</desc>" << std::endl;
1124
1125 if ( clipping ) {
1126 out << "<g clip-rule=\"nonzero\">\n"
1127 " <clipPath id=\"GlobalClipPath\">\n"
1128 " <path clip-rule=\"evenodd\" d=\"";
1129 _clippingPath.flushSVGCommands( out, transform );
1130 out << "\" />\n"
1131 " </clipPath>\n"
1132 "<g clip-path=\"url(#GlobalClipPath)\">\n";
1133 }
1134
1135 // Draw the background color if needed.
1136 if ( _backgroundColor != Color::Null ) {
1137 Rectangle r( bbox, Color::Null, _backgroundColor, 0.0 );
1138 r.flushSVG( out, transform );
1139 }
1140
1141 // Draw the shapes.
1142 std::vector< Shape* > shapes = _shapes;
1143 stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
1144 std::vector< Shape* >::const_iterator i = shapes.begin();
1145 std::vector< Shape* >::const_iterator end = shapes.end();
1146 while ( i != end ) {
1147 (*i)->flushSVG( out, transform );
1148 ++i;
1149 }
1150
1151 if ( clipping )
1152 out << "</g>\n</g>";
1153 out << "</svg>" << std::endl;
1154 }
1155
1156 void
saveTikZ(const char * filename,PageSize size,double margin) const1157 Board::saveTikZ( const char * filename, PageSize size, double margin ) const
1158 {
1159 saveTikZ( filename, pageSizes[size][0], pageSizes[size][1], margin );
1160 }
1161
1162 void
saveTikZ(std::ostream & out,PageSize size,double margin) const1163 Board::saveTikZ( std::ostream & out, PageSize size, double margin ) const
1164 {
1165 saveTikZ( out, pageSizes[size][0], pageSizes[size][1], margin );
1166 }
1167
1168 void
saveTikZ(std::ostream & out,double pageWidth,double pageHeight,double margin) const1169 Board::saveTikZ( std::ostream & out, double pageWidth, double pageHeight, double margin ) const
1170 {
1171 TransformTikZ transform;
1172 Rect box = boundingBox(UseLineWidth);
1173 bool clipping = _clippingPath.size() > 2;
1174 if ( clipping )
1175 box = box && _clippingPath.boundingBox();
1176 transform.setBoundingBox( box, pageWidth, pageHeight, margin );
1177
1178 out << "\\begin{tikzpicture}[anchor=south west,text depth=0,x={(1pt,0pt)},y={(0pt,-1pt)}]" << std::endl;
1179
1180 if ( clipping ) {
1181 out << "\\clip ";
1182 _clippingPath.flushTikZPoints( out, transform );
1183 out << "\n";
1184 }
1185
1186 // Draw the background color if needed.
1187 if ( _backgroundColor != Color::Null ) {
1188 Rectangle r( box, Color::Null, _backgroundColor, 0.0 );
1189 r.flushTikZ( out, transform );
1190 }
1191
1192 // Draw the shapes.
1193 std::vector< Shape* > shapes = _shapes;
1194 stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
1195 std::vector< Shape* >::const_iterator i = shapes.begin();
1196 std::vector< Shape* >::const_iterator end = shapes.end();
1197 while ( i != end ) {
1198 (*i)->flushTikZ( out, transform );
1199 ++i;
1200 }
1201 out << "\\end{tikzpicture}" << std::endl;
1202 }
1203
1204 Group
makeGrid(Point topLeft,size_t columns,size_t rows,double width,double height,Color penColor,Color fillColor,double lineWidth,const LineStyle style,const LineCap cap,const LineJoin join,int depth)1205 Board::makeGrid( Point topLeft,
1206 size_t columns, size_t rows,
1207 double width, double height,
1208 Color penColor, Color fillColor, double lineWidth,
1209 const LineStyle style,
1210 const LineCap cap,
1211 const LineJoin join,
1212 int depth )
1213 {
1214 Group group;
1215 double cellSide = width / columns;
1216 group << Rectangle(topLeft.x,topLeft.y,width,height,penColor,fillColor,lineWidth,style,cap,join,depth);
1217 Line vLine(topLeft.x+cellSide,topLeft.y,topLeft.x+cellSide,topLeft.y-height,penColor,lineWidth,style,Shape::RoundCap,join,depth);
1218 while ( --columns ) {
1219 group << vLine;
1220 vLine.translate(cellSide,0);
1221 }
1222 cellSide = height / rows;
1223 Line hLine(topLeft.x,topLeft.y-cellSide,topLeft.x+width,topLeft.y-cellSide,penColor,lineWidth,style,Shape::RoundCap,join,depth);
1224 while ( --rows ) {
1225 group << hLine;
1226 hLine.translate(0,-cellSide);
1227 }
1228
1229 return group;
1230 }
1231
penColor() const1232 Color Board::penColor() const
1233 {
1234 return _state.penColor;
1235 }
1236
fillColor() const1237 Color Board::fillColor() const
1238 {
1239 return _state.fillColor;
1240 }
1241
1242 double
toMillimeter(double x,Board::Unit unit)1243 Board::toMillimeter(double x, Board::Unit unit)
1244 {
1245 // enum Unit { UPoint, UInche, UCentimeter, UMillimeter };
1246 switch (unit) {
1247 case UPoint:
1248 return x * 25.4 / 72.0;
1249 break;
1250 case UInche:
1251 return x * 25.4;
1252 break;
1253 case UCentimeter:
1254 return x * 10.0;
1255 break;
1256 case UMillimeter:
1257 return x;
1258 break;
1259 default:
1260 Tools::error << "toMillimeter(): bad unit (" << unit << ")\n";
1261 return 0;
1262 break;
1263 }
1264 }
1265
1266 void
saveTikZ(const char * filename,double pageWidth,double pageHeight,double margin) const1267 Board::saveTikZ( const char * filename, double pageWidth, double pageHeight, double margin ) const
1268 {
1269 std::ofstream out( filename );
1270 saveTikZ(out,pageWidth,pageHeight,margin);
1271 out.close();
1272 }
1273
1274 void
save(const char * filename,double pageWidth,double pageHeight,double margin,Unit unit) const1275 Board::save(const char * filename, double pageWidth, double pageHeight, double margin , Unit unit) const
1276 {
1277 if ( Tools::stringEndsWith(filename,".eps", Tools::CaseInsensitive) ) {
1278 saveEPS( filename, pageWidth, pageHeight, margin, unit );
1279 return;
1280 }
1281 if ( Tools::stringEndsWith(filename,".fig", Tools::CaseInsensitive) ) {
1282 saveFIG( filename, pageWidth, pageHeight, margin, unit );
1283 return;
1284 }
1285 if ( Tools::stringEndsWith(filename,".svg", Tools::CaseInsensitive) ) {
1286 saveSVG( filename, pageWidth, pageHeight, margin, unit );
1287 return;
1288 }
1289 if ( Tools::stringEndsWith(filename,".tikz", Tools::CaseInsensitive) ) {
1290 saveTikZ( filename, pageWidth, pageHeight, margin );
1291 return;
1292 }
1293 }
1294
1295 void
save(const char * filename,PageSize size,double margin,Unit unit) const1296 Board::save(const char * filename, PageSize size, double margin , Unit unit) const
1297 {
1298 if ( size == BoundingBox ) {
1299 save( filename, 0.0, 0.0, margin, unit );
1300 } else {
1301 save( filename, pageSizes[size][0], pageSizes[size][1], toMillimeter(margin,unit), UMillimeter );
1302 }
1303 }
1304
1305 } // namespace LibBoard;
1306
1307 /**
1308 * @example examples/arithmetic.cpp
1309 * @example examples/arrows.cpp
1310 * @example examples/clipping.cpp
1311 * @example examples/ellipse.cpp
1312 * @example examples/example1.cpp
1313 * @example examples/example2.cpp
1314 * @example examples/example3.cpp
1315 * @example examples/example4.cpp
1316 * @example examples/flag.cpp
1317 * @example examples/graph.cpp
1318 * @example examples/koch.cpp
1319 * @example examples/line_style.cpp
1320 * @example examples/line_segment.cpp
1321 * @example examples/logo.cpp
1322 * @example examples/ruler.cpp
1323 * @example examples/scale_ellipse.cpp
1324 * @example examples/stroke_path.cpp
1325 * @example examples/tilings.cpp
1326 * @example examples/Makefile
1327 */
1328
1329 /**
1330 * @mainpage LibBoard - A C++ library for simple Postscript, SVG, and XFig drawings
1331 *
1332 * <table border="0"><tr><td><img align=left src="http://foureys.users.greyc.fr/board/doc/LibBoardLogoII_Small.png"/></td>
1333 * <td>(Copyleft) 2007 Sébastien Fourey - GREYC ENSICAEN</td></tr></table>
1334 *
1335 * @section intro_sec Introduction
1336 *
1337 * The board library allows simple drawings in:
1338 * <ul>
1339 * <li>Encapsulated Postcript files (EPS) ;
1340 * <li>XFig files (FIG) ;
1341 * <li>Scalable Vector Graphics files (SVG).
1342 * </ul>
1343 *
1344 * The main class of the library is the #LibBoard#Board class. It is intented to
1345 * be as simple as possible so that it can be used quickly in programs to
1346 * generate the kind of figure one would rather not draw by hand, but which can
1347 * be easily drawn by a computer (C++) program.
1348 *
1349 * @section examples_sec Code examples
1350 *
1351 * <ul>
1352 * <li>See the "Examples" tab above or visit
1353 * <a href="https://github.com/c-koi/libboard/blob/v0.9.4/EXAMPLES.md">dedicated page on GitHub</a>.
1354 * </ul>
1355 *
1356 * @section links_sec Links
1357 *
1358 * <ul>
1359 * <li>Visit the <a href="https://github.com/c-koi/libboard">official source code repository</a>.</li>
1360 * </ul>
1361 */
1362