DGtal 1.4.0
Loading...
Searching...
No Matches
ShapeList.cpp
1/* -*- mode: c++ -*- */
9/*
10 * \@copyright This File is part of the Board library which is
11 * licensed under the terms of the GNU Lesser General Public Licence.
12 * See the LICENCE file for further details.
13 */
14#include "Board/ShapeList.h"
15#include "Board/Tools.h"
16#include <algorithm>
17#include <typeinfo>
18
19#if defined( max )
20#undef max
21#endif
22
23namespace LibBoard {
24
25//
26// Definition of the ShapeList methods.
27//
28
29const std::string ShapeList::_name("ListOfShapes");
30
31const std::string &
33{
34 return _name;
35}
36
41
44{
45 free();
46 _shapes.clear();
47 _nextDepth = std::numeric_limits<int>::max() - 1;
48 return *this;
49}
50
51void
53{
54 std::vector<Shape*>::const_iterator i = _shapes.begin();
55 std::vector<Shape*>::const_iterator end = _shapes.end();
56 while ( i != end ) {
57 delete *i;
58 ++i;
59 }
60}
61
62ShapeList::ShapeList( const ShapeList & other ) : Shape( other )
63{
64 if ( ! other._shapes.size() ) return;
65 _shapes.resize( other._shapes.size(), 0 );
66 std::vector<Shape*>::iterator t = _shapes.begin();
67 std::vector<Shape*>::const_iterator i = other._shapes.begin();
68 std::vector<Shape*>::const_iterator end = other._shapes.end();
69 while ( i != end ) {
70 *t = (*i)->clone();
71 ++i;
72 ++t;
73 }
74}
75
78{
79 free();
80 if ( ! other._shapes.size() ) return *this;
81 _shapes.resize( other._shapes.size(), 0 );
82 std::vector<Shape*>::iterator t = _shapes.begin();
83 std::vector<Shape*>::const_iterator i = other._shapes.begin();
84 std::vector<Shape*>::const_iterator end = other._shapes.end();
85 while ( i != end ) {
86 *t = (*i)->clone();
87 ++i;
88 ++t;
89 }
90 return *this;
91}
92
94ShapeList::operator<<( const Shape & shape )
95{
96 if ( typeid( shape ) == typeid( ShapeList ) ) {
97 // Insertion on top, respecting the same depth order.
98 const ShapeList & sl = dynamic_cast<const ShapeList &>( shape );
99 std::vector<Shape*> shapes = sl._shapes;
100 stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
101 std::vector<Shape*>::iterator i = shapes.begin();
102 std::vector<Shape*>::iterator end = shapes.end();
103 while ( i != end ) {
104 Shape * s = (*i)->clone();
105 s->depth( _nextDepth-- );
106 _shapes.push_back( s );
107 ++i;
108 }
109 } else {
110 Shape * s = shape.clone();
111 if ( s->depth() == -1 )
112 s->depth( _nextDepth-- );
113 _shapes.push_back( s );
114 if ( typeid( shape ) == typeid( Group ) ) {
115 _nextDepth = dynamic_cast<const Group&>(shape).minDepth() - 1;
116 }
117 }
118 return *this;
119}
120
121void
122ShapeList::addShape( const Shape & shape, double scaleFactor )
123{
124 if ( typeid( shape ) == typeid( ShapeList ) ) {
125 // Insertion on top, respecting the same depth order.
126 const ShapeList & sl = dynamic_cast<const ShapeList &>( shape );
127 std::vector<Shape*> shapes = sl._shapes;
128 stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
129 std::vector<Shape*>::iterator i = shapes.begin();
130 std::vector<Shape*>::iterator end = shapes.end();
131 while ( i != end ) {
132 Shape * s = (*i)->clone();
133 s->depth( _nextDepth-- );
134 if ( scaleFactor != 1.0 )
135 s->scaleAll( scaleFactor );
136 _shapes.push_back( s );
137 ++i;
138 }
139 } else {
140 Shape * s = shape.clone();
141 if ( s->depth() == -1 )
142 s->depth( _nextDepth-- );
143 if ( scaleFactor != 1.0 )
144 s->scaleAll( scaleFactor );
145 _shapes.push_back( s );
146 if ( typeid( shape ) == typeid( Group ) ) {
147 _nextDepth = dynamic_cast<const Group&>(shape).minDepth() - 1;
148 }
149 }
150}
151
152ShapeList &
153ShapeList::dup( unsigned int count )
154{
155 if ( ! _shapes.size() ) {
156 warning << "dup() called with an empty list of shapes.\n";
157 return *this;
158 }
159 while ( count-- ) {
160 (*this) << (*_shapes.back());
161 }
162 return *this;
163}
164
165ShapeList &
167{
168 if ( typeid( shape ) == typeid( ShapeList ) ) {
169 const ShapeList & sl = dynamic_cast<const ShapeList &>( shape );
170 std::vector<Shape*>::const_iterator i = sl._shapes.begin();
171 std::vector<Shape*>::const_iterator end = sl._shapes.end();
172 while ( i != end ) {
173 Shape * s = (*i)->clone();
174 _shapes.push_back( s );
175 ++i;
176 }
177 } else {
178 _shapes.push_back( shape.clone() );
179 }
180 return *this;
181}
182
183ShapeList &
184ShapeList::insert( const Shape & , int /* depth */ )
185{
186 warning << "ShapeList::insert() not implemented yet.\n";
187 return *this;
188}
189
190
191Point
193 std::vector<Shape*>::const_iterator i = _shapes.begin();
194 std::vector<Shape*>::const_iterator end = _shapes.end();
195 double f = 1.0 / _shapes.size();
196 Point r(0,0);
197 while ( i != end ) {
198 r += f * (*i)->center();
199 ++i;
200 }
201 return r;
202}
203
204Shape &
205ShapeList::rotate( double angle, const Point & rotCenter )
206{
207 std::vector<Shape*>::iterator i = _shapes.begin();
208 std::vector<Shape*>::iterator end = _shapes.end();
209 while ( i != end ) {
210 (*i)->rotate( angle, rotCenter );
211 ++i;
212 }
213 return *this;
214}
215
217ShapeList::rotated( double angle, const Point & rotCenter )
218{
219 ShapeList r( *this );
220 return static_cast<ShapeList&>( r.rotate( angle, rotCenter ) );
221}
222
223Shape &
224ShapeList::rotate( double angle )
225{
226 return ShapeList::rotate( angle, center() );
227}
228
230ShapeList::rotated( double angle )
231{
232 return static_cast<ShapeList&>( ShapeList( *this ).rotate( angle, center() ) );
233}
234
235Shape &
236ShapeList::translate( double dx, double dy )
237{
238 std::vector<Shape*>::iterator i = _shapes.begin();
239 std::vector<Shape*>::iterator end = _shapes.end();
240 while ( i != end ) {
241 (*i)->translate( dx, dy );
242 ++i;
243 }
244 return *this;
245}
246
248ShapeList::translated( double dx, double dy )
249{
250 return static_cast<ShapeList&>( ShapeList( *this ).translate( dx, dy ) );
251}
252
253Shape &
254ShapeList::scale( double sx, double sy )
255{
256 Point c = center();
257 Point delta;
258 std::vector<Shape*>::iterator i = _shapes.begin();
259 std::vector<Shape*>::iterator end = _shapes.end();
260 while ( i != end ) {
261 delta = (*i)->center() - c;
262 delta.x *= sx;
263 delta.y *= sy;
264 (*i)->scale( sx, sy );
265 delta = ( c + delta ) - (*i)->center();
266 (*i++)->translate( delta.x, delta.y );
267 }
268 return *this;
269}
270
271Shape &
273{
274 return ShapeList::scale( s, s );
275}
276
278ShapeList::scaled( double sx, double sy )
279{
280 return static_cast<ShapeList&>( ShapeList( *this ).scale( sx, sy ) );
281}
282
285{
286 return static_cast<ShapeList&>( ShapeList( *this ).scale( s, s ) );
287}
288
289void
291{
292 std::vector<Shape*>::iterator i = _shapes.begin();
293 std::vector<Shape*>::iterator end = _shapes.end();
294 while ( i != end ) {
295 (*i++)->scaleAll( s );
296 }
297}
298
299void
300ShapeList::flushPostscript( std::ostream & stream,
301 const TransformEPS & transform ) const
302{
303 std::vector< Shape* > shapes = _shapes;
304 stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
305 std::vector< Shape* >::const_iterator i = shapes.begin();
306 std::vector< Shape* >::const_iterator end = shapes.end();
307 stream << "%%% Begin ShapeList\n";
308 while ( i != end ) {
309 (*i++)->flushPostscript( stream, transform );
310 }
311 stream << "%%% End ShapeList\n";
312}
313
314void
315ShapeList::flushFIG( std::ostream & stream,
316 const TransformFIG & transform,
317 std::map<DGtal::Color,int> & colormap ) const
318{
319 std::vector< Shape* > shapes = _shapes;
320 stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
321 std::vector< Shape* >::const_iterator i = shapes.begin();
322 std::vector< Shape* >::const_iterator end = shapes.end();
323 while ( i != end ) {
324 (*i)->flushFIG( stream, transform, colormap );
325 ++i;
326 }
327}
328
329void
330ShapeList::flushSVG( std::ostream & stream,
331 const TransformSVG & transform ) const
332{
333 std::vector< Shape* > shapes = _shapes;
334 stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
335 std::vector< Shape* >::const_iterator i = shapes.begin();
336 std::vector< Shape* >::const_iterator end = shapes.end();
337 //stream << "<g>\n";
338 while ( i != end ) {
339 (*i)->flushSVG( stream, transform );
340 ++i;
341 }
342 //stream << "</g>\n";
343}
344
345#ifdef WITH_CAIRO
346void
348 const TransformCairo & transform ) const
349{
350 std::vector< Shape* > shapes = _shapes;
351 stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
352 std::vector< Shape* >::const_iterator i = shapes.begin();
353 std::vector< Shape* >::const_iterator end = shapes.end();
354
355 while ( i != end ) {
356 (*i)->flushCairo( cr, transform );
357 ++i;
358 }
359}
360#endif
361
362void
363ShapeList::flushTikZ( std::ostream & stream,
364 const TransformTikZ & transform ) const
365{
366 std::vector< Shape* > shapes = _shapes;
367 stable_sort( shapes.begin(), shapes.end(), shapeGreaterDepth );
368 std::vector< Shape* >::const_iterator i = shapes.begin();
369 std::vector< Shape* >::const_iterator end = shapes.end();
370 stream << "\\begin{scope}\n";
371 while ( i != end ) {
372 (*i)->flushTikZ( stream, transform );
373 ++i;
374 }
375 stream << "\\end{scope}\n";
376}
377
378Rect
380{
381 Rect r;
382 std::vector< Shape* >::const_iterator i = _shapes.begin();
383 std::vector< Shape* >::const_iterator end = _shapes.end();
384 if ( i == end ) return r;
385 r = (*i)->boundingBox();
386 ++i;
387 while ( i != end ) {
388 r = r || (*i)->boundingBox();
389 ++i;
390 }
391 return r;
392}
393
394int
396{
397 int res = std::numeric_limits<int>::max();
398 int d;
399 ShapeList * sl;
400 std::vector< Shape* >::const_iterator i = _shapes.begin();
401 std::vector< Shape* >::const_iterator end = _shapes.end();
402 while ( i != end ) {
403 sl = dynamic_cast<ShapeList*>( *i );
404 if ( sl ) {
405 d = sl->minDepth();
406 } else {
407 d = (*i)->depth();
408 }
409 if ( d < res ) res = d;
410 ++i;
411 }
412 return res;
413}
414
415#if defined( min )
416#undef min
417#define _HAS_MSVC_MIN_ true
418#endif
419
420int
422{
423 int res = std::numeric_limits<int>::min();
424 int d;
425 ShapeList * sl;
426 std::vector< Shape* >::const_iterator i = _shapes.begin();
427 std::vector< Shape* >::const_iterator end = _shapes.end();
428 while ( i != end ) {
429 sl = dynamic_cast<ShapeList*>( *i );
430 if ( sl ) {
431 d = sl->maxDepth();
432 } else {
433 d = (*i)->depth();
434 }
435 if ( d > res ) res = d;
436 ++i;
437 }
438 return res;
439}
440
441#if defined( _HAS_MSVC_MIN_ )
442#define min(A,B) ((A)<(B)?(A):(B))
443#endif
444
445void
447{
448 std::vector< Shape* >::const_iterator i = _shapes.begin();
449 std::vector< Shape* >::const_iterator end = _shapes.end();
450 while ( i != end ) {
451 (*i++)->shiftDepth( shift );
452 }
453}
454
455Shape *
457{
458 return new ShapeList( *this );
459}
460
461Shape &
462ShapeList::last( const unsigned int position )
463{
464 return last<Shape>( position );
465}
466
467Shape &
469{
470 return last<Shape>( 0 );
471}
472
473
474//
475// Definition of the Group methods.
476//
477
478const std::string Group::_name("GroupOfShapes");
479
480const std::string &
482{
483 return _name;
484}
485
486Shape &
487Group::rotate( double angle, const Point & rotCenter )
488{
489 ShapeList::rotate( angle, rotCenter );
490 _clippingPath.rotate( angle, rotCenter );
491 return (*this);
492}
493
494Shape &
495Group::rotate( double angle )
496{
497 ShapeList::rotate( angle );
498 _clippingPath.rotate( angle, center() );
499 return (*this);
500}
501
502Shape &
503Group::translate( double dx, double dy )
504{
505 ShapeList::translate( dx, dy );
506 _clippingPath.translate( dx, dy );
507 return (*this);
508}
509
510Shape &
511Group::scale( double sx, double sy )
512{
513 Point delta = _clippingPath.center() - center();
514 delta.x *= sx;
515 delta.y *= sy;
516 _clippingPath.scale( sx, sy );
517 ShapeList::scale( sx, sy );
518 delta = ( center() + delta ) - _clippingPath.center();
519 _clippingPath.translate( delta.x, delta.y );
520 return (*this);
521}
522
523Shape &
524Group::scale( double s )
525{
526 Point delta = _clippingPath.center() - center();
527 delta *= s;
528 _clippingPath.scale( s );
529 ShapeList::scale( s );
530 delta = ( center() + delta ) - _clippingPath.center();
531 _clippingPath.translate( delta.x, delta.y );
532 return (*this);
533}
534
535Group
536Group::rotated( double angle, const Point & rotCenter )
537{
538 return static_cast<const Group &>( Group( *this ).rotate( angle, rotCenter ) );
539}
540
541Group
542Group::rotated( double angle )
543{
544 return static_cast<const Group &>( Group( *this ).rotate( angle ) );
545}
546
547Group
548Group::translated( double dx, double dy )
549{
550 return static_cast<const Group &>( Group( *this ).translate( dx, dy ) );
551}
552
553Group
554Group::scaled( double sx, double sy )
555{
556 return static_cast<const Group &>( Group( *this ).scale( sx, sy ) );
557}
558
559Group
560Group::scaled( double s )
561{
562 return static_cast<const Group &>( Group( *this ).scale( s ) );
563}
564
565
566void
567Group::setClippingRectangle( float x, float y, float width, float height )
568{
570 _clippingPath << Point( x, y );
571 _clippingPath << Point( x + width, y );
572 _clippingPath << Point( x + width, y - height);
573 _clippingPath << Point( x , y - height );
574}
575
576void
577Group::setClippingPath( const std::vector<Point> & points )
578{
580 std::vector<Point>::const_iterator it = points.begin();
581 std::vector<Point>::const_iterator end = points.end();
582 while ( it != end ) {
583 _clippingPath << *it;
584 ++it;
585 }
586}
587
588void
590{
591 _clippingPath = path;
592 _clippingPath.setClosed( true );
593 if ( _clippingPath.size() > 1 ) {
594 if ( _clippingPath[0] == _clippingPath[ _clippingPath.size() - 1 ] )
596 }
597}
598
599void
600Group::flushPostscript( std::ostream & stream,
601 const TransformEPS & transform ) const
602{
603 if ( _clippingPath.size() > 2 ) {
604 stream << "%%% Begin Clipped Group " << _clippingCount << "\n";
605 stream << " gsave n ";
606 _clippingPath.flushPostscript( stream, transform );
607 stream << " 0 slw clip " << std::endl;
608 ShapeList::flushPostscript( stream, transform );
609 stream << " grestore\n";
610 stream << "%%% End Clipped Group " << _clippingCount << "\n";
612 } else {
613 stream << "%%% Begin Group\n";
614 ShapeList::flushPostscript( stream, transform );
615 stream << "%%% End Group\n";
616 }
617}
618
619void
620Group::flushFIG( std::ostream & stream,
621 const TransformFIG & transform,
622 std::map<DGtal::Color,int> & colormap ) const
623{
624 Rect box = boundingBox();
625 stream << "# Begin group\n";
626 stream << "6 "
627 << transform.mapX( box.left ) << " "
628 << transform.mapY( box.top ) << " "
629 << transform.mapX( box.left + box.width ) << " "
630 << transform.mapY( box.top - box.height ) << "\n";
631 ShapeList::flushFIG( stream, transform, colormap );
632 stream << "-6\n";
633 stream << "# End Group\n";
634}
635
636void
637Group::flushSVG( std::ostream & stream,
638 const TransformSVG & transform ) const
639{
640 if ( _clippingPath.size() > 2 ) {
641 stream << "<g clip-rule=\"nonzero\">\n"
642 << " <clipPath id=\"LocalClipPath" << _clippingCount << "\">\n"
643 << " <path clip-rule=\"evenodd\" d=\"";
644 _clippingPath.flushSVGCommands( stream, transform );
645 stream << "\" />\n";
646 stream << " </clipPath>\n";
647 stream << "<g clip-path=\"url(#LocalClipPath" << _clippingCount <<")\">\n";
649 ShapeList::flushSVG( stream, transform );
650 stream << "</g>\n";
651 stream << "</g>\n";
652 } else {
653 stream << "<g>\n";
654 ShapeList::flushSVG( stream, transform );
655 stream << "</g>\n";
656 }
657}
658
659#ifdef WITH_CAIRO
660void
661Group::flushCairo( cairo_t * /*cr*/,
662 const TransformCairo & /*transform*/ ) const
663{
664 //todo
665 //ShapeList::flushCairo( cr, transform );
666}
667#endif
668
669void
670Group::flushTikZ( std::ostream & stream,
671 const TransformTikZ & transform ) const
672{
673 // FIXME: implement clipping
674 stream << "\\begin{scope}\n";
675 ShapeList::flushTikZ( stream, transform );
676 stream << "\\end{scope}\n";
677}
678
679Rect
681{
682 if ( _clippingPath.size() > 2 )
684 else
685 return ShapeList::boundingBox();
686}
687
688
689Shape *
691{
692 return new Group( *this );
693}
694
695Group &
696Group::operator=( const Group & other )
697{
698 ShapeList::operator=( other );
699 return *this;
700}
701
702unsigned int Group::_clippingCount = 0;
703
704} // namespace LibBoard
bool shapeGreaterDepth(const Shape *s1, const Shape *s2)
Definition Shapes.cpp:95
MessageStream warning
A group of shapes. A group is basically a ShapeList except that when rendered in either an SVG of a F...
Definition ShapeList.h:183
static unsigned int _clippingCount
Definition ShapeList.h:273
void flushSVG(std::ostream &stream, const TransformSVG &transform) const
Shape & rotate(double angle, const Point &center)
Group rotated(double angle, const Point &center)
static const std::string _name
Definition ShapeList.h:271
const std::string & name() const
void flushFIG(std::ostream &stream, const TransformFIG &transform, std::map< DGtal::Color, int > &colormap) const
Shape * clone() const
void flushCairo(cairo_t *cr, const TransformCairo &transform) const
Rect boundingBox() const
Group(int depthValue=-1)
Definition ShapeList.h:185
Group scaled(double sx, double sy)
void flushPostscript(std::ostream &stream, const TransformEPS &transform) const
Group & operator=(const Group &other)
Group translated(double dx, double dy)
Shape & translate(double dx, double dy)
Shape & scale(double sx, double sy)
void setClippingPath(const std::vector< Point > &points)
void setClippingRectangle(float x, float y, float width, float height)
void flushTikZ(std::ostream &stream, const TransformTikZ &transform) const
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
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)
ShapeList scaled(double sx, double sy)
void flushCairo(cairo_t *cr, const TransformCairo &transform) const
const std::string & name() const
Definition ShapeList.cpp:32
void flushPostscript(std::ostream &stream, const TransformEPS &transform) const
void flushFIG(std::ostream &stream, const TransformFIG &transform, std::map< DGtal::Color, int > &colormap) const
Shape & rotate(double angle, const Point &center)
void flushSVG(std::ostream &stream, const TransformSVG &transform) const
virtual int minDepth() const
std::vector< Shape * > _shapes
Definition ShapeList.h:169
ShapeList(int depth=-1)
void flushTikZ(std::ostream &stream, const TransformTikZ &transform) const
Shape & translate(double dx, double dy)
void shiftDepth(int shift)
ShapeList & insert(const Shape &shape, int depth)
ShapeList & dup(unsigned int copies=1)
Shape & scale(double sx, double sy)
T & last(const unsigned int position=0)
ShapeList translated(double dx, double dy)
static const std::string _name
Definition ShapeList.h:163
Point center() const
ShapeList rotated(double angle, const Point &center)
Rect boundingBox() const
virtual int maxDepth() const
ShapeList & operator<<(const Shape &shape)
Definition ShapeList.cpp:94
ShapeList & operator+=(const Shape &shape)
ShapeList & operator=(const ShapeList &other)
Definition ShapeList.cpp:77
Shape * clone() const
void scaleAll(double s)
ShapeList & clear()
Definition ShapeList.cpp:43
Abstract structure for a 2D shape.
int depth() const
virtual Shape & translate(double dx, double dy)=0
virtual Shape * clone() const =0
virtual Shape & rotate(double angle, const Point &center)=0
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
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