Updating the changelog in the VERSION file, and version_sync.
[shapes.git] / source / drawabletypes.cc
blobf609a6c08b2694a7c27c03ed0d9e7362be0b1a60
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 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"
36 #include <ctype.h>
37 #include <list>
38 #include <algorithm>
40 using namespace Shapes;
43 Lang::Drawable2D::Drawable2D( )
44 { }
46 Lang::Drawable2D::~Drawable2D( )
47 { }
49 RefCountPtr< const Lang::Transformed2D >
50 Lang::Drawable2D::typed_transformed( const Lang::Transform2D & tf, const RefCountPtr< const Lang::Drawable2D > & self ) const
52 return RefCountPtr< const Lang::Transformed2D >( new Lang::Transformed2D( self, tf ) );
55 RefCountPtr< const Lang::Geometric2D >
56 Lang::Drawable2D::transformed( const Lang::Transform2D & tf, const RefCountPtr< const Lang::Geometric2D > & self ) const
58 return typed_transformed( tf, self.down_cast< const Lang::Drawable2D >( ) );
61 RefCountPtr< const Lang::Geometric3D >
62 Lang::Drawable2D::to3D( const RefCountPtr< const Lang::Geometric2D > & self ) const
64 typedef const Lang::Drawable2D SelfType;
65 RefCountPtr< SelfType > typedSelf = self.down_cast< SelfType >( );
66 if( typedSelf == NullPtr< SelfType >( ) )
68 throw Exceptions::InternalError( "The self-value passed to Drawable2D::to3D was of bad type." );
70 return RefCountPtr< const Lang::Geometric3D >( new Lang::Drawable2Din3D( typedSelf ) );
73 void
74 Lang::Drawable2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
76 // Not overloading this methods means that there are no tagged objects within this.
79 bool
80 Lang::Drawable2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
82 // Not overloading this methods means that there are no tagged objects within this.
83 return false;
86 void
87 Lang::Drawable2D::gcMark( Kernel::GCMarkedSet & marked )
88 { }
90 RefCountPtr< const Lang::Class > Lang::Drawable2D::TypeID = NullPtr< const Lang::Class >( ); /* The value is set in main */
91 TYPEINFOIMPL( Drawable2D );
92 DISPATCHIMPL( Drawable2D );
95 Lang::Group2D::Group2D( )
96 { }
98 Lang::Group2D::~Group2D( )
99 { }
101 RefCountPtr< const Lang::Class > Lang::Group2D::TypeID( new Lang::SystemFinalClass( strrefdup( "Group2D" ) ) );
102 TYPEINFOIMPL( Group2D );
105 RefCountPtr< const Lang::Group2D >
106 Helpers::newGroup2D( const RefCountPtr< const Kernel::GraphicsState > & metaState, const RefCountPtr< const Lang::Drawable2D > & obj2, const RefCountPtr< const Lang::Drawable2D > & obj1 )
108 RefCountPtr< const Lang::Group2D > res = Lang::THE_NULL2D;
109 res = RefCountPtr< const Lang::GroupPair2D >( new Lang::GroupPair2D( obj1,
110 res,
111 metaState ) );
112 res = RefCountPtr< const Lang::GroupPair2D >( new Lang::GroupPair2D( obj2,
113 res,
114 metaState ) );
115 return res;
118 RefCountPtr< const Lang::Group2D >
119 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 )
121 RefCountPtr< const Lang::Group2D > res = Lang::THE_NULL2D;
122 res = RefCountPtr< const Lang::GroupPair2D >( new Lang::GroupPair2D( obj1,
123 res,
124 metaState ) );
125 res = RefCountPtr< const Lang::GroupPair2D >( new Lang::GroupPair2D( obj2,
126 res,
127 metaState ) );
128 res = RefCountPtr< const Lang::GroupPair2D >( new Lang::GroupPair2D( obj3,
129 res,
130 metaState ) );
131 return res;
135 Lang::GroupPair2D::GroupPair2D( RefCountPtr< const Lang::Drawable2D > car, RefCountPtr< const Lang::Group2D > cdr, const RefCountPtr< const Kernel::GraphicsState > & metaState )
136 : metaState_( metaState ), car_( car ), cdr_( cdr )
139 Lang::GroupPair2D::~GroupPair2D( )
142 bool
143 Lang::GroupPair2D::isNull( ) const
145 return false;
148 void
149 Lang::GroupPair2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
151 cdr_->shipout( os, pdfState, tf );
152 if( pdfState->graphics_.synchBlend( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) ) )
154 os << std::endl ;
156 car_->shipout( os, pdfState, tf );
159 RefCountPtr< const Lang::ElementaryPath2D >
160 Lang::GroupPair2D::bbox( Lang::Drawable2D::BoxType boxType ) const
162 RefCountPtr< const Lang::ElementaryPath2D > carbbox = car_->bbox( boxType );
163 RefCountPtr< const Lang::ElementaryPath2D > cdrbbox = cdr_->bbox( boxType );
165 if( cdrbbox->empty( ) )
167 return carbbox;
170 Concrete::Length xmin = Concrete::HUGE_LENGTH;
171 Concrete::Length xmax = -Concrete::HUGE_LENGTH;
172 Concrete::Length ymin = Concrete::HUGE_LENGTH;
173 Concrete::Length ymax = -Concrete::HUGE_LENGTH;
175 typedef typeof *carbbox PathType;
176 for( PathType::const_iterator i = carbbox->begin( ); i != carbbox->end( ); ++i )
178 Concrete::Length x = (*i)->mid_->x_;
179 xmin = std::min( xmin, x );
180 xmax = std::max( xmax, x );
182 Concrete::Length y = (*i)->mid_->y_;
183 ymin = std::min( ymin, y );
184 ymax = std::max( ymax, y );
187 for( PathType::const_iterator i = cdrbbox->begin( ); i != cdrbbox->end( ); ++i )
189 Concrete::Length x = (*i)->mid_->x_;
190 xmin = std::min( xmin, x );
191 xmax = std::max( xmax, x );
193 Concrete::Length y = (*i)->mid_->y_;
194 ymin = std::min( ymin, y );
195 ymax = std::max( ymax, y );
198 Lang::ElementaryPath2D * res = new Lang::ElementaryPath2D;
200 if( xmin < Concrete::HUGE_LENGTH )
202 res->push_back( new Concrete::PathPoint2D( xmin, ymin ) );
203 res->push_back( new Concrete::PathPoint2D( xmin, ymax ) );
204 res->push_back( new Concrete::PathPoint2D( xmax, ymax ) );
205 res->push_back( new Concrete::PathPoint2D( xmax, ymin ) );
206 res->close( );
209 return RefCountPtr< const Lang::ElementaryPath2D >( res );
213 void
214 Lang::GroupPair2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
216 /* Note the order! Objects are added on the car side of a group being built, so the car side is the "latter".
218 cdr_->findTags( dst, dyn, key, tf );
219 car_->findTags( dst, dyn, key, tf );
222 bool
223 Lang::GroupPair2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
225 return
226 cdr_->findOneTag( evalState, key, tf ) ||
227 car_->findOneTag( evalState, key, tf );
230 RefCountPtr< const Lang::Group2D >
231 Lang::GroupPair2D::removeShallow( Lang::Symbol::KeyType key ) const
234 typedef const Lang::Tagged2D TaggedType;
235 TaggedType * t = dynamic_cast< TaggedType * >( car_.getPtr( ) );
236 if( t != 0 && t->key( ) == key )
238 return cdr_->removeShallow( key );
241 return RefCountPtr< const Lang::Group2D >( new Lang::GroupPair2D( car_, cdr_->removeShallow( key ), metaState_ ) );
244 void
245 Lang::GroupPair2D::gcMark( Kernel::GCMarkedSet & marked )
247 const_cast< Lang::Drawable2D * >( car_.getPtr( ) )->gcMark( marked );
248 const_cast< Lang::Group2D * >( cdr_.getPtr( ) )->gcMark( marked );
252 Lang::GroupNull2D::GroupNull2D( )
255 Lang::GroupNull2D::~GroupNull2D( )
258 bool
259 Lang::GroupNull2D::isNull( ) const
261 return true;
264 RefCountPtr< const Lang::Group2D >
265 Lang::GroupNull2D::removeShallow( Lang::Symbol::KeyType key ) const
267 return Lang::THE_NULL2D;
270 void
271 Lang::GroupNull2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
274 RefCountPtr< const Lang::ElementaryPath2D >
275 Lang::GroupNull2D::bbox( Lang::Drawable2D::BoxType boxType ) const
277 return Lang::THE_EMPTYPATH2D;
281 Lang::XObject::XObject( const RefCountPtr< SimplePDF::PDF_Object > & resource, const RefCountPtr< const Lang::ElementaryPath2D > & boundingbox )
282 : metaState_( Kernel::THE_NO_STATE ), resource_( resource ), boundingbox_( boundingbox ), bleedbox_( boundingbox )
285 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 )
286 : metaState_( metaState ), resource_( resource ), boundingbox_( boundingbox ), bleedbox_( bleedbox )
289 Lang::XObject::~XObject( )
292 void
293 Lang::XObject::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
295 Kernel::Auto_qQ auto_qQ( & pdfState->graphics_, & pdfState->text_, os, false );
296 if( ! tf.isIdentity( ) )
298 auto_qQ.activate( );
299 tf.shipout( os );
300 os << " cm" << std::endl ;
302 if( metaState_ != Kernel::THE_NO_STATE )
304 pdfState->graphics_.synchForNonStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
306 os << pdfState->resources_->nameofXObject( resource_ ) << " Do" << std::endl ;
309 RefCountPtr< SimplePDF::PDF_Object >
310 Lang::XObject::getResource( ) const
312 return resource_;
315 RefCountPtr< const Lang::ElementaryPath2D >
316 Lang::XObject::bbox( Lang::Drawable2D::BoxType boxType ) const
318 switch( boxType )
320 case Lang::Drawable2D::BOUNDING:
321 return boundingbox_;
322 case Lang::Drawable2D::BLEED:
323 return bleedbox_;
325 throw Exceptions::InternalError( "Lang::XObject::bbox: boxType out of range." );
328 RefCountPtr< const Lang::XObject >
329 Lang::XObject::cloneWithState( const RefCountPtr< const Kernel::GraphicsState > & metaState, Concrete::Length bleedMargin ) const
331 Concrete::Coords2D llcorner( 0, 0 );
332 Concrete::Coords2D urcorner( 0, 0 );
333 boundingbox_->boundingRectangle( & llcorner, & urcorner );
335 Lang::ElementaryPath2D * bleedBox = new Lang::ElementaryPath2D;
337 bleedBox->push_back( new Concrete::PathPoint2D( llcorner.x_ - bleedMargin, llcorner.y_ - bleedMargin ) );
338 bleedBox->push_back( new Concrete::PathPoint2D( urcorner.x_ + bleedMargin, llcorner.y_ - bleedMargin ) );
339 bleedBox->push_back( new Concrete::PathPoint2D( urcorner.x_ + bleedMargin, urcorner.y_ + bleedMargin ) );
340 bleedBox->push_back( new Concrete::PathPoint2D( llcorner.x_ - bleedMargin, urcorner.y_ + bleedMargin ) );
341 bleedBox->close( );
343 return RefCountPtr< const Lang::XObject >( new Lang::XObject( resource_, boundingbox_, RefCountPtr< const Lang::ElementaryPath2D >( bleedBox ), metaState ) );
346 void
347 Lang::XObject::setDebugStr( const std::string & debugStr )
349 debugStr_ = debugStr;
352 const std::string &
353 Lang::XObject::getDebugStr( ) const
355 return debugStr_;
358 void
359 Lang::XObject::show( std::ostream & os ) const
361 os << "XObject (" << getDebugStr( ) << ")" ;
364 void
365 Lang::XObject::gcMark( Kernel::GCMarkedSet & marked )
367 // At the time of writing, there is nothing to propagate to.
371 Lang::TransparencyGroup::TransparencyGroup( const RefCountPtr< SimplePDF::PDF_Indirect_out > & indirection, RefCountPtr< const Lang::ElementaryPath2D > mybbox, const RefCountPtr< const Lang::ColorSpace > & colorSpace )
372 : Lang::XObject( indirection, mybbox ), colorSpace_( colorSpace ), indirection_( indirection )
375 Lang::TransparencyGroup::~TransparencyGroup( )
378 RefCountPtr< const Lang::ColorSpace >
379 Lang::TransparencyGroup::colorSpace( ) const
381 return colorSpace_;
384 RefCountPtr< SimplePDF::PDF_Indirect_out >
385 Lang::TransparencyGroup::getPDF_Object( ) const
387 return indirection_.unconst_cast< SimplePDF::PDF_Indirect_out >( );
390 RefCountPtr< const Lang::TransparencyGroup >
391 Helpers::newTransparencyGroup( const RefCountPtr< const Lang::Group2D > & content, bool isolated, bool knockout, const RefCountPtr< const Lang::ColorSpace > & blendSpace )
393 RefCountPtr< const Lang::ElementaryPath2D > theBBox = content->bbox( Lang::Drawable2D::BOUNDING );
394 Concrete::Coords2D llcorner( 0, 0 );
395 Concrete::Coords2D urcorner( 0, 0 );
396 if( ! theBBox->boundingRectangle( & llcorner, & urcorner ) )
398 throw Exceptions::InternalError( "newTransparencyGroup: The object has no bounding box!" );
401 using namespace Shapes;
403 RefCountPtr< SimplePDF::PDF_Stream_out > form;
405 (*form)[ "Subtype" ] = SimplePDF::newName( "Form" );
406 (*form)[ "FormType" ] = SimplePDF::newInt( 1 );
407 (*form)[ "BBox" ] = RefCountPtr< SimplePDF::PDF_Vector >( new SimplePDF::PDF_Vector( llcorner.x_.offtype< 1, 0 >( ), llcorner.y_.offtype< 1, 0 >( ),
408 urcorner.x_.offtype< 1, 0 >( ), urcorner.y_.offtype< 1, 0 >( ) ) );
409 RefCountPtr< SimplePDF::PDF_Resources > resources;
410 (*form)[ "Resources" ] = SimplePDF::indirect( resources, & Kernel::theIndirectObjectCount );
412 if( ! Kernel::allowTransparency )
414 /* OK, fine. */
416 else if( ! Kernel::the_PDF_version.greaterOrEqual( SimplePDF::PDF_Version::PDF_1_4 ) )
418 Kernel::the_PDF_version.message( SimplePDF::PDF_Version::PDF_1_4, "A transparency group was replaced by a plain XObject." );
420 else
422 RefCountPtr< SimplePDF::PDF_Dictionary > groupDic;
423 (*form)[ "Group" ] = groupDic;
424 (*groupDic)[ "S" ] = SimplePDF::newName( "Transparency" );
425 if( ! blendSpace->isInherent( ) )
427 (*groupDic)[ "CS" ] = blendSpace->name( );
429 if( isolated )
431 (*groupDic)[ "I" ] = SimplePDF::newBoolean( true );
433 if( knockout )
435 (*groupDic)[ "K" ] = SimplePDF::newBoolean( true );
439 /* There's a possibility of adding a transformation matrix entry in the dictionary here, but it is not used, not even
440 * for transformed drawables.
442 // (*markForm)[ "Matrix" ] = RefCountPtr<PDF_Object>( new PDF_Vector( 1, 0, 0, 1, -30, -30 ) );
444 Kernel::PageContentStates pdfState( resources );
445 content->shipout( form->data, & pdfState, Lang::Transform2D( 1, 0, 0, 1, Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH ) );
447 Lang::TransparencyGroup * res = new Lang::TransparencyGroup( SimplePDF::indirect( form, & Kernel::theIndirectObjectCount ),
448 content->bbox( Lang::Drawable2D::BOUNDING ),
449 blendSpace );
450 res->setDebugStr( "transparency group" );
451 return RefCountPtr< const Lang::TransparencyGroup >( res );
457 Lang::PaintedPath2D::PaintedPath2D( const RefCountPtr< const Kernel::GraphicsState > & metaState,
458 const char * paintCmd )
459 : metaState_( metaState ), paintCmd_( paintCmd )
462 Lang::PaintedPath2D::PaintedPath2D( const RefCountPtr< const Kernel::GraphicsState > & metaState,
463 RefCountPtr< const Lang::ElementaryPath2D > path,
464 const char * paintCmd )
465 : metaState_( metaState ), paintCmd_( paintCmd )
467 addSubPath( path );
470 Lang::PaintedPath2D::PaintedPath2D( const RefCountPtr< const Kernel::GraphicsState > & metaState,
471 RefCountPtr< const Lang::MultiPath2D > paths,
472 const char * paintCmd )
473 : metaState_( metaState ), paintCmd_( paintCmd )
475 for( Lang::MultiPath2D::const_iterator i = paths->begin( ); i != paths->end( ); ++i )
478 typedef const Lang::ElementaryPath2D ArgType;
479 RefCountPtr< ArgType > subpath = (*i).down_cast< ArgType >( );
480 if( subpath != NullPtr< ArgType >( ) )
482 addSubPath( subpath );
483 continue;
488 typedef const Lang::CompositePath2D ArgType;
489 ArgType * subpath = dynamic_cast< ArgType * >( (*i).getPtr( ) );
490 if( subpath != 0 )
492 addSubPath( subpath->getElementaryPath( ) );
493 continue;
496 throw Exceptions::InternalError( "Painting 2D path: Encountered a subpath of unexpected type" );
500 Lang::PaintedPath2D::~PaintedPath2D( )
503 RefCountPtr< const Lang::Class > Lang::PaintedPath2D::TypeID( new Lang::SystemFinalClass( strrefdup( "PaintedPath2D" ) ) );
504 TYPEINFOIMPL( PaintedPath2D );
506 void
507 Lang::PaintedPath2D::addSubPath( RefCountPtr< const Lang::ElementaryPath2D > subpath )
509 path_.push_back( subpath );
512 void
513 Lang::PaintedPath2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
515 /* Transforming the path by tf is not good enough, since that does not transform softmasks etc.
518 char pdfCmd[4];
519 strcpy( pdfCmd, paintCmd_ );
521 Kernel::Auto_qQ auto_qQ( & pdfState->graphics_, & pdfState->text_, os, false );
522 if( ! tf.isIdentity( ) )
524 auto_qQ.activate( );
525 tf.shipout( os );
526 os << " cm" << std::endl ;
528 if( strcmp( paintCmd_, "S" ) == 0 )
530 pdfState->graphics_.synchForStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
532 else if( strcmp( paintCmd_, "f" ) == 0 ||
533 strcmp( paintCmd_, "f*" ) == 0 )
535 pdfState->graphics_.synchForNonStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
537 else if( strcmp( paintCmd_, "B" ) == 0 ||
538 strcmp( paintCmd_, "B*" ) == 0 ||
539 strcmp( paintCmd_, "b" ) == 0 ||
540 strcmp( paintCmd_, "b*" ) == 0 )
542 pdfState->graphics_.synchForNonStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
543 pdfState->graphics_.synchForStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
545 else if( strcmp( paintCmd_, "E" ) == 0 ||
546 strcmp( paintCmd_, "E*" ) == 0 ||
547 strcmp( paintCmd_, "e" ) == 0 ||
548 strcmp( paintCmd_, "e*" ) == 0 )
550 pdfCmd[0] += 'B' - 'E';
551 // Note that this is my own interpretation; usually, the stroke is made with the stroking color,
552 // but I use this to make filled regions just a little bit bigger, and then it is the nonstroking
553 // color that shall be applied to the stroke as well.
554 pdfState->graphics_.synchForNonStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
555 pdfState->graphics_.synchStrokingColorWithNonStrokingColor( os, pdfState->resources_.getPtr( ), Concrete::ZERO_LENGTH );
557 else
559 throw Exceptions::InternalError( "Unexpected paintCmd in PaintedPath2D::shipout" );
562 typedef typeof path_ ListType;
563 for( ListType::const_iterator i = path_.begin( ); i != path_.end( ); ++i )
565 (*i)->writePath( os );
567 os << " " << pdfCmd << std::endl ;
570 RefCountPtr< const Lang::ElementaryPath2D >
571 Lang::PaintedPath2D::bbox( Lang::Drawable2D::BoxType boxType ) const
573 if( path_.empty( ) )
575 return RefCountPtr< const Lang::ElementaryPath2D >( new Lang::ElementaryPath2D );
578 Concrete::Length xmin = Concrete::HUGE_LENGTH;
579 Concrete::Length xmax = -Concrete::HUGE_LENGTH;
580 Concrete::Length ymin = Concrete::HUGE_LENGTH;
581 Concrete::Length ymax = -Concrete::HUGE_LENGTH;
583 Concrete::Coords2D llcorner( 0, 0 ); /* Temporary variables to be used in the loop below. */
584 Concrete::Coords2D urcorner( 0, 0 );
586 typedef typeof path_ PathType;
587 for( PathType::const_iterator j = path_.begin( ); j != path_.end( ); ++j )
589 if( (*j)->boundingRectangle( & llcorner, & urcorner ) )
591 /* non-empty path */
592 xmin = std::min( xmin, llcorner.x_ );
593 xmax = std::max( xmax, urcorner.x_ );
594 ymin = std::min( ymin, llcorner.y_ );
595 ymax = std::max( ymax, urcorner.y_ );
599 Lang::ElementaryPath2D * res = new Lang::ElementaryPath2D;
601 if( xmin < Concrete::HUGE_LENGTH )
603 if( toupper( *paintCmd_ ) == 'S' ||
604 toupper( *paintCmd_ ) == 'B' )
606 xmin -= 0.5 * metaState_->width_;
607 ymin -= 0.5 * metaState_->width_;
608 xmax += 0.5 * metaState_->width_;
609 ymax += 0.5 * metaState_->width_;
611 res->push_back( new Concrete::PathPoint2D( xmin, ymin ) );
612 res->push_back( new Concrete::PathPoint2D( xmin, ymax ) );
613 res->push_back( new Concrete::PathPoint2D( xmax, ymax ) );
614 res->push_back( new Concrete::PathPoint2D( xmax, ymin ) );
615 res->close( );
618 return RefCountPtr< const Lang::ElementaryPath2D >( res );
621 void
622 Lang::PaintedPath2D::gcMark( Kernel::GCMarkedSet & marked )
626 Lang::Transformed2D::Transformed2D( RefCountPtr< const Lang::Drawable2D > element, const Lang::Transform2D & mytf )
627 : mytf_( mytf ), element_( element )
630 Lang::Transformed2D::~Transformed2D( )
633 void
634 Lang::Transformed2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
636 element_->shipout( os, pdfState, Lang::Transform2D( tf, mytf_ ) );
639 RefCountPtr< const Lang::ElementaryPath2D >
640 Lang::Transformed2D::bbox( Lang::Drawable2D::BoxType boxType ) const
642 return element_->bbox( boxType )->elementaryTransformed( mytf_ );
645 void
646 Lang::Transformed2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
648 element_->findTags( dst, dyn, key, Lang::Transform2D( tf, mytf_ ) );
651 bool
652 Lang::Transformed2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
654 return
655 element_->findOneTag( evalState, key, Lang::Transform2D( tf, mytf_ ) );
658 void
659 Lang::Transformed2D::gcMark( Kernel::GCMarkedSet & marked )
661 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
665 Lang::BBoxed2D::BBoxed2D( RefCountPtr< const Lang::Drawable2D > element, RefCountPtr< const Lang::ElementaryPath2D > mybbox, BoxType boxType )
666 : Lang::PaintedPolygon2D( Kernel::THE_NO_STATE, mybbox ), mybbox_( mybbox ), element_( element ), boxType_( boxType )
669 Lang::BBoxed2D::~BBoxed2D( )
672 void
673 Lang::BBoxed2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
675 /* At the moment, we don't clip according to the bbox, we only lie about our size.
677 element_->shipout( os, pdfState, tf );
680 RefCountPtr< const Lang::ElementaryPath2D >
681 Lang::BBoxed2D::bbox( Lang::Drawable2D::BoxType boxType ) const
683 if( boxType_ == BOTH
684 || ( boxType == Lang::Drawable2D::BOUNDING && boxType_ == BOUNDING )
685 || ( boxType == Lang::Drawable2D::BLEED && boxType_ == BLEED ) )
687 return mybbox_;
689 return element_->bbox( boxType );
692 void
693 Lang::BBoxed2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
695 element_->findTags( dst, dyn, key, tf );
698 bool
699 Lang::BBoxed2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
701 return
702 element_->findOneTag( evalState, key, tf );
705 void
706 Lang::BBoxed2D::gcMark( Kernel::GCMarkedSet & marked )
708 Lang::PaintedPolygon2D::gcMark( marked );
709 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
713 Lang::Clipped2D::Clipped2D( const RefCountPtr< const Lang::Drawable2D > & element, const char * clipCommand )
714 : element_( element ), clipCommand_( clipCommand )
717 Lang::Clipped2D::~Clipped2D( )
720 void
721 Lang::Clipped2D::addSubPath( const RefCountPtr< const Lang::ElementaryPath2D > & subpath )
723 clipList_.push_back( subpath );
726 void
727 Lang::Clipped2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
729 Kernel::Auto_qQ auto_qQ( & pdfState->graphics_, & pdfState->text_, os );
730 if( ! tf.isIdentity( ) )
732 tf.shipout( os );
733 os << " cm" << std::endl ;
735 typedef typeof clipList_ ListType;
736 for( ListType::const_iterator i = clipList_.begin( ); i != clipList_.end( ); ++i )
738 (*i)->writePath( os );
740 os << " " << clipCommand_ << " n" << std::endl ;
741 element_->shipout( os, pdfState, THE_2D_IDENTITY );
744 RefCountPtr< const Lang::ElementaryPath2D >
745 Lang::Clipped2D::bbox( Lang::Drawable2D::BoxType boxType ) const
747 RefCountPtr< const Lang::ElementaryPath2D > elem_bbox = element_->bbox( boxType );
749 if( clipList_.empty( ) )
751 return RefCountPtr< const Lang::ElementaryPath2D >( new Lang::ElementaryPath2D );
754 Concrete::Coords2D llElemBbox( 0, 0 );
755 Concrete::Coords2D urElemBbox( 0, 0 );
756 elem_bbox->boundingRectangle( & llElemBbox, & urElemBbox );
758 Concrete::Length xmin = Concrete::HUGE_LENGTH;
759 Concrete::Length xmax = -Concrete::HUGE_LENGTH;
760 Concrete::Length ymin = Concrete::HUGE_LENGTH;
761 Concrete::Length ymax = -Concrete::HUGE_LENGTH;
763 Concrete::Coords2D llcorner( 0, 0 ); /* Temporary variables to be used in the loop below. */
764 Concrete::Coords2D urcorner( 0, 0 );
766 typedef typeof clipList_ PathType;
767 for( PathType::const_iterator j = clipList_.begin( ); j != clipList_.end( ); ++j )
769 if( (*j)->boundingRectangle( & llcorner, & urcorner ) )
771 /* non-empty path */
772 xmin = std::min( xmin, llcorner.x_ );
773 xmax = std::max( xmax, urcorner.x_ );
774 ymin = std::min( ymin, llcorner.y_ );
775 ymax = std::max( ymax, urcorner.y_ );
779 xmin = std::max( xmin, llElemBbox.x_ );
780 ymin = std::max( ymin, llElemBbox.y_ );
781 xmax = std::min( xmax, urElemBbox.x_ );
782 ymax = std::min( ymax, urElemBbox.y_ );
784 Lang::ElementaryPath2D * res = new Lang::ElementaryPath2D;
786 if( xmin < xmax && ymin < ymax )
788 res->push_back( new Concrete::PathPoint2D( xmin, ymin ) );
789 res->push_back( new Concrete::PathPoint2D( xmin, ymax ) );
790 res->push_back( new Concrete::PathPoint2D( xmax, ymax ) );
791 res->push_back( new Concrete::PathPoint2D( xmax, ymin ) );
792 res->close( );
795 return RefCountPtr< const Lang::ElementaryPath2D >( res );
798 void
799 Lang::Clipped2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
801 element_->findTags( dst, dyn, key, tf );
804 bool
805 Lang::Clipped2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
807 return
808 element_->findOneTag( evalState, key, tf );
811 void
812 Lang::Clipped2D::gcMark( Kernel::GCMarkedSet & marked )
814 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
817 RefCountPtr< const Lang::Drawable2D >
818 Lang::Clipped2D::debugPolys( ) const
820 Kernel::GraphicsState * frameStatePtr = new Kernel::GraphicsState( true );
821 frameStatePtr->width_ = Concrete::Length( 0.2 );
822 RefCountPtr< const Kernel::GraphicsState > frameState( frameStatePtr );
824 Lang::PaintedPath2D * res = new Lang::PaintedPath2D( frameState, "S" );
825 typedef typeof clipList_ ListType;
826 for( ListType::const_iterator i = clipList_.begin( ); i != clipList_.end( ); ++i )
828 res->addSubPath( *i );
831 return RefCountPtr< const Lang::Drawable2D >( res );
834 bool
835 Lang::Clipped2D::isSingleConvexPoly( Concrete::Length tol ) const
837 if( clipList_.size( ) != 1 )
839 return false;
841 return clipList_.front( )->isConvexPoly( tol );
844 bool
845 Lang::Clipped2D::convexPolyContains( const Concrete::Coords2D & p, Concrete::Length tol ) const
847 return clipList_.front( )->convexPolyContains( p, tol );
850 Lang::SoftMasked2D::SoftMasked2D( const RefCountPtr< const Lang::Drawable2D > & element, const RefCountPtr< const Lang::SoftMask > & mask )
851 : element_( element ), mask_( mask )
854 Lang::SoftMasked2D::~SoftMasked2D( )
857 void
858 Lang::SoftMasked2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
860 const SimplePDF::PDF_Version::Version SOFTMASK_VERSION = SimplePDF::PDF_Version::PDF_1_4;
861 if( Kernel::the_PDF_version.greaterOrEqual( SOFTMASK_VERSION ) )
863 Kernel::Auto_qQ auto_qQ( & pdfState->graphics_, & pdfState->text_, os );
864 if( ! tf.isIdentity( ) )
866 tf.shipout( os );
867 os << " cm" << std::endl ;
869 os << pdfState->resources_->nameofGraphicsState( mask_->graphicsStateResource_ ) << " gs " << std::endl ;
870 element_->shipout( os, pdfState, THE_2D_IDENTITY );
872 else
874 Kernel::the_PDF_version.message( SOFTMASK_VERSION, "A soft mask was ignored." );
875 element_->shipout( os, pdfState, tf );
879 RefCountPtr< const Lang::ElementaryPath2D >
880 Lang::SoftMasked2D::bbox( Lang::Drawable2D::BoxType boxType ) const
882 return element_->bbox( boxType );
885 void
886 Lang::SoftMasked2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
888 element_->findTags( dst, dyn, key, tf );
891 bool
892 Lang::SoftMasked2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
894 return
895 element_->findOneTag( evalState, key, tf );
898 void
899 Lang::SoftMasked2D::gcMark( Kernel::GCMarkedSet & marked )
901 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
902 const_cast< Lang::SoftMask * >( mask_.getPtr( ) )->gcMark( marked );
906 Lang::TextMasked2D::TextMasked2D( const RefCountPtr< const Lang::Drawable2D > & element, const RefCountPtr< const Lang::Text > & mask )
907 : element_( element ), mask_( mask )
910 Lang::TextMasked2D::~TextMasked2D( )
913 void
914 Lang::TextMasked2D::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
916 Kernel::Auto_qQ auto_qQ( & pdfState->graphics_, & pdfState->text_, os );
917 if( ! tf.isIdentity( ) )
919 tf.shipout( os );
920 os << " cm" << std::endl ;
922 mask_->shipout_clip( os, pdfState, THE_2D_IDENTITY );
923 element_->shipout( os, pdfState, THE_2D_IDENTITY );
926 RefCountPtr< const Lang::ElementaryPath2D >
927 Lang::TextMasked2D::bbox( Lang::Drawable2D::BoxType boxType ) const
929 return mask_->bbox( boxType );
932 void
933 Lang::TextMasked2D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
935 element_->findTags( dst, dyn, key, tf );
938 bool
939 Lang::TextMasked2D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform2D & tf ) const
941 return
942 element_->findOneTag( evalState, key, tf );
945 void
946 Lang::TextMasked2D::gcMark( Kernel::GCMarkedSet & marked )
948 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
949 const_cast< Lang::Text * >( mask_.getPtr( ) )->gcMark( marked );
953 Lang::Drawable3D::Drawable3D( )
956 Lang::Drawable3D::~Drawable3D( )
959 RefCountPtr< const Lang::Transformed3D >
960 Lang::Drawable3D::typed_transformed( const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
962 return RefCountPtr< const Lang::Transformed3D >( new Lang::Transformed3D( self, tf ) );
965 RefCountPtr< const Lang::Geometric3D >
966 Lang::Drawable3D::transformed( const Lang::Transform3D & tf, const RefCountPtr< const Lang::Geometric3D > & self ) const
968 return typed_transformed( tf, self.down_cast< const Lang::Drawable3D >( ) );
971 RefCountPtr< const Lang::Geometric2D >
972 Lang::Drawable3D::to2D( const Kernel::PassedDyn & dyn, const RefCountPtr< const Lang::Geometric3D > & self ) const
974 typedef const Lang::Drawable3D SelfType;
975 RefCountPtr< SelfType > typedSelf = self.down_cast< SelfType >( );
976 if( typedSelf == NullPtr< SelfType >( ) )
978 throw Exceptions::InternalError( "The self-value passed to Drawable3D::to2D was of bad type." );
980 return typed_to2D( dyn, Lang::THE_3D_IDENTITY, typedSelf );
983 void
984 Lang::Drawable3D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
986 // Not overloading this methods means that there are no tagged objects within this.
989 bool
990 Lang::Drawable3D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
992 // Not overloading this methods means that there are no tagged objects within this.
993 return false;
996 void
997 Lang::Drawable3D::gcMark( Kernel::GCMarkedSet & marked )
1000 RefCountPtr< const Lang::Class > Lang::Drawable3D::TypeID = NullPtr< const Lang::Class >( ); /* The value is set in main */
1001 TYPEINFOIMPL( Drawable3D );
1002 DISPATCHIMPL( Drawable3D );
1005 Lang::Group3D::Group3D( )
1008 Lang::Group3D::~Group3D( )
1011 RefCountPtr< const Lang::Drawable2D >
1012 Lang::Group3D::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1014 return group_to2D( dyn, tf );
1018 RefCountPtr< const Lang::Class > Lang::Group3D::TypeID( new Lang::SystemFinalClass( strrefdup( "Group3D" ) ) );
1019 TYPEINFOIMPL( Group3D );
1021 RefCountPtr< const Lang::Group3D >
1022 Helpers::newGroup3D( const RefCountPtr< const Kernel::GraphicsState > & metaState, const RefCountPtr< const Lang::Drawable3D > & obj2, const RefCountPtr< const Lang::Drawable3D > & obj1 )
1024 RefCountPtr< const Lang::Group3D > res = Lang::THE_NULL3D;
1025 res = RefCountPtr< const Lang::GroupPair3D >( new Lang::GroupPair3D( obj1,
1026 res,
1027 metaState ) );
1028 res = RefCountPtr< const Lang::GroupPair3D >( new Lang::GroupPair3D( obj2,
1029 res,
1030 metaState ) );
1031 return res;
1034 RefCountPtr< const Lang::Group3D >
1035 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 )
1037 RefCountPtr< const Lang::Group3D > res = Lang::THE_NULL3D;
1038 res = RefCountPtr< const Lang::GroupPair3D >( new Lang::GroupPair3D( obj1,
1039 res,
1040 metaState ) );
1041 res = RefCountPtr< const Lang::GroupPair3D >( new Lang::GroupPair3D( obj2,
1042 res,
1043 metaState ) );
1044 res = RefCountPtr< const Lang::GroupPair3D >( new Lang::GroupPair3D( obj3,
1045 res,
1046 metaState ) );
1047 return res;
1051 Lang::GroupPair3D::GroupPair3D( const RefCountPtr< const Lang::Drawable3D > & car, const RefCountPtr< const Lang::Group3D > & cdr, const RefCountPtr< const Kernel::GraphicsState > & metaState )
1052 : metaState_( metaState ), car_( car ), cdr_( cdr )
1055 Lang::GroupPair3D::~GroupPair3D( )
1058 bool
1059 Lang::GroupPair3D::isNull( ) const
1061 return false;
1064 RefCountPtr< const Lang::Group2D >
1065 Lang::GroupPair3D::group_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf ) const
1067 return RefCountPtr< const Lang::Group2D >( new Lang::GroupPair2D( car_->typed_to2D( dyn, tf, car_ ),
1068 cdr_->group_to2D( dyn, tf ),
1069 metaState_ ) );
1072 void
1073 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
1075 car_->polygonize( zBufPile, linePile, dyn, tf, car_ );
1076 cdr_->polygonize( zBufPile, linePile, dyn, tf, cdr_ );
1079 void
1080 Lang::GroupPair3D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1082 /* See note on order in GroupPair2D!
1084 cdr_->findTags( dst, dyn, key, tf );
1085 car_->findTags( dst, dyn, key, tf );
1088 bool
1089 Lang::GroupPair3D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1091 return
1092 cdr_->findOneTag( evalState, key, tf ) ||
1093 car_->findOneTag( evalState, key, tf );
1096 RefCountPtr< const Lang::Group3D >
1097 Lang::GroupPair3D::removeShallow( Lang::Symbol::KeyType key ) const
1100 typedef const Lang::Tagged3D TaggedType;
1101 TaggedType * t = dynamic_cast< TaggedType * >( car_.getPtr( ) );
1102 if( t != 0 && t->key( ) == key )
1104 return cdr_->removeShallow( key );
1107 return RefCountPtr< const Lang::Group3D >( new Lang::GroupPair3D( car_, cdr_->removeShallow( key ), metaState_ ) );
1110 void
1111 Lang::GroupPair3D::gcMark( Kernel::GCMarkedSet & marked )
1113 const_cast< Lang::Drawable3D * >( car_.getPtr( ) )->gcMark( marked );
1114 const_cast< Lang::Group3D * >( cdr_.getPtr( ) )->gcMark( marked );
1118 Lang::GroupNull3D::GroupNull3D( )
1121 Lang::GroupNull3D::~GroupNull3D( )
1124 bool
1125 Lang::GroupNull3D::isNull( ) const
1127 return true;
1130 RefCountPtr< const Lang::Group3D >
1131 Lang::GroupNull3D::removeShallow( Lang::Symbol::KeyType key ) const
1133 return Lang::THE_NULL3D;
1136 RefCountPtr< const Lang::Group2D >
1137 Lang::GroupNull3D::group_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf ) const
1139 return Lang::THE_NULL2D;
1142 void
1143 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
1147 Lang::Drawable2Din3D::Drawable2Din3D( RefCountPtr< const Lang::Drawable2D > element )
1148 : element_( element )
1151 Lang::Drawable2Din3D::~Drawable2Din3D( )
1154 RefCountPtr< const Lang::Drawable2D >
1155 Lang::Drawable2Din3D::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1157 Concrete::Length eyez = dyn->getEyeZ( );
1158 if( eyez < Concrete::HUGE_LENGTH )
1160 std::ostringstream msg;
1161 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." ;
1162 throw Exceptions::MiscellaneousRequirement( strrefdup( msg.str( ).c_str( ) ) );
1165 // The transform in 2D is obtained by setting z = 0 in the source 3D coordinates, and omitting the z-coordinate in the new coordinates
1167 return RefCountPtr< const Lang::Drawable2D >( new Lang::Transformed2D( element_, Lang::Transform2D( tf.xx_, tf.yx_, tf.xy_, tf.yy_, tf.xt_, tf.yt_ ) ) );
1170 void
1171 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
1173 throw Exceptions::NotImplemented( "Triangularization of immersed objects." );
1176 void
1177 Lang::Drawable2Din3D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1179 Concrete::Length eyez = dyn->getEyeZ( );
1180 if( eyez < Concrete::HUGE_LENGTH )
1182 std::ostringstream msg;
1183 msg << "Tags in an immersed object are not accessible from a finite viewing distance. Consider using facing rather than immerse." ;
1184 throw Exceptions::MiscellaneousRequirement( strrefdup( msg.str( ).c_str( ) ) );
1187 // The transform in 2D is obtained by setting z = 0 in the source 3D coordinates, and omitting the z-coordinate in the new coordinates
1189 element_->findTags( dst, dyn, key, Lang::Transform2D( tf.xx_, tf.yx_, tf.xy_, tf.yy_, tf.xt_, tf.yt_ ) );
1192 bool
1193 Lang::Drawable2Din3D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1195 Concrete::Length eyez = evalState->dyn_->getEyeZ( );
1196 if( eyez < Concrete::HUGE_LENGTH )
1198 std::ostringstream msg;
1199 msg << "Tags in an immersed object are not accessible from a finite viewing distance. Consider using facing rather than immerse." ;
1200 throw Exceptions::MiscellaneousRequirement( strrefdup( msg.str( ).c_str( ) ) );
1203 // The transform in 2D is obtained by setting z = 0 in the source 3D coordinates, and omitting the z-coordinate in the new coordinates
1205 return
1206 element_->findOneTag( evalState, key, Lang::Transform2D( tf.xx_, tf.yx_, tf.xy_, tf.yy_, tf.xt_, tf.yt_ ) );
1209 void
1210 Lang::Drawable2Din3D::gcMark( Kernel::GCMarkedSet & marked )
1212 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
1217 Lang::Facing2Din3D::Facing2Din3D( RefCountPtr< const Lang::Drawable2D > element, bool scale, bool distort )
1218 : element_( element ), scale_( scale ), distort_( distort )
1221 Lang::Facing2Din3D::~Facing2Din3D( )
1224 RefCountPtr< const Lang::Drawable2D >
1225 Lang::Facing2Din3D::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1227 Concrete::Length eyez = dyn->getEyeZ( );
1228 double s = 1;
1229 if( scale_ && eyez < Concrete::HUGE_LENGTH )
1231 s = eyez / ( eyez - tf.zt_ );
1234 Concrete::Length x;
1235 Concrete::Length y;
1236 if( eyez < Concrete::HUGE_LENGTH )
1238 x = tf.xt_ * ( eyez / ( eyez - tf.zt_ ) );
1239 y = tf.yt_ * ( eyez / ( eyez - tf.zt_ ) );
1241 else
1243 x = tf.xt_;
1244 y = tf.yt_;
1247 if( distort_ )
1249 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 ) ) );
1251 else
1253 return RefCountPtr< const Lang::Drawable2D >( new Lang::Transformed2D( element_, Lang::Transform2D( s, 0, 0, s, x, y ) ) );
1257 void
1258 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
1260 throw Exceptions::MiscellaneousRequirement( "Facing objects cannot be polygonized." );
1263 void
1264 Lang::Facing2Din3D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1266 Concrete::Length eyez = dyn->getEyeZ( );
1267 double s = 1;
1268 if( scale_ && eyez < Concrete::HUGE_LENGTH )
1270 s = eyez / ( eyez - tf.zt_ );
1273 Concrete::Length x;
1274 Concrete::Length y;
1275 if( eyez < Concrete::HUGE_LENGTH )
1277 x = tf.xt_ * ( eyez / ( eyez - tf.zt_ ) );
1278 y = tf.yt_ * ( eyez / ( eyez - tf.zt_ ) );
1280 else
1282 x = tf.xt_;
1283 y = tf.yt_;
1286 if( distort_ )
1288 element_->findTags( dst, dyn, key, Lang::Transform2D( s * tf.xx_, s * tf.yx_, s * tf.xy_, s * tf.yy_, x, y ) );
1290 else
1292 element_->findTags( dst, dyn, key, Lang::Transform2D( s, 0, 0, s, x, y ) );
1296 bool
1297 Lang::Facing2Din3D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1299 Concrete::Length eyez = evalState->dyn_->getEyeZ( );
1300 double s = 1;
1301 if( scale_ && eyez < Concrete::HUGE_LENGTH )
1303 s = eyez / ( eyez - tf.zt_ );
1306 Concrete::Length x;
1307 Concrete::Length y;
1308 if( eyez < Concrete::HUGE_LENGTH )
1310 x = tf.xt_ * ( eyez / ( eyez - tf.zt_ ) );
1311 y = tf.yt_ * ( eyez / ( eyez - tf.zt_ ) );
1313 else
1315 x = tf.xt_;
1316 y = tf.yt_;
1319 if( distort_ )
1321 return
1322 element_->findOneTag( evalState, key, Lang::Transform2D( s * tf.xx_, s * tf.yx_, s * tf.xy_, s * tf.yy_, x, y ) );
1324 else
1326 return
1327 element_->findOneTag( evalState, key, Lang::Transform2D( s, 0, 0, s, x, y ) );
1331 void
1332 Lang::Facing2Din3D::gcMark( Kernel::GCMarkedSet & marked )
1334 const_cast< Lang::Drawable2D * >( element_.getPtr( ) )->gcMark( marked );
1338 Lang::FacingFunction3D::FacingFunction3D( Kernel::PassedDyn dyn, RefCountPtr< const Lang::Function > generator )
1339 : dyn_( dyn ), generator_( generator )
1342 Lang::FacingFunction3D::~FacingFunction3D( )
1345 RefCountPtr< const Lang::Drawable2D >
1346 Lang::FacingFunction3D::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
1348 /* Too bad we can't call the function CPP here...
1350 Kernel::ValueRef valUntyped = NullPtr< const Lang::Value >( );
1352 Ast::SourceLocation loc = Ast::SourceLocation( Ast::FileID::build_internal( "<Facing a function in 3D>" ) );
1354 /* Note that the use of a StoreValueContinuation relies on valUntyped being alive at the time the continuation is invoked.
1356 bool done = false;
1357 Kernel::EvalState evalState( 0,
1359 dyn_,
1360 Kernel::ContRef( new Kernel::StoreValueContinuation( & valUntyped,
1361 Kernel::ContRef( new Kernel::ExitContinuation( & done, loc ) ),
1362 loc ) ) );
1364 generator_->call( & evalState, RefCountPtr< const Lang::Value >( new Lang::Transform3D( tf ) ), loc );
1366 while( ! done )
1368 evalState.expr_->eval( & evalState );
1371 return Helpers::down_cast< const Lang::Drawable2D >( valUntyped, loc );
1374 void
1375 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
1377 throw Exceptions::MiscellaneousRequirement( "Facing functions cannot be polygonized." );
1380 void
1381 Lang::FacingFunction3D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1384 * At the moment, we don't search facing functions for tags!
1388 bool
1389 Lang::FacingFunction3D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
1392 * At the moment, we don't search facing functions for tags!
1394 return false;
1397 void
1398 Lang::FacingFunction3D::gcMark( Kernel::GCMarkedSet & marked )
1400 const_cast< Lang::Function * >( generator_.getPtr( ) )->gcMark( marked );
1404 Computation::PaintedPolygon3D::PaintedPolygon3D( bool singleSided, const Concrete::UnitFloatTriple & normal, Concrete::Length m, Concrete::Length tiebreaker )
1405 : singleSided_( singleSided ), normal_( normal ), m_( m ), tiebreaker_( tiebreaker )
1408 Computation::PaintedPolygon3D::~PaintedPolygon3D( )
1411 void
1412 Computation::PaintedPolygon3D::pushPoint( const Concrete::Coords3D & p )
1414 Concrete::Length tmp = Concrete::inner( normal_, p ) - m_;
1415 if( fabs( tmp > Computation::theTrixelizeSplicingTol ) )
1417 std::cerr << "Greater than tol: " << tmp.offtype< 1, 0 >( ) << std::endl ;
1418 throw Exceptions::OutOfRange( "The 3D painted path was not flat enough to make a polygon." );
1420 points_.push_back( p );
1423 void
1424 Computation::PaintedPolygon3D::push_zBufTriangles( const Lang::Transform3D & tf, const Concrete::Length eyez, std::list< Computation::ZBufTriangle > * triangleQueue, bool respectSingleSided ) const
1426 // This function shall not push tiny triangles!
1428 // Note that the ZBufTriangles pushed are not completely transformed, since *this is the painter, and not transformed by tf.
1429 // The ugly solution to this is that tf must also be specified when painting the area.
1431 if( points_.size( ) < 3 )
1433 return;
1436 // At the moment, convexity is assumed!
1438 typedef Computation::ZBufTriangle::ZMap ZMapType;
1439 if( tf.isIdentity( ) )
1441 if( respectSingleSided && singleSided_ )
1443 const Concrete::Coords3D & somePoint = points_.front( );
1444 if( normal_.z_ * eyez - Concrete::inner( normal_, somePoint ) <= 0 )
1446 return;
1450 RefCountPtr< const ZMapType > zMap( new ZMapType( normal_, m_, tiebreaker_, eyez ) );
1451 typedef typeof points_ ListType;
1452 ListType::const_iterator i = points_.begin( );
1453 Concrete::Coords2D p0 = i->make2DAutomatic( eyez );
1454 ++i;
1455 Concrete::Coords2D p1 = i->make2DAutomatic( eyez );
1456 ++i;
1457 for( ; i != points_.end( ); ++i )
1459 Concrete::Coords2D p2 = i->make2DAutomatic( eyez );
1460 // This tolerance test assures that we don't produce tiny-tiny triangles. It is an inscribed circle test.
1461 if( Computation::triangleArea( p0, p1, p2 ) > Computation::theTrixelizeOverlapTol * Computation::triangleSemiPerimeter( p0, p1, p2 ) )
1463 triangleQueue->push_back( Computation::ZBufTriangle( this,
1464 zMap,
1465 p0, p1, p2 ) );
1467 p1 = p2;
1470 else
1472 RefCountPtr< const ZMapType > zMap = RefCountPtr< const ZMapType >( NullPtr< const ZMapType >( ) );
1474 Concrete::UnitFloatTriple Tnormal = tf.transformPlaneUnitNormal( normal_ );
1475 if( respectSingleSided && singleSided_ )
1477 const Concrete::Coords3D & somePoint = points_.front( );
1478 if( Tnormal.z_ * eyez - Concrete::inner( Tnormal, somePoint.transformed( tf ) ) <= 0 )
1480 return;
1484 double ax = fabs( normal_.x_ );
1485 double ay = fabs( normal_.y_ );
1486 double az = fabs( normal_.z_ );
1487 Concrete::Coords3D x0( 0, 0, 0 );
1488 if( ax >= ay && ax >= az )
1490 x0 = Concrete::Coords3D( m_ / normal_.x_, 0, 0 );
1492 else if( ay >= az )
1494 x0 = Concrete::Coords3D( 0, m_ / normal_.y_, 0 );
1496 else
1498 x0 = Concrete::Coords3D( 0, 0, m_ / normal_.z_ );
1500 Concrete::Length Tm = Concrete::inner( Tnormal, x0.transformed( tf ) );
1502 zMap = RefCountPtr< const ZMapType >( new ZMapType( Tnormal, Tm, tiebreaker_, eyez ) );
1506 typedef typeof points_ ListType;
1507 ListType::const_iterator i = points_.begin( );
1508 Concrete::Coords2D p0 = i->transformed( tf ).make2DAutomatic( eyez );
1509 ++i;
1510 Concrete::Coords2D p1 = i->transformed( tf ).make2DAutomatic( eyez );
1511 ++i;
1512 for( ; i != points_.end( ); ++i )
1514 Concrete::Coords2D p2 = i->transformed( tf ).make2DAutomatic( eyez );
1515 // This tolerance test assures that we don't produce tiny-tiny triangles. It is an inscribed circle test.
1516 if( Computation::triangleArea( p0, p1, p2 ) > Computation::theTrixelizeOverlapTol * Computation::triangleSemiPerimeter( p0, p1, p2 ) )
1518 triangleQueue->push_back( Computation::ZBufTriangle( this,
1519 zMap,
1520 p0, p1, p2 ) );
1522 p1 = p2;
1527 Concrete::Coords3D
1528 Computation::PaintedPolygon3D::computeMean( ) const
1530 Concrete::Coords3D res( 0, 0, 0 );
1531 typedef typeof points_ ListType;
1532 for( ListType::const_iterator i = points_.begin( ); i != points_.end( ); ++i )
1534 res = res + *i;
1536 return ( 1. / points_.size( ) ) * res;
1539 const Computation::FacetLatticeVertex *
1540 Computation::FacetLatticeEdge::getOther( const FacetLatticeEdge * e ) const
1542 if( p0_ == e->p0_ || p0_ == e->p1_ )
1544 return p1_;
1546 return p0_;
1549 bool
1550 Computation::FacetLatticeEdge::sharePoint( const FacetLatticeEdge * e ) const
1552 return
1553 p0_ == e->p0_ ||
1554 p0_ == e->p1_ ||
1555 p1_ == e->p0_ ||
1556 p1_ == e->p1_;
1560 void
1561 Computation::FacetLatticeEdge::split( const Concrete::Length eyez,
1562 PtrOwner_back_Access< std::list< const Computation::FacetLatticeEdge * > > * edgeMem,
1563 PtrOwner_back_Access< std::list< const Computation::FacetLatticeVertex * > > * vertexMem,
1564 const Computation::FacetLatticeEdge ** child1, const Computation::FacetLatticeEdge ** child2 ) const
1566 if( child1_ != 0 )
1568 *child1 = child1_;
1569 *child2 = child2_;
1570 return;
1573 if( eyez == Concrete::HUGE_LENGTH )
1575 FacetLatticeVertex * pNew = new FacetLatticeVertex( 0.5 * ( p0_->p3D_ + p1_->p3D_ ), eyez, vertexMem->size( ) );
1576 vertexMem->push_back( pNew );
1577 child1_ = new Computation::FacetLatticeEdge( p0_, pNew );
1578 edgeMem->push_back( child1_ );
1579 child2_ = new Computation::FacetLatticeEdge( pNew, p1_ );
1580 edgeMem->push_back( child2_ );
1582 else
1584 // We compute the midpoint _in_view_, and then find where this is along the 3D line.
1585 Concrete::Coords2D mid2D = 0.5 * ( p0_->p2D_ + p1_->p2D_ );
1587 // If we write the point we seek in 3D as
1588 // p0_ + lambda * ( p1_ - p0_ )
1589 // then <lambda> must solve the overdetermined system
1590 // a * lambda == -b
1591 // where
1592 const double ra = ( p1_->p3D_.z_ - p0_->p3D_.z_ ) / eyez;
1593 Concrete::Coords2D a( p1_->p3D_.x_ - p0_->p3D_.x_ + mid2D.x_ * ra,
1594 p1_->p3D_.y_ - p0_->p3D_.y_ + mid2D.y_ * ra );
1595 const double rb = static_cast< double >( p0_->p3D_.z_ / eyez ) - 1;
1596 Concrete::Coords2D b( p0_->p3D_.x_ + mid2D.x_ * rb,
1597 p0_->p3D_.y_ + mid2D.y_ * rb );
1598 const double lambda = - Concrete::innerScalar( a, b ) / Concrete::innerScalar( a, a );
1600 FacetLatticeVertex * pNew = new FacetLatticeVertex( ( 1 - lambda ) * p0_->p3D_ + lambda * p1_->p3D_, eyez, vertexMem->size( ) );
1601 vertexMem->push_back( pNew );
1602 child1_ = new Computation::FacetLatticeEdge( p0_, pNew );
1603 edgeMem->push_back( child1_ );
1604 child2_ = new Computation::FacetLatticeEdge( pNew, p1_ );
1605 edgeMem->push_back( child2_ );
1608 *child1 = child1_;
1609 *child2 = child2_;
1613 Computation::FacetLatticeVertex::FacetLatticeVertex( const Concrete::Coords3D & p3D, const Concrete::Length eyez, const size_t i )
1614 : p3D_( p3D ), p2D_( p3D.make2DAutomatic( eyez ) ), i_( i )
1617 const Computation::FacetLatticeEdge *
1618 Computation::FacetLatticeTriangle::getOther( const Computation::FacetLatticeEdge *ea, const Computation::FacetLatticeEdge *eb ) const
1620 if( ea == e0_ )
1622 if( eb == e1_ )
1624 return e2_;
1626 return e1_;
1628 else if( ea == e1_ )
1630 if( eb == e0_ )
1632 return e2_;
1634 return e0_;
1636 else if( ea == e2_ )
1638 if( eb == e0_ )
1640 return e1_;
1642 return e0_;
1645 throw Exceptions::InternalError( "FacetTriangle::getOther called with alien edge." );
1648 bool
1649 Computation::FacetLatticeTriangle::fitsResolution( const Concrete::Length resolution, const Concrete::Length eyez,
1650 PtrOwner_back_Access< std::list< const Computation::FacetLatticeEdge * > > * edgeMem,
1651 PtrOwner_back_Access< std::list< const Computation::FacetLatticeVertex * > > * vertexMem,
1652 const Computation::FacetLatticeTriangle ** child1, const Computation::FacetLatticeTriangle ** child2 ) const
1654 const Computation::FacetLatticeEdge * ec1;
1655 const Computation::FacetLatticeEdge * ec2;
1657 Concrete::Length l0 = e0_->length2D( );
1658 Concrete::Length l1 = e1_->length2D( );
1659 Concrete::Length l2 = e2_->length2D( );
1660 Concrete::Length lMax = std::max( l0, std::max( l1, l2 ) );
1662 if( lMax < resolution )
1664 return true;
1667 const Computation::FacetLatticeEdge * ea = e0_;
1668 const Computation::FacetLatticeEdge * eb = e1_;
1669 const Computation::FacetLatticeEdge * ec = e2_;
1670 if( l1 == lMax )
1672 ea = e1_;
1673 eb = e2_;
1674 ec = e0_;
1676 else if( l2 == lMax )
1678 ea = e2_;
1679 eb = e0_;
1680 ec = e1_;
1684 ea->split( eyez, edgeMem, vertexMem, & ec1, & ec2 );
1685 Computation::FacetLatticeEdge * newEdge = new Computation::FacetLatticeEdge( ea->midpoint( ), eb->getOther( ea ) );
1686 edgeMem->push_back( newEdge );
1687 if( eb->sharePoint( ec2 ) )
1689 *child1 = new Computation::FacetLatticeTriangle( ec2, eb, newEdge );
1690 *child2 = new Computation::FacetLatticeTriangle( newEdge, ec, ec1 );
1692 else
1694 *child1 = new Computation::FacetLatticeTriangle( ec1, eb, newEdge );
1695 *child2 = new Computation::FacetLatticeTriangle( newEdge, ec, ec2 );
1698 return false;
1702 RefCountPtr< const Lang::Drawable2D >
1703 Computation::FacetLatticeTriangle::paint( const RefCountPtr< const Computation::FacetInterpolatorGray > & interpolator, const std::list< RefCountPtr< const Lang::LightSource > > & lights, const Concrete::Length eyez ) const
1705 Kernel::GraphicsState * metaStatePtr = new Kernel::GraphicsState( true );
1707 metaStatePtr->nonStrokingColor_ = interpolator->compute( Lang::THE_3D_IDENTITY, lights,
1708 Computation::triangleIncenter( v0_->p3D_, v1_->p3D_, v2_->p3D_ ),
1709 eyez );
1711 RefCountPtr< const Kernel::GraphicsState > metaState( metaStatePtr );
1713 RefCountPtr< Lang::ElementaryPath2D > path = RefCountPtr< Lang::ElementaryPath2D >( new Lang::ElementaryPath2D( ) );
1714 path->close( );
1715 // It's a pity we have to copy duplicate those points...
1716 path->push_back( new Concrete::PathPoint2D( new Concrete::Coords2D( v0_->p2D_ ) ) );
1717 path->push_back( new Concrete::PathPoint2D( new Concrete::Coords2D( v1_->p2D_ ) ) );
1718 path->push_back( new Concrete::PathPoint2D( new Concrete::Coords2D( v2_->p2D_ ) ) );
1720 return RefCountPtr< const Lang::PaintedPolygon2D >( new Lang::PaintedPolygon2D( metaState, path ) );
1723 RefCountPtr< const Lang::Drawable2D >
1724 Computation::FacetLatticeTriangle::paint( const RefCountPtr< const Computation::FacetInterpolatorRGB > & interpolator, const std::list< RefCountPtr< const Lang::LightSource > > & lights, const Concrete::Length eyez ) const
1726 Kernel::GraphicsState * metaStatePtr = new Kernel::GraphicsState( true );
1728 metaStatePtr->nonStrokingColor_ = interpolator->compute( Lang::THE_3D_IDENTITY, lights,
1729 Computation::triangleIncenter( v0_->p3D_, v1_->p3D_, v2_->p3D_ ),
1730 eyez );
1732 RefCountPtr< const Kernel::GraphicsState > metaState( metaStatePtr );
1734 RefCountPtr< Lang::ElementaryPath2D > path = RefCountPtr< Lang::ElementaryPath2D >( new Lang::ElementaryPath2D( ) );
1735 path->close( );
1736 // It's a pity we have to copy duplicate those points...
1737 path->push_back( new Concrete::PathPoint2D( new Concrete::Coords2D( v0_->p2D_ ) ) );
1738 path->push_back( new Concrete::PathPoint2D( new Concrete::Coords2D( v1_->p2D_ ) ) );
1739 path->push_back( new Concrete::PathPoint2D( new Concrete::Coords2D( v2_->p2D_ ) ) );
1741 return RefCountPtr< const Lang::PaintedPolygon2D >( new Lang::PaintedPolygon2D( metaState, path ) );
1744 void
1745 Computation::FacetLatticeTriangle::getVertexes( const Computation::FacetLatticeVertex ** va, const Computation::FacetLatticeVertex ** vb, const Computation::FacetLatticeVertex ** vc ) const
1747 *va = v0_;
1748 *vb = v1_;
1749 *vc = v2_;
1752 // This function is very close to the PDF definition of a free-form triangle mesh.
1753 // 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.
1754 // 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.
1755 unsigned char
1756 Computation::FacetLatticeTriangle::extendLattice( const Computation::FacetLatticeVertex ** va, const Computation::FacetLatticeVertex ** vb, const Computation::FacetLatticeVertex ** vc ) const
1758 // vc must be part of this triangle if we are to extend va--vb--vc.
1759 if( v0_ == *vc || v1_ == *vc || v2_ == *vc )
1761 // First, we try to extend vb--vc (corresponding to flag=1)
1762 if( v0_ == *vb || v1_ == *vb || v2_ == *vb )
1764 // We now update va and vb so that they define the edge that is extended.
1765 *va = *vb;
1766 *vb = *vc;
1768 // Now we need to find which of our corners that is the added one.
1769 if( v0_ != *va && v0_ != *vb )
1771 *vc = v0_;
1773 else if( v1_ != *va && v1_ != *vb )
1775 *vc = v1_;
1777 else
1779 *vc = v2_;
1781 return 1;
1784 // Then, we try to extend va--vc (corresponding to flag=2)
1785 if( v0_ == *va || v1_ == *va || v2_ == *va )
1787 // We now update va and vb so that they define the edge that is extended.
1788 // *va = *va;
1789 *vb = *vc;
1791 // Now we need to find which of our corners that is the added one.
1792 if( v0_ != *va && v0_ != *vb )
1794 *vc = v0_;
1796 else if( v1_ != *va && v1_ != *vb )
1798 *vc = v1_;
1800 else
1802 *vc = v2_;
1804 return 2;
1808 return 3;
1811 void
1812 Computation::FacetLatticeTriangle::display2D( std::ostream & os ) const
1814 Concrete::Length lMax = Concrete::ZERO_LENGTH;
1816 Concrete::Length tmp = v0_->p2D_.distanceTo( v1_->p2D_ );
1817 if( tmp > lMax )
1819 lMax = tmp;
1823 Concrete::Length tmp = v1_->p2D_.distanceTo( v2_->p2D_ );
1824 if( tmp > lMax )
1826 lMax = tmp;
1830 Concrete::Length tmp = v2_->p2D_.distanceTo( v0_->p2D_ );
1831 if( tmp > lMax )
1833 lMax = tmp;
1837 os << "Triangle ( " << v0_->p2D_ << " -- " << v1_->p2D_ << " -- " << v2_->p2D_ << " ) "
1838 << " with 2D area " << Concrete::Area::offtype( Computation::triangleArea( v0_->p2D_, v1_->p2D_, v2_->p2D_ ) )
1839 << " and longest side " << Lang::Length( lMax ) ;
1842 void
1843 Computation::FacetLatticeTriangle::display3D( std::ostream & os ) const
1845 os << "Triangle ( " << v0_->p3D_ << " -- " << v1_->p3D_ << " -- " << v2_->p3D_ << " )" ;
1849 void
1850 Computation::PaintedPolygon3D::makeLattice( PtrOwner_back_Access< std::list< const Computation::FacetLatticeTriangle * > > * lattice,
1851 PtrOwner_back_Access< std::list< const Computation::FacetLatticeEdge * > > * edgeMem,
1852 PtrOwner_back_Access< std::list< const FacetLatticeVertex * > > * vertexMem,
1853 const Concrete::Length viewResolution,
1854 const Concrete::Length eyez, const Lang::Transform3D & tf ) const
1856 if( points_.size( ) < 3 )
1858 throw Exceptions::InternalError( "Less than three points in PaintedPolygon3D::makeLattice!" );
1861 std::list< const Computation::FacetLatticeTriangle * > jobQueue;
1863 typedef typeof points_ ListType;
1865 if( points_.size( ) == 3 )
1867 ListType::const_iterator i = points_.begin( );
1868 Computation::FacetLatticeVertex * p0 = new Computation::FacetLatticeVertex( i->transformed( tf ), eyez, vertexMem->size( ) );
1869 vertexMem->push_back( p0 );
1870 ++i;
1871 Computation::FacetLatticeVertex * p1 = new Computation::FacetLatticeVertex( i->transformed( tf ), eyez, vertexMem->size( ) );
1872 vertexMem->push_back( p1 );
1873 ++i;
1874 Computation::FacetLatticeVertex * p2 = new Computation::FacetLatticeVertex( i->transformed( tf ), eyez, vertexMem->size( ) );
1875 vertexMem->push_back( p2 );
1877 Computation::FacetLatticeEdge * e0 = new Computation::FacetLatticeEdge( p0, p1 );
1878 edgeMem->push_back( e0 );
1879 Computation::FacetLatticeEdge * e1 = new Computation::FacetLatticeEdge( p1, p2 );
1880 edgeMem->push_back( e1 );
1881 Computation::FacetLatticeEdge * e2 = new Computation::FacetLatticeEdge( p2, p0 );
1882 edgeMem->push_back( e2 );
1884 jobQueue.push_back( new Computation::FacetLatticeTriangle( e0, e1, e2 ) );
1886 else
1888 ListType::const_iterator i = points_.begin( );
1889 Computation::FacetLatticeVertex * p0 = new Computation::FacetLatticeVertex( i->transformed( tf ), eyez, vertexMem->size( ) );
1890 vertexMem->push_back( p0 );
1891 ++i;
1892 Computation::FacetLatticeVertex * p1 = new Computation::FacetLatticeVertex( i->transformed( tf ), eyez, vertexMem->size( ) );
1893 vertexMem->push_back( p1 );
1894 ++i;
1896 Computation::FacetLatticeEdge * e0 = new Computation::FacetLatticeEdge( p0, p1 );
1897 edgeMem->push_back( e0 );
1899 for( ; i != points_.end( ); ++i )
1901 Computation::FacetLatticeVertex * p2 = new Computation::FacetLatticeVertex( i->transformed( tf ), eyez, vertexMem->size( ) );
1902 vertexMem->push_back( p2 );
1904 Computation::FacetLatticeEdge * e1 = new Computation::FacetLatticeEdge( p1, p2 );
1905 edgeMem->push_back( e1 );
1907 Computation::FacetLatticeEdge * e2 = new Computation::FacetLatticeEdge( p2, p0 );
1908 edgeMem->push_back( e2 );
1910 jobQueue.push_back( new Computation::FacetLatticeTriangle( e0, e1, e2 ) );
1912 p1 = p2;
1913 e0 = e2;
1917 while( ! jobQueue.empty( ) )
1919 // std::cerr << "Triangles in queue: " << jobQueue.size( ) << " Triangles in lattice: " << lattice->size( ) << std::endl ;
1920 const Computation::FacetLatticeTriangle * currentTriangle = jobQueue.front( );
1921 jobQueue.pop_front( );
1922 const Computation::FacetLatticeTriangle * child1 = 0;
1923 const Computation::FacetLatticeTriangle * child2 = 0;
1924 if( currentTriangle->fitsResolution( viewResolution, eyez, edgeMem, vertexMem, & child1, & child2 ) )
1926 lattice->push_back( currentTriangle );
1928 else
1930 jobQueue.push_back( child1 );
1931 jobQueue.push_back( child2 );
1932 delete currentTriangle;
1937 Computation::StrokedLine3D::StrokedLine3D( const Concrete::Coords3D & p0, const Concrete::Coords3D & p1, const RefCountPtr< const Kernel::GraphicsState > metaState )
1938 : p0_( p0 ), p1_( p1 ), metaState_( metaState )
1941 Computation::StrokedLine3D::~StrokedLine3D( )
1944 void
1945 Computation::StrokedLine3D::push_zBufLine( const Lang::Transform3D & tf, const Concrete::Length eyez, std::list< const Computation::ZBufLine * > * lineQueue ) const
1947 typedef Computation::ZBufLine::ZMap ZMapType;
1948 typedef const Bezier::PolyCoeffs< Concrete::Coords2D > ViewType;
1949 RefCountPtr< ViewType > nullView = RefCountPtr< ViewType >( NullPtr< ViewType >( ) );
1950 if( tf.isIdentity( ) )
1952 Concrete::Coords3D d = p1_ - p0_;
1953 RefCountPtr< const ZMapType > zMap( new ZMapType( p0_, d.directionNoFail( ), eyez ) );
1954 lineQueue->push_back( new Computation::ZBufLine( this, zMap, nullView, p0_.make2DAutomatic( eyez ), p1_.make2DAutomatic( eyez ) ) );
1956 else
1958 Concrete::Coords3D tfp0 = p0_.transformed( tf );
1959 Concrete::Coords3D tfp1 = p1_.transformed( tf );
1960 Concrete::Coords3D d = tfp1 - tfp0;
1961 RefCountPtr< const ZMapType > zMap( new ZMapType( tfp0, d.directionNoFail( ), eyez ) );
1962 lineQueue->push_back( new Computation::ZBufLine( this, zMap, nullView, tfp0.make2DAutomatic( eyez ), tfp1.make2DAutomatic( eyez ) ) );
1967 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 )
1968 : Computation::StrokedLine3D( p0, p1, metaState ),
1969 p0front_( p0front ),
1970 p1rear_( p1rear )
1973 Computation::StrokedSplineSegment3D::~StrokedSplineSegment3D( )
1976 void
1977 Computation::StrokedSplineSegment3D::push_zBufLine( const Lang::Transform3D & tf, const Concrete::Length eyez, std::list< const Computation::ZBufLine * > * lineQueue ) const
1979 typedef Computation::ZBufLine::ZMap ZMapType;
1980 typedef const Bezier::PolyCoeffs< Concrete::Coords2D > ViewType;
1981 if( tf.isIdentity( ) )
1983 Concrete::Coords3D d = p1_ - p0_;
1984 RefCountPtr< const ZMapType > zMap( new ZMapType( p0_, d.directionNoFail( ), eyez ) );
1985 RefCountPtr< ViewType > bezierView = RefCountPtr< ViewType >( new ViewType( Bezier::ControlPoints< Concrete::Coords2D >( p0_.make2DAutomatic( eyez ), p0front_.make2DAutomatic( eyez ), p1rear_.make2DAutomatic( eyez ), p1_.make2DAutomatic( eyez ) ) ) );
1986 lineQueue->push_back( new Computation::ZBufLine( this, zMap, bezierView, p0_.make2DAutomatic( eyez ), p1_.make2DAutomatic( eyez ) ) );
1988 else
1990 Concrete::Coords3D tfp0 = p0_.transformed( tf );
1991 Concrete::Coords3D tfp0front = p0front_.transformed( tf );
1992 Concrete::Coords3D tfp1rear = p1rear_.transformed( tf );
1993 Concrete::Coords3D tfp1 = p1_.transformed( tf );
1994 Concrete::Coords3D d = tfp1 - tfp0;
1995 RefCountPtr< const ZMapType > zMap( new ZMapType( tfp0, d.directionNoFail( ), eyez ) );
1996 RefCountPtr< ViewType > bezierView = RefCountPtr< ViewType >( new ViewType( Bezier::ControlPoints< Concrete::Coords2D >( tfp0.make2DAutomatic( eyez ), tfp0front.make2DAutomatic( eyez ), tfp1rear.make2DAutomatic( eyez ), tfp1.make2DAutomatic( eyez ) ) ) );
1997 lineQueue->push_back( new Computation::ZBufLine( this, zMap, bezierView, tfp0.make2DAutomatic( eyez ), tfp1.make2DAutomatic( eyez ) ) );
2002 Computation::FilledPolygon3D::FilledPolygon3D( const RefCountPtr< const Kernel::GraphicsState > & metaState,
2003 const Concrete::UnitFloatTriple & normal, Concrete::Length m,
2004 Concrete::Length tiebreaker )
2005 : Computation::PaintedPolygon3D( false, normal, m, tiebreaker ), metaState_( metaState ) // false means not single-sided.
2008 Computation::FilledPolygon3D::~FilledPolygon3D( )
2011 RefCountPtr< const Lang::PaintedPolygon2D >
2012 Computation::FilledPolygon3D::polygon_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const std::list< RefCountPtr< const Lang::LightSource > > & lights ) const
2014 // A FilledPolygon3D is characterized by that it doesn't take notice about the lights or orientation.
2016 Concrete::Length eyez = dyn->getEyeZ( );
2018 RefCountPtr< Lang::ElementaryPath2D > path = RefCountPtr< Lang::ElementaryPath2D >( new Lang::ElementaryPath2D( ) );
2019 path->close( );
2020 if( tf.isIdentity( ) )
2022 typedef typeof points_ ListType;
2023 for( ListType::const_iterator i = points_.begin( ); i != points_.end( ); ++i )
2025 path->push_back( new Concrete::PathPoint2D( i->make2D( eyez ) ) );
2028 else
2030 typedef typeof points_ ListType;
2031 for( ListType::const_iterator i = points_.begin( ); i != points_.end( ); ++i )
2033 path->push_back( new Concrete::PathPoint2D( i->transformed( tf ).make2D( eyez ) ) );
2037 return RefCountPtr< const Lang::PaintedPolygon2D >( new Lang::PaintedPolygon2D( metaState_, path ) );
2040 RefCountPtr< const Lang::Color >
2041 Computation::FilledPolygon3D::getColor( ) const
2043 return metaState_->nonStrokingColor_;
2046 void
2047 Computation::FilledPolygon3D::gcMark( Kernel::GCMarkedSet & marked )
2049 // const_cast< Kernel::GraphicsState * >( metaState_.getPtr( ) )->gcMark( marked );
2052 Computation::NullPolygon3D::NullPolygon3D( )
2053 : Computation::PaintedPolygon3D( true, Concrete::UnitFloatTriple( 1., 0., 0., 1. ), 0, Concrete::ZERO_LENGTH )
2056 Computation::NullPolygon3D::~NullPolygon3D( )
2059 RefCountPtr< const Lang::PaintedPolygon2D >
2060 Computation::NullPolygon3D::polygon_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const std::list< RefCountPtr< const Lang::LightSource > > & lights ) const
2062 throw Exceptions::InternalError( "NullPolygon3D::polygon_to2D was invoked!" );
2063 // return Lang::THE_NULL_POLYGON2D;
2066 RefCountPtr< const Lang::Color >
2067 Computation::NullPolygon3D::getColor( ) const
2069 return Lang::THE_BLACK;
2072 void
2073 Computation::NullPolygon3D::gcMark( Kernel::GCMarkedSet & marked )
2077 Lang::PaintedPolygon2D::PaintedPolygon2D( RefCountPtr< const Kernel::GraphicsState > metaState, RefCountPtr< const Lang::ElementaryPath2D > path )
2078 : Lang::PaintedPath2D( metaState, "E" ) // "E" for "extended fill"
2080 if( ! path->isClosed( ) )
2082 throw Exceptions::InternalError( "Attempt to create PaintedPolygon2D with non-closed path." );
2084 addSubPath( path );
2087 Lang::PaintedPolygon2D::~PaintedPolygon2D( )
2090 RefCountPtr< const Lang::Drawable2D >
2091 Lang::PaintedPolygon2D::clip( std::list< Computation::ZBufTriangle > * regions, const RefCountPtr< const Lang::PaintedPolygon2D > selfRef ) const
2093 if( regions->empty( ) )
2095 throw Exceptions::InternalError( "Empty list of regions in PaintedPolygon2D::clip. (This triangle should not have been generated at all!)" );
2097 if( regions->size( ) == 1 )
2099 const Computation::ZBufTriangle & theClip = regions->front( );
2100 const Lang::ElementaryPath2D & paintPath = * path_.front( );
2101 bool isInside = true;
2102 for( Lang::ElementaryPath2D::const_iterator i = paintPath.begin( ); i != paintPath.end( ); ++i )
2104 if( ! theClip.contains( *((*i)->mid_), Computation::theTrixelizeOverlapTol ) )
2106 isInside = false;
2107 break;
2110 if( isInside )
2112 return selfRef;
2116 // If we reach here, clipping shall be done
2117 Lang::Clipped2D * resPtr = new Lang::Clipped2D( selfRef, "W" );
2118 Lang::ZBuf::trianglesToPolys( regions, resPtr );
2119 RefCountPtr< const Lang::Clipped2D > res( resPtr );
2121 if( selfRef->isContainedIn( resPtr ) )
2123 return selfRef;
2126 const bool SHOW_POLYS = false;
2127 if( SHOW_POLYS )
2129 return res->debugPolys( );
2132 return res;
2136 bool
2137 Lang::PaintedPath2D::isContainedIn( const Lang::Clipped2D * clipping ) const
2139 if( ! clipping->isSingleConvexPoly( Computation::theTrixelizeOverlapTol ) )
2141 return false;
2144 typedef typeof path_ PathType;
2145 for( PathType::const_iterator subpath = path_.begin( ); subpath != path_.end( ); ++subpath )
2147 typedef typeof **subpath SubpathType;
2148 for( SubpathType::const_iterator i = (*subpath)->begin( ); i != (*subpath)->end( ); ++i )
2150 Concrete::PathPoint2D * pathPoint = *i;
2151 if( pathPoint->rear_ != pathPoint->mid_ ||
2152 pathPoint->front_ != pathPoint->mid_ )
2154 return false;
2156 if( ! clipping->convexPolyContains( *(pathPoint->mid_), Computation::theTrixelizeOverlapTol ) )
2158 return false;
2163 return true;
2167 Lang::PaintedPath3D::PaintedPath3D( RefCountPtr< const Kernel::GraphicsState > metaState,
2168 const char * paintCmd, Concrete::Length tiebreaker )
2169 : metaState_( metaState ), paintCmd_( paintCmd ), tiebreaker_( tiebreaker )
2172 Lang::PaintedPath3D::PaintedPath3D( RefCountPtr< const Kernel::GraphicsState > metaState,
2173 RefCountPtr< const Lang::ElementaryPath3D > path,
2174 const char * paintCmd, Concrete::Length tiebreaker )
2175 : metaState_( metaState ), paintCmd_( paintCmd ), tiebreaker_( tiebreaker )
2177 addSubPath( path );
2180 Lang::PaintedPath3D::PaintedPath3D( RefCountPtr< const Kernel::GraphicsState > metaState,
2181 RefCountPtr< const Lang::MultiPath3D > paths,
2182 const char * paintCmd, Concrete::Length tiebreaker )
2183 : metaState_( metaState ), paintCmd_( paintCmd ), tiebreaker_( tiebreaker )
2185 for( Lang::MultiPath3D::const_iterator i = paths->begin( ); i != paths->end( ); ++i )
2188 typedef const Lang::ElementaryPath3D ArgType;
2189 RefCountPtr< ArgType > subpath = (*i).down_cast< ArgType >( );
2190 if( subpath != NullPtr< ArgType >( ) )
2192 addSubPath( subpath );
2193 continue;
2198 typedef const Lang::CompositePath3D ArgType;
2199 ArgType * subpath = dynamic_cast< ArgType * >( (*i).getPtr( ) );
2200 if( subpath != 0 )
2202 addSubPath( subpath->getElementaryPath( ) );
2203 continue;
2206 throw Exceptions::InternalError( "Painting 3D path: Encountered a subpath of unexpected type" );
2210 Lang::PaintedPath3D::~PaintedPath3D( )
2213 RefCountPtr< const Lang::Class > Lang::PaintedPath3D::TypeID( new Lang::SystemFinalClass( strrefdup( "PaintedPath3D" ) ) );
2214 TYPEINFOIMPL( PaintedPath3D );
2216 void
2217 Lang::PaintedPath3D::addSubPath( RefCountPtr< const Lang::ElementaryPath3D > subpath )
2219 path_.push_back( subpath );
2222 RefCountPtr< const Lang::Drawable2D >
2223 Lang::PaintedPath3D::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2225 Concrete::Length eyez = dyn->getEyeZ( );
2227 RefCountPtr< const Lang::Group2D > res( Lang::THE_NULL2D );
2229 if( tf.isIdentity( ) )
2231 if( ! metaState_->dash_->isSolid( ) && *paintCmd_ == 'S' )
2233 for( std::list< RefCountPtr< const Lang::ElementaryPath3D > >::const_iterator i = path_.begin( ); i != path_.end( ); ++i )
2235 (*i)->dashifyIn2D( & res, eyez, metaState_ );
2238 else
2240 for( std::list< RefCountPtr< const Lang::ElementaryPath3D > >::const_iterator i = path_.begin( ); i != path_.end( ); ++i )
2242 res = RefCountPtr< const Lang::Group2D >( new Lang::GroupPair2D( RefCountPtr< const Lang::Drawable2D >( new Lang::PaintedPath2D( metaState_, (*i)->make2D( eyez ), paintCmd_ ) ),
2243 res,
2244 metaState_ ) );
2248 else
2250 if( ! metaState_->dash_->isSolid( ) && *paintCmd_ == 'S' )
2252 for( std::list< RefCountPtr< const Lang::ElementaryPath3D > >::const_iterator i = path_.begin( ); i != path_.end( ); ++i )
2254 (*i)->elementaryTransformed( tf )->dashifyIn2D( & res, eyez, metaState_ );
2257 else
2259 for( std::list< RefCountPtr< const Lang::ElementaryPath3D > >::const_iterator i = path_.begin( ); i != path_.end( ); ++i )
2261 res = RefCountPtr< const Lang::Group2D >( new Lang::GroupPair2D( RefCountPtr< const Lang::Drawable2D >( new Lang::PaintedPath2D( metaState_,
2262 (*i)->elementaryTransformed( tf )->make2D( eyez ),
2263 paintCmd_ ) ),
2264 res,
2265 metaState_ ) );
2269 return res;
2272 void
2273 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
2275 if( strcmp( paintCmd_, "S" ) == 0 )
2277 typedef typeof path_ ListType;
2278 for( ListType::const_iterator subi = path_.begin( ); subi != path_.end( ); ++subi )
2280 const RefCountPtr< const Lang::ElementaryPath3D > & theSub = *subi;
2282 if( theSub->size( ) < 2 )
2284 continue;
2287 typedef typeof *theSub SubListType;
2288 SubListType::const_iterator i = theSub->begin( );
2289 Concrete::Coords3D p0 = (*i)->mid_->transformed( tf );
2290 SubListType::const_iterator iLast = i;
2291 ++i;
2292 for( ; i != theSub->end( ); iLast = i, ++i )
2294 Concrete::Coords3D p1 = (*i)->mid_->transformed( tf );
2295 if( (*iLast)->front_ != (*iLast)->mid_ || (*i)->rear_ != (*i)->mid_ )
2297 linePile->push_back( RefCountPtr< Computation::StrokedSplineSegment3D >
2298 ( new Computation::StrokedSplineSegment3D( p0, (*iLast)->front_->transformed( tf ), (*i)->rear_->transformed( tf ), p1, metaState_ ) ) );
2300 else
2302 linePile->push_back( RefCountPtr< Computation::StrokedLine3D >
2303 ( new Computation::StrokedLine3D( p0, p1, metaState_ ) ) );
2305 p0 = p1;
2307 if( theSub->isClosed( ) )
2309 i = theSub->begin( );
2310 Concrete::Coords3D p1 = (*i)->mid_->transformed( tf );
2311 if( (*iLast)->front_ != (*iLast)->mid_ || (*i)->rear_ != (*i)->mid_ )
2313 linePile->push_back( RefCountPtr< Computation::StrokedSplineSegment3D >
2314 ( new Computation::StrokedSplineSegment3D( p0, (*iLast)->front_->transformed( tf ), (*i)->rear_->transformed( tf ), p1, metaState_ ) ) );
2316 else
2318 linePile->push_back( RefCountPtr< Computation::StrokedLine3D >
2319 ( new Computation::StrokedLine3D( p0, p1, metaState_ ) ) );
2324 return;
2327 if( ! ( strcmp( paintCmd_, "f" ) == 0 ||
2328 strcmp( paintCmd_, "B" ) == 0 ) )
2330 throw Exceptions::MiscellaneousRequirement( "Only stroked and (non-*) filled polygons can be put i a z buffer." );
2334 // When we get here we know that the paintCmd_ is "f" or "B", that is, a plain fill.
2336 // if( path.size( ) > 1 )
2337 // {
2338 // std::cerr << "Warning: The result from triangularizing a composite path may not be what is expected." << std::endl ;
2339 // }
2341 typedef typeof path_ ListType;
2342 for( ListType::const_iterator subi = path_.begin( ); subi != path_.end( ); ++subi )
2344 const RefCountPtr< const Lang::ElementaryPath3D > & theSub = *subi;
2346 if( theSub->size( ) < 3 )
2348 continue;
2350 if( ! theSub->isClosed( ) )
2352 throw "Not closed";
2355 typedef typeof *theSub SubListType;
2357 RefCountPtr< Computation::FilledPolygon3D > newPoly = RefCountPtr< Computation::FilledPolygon3D >( NullPtr< Computation::FilledPolygon3D >( ) );
2359 // First we must compute an equation for the polygon!
2361 Concrete::Coords3D p0( 0, 0, 0 );
2362 Concrete::Coords3D p1( 0, 0, 0 );
2363 Concrete::Coords3D p2( 0, 0, 0 );
2364 theSub->getRepresentativePoints( tf, & p0, & p1, & p2 );
2368 Concrete::UnitFloatTriple normal = Concrete::crossDirection( p2 - p0, p1 - p0 );
2369 Concrete::Length m = Concrete::inner( normal, p0 );
2370 newPoly = RefCountPtr< Computation::FilledPolygon3D >( new Computation::FilledPolygon3D( metaState_, normal, m, tiebreaker_ ) );
2372 catch( const NonLocalExit::CrossDirectionOfParallel & ball )
2374 // This means that the crossDirection called failed because the vectors were parallel.
2375 // A polygon of lower dimension is invisible, so we may just continue
2376 continue;
2380 zBufPile->push_back( newPoly );
2382 for( SubListType::const_iterator i = theSub->begin( ); i != theSub->end( ); ++i )
2384 if( (*i)->front_ != (*i)->mid_ || (*i)->rear_ != (*i)->mid_ )
2386 throw "Corner has handle";
2388 newPoly->pushPoint( (*i)->mid_->transformed( tf ) );
2393 void
2394 Lang::PaintedPath3D::gcMark( Kernel::GCMarkedSet & marked )
2398 Lang::SingleSided3DGray::SingleSided3DGray( const RefCountPtr< const Lang::ElementaryPath3D > & points,
2399 const RefCountPtr< const Computation::FacetInterpolatorGray > & interpolator,
2400 bool singleSided,
2401 const Concrete::UnitFloatTriple & polygonUnitNormal,
2402 Concrete::Length m,
2403 Concrete::Length tiebreaker,
2404 Concrete::Length viewResolution,
2405 Computation::FacetShadeOrder shadeOrder )
2406 : points_( points ), interpolator_( interpolator ), singleSided_( singleSided ), polygonUnitNormal_( polygonUnitNormal ), m_( m ), tiebreaker_( tiebreaker ),
2407 viewResolution_( viewResolution ), shadeOrder_( shadeOrder )
2410 Lang::SingleSided3DGray::~SingleSided3DGray( )
2413 RefCountPtr< const Lang::Class > Lang::SingleSided3DGray::TypeID( new Lang::SystemFinalClass( strrefdup( "SingleSided3D(gray)" ) ) );
2414 TYPEINFOIMPL( SingleSided3DGray );
2416 RefCountPtr< const Lang::Drawable2D >
2417 Lang::SingleSided3DGray::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2419 throw Exceptions::NotImplemented( "SingleSided3DGray::typed_to2D; What light scene should be used?" );
2422 void
2423 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
2425 Concrete::UnitFloatTriple Tnormal = tf.transformPlaneUnitNormal( polygonUnitNormal_ );
2427 double ax = fabs( polygonUnitNormal_.x_ );
2428 double ay = fabs( polygonUnitNormal_.y_ );
2429 double az = fabs( polygonUnitNormal_.z_ );
2430 Concrete::Coords3D x0( 0, 0, 0 );
2431 if( ax >= ay && ax >= az )
2433 x0 = Concrete::Coords3D( m_ / polygonUnitNormal_.x_, 0, 0 );
2435 else if( ay >= az )
2437 x0 = Concrete::Coords3D( 0, m_ / polygonUnitNormal_.y_, 0 );
2439 else
2441 x0 = Concrete::Coords3D( 0, 0, m_ / polygonUnitNormal_.z_ );
2443 Concrete::Length Tm = Concrete::inner( Tnormal, x0.transformed( tf ) );
2445 RefCountPtr< Computation::SingleSidedPolygon3DGray > res =
2446 RefCountPtr< Computation::SingleSidedPolygon3DGray >
2447 ( new Computation::SingleSidedPolygon3DGray( interpolator_->transformed( tf ),
2448 singleSided_,
2449 Tnormal,
2451 tiebreaker_,
2452 viewResolution_,
2453 shadeOrder_ ) );
2455 typedef Lang::ElementaryPath3D ListType;
2456 for( ListType::const_iterator i = points_->begin( ); i != points_->end( ); ++i )
2458 // The creator of *this is responsible for asserting that there are no handles at the pathpoints.
2459 res->pushPoint( (*i)->mid_->transformed( tf ) );
2463 zBufPile->push_back( res );
2466 void
2467 Lang::SingleSided3DGray::gcMark( Kernel::GCMarkedSet & marked )
2469 const_cast< Lang::ElementaryPath3D * >( points_.getPtr( ) )->gcMark( marked );
2470 const_cast< Computation::FacetInterpolatorGray * >( interpolator_.getPtr( ) )->gcMark( marked );
2474 Lang::SingleSided3DRGB::SingleSided3DRGB( const RefCountPtr< const Lang::ElementaryPath3D > & points,
2475 const RefCountPtr< const Computation::FacetInterpolatorRGB > & interpolator,
2476 bool singleSided,
2477 const Concrete::UnitFloatTriple & polygonUnitNormal,
2478 Concrete::Length m,
2479 Concrete::Length tiebreaker,
2480 Concrete::Length viewResolution,
2481 Computation::FacetShadeOrder shadeOrder )
2482 : points_( points ), interpolator_( interpolator ), singleSided_( singleSided ), polygonUnitNormal_( polygonUnitNormal ), m_( m ), tiebreaker_( tiebreaker ),
2483 viewResolution_( viewResolution ), shadeOrder_( shadeOrder )
2486 Lang::SingleSided3DRGB::~SingleSided3DRGB( )
2489 RefCountPtr< const Lang::Class > Lang::SingleSided3DRGB::TypeID( new Lang::SystemFinalClass( strrefdup( "SingleSided3D(RGB)" ) ) );
2490 TYPEINFOIMPL( SingleSided3DRGB );
2492 RefCountPtr< const Lang::Drawable2D >
2493 Lang::SingleSided3DRGB::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2495 throw Exceptions::NotImplemented( "SingleSided3DRGB::typed_to2D; What light scene should be used?" );
2498 void
2499 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
2501 Concrete::UnitFloatTriple Tnormal = tf.transformPlaneUnitNormal( polygonUnitNormal_ );
2503 double ax = fabs( polygonUnitNormal_.x_ );
2504 double ay = fabs( polygonUnitNormal_.y_ );
2505 double az = fabs( polygonUnitNormal_.z_ );
2506 Concrete::Coords3D x0( 0, 0, 0 );
2507 if( ax >= ay && ax >= az )
2509 x0 = Concrete::Coords3D( m_ / polygonUnitNormal_.x_, 0, 0 );
2511 else if( ay >= az )
2513 x0 = Concrete::Coords3D( 0, m_ / polygonUnitNormal_.y_, 0 );
2515 else
2517 x0 = Concrete::Coords3D( 0, 0, m_ / polygonUnitNormal_.z_ );
2519 Concrete::Length Tm = Concrete::inner( Tnormal, x0.transformed( tf ) );
2521 RefCountPtr< Computation::SingleSidedPolygon3DRGB > res =
2522 RefCountPtr< Computation::SingleSidedPolygon3DRGB >
2523 ( new Computation::SingleSidedPolygon3DRGB( interpolator_->transformed( tf ),
2524 singleSided_,
2525 Tnormal,
2527 tiebreaker_,
2528 viewResolution_,
2529 shadeOrder_ ) );
2531 typedef Lang::ElementaryPath3D ListType;
2532 for( ListType::const_iterator i = points_->begin( ); i != points_->end( ); ++i )
2534 // The creator of *this is responsible for asserting that there are no handles at the pathpoints.
2535 res->pushPoint( (*i)->mid_->transformed( tf ) );
2539 zBufPile->push_back( res );
2542 void
2543 Lang::SingleSided3DRGB::gcMark( Kernel::GCMarkedSet & marked )
2545 const_cast< Lang::ElementaryPath3D * >( points_.getPtr( ) )->gcMark( marked );
2546 const_cast< Computation::FacetInterpolatorRGB * >( interpolator_.getPtr( ) )->gcMark( marked );
2551 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 )
2552 : metaState_( metaState ), pile_( pile ), linePile_( linePile ), lightPile_( lightPile )
2555 Lang::ZBuf::~ZBuf( )
2558 void
2559 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
2562 typedef typeof *pile_ ListType;
2563 for( ListType::const_iterator i = pile_->begin( ); i != pile_->end( ); ++i )
2565 zBufPile->push_back( *i );
2569 typedef typeof *linePile_ ListType;
2570 for( ListType::const_iterator i = linePile_->begin( ); i != linePile_->end( ); ++i )
2572 linePile->push_back( *i );
2577 void
2578 Lang::ZBuf::gcMark( Kernel::GCMarkedSet & marked )
2580 // At the time of writing, PaintedPolygon3D is not involved in gc.
2584 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 )
2585 : metaState_( metaState ), pile_( pile ), linePile_( linePile ), lightPile_( lightPile )
2588 Lang::ZSorter::~ZSorter( )
2591 void
2592 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
2595 typedef typeof *pile_ ListType;
2596 for( ListType::const_iterator i = pile_->begin( ); i != pile_->end( ); ++i )
2598 zBufPile->push_back( *i );
2602 typedef typeof *linePile_ ListType;
2603 for( ListType::const_iterator i = linePile_->begin( ); i != linePile_->end( ); ++i )
2605 linePile->push_back( *i );
2610 void
2611 Lang::ZSorter::gcMark( Kernel::GCMarkedSet & marked )
2613 // At the time of writing, PaintedPolygon3D is not involved in gc.
2617 Lang::Transformed3D::Transformed3D( RefCountPtr< const Lang::Drawable3D > element, const Lang::Transform3D & mytf )
2618 : mytf_( mytf ), element_( element )
2621 Lang::Transformed3D::~Transformed3D( )
2624 RefCountPtr< const Lang::Drawable2D >
2625 Lang::Transformed3D::typed_to2D( const Kernel::PassedDyn & dyn, const Lang::Transform3D & tf, const RefCountPtr< const Lang::Drawable3D > & self ) const
2627 return element_->typed_to2D( dyn, Lang::Transform3D( tf, mytf_ ), element_ );
2630 void
2631 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
2633 element_->polygonize( zBufPile, linePile, dyn, Lang::Transform3D( tf, mytf_ ), element_ );
2636 void
2637 Lang::Transformed3D::findTags( std::vector< Kernel::ValueRef > * dst, const Kernel::PassedDyn & dyn, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
2639 element_->findTags( dst, dyn, key, Lang::Transform3D( tf, mytf_ ) );
2642 bool
2643 Lang::Transformed3D::findOneTag( Kernel::EvalState * evalState, Lang::Symbol::KeyType key, const Lang::Transform3D & tf ) const
2645 return
2646 element_->findOneTag( evalState, key, Lang::Transform3D( tf, mytf_ ) );
2649 void
2650 Lang::Transformed3D::gcMark( Kernel::GCMarkedSet & marked )
2652 const_cast< Lang::Drawable3D * >( element_.getPtr( ) )->gcMark( marked );
2655 Lang::Text::Text( const RefCountPtr< const Kernel::GraphicsState > & metaState, const RefCountPtr< const Kernel::TextState > & textState, const RefCountPtr< const std::list< RefCountPtr< const Lang::TextOperation > > > & elements, const RefCountPtr< const Lang::ElementaryPath2D > & mybbox )
2656 : metaState_( metaState ), textState_( textState ), elements_( elements ), mybbox_( mybbox )
2659 Lang::Text::~Text( )
2662 void
2663 Lang::Text::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
2665 pdfState->resources_->requireProcedureSet( SimplePDF::PDF_Resources::PROC_SET_TEXT );
2667 pdfState->graphics_.synchForNonStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
2668 os << "BT" << std::endl ;
2669 if( ! tf.isIdentity( ) )
2671 tf.shipout( os );
2672 os << " Tm" << std::endl ;
2675 pdfState->text_.synchKnockout( os, textState_.getPtr( ), pdfState->resources_.getPtr( ) );
2677 typedef typeof *elements_ ListType;
2678 for( ListType::const_iterator i = elements_->begin( ); i != elements_->end( ); ++i )
2680 (*i)->shipout( os, pdfState, tf );
2682 os << "ET" << std::endl ;
2685 void
2686 Lang::Text::shipout_clip( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf ) const
2688 pdfState->resources_->requireProcedureSet( SimplePDF::PDF_Resources::PROC_SET_TEXT );
2690 os << "BT" << std::endl ;
2691 if( ! tf.isIdentity( ) )
2693 tf.shipout( os );
2694 os << " Tm" << std::endl ;
2697 pdfState->text_.synchKnockout( os, textState_.getPtr( ), pdfState->resources_.getPtr( ) );
2699 typedef typeof *elements_ ListType;
2700 for( ListType::const_iterator i = elements_->begin( ); i != elements_->end( ); ++i )
2702 (*i)->shipout( os, pdfState, tf, true ); /* true means "clip" */
2704 os << "ET" << std::endl ;
2707 RefCountPtr< const Lang::ElementaryPath2D >
2708 Lang::Text::bbox( Lang::Drawable2D::BoxType boxType ) const
2710 return mybbox_;
2713 void
2714 Lang::Text::gcMark( Kernel::GCMarkedSet & marked )
2716 typedef typeof *elements_ ListType;
2717 for( ListType::const_iterator i = elements_->begin( ); i != elements_->end( ); ++i )
2719 const_cast< Lang::TextOperation * >( i->getPtr( ) )->gcMark( marked );
2726 RefCountPtr< const Lang::TransparencyGroup >
2727 Helpers::newSolidTransparencyGroup( const RefCountPtr< const Lang::Drawable2D > & obj2, const RefCountPtr< const Lang::Drawable2D > & obj1 )
2729 return Helpers::newTransparencyGroup( Helpers::newGroup2D( Kernel::THE_DEFAULT_STATE, obj2, obj1 ),
2730 true,
2731 true,
2732 Lang::THE_INHERITED_COLOR_SPACE );
2735 RefCountPtr< const Lang::TransparencyGroup >
2736 Helpers::newSolidTransparencyGroup( const RefCountPtr< const Lang::Drawable2D > & obj3, const RefCountPtr< const Lang::Drawable2D > & obj2, const RefCountPtr< const Lang::Drawable2D > & obj1 )
2738 return Helpers::newTransparencyGroup( Helpers::newGroup2D( Kernel::THE_DEFAULT_STATE, obj3, obj2, obj1 ),
2739 true,
2740 true,
2741 Lang::THE_INHERITED_COLOR_SPACE );
2745 bool
2746 Computation::operator < ( const Computation::UndirectedEdge & p1, const Computation::UndirectedEdge & p2 )
2748 if( p1.low( ) < p2.low( ) )
2750 return true;
2752 if( p1.low( ) > p2.low( ) )
2754 return false;
2756 return p1.high( ) < p2.high( );