Merge branch 'ht/mem-debug' into ht/graphs
[shapes.git] / source / drawabletypes.cc
blob25dfc5c0e38304f98bf883036c967b55d2718037
1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * any later version.
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008, 2009, 2010, 2014 Henrik Tidefelt
19 #include <cmath>
21 #include "shapestypes.h"
22 #include "shapesexceptions.h"
23 #include "astexpr.h"
24 #include "consts.h"
25 #include "angleselect.h"
26 #include "astvar.h"
27 #include "astclass.h"
28 #include "statetypes.h"
29 #include "lighttypes.h"
30 #include "shadingtypes.h"
31 #include "globals.h"
32 #include "trianglefunctions.h"
33 #include "pagecontentstates.h"
34 #include "continuations.h"
35 #include "warn.h"
37 #include <ctype.h>
38 #include <list>
39 #include <algorithm>
41 using namespace Shapes;
44 Lang::Drawable2D::Drawable2D( )
45 { }
47 Lang::Drawable2D::~Drawable2D( )
48 { }
50 RefCountPtr< const Lang::Transformed2D >
51 Lang::Drawable2D::typed_transformed( const Lang::Transform2D & tf, const RefCountPtr< const Lang::Drawable2D > & self ) const
53 return RefCountPtr< const Lang::Transformed2D >( new Lang::Transformed2D( self, tf ) );
56 RefCountPtr< const Lang::Geometric2D >
57 Lang::Drawable2D::transformed( const Lang::Transform2D & tf, const RefCountPtr< const Lang::Geometric2D > & self ) const
59 return typed_transformed( tf, self.down_cast< const Lang::Drawable2D >( ) );
62 RefCountPtr< const Lang::Geometric3D >
63 Lang::Drawable2D::to3D( const RefCountPtr< const Lang::Geometric2D > & self ) const
65 typedef const Lang::Drawable2D SelfType;
66 RefCountPtr< SelfType > typedSelf = self.down_cast< SelfType >( );
67 if( typedSelf == NullPtr< SelfType >( ) )
69 throw Exceptions::InternalError( "The self-value passed to Drawable2D::to3D was of bad type." );
71 return RefCountPtr< const Lang::Geometric3D >( new Lang::Drawable2Din3D( typedSelf ) );
74 void
75 Lang::Drawable2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
77 // Not overloading this methods means that there are no tagged objects within this.
80 bool
81 Lang::Drawable2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
83 // Not overloading this methods means that there are no tagged objects within this.
84 return false;
87 void
88 Lang::Drawable2D::gcMark( Kernel::GCMarkedSet & marked )
89 { }
91 RefCountPtr< const Lang::Class > Lang::Drawable2D::TypeID = NullPtr< const Lang::Class >( ); /* The value is set in main */
92 TYPEINFOIMPL( Drawable2D );
93 DISPATCHIMPL( Drawable2D );
96 Lang::Group2D::Group2D( )
97 { }
99 Lang::Group2D::~Group2D( )
102 RefCountPtr< const Lang::Class > Lang::Group2D::TypeID( new Lang::SystemFinalClass( strrefdup( "Group2D" ) ) );
103 TYPEINFOIMPL( Group2D );
106 RefCountPtr< const Lang::Group2D >
107 Helpers::newGroup2D( const RefCountPtr< const Kernel::GraphicsState > & metaState, const RefCountPtr< const Lang::Drawable2D > & obj2, const RefCountPtr< const Lang::Drawable2D > & obj1 )
109 RefCountPtr< const Lang::Group2D > res = Lang::THE_NULL2D;
110 res = RefCountPtr< const Lang::GroupPair2D >( new Lang::GroupPair2D( obj1,
111 res,
112 metaState ) );
113 res = RefCountPtr< const Lang::GroupPair2D >( new Lang::GroupPair2D( obj2,
114 res,
115 metaState ) );
116 return res;
119 RefCountPtr< const Lang::Group2D >
120 Helpers::newGroup2D( const RefCountPtr< const Kernel::GraphicsState > & metaState, const RefCountPtr< const Lang::Drawable2D > & obj3, const RefCountPtr< const Lang::Drawable2D > & obj2, const RefCountPtr< const Lang::Drawable2D > & obj1 )
122 RefCountPtr< const Lang::Group2D > res = Lang::THE_NULL2D;
123 res = RefCountPtr< const Lang::GroupPair2D >( new Lang::GroupPair2D( obj1,
124 res,
125 metaState ) );
126 res = RefCountPtr< const Lang::GroupPair2D >( new Lang::GroupPair2D( obj2,
127 res,
128 metaState ) );
129 res = RefCountPtr< const Lang::GroupPair2D >( new Lang::GroupPair2D( obj3,
130 res,
131 metaState ) );
132 return res;
136 Lang::GroupPair2D::GroupPair2D( RefCountPtr< const Lang::Drawable2D > car, RefCountPtr< const Lang::Group2D > cdr, const RefCountPtr< const Kernel::GraphicsState > & metaState )
137 : metaState_( metaState ), car_( car ), cdr_( cdr )
140 Lang::GroupPair2D::~GroupPair2D( )
143 bool
144 Lang::GroupPair2D::isNull( ) const
146 return false;
149 void
150 Lang::GroupPair2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
152 cdr_->shipout( os, pdfState, tf );
153 if( pdfState->graphics_.synchBlend( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) ) )
155 os << std::endl ;
157 car_->shipout( os, pdfState, tf );
160 RefCountPtr< const Lang::ElementaryPath2D >
161 Lang::GroupPair2D::bbox( Lang::Drawable2D::BoxType boxType ) const
163 RefCountPtr< const Lang::ElementaryPath2D > carbbox = car_->bbox( boxType );
164 RefCountPtr< const Lang::ElementaryPath2D > cdrbbox = cdr_->bbox( boxType );
166 if( cdrbbox->empty( ) )
168 return carbbox;
171 Concrete::Length xmin = Concrete::HUGE_LENGTH;
172 Concrete::Length xmax = -Concrete::HUGE_LENGTH;
173 Concrete::Length ymin = Concrete::HUGE_LENGTH;
174 Concrete::Length ymax = -Concrete::HUGE_LENGTH;
176 typedef typeof *carbbox PathType;
177 for( PathType::const_iterator i = carbbox->begin( ); i != carbbox->end( ); ++i )
179 Concrete::Length x = (*i)->mid_->x_;
180 xmin = std::min( xmin, x );
181 xmax = std::max( xmax, x );
183 Concrete::Length y = (*i)->mid_->y_;
184 ymin = std::min( ymin, y );
185 ymax = std::max( ymax, y );
188 for( PathType::const_iterator i = cdrbbox->begin( ); i != cdrbbox->end( ); ++i )
190 Concrete::Length x = (*i)->mid_->x_;
191 xmin = std::min( xmin, x );
192 xmax = std::max( xmax, x );
194 Concrete::Length y = (*i)->mid_->y_;
195 ymin = std::min( ymin, y );
196 ymax = std::max( ymax, y );
199 Lang::ElementaryPath2D * res = new Lang::ElementaryPath2D;
201 if( xmin < Concrete::HUGE_LENGTH )
203 res->push_back( new Concrete::PathPoint2D( xmin, ymin ) );
204 res->push_back( new Concrete::PathPoint2D( xmin, ymax ) );
205 res->push_back( new Concrete::PathPoint2D( xmax, ymax ) );
206 res->push_back( new Concrete::PathPoint2D( xmax, ymin ) );
207 res->close( );
210 return RefCountPtr< const Lang::ElementaryPath2D >( res );
214 void
215 Lang::GroupPair2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
217 /* Note the order! Objects are added on the car side of a group being built, so the car side is the "latter".
219 cdr_->findTags( dst, dyn, key, tf );
220 car_->findTags( dst, dyn, key, tf );
223 bool
224 Lang::GroupPair2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
226 return
227 cdr_->findOneTag( evalState, key, tf ) ||
228 car_->findOneTag( evalState, key, tf );
231 RefCountPtr< const Lang::Group2D >
232 Lang::GroupPair2D::removeShallow( Lang::Symbol::KeyType key ) const
235 typedef const Lang::Tagged2D TaggedType;
236 TaggedType * t = dynamic_cast< TaggedType * >( car_.getPtr( ) );
237 if( t != 0 && t->key( ) == key )
239 return cdr_->removeShallow( key );
242 return RefCountPtr< const Lang::Group2D >( new Lang::GroupPair2D( car_, cdr_->removeShallow( key ), metaState_ ) );
245 void
246 Lang::GroupPair2D::gcMark( Kernel::GCMarkedSet & marked )
248 const_cast< Lang::Drawable2D * >( car_.getPtr( ) )->gcMark( marked );
249 const_cast< Lang::Group2D * >( cdr_.getPtr( ) )->gcMark( marked );
253 Lang::GroupNull2D::GroupNull2D( )
256 Lang::GroupNull2D::~GroupNull2D( )
259 bool
260 Lang::GroupNull2D::isNull( ) const
262 return true;
265 RefCountPtr< const Lang::Group2D >
266 Lang::GroupNull2D::removeShallow( Lang::Symbol::KeyType key ) const
268 return Lang::THE_NULL2D;
271 void
272 Lang::GroupNull2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
275 RefCountPtr< const Lang::ElementaryPath2D >
276 Lang::GroupNull2D::bbox( Lang::Drawable2D::BoxType boxType ) const
278 return Lang::THE_EMPTYPATH2D;
282 Lang::XObject::XObject( const RefCountPtr< SimplePDF::PDF_Object > & resource, const RefCountPtr< const Lang::ElementaryPath2D > & boundingbox )
283 : metaState_( Kernel::THE_NO_STATE ), resource_( resource ), boundingbox_( boundingbox ), bleedbox_( boundingbox )
286 Lang::XObject::XObject( const RefCountPtr< SimplePDF::PDF_Object > & resource, const RefCountPtr< const Lang::ElementaryPath2D > & boundingbox, const RefCountPtr< const Lang::ElementaryPath2D > & bleedbox, const RefCountPtr< const Kernel::GraphicsState > & metaState )
287 : metaState_( metaState ), resource_( resource ), boundingbox_( boundingbox ), bleedbox_( bleedbox )
290 Lang::XObject::~XObject( )
293 void
294 Lang::XObject::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
296 Kernel::Auto_qQ auto_qQ( & pdfState->graphics_, & pdfState->text_, os, false );
297 if( ! tf.isIdentity( ) )
299 auto_qQ.activate( );
300 tf.shipout( os );
301 os << " cm" << std::endl ;
303 if( metaState_ != Kernel::THE_NO_STATE )
305 pdfState->graphics_.synchForNonStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
307 os << pdfState->resources_->nameofXObject( resource_ ) << " Do" << std::endl ;
310 RefCountPtr< SimplePDF::PDF_Object >
311 Lang::XObject::getResource( ) const
313 return resource_;
316 RefCountPtr< const Lang::ElementaryPath2D >
317 Lang::XObject::bbox( Lang::Drawable2D::BoxType boxType ) const
319 switch( boxType )
321 case Lang::Drawable2D::BOUNDING:
322 return boundingbox_;
323 case Lang::Drawable2D::BLEED:
324 return bleedbox_;
326 throw Exceptions::InternalError( "Lang::XObject::bbox: boxType out of range." );
329 RefCountPtr< const Lang::XObject >
330 Lang::XObject::cloneWithState( const RefCountPtr< const Kernel::GraphicsState > & metaState, Concrete::Length bleedMargin ) const
332 Concrete::Coords2D llcorner( 0, 0 );
333 Concrete::Coords2D urcorner( 0, 0 );
334 boundingbox_->boundingRectangle( & llcorner, & urcorner );
336 Lang::ElementaryPath2D * bleedBox = new Lang::ElementaryPath2D;
338 bleedBox->push_back( new Concrete::PathPoint2D( llcorner.x_ - bleedMargin, llcorner.y_ - bleedMargin ) );
339 bleedBox->push_back( new Concrete::PathPoint2D( urcorner.x_ + bleedMargin, llcorner.y_ - bleedMargin ) );
340 bleedBox->push_back( new Concrete::PathPoint2D( urcorner.x_ + bleedMargin, urcorner.y_ + bleedMargin ) );
341 bleedBox->push_back( new Concrete::PathPoint2D( llcorner.x_ - bleedMargin, urcorner.y_ + bleedMargin ) );
342 bleedBox->close( );
344 return RefCountPtr< const Lang::XObject >( new Lang::XObject( resource_, boundingbox_, RefCountPtr< const Lang::ElementaryPath2D >( bleedBox ), metaState ) );
347 void
348 Lang::XObject::setDebugStr( const std::string & debugStr )
350 debugStr_ = debugStr;
353 const std::string &
354 Lang::XObject::getDebugStr( ) const
356 return debugStr_;
359 void
360 Lang::XObject::show( std::ostream & os ) const
362 os << "XObject (" << getDebugStr( ) << ")" ;
365 void
366 Lang::XObject::gcMark( Kernel::GCMarkedSet & marked )
368 // At the time of writing, there is nothing to propagate to.
372 Lang::TransparencyGroup::TransparencyGroup( const RefCountPtr< SimplePDF::PDF_Indirect_out > & indirection, RefCountPtr< const Lang::ElementaryPath2D > mybbox, const RefCountPtr< const Lang::ColorSpace > & colorSpace )
373 : Lang::XObject( indirection, mybbox ), colorSpace_( colorSpace ), indirection_( indirection )
376 Lang::TransparencyGroup::~TransparencyGroup( )
379 RefCountPtr< const Lang::ColorSpace >
380 Lang::TransparencyGroup::colorSpace( ) const
382 return colorSpace_;
385 RefCountPtr< SimplePDF::PDF_Indirect_out >
386 Lang::TransparencyGroup::getPDF_Object( ) const
388 return indirection_.unconst_cast< SimplePDF::PDF_Indirect_out >( );
391 RefCountPtr< const Lang::TransparencyGroup >
392 Helpers::newTransparencyGroup( const RefCountPtr< const Lang::Drawable2D > & content, bool isolated, bool knockout, const RefCountPtr< const Lang::ColorSpace > & blendSpace )
394 RefCountPtr< const Lang::ElementaryPath2D > theBBox = content->bbox( Lang::Drawable2D::BOUNDING );
395 Concrete::Coords2D llcorner( 0, 0 );
396 Concrete::Coords2D urcorner( 0, 0 );
397 if( ! theBBox->boundingRectangle( & llcorner, & urcorner ) )
399 throw Exceptions::InternalError( "newTransparencyGroup: The object has no bounding box!" );
402 using namespace Shapes;
404 RefCountPtr< SimplePDF::PDF_Stream_out > form;
406 (*form)[ "Subtype" ] = SimplePDF::newName( "Form" );
407 (*form)[ "FormType" ] = SimplePDF::newInt( 1 );
408 (*form)[ "BBox" ] = RefCountPtr< SimplePDF::PDF_Vector >( new SimplePDF::PDF_Vector( llcorner.x_.offtype< 1, 0 >( ), llcorner.y_.offtype< 1, 0 >( ),
409 urcorner.x_.offtype< 1, 0 >( ), urcorner.y_.offtype< 1, 0 >( ) ) );
410 RefCountPtr< SimplePDF::PDF_Resources > resources;
411 (*form)[ "Resources" ] = SimplePDF::indirect( resources, & Kernel::theIndirectObjectCount );
413 if( ! Kernel::allowTransparency )
415 /* OK, fine. */
417 else if( ! Kernel::the_PDF_version.greaterOrEqual( SimplePDF::PDF_Version::PDF_1_4 ) )
419 Kernel::the_PDF_version.message( SimplePDF::PDF_Version::PDF_1_4, "A transparency group was replaced by a plain XObject." );
421 else
423 RefCountPtr< SimplePDF::PDF_Dictionary > groupDic;
424 (*form)[ "Group" ] = groupDic;
425 (*groupDic)[ "S" ] = SimplePDF::newName( "Transparency" );
426 if( ! blendSpace->isInherent( ) )
428 (*groupDic)[ "CS" ] = blendSpace->name( );
430 if( isolated )
432 (*groupDic)[ "I" ] = SimplePDF::newBoolean( true );
434 if( knockout )
436 (*groupDic)[ "K" ] = SimplePDF::newBoolean( true );
440 /* There's a possibility of adding a transformation matrix entry in the dictionary here, but it is not used, not even
441 * for transformed drawables.
443 // (*markForm)[ "Matrix" ] = RefCountPtr<PDF_Object>( new PDF_Vector( 1, 0, 0, 1, -30, -30 ) );
445 Kernel::PageContentStates pdfState( resources );
446 content->shipout( form->data, & pdfState, Lang::Transform2D( 1, 0, 0, 1, Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH ) );
448 Lang::TransparencyGroup * res = new Lang::TransparencyGroup( SimplePDF::indirect( form, & Kernel::theIndirectObjectCount ),
449 content->bbox( Lang::Drawable2D::BOUNDING ),
450 blendSpace );
451 res->setDebugStr( "transparency group" );
452 return RefCountPtr< const Lang::TransparencyGroup >( res );
455 Lang::RasterImage *
456 Lang::RasterImage::newInstance( size_t size_x, size_t size_y, size_t size_depth, Concrete::Length pixelSize_x, Concrete::Length pixelSize_y, RefCountPtr< const Lang::ColorSpace > colorSpace )
458 RefCountPtr< SimplePDF::PDF_Stream_out > stream = RefCountPtr< SimplePDF::PDF_Stream_out >( new SimplePDF::PDF_Stream_out );
459 RefCountPtr< SimplePDF::PDF_Object > indirection = SimplePDF::indirect( stream, & Kernel::theIndirectObjectCount );
461 (*stream)[ "Subtype" ] = SimplePDF::newName( "Image" );
462 (*stream)[ "Width" ] = SimplePDF::newInt( size_x );
463 (*stream)[ "Height" ] = SimplePDF::newInt( size_y );
464 (*stream)[ "ColorSpace" ] = colorSpace->name( );
465 (*stream)[ "BitsPerComponent" ] = SimplePDF::newInt( size_depth );
467 return new RasterImage( indirection, size_x, size_y, size_depth, pixelSize_x, pixelSize_y, colorSpace, stream );
470 void
471 Lang::RasterImage::setSoftMask( const RefCountPtr< const Lang::RasterImage > & softMask )
473 /* The caller is responsible for also adding the soft mask under "SMask" in the stream dictionary! */
474 softMask_ = softMask;
477 Lang::RasterImage::RasterImage( const RefCountPtr< SimplePDF::PDF_Object > & resource, size_t size_x, size_t size_y, size_t size_depth, Concrete::Length pixelSize_x, Concrete::Length pixelSize_y, RefCountPtr< const Lang::ColorSpace > colorSpace, RefCountPtr< SimplePDF::PDF_Stream_out > & stream )
478 : Lang::XObject( resource, RefCountPtr< const Lang::ElementaryPath2D >( newBoundingBox( size_x, size_y, pixelSize_x, pixelSize_y ) ) ),
479 size_x_( size_x ), size_y_( size_y ), size_depth_( size_depth ), pixelSize_x_( pixelSize_x ), pixelSize_y_( pixelSize_y ), colorSpace_( colorSpace ),
480 softMask_( NullPtr< const Lang::RasterImage >( ) ),
481 stream_( stream )
484 Lang::ElementaryPath2D *
485 Lang::RasterImage::newBoundingBox( size_t size_x, size_t size_y, Concrete::Length pixelSize_x, Concrete::Length pixelSize_y )
487 /* Note that this bounding box assumes that the image is scaled to resolution during shipout. */
488 Lang::ElementaryPath2D * res = new Lang::ElementaryPath2D;
490 res->push_back( new Concrete::PathPoint2D( Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH ) );
491 res->push_back( new Concrete::PathPoint2D( size_x * pixelSize_x, Concrete::ZERO_LENGTH ) );
492 res->push_back( new Concrete::PathPoint2D( size_x * pixelSize_x, size_y * pixelSize_y ) );
493 res->push_back( new Concrete::PathPoint2D( Concrete::ZERO_LENGTH, size_y * pixelSize_y ) );
494 res->close( );
495 return res;
498 Lang::RasterImage::~RasterImage( )
501 RefCountPtr< const Lang::Class > Lang::RasterImage::TypeID( new Lang::SystemFinalClass( strrefdup( "RasterImage" ) ) );
502 TYPEINFOIMPL( RasterImage );
504 void
505 Lang::RasterImage::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
507 Lang::XObject::shipout( os, pdfState, Lang::Transform2D( tf, Transform2D( size_x_ * static_cast< double >( Concrete::Length::offtype( pixelSize_x_ ) ), 0, 0, size_y_ * static_cast< double >( Concrete::Length::offtype( pixelSize_y_ ) ),
508 Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH ) ) );
511 Kernel::VariableHandle
512 Lang::RasterImage::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
514 if( strcmp( fieldID, "size_x" ) == 0 )
516 return Helpers::newValHandle( new Lang::Integer( size_x_ ) );
518 if( strcmp( fieldID, "size_y" ) == 0 )
520 return Helpers::newValHandle( new Lang::Integer( size_y_ ) );
522 if( strcmp( fieldID, "depth" ) == 0 )
524 return Helpers::newValHandle( new Lang::Integer( size_depth_ ) );
526 if( strcmp( fieldID, "space" ) == 0 )
528 return Kernel::VariableHandle( new Kernel::Variable( colorSpace_ ) );
530 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
533 void
534 Lang::RasterImage::gcMark( Kernel::GCMarkedSet & marked )
536 const_cast< Lang::ColorSpace * >( colorSpace_.getPtr( ) )->gcMark( marked );
537 if( softMask_ != NullPtr< const Lang::RasterImage >( ) )
539 const_cast< Lang::RasterImage * >( softMask_.getPtr( ) )->gcMark( marked );
541 Lang::XObject::gcMark( marked );
546 Lang::PaintedPath2D::PaintedPath2D( const RefCountPtr< const Kernel::GraphicsState > & metaState,
547 const char * paintCmd )
548 : metaState_( metaState ), paintCmd_( paintCmd )
551 Lang::PaintedPath2D::PaintedPath2D( const RefCountPtr< const Kernel::GraphicsState > & metaState,
552 RefCountPtr< const Lang::ElementaryPath2D > path,
553 const char * paintCmd )
554 : metaState_( metaState ), paintCmd_( paintCmd )
556 addSubPath( path );
559 Lang::PaintedPath2D::PaintedPath2D( const RefCountPtr< const Kernel::GraphicsState > & metaState,
560 RefCountPtr< const Lang::MultiPath2D > paths,
561 const char * paintCmd )
562 : metaState_( metaState ), paintCmd_( paintCmd )
564 for( Lang::MultiPath2D::const_iterator i = paths->begin( ); i != paths->end( ); ++i )
567 typedef const Lang::ElementaryPath2D ArgType;
568 RefCountPtr< ArgType > subpath = (*i).down_cast< ArgType >( );
569 if( subpath != NullPtr< ArgType >( ) )
571 addSubPath( subpath );
572 continue;
577 typedef const Lang::CompositePath2D ArgType;
578 ArgType * subpath = dynamic_cast< ArgType * >( (*i).getPtr( ) );
579 if( subpath != 0 )
581 addSubPath( subpath->getElementaryPath( ) );
582 continue;
585 throw Exceptions::InternalError( "Painting 2D path: Encountered a subpath of unexpected type" );
589 Lang::PaintedPath2D::~PaintedPath2D( )
592 RefCountPtr< const Lang::Class > Lang::PaintedPath2D::TypeID( new Lang::SystemFinalClass( strrefdup( "PaintedPath2D" ) ) );
593 TYPEINFOIMPL( PaintedPath2D );
595 void
596 Lang::PaintedPath2D::addSubPath( RefCountPtr< const Lang::ElementaryPath2D > subpath )
598 path_.push_back( subpath );
601 void
602 Lang::PaintedPath2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
604 /* Transforming the path by tf is not good enough, since that does not transform softmasks etc.
607 char pdfCmd[4];
608 strcpy( pdfCmd, paintCmd_ );
610 Kernel::Auto_qQ auto_qQ( & pdfState->graphics_, & pdfState->text_, os, false );
611 if( ! tf.isIdentity( ) )
613 auto_qQ.activate( );
614 tf.shipout( os );
615 os << " cm" << std::endl ;
617 if( strcmp( paintCmd_, "S" ) == 0 )
619 pdfState->graphics_.synchForStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
621 else if( strcmp( paintCmd_, "f" ) == 0 ||
622 strcmp( paintCmd_, "f*" ) == 0 )
624 pdfState->graphics_.synchForNonStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
626 else if( strcmp( paintCmd_, "B" ) == 0 ||
627 strcmp( paintCmd_, "B*" ) == 0 ||
628 strcmp( paintCmd_, "b" ) == 0 ||
629 strcmp( paintCmd_, "b*" ) == 0 )
631 pdfState->graphics_.synchForNonStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
632 pdfState->graphics_.synchForStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
634 else if( strcmp( paintCmd_, "E" ) == 0 ||
635 strcmp( paintCmd_, "E*" ) == 0 ||
636 strcmp( paintCmd_, "e" ) == 0 ||
637 strcmp( paintCmd_, "e*" ) == 0 )
639 pdfCmd[0] += 'B' - 'E';
640 // Note that this is my own interpretation; usually, the stroke is made with the stroking color,
641 // but I use this to make filled regions just a little bit bigger, and then it is the nonstroking
642 // color that shall be applied to the stroke as well.
643 pdfState->graphics_.synchForNonStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
644 pdfState->graphics_.synchStrokingColorWithNonStrokingColor( os, pdfState->resources_.getPtr( ), Concrete::ZERO_LENGTH );
646 else
648 throw Exceptions::InternalError( "Unexpected paintCmd in PaintedPath2D::shipout" );
651 typedef typeof path_ ListType;
652 for( ListType::const_iterator i = path_.begin( ); i != path_.end( ); ++i )
654 (*i)->writePath( os );
656 os << " " << pdfCmd << std::endl ;
659 RefCountPtr< const Lang::ElementaryPath2D >
660 Lang::PaintedPath2D::bbox( Lang::Drawable2D::BoxType boxType ) const
662 if( path_.empty( ) )
664 return RefCountPtr< const Lang::ElementaryPath2D >( new Lang::ElementaryPath2D );
667 Concrete::Length xmin = Concrete::HUGE_LENGTH;
668 Concrete::Length xmax = -Concrete::HUGE_LENGTH;
669 Concrete::Length ymin = Concrete::HUGE_LENGTH;
670 Concrete::Length ymax = -Concrete::HUGE_LENGTH;
672 Concrete::Coords2D llcorner( 0, 0 ); /* Temporary variables to be used in the loop below. */
673 Concrete::Coords2D urcorner( 0, 0 );
675 typedef typeof path_ PathType;
676 for( PathType::const_iterator j = path_.begin( ); j != path_.end( ); ++j )
678 if( (*j)->boundingRectangle( & llcorner, & urcorner ) )
680 /* non-empty path */
681 xmin = std::min( xmin, llcorner.x_ );
682 xmax = std::max( xmax, urcorner.x_ );
683 ymin = std::min( ymin, llcorner.y_ );
684 ymax = std::max( ymax, urcorner.y_ );
688 Lang::ElementaryPath2D * res = new Lang::ElementaryPath2D;
690 if( xmin < Concrete::HUGE_LENGTH )
692 if( toupper( *paintCmd_ ) == 'S' ||
693 toupper( *paintCmd_ ) == 'B' )
695 xmin -= 0.5 * metaState_->width_;
696 ymin -= 0.5 * metaState_->width_;
697 xmax += 0.5 * metaState_->width_;
698 ymax += 0.5 * metaState_->width_;
700 res->push_back( new Concrete::PathPoint2D( xmin, ymin ) );
701 res->push_back( new Concrete::PathPoint2D( xmin, ymax ) );
702 res->push_back( new Concrete::PathPoint2D( xmax, ymax ) );
703 res->push_back( new Concrete::PathPoint2D( xmax, ymin ) );
704 res->close( );
707 return RefCountPtr< const Lang::ElementaryPath2D >( res );
710 void
711 Lang::PaintedPath2D::gcMark( Kernel::GCMarkedSet & marked )
715 Lang::Transformed2D::Transformed2D( RefCountPtr< const Lang::Drawable2D > element, const Lang::Transform2D & mytf )
716 : mytf_( mytf ), element_( element )
719 Lang::Transformed2D::~Transformed2D( )
722 void
723 Lang::Transformed2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
725 element_->shipout( os, pdfState, Lang::Transform2D( tf, mytf_ ) );
728 RefCountPtr< const Lang::ElementaryPath2D >
729 Lang::Transformed2D::bbox( Lang::Drawable2D::BoxType boxType ) const
731 return element_->bbox( boxType )->elementaryTransformed( mytf_ );
734 void
735 Lang::Transformed2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
737 element_->findTags( dst, dyn, key, Lang::Transform2D( tf, mytf_ ) );
740 bool
741 Lang::Transformed2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
743 return
744 element_->findOneTag( evalState, key, Lang::Transform2D( tf, mytf_ ) );
747 void
748 Lang::Transformed2D::gcMark( Kernel::GCMarkedSet & marked )
750 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
754 Lang::BBoxed2D::BBoxed2D( RefCountPtr< const Lang::Drawable2D > element, RefCountPtr< const Lang::ElementaryPath2D > mybbox, BoxType boxType )
755 : Lang::PaintedPolygon2D( Kernel::THE_NO_STATE, mybbox ), mybbox_( mybbox ), element_( element ), boxType_( boxType )
758 Lang::BBoxed2D::~BBoxed2D( )
761 void
762 Lang::BBoxed2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
764 /* At the moment, we don't clip according to the bbox, we only lie about our size.
766 element_->shipout( os, pdfState, tf );
769 RefCountPtr< const Lang::ElementaryPath2D >
770 Lang::BBoxed2D::bbox( Lang::Drawable2D::BoxType boxType ) const
772 if( boxType_ == BOTH
773 || ( boxType == Lang::Drawable2D::BOUNDING && boxType_ == BOUNDING )
774 || ( boxType == Lang::Drawable2D::BLEED && boxType_ == BLEED ) )
776 return mybbox_;
778 return element_->bbox( boxType );
781 void
782 Lang::BBoxed2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
784 element_->findTags( dst, dyn, key, tf );
787 bool
788 Lang::BBoxed2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
790 return
791 element_->findOneTag( evalState, key, tf );
794 void
795 Lang::BBoxed2D::gcMark( Kernel::GCMarkedSet & marked )
797 Lang::PaintedPolygon2D::gcMark( marked );
798 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
802 Lang::Clipped2D::Clipped2D( const RefCountPtr< const Lang::Drawable2D > & element, const char * clipCommand )
803 : element_( element ), clipCommand_( clipCommand )
806 Lang::Clipped2D::~Clipped2D( )
809 void
810 Lang::Clipped2D::addSubPath( const RefCountPtr< const Lang::ElementaryPath2D > & subpath )
812 clipList_.push_back( subpath );
815 void
816 Lang::Clipped2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
818 Kernel::Auto_qQ auto_qQ( & pdfState->graphics_, & pdfState->text_, os );
819 if( ! tf.isIdentity( ) )
821 tf.shipout( os );
822 os << " cm" << std::endl ;
824 typedef typeof clipList_ ListType;
825 for( ListType::const_iterator i = clipList_.begin( ); i != clipList_.end( ); ++i )
827 (*i)->writePath( os );
829 os << " " << clipCommand_ << " n" << std::endl ;
830 element_->shipout( os, pdfState, THE_2D_IDENTITY );
833 RefCountPtr< const Lang::ElementaryPath2D >
834 Lang::Clipped2D::bbox( Lang::Drawable2D::BoxType boxType ) const
836 RefCountPtr< const Lang::ElementaryPath2D > elem_bbox = element_->bbox( boxType );
838 if( clipList_.empty( ) )
840 return RefCountPtr< const Lang::ElementaryPath2D >( new Lang::ElementaryPath2D );
843 Concrete::Coords2D llElemBbox( 0, 0 );
844 Concrete::Coords2D urElemBbox( 0, 0 );
845 elem_bbox->boundingRectangle( & llElemBbox, & urElemBbox );
847 Concrete::Length xmin = Concrete::HUGE_LENGTH;
848 Concrete::Length xmax = -Concrete::HUGE_LENGTH;
849 Concrete::Length ymin = Concrete::HUGE_LENGTH;
850 Concrete::Length ymax = -Concrete::HUGE_LENGTH;
852 Concrete::Coords2D llcorner( 0, 0 ); /* Temporary variables to be used in the loop below. */
853 Concrete::Coords2D urcorner( 0, 0 );
855 typedef typeof clipList_ PathType;
856 for( PathType::const_iterator j = clipList_.begin( ); j != clipList_.end( ); ++j )
858 if( (*j)->boundingRectangle( & llcorner, & urcorner ) )
860 /* non-empty path */
861 xmin = std::min( xmin, llcorner.x_ );
862 xmax = std::max( xmax, urcorner.x_ );
863 ymin = std::min( ymin, llcorner.y_ );
864 ymax = std::max( ymax, urcorner.y_ );
868 xmin = std::max( xmin, llElemBbox.x_ );
869 ymin = std::max( ymin, llElemBbox.y_ );
870 xmax = std::min( xmax, urElemBbox.x_ );
871 ymax = std::min( ymax, urElemBbox.y_ );
873 Lang::ElementaryPath2D * res = new Lang::ElementaryPath2D;
875 if( xmin < xmax && ymin < ymax )
877 res->push_back( new Concrete::PathPoint2D( xmin, ymin ) );
878 res->push_back( new Concrete::PathPoint2D( xmin, ymax ) );
879 res->push_back( new Concrete::PathPoint2D( xmax, ymax ) );
880 res->push_back( new Concrete::PathPoint2D( xmax, ymin ) );
881 res->close( );
884 return RefCountPtr< const Lang::ElementaryPath2D >( res );
887 void
888 Lang::Clipped2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
890 element_->findTags( dst, dyn, key, tf );
893 bool
894 Lang::Clipped2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
896 return
897 element_->findOneTag( evalState, key, tf );
900 void
901 Lang::Clipped2D::gcMark( Kernel::GCMarkedSet & marked )
903 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
906 RefCountPtr< const Lang::Drawable2D >
907 Lang::Clipped2D::debugPolys( ) const
909 Kernel::GraphicsState * frameStatePtr = new Kernel::GraphicsState( true );
910 frameStatePtr->width_ = Concrete::Length( 0.2 );
911 RefCountPtr< const Kernel::GraphicsState > frameState( frameStatePtr );
913 Lang::PaintedPath2D * res = new Lang::PaintedPath2D( frameState, "S" );
914 typedef typeof clipList_ ListType;
915 for( ListType::const_iterator i = clipList_.begin( ); i != clipList_.end( ); ++i )
917 res->addSubPath( *i );
920 return RefCountPtr< const Lang::Drawable2D >( res );
923 bool
924 Lang::Clipped2D::isSingleConvexPoly( Concrete::Length tol ) const
926 if( clipList_.size( ) != 1 )
928 return false;
930 return clipList_.front( )->isConvexPoly( tol );
933 bool
934 Lang::Clipped2D::convexPolyContains( const Concrete::Coords2D & p, Concrete::Length tol ) const
936 return clipList_.front( )->convexPolyContains( p, tol );
939 Lang::SoftMasked2D::SoftMasked2D( const RefCountPtr< const Lang::Drawable2D > & element, const RefCountPtr< const Lang::SoftMask > & mask )
940 : element_( element ), mask_( mask )
943 Lang::SoftMasked2D::~SoftMasked2D( )
946 void
947 Lang::SoftMasked2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
949 const SimplePDF::PDF_Version::Version SOFTMASK_VERSION = SimplePDF::PDF_Version::PDF_1_4;
950 if( Kernel::the_PDF_version.greaterOrEqual( SOFTMASK_VERSION ) )
952 Kernel::Auto_qQ auto_qQ( & pdfState->graphics_, & pdfState->text_, os );
953 if( ! tf.isIdentity( ) )
955 tf.shipout( os );
956 os << " cm" << std::endl ;
958 os << pdfState->resources_->nameofGraphicsState( mask_->graphicsStateResource_ ) << " gs " << std::endl ;
959 element_->shipout( os, pdfState, THE_2D_IDENTITY );
961 else
963 Kernel::the_PDF_version.message( SOFTMASK_VERSION, "A soft mask was ignored." );
964 element_->shipout( os, pdfState, tf );
968 RefCountPtr< const Lang::ElementaryPath2D >
969 Lang::SoftMasked2D::bbox( Lang::Drawable2D::BoxType boxType ) const
971 return element_->bbox( boxType );
974 void
975 Lang::SoftMasked2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
977 element_->findTags( dst, dyn, key, tf );
980 bool
981 Lang::SoftMasked2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
983 return
984 element_->findOneTag( evalState, key, tf );
987 void
988 Lang::SoftMasked2D::gcMark( Kernel::GCMarkedSet & marked )
990 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
991 const_cast< Lang::SoftMask * >( mask_.getPtr( ) )->gcMark( marked );
995 Lang::TextMasked2D::TextMasked2D( const RefCountPtr< const Lang::Drawable2D > & element, const RefCountPtr< const Lang::Text > & mask )
996 : element_( element ), mask_( mask )
999 Lang::TextMasked2D::~TextMasked2D( )
1002 void
1003 Lang::TextMasked2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
1005 mask_->shipout_clip( os, pdfState, tf, element_ );
1008 RefCountPtr< const Lang::ElementaryPath2D >
1009 Lang::TextMasked2D::bbox( Lang::Drawable2D::BoxType boxType ) const
1011 return mask_->bbox( boxType );
1014 void
1015 Lang::TextMasked2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
1017 element_->findTags( dst, dyn, key, tf );
1020 bool
1021 Lang::TextMasked2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
1023 return
1024 element_->findOneTag( evalState, key, tf );
1027 void
1028 Lang::TextMasked2D::gcMark( Kernel::GCMarkedSet & marked )
1030 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
1031 const_cast< Lang::Text * >( mask_.getPtr( ) )->gcMark( marked );
1035 Lang::Drawable3D::Drawable3D( )
1038 Lang::Drawable3D::~Drawable3D( )
1041 RefCountPtr< const Lang::Transformed3D >
1042 Lang::Drawable3D::typed_transformed( const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1044 return RefCountPtr< const Lang::Transformed3D >( new Lang::Transformed3D( self, tf ) );
1047 RefCountPtr< const Lang::Geometric3D >
1048 Lang::Drawable3D::transformed( const Lang::Transform3D & tf, const RefCountPtr< const Lang::Geometric3D > & self ) const
1050 return typed_transformed( tf, self.down_cast< const Lang::Drawable3D >( ) );
1053 RefCountPtr< const Lang::Geometric2D >
1054 Lang::Drawable3D::to2D( const Kernel::PassedDyn & dyn, const RefCountPtr< const Lang::Geometric3D > & self ) const
1056 typedef const Lang::Drawable3D SelfType;
1057 RefCountPtr< SelfType > typedSelf = self.down_cast< SelfType >( );
1058 if( typedSelf == NullPtr< SelfType >( ) )
1060 throw Exceptions::InternalError( "The self-value passed to Drawable3D::to2D was of bad type." );
1062 return typed_to2D( dyn, Lang::THE_3D_IDENTITY, typedSelf );
1065 void
1066 Lang::Drawable3D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1068 // Not overloading this methods means that there are no tagged objects within this.
1071 bool
1072 Lang::Drawable3D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1074 // Not overloading this methods means that there are no tagged objects within this.
1075 return false;
1078 void
1079 Lang::Drawable3D::gcMark( Kernel::GCMarkedSet & marked )
1082 RefCountPtr< const Lang::Class > Lang::Drawable3D::TypeID = NullPtr< const Lang::Class >( ); /* The value is set in main */
1083 TYPEINFOIMPL( Drawable3D );
1084 DISPATCHIMPL( Drawable3D );
1087 Lang::Group3D::Group3D( )
1090 Lang::Group3D::~Group3D( )
1093 RefCountPtr< const Lang::Drawable2D >
1094 Lang::Group3D::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1096 return group_to2D( dyn, tf );
1100 RefCountPtr< const Lang::Class > Lang::Group3D::TypeID( new Lang::SystemFinalClass( strrefdup( "Group3D" ) ) );
1101 TYPEINFOIMPL( Group3D );
1103 RefCountPtr< const Lang::Group3D >
1104 Helpers::newGroup3D( const RefCountPtr< const Kernel::GraphicsState > & metaState, const RefCountPtr< const Lang::Drawable3D > & obj2, const RefCountPtr< const Lang::Drawable3D > & obj1 )
1106 RefCountPtr< const Lang::Group3D > res = Lang::THE_NULL3D;
1107 res = RefCountPtr< const Lang::GroupPair3D >( new Lang::GroupPair3D( obj1,
1108 res,
1109 metaState ) );
1110 res = RefCountPtr< const Lang::GroupPair3D >( new Lang::GroupPair3D( obj2,
1111 res,
1112 metaState ) );
1113 return res;
1116 RefCountPtr< const Lang::Group3D >
1117 Helpers::newGroup3D( const RefCountPtr< const Kernel::GraphicsState > & metaState, const RefCountPtr< const Lang::Drawable3D > & obj3, const RefCountPtr< const Lang::Drawable3D > & obj2, const RefCountPtr< const Lang::Drawable3D > & obj1 )
1119 RefCountPtr< const Lang::Group3D > res = Lang::THE_NULL3D;
1120 res = RefCountPtr< const Lang::GroupPair3D >( new Lang::GroupPair3D( obj1,
1121 res,
1122 metaState ) );
1123 res = RefCountPtr< const Lang::GroupPair3D >( new Lang::GroupPair3D( obj2,
1124 res,
1125 metaState ) );
1126 res = RefCountPtr< const Lang::GroupPair3D >( new Lang::GroupPair3D( obj3,
1127 res,
1128 metaState ) );
1129 return res;
1133 Lang::GroupPair3D::GroupPair3D( const RefCountPtr< const Lang::Drawable3D > & car, const RefCountPtr< const Lang::Group3D > & cdr, const RefCountPtr< const Kernel::GraphicsState > & metaState )
1134 : metaState_( metaState ), car_( car ), cdr_( cdr )
1137 Lang::GroupPair3D::~GroupPair3D( )
1140 bool
1141 Lang::GroupPair3D::isNull( ) const
1143 return false;
1146 RefCountPtr< const Lang::Group2D >
1147 Lang::GroupPair3D::group_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf ) const
1149 return RefCountPtr< const Lang::Group2D >( new Lang::GroupPair2D( car_->typed_to2D( dyn, tf, car_ ),
1150 cdr_->group_to2D( dyn, tf ),
1151 metaState_ ) );
1154 void
1155 Lang::GroupPair3D::polygonize( std::list< RefCountPtr< Computation::PaintedPolygon3D > > * zBufPile, std::list< RefCountPtr< Computation::StrokedLine3D > > * linePile, const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1157 car_->polygonize( zBufPile, linePile, dyn, tf, car_ );
1158 cdr_->polygonize( zBufPile, linePile, dyn, tf, cdr_ );
1161 void
1162 Lang::GroupPair3D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1164 /* See note on order in GroupPair2D!
1166 cdr_->findTags( dst, dyn, key, tf );
1167 car_->findTags( dst, dyn, key, tf );
1170 bool
1171 Lang::GroupPair3D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1173 return
1174 cdr_->findOneTag( evalState, key, tf ) ||
1175 car_->findOneTag( evalState, key, tf );
1178 RefCountPtr< const Lang::Group3D >
1179 Lang::GroupPair3D::removeShallow( Lang::Symbol::KeyType key ) const
1182 typedef const Lang::Tagged3D TaggedType;
1183 TaggedType * t = dynamic_cast< TaggedType * >( car_.getPtr( ) );
1184 if( t != 0 && t->key( ) == key )
1186 return cdr_->removeShallow( key );
1189 return RefCountPtr< const Lang::Group3D >( new Lang::GroupPair3D( car_, cdr_->removeShallow( key ), metaState_ ) );
1192 void
1193 Lang::GroupPair3D::gcMark( Kernel::GCMarkedSet & marked )
1195 const_cast< Lang::Drawable3D * >( car_.getPtr( ) )->gcMark( marked );
1196 const_cast< Lang::Group3D * >( cdr_.getPtr( ) )->gcMark( marked );
1200 Lang::GroupNull3D::GroupNull3D( )
1203 Lang::GroupNull3D::~GroupNull3D( )
1206 bool
1207 Lang::GroupNull3D::isNull( ) const
1209 return true;
1212 RefCountPtr< const Lang::Group3D >
1213 Lang::GroupNull3D::removeShallow( Lang::Symbol::KeyType key ) const
1215 return Lang::THE_NULL3D;
1218 RefCountPtr< const Lang::Group2D >
1219 Lang::GroupNull3D::group_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf ) const
1221 return Lang::THE_NULL2D;
1224 void
1225 Lang::GroupNull3D::polygonize( std::list< RefCountPtr< Computation::PaintedPolygon3D > > * zBufPile, std::list< RefCountPtr< Computation::StrokedLine3D > > * linePile, const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1229 Lang::Drawable2Din3D::Drawable2Din3D( RefCountPtr< const Lang::Drawable2D > element )
1230 : element_( element )
1233 Lang::Drawable2Din3D::~Drawable2Din3D( )
1236 RefCountPtr< const Lang::Drawable2D >
1237 Lang::Drawable2Din3D::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1239 Concrete::Length eyez = dyn->getEyeZ( );
1240 if( eyez < Concrete::HUGE_LENGTH )
1242 std::ostringstream msg;
1243 msg << "An object of type " << element_->getTypeName( ) << " in 3D cannot go back to 2D viewed from a finite distance. Consider using facing rather than immerse." ;
1244 throw Exceptions::MiscellaneousRequirement( strrefdup( msg.str( ).c_str( ) ) );
1247 // The transform in 2D is obtained by setting z = 0 in the source 3D coordinates, and omitting the z-coordinate in the new coordinates
1249 return RefCountPtr< const Lang::Drawable2D >( new Lang::Transformed2D( element_, Lang::Transform2D( tf.xx_, tf.yx_, tf.xy_, tf.yy_, tf.xt_, tf.yt_ ) ) );
1252 void
1253 Lang::Drawable2Din3D::polygonize( std::list< RefCountPtr< Computation::PaintedPolygon3D > > * zBufPile, std::list< RefCountPtr< Computation::StrokedLine3D > > * linePile, const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1255 throw Exceptions::NotImplemented( "Triangularization of immersed objects." );
1258 void
1259 Lang::Drawable2Din3D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1261 Concrete::Length eyez = dyn->getEyeZ( );
1262 if( eyez < Concrete::HUGE_LENGTH )
1264 std::ostringstream msg;
1265 msg << "Tags in an immersed object are not accessible from a finite viewing distance. Consider using facing rather than immerse." ;
1266 throw Exceptions::MiscellaneousRequirement( strrefdup( msg.str( ).c_str( ) ) );
1269 // The transform in 2D is obtained by setting z = 0 in the source 3D coordinates, and omitting the z-coordinate in the new coordinates
1271 element_->findTags( dst, dyn, key, Lang::Transform2D( tf.xx_, tf.yx_, tf.xy_, tf.yy_, tf.xt_, tf.yt_ ) );
1274 bool
1275 Lang::Drawable2Din3D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1277 Concrete::Length eyez = evalState->dyn_->getEyeZ( );
1278 if( eyez < Concrete::HUGE_LENGTH )
1280 std::ostringstream msg;
1281 msg << "Tags in an immersed object are not accessible from a finite viewing distance. Consider using facing rather than immerse." ;
1282 throw Exceptions::MiscellaneousRequirement( strrefdup( msg.str( ).c_str( ) ) );
1285 // The transform in 2D is obtained by setting z = 0 in the source 3D coordinates, and omitting the z-coordinate in the new coordinates
1287 return
1288 element_->findOneTag( evalState, key, Lang::Transform2D( tf.xx_, tf.yx_, tf.xy_, tf.yy_, tf.xt_, tf.yt_ ) );
1291 void
1292 Lang::Drawable2Din3D::gcMark( Kernel::GCMarkedSet & marked )
1294 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
1299 Lang::Facing2Din3D::Facing2Din3D( RefCountPtr< const Lang::Drawable2D > element, bool scale, bool distort )
1300 : element_( element ), scale_( scale ), distort_( distort )
1303 Lang::Facing2Din3D::~Facing2Din3D( )
1306 RefCountPtr< const Lang::Drawable2D >
1307 Lang::Facing2Din3D::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1309 Concrete::Length eyez = dyn->getEyeZ( );
1310 double s = 1;
1311 if( scale_ && eyez < Concrete::HUGE_LENGTH )
1313 s = eyez / ( eyez - tf.zt_ );
1316 Concrete::Length x;
1317 Concrete::Length y;
1318 if( eyez < Concrete::HUGE_LENGTH )
1320 x = tf.xt_ * ( eyez / ( eyez - tf.zt_ ) );
1321 y = tf.yt_ * ( eyez / ( eyez - tf.zt_ ) );
1323 else
1325 x = tf.xt_;
1326 y = tf.yt_;
1329 if( distort_ )
1331 return RefCountPtr< const Lang::Drawable2D >( new Lang::Transformed2D( element_, Lang::Transform2D( s * tf.xx_, s * tf.yx_, s * tf.xy_, s * tf.yy_, x, y ) ) );
1333 else
1335 return RefCountPtr< const Lang::Drawable2D >( new Lang::Transformed2D( element_, Lang::Transform2D( s, 0, 0, s, x, y ) ) );
1339 void
1340 Lang::Facing2Din3D::polygonize( std::list< RefCountPtr< Computation::PaintedPolygon3D > > * zBufPile, std::list< RefCountPtr< Computation::StrokedLine3D > > * linePile, const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1342 throw Exceptions::MiscellaneousRequirement( "Facing objects cannot be polygonized." );
1345 void
1346 Lang::Facing2Din3D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1348 Concrete::Length eyez = dyn->getEyeZ( );
1349 double s = 1;
1350 if( scale_ && eyez < Concrete::HUGE_LENGTH )
1352 s = eyez / ( eyez - tf.zt_ );
1355 Concrete::Length x;
1356 Concrete::Length y;
1357 if( eyez < Concrete::HUGE_LENGTH )
1359 x = tf.xt_ * ( eyez / ( eyez - tf.zt_ ) );
1360 y = tf.yt_ * ( eyez / ( eyez - tf.zt_ ) );
1362 else
1364 x = tf.xt_;
1365 y = tf.yt_;
1368 if( distort_ )
1370 element_->findTags( dst, dyn, key, Lang::Transform2D( s * tf.xx_, s * tf.yx_, s * tf.xy_, s * tf.yy_, x, y ) );
1372 else
1374 element_->findTags( dst, dyn, key, Lang::Transform2D( s, 0, 0, s, x, y ) );
1378 bool
1379 Lang::Facing2Din3D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1381 Concrete::Length eyez = evalState->dyn_->getEyeZ( );
1382 double s = 1;
1383 if( scale_ && eyez < Concrete::HUGE_LENGTH )
1385 s = eyez / ( eyez - tf.zt_ );
1388 Concrete::Length x;
1389 Concrete::Length y;
1390 if( eyez < Concrete::HUGE_LENGTH )
1392 x = tf.xt_ * ( eyez / ( eyez - tf.zt_ ) );
1393 y = tf.yt_ * ( eyez / ( eyez - tf.zt_ ) );
1395 else
1397 x = tf.xt_;
1398 y = tf.yt_;
1401 if( distort_ )
1403 return
1404 element_->findOneTag( evalState, key, Lang::Transform2D( s * tf.xx_, s * tf.yx_, s * tf.xy_, s * tf.yy_, x, y ) );
1406 else
1408 return
1409 element_->findOneTag( evalState, key, Lang::Transform2D( s, 0, 0, s, x, y ) );
1413 void
1414 Lang::Facing2Din3D::gcMark( Kernel::GCMarkedSet & marked )
1416 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
1420 Lang::FacingFunction3D::FacingFunction3D( Kernel::PassedDyn dyn, RefCountPtr< const Lang::Function > generator )
1421 : dyn_( dyn ), generator_( generator )
1424 Lang::FacingFunction3D::~FacingFunction3D( )
1427 RefCountPtr< const Lang::Drawable2D >
1428 Lang::FacingFunction3D::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1430 /* Too bad we can't call the function CPP here...
1432 Kernel::ValueRef valUntyped = NullPtr< const Lang::Value >( );
1434 static Ast::SourceLocation loc( Ast::FileID::build_internal( "<Facing a function in 3D>" ) );
1436 /* Note that the use of a StoreValueContinuation relies on valUntyped being alive at the time the continuation is invoked.
1438 bool done = false;
1439 Kernel::EvalState evalState( 0,
1441 dyn_,
1442 Kernel::ContRef( new Kernel::StoreValueContinuation( & valUntyped,
1443 Kernel::ContRef( new Kernel::ExitContinuation( & done, loc ) ),
1444 loc ) ) );
1446 generator_->call( & evalState, RefCountPtr< const Lang::Value >( new Lang::Transform3D( tf ) ), loc );
1448 while( ! done )
1450 evalState.expr_->eval( & evalState );
1453 return Helpers::down_cast< const Lang::Drawable2D >( valUntyped, loc );
1456 void
1457 Lang::FacingFunction3D::polygonize( std::list< RefCountPtr< Computation::PaintedPolygon3D > > * zBufPile, std::list< RefCountPtr< Computation::StrokedLine3D > > * linePile, const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1459 throw Exceptions::MiscellaneousRequirement( "Facing functions cannot be polygonized." );
1462 void
1463 Lang::FacingFunction3D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1466 * At the moment, we don't search facing functions for tags!
1470 bool
1471 Lang::FacingFunction3D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1474 * At the moment, we don't search facing functions for tags!
1476 return false;
1479 void
1480 Lang::FacingFunction3D::gcMark( Kernel::GCMarkedSet & marked )
1482 const_cast< Lang::Function * >( generator_.getPtr( ) )->gcMark( marked );
1486 Computation::PaintedPolygon3D::PaintedPolygon3D( bool singleSided, const Concrete::UnitFloatTriple & normal, Concrete::Length m, Concrete::Length tiebreaker )
1487 : singleSided_( singleSided ), normal_( normal ), m_( m ), tiebreaker_( tiebreaker )
1490 Computation::PaintedPolygon3D::~PaintedPolygon3D( )
1493 void
1494 Computation::PaintedPolygon3D::pushPoint( const Concrete::Coords3D & p )
1496 Concrete::Length tmp = Concrete::inner( normal_, p ) - m_;
1497 if( tmp.abs( ) > Computation::theTrixelizeSplicingTol )
1499 std::ostringstream msg;
1500 msg << "The 3D painted path was not flat enough (" << tmp.offtype< 1, 0 >( ) << " > splicingtol) to make a polygon." ;
1501 throw Exceptions::OutOfRange( strrefdup( msg ) );
1503 points_.push_back( p );
1506 void
1507 Computation::PaintedPolygon3D::push_zBufTriangles( const Lang::Transform3D & tf, const Concrete::Length eyez, std::list< Computation::ZBufTriangle > * triangleQueue, bool respectSingleSided ) const
1509 // This function shall not push tiny triangles!
1511 // Note that the ZBufTriangles pushed are not completely transformed, since *this is the painter, and not transformed by tf.
1512 // The ugly solution to this is that tf must also be specified when painting the area.
1514 if( points_.size( ) < 3 )
1516 return;
1519 // At the moment, convexity is assumed!
1521 typedef Computation::ZBufTriangle::ZMap ZMapType;
1522 if( tf.isIdentity( ) )
1524 if( respectSingleSided && singleSided_ )
1526 const Concrete::Coords3D & somePoint = points_.front( );
1527 if( normal_.z_ * eyez - Concrete::inner( normal_, somePoint ) <= 0 )
1529 return;
1533 RefCountPtr< const ZMapType > zMap( new ZMapType( normal_, m_, tiebreaker_, eyez ) );
1534 typedef typeof points_ ListType;
1535 ListType::const_iterator i = points_.begin( );
1536 Concrete::Coords2D p0 = i->make2DAutomatic( eyez );
1537 ++i;
1538 Concrete::Coords2D p1 = i->make2DAutomatic( eyez );
1539 ++i;
1540 for( ; i != points_.end( ); ++i )
1542 Concrete::Coords2D p2 = i->make2DAutomatic( eyez );
1543 // This tolerance test assures that we don't produce tiny-tiny triangles. It is an inscribed circle test.
1544 if( Computation::triangleArea( p0, p1, p2 ) > Computation::theTrixelizeOverlapTol * Computation::triangleSemiPerimeter( p0, p1, p2 ) )
1546 triangleQueue->push_back( Computation::ZBufTriangle( this,
1547 zMap,
1548 p0, p1, p2 ) );
1550 p1 = p2;
1553 else
1555 RefCountPtr< const ZMapType > zMap = RefCountPtr< const ZMapType >( NullPtr< const ZMapType >( ) );
1557 Concrete::UnitFloatTriple Tnormal = tf.transformPlaneUnitNormal( normal_ );
1558 if( respectSingleSided && singleSided_ )
1560 const Concrete::Coords3D & somePoint = points_.front( );
1561 if( Tnormal.z_ * eyez - Concrete::inner( Tnormal, somePoint.transformed( tf ) ) <= 0 )
1563 return;
1567 double ax = fabs( normal_.x_ );
1568 double ay = fabs( normal_.y_ );
1569 double az = fabs( normal_.z_ );
1570 Concrete::Coords3D x0( 0, 0, 0 );
1571 if( ax >= ay && ax >= az )
1573 x0 = Concrete::Coords3D( m_ / normal_.x_, 0, 0 );
1575 else if( ay >= az )
1577 x0 = Concrete::Coords3D( 0, m_ / normal_.y_, 0 );
1579 else
1581 x0 = Concrete::Coords3D( 0, 0, m_ / normal_.z_ );
1583 Concrete::Length Tm = Concrete::inner( Tnormal, x0.transformed( tf ) );
1585 zMap = RefCountPtr< const ZMapType >( new ZMapType( Tnormal, Tm, tiebreaker_, eyez ) );
1589 typedef typeof points_ ListType;
1590 ListType::const_iterator i = points_.begin( );
1591 Concrete::Coords2D p0 = i->transformed( tf ).make2DAutomatic( eyez );
1592 ++i;
1593 Concrete::Coords2D p1 = i->transformed( tf ).make2DAutomatic( eyez );
1594 ++i;
1595 for( ; i != points_.end( ); ++i )
1597 Concrete::Coords2D p2 = i->transformed( tf ).make2DAutomatic( eyez );
1598 // This tolerance test assures that we don't produce tiny-tiny triangles. It is an inscribed circle test.
1599 if( Computation::triangleArea( p0, p1, p2 ) > Computation::theTrixelizeOverlapTol * Computation::triangleSemiPerimeter( p0, p1, p2 ) )
1601 triangleQueue->push_back( Computation::ZBufTriangle( this,
1602 zMap,
1603 p0, p1, p2 ) );
1605 p1 = p2;
1610 Concrete::Coords3D
1611 Computation::PaintedPolygon3D::computeMean( ) const
1613 Concrete::Coords3D res( 0, 0, 0 );
1614 typedef typeof points_ ListType;
1615 for( ListType::const_iterator i = points_.begin( ); i != points_.end( ); ++i )
1617 res = res + *i;
1619 return ( 1. / points_.size( ) ) * res;
1622 const Computation::FacetLatticeVertex *
1623 Computation::FacetLatticeEdge::getOther( const FacetLatticeEdge * e ) const
1625 if( p0_ == e->p0_ || p0_ == e->p1_ )
1627 return p1_;
1629 return p0_;
1632 bool
1633 Computation::FacetLatticeEdge::sharePoint( const FacetLatticeEdge * e ) const
1635 return
1636 p0_ == e->p0_ ||
1637 p0_ == e->p1_ ||
1638 p1_ == e->p0_ ||
1639 p1_ == e->p1_;
1643 void
1644 Computation::FacetLatticeEdge::split( const Concrete::Length eyez,
1645 PtrOwner_back_Access< std::list< const Computation::FacetLatticeEdge * > > * edgeMem,
1646 PtrOwner_back_Access< std::list< const Computation::FacetLatticeVertex * > > * vertexMem,
1647 const Computation::FacetLatticeEdge ** child1, const Computation::FacetLatticeEdge ** child2 ) const
1649 if( child1_ != 0 )
1651 *child1 = child1_;
1652 *child2 = child2_;
1653 return;
1656 if( eyez == Concrete::HUGE_LENGTH )
1658 FacetLatticeVertex * pNew = new FacetLatticeVertex( 0.5 * ( p0_->p3D_ + p1_->p3D_ ), eyez, vertexMem->size( ) );
1659 vertexMem->push_back( pNew );
1660 child1_ = new Computation::FacetLatticeEdge( p0_, pNew );
1661 edgeMem->push_back( child1_ );
1662 child2_ = new Computation::FacetLatticeEdge( pNew, p1_ );
1663 edgeMem->push_back( child2_ );
1665 else
1667 // We compute the midpoint _in_view_, and then find where this is along the 3D line.
1668 Concrete::Coords2D mid2D = 0.5 * ( p0_->p2D_ + p1_->p2D_ );
1670 // If we write the point we seek in 3D as
1671 // p0_ + lambda * ( p1_ - p0_ )
1672 // then <lambda> must solve the overdetermined system
1673 // a * lambda == -b
1674 // where
1675 const double ra = ( p1_->p3D_.z_ - p0_->p3D_.z_ ) / eyez;
1676 Concrete::Coords2D a( p1_->p3D_.x_ - p0_->p3D_.x_ + mid2D.x_ * ra,
1677 p1_->p3D_.y_ - p0_->p3D_.y_ + mid2D.y_ * ra );
1678 const double rb = static_cast< double >( p0_->p3D_.z_ / eyez ) - 1;
1679 Concrete::Coords2D b( p0_->p3D_.x_ + mid2D.x_ * rb,
1680 p0_->p3D_.y_ + mid2D.y_ * rb );
1681 const double lambda = - Concrete::innerScalar( a, b ) / Concrete::innerScalar( a, a );
1683 FacetLatticeVertex * pNew = new FacetLatticeVertex( ( 1 - lambda ) * p0_->p3D_ + lambda * p1_->p3D_, eyez, vertexMem->size( ) );
1684 vertexMem->push_back( pNew );
1685 child1_ = new Computation::FacetLatticeEdge( p0_, pNew );
1686 edgeMem->push_back( child1_ );
1687 child2_ = new Computation::FacetLatticeEdge( pNew, p1_ );
1688 edgeMem->push_back( child2_ );
1691 *child1 = child1_;
1692 *child2 = child2_;
1696 Computation::FacetLatticeVertex::FacetLatticeVertex( const Concrete::Coords3D & p3D, const Concrete::Length eyez, const size_t i )
1697 : p3D_( p3D ), p2D_( p3D.make2DAutomatic( eyez ) ), i_( i )
1700 const Computation::FacetLatticeEdge *
1701 Computation::FacetLatticeTriangle::getOther( const Computation::FacetLatticeEdge *ea, const Computation::FacetLatticeEdge *eb ) const
1703 if( ea == e0_ )
1705 if( eb == e1_ )
1707 return e2_;
1709 return e1_;
1711 else if( ea == e1_ )
1713 if( eb == e0_ )
1715 return e2_;
1717 return e0_;
1719 else if( ea == e2_ )
1721 if( eb == e0_ )
1723 return e1_;
1725 return e0_;
1728 throw Exceptions::InternalError( "FacetTriangle::getOther called with alien edge." );
1731 bool
1732 Computation::FacetLatticeTriangle::fitsResolution( const Concrete::Length resolution, const Concrete::Length eyez,
1733 PtrOwner_back_Access< std::list< const Computation::FacetLatticeEdge * > > * edgeMem,
1734 PtrOwner_back_Access< std::list< const Computation::FacetLatticeVertex * > > * vertexMem,
1735 const Computation::FacetLatticeTriangle ** child1, const Computation::FacetLatticeTriangle ** child2 ) const
1737 const Computation::FacetLatticeEdge * ec1;
1738 const Computation::FacetLatticeEdge * ec2;
1740 Concrete::Length l0 = e0_->length2D( );
1741 Concrete::Length l1 = e1_->length2D( );
1742 Concrete::Length l2 = e2_->length2D( );
1743 Concrete::Length lMax = std::max( l0, std::max( l1, l2 ) );
1745 if( lMax < resolution )
1747 return true;
1750 const Computation::FacetLatticeEdge * ea = e0_;
1751 const Computation::FacetLatticeEdge * eb = e1_;
1752 const Computation::FacetLatticeEdge * ec = e2_;
1753 if( l1 == lMax )
1755 ea = e1_;
1756 eb = e2_;
1757 ec = e0_;
1759 else if( l2 == lMax )
1761 ea = e2_;
1762 eb = e0_;
1763 ec = e1_;
1767 ea->split( eyez, edgeMem, vertexMem, & ec1, & ec2 );
1768 Computation::FacetLatticeEdge * newEdge = new Computation::FacetLatticeEdge( ea->midpoint( ), eb->getOther( ea ) );
1769 edgeMem->push_back( newEdge );
1770 if( eb->sharePoint( ec2 ) )
1772 *child1 = new Computation::FacetLatticeTriangle( ec2, eb, newEdge );
1773 *child2 = new Computation::FacetLatticeTriangle( newEdge, ec, ec1 );
1775 else
1777 *child1 = new Computation::FacetLatticeTriangle( ec1, eb, newEdge );
1778 *child2 = new Computation::FacetLatticeTriangle( newEdge, ec, ec2 );
1781 return false;
1785 RefCountPtr< const Lang::Drawable2D >
1786 Computation::FacetLatticeTriangle::paint( const RefCountPtr< const Computation::FacetInterpolatorGray > & interpolator, const std::list< RefCountPtr< const Lang::LightSource > > & lights, const Concrete::Length eyez ) const
1788 Kernel::GraphicsState * metaStatePtr = new Kernel::GraphicsState( true );
1790 metaStatePtr->nonStrokingColor_ = interpolator->compute( Lang::THE_3D_IDENTITY, lights,
1791 Computation::triangleIncenter( v0_->p3D_, v1_->p3D_, v2_->p3D_ ),
1792 eyez );
1794 RefCountPtr< const Kernel::GraphicsState > metaState( metaStatePtr );
1796 RefCountPtr< Lang::ElementaryPath2D > path = RefCountPtr< Lang::ElementaryPath2D >( new Lang::ElementaryPath2D( ) );
1797 path->close( );
1798 // It's a pity we have to copy duplicate those points...
1799 path->push_back( new Concrete::PathPoint2D( new Concrete::Coords2D( v0_->p2D_ ) ) );
1800 path->push_back( new Concrete::PathPoint2D( new Concrete::Coords2D( v1_->p2D_ ) ) );
1801 path->push_back( new Concrete::PathPoint2D( new Concrete::Coords2D( v2_->p2D_ ) ) );
1803 return RefCountPtr< const Lang::PaintedPolygon2D >( new Lang::PaintedPolygon2D( metaState, path ) );
1806 RefCountPtr< const Lang::Drawable2D >
1807 Computation::FacetLatticeTriangle::paint( const RefCountPtr< const Computation::FacetInterpolatorRGB > & interpolator, const std::list< RefCountPtr< const Lang::LightSource > > & lights, const Concrete::Length eyez ) const
1809 Kernel::GraphicsState * metaStatePtr = new Kernel::GraphicsState( true );
1811 metaStatePtr->nonStrokingColor_ = interpolator->compute( Lang::THE_3D_IDENTITY, lights,
1812 Computation::triangleIncenter( v0_->p3D_, v1_->p3D_, v2_->p3D_ ),
1813 eyez );
1815 RefCountPtr< const Kernel::GraphicsState > metaState( metaStatePtr );
1817 RefCountPtr< Lang::ElementaryPath2D > path = RefCountPtr< Lang::ElementaryPath2D >( new Lang::ElementaryPath2D( ) );
1818 path->close( );
1819 // It's a pity we have to copy duplicate those points...
1820 path->push_back( new Concrete::PathPoint2D( new Concrete::Coords2D( v0_->p2D_ ) ) );
1821 path->push_back( new Concrete::PathPoint2D( new Concrete::Coords2D( v1_->p2D_ ) ) );
1822 path->push_back( new Concrete::PathPoint2D( new Concrete::Coords2D( v2_->p2D_ ) ) );
1824 return RefCountPtr< const Lang::PaintedPolygon2D >( new Lang::PaintedPolygon2D( metaState, path ) );
1827 void
1828 Computation::FacetLatticeTriangle::getVertexes( const Computation::FacetLatticeVertex ** va, const Computation::FacetLatticeVertex ** vb, const Computation::FacetLatticeVertex ** vc ) const
1830 *va = v0_;
1831 *vb = v1_;
1832 *vc = v2_;
1835 // This function is very close to the PDF definition of a free-form triangle mesh.
1836 // If this triangle is an extension of va--vb--vc, then va, vb, vc are updated and the corresponding flag (se PDF spec) is returned.
1837 // If this is not an extension, the value 3 is returned (which is not a legal falg value), and va, vb, vc are left unchanged.
1838 unsigned char
1839 Computation::FacetLatticeTriangle::extendLattice( const Computation::FacetLatticeVertex ** va, const Computation::FacetLatticeVertex ** vb, const Computation::FacetLatticeVertex ** vc ) const
1841 // vc must be part of this triangle if we are to extend va--vb--vc.
1842 if( v0_ == *vc || v1_ == *vc || v2_ == *vc )
1844 // First, we try to extend vb--vc (corresponding to flag=1)
1845 if( v0_ == *vb || v1_ == *vb || v2_ == *vb )
1847 // We now update va and vb so that they define the edge that is extended.
1848 *va = *vb;
1849 *vb = *vc;
1851 // Now we need to find which of our corners that is the added one.
1852 if( v0_ != *va && v0_ != *vb )
1854 *vc = v0_;
1856 else if( v1_ != *va && v1_ != *vb )
1858 *vc = v1_;
1860 else
1862 *vc = v2_;
1864 return 1;
1867 // Then, we try to extend va--vc (corresponding to flag=2)
1868 if( v0_ == *va || v1_ == *va || v2_ == *va )
1870 // We now update va and vb so that they define the edge that is extended.
1871 // *va = *va;
1872 *vb = *vc;
1874 // Now we need to find which of our corners that is the added one.
1875 if( v0_ != *va && v0_ != *vb )
1877 *vc = v0_;
1879 else if( v1_ != *va && v1_ != *vb )
1881 *vc = v1_;
1883 else
1885 *vc = v2_;
1887 return 2;
1891 return 3;
1894 void
1895 Computation::FacetLatticeTriangle::display2D( std::ostream & os ) const
1897 Concrete::Length lMax = Concrete::ZERO_LENGTH;
1899 Concrete::Length tmp = v0_->p2D_.distanceTo( v1_->p2D_ );
1900 if( tmp > lMax )
1902 lMax = tmp;
1906 Concrete::Length tmp = v1_->p2D_.distanceTo( v2_->p2D_ );
1907 if( tmp > lMax )
1909 lMax = tmp;
1913 Concrete::Length tmp = v2_->p2D_.distanceTo( v0_->p2D_ );
1914 if( tmp > lMax )
1916 lMax = tmp;
1920 os << "Triangle ( " << v0_->p2D_ << " -- " << v1_->p2D_ << " -- " << v2_->p2D_ << " ) "
1921 << " with 2D area " << Concrete::Area::offtype( Computation::triangleArea( v0_->p2D_, v1_->p2D_, v2_->p2D_ ) )
1922 << " and longest side " << Lang::Length( lMax ) ;
1925 void
1926 Computation::FacetLatticeTriangle::display3D( std::ostream & os ) const
1928 os << "Triangle ( " << v0_->p3D_ << " -- " << v1_->p3D_ << " -- " << v2_->p3D_ << " )" ;
1932 void
1933 Computation::PaintedPolygon3D::makeLattice( PtrOwner_back_Access< std::list< const Computation::FacetLatticeTriangle * > > * lattice,
1934 PtrOwner_back_Access< std::list< const Computation::FacetLatticeEdge * > > * edgeMem,
1935 PtrOwner_back_Access< std::list< const FacetLatticeVertex * > > * vertexMem,
1936 const Concrete::Length viewResolution,
1937 const Concrete::Length eyez, const Lang::Transform3D & tf ) const
1939 if( points_.size( ) < 3 )
1941 throw Exceptions::InternalError( "Less than three points in PaintedPolygon3D::makeLattice!" );
1944 std::list< const Computation::FacetLatticeTriangle * > jobQueue;
1946 typedef typeof points_ ListType;
1948 if( points_.size( ) == 3 )
1950 ListType::const_iterator i = points_.begin( );
1951 Computation::FacetLatticeVertex * p0 = new Computation::FacetLatticeVertex( i->transformed( tf ), eyez, vertexMem->size( ) );
1952 vertexMem->push_back( p0 );
1953 ++i;
1954 Computation::FacetLatticeVertex * p1 = new Computation::FacetLatticeVertex( i->transformed( tf ), eyez, vertexMem->size( ) );
1955 vertexMem->push_back( p1 );
1956 ++i;
1957 Computation::FacetLatticeVertex * p2 = new Computation::FacetLatticeVertex( i->transformed( tf ), eyez, vertexMem->size( ) );
1958 vertexMem->push_back( p2 );
1960 Computation::FacetLatticeEdge * e0 = new Computation::FacetLatticeEdge( p0, p1 );
1961 edgeMem->push_back( e0 );
1962 Computation::FacetLatticeEdge * e1 = new Computation::FacetLatticeEdge( p1, p2 );
1963 edgeMem->push_back( e1 );
1964 Computation::FacetLatticeEdge * e2 = new Computation::FacetLatticeEdge( p2, p0 );
1965 edgeMem->push_back( e2 );
1967 jobQueue.push_back( new Computation::FacetLatticeTriangle( e0, e1, e2 ) );
1969 else
1971 ListType::const_iterator i = points_.begin( );
1972 Computation::FacetLatticeVertex * p0 = new Computation::FacetLatticeVertex( i->transformed( tf ), eyez, vertexMem->size( ) );
1973 vertexMem->push_back( p0 );
1974 ++i;
1975 Computation::FacetLatticeVertex * p1 = new Computation::FacetLatticeVertex( i->transformed( tf ), eyez, vertexMem->size( ) );
1976 vertexMem->push_back( p1 );
1977 ++i;
1979 Computation::FacetLatticeEdge * e0 = new Computation::FacetLatticeEdge( p0, p1 );
1980 edgeMem->push_back( e0 );
1982 for( ; i != points_.end( ); ++i )
1984 Computation::FacetLatticeVertex * p2 = new Computation::FacetLatticeVertex( i->transformed( tf ), eyez, vertexMem->size( ) );
1985 vertexMem->push_back( p2 );
1987 Computation::FacetLatticeEdge * e1 = new Computation::FacetLatticeEdge( p1, p2 );
1988 edgeMem->push_back( e1 );
1990 Computation::FacetLatticeEdge * e2 = new Computation::FacetLatticeEdge( p2, p0 );
1991 edgeMem->push_back( e2 );
1993 jobQueue.push_back( new Computation::FacetLatticeTriangle( e0, e1, e2 ) );
1995 p1 = p2;
1996 e0 = e2;
2000 while( ! jobQueue.empty( ) )
2002 const Computation::FacetLatticeTriangle * currentTriangle = jobQueue.front( );
2003 jobQueue.pop_front( );
2004 const Computation::FacetLatticeTriangle * child1 = 0;
2005 const Computation::FacetLatticeTriangle * child2 = 0;
2006 if( currentTriangle->fitsResolution( viewResolution, eyez, edgeMem, vertexMem, & child1, & child2 ) )
2008 lattice->push_back( currentTriangle );
2010 else
2012 jobQueue.push_back( child1 );
2013 jobQueue.push_back( child2 );
2014 delete currentTriangle;
2019 Computation::StrokedLine3D::StrokedLine3D( const Concrete::Coords3D & p0, const Concrete::Coords3D & p1, const RefCountPtr< const Kernel::GraphicsState > metaState )
2020 : p0_( p0 ), p1_( p1 ), metaState_( metaState )
2023 Computation::StrokedLine3D::~StrokedLine3D( )
2026 void
2027 Computation::StrokedLine3D::push_zBufLine( const Lang::Transform3D & tf, const Concrete::Length eyez, std::list< const Computation::ZBufLine * > * lineQueue ) const
2029 typedef Computation::ZBufLine::ZMap ZMapType;
2030 typedef const Bezier::PolyCoeffs< Concrete::Coords2D > ViewType;
2031 RefCountPtr< ViewType > nullView = RefCountPtr< ViewType >( NullPtr< ViewType >( ) );
2032 if( tf.isIdentity( ) )
2034 Concrete::Coords3D d = p1_ - p0_;
2035 RefCountPtr< const ZMapType > zMap( new ZMapType( p0_, d.directionNoFail( ), eyez ) );
2036 lineQueue->push_back( new Computation::ZBufLine( this, zMap, nullView, p0_.make2DAutomatic( eyez ), p1_.make2DAutomatic( eyez ) ) );
2038 else
2040 Concrete::Coords3D tfp0 = p0_.transformed( tf );
2041 Concrete::Coords3D tfp1 = p1_.transformed( tf );
2042 Concrete::Coords3D d = tfp1 - tfp0;
2043 RefCountPtr< const ZMapType > zMap( new ZMapType( tfp0, d.directionNoFail( ), eyez ) );
2044 lineQueue->push_back( new Computation::ZBufLine( this, zMap, nullView, tfp0.make2DAutomatic( eyez ), tfp1.make2DAutomatic( eyez ) ) );
2049 Computation::StrokedSplineSegment3D::StrokedSplineSegment3D( const Concrete::Coords3D & p0, const Concrete::Coords3D & p0front, const Concrete::Coords3D & p1rear, const Concrete::Coords3D & p1, const RefCountPtr< const Kernel::GraphicsState > metaState )
2050 : Computation::StrokedLine3D( p0, p1, metaState ),
2051 p0front_( p0front ),
2052 p1rear_( p1rear )
2055 Computation::StrokedSplineSegment3D::~StrokedSplineSegment3D( )
2058 void
2059 Computation::StrokedSplineSegment3D::push_zBufLine( const Lang::Transform3D & tf, const Concrete::Length eyez, std::list< const Computation::ZBufLine * > * lineQueue ) const
2061 typedef Computation::ZBufLine::ZMap ZMapType;
2062 typedef const Bezier::PolyCoeffs< Concrete::Coords2D > ViewType;
2063 if( tf.isIdentity( ) )
2065 Concrete::Coords3D d = p1_ - p0_;
2066 RefCountPtr< const ZMapType > zMap( new ZMapType( p0_, d.directionNoFail( ), eyez ) );
2067 RefCountPtr< ViewType > bezierView = RefCountPtr< ViewType >( new ViewType( Bezier::ControlPoints< Concrete::Coords2D >( p0_.make2DAutomatic( eyez ), p0front_.make2DAutomatic( eyez ), p1rear_.make2DAutomatic( eyez ), p1_.make2DAutomatic( eyez ) ) ) );
2068 lineQueue->push_back( new Computation::ZBufLine( this, zMap, bezierView, p0_.make2DAutomatic( eyez ), p1_.make2DAutomatic( eyez ) ) );
2070 else
2072 Concrete::Coords3D tfp0 = p0_.transformed( tf );
2073 Concrete::Coords3D tfp0front = p0front_.transformed( tf );
2074 Concrete::Coords3D tfp1rear = p1rear_.transformed( tf );
2075 Concrete::Coords3D tfp1 = p1_.transformed( tf );
2076 Concrete::Coords3D d = tfp1 - tfp0;
2077 RefCountPtr< const ZMapType > zMap( new ZMapType( tfp0, d.directionNoFail( ), eyez ) );
2078 RefCountPtr< ViewType > bezierView = RefCountPtr< ViewType >( new ViewType( Bezier::ControlPoints< Concrete::Coords2D >( tfp0.make2DAutomatic( eyez ), tfp0front.make2DAutomatic( eyez ), tfp1rear.make2DAutomatic( eyez ), tfp1.make2DAutomatic( eyez ) ) ) );
2079 lineQueue->push_back( new Computation::ZBufLine( this, zMap, bezierView, tfp0.make2DAutomatic( eyez ), tfp1.make2DAutomatic( eyez ) ) );
2084 Computation::FilledPolygon3D::FilledPolygon3D( const RefCountPtr< const Kernel::GraphicsState > & metaState,
2085 const Concrete::UnitFloatTriple & normal, Concrete::Length m,
2086 Concrete::Length tiebreaker )
2087 : Computation::PaintedPolygon3D( false, normal, m, tiebreaker ), metaState_( metaState ) // false means not single-sided.
2090 Computation::FilledPolygon3D::~FilledPolygon3D( )
2093 RefCountPtr< const Lang::PaintedPolygon2D >
2094 Computation::FilledPolygon3D::polygon_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const std::list< RefCountPtr< const Lang::LightSource > > & lights ) const
2096 // A FilledPolygon3D is characterized by that it doesn't take notice about the lights or orientation.
2098 Concrete::Length eyez = dyn->getEyeZ( );
2100 RefCountPtr< Lang::ElementaryPath2D > path = RefCountPtr< Lang::ElementaryPath2D >( new Lang::ElementaryPath2D( ) );
2101 path->close( );
2102 if( tf.isIdentity( ) )
2104 typedef typeof points_ ListType;
2105 for( ListType::const_iterator i = points_.begin( ); i != points_.end( ); ++i )
2107 path->push_back( new Concrete::PathPoint2D( i->make2D( eyez ) ) );
2110 else
2112 typedef typeof points_ ListType;
2113 for( ListType::const_iterator i = points_.begin( ); i != points_.end( ); ++i )
2115 path->push_back( new Concrete::PathPoint2D( i->transformed( tf ).make2D( eyez ) ) );
2119 return RefCountPtr< const Lang::PaintedPolygon2D >( new Lang::PaintedPolygon2D( metaState_, path ) );
2122 RefCountPtr< const Lang::Color >
2123 Computation::FilledPolygon3D::getColor( ) const
2125 return metaState_->nonStrokingColor_;
2128 void
2129 Computation::FilledPolygon3D::gcMark( Kernel::GCMarkedSet & marked )
2131 // const_cast< Kernel::GraphicsState * >( metaState_.getPtr( ) )->gcMark( marked );
2134 Computation::NullPolygon3D::NullPolygon3D( )
2135 : Computation::PaintedPolygon3D( true, Concrete::UnitFloatTriple( 1., 0., 0., 1. ), 0, Concrete::ZERO_LENGTH )
2138 Computation::NullPolygon3D::~NullPolygon3D( )
2141 RefCountPtr< const Lang::PaintedPolygon2D >
2142 Computation::NullPolygon3D::polygon_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const std::list< RefCountPtr< const Lang::LightSource > > & lights ) const
2144 throw Exceptions::InternalError( "NullPolygon3D::polygon_to2D was invoked!" );
2145 // return Lang::THE_NULL_POLYGON2D;
2148 RefCountPtr< const Lang::Color >
2149 Computation::NullPolygon3D::getColor( ) const
2151 return Lang::THE_BLACK;
2154 void
2155 Computation::NullPolygon3D::gcMark( Kernel::GCMarkedSet & marked )
2159 Lang::PaintedPolygon2D::PaintedPolygon2D( RefCountPtr< const Kernel::GraphicsState > metaState, RefCountPtr< const Lang::ElementaryPath2D > path )
2160 : Lang::PaintedPath2D( metaState, "E" ) // "E" for "extended fill"
2162 if( ! path->isClosed( ) )
2164 throw Exceptions::InternalError( "Attempt to create PaintedPolygon2D with non-closed path." );
2166 addSubPath( path );
2169 Lang::PaintedPolygon2D::~PaintedPolygon2D( )
2172 RefCountPtr< const Lang::Drawable2D >
2173 Lang::PaintedPolygon2D::clip( std::list< Computation::ZBufTriangle > * regions, const RefCountPtr< const Lang::PaintedPolygon2D > selfRef ) const
2175 if( regions->empty( ) )
2177 throw Exceptions::InternalError( "Empty list of regions in PaintedPolygon2D::clip. (This triangle should not have been generated at all!)" );
2179 if( regions->size( ) == 1 )
2181 const Computation::ZBufTriangle & theClip = regions->front( );
2182 const Lang::ElementaryPath2D & paintPath = * path_.front( );
2183 bool isInside = true;
2184 for( Lang::ElementaryPath2D::const_iterator i = paintPath.begin( ); i != paintPath.end( ); ++i )
2186 if( ! theClip.contains( *((*i)->mid_), Computation::theTrixelizeOverlapTol ) )
2188 isInside = false;
2189 break;
2192 if( isInside )
2194 return selfRef;
2198 // If we reach here, clipping shall be done
2199 Lang::Clipped2D * resPtr = new Lang::Clipped2D( selfRef, "W" );
2200 Lang::ZBuf::trianglesToPolys( regions, resPtr );
2201 RefCountPtr< const Lang::Clipped2D > res( resPtr );
2203 if( selfRef->isContainedIn( resPtr ) )
2205 return selfRef;
2208 const bool SHOW_POLYS = false;
2209 if( SHOW_POLYS )
2211 return res->debugPolys( );
2214 return res;
2218 bool
2219 Lang::PaintedPath2D::isContainedIn( const Lang::Clipped2D * clipping ) const
2221 if( ! clipping->isSingleConvexPoly( Computation::theTrixelizeOverlapTol ) )
2223 return false;
2226 typedef typeof path_ PathType;
2227 for( PathType::const_iterator subpath = path_.begin( ); subpath != path_.end( ); ++subpath )
2229 typedef typeof **subpath SubpathType;
2230 for( SubpathType::const_iterator i = (*subpath)->begin( ); i != (*subpath)->end( ); ++i )
2232 Concrete::PathPoint2D * pathPoint = *i;
2233 if( pathPoint->rear_ != pathPoint->mid_ ||
2234 pathPoint->front_ != pathPoint->mid_ )
2236 return false;
2238 if( ! clipping->convexPolyContains( *(pathPoint->mid_), Computation::theTrixelizeOverlapTol ) )
2240 return false;
2245 return true;
2249 Lang::PaintedPath3D::PaintedPath3D( RefCountPtr< const Kernel::GraphicsState > metaState,
2250 const char * paintCmd, Concrete::Length tiebreaker )
2251 : metaState_( metaState ), paintCmd_( paintCmd ), tiebreaker_( tiebreaker )
2254 Lang::PaintedPath3D::PaintedPath3D( RefCountPtr< const Kernel::GraphicsState > metaState,
2255 RefCountPtr< const Lang::ElementaryPath3D > path,
2256 const char * paintCmd, Concrete::Length tiebreaker )
2257 : metaState_( metaState ), paintCmd_( paintCmd ), tiebreaker_( tiebreaker )
2259 addSubPath( path );
2262 Lang::PaintedPath3D::PaintedPath3D( RefCountPtr< const Kernel::GraphicsState > metaState,
2263 RefCountPtr< const Lang::MultiPath3D > paths,
2264 const char * paintCmd, Concrete::Length tiebreaker )
2265 : metaState_( metaState ), paintCmd_( paintCmd ), tiebreaker_( tiebreaker )
2267 for( Lang::MultiPath3D::const_iterator i = paths->begin( ); i != paths->end( ); ++i )
2270 typedef const Lang::ElementaryPath3D ArgType;
2271 RefCountPtr< ArgType > subpath = (*i).down_cast< ArgType >( );
2272 if( subpath != NullPtr< ArgType >( ) )
2274 addSubPath( subpath );
2275 continue;
2280 typedef const Lang::CompositePath3D ArgType;
2281 ArgType * subpath = dynamic_cast< ArgType * >( (*i).getPtr( ) );
2282 if( subpath != 0 )
2284 addSubPath( subpath->getElementaryPath( ) );
2285 continue;
2288 throw Exceptions::InternalError( "Painting 3D path: Encountered a subpath of unexpected type" );
2292 Lang::PaintedPath3D::~PaintedPath3D( )
2295 RefCountPtr< const Lang::Class > Lang::PaintedPath3D::TypeID( new Lang::SystemFinalClass( strrefdup( "PaintedPath3D" ) ) );
2296 TYPEINFOIMPL( PaintedPath3D );
2298 void
2299 Lang::PaintedPath3D::addSubPath( RefCountPtr< const Lang::ElementaryPath3D > subpath )
2301 path_.push_back( subpath );
2304 RefCountPtr< const Lang::Drawable2D >
2305 Lang::PaintedPath3D::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2307 Concrete::Length eyez = dyn->getEyeZ( );
2309 RefCountPtr< const Lang::Group2D > res( Lang::THE_NULL2D );
2311 if( tf.isIdentity( ) )
2313 if( ! metaState_->dash_->isSolid( ) && *paintCmd_ == 'S' )
2315 for( std::list< RefCountPtr< const Lang::ElementaryPath3D > >::const_iterator i = path_.begin( ); i != path_.end( ); ++i )
2317 (*i)->dashifyIn2D( & res, eyez, metaState_ );
2320 else
2322 for( std::list< RefCountPtr< const Lang::ElementaryPath3D > >::const_iterator i = path_.begin( ); i != path_.end( ); ++i )
2324 res = RefCountPtr< const Lang::Group2D >( new Lang::GroupPair2D( RefCountPtr< const Lang::Drawable2D >( new Lang::PaintedPath2D( metaState_, (*i)->make2D( eyez ), paintCmd_ ) ),
2325 res,
2326 metaState_ ) );
2330 else
2332 if( ! metaState_->dash_->isSolid( ) && *paintCmd_ == 'S' )
2334 for( std::list< RefCountPtr< const Lang::ElementaryPath3D > >::const_iterator i = path_.begin( ); i != path_.end( ); ++i )
2336 (*i)->elementaryTransformed( tf )->dashifyIn2D( & res, eyez, metaState_ );
2339 else
2341 for( std::list< RefCountPtr< const Lang::ElementaryPath3D > >::const_iterator i = path_.begin( ); i != path_.end( ); ++i )
2343 res = RefCountPtr< const Lang::Group2D >( new Lang::GroupPair2D( RefCountPtr< const Lang::Drawable2D >( new Lang::PaintedPath2D( metaState_,
2344 (*i)->elementaryTransformed( tf )->make2D( eyez ),
2345 paintCmd_ ) ),
2346 res,
2347 metaState_ ) );
2351 return res;
2354 void
2355 Lang::PaintedPath3D::polygonize( std::list< RefCountPtr< Computation::PaintedPolygon3D > > * zBufPile, std::list< RefCountPtr< Computation::StrokedLine3D > > * linePile, const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2357 if( strcmp( paintCmd_, "S" ) == 0 )
2359 typedef typeof path_ ListType;
2360 for( ListType::const_iterator subi = path_.begin( ); subi != path_.end( ); ++subi )
2362 const RefCountPtr< const Lang::ElementaryPath3D > & theSub = *subi;
2364 if( theSub->size( ) < 2 )
2366 continue;
2369 typedef typeof *theSub SubListType;
2370 SubListType::const_iterator i = theSub->begin( );
2371 Concrete::Coords3D p0 = (*i)->mid_->transformed( tf );
2372 SubListType::const_iterator iLast = i;
2373 ++i;
2374 for( ; i != theSub->end( ); iLast = i, ++i )
2376 Concrete::Coords3D p1 = (*i)->mid_->transformed( tf );
2377 if( (*iLast)->front_ != (*iLast)->mid_ || (*i)->rear_ != (*i)->mid_ )
2379 linePile->push_back( RefCountPtr< Computation::StrokedSplineSegment3D >
2380 ( new Computation::StrokedSplineSegment3D( p0, (*iLast)->front_->transformed( tf ), (*i)->rear_->transformed( tf ), p1, metaState_ ) ) );
2382 else
2384 linePile->push_back( RefCountPtr< Computation::StrokedLine3D >
2385 ( new Computation::StrokedLine3D( p0, p1, metaState_ ) ) );
2387 p0 = p1;
2389 if( theSub->isClosed( ) )
2391 i = theSub->begin( );
2392 Concrete::Coords3D p1 = (*i)->mid_->transformed( tf );
2393 if( (*iLast)->front_ != (*iLast)->mid_ || (*i)->rear_ != (*i)->mid_ )
2395 linePile->push_back( RefCountPtr< Computation::StrokedSplineSegment3D >
2396 ( new Computation::StrokedSplineSegment3D( p0, (*iLast)->front_->transformed( tf ), (*i)->rear_->transformed( tf ), p1, metaState_ ) ) );
2398 else
2400 linePile->push_back( RefCountPtr< Computation::StrokedLine3D >
2401 ( new Computation::StrokedLine3D( p0, p1, metaState_ ) ) );
2406 return;
2409 if( ! ( strcmp( paintCmd_, "f" ) == 0 ||
2410 strcmp( paintCmd_, "B" ) == 0 ) )
2412 throw Exceptions::MiscellaneousRequirement( "Only stroked and (non-*) filled polygons can be put i a z buffer." );
2416 // When we get here we know that the paintCmd_ is "f" or "B", that is, a plain fill.
2418 // if( path.size( ) > 1 )
2419 // {
2420 // WARN_OR_THROW( Exceptionssha::MiscellanueousRequirement( "The result from triangularizing a composite path may not be what is expected." ) );
2421 // }
2423 typedef typeof path_ ListType;
2424 for( ListType::const_iterator subi = path_.begin( ); subi != path_.end( ); ++subi )
2426 const RefCountPtr< const Lang::ElementaryPath3D > & theSub = *subi;
2428 if( theSub->size( ) < 3 )
2430 continue;
2432 if( ! theSub->isClosed( ) )
2434 throw "Not closed";
2437 typedef typeof *theSub SubListType;
2439 RefCountPtr< Computation::FilledPolygon3D > newPoly = RefCountPtr< Computation::FilledPolygon3D >( NullPtr< Computation::FilledPolygon3D >( ) );
2441 // First we must compute an equation for the polygon!
2443 Concrete::Coords3D p0( 0, 0, 0 );
2444 Concrete::Coords3D p1( 0, 0, 0 );
2445 Concrete::Coords3D p2( 0, 0, 0 );
2446 theSub->getRepresentativePoints( tf, & p0, & p1, & p2 );
2450 Concrete::UnitFloatTriple normal = Concrete::crossDirection( p2 - p0, p1 - p0 );
2451 Concrete::Length m = Concrete::inner( normal, p0 );
2452 newPoly = RefCountPtr< Computation::FilledPolygon3D >( new Computation::FilledPolygon3D( metaState_, normal, m, tiebreaker_ ) );
2454 catch( const NonLocalExit::CrossDirectionOfParallel & ball )
2456 // This means that the crossDirection called failed because the vectors were parallel.
2457 // A polygon of lower dimension is invisible, so we may just continue
2458 continue;
2462 zBufPile->push_back( newPoly );
2464 for( SubListType::const_iterator i = theSub->begin( ); i != theSub->end( ); ++i )
2466 if( (*i)->front_ != (*i)->mid_ || (*i)->rear_ != (*i)->mid_ )
2468 throw "Corner has handle";
2470 newPoly->pushPoint( (*i)->mid_->transformed( tf ) );
2475 void
2476 Lang::PaintedPath3D::gcMark( Kernel::GCMarkedSet & marked )
2480 Lang::SingleSided3DGray::SingleSided3DGray( const RefCountPtr< const Lang::ElementaryPath3D > & points,
2481 const RefCountPtr< const Computation::FacetInterpolatorGray > & interpolator,
2482 bool singleSided,
2483 const Concrete::UnitFloatTriple & polygonUnitNormal,
2484 Concrete::Length m,
2485 Concrete::Length tiebreaker,
2486 Concrete::Length viewResolution,
2487 Computation::FacetShadeOrder shadeOrder )
2488 : points_( points ), interpolator_( interpolator ), singleSided_( singleSided ), polygonUnitNormal_( polygonUnitNormal ), m_( m ), tiebreaker_( tiebreaker ),
2489 viewResolution_( viewResolution ), shadeOrder_( shadeOrder )
2492 Lang::SingleSided3DGray::~SingleSided3DGray( )
2495 RefCountPtr< const Lang::Class > Lang::SingleSided3DGray::TypeID( new Lang::SystemFinalClass( strrefdup( "SingleSided3D(gray)" ) ) );
2496 TYPEINFOIMPL( SingleSided3DGray );
2498 RefCountPtr< const Lang::Drawable2D >
2499 Lang::SingleSided3DGray::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2501 throw Exceptions::NotImplemented( "SingleSided3DGray::typed_to2D; What light scene should be used?" );
2504 void
2505 Lang::SingleSided3DGray::polygonize( std::list< RefCountPtr< Computation::PaintedPolygon3D > > * zBufPile, std::list< RefCountPtr< Computation::StrokedLine3D > > * linePile, const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2507 Concrete::UnitFloatTriple Tnormal = tf.transformPlaneUnitNormal( polygonUnitNormal_ );
2509 double ax = fabs( polygonUnitNormal_.x_ );
2510 double ay = fabs( polygonUnitNormal_.y_ );
2511 double az = fabs( polygonUnitNormal_.z_ );
2512 Concrete::Coords3D x0( 0, 0, 0 );
2513 if( ax >= ay && ax >= az )
2515 x0 = Concrete::Coords3D( m_ / polygonUnitNormal_.x_, 0, 0 );
2517 else if( ay >= az )
2519 x0 = Concrete::Coords3D( 0, m_ / polygonUnitNormal_.y_, 0 );
2521 else
2523 x0 = Concrete::Coords3D( 0, 0, m_ / polygonUnitNormal_.z_ );
2525 Concrete::Length Tm = Concrete::inner( Tnormal, x0.transformed( tf ) );
2527 RefCountPtr< Computation::SingleSidedPolygon3DGray > res =
2528 RefCountPtr< Computation::SingleSidedPolygon3DGray >
2529 ( new Computation::SingleSidedPolygon3DGray( interpolator_->transformed( tf ),
2530 singleSided_,
2531 Tnormal,
2533 tiebreaker_,
2534 viewResolution_,
2535 shadeOrder_ ) );
2537 typedef Lang::ElementaryPath3D ListType;
2538 for( ListType::const_iterator i = points_->begin( ); i != points_->end( ); ++i )
2540 // The creator of *this is responsible for asserting that there are no handles at the pathpoints.
2541 res->pushPoint( (*i)->mid_->transformed( tf ) );
2545 zBufPile->push_back( res );
2548 void
2549 Lang::SingleSided3DGray::gcMark( Kernel::GCMarkedSet & marked )
2551 const_cast< Lang::ElementaryPath3D * >( points_.getPtr( ) )->gcMark( marked );
2552 const_cast< Computation::FacetInterpolatorGray * >( interpolator_.getPtr( ) )->gcMark( marked );
2556 Lang::SingleSided3DRGB::SingleSided3DRGB( const RefCountPtr< const Lang::ElementaryPath3D > & points,
2557 const RefCountPtr< const Computation::FacetInterpolatorRGB > & interpolator,
2558 bool singleSided,
2559 const Concrete::UnitFloatTriple & polygonUnitNormal,
2560 Concrete::Length m,
2561 Concrete::Length tiebreaker,
2562 Concrete::Length viewResolution,
2563 Computation::FacetShadeOrder shadeOrder )
2564 : points_( points ), interpolator_( interpolator ), singleSided_( singleSided ), polygonUnitNormal_( polygonUnitNormal ), m_( m ), tiebreaker_( tiebreaker ),
2565 viewResolution_( viewResolution ), shadeOrder_( shadeOrder )
2568 Lang::SingleSided3DRGB::~SingleSided3DRGB( )
2571 RefCountPtr< const Lang::Class > Lang::SingleSided3DRGB::TypeID( new Lang::SystemFinalClass( strrefdup( "SingleSided3D(RGB)" ) ) );
2572 TYPEINFOIMPL( SingleSided3DRGB );
2574 RefCountPtr< const Lang::Drawable2D >
2575 Lang::SingleSided3DRGB::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2577 throw Exceptions::NotImplemented( "SingleSided3DRGB::typed_to2D; What light scene should be used?" );
2580 void
2581 Lang::SingleSided3DRGB::polygonize( std::list< RefCountPtr< Computation::PaintedPolygon3D > > * zBufPile, std::list< RefCountPtr< Computation::StrokedLine3D > > * linePile, const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2583 Concrete::UnitFloatTriple Tnormal = tf.transformPlaneUnitNormal( polygonUnitNormal_ );
2585 double ax = fabs( polygonUnitNormal_.x_ );
2586 double ay = fabs( polygonUnitNormal_.y_ );
2587 double az = fabs( polygonUnitNormal_.z_ );
2588 Concrete::Coords3D x0( 0, 0, 0 );
2589 if( ax >= ay && ax >= az )
2591 x0 = Concrete::Coords3D( m_ / polygonUnitNormal_.x_, 0, 0 );
2593 else if( ay >= az )
2595 x0 = Concrete::Coords3D( 0, m_ / polygonUnitNormal_.y_, 0 );
2597 else
2599 x0 = Concrete::Coords3D( 0, 0, m_ / polygonUnitNormal_.z_ );
2601 Concrete::Length Tm = Concrete::inner( Tnormal, x0.transformed( tf ) );
2603 RefCountPtr< Computation::SingleSidedPolygon3DRGB > res =
2604 RefCountPtr< Computation::SingleSidedPolygon3DRGB >
2605 ( new Computation::SingleSidedPolygon3DRGB( interpolator_->transformed( tf ),
2606 singleSided_,
2607 Tnormal,
2609 tiebreaker_,
2610 viewResolution_,
2611 shadeOrder_ ) );
2613 typedef Lang::ElementaryPath3D ListType;
2614 for( ListType::const_iterator i = points_->begin( ); i != points_->end( ); ++i )
2616 // The creator of *this is responsible for asserting that there are no handles at the pathpoints.
2617 res->pushPoint( (*i)->mid_->transformed( tf ) );
2621 zBufPile->push_back( res );
2624 void
2625 Lang::SingleSided3DRGB::gcMark( Kernel::GCMarkedSet & marked )
2627 const_cast< Lang::ElementaryPath3D * >( points_.getPtr( ) )->gcMark( marked );
2628 const_cast< Computation::FacetInterpolatorRGB * >( interpolator_.getPtr( ) )->gcMark( marked );
2633 Lang::ZBuf::ZBuf( const RefCountPtr< std::list< RefCountPtr< Computation::PaintedPolygon3D > > > & pile, const RefCountPtr< std::list< RefCountPtr< Computation::StrokedLine3D > > > & linePile, const RefCountPtr< std::list< RefCountPtr< const Lang::LightSource > > > & lightPile, const RefCountPtr< const Kernel::GraphicsState > & metaState )
2634 : metaState_( metaState ), pile_( pile ), linePile_( linePile ), lightPile_( lightPile )
2637 Lang::ZBuf::~ZBuf( )
2640 void
2641 Lang::ZBuf::polygonize( std::list< RefCountPtr< Computation::PaintedPolygon3D > > * zBufPile, std::list< RefCountPtr< Computation::StrokedLine3D > > * linePile, const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2644 typedef typeof *pile_ ListType;
2645 for( ListType::const_iterator i = pile_->begin( ); i != pile_->end( ); ++i )
2647 zBufPile->push_back( *i );
2651 typedef typeof *linePile_ ListType;
2652 for( ListType::const_iterator i = linePile_->begin( ); i != linePile_->end( ); ++i )
2654 linePile->push_back( *i );
2659 void
2660 Lang::ZBuf::gcMark( Kernel::GCMarkedSet & marked )
2662 // At the time of writing, PaintedPolygon3D is not involved in gc.
2666 Lang::ZSorter::ZSorter( const RefCountPtr< std::list< RefCountPtr< Computation::PaintedPolygon3D > > > & pile, const RefCountPtr< std::list< RefCountPtr< Computation::StrokedLine3D > > > & linePile, const RefCountPtr< std::list< RefCountPtr< const Lang::LightSource > > > & lightPile, const RefCountPtr< const Kernel::GraphicsState > & metaState )
2667 : metaState_( metaState ), pile_( pile ), linePile_( linePile ), lightPile_( lightPile )
2670 Lang::ZSorter::~ZSorter( )
2673 void
2674 Lang::ZSorter::polygonize( std::list< RefCountPtr< Computation::PaintedPolygon3D > > * zBufPile, std::list< RefCountPtr< Computation::StrokedLine3D > > * linePile, const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2677 typedef typeof *pile_ ListType;
2678 for( ListType::const_iterator i = pile_->begin( ); i != pile_->end( ); ++i )
2680 zBufPile->push_back( *i );
2684 typedef typeof *linePile_ ListType;
2685 for( ListType::const_iterator i = linePile_->begin( ); i != linePile_->end( ); ++i )
2687 linePile->push_back( *i );
2692 void
2693 Lang::ZSorter::gcMark( Kernel::GCMarkedSet & marked )
2695 // At the time of writing, PaintedPolygon3D is not involved in gc.
2699 Lang::Transformed3D::Transformed3D( RefCountPtr< const Lang::Drawable3D > element, const Lang::Transform3D & mytf )
2700 : mytf_( mytf ), element_( element )
2703 Lang::Transformed3D::~Transformed3D( )
2706 RefCountPtr< const Lang::Drawable2D >
2707 Lang::Transformed3D::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2709 return element_->typed_to2D( dyn, Lang::Transform3D( tf, mytf_ ), element_ );
2712 void
2713 Lang::Transformed3D::polygonize( std::list< RefCountPtr< Computation::PaintedPolygon3D > > * zBufPile, std::list< RefCountPtr< Computation::StrokedLine3D > > * linePile, const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2715 element_->polygonize( zBufPile, linePile, dyn, Lang::Transform3D( tf, mytf_ ), element_ );
2718 void
2719 Lang::Transformed3D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
2721 element_->findTags( dst, dyn, key, Lang::Transform3D( tf, mytf_ ) );
2724 bool
2725 Lang::Transformed3D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
2727 return
2728 element_->findOneTag( evalState, key, Lang::Transform3D( tf, mytf_ ) );
2731 void
2732 Lang::Transformed3D::gcMark( Kernel::GCMarkedSet & marked )
2734 const_cast< Lang::Drawable3D * >( element_.getPtr( ) )->gcMark( marked );
2737 Lang::Text::Text( const RefCountPtr< const Kernel::TextState > & textState, const RefCountPtr< const std::list< RefCountPtr< const Lang::TextOperation > > > & elements, const RefCountPtr< const Lang::ElementaryPath2D > & mybbox )
2738 : textState_( textState ), elements_( elements ), mybbox_( mybbox )
2741 Lang::Text::~Text( )
2744 void
2745 Lang::Text::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
2747 if( textState_->font_->outline( ) )
2749 if( ( pdfState->text_.knockout_ & Kernel::TextState::KNOCKOUT_UNDEFINED_BIT ) != 0 &&
2750 ( pdfState->text_.knockout_ & Kernel::TextState::KNOCKOUT_FLAG_BIT ) == 0 )
2752 Kernel::TextState newState;
2753 newState.knockout_ = 0; /* Clear the KNOCKOUT_FLAG_BIT. */
2754 Helpers::newTransparencyGroup( RefCountPtr< const Lang::Drawable2D >
2755 ( new Lang::Text( RefCountPtr< const Kernel::TextState >( new Kernel::TextState( newState, *textState_ ) ),
2756 elements_,
2757 mybbox_ ) ),
2758 false, /* The group shall be isolated. */
2759 false, /* Not knockout. */
2760 Lang::THE_INHERITED_COLOR_SPACE )->shipout( os, pdfState, tf );
2762 else
2764 Lang::Transform2D textMatrix( 0, 0, 0, 0, Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH );
2765 Lang::Transform2D lineMatrix( 0, 0, 0, 0, Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH );
2766 lineMatrix.replaceBy( Lang::THE_2D_IDENTITY );
2767 textMatrix.replaceBy( lineMatrix );
2768 typedef typeof *elements_ ListType;
2769 for( ListType::const_iterator i = elements_->begin( ); i != elements_->end( ); ++i )
2771 (*i)->shipout_outlined( os, pdfState, tf, & textMatrix, & lineMatrix, 0 ); /* 0 means that this is a painting operation, not clipping. */
2775 else
2777 pdfState->resources_->requireProcedureSet( SimplePDF::PDF_Resources::PROC_SET_TEXT );
2779 os << "BT" << std::endl ;
2780 if( ! tf.isIdentity( ) )
2782 tf.shipout( os );
2783 os << " Tm" << std::endl ;
2786 pdfState->text_.synchKnockout( os, textState_.getPtr( ), pdfState->resources_.getPtr( ) );
2788 typedef typeof *elements_ ListType;
2789 for( ListType::const_iterator i = elements_->begin( ); i != elements_->end( ); ++i )
2791 (*i)->shipout( os, pdfState, tf );
2793 os << "ET" << std::endl ;
2797 void
2798 Lang::Text::shipout_clip( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf, const RefCountPtr< const Lang::Drawable2D > & content ) const
2800 if( textState_->font_->outline( ) )
2802 Lang::Transform2D textMatrix( 0, 0, 0, 0, Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH );
2803 Lang::Transform2D lineMatrix( 0, 0, 0, 0, Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH );
2804 textMatrix.replaceBy( Lang::THE_2D_IDENTITY );
2805 lineMatrix.replaceBy( Lang::THE_2D_IDENTITY );
2806 if( ( pdfState->text_.knockout_ & Kernel::TextState::KNOCKOUT_UNDEFINED_BIT ) != 0 &&
2807 ( pdfState->text_.knockout_ & Kernel::TextState::KNOCKOUT_FLAG_BIT ) == 0 )
2809 /* If the text knockout mode is false (by default, it is true), we emulate the effect by creating a temporary
2810 * object with default knockout mode inside a transparency group with the correct knockout mode, and then
2811 * shipout that object instead.
2813 Kernel::TextState newState;
2814 newState.knockout_ = 0; /* Clear the KNOCKOUT_FLAG_BIT. */
2815 Helpers::newTransparencyGroup( RefCountPtr< const Lang::Drawable2D >
2816 ( new Lang::TextMasked2D( content,
2817 RefCountPtr< const Lang::Text >
2818 ( new Lang::Text( RefCountPtr< const Kernel::TextState >( new Kernel::TextState( newState, *textState_ ) ),
2819 elements_,
2820 mybbox_ ) ) ) ),
2821 false, /* The group shall be isolated. */
2822 false, /* Not knockout. */
2823 Lang::THE_INHERITED_COLOR_SPACE )->shipout( os, pdfState, tf );
2825 else
2827 RefCountPtr< const Lang::ElementaryPath2D > theBBox = content->bbox( Lang::Drawable2D::BOUNDING )->elementaryTransformed( tf );
2828 Concrete::Coords2D llcorner( 0, 0 );
2829 Concrete::Coords2D urcorner( 0, 0 );
2830 if( ! theBBox->boundingRectangle( & llcorner, & urcorner ) )
2832 throw Exceptions::InternalError( "Text mask: The content has no bounding box!" );
2835 RefCountPtr< SimplePDF::PDF_Stream_out > form;
2836 RefCountPtr< SimplePDF::PDF_Object > indirection = SimplePDF::indirect( form, & Kernel::theIndirectObjectCount );
2838 RefCountPtr< SimplePDF::PDF_Resources > resources;
2839 (*form)[ "Resources" ] = SimplePDF::indirect( resources, & Kernel::theIndirectObjectCount );
2841 (*form)[ "Subtype" ] = SimplePDF::newName( "Form" );
2842 (*form)[ "FormType" ] = SimplePDF::newInt( 1 );
2843 (*form)[ "BBox" ] = RefCountPtr< SimplePDF::PDF_Vector >( new SimplePDF::PDF_Vector( llcorner.x_.offtype< 1, 0 >( ), llcorner.y_.offtype< 1, 0 >( ),
2844 urcorner.x_.offtype< 1, 0 >( ), urcorner.y_.offtype< 1, 0 >( ) ) );
2846 Kernel::PageContentStates contentState( resources );
2847 content->shipout( form->data, & contentState, tf );
2849 const SimplePDF::PDF_Name & xoName = pdfState->resources_->nameofXObject( indirection );
2850 typedef typeof *elements_ ListType;
2851 for( ListType::const_iterator i = elements_->begin( ); i != elements_->end( ); ++i )
2853 (*i)->shipout_outlined( os, pdfState, tf, & textMatrix, & lineMatrix, & xoName ); /* Passing xoName means "clip". */
2857 else
2859 Kernel::Auto_qQ auto_qQ( & pdfState->graphics_, & pdfState->text_, os );
2860 if( ! tf.isIdentity( ) )
2862 tf.shipout( os );
2863 os << " cm" << std::endl ;
2866 pdfState->resources_->requireProcedureSet( SimplePDF::PDF_Resources::PROC_SET_TEXT );
2868 os << "BT" << std::endl ;
2870 pdfState->text_.synchKnockout( os, textState_.getPtr( ), pdfState->resources_.getPtr( ) );
2872 typedef typeof *elements_ ListType;
2873 for( ListType::const_iterator i = elements_->begin( ); i != elements_->end( ); ++i )
2875 (*i)->shipout( os, pdfState, THE_2D_IDENTITY, true ); /* true means "clip" */
2877 os << "ET" << std::endl ;
2879 content->shipout( os, pdfState, THE_2D_IDENTITY );
2883 RefCountPtr< const Lang::ElementaryPath2D >
2884 Lang::Text::bbox( Lang::Drawable2D::BoxType boxType ) const
2886 return mybbox_;
2889 void
2890 Lang::Text::gcMark( Kernel::GCMarkedSet & marked )
2892 typedef typeof *elements_ ListType;
2893 for( ListType::const_iterator i = elements_->begin( ); i != elements_->end( ); ++i )
2895 const_cast< Lang::TextOperation * >( i->getPtr( ) )->gcMark( marked );
2902 RefCountPtr< const Lang::TransparencyGroup >
2903 Helpers::newSolidTransparencyGroup( const RefCountPtr< const Lang::Drawable2D > & obj2, const RefCountPtr< const Lang::Drawable2D > & obj1 )
2905 return Helpers::newTransparencyGroup( Helpers::newGroup2D( Kernel::THE_DEFAULT_STATE, obj2, obj1 ),
2906 true,
2907 true,
2908 Lang::THE_INHERITED_COLOR_SPACE );
2911 RefCountPtr< const Lang::TransparencyGroup >
2912 Helpers::newSolidTransparencyGroup( const RefCountPtr< const Lang::Drawable2D > & obj3, const RefCountPtr< const Lang::Drawable2D > & obj2, const RefCountPtr< const Lang::Drawable2D > & obj1 )
2914 return Helpers::newTransparencyGroup( Helpers::newGroup2D( Kernel::THE_DEFAULT_STATE, obj3, obj2, obj1 ),
2915 true,
2916 true,
2917 Lang::THE_INHERITED_COLOR_SPACE );
2921 bool
2922 Computation::operator < ( const Computation::UndirectedEdge & p1, const Computation::UndirectedEdge & p2 )
2924 if( p1.low( ) < p2.low( ) )
2926 return true;
2928 if( p1.low( ) > p2.low( ) )
2930 return false;
2932 return p1.high( ) < p2.high( );