Update suitable examples and tests to use blank mode
[shapes.git] / source / coredraw.cc
blob93981ab90b669fa39bd0d303b96e21a439e2f92e
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, 2010 Henrik Tidefelt
19 #include <cmath>
21 #include "Shapes_Helpers_decls.h"
23 #include "shapescore.h"
24 #include "globals.h"
25 #include "shapesexceptions.h"
26 #include "consts.h"
27 #include "simplepdfi.h"
28 #include "autoonoff.h"
29 #include "hottypes.h"
30 #include "astfun.h"
31 #include "warn.h"
33 #include <iostream>
34 #include <sstream>
35 #include <fstream>
36 #include <vector>
37 #include <stdio.h>
39 using namespace Shapes;
42 namespace Shapes
44 namespace Helpers
46 RefCountPtr< const Lang::TransparencyGroup >
47 newSolidTransparencyGroup( const RefCountPtr< const Lang::Drawable2D > & obj2, const RefCountPtr< const Lang::Drawable2D > & obj1 );
48 RefCountPtr< const Lang::TransparencyGroup >
49 newSolidTransparencyGroup( const RefCountPtr< const Lang::Drawable2D > & obj3, const RefCountPtr< const Lang::Drawable2D > & obj2, const RefCountPtr< const Lang::Drawable2D > & obj1 );
51 void stroke_helper_2D( Kernel::EvalState * evalState, const RefCountPtr< const Lang::ElementaryPath2D > & path, Kernel::Arguments & args, bool fill, const Ast::SourceLocation & callLoc );
52 void stroke_helper_3D( Kernel::EvalState * evalState, const RefCountPtr< const Lang::ElementaryPath3D > & path, Kernel::Arguments & args, bool fill, const Ast::SourceLocation & callLoc );
56 namespace Shapes
58 namespace Lang
61 class Core_spot : public Lang::CoreFunction
63 public:
64 Core_spot( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
65 virtual void
66 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
68 const size_t ARITY = 1;
69 CHECK_ARITY( args, ARITY, id_ );
71 typedef const Lang::Coords2D ArgType;
72 RefCountPtr< ArgType > p = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 0, callLoc );
74 ElementaryPath2D * pth = new ElementaryPath2D;
75 pth->push_back( new Concrete::PathPoint2D( p->x_.get( ), p->y_.get( ) ) );
76 if( Kernel::allowSingletonPaths )
78 pth->close( );
80 else
82 pth->push_back( new Concrete::PathPoint2D( p->x_.get( ), p->y_.get( ) ) );
85 Kernel::GraphicsState * capState( new Kernel::GraphicsState( *evalState->dyn_->getGraphicsState( ) ) );
86 capState->cap_ = Lang::CapStyle::CAP_ROUND;
88 Kernel::ContRef cont = evalState->cont_;
89 cont->takeValue( Kernel::ValueRef( new Lang::PaintedPath2D
90 ( RefCountPtr< const Kernel::GraphicsState >( capState ),
91 RefCountPtr< const Lang::ElementaryPath2D >( pth ),
92 "S" ) ),
93 evalState );
97 class Core_stroke : public Lang::CoreFunction
99 bool fill_;
100 public:
101 Core_stroke( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name, bool fill )
102 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) ), fill_( fill )
104 formals_->appendEvaluatedCoreFormal( "path", Kernel::THE_SLOT_VARIABLE );
105 formals_->appendEvaluatedCoreFormal( "head", Kernel::VariableHandle( new Kernel::Variable( Lang::THE_NO_ARROW ) ) );
106 formals_->appendEvaluatedCoreFormal( "tail", Kernel::VariableHandle( new Kernel::Variable( Lang::THE_NO_ARROW ) ) );
109 virtual void
110 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
112 args.applyDefaults( callLoc );
116 typedef const Lang::ElementaryPath2D ArgType;
117 RefCountPtr< ArgType > arg = Helpers::elementaryPathTry2D( args.getValue( 0 ) );
118 Helpers::stroke_helper_2D( evalState, arg, args, fill_, callLoc );
119 return;
121 catch( const NonLocalExit::NotThisType & ball )
123 /* Wrong type; never mind!.. but see below!
129 typedef const Lang::ElementaryPath3D ArgType;
130 RefCountPtr< ArgType > arg = Helpers::elementaryPathTry3D( args.getValue( 0 ) );
131 Helpers::stroke_helper_3D( evalState, arg, args, fill_, callLoc );
132 return;
134 catch( const NonLocalExit::NotThisType & ball )
136 /* Wrong type; never mind!.. but see below!
140 const char * paintCmd = fill_ ? "B" : "S";
144 typedef const Lang::MultiPath2D ArgType;
145 RefCountPtr< ArgType > path = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( 0 ) );
146 RefCountPtr< const Lang::Function > arrowHead = Helpers::down_cast_CoreArgument< const Lang::Function >( id_, args, 1, callLoc );
147 RefCountPtr< const Lang::Function > arrowTail = Helpers::down_cast_CoreArgument< const Lang::Function >( id_, args, 2, callLoc );
148 if( arrowHead != Lang::THE_NO_ARROW ||
149 arrowTail != Lang::THE_NO_ARROW )
151 throw Exceptions::MiscellaneousRequirement( strrefdup( "Arrowheads/tails are not supported for composite paths." ) );
153 Kernel::ContRef cont = evalState->cont_;
154 cont->takeValue( Kernel::ValueRef( new Lang::PaintedPath2D( evalState->dyn_->getGraphicsState( ), path, paintCmd ) ),
155 evalState );
156 return;
158 catch( const NonLocalExit::NotThisType & ball )
160 /* Wrong type; never mind!.. but see below!
166 typedef const Lang::MultiPath3D ArgType;
167 RefCountPtr< ArgType > path = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( 0 ) );
168 RefCountPtr< const Lang::Function > arrowHead = Helpers::down_cast_CoreArgument< const Lang::Function >( id_, args, 1, callLoc );
169 RefCountPtr< const Lang::Function > arrowTail = Helpers::down_cast_CoreArgument< const Lang::Function >( id_, args, 2, callLoc );
170 if( arrowHead != Lang::THE_NO_ARROW ||
171 arrowTail != Lang::THE_NO_ARROW )
173 throw Exceptions::MiscellaneousRequirement( strrefdup( "Arrowheads/tails are not supported for composite paths." ) );
175 Kernel::ContRef cont = evalState->cont_;
176 cont->takeValue( Kernel::ValueRef( new Lang::PaintedPath3D( evalState->dyn_->getGraphicsState( ), path, paintCmd ) ),
177 evalState );
178 return;
180 catch( const NonLocalExit::NotThisType & ball )
182 /* Wrong type; never mind!.. but see below!
186 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, 0, Helpers::typeSetString( Lang::ElementaryPath2D::staticTypeName( ), Lang::ElementaryPath3D::staticTypeName( ) ) );
190 class Core_fill : public Lang::CoreFunction
192 public:
193 Core_fill( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
194 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
196 formals_->appendEvaluatedCoreFormal( "path", Kernel::THE_SLOT_VARIABLE );
197 formals_->appendEvaluatedCoreFormal( "tiebreaker", Kernel::THE_VOID_VARIABLE );
200 virtual void
201 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
203 args.applyDefaults( callLoc );
205 RefCountPtr< const Lang::Length > tiebreaker = Helpers::down_cast_CoreArgument< const Lang::Length >( id_, args, 1, callLoc, true );
209 typedef const Lang::ElementaryPath2D ArgType;
210 RefCountPtr< ArgType > path = Helpers::elementaryPathTry2D( args.getValue( 0 ) );
211 if( tiebreaker != NullPtr< const Lang::Length >( ) )
213 throw Exceptions::CoreOutOfRange( id_, args, 1, "The tiebreaker may not specified for 2D paths." );
215 Kernel::ContRef cont = evalState->cont_;
216 cont->takeValue( Kernel::ValueRef( new Lang::PaintedPath2D( evalState->dyn_->getGraphicsState( ), path, "f" ) ),
217 evalState );
218 return;
220 catch( const NonLocalExit::NotThisType & ball )
222 /* Wrong type; never mind!.. but see below!
228 typedef const Lang::ElementaryPath3D ArgType;
229 RefCountPtr< ArgType > path = Helpers::elementaryPathTry3D( args.getValue( 0 ) );
230 Concrete::Length tiebreakerVal = Concrete::ZERO_LENGTH;
231 if( tiebreaker != NullPtr< const Lang::Length >( ) )
233 tiebreakerVal = tiebreaker->get( );
235 Kernel::ContRef cont = evalState->cont_;
236 cont->takeValue( Kernel::ValueRef( new Lang::PaintedPath3D( evalState->dyn_->getGraphicsState( ), path, "f", tiebreakerVal ) ),
237 evalState );
238 return;
240 catch( const NonLocalExit::NotThisType & ball )
242 /* Wrong type; never mind!.. but see below!
248 typedef const Lang::MultiPath2D ArgType;
249 RefCountPtr< ArgType > path = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( 0 ) );
250 if( tiebreaker != NullPtr< const Lang::Length >( ) )
252 throw Exceptions::CoreOutOfRange( id_, args, 1, "The tiebreaker may not specified for 2D paths." );
254 Kernel::ContRef cont = evalState->cont_;
255 cont->takeValue( Kernel::ValueRef( new Lang::PaintedPath2D( evalState->dyn_->getGraphicsState( ), path, "f" ) ),
256 evalState );
257 return;
259 catch( const NonLocalExit::NotThisType & ball )
261 /* Wrong type; never mind!.. but see below!
267 typedef const Lang::MultiPath3D ArgType;
268 RefCountPtr< ArgType > path = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( 0 ) );
269 Concrete::Length tiebreakerVal = Concrete::ZERO_LENGTH;
270 if( tiebreaker != NullPtr< const Lang::Length >( ) )
272 tiebreakerVal = tiebreaker->get( );
274 Kernel::ContRef cont = evalState->cont_;
275 cont->takeValue( Kernel::ValueRef( new Lang::PaintedPath3D( evalState->dyn_->getGraphicsState( ), path, "f", tiebreakerVal ) ),
276 evalState );
277 return;
279 catch( const NonLocalExit::NotThisType & ball )
281 /* Wrong type; never mind!.. but see below!
285 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, 0, Helpers::typeSetString( Lang::MultiPath2D::staticTypeName( ), Lang::MultiPath3D::staticTypeName( ) ) );
289 class Core_fillstar : public Lang::CoreFunction
291 public:
292 Core_fillstar( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
293 virtual void
294 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
296 const size_t ARITY = 1;
297 CHECK_ARITY( args, ARITY, id_ );
301 typedef const Lang::ElementaryPath2D ArgType;
302 RefCountPtr< ArgType > path = Helpers::elementaryPathTry2D( args.getValue( 0 ) );
303 Kernel::ContRef cont = evalState->cont_;
304 cont->takeValue( Kernel::ValueRef( new Lang::PaintedPath2D( evalState->dyn_->getGraphicsState( ), path, "f*" ) ),
305 evalState );
306 return;
308 catch( const NonLocalExit::NotThisType & ball )
310 /* Wrong type; never mind!.. but see below!
316 typedef const Lang::MultiPath2D ArgType;
317 RefCountPtr< ArgType > path = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( 0 ) );
318 Kernel::ContRef cont = evalState->cont_;
319 cont->takeValue( Kernel::ValueRef( new Lang::PaintedPath2D( evalState->dyn_->getGraphicsState( ), path, "f*" ) ),
320 evalState );
321 return;
323 catch( const NonLocalExit::NotThisType & ball )
325 /* Wrong type; never mind!.. but see below!
329 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, 0, Helpers::typeSetString( Lang::ElementaryPath2D::staticTypeName( ), Lang::MultiPath2D::staticTypeName( ) ) );
333 class Core_facetnormal : public Lang::CoreFunction
335 public:
336 Core_facetnormal( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
337 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
339 formals_->appendEvaluatedCoreFormal( "location", Kernel::THE_SLOT_VARIABLE );
340 formals_->appendEvaluatedCoreFormal( "normal", Kernel::THE_SLOT_VARIABLE );
343 virtual void
344 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
346 args.applyDefaults( callLoc );
348 typedef const Lang::Coords3D LocationType;
349 typedef const Lang::FloatTriple NormalType;
351 RefCountPtr< LocationType > location = Helpers::down_cast_CoreArgument< LocationType >( id_, args, 0, callLoc, true );
352 RefCountPtr< NormalType > normal = Helpers::down_cast_CoreArgument< NormalType >( id_, args, 1, callLoc, true );
354 RefCountPtr< const Kernel::FacetState > facetState = evalState->dyn_->getFacetState( );
356 Kernel::ContRef cont = evalState->cont_;
358 RefCountPtr< const Lang::Color > nonStroking = evalState->dyn_->getGraphicsState( )->nonStrokingColor_;
360 /* If both @nonstroking and @autointensity are Gray, then we create a FacetNormalGray, otherwise colors are converted when needed to RGB so that we can create
361 * a FacetNormalRGB.
366 typedef const Lang::Gray ColorType;
367 RefCountPtr< ColorType > lightMultiply = Helpers::try_cast_CoreArgument< ColorType >( nonStroking );
369 cont->takeValue( Kernel::ValueRef( new Lang::FacetNormalGray( Concrete::Coords3D( location->x_.get( ),
370 location->y_.get( ),
371 location->z_.get( ) ),
372 facetState->reflections_,
373 Concrete::UnitFloatTriple( normal->x_, normal->y_, normal->z_ ),
374 lightMultiply->components( ),
375 facetState->autoScattering_,
376 Helpers::try_cast_CoreArgument< ColorType >( facetState->autoIntensity_ )->components( ) ) ),
377 evalState );
378 return;
380 catch( const NonLocalExit::NotThisType & ball )
382 /* Wrong type; never mind!.. but see below!
386 // When we reach here, we shall try to convert all colors to RGB.
388 typedef const Lang::RGB ColorType;
389 Concrete::RGB lightMultiply( 0, 0, 0 );
392 lightMultiply = Helpers::try_cast_CoreArgument< ColorType >( nonStroking )->components( );
393 goto doneMultiply;
395 catch( const NonLocalExit::NotThisType & ball )
397 /* Wrong type; never mind!.. but see below!
402 double a = Helpers::try_cast_CoreArgument< const Lang::Gray >( nonStroking )->components( ).gr_;
403 lightMultiply = Concrete::RGB( a, a, a );
404 goto doneMultiply;
406 catch( const NonLocalExit::NotThisType & ball )
408 /* Wrong type; never mind!.. but see below!
411 throw Exceptions::CoreDynamicTypeMismatch( callLoc, id_, Lang::DYNAMIC_VARIABLE_ID_NONSTROKING,
412 nonStroking->getTypeName( ),
413 Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
414 doneMultiply:
416 Concrete::RGB autoIntensity( 0, 0, 0 );
419 autoIntensity = Helpers::try_cast_CoreArgument< ColorType >( facetState->autoIntensity_ )->components( );
420 goto doneAuto;
422 catch( const NonLocalExit::NotThisType & ball )
424 /* Wrong type; never mind!.. but see below!
429 double a = Helpers::try_cast_CoreArgument< const Lang::Gray >( facetState->autoIntensity_ )->components( ).gr_;
430 autoIntensity = Concrete::RGB( a, a, a );
431 goto doneAuto;
433 catch( const NonLocalExit::NotThisType & ball )
435 /* Wrong type; never mind!.. but see below!
438 throw Exceptions::CoreDynamicTypeMismatch( callLoc, id_, Lang::DYNAMIC_VARIABLE_ID_AUTOINTENSITY,
439 nonStroking->getTypeName( ),
440 Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
441 doneAuto:
443 cont->takeValue( Kernel::ValueRef( new Lang::FacetNormalRGB( Concrete::Coords3D( location->x_.get( ),
444 location->y_.get( ),
445 location->z_.get( ) ),
446 facetState->reflections_,
447 Concrete::UnitFloatTriple( normal->x_, normal->y_, normal->z_ ),
448 lightMultiply,
449 facetState->autoScattering_,
450 autoIntensity ) ),
451 evalState );
452 return;
456 class Core_facet : public Lang::CoreFunction
458 public:
459 Core_facet( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
460 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
462 formals_->appendEvaluatedCoreFormal( "path", Kernel::THE_SLOT_VARIABLE );
463 formals_->appendEvaluatedCoreFormal( "n1", Kernel::THE_VOID_VARIABLE );
464 formals_->appendEvaluatedCoreFormal( "n2", Kernel::THE_VOID_VARIABLE );
465 formals_->appendEvaluatedCoreFormal( "n3", Kernel::THE_VOID_VARIABLE );
466 formals_->appendEvaluatedCoreFormal( "tiebreaker", Kernel::VariableHandle( new Kernel::Variable( RefCountPtr< const Lang::Value >( new Lang::Length( Concrete::ZERO_LENGTH ) ) ) ) );
467 formals_->appendEvaluatedCoreFormal( "double", Kernel::THE_VOID_VARIABLE );
470 virtual void
471 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
473 args.applyDefaults( callLoc );
475 // Note that the <double> defaults to false if and only if there is at least one normal specifyed, and all normals agree on what is the outward normal.
477 typedef const Lang::ElementaryPath3D PathType;
478 typedef const Lang::FacetNormalGray GrayNormalType;
479 typedef const Lang::FacetNormalRGB RGBNormalType;
480 typedef const Lang::Length TiebreakerType;
481 typedef const Lang::Boolean DoubleSidedType;
483 RefCountPtr< PathType > path = Helpers::elementaryPathCast3D( id_, args, 0, callLoc );
485 bool isRGB = true;
486 bool foundColor = false;
487 size_t numNormals = 0;
488 RefCountPtr< GrayNormalType > nGray1 = RefCountPtr< GrayNormalType >( NullPtr< GrayNormalType >( ) );
489 RefCountPtr< GrayNormalType > nGray2 = RefCountPtr< GrayNormalType >( NullPtr< GrayNormalType >( ) );
490 RefCountPtr< GrayNormalType > nGray3 = RefCountPtr< GrayNormalType >( NullPtr< GrayNormalType >( ) );
491 RefCountPtr< RGBNormalType > nRGB1 = RefCountPtr< RGBNormalType >( NullPtr< RGBNormalType >( ) );
492 RefCountPtr< RGBNormalType > nRGB2 = RefCountPtr< RGBNormalType >( NullPtr< RGBNormalType >( ) );
493 RefCountPtr< RGBNormalType > nRGB3 = RefCountPtr< RGBNormalType >( NullPtr< RGBNormalType >( ) );
494 Concrete::UnitFloatTriple d1( 0, 0, 0, 1. );
495 Concrete::UnitFloatTriple d2( 0, 0, 0, 1. );
496 Concrete::UnitFloatTriple d3( 0, 0, 0, 1. );
499 typedef GrayNormalType NormalType;
500 nGray1 = Helpers::try_cast_CoreArgument< NormalType >( args.getValue( 1 ), true );
501 nGray2 = Helpers::try_cast_CoreArgument< NormalType >( args.getValue( 2 ), true );
502 nGray3 = Helpers::try_cast_CoreArgument< NormalType >( args.getValue( 3 ), true );
503 // If we reach here, numNormals will be zero.
504 if( nGray1 != NullPtr< NormalType >( ) )
506 d1 = nGray1->normal( );
507 ++numNormals;
509 if( nGray2 != NullPtr< NormalType >( ) )
511 if( numNormals < 1 )
513 throw Exceptions::CoreOutOfRange( id_, args, 2, "The normal n1 must be provided before providing n2." );
515 d2 = nGray2->normal( );
516 ++numNormals;
518 if( nGray3 != NullPtr< NormalType >( ) )
520 if( numNormals < 2 )
522 throw Exceptions::CoreOutOfRange( id_, args, 2, "The normals n1 and n2 must be provided before providing n3." );
524 d3 = nGray3->normal( );
525 ++numNormals;
527 foundColor = true;
528 isRGB = false;
530 catch( const NonLocalExit::NotThisType & ball )
532 /* Wrong type; never mind!.. but see below!
535 if( ! foundColor )
539 typedef RGBNormalType NormalType;
540 nRGB1 = Helpers::try_cast_CoreArgument< NormalType >( args.getValue( 1 ), true );
541 nRGB2 = Helpers::try_cast_CoreArgument< NormalType >( args.getValue( 2 ), true );
542 nRGB3 = Helpers::try_cast_CoreArgument< NormalType >( args.getValue( 3 ), true );
543 // If we reach here, numNormals will be zero.
544 if( nRGB1 != NullPtr< NormalType >( ) )
546 ++numNormals;
547 d1 = nRGB1->normal( );
549 if( nRGB2 != NullPtr< NormalType >( ) )
551 if( numNormals < 1 )
553 throw Exceptions::CoreOutOfRange( id_, args, 2, "The normal n1 must be provided before providing n2." );
555 ++numNormals;
556 d2 = nRGB2->normal( );
558 if( nRGB3 != NullPtr< NormalType >( ) )
560 if( numNormals < 2 )
562 throw Exceptions::CoreOutOfRange( id_, args, 2, "The normals n1 and n2 must be provided before providing n3." );
564 ++numNormals;
565 d3 = nRGB3->normal( );
567 foundColor = true;
569 catch( const NonLocalExit::NotThisType & ball )
571 /* Wrong type; never mind!.. but see below!
575 if( ! foundColor )
577 throw Exceptions::MiscellaneousRequirement( "The procided facet normals must either be all gray or all RGB." );
579 RefCountPtr< const Lang::Color > nonStroking = evalState->dyn_->getGraphicsState( )->nonStrokingColor_;
580 if( numNormals == 0 )
582 isRGB = dynamic_cast< const Lang::RGB * >( nonStroking.getPtr( ) ) != 0;
583 if( ! isRGB &&
584 dynamic_cast< const Lang::Gray * >( nonStroking.getPtr( ) ) == 0 )
586 throw Exceptions::CoreDynamicTypeMismatch( callLoc, id_, Lang::DYNAMIC_VARIABLE_ID_NONSTROKING,
587 nonStroking->getTypeName( ),
588 Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
592 RefCountPtr< TiebreakerType > tiebreaker = Helpers::down_cast_CoreArgument< TiebreakerType >( id_, args, 4, callLoc );
593 RefCountPtr< DoubleSidedType > doubleSided = Helpers::down_cast_CoreArgument< DoubleSidedType >( id_, args, 5, callLoc, true );
595 if( path->size( ) < 3 )
597 throw Exceptions::CoreOutOfRange( id_, args, 0, "A facet path must have at least 3 points." );
599 if( ! path->isClosed( ) )
601 throw Exceptions::CoreOutOfRange( id_, args, 0, "A facet path must be closed." );
604 for( PathType::const_iterator i = path->begin( ); i != path->end( ); ++i )
606 if( (*i)->front_ != (*i)->mid_ || (*i)->rear_ != (*i)->mid_ )
608 throw Exceptions::CoreOutOfRange( id_, args, 0, "A facet path must be a polygon." );
613 Kernel::ContRef cont = evalState->cont_;
615 Concrete::Coords3D p0( 0, 0, 0 );
616 Concrete::Coords3D p1( 0, 0, 0 );
617 Concrete::Coords3D p2( 0, 0, 0 );
618 path->getRepresentativePoints( Lang::THE_3D_IDENTITY, & p0, & p1, & p2 );
620 Concrete::UnitFloatTriple normal( 1., 0., 0., 1. );
623 normal = Concrete::crossDirection( p2 - p0, p1 - p0 );
625 catch( const NonLocalExit::CrossDirectionOfParallel & ball )
627 // This means that the crossDirection called failed because the vectors were parallel.
628 // A polygon of lower dimension is invisible, so we may just return an empty object.
629 cont->takeValue( Lang::THE_NULL3D,
630 evalState );
631 return;
634 bool isDoubleSided;
635 if( doubleSided != NullPtr< DoubleSidedType >( ) )
637 isDoubleSided = doubleSided->val_;
639 else
641 if( numNormals == 0 )
643 isDoubleSided = true;
645 else
647 bool allAgree = true;
648 bool n1Agree = Concrete::inner( normal, d1 ) > 0;
649 if( d2.normSquaredThatOughtToBeOne( ) > 0.5 )
651 allAgree = allAgree && ( ( Concrete::inner( normal, d2 ) > 0 ) == n1Agree );
653 if( d3.normSquaredThatOughtToBeOne( ) > 0.5 )
655 allAgree = allAgree && ( ( Concrete::inner( normal, d3 ) > 0 ) == n1Agree );
657 if( allAgree )
659 if( ! n1Agree )
661 normal = normal.reverse( );
663 isDoubleSided = false;
665 else
667 WARN_OR_THROW( Exceptions::MiscellaneousRequirement( "A facet without explicitly specified double-sidedness has normals pointing in crazy directions, and will be treated as double-sided." ) );
668 isDoubleSided = true;
673 if( isRGB )
675 typedef RGBNormalType NormalType;
676 RefCountPtr< NormalType > n1 = nRGB1;
677 RefCountPtr< NormalType > n2 = nRGB2;
678 RefCountPtr< NormalType > n3 = nRGB3;
679 RefCountPtr< const Computation::FacetInterpolatorRGB > interpolator = RefCountPtr< const Computation::FacetInterpolatorRGB >( NullPtr< const Computation::FacetInterpolatorRGB >( ) );
681 if( numNormals == 0 )
683 typedef const Lang::RGB ColorType;
684 RefCountPtr< ColorType > lightMultiply = Helpers::down_cast_CoreDynamic< ColorType >( id_, Lang::DYNAMIC_VARIABLE_ID_NONSTROKING, nonStroking, callLoc );
685 RefCountPtr< const Kernel::FacetState > facetState = evalState->dyn_->getFacetState( );
687 interpolator = RefCountPtr< const Computation::FacetInterpolatorRGB >
688 ( new Computation::FacetInterpolatorRGB1
689 ( RefCountPtr< const Lang::FacetNormalRGB >
690 ( new Lang::FacetNormalRGB
691 ( (1./3)*( p0 + p1 + p2 ),
692 facetState->reflections_,
693 normal,
694 lightMultiply->components( ),
695 facetState->autoScattering_,
696 Helpers::down_cast_CoreDynamic< ColorType >( id_, Lang::DYNAMIC_VARIABLE_ID_AUTOINTENSITY, facetState->autoIntensity_, callLoc )->components( ) ) ) ) );
698 else if( numNormals == 1 )
700 interpolator = RefCountPtr< const Computation::FacetInterpolatorRGB >
701 ( new Computation::FacetInterpolatorRGB1( n1 ) );
703 else if( numNormals == 2 )
705 interpolator = RefCountPtr< const Computation::FacetInterpolatorRGB >
706 ( new Computation::FacetInterpolatorRGB2( n1, n2 ) );
708 else if( numNormals == 3 )
710 interpolator = RefCountPtr< const Computation::FacetInterpolatorRGB >
711 ( new Computation::FacetInterpolatorRGB3( n1, n2, n3 ) );
713 else
715 throw Exceptions::InternalError( "Number of facet normals is out of range!" );
718 RefCountPtr< const Kernel::FacetState > facetState = evalState->dyn_->getFacetState( );
720 cont->takeValue( Kernel::ValueRef( new Lang::SingleSided3DRGB( path, interpolator,
721 ! isDoubleSided, // Note that this argument refers to single-sidedness
722 normal, Concrete::inner( normal, p0 ),
723 tiebreaker->get( ),
724 facetState->viewResolution_,
725 facetState->shadeOrder_ ) ),
726 evalState );
728 else // not isRGB
730 typedef GrayNormalType NormalType;
731 RefCountPtr< NormalType > n1 = nGray1;
732 RefCountPtr< NormalType > n2 = nGray2;
733 RefCountPtr< NormalType > n3 = nGray3;
734 RefCountPtr< const Computation::FacetInterpolatorGray > interpolator = RefCountPtr< const Computation::FacetInterpolatorGray >( NullPtr< const Computation::FacetInterpolatorGray >( ) );
736 if( numNormals == 0 )
738 typedef const Lang::Gray ColorType;
739 RefCountPtr< ColorType > lightMultiply = Helpers::down_cast_CoreDynamic< ColorType >( id_, Lang::DYNAMIC_VARIABLE_ID_NONSTROKING, nonStroking, callLoc );
740 RefCountPtr< const Kernel::FacetState > facetState = evalState->dyn_->getFacetState( );
742 interpolator = RefCountPtr< const Computation::FacetInterpolatorGray >
743 ( new Computation::FacetInterpolatorGray1
744 ( RefCountPtr< const Lang::FacetNormalGray >
745 ( new Lang::FacetNormalGray
746 ( (1./3)*( p0 + p1 + p2 ),
747 facetState->reflections_,
748 normal,
749 lightMultiply->components( ),
750 facetState->autoScattering_,
751 Helpers::down_cast_CoreDynamic< ColorType >( id_, Lang::DYNAMIC_VARIABLE_ID_AUTOINTENSITY, facetState->autoIntensity_, callLoc )->components( ) ) ) ) );
754 else if( numNormals == 1 )
756 interpolator = RefCountPtr< const Computation::FacetInterpolatorGray >
757 ( new Computation::FacetInterpolatorGray1( n1 ) );
759 else if( numNormals == 2 )
761 interpolator = RefCountPtr< const Computation::FacetInterpolatorGray >
762 ( new Computation::FacetInterpolatorGray2( n1, n2 ) );
764 else if( numNormals == 3 )
766 interpolator = RefCountPtr< const Computation::FacetInterpolatorGray >
767 ( new Computation::FacetInterpolatorGray3( n1, n2, n3 ) );
769 else
771 throw Exceptions::InternalError( "Number of facet normals is out of range!" );
774 RefCountPtr< const Kernel::FacetState > facetState = evalState->dyn_->getFacetState( );
776 cont->takeValue( Kernel::ValueRef( new Lang::SingleSided3DGray( path, interpolator,
777 ! isDoubleSided, // Note that this argument refers to single-sidedness
778 normal, Concrete::inner( normal, p0 ),
779 tiebreaker->get( ),
780 facetState->viewResolution_,
781 facetState->shadeOrder_ ) ),
782 evalState );
787 class Core_from3Dto2D : public Lang::CoreFunction
789 public:
790 Core_from3Dto2D( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
791 void
792 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
794 const size_t ARITY = 1;
795 CHECK_ARITY( args, ARITY, id_ );
797 typedef const Lang::Geometric3D ArgType;
798 RefCountPtr< ArgType > obj = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 0, callLoc );
800 Kernel::ContRef cont = evalState->cont_;
801 cont->takeValue( obj->to2D( evalState->dyn_, obj ),
802 evalState );
806 class Core_from2Dto3D : public Lang::CoreFunction
808 public:
809 Core_from2Dto3D( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
810 virtual void
811 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
813 const size_t ARITY = 1;
814 CHECK_ARITY( args, ARITY, id_ );
816 typedef const Lang::Geometric2D ArgType;
817 RefCountPtr< ArgType > obj = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 0, callLoc );
819 Kernel::ContRef cont = evalState->cont_;
820 cont->takeValue( obj->to3D( obj ),
821 evalState );
825 class Core_facing2Din3D : public Lang::CoreFunction
827 public:
828 Core_facing2Din3D( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
829 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
831 formals_->appendEvaluatedCoreFormal( "obj", Kernel::THE_SLOT_VARIABLE );
832 formals_->appendEvaluatedCoreFormal( "scale", Kernel::VariableHandle( new Kernel::Variable( Lang::THE_FALSE ) ) );
833 formals_->appendEvaluatedCoreFormal( "distort", Kernel::VariableHandle( new Kernel::Variable( Lang::THE_FALSE ) ) );
835 virtual void
836 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
838 args.applyDefaults( callLoc );
842 typedef const Lang::Drawable2D ArgType;
843 Kernel::ContRef cont = evalState->cont_;
844 cont->takeValue( Kernel::ValueRef( new Lang::Facing2Din3D( Helpers::try_cast_CoreArgument< ArgType >( args.getValue( 0 ) ),
845 Helpers::down_cast_CoreArgument< const Lang::Boolean >( id_, args, 1, callLoc )->val_,
846 Helpers::down_cast_CoreArgument< const Lang::Boolean >( id_, args, 2, callLoc )->val_ ) ),
847 evalState );
848 return;
850 catch( const NonLocalExit::NotThisType & ball )
852 /* Wrong type; never mind!.. but see below!
858 typedef const Lang::Function ArgType;
859 Kernel::ContRef cont = evalState->cont_;
860 /* The scale and distort arguments will simply be ignored.
862 cont->takeValue( Kernel::ValueRef( new Lang::FacingFunction3D( evalState->dyn_, Helpers::try_cast_CoreArgument< ArgType >( args.getValue( 0 ) ) ) ),
863 evalState );
864 return;
866 catch( const NonLocalExit::NotThisType & ball )
868 /* Wrong type; never mind!.. but see below!
872 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, 0, Helpers::typeSetString( Lang::Drawable2D::staticTypeName( ), Lang::Function::staticTypeName( ) ) );
876 class Core_bboxed : public Lang::CoreFunction
878 public:
879 Core_bboxed( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
880 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
882 formals_->appendEvaluatedCoreFormal( "obj", Kernel::THE_SLOT_VARIABLE );
883 formals_->appendEvaluatedCoreFormal( "path", Kernel::THE_SLOT_VARIABLE );
884 formals_->appendEvaluatedCoreFormal( "type", Helpers::newValHandle( new Lang::Symbol( "bounding" ) ) );
886 virtual void
887 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
889 args.applyDefaults( callLoc );
891 size_t argsi = 0;
893 typedef const Lang::Drawable2D ArgType1;
894 RefCountPtr< ArgType1 > obj = Helpers::down_cast_CoreArgument< ArgType1 >( id_, args, argsi, callLoc );
896 ++argsi;
898 typedef const Lang::ElementaryPath2D ArgType2;
899 RefCountPtr< ArgType2 > p = Helpers::elementaryPathCast2D( id_, args, argsi, callLoc );
901 ++argsi;
902 typedef const Lang::Symbol TypeType;
903 RefCountPtr< TypeType > type = Helpers::down_cast_CoreArgument< TypeType >( id_, args, argsi, callLoc );
904 Lang::BBoxed2D::BoxType bt = Lang::BBoxed2D::BOUNDING;
905 static Lang::Symbol BOUNDING( "bounding" );
906 static Lang::Symbol BLEED( "bleed" );
907 static Lang::Symbol BOTH( "both" );
908 if( *type == BOUNDING )
910 bt = Lang::BBoxed2D::BOUNDING;
912 else if( *type == BLEED )
914 bt = Lang::BBoxed2D::BLEED;
916 else if( *type == BOTH )
918 bt = Lang::BBoxed2D::BOTH;
920 else
922 std::ostringstream msg;
923 msg << "The only allowed symbols are { " ;
924 BOUNDING.show( msg );
925 msg << " , " ;
926 BLEED.show( msg );
927 msg << " , " ;
928 BOTH.show( msg );
929 msg << " }." ;
930 throw Exceptions::CoreOutOfRange( id_, args, argsi, strrefdup( msg ) );
933 Kernel::ContRef cont = evalState->cont_;
934 cont->takeValue( Kernel::ValueRef( new Lang::BBoxed2D( obj, p, bt ) ),
935 evalState );
939 class Core_clip : public Lang::CoreFunction
941 public:
942 typedef enum { NONZERO_WINDING, EVEN_ODD } WindingRule;
943 private:
944 WindingRule windingRule_;
945 public:
946 Core_clip( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name, WindingRule windingRule )
947 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) ),
948 windingRule_( windingRule )
950 formals_->appendEvaluatedCoreFormal( "obj", Kernel::THE_SLOT_VARIABLE );
951 formals_->appendEvaluatedCoreFormal( "mask", Kernel::THE_SLOT_VARIABLE );
953 virtual void
954 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
956 args.applyDefaults( callLoc );
958 size_t argsi = 0;
960 typedef const Lang::Drawable2D ArgType1;
961 RefCountPtr< ArgType1 > obj = Helpers::down_cast_CoreArgument< ArgType1 >( id_, args, argsi, callLoc );
963 RefCountPtr< Lang::Clipped2D > res( new Lang::Clipped2D( obj, ( windingRule_ == NONZERO_WINDING ) ? "W" : "W*" ) );
965 ++argsi;
968 typedef const Lang::ElementaryPath2D ArgType;
969 RefCountPtr< ArgType > path = Helpers::elementaryPathTry2D( args.getValue( argsi ) );
970 res->addSubPath( path );
971 goto done;
973 catch( const NonLocalExit::NotThisType & ball )
975 /* Wrong type; never mind!.. but see below!
981 typedef const Lang::MultiPath2D ArgType;
982 RefCountPtr< ArgType > path = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
983 for( Lang::MultiPath2D::const_iterator i = path->begin( ); i != path->end( ); ++i )
986 typedef const Lang::ElementaryPath2D ArgType;
987 RefCountPtr< ArgType > subpath = (*i).down_cast< ArgType >( );
988 if( subpath != NullPtr< ArgType >( ) )
990 res->addSubPath( subpath );
991 continue;
996 typedef const Lang::Connection2D ArgType;
997 ArgType * subpath = dynamic_cast< ArgType * >( (*i).getPtr( ) );
998 if( subpath != 0 )
1000 res->addSubPath( subpath->getElementaryPath( ) );
1001 continue;
1004 throw Exceptions::InternalError( "clip: Encountered a subpath of unexpected type" );
1006 goto done;
1008 catch( const NonLocalExit::NotThisType & ball )
1010 /* Wrong type; never mind!.. but see below!
1014 if( windingRule_ == EVEN_ODD )
1016 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, argsi, Helpers::typeSetString( Lang::ElementaryPath2D::staticTypeName( ), Lang::MultiPath2D::staticTypeName( ) ) );
1021 typedef const Lang::Text ArgType;
1022 RefCountPtr< ArgType > mask = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
1023 Kernel::ContRef cont = evalState->cont_;
1024 cont->takeValue( RefCountPtr< Lang::TextMasked2D >( new Lang::TextMasked2D( obj, mask ) ),
1025 evalState );
1026 return;
1028 catch( const NonLocalExit::NotThisType & ball )
1030 /* Wrong type; never mind!.. but see below!
1036 typedef const Lang::SoftMask ArgType;
1037 RefCountPtr< ArgType > mask = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
1038 Kernel::ContRef cont = evalState->cont_;
1039 cont->takeValue( RefCountPtr< Lang::SoftMasked2D >( new Lang::SoftMasked2D( obj, mask ) ),
1040 evalState );
1041 return;
1043 catch( const NonLocalExit::NotThisType & ball )
1045 /* Wrong type; never mind!.. but see below!
1049 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, argsi, Helpers::typeSetString( Lang::ElementaryPath2D::staticTypeName( ), Lang::MultiPath2D::staticTypeName( ), Lang::Text::staticTypeName( ), Lang::SoftMask::staticTypeName( ) ) );
1051 done:
1052 Kernel::ContRef cont = evalState->cont_;
1053 cont->takeValue( res,
1054 evalState );
1063 namespace Shapes
1065 namespace Kernel
1067 class ArrowheadReceiverFormals2D : public Kernel::EvaluatedFormals
1069 public:
1070 ArrowheadReceiverFormals2D( )
1071 : Kernel::EvaluatedFormals( Ast::FileID::build_internal( "< Arrowhead receiver >" ), true )
1073 appendEvaluatedCoreFormal( "picture", Kernel::THE_SLOT_VARIABLE );
1074 appendEvaluatedCoreFormal( "cut", Kernel::VariableHandle( new Kernel::Variable( RefCountPtr< const Lang::Value >( new Lang::Length( 0 ) ) ) ) );
1078 ArrowheadReceiverFormals2D theArrowheadReceiverFormals2D;
1080 class Stroke2DCont_tail : public Kernel::ForcedStructureContinuation
1082 RefCountPtr< const Kernel::GraphicsState > graphicsState_;
1083 RefCountPtr< const Lang::ElementaryPath2D > path_;
1084 Kernel::PassedEnv env_;
1085 Kernel::PassedDyn dyn_;
1086 Kernel::ContRef cont_;
1087 public:
1088 Stroke2DCont_tail( const RefCountPtr< const Kernel::GraphicsState > & graphicsState, const RefCountPtr< const Lang::ElementaryPath2D > & path,
1089 const Kernel::PassedEnv & env, const Kernel::PassedDyn & dyn, Kernel::ContRef cont, const Ast::SourceLocation & traceLoc )
1090 : Kernel::ForcedStructureContinuation( "Stroke's arrow tail receiver", traceLoc ), graphicsState_( graphicsState ), path_( path ), env_( env ), dyn_( dyn ), cont_( cont )
1092 virtual ~Stroke2DCont_tail( ) { }
1093 virtual void takeStructure( const RefCountPtr< const Lang::Structure > & structure, Kernel::EvalState * evalState ) const
1095 /* Argument 0: picture
1096 * Argument 1: cut
1098 Kernel::Arguments args( & theArrowheadReceiverFormals2D );
1099 structure->argList_->bind( & args, structure->values_, env_, dyn_ );
1100 args.applyDefaults( traceLoc_ );
1102 typedef const Lang::Drawable2D ArgType0;
1103 RefCountPtr< ArgType0 > picture = Helpers::down_cast_StructureContinuationArgument< ArgType0 >( continuationName_, args, 0, traceLoc_ );
1105 typedef const Lang::Length ArgType1;
1106 RefCountPtr< ArgType1 > cutTail = Helpers::down_cast_StructureContinuationArgument< ArgType1 >( continuationName_, args, 1, traceLoc_ );
1108 if( cutTail->get( ) < 0 )
1110 throw Exceptions::MiscellaneousRequirement( strrefdup( "Arrow tail cut length was negative." ) );
1112 else if( cutTail->get( ) == 0 )
1114 cont_->takeValue( Helpers::newSolidTransparencyGroup( picture,
1115 RefCountPtr< const Lang::Drawable2D >( new Lang::PaintedPath2D( graphicsState_, path_, "S" ) ) ),
1116 evalState );
1118 else
1120 Concrete::SplineTime t1 = path_->arcTime( cutTail->get( ) );
1121 Concrete::SplineTime t2( HUGE_VAL );
1122 RefCountPtr< const Lang::ElementaryPath2D > subpath = path_->subpath( t1, t2 );
1123 if( ! subpath->empty( ) )
1125 cont_->takeValue( Helpers::newSolidTransparencyGroup( picture,
1126 RefCountPtr< const Lang::Drawable2D >( new Lang::PaintedPath2D( graphicsState_, subpath, "S" ) ) ),
1127 evalState );
1129 else
1131 cont_->takeValue( picture,
1132 evalState );
1137 virtual Kernel::ContRef up( ) const
1139 return cont_;
1141 virtual RefCountPtr< const char > description( ) const
1143 return strrefdup( "2D stroke's tail" );
1145 virtual void gcMark( Kernel::GCMarkedSet & marked )
1147 cont_->gcMark( marked );
1151 class Stroke2DCont_head : public Kernel::ForcedStructureContinuation
1153 RefCountPtr< const Kernel::GraphicsState > graphicsState_;
1154 RefCountPtr< const Lang::ElementaryPath2D > path_;
1155 Kernel::PassedEnv env_;
1156 Kernel::PassedDyn dyn_;
1157 Kernel::ContRef cont_;
1158 public:
1159 Stroke2DCont_head( const RefCountPtr< const Kernel::GraphicsState > & graphicsState, const RefCountPtr< const Lang::ElementaryPath2D > & path,
1160 const Kernel::PassedEnv & env, const Kernel::PassedDyn & dyn, Kernel::ContRef cont, const Ast::SourceLocation & traceLoc )
1161 : Kernel::ForcedStructureContinuation( "Stroke's arrow tail receiver", traceLoc ), graphicsState_( graphicsState ), path_( path ), env_( env ), dyn_( dyn ), cont_( cont )
1163 virtual ~Stroke2DCont_head( ) { }
1164 virtual void takeStructure( const RefCountPtr< const Lang::Structure > & structure, Kernel::EvalState * evalState ) const
1166 /* Argument 0: picture
1167 * Argument 1: cut
1169 Kernel::Arguments args( & theArrowheadReceiverFormals2D );
1170 structure->argList_->bind( & args, structure->values_, env_, dyn_ );
1171 args.applyDefaults( traceLoc_ );
1173 typedef const Lang::Drawable2D ArgType0;
1174 RefCountPtr< ArgType0 > picture = Helpers::down_cast_StructureContinuationArgument< ArgType0 >( continuationName_, args, 0, traceLoc_ );
1176 typedef const Lang::Length ArgType1;
1177 RefCountPtr< ArgType1 > cutHead = Helpers::down_cast_StructureContinuationArgument< ArgType1 >( continuationName_, args, 1, traceLoc_ );
1179 if( cutHead->get( ) < 0 )
1181 throw Exceptions::MiscellaneousRequirement( strrefdup( "Arrow head cut length was negative." ) );
1183 else if( cutHead->get( ) == 0 )
1185 cont_->takeValue( Helpers::newSolidTransparencyGroup( picture,
1186 RefCountPtr< const Lang::Drawable2D >( new Lang::PaintedPath2D( graphicsState_, path_, "S" ) ) ),
1187 evalState );
1189 else
1191 Concrete::SplineTime t1( 0 );
1192 Concrete::SplineTime t2 = path_->arcTime( path_->arcLength( ) - cutHead->get( ) );
1193 RefCountPtr< const Lang::ElementaryPath2D > subpath = path_->subpath( t1, t2 );
1194 if( ! subpath->empty( ) )
1196 cont_->takeValue( Helpers::newSolidTransparencyGroup( picture,
1197 RefCountPtr< const Lang::Drawable2D >( new Lang::PaintedPath2D( graphicsState_, subpath, "S" ) ) ),
1198 evalState );
1200 else
1202 cont_->takeValue( picture,
1203 evalState );
1207 virtual Kernel::ContRef up( ) const
1209 return cont_;
1211 virtual RefCountPtr< const char > description( ) const
1213 return strrefdup( "2D stroke's head" );
1215 virtual void gcMark( Kernel::GCMarkedSet & marked )
1217 cont_->gcMark( marked );
1221 class Stroke2DCont_both2 : public Kernel::ForcedStructureContinuation
1223 RefCountPtr< const Kernel::GraphicsState > graphicsState_;
1224 RefCountPtr< const Lang::ElementaryPath2D > path_;
1225 RefCountPtr< const Lang::Drawable2D > tail_;
1226 Lang::Length cutTail_;
1227 Kernel::PassedEnv env_;
1228 Kernel::PassedDyn dyn_;
1229 Kernel::ContRef cont_;
1230 public:
1231 Stroke2DCont_both2( const RefCountPtr< const Kernel::GraphicsState > & graphicsState, const RefCountPtr< const Lang::ElementaryPath2D > & path,
1232 const RefCountPtr< const Lang::Drawable2D > & tail, Lang::Length cutTail,
1233 const Kernel::PassedEnv & env, const Kernel::PassedDyn & dyn, Kernel::ContRef cont, const Ast::SourceLocation & traceLoc )
1234 : Kernel::ForcedStructureContinuation( "Stroke's arrow head receiver", traceLoc ), graphicsState_( graphicsState ), path_( path ), tail_( tail ), cutTail_( cutTail ), env_( env ), dyn_( dyn ), cont_( cont )
1236 virtual ~Stroke2DCont_both2( ) { }
1237 virtual void takeStructure( const RefCountPtr< const Lang::Structure > & structure, Kernel::EvalState * evalState ) const
1239 /* Argument 0: picture
1240 * Argument 1: cut
1242 Kernel::Arguments args( & theArrowheadReceiverFormals2D );
1243 structure->argList_->bind( & args, structure->values_, env_, dyn_ );
1244 args.applyDefaults( traceLoc_ );
1246 typedef const Lang::Drawable2D ArgType0;
1247 RefCountPtr< ArgType0 > picture = Helpers::down_cast_StructureContinuationArgument< ArgType0 >( continuationName_, args, 0, traceLoc_ );
1249 typedef const Lang::Length ArgType1;
1250 RefCountPtr< ArgType1 > cutHead = Helpers::down_cast_StructureContinuationArgument< ArgType1 >( continuationName_, args, 1, traceLoc_ );
1252 if( cutHead->get( ) < 0 )
1254 throw Exceptions::MiscellaneousRequirement( strrefdup( "Aarrow head cut length was negative." ) );
1257 if( cutTail_.get( ) == 0 && cutHead->get( ) == 0 )
1259 cont_->takeValue( Helpers::newSolidTransparencyGroup( picture,
1260 tail_,
1261 RefCountPtr< const Lang::Drawable2D >( new Lang::PaintedPath2D( graphicsState_, path_, "S" ) ) ),
1262 evalState );
1264 else
1266 Concrete::SplineTime t1( 0 );
1267 if( cutTail_.get( ) > 0 )
1269 t1 = path_->arcTime( cutTail_.get( ) );
1272 Concrete::SplineTime t2( HUGE_VAL );
1273 if( cutHead->get( ) > 0 )
1275 t2 = path_->arcTime( path_->arcLength( ) - cutHead->get( ) );
1278 RefCountPtr< const Lang::ElementaryPath2D > subpath = path_->subpath( t1, t2 );
1280 if( ! subpath->empty( ) )
1282 cont_->takeValue( Helpers::newSolidTransparencyGroup( picture,
1283 tail_,
1284 RefCountPtr< const Lang::Drawable2D >( new Lang::PaintedPath2D( graphicsState_, subpath, "S" ) ) ),
1285 evalState );
1287 else
1289 cont_->takeValue( Helpers::newSolidTransparencyGroup( picture,
1290 tail_ ),
1291 evalState );
1295 virtual Kernel::ContRef up( ) const
1297 return cont_;
1299 virtual RefCountPtr< const char > description( ) const
1301 return strrefdup( "2D stroke's head & tail, second" );
1303 virtual void gcMark( Kernel::GCMarkedSet & marked )
1305 const_cast< Lang::Drawable2D * >( tail_.getPtr( ) )->gcMark( marked );
1306 cont_->gcMark( marked );
1310 class Stroke2DCont_both1 : public Kernel::ForcedStructureContinuation
1312 RefCountPtr< const Kernel::GraphicsState > graphicsState_;
1313 RefCountPtr< const Lang::ElementaryPath2D > path_;
1314 RefCountPtr< const Lang::Function > headFunction_;
1315 Kernel::PassedEnv env_;
1316 Kernel::PassedDyn dyn_;
1317 Kernel::ContRef cont_;
1318 public:
1319 Stroke2DCont_both1( const RefCountPtr< const Kernel::GraphicsState > & graphicsState, const RefCountPtr< const Lang::ElementaryPath2D > & path,
1320 const RefCountPtr< const Lang::Function > & headFunction,
1321 const Kernel::PassedEnv & env, const Kernel::PassedDyn & dyn, Kernel::ContRef cont, const Ast::SourceLocation & traceLoc )
1322 : Kernel::ForcedStructureContinuation( "Stroke's arrow tail receiver", traceLoc ), graphicsState_( graphicsState ), path_( path ), headFunction_( headFunction ), env_( env ), dyn_( dyn ), cont_( cont )
1324 virtual ~Stroke2DCont_both1( ) { }
1325 virtual void takeStructure( const RefCountPtr< const Lang::Structure > & structure, Kernel::EvalState * evalState ) const
1327 /* Argument 0: picture
1328 * Argument 1: cut
1330 Kernel::Arguments args( & theArrowheadReceiverFormals2D );
1331 structure->argList_->bind( & args, structure->values_, env_, dyn_ );
1332 args.applyDefaults( traceLoc_ );
1334 typedef const Lang::Drawable2D ArgType0;
1335 RefCountPtr< ArgType0 > picture = Helpers::down_cast_StructureContinuationArgument< ArgType0 >( continuationName_, args, 0, traceLoc_ );
1337 typedef const Lang::Length ArgType1;
1338 RefCountPtr< ArgType1 > cutTail = Helpers::down_cast_StructureContinuationArgument< ArgType1 >( continuationName_, args, 1, traceLoc_ );
1340 if( cutTail->get( ) < 0 )
1342 throw Exceptions::MiscellaneousRequirement( strrefdup( "Arrow tail cut length was negative." ) );
1345 evalState->env_ = env_;
1346 evalState->dyn_ = dyn_;
1347 evalState->cont_ = Kernel::ContRef( new Kernel::Stroke2DCont_both2( graphicsState_, path_, picture, *cutTail, env_, dyn_, cont_, traceLoc_ ) );
1348 headFunction_->call( evalState, path_->reverse( ), traceLoc_ );
1350 virtual Kernel::ContRef up( ) const
1352 return cont_;
1354 virtual RefCountPtr< const char > description( ) const
1356 return strrefdup( "2D stroke's head & tail, first" );
1358 virtual void gcMark( Kernel::GCMarkedSet & marked )
1360 const_cast< Lang::Function * >( headFunction_.getPtr( ) )->gcMark( marked );
1361 dyn_->gcMark( marked );
1362 cont_->gcMark( marked );
1371 void
1372 Helpers::stroke_helper_2D( Kernel::EvalState * evalState, const RefCountPtr< const Lang::ElementaryPath2D > & path, Kernel::Arguments & args, bool fill, const Ast::SourceLocation & callLoc )
1374 RefCountPtr< const Lang::Function > arrowHead = args.getHandle( 1 )->getVal< const Lang::Function >( "< core function stroke: head >" );
1375 RefCountPtr< const Lang::Function > arrowTail = args.getHandle( 2 )->getVal< const Lang::Function >( "< core function stroke: tail >" );
1376 if( ( arrowHead == Lang::THE_NO_ARROW &&
1377 arrowTail == Lang::THE_NO_ARROW ) ||
1378 path->size( ) < 2 )
1380 Kernel::ContRef cont = evalState->cont_;
1381 cont->takeValue( Kernel::ValueRef( new Lang::PaintedPath2D( evalState->dyn_->getGraphicsState( ), path, fill ? "B" : "S" ) ),
1382 evalState );
1383 return;
1385 else
1387 /* The computation must continue outside here since functions are to be called, and resulting graphics collected.
1389 if( fill )
1391 throw Exceptions::NotImplemented( "Arrowheads in fill-stroke command." );
1394 if( arrowTail == Lang::THE_NO_ARROW )
1396 /* There's only an arrow at the head.
1398 evalState->cont_ = Kernel::ContRef( new Kernel::Stroke2DCont_head( evalState->dyn_->getGraphicsState( ), path, evalState->env_, evalState->dyn_, evalState->cont_, callLoc ) );
1399 arrowHead->call( evalState, path->reverse( ), callLoc );
1400 return;
1403 if( arrowHead == Lang::THE_NO_ARROW )
1405 /* There's only an arrow at the tail.
1407 evalState->cont_ = Kernel::ContRef( new Kernel::Stroke2DCont_tail( evalState->dyn_->getGraphicsState( ), path, evalState->env_, evalState->dyn_, evalState->cont_, callLoc ) );
1408 arrowHead->call( arrowTail, evalState, args.getHandle( 0 ), callLoc );
1409 return;
1412 evalState->cont_ = Kernel::ContRef( new Kernel::Stroke2DCont_both1( evalState->dyn_->getGraphicsState( ), path, arrowHead, evalState->env_, evalState->dyn_, evalState->cont_, callLoc ) );
1413 arrowTail->call( arrowTail, evalState, args.getHandle( 0 ), callLoc );
1414 return;
1419 namespace Shapes
1421 namespace Kernel
1423 class ArrowheadReceiverFormals3D : public Kernel::EvaluatedFormals
1425 public:
1426 ArrowheadReceiverFormals3D( )
1427 : Kernel::EvaluatedFormals( Ast::FileID::build_internal( "< Arrowhead receiver (3D) >" ), true )
1429 appendEvaluatedCoreFormal( "picture", Kernel::THE_SLOT_VARIABLE );
1430 appendEvaluatedCoreFormal( "cut", Kernel::VariableHandle( new Kernel::Variable( RefCountPtr< const Lang::Value >( new Lang::Length( 0 ) ) ) ) );
1434 ArrowheadReceiverFormals3D theArrowheadReceiverFormals3D;
1436 class Stroke3DCont_tail : public Kernel::ForcedStructureContinuation
1438 RefCountPtr< const Kernel::GraphicsState > graphicsState_;
1439 RefCountPtr< const Lang::ElementaryPath3D > path_;
1440 Kernel::PassedEnv env_;
1441 Kernel::PassedDyn dyn_;
1442 Kernel::ContRef cont_;
1443 public:
1444 Stroke3DCont_tail( const RefCountPtr< const Kernel::GraphicsState > & graphicsState, const RefCountPtr< const Lang::ElementaryPath3D > & path,
1445 const Kernel::PassedEnv & env, const Kernel::PassedDyn & dyn, Kernel::ContRef cont, const Ast::SourceLocation & traceLoc )
1446 : Kernel::ForcedStructureContinuation( "Stroke's arrow tail receiver", traceLoc ), graphicsState_( graphicsState ), path_( path ), env_( env ), dyn_( dyn ), cont_( cont )
1448 virtual ~Stroke3DCont_tail( ) { }
1449 virtual void takeStructure( const RefCountPtr< const Lang::Structure > & structure, Kernel::EvalState * evalState ) const
1451 /* Argument 0: picture
1452 * Argument 1: cut
1454 Kernel::Arguments args( & theArrowheadReceiverFormals3D );
1455 structure->argList_->bind( & args, structure->values_, env_, dyn_ );
1456 args.applyDefaults( traceLoc_ );
1458 typedef const Lang::Drawable3D ArgType0;
1459 RefCountPtr< ArgType0 > picture = Helpers::down_cast_StructureContinuationArgument< ArgType0 >( continuationName_, args, 0, traceLoc_ );
1461 typedef const Lang::Length ArgType1;
1462 RefCountPtr< ArgType1 > cutTail = Helpers::down_cast_StructureContinuationArgument< ArgType1 >( continuationName_, args, 1, traceLoc_ );
1464 if( cutTail->get( ) < 0 )
1466 throw Exceptions::MiscellaneousRequirement( strrefdup( "Arrow tail cut length was negative." ) );
1468 else if( cutTail->get( ) == 0 )
1470 cont_->takeValue( Helpers::newGroup3D( evalState->dyn_->getGraphicsState( ),
1471 picture,
1472 RefCountPtr< const Lang::Drawable3D >( new Lang::PaintedPath3D( graphicsState_, path_, "S" ) ) ),
1473 evalState );
1475 else
1477 Concrete::SplineTime t1 = path_->arcTime( cutTail->get( ) );
1478 Concrete::SplineTime t2( HUGE_VAL );
1479 RefCountPtr< const Lang::ElementaryPath3D > subpath = path_->subpath( t1, t2 );
1480 if( ! subpath->empty( ) )
1482 cont_->takeValue( Helpers::newGroup3D( evalState->dyn_->getGraphicsState( ),
1483 picture,
1484 RefCountPtr< const Lang::Drawable3D >( new Lang::PaintedPath3D( graphicsState_, subpath, "S" ) ) ),
1485 evalState );
1487 else
1489 cont_->takeValue( picture,
1490 evalState );
1495 virtual Kernel::ContRef up( ) const
1497 return cont_;
1499 virtual RefCountPtr< const char > description( ) const
1501 return strrefdup( "3D stroke's tail" );
1503 virtual void gcMark( Kernel::GCMarkedSet & marked )
1505 cont_->gcMark( marked );
1509 class Stroke3DCont_head : public Kernel::ForcedStructureContinuation
1511 RefCountPtr< const Kernel::GraphicsState > graphicsState_;
1512 RefCountPtr< const Lang::ElementaryPath3D > path_;
1513 Kernel::PassedEnv env_;
1514 Kernel::PassedDyn dyn_;
1515 Kernel::ContRef cont_;
1516 public:
1517 Stroke3DCont_head( const RefCountPtr< const Kernel::GraphicsState > & graphicsState, const RefCountPtr< const Lang::ElementaryPath3D > & path,
1518 const Kernel::PassedEnv & env, const Kernel::PassedDyn & dyn, Kernel::ContRef cont, const Ast::SourceLocation & traceLoc )
1519 : Kernel::ForcedStructureContinuation( "Stroke's arrow tail receiver", traceLoc ), graphicsState_( graphicsState ), path_( path ), env_( env ), dyn_( dyn ), cont_( cont )
1521 virtual ~Stroke3DCont_head( ) { }
1522 virtual void takeStructure( const RefCountPtr< const Lang::Structure > & structure, Kernel::EvalState * evalState ) const
1524 /* Argument 0: picture
1525 * Argument 1: cut
1527 Kernel::Arguments args( & theArrowheadReceiverFormals3D );
1528 structure->argList_->bind( & args, structure->values_, env_, dyn_ );
1529 args.applyDefaults( traceLoc_ );
1531 typedef const Lang::Drawable3D ArgType0;
1532 RefCountPtr< ArgType0 > picture = Helpers::down_cast_StructureContinuationArgument< ArgType0 >( continuationName_, args, 0, traceLoc_ );
1534 typedef const Lang::Length ArgType1;
1535 RefCountPtr< ArgType1 > cutHead = Helpers::down_cast_StructureContinuationArgument< ArgType1 >( continuationName_, args, 1, traceLoc_ );
1537 if( cutHead->get( ) < 0 )
1539 throw Exceptions::MiscellaneousRequirement( strrefdup( "Arrow head cut length was negative." ) );
1541 else if( cutHead->get( ) == 0 )
1543 cont_->takeValue( Helpers::newGroup3D( evalState->dyn_->getGraphicsState( ),
1544 picture,
1545 RefCountPtr< const Lang::Drawable3D >( new Lang::PaintedPath3D( graphicsState_, path_, "S" ) ) ),
1546 evalState );
1548 else
1550 Concrete::SplineTime t1( 0 );
1551 Concrete::SplineTime t2 = path_->arcTime( path_->arcLength( ) - cutHead->get( ) );
1552 RefCountPtr< const Lang::ElementaryPath3D > subpath = path_->subpath( t1, t2 );
1553 if( ! subpath->empty( ) )
1555 cont_->takeValue( Helpers::newGroup3D( evalState->dyn_->getGraphicsState( ),
1556 picture,
1557 RefCountPtr< const Lang::Drawable3D >( new Lang::PaintedPath3D( graphicsState_, subpath, "S" ) ) ),
1558 evalState );
1560 else
1562 cont_->takeValue( picture,
1563 evalState );
1567 virtual Kernel::ContRef up( ) const
1569 return cont_;
1571 virtual RefCountPtr< const char > description( ) const
1573 return strrefdup( "3D stroke's head" );
1575 virtual void gcMark( Kernel::GCMarkedSet & marked )
1577 cont_->gcMark( marked );
1581 class Stroke3DCont_both2 : public Kernel::ForcedStructureContinuation
1583 RefCountPtr< const Kernel::GraphicsState > graphicsState_;
1584 RefCountPtr< const Lang::ElementaryPath3D > path_;
1585 RefCountPtr< const Lang::Drawable3D > tail_;
1586 Lang::Length cutTail_;
1587 Kernel::PassedEnv env_;
1588 Kernel::PassedDyn dyn_;
1589 Kernel::ContRef cont_;
1590 public:
1591 Stroke3DCont_both2( const RefCountPtr< const Kernel::GraphicsState > & graphicsState, const RefCountPtr< const Lang::ElementaryPath3D > & path,
1592 const RefCountPtr< const Lang::Drawable3D > & tail, Lang::Length cutTail,
1593 const Kernel::PassedEnv & env, const Kernel::PassedDyn & dyn, Kernel::ContRef cont, const Ast::SourceLocation & traceLoc )
1594 : Kernel::ForcedStructureContinuation( "Stroke's arrow head receiver", traceLoc ), graphicsState_( graphicsState ), path_( path ), tail_( tail ), cutTail_( cutTail ), env_( env ), dyn_( dyn ), cont_( cont )
1596 virtual ~Stroke3DCont_both2( ) { }
1597 virtual void takeStructure( const RefCountPtr< const Lang::Structure > & structure, Kernel::EvalState * evalState ) const
1599 /* Argument 0: picture
1600 * Argument 1: cut
1602 Kernel::Arguments args( & theArrowheadReceiverFormals3D );
1603 structure->argList_->bind( & args, structure->values_, env_, dyn_ );
1604 args.applyDefaults( traceLoc_ );
1606 typedef const Lang::Drawable3D ArgType0;
1607 RefCountPtr< ArgType0 > picture = Helpers::down_cast_StructureContinuationArgument< ArgType0 >( continuationName_, args, 0, traceLoc_ );
1609 typedef const Lang::Length ArgType1;
1610 RefCountPtr< ArgType1 > cutHead = Helpers::down_cast_StructureContinuationArgument< ArgType1 >( continuationName_, args, 1, traceLoc_ );
1612 if( cutHead->get( ) < 0 )
1614 throw Exceptions::MiscellaneousRequirement( strrefdup( "Aarrow head cut length was negative." ) );
1617 if( cutTail_.get( ) == 0 && cutHead->get( ) == 0 )
1619 cont_->takeValue( Helpers::newGroup3D( evalState->dyn_->getGraphicsState( ),
1620 picture,
1621 tail_,
1622 RefCountPtr< const Lang::Drawable3D >( new Lang::PaintedPath3D( graphicsState_, path_, "S" ) ) ),
1623 evalState );
1625 else
1627 Concrete::SplineTime t1( 0 );
1628 if( cutTail_.get( ) > 0 )
1630 t1 = path_->arcTime( cutTail_.get( ) );
1633 Concrete::SplineTime t2( HUGE_VAL );
1634 if( cutHead->get( ) > 0 )
1636 t2 = path_->arcTime( path_->arcLength( ) - cutHead->get( ) );
1639 RefCountPtr< const Lang::ElementaryPath3D > subpath = path_->subpath( t1, t2 );
1641 if( ! subpath->empty( ) )
1643 cont_->takeValue( Helpers::newGroup3D( evalState->dyn_->getGraphicsState( ),
1644 picture,
1645 tail_,
1646 RefCountPtr< const Lang::Drawable3D >( new Lang::PaintedPath3D( graphicsState_, subpath, "S" ) ) ),
1647 evalState );
1649 else
1651 cont_->takeValue( Helpers::newGroup3D( evalState->dyn_->getGraphicsState( ),
1652 picture,
1653 tail_ ),
1654 evalState );
1658 virtual Kernel::ContRef up( ) const
1660 return cont_;
1662 virtual RefCountPtr< const char > description( ) const
1664 return strrefdup( "3D stroke's head & tail, second" );
1666 virtual void gcMark( Kernel::GCMarkedSet & marked )
1668 const_cast< Lang::Drawable3D * >( tail_.getPtr( ) )->gcMark( marked );
1669 cont_->gcMark( marked );
1673 class Stroke3DCont_both1 : public Kernel::ForcedStructureContinuation
1675 RefCountPtr< const Kernel::GraphicsState > graphicsState_;
1676 RefCountPtr< const Lang::ElementaryPath3D > path_;
1677 RefCountPtr< const Lang::Function > headFunction_;
1678 Kernel::PassedEnv env_;
1679 Kernel::PassedDyn dyn_;
1680 Kernel::ContRef cont_;
1681 public:
1682 Stroke3DCont_both1( const RefCountPtr< const Kernel::GraphicsState > & graphicsState, const RefCountPtr< const Lang::ElementaryPath3D > & path,
1683 const RefCountPtr< const Lang::Function > & headFunction,
1684 const Kernel::PassedEnv & env, const Kernel::PassedDyn & dyn, Kernel::ContRef cont, const Ast::SourceLocation & traceLoc )
1685 : Kernel::ForcedStructureContinuation( "Stroke's arrow tail receiver", traceLoc ), graphicsState_( graphicsState ), path_( path ), headFunction_( headFunction ), env_( env ), dyn_( dyn ), cont_( cont )
1687 virtual ~Stroke3DCont_both1( ) { }
1688 virtual void takeStructure( const RefCountPtr< const Lang::Structure > & structure, Kernel::EvalState * evalState ) const
1690 /* Argument 0: picture
1691 * Argument 1: cut
1693 Kernel::Arguments args( & theArrowheadReceiverFormals3D );
1694 structure->argList_->bind( & args, structure->values_, env_, dyn_ );
1695 args.applyDefaults( traceLoc_ );
1697 typedef const Lang::Drawable3D ArgType0;
1698 RefCountPtr< ArgType0 > picture = Helpers::down_cast_StructureContinuationArgument< ArgType0 >( continuationName_, args, 0, traceLoc_ );
1700 typedef const Lang::Length ArgType1;
1701 RefCountPtr< ArgType1 > cutTail = Helpers::down_cast_StructureContinuationArgument< ArgType1 >( continuationName_, args, 1, traceLoc_ );
1703 if( cutTail->get( ) < 0 )
1705 throw Exceptions::MiscellaneousRequirement( strrefdup( "Arrow tail cut length was negative." ) );
1708 evalState->env_ = env_;
1709 evalState->dyn_ = dyn_;
1710 evalState->cont_ = Kernel::ContRef( new Kernel::Stroke3DCont_both2( graphicsState_, path_, picture, *cutTail, env_, dyn_, cont_, traceLoc_ ) );
1711 headFunction_->call( evalState, path_->reverse( ), traceLoc_ );
1713 virtual Kernel::ContRef up( ) const
1715 return cont_;
1717 virtual RefCountPtr< const char > description( ) const
1719 return strrefdup( "3D stroke's head & tail, first" );
1721 virtual void gcMark( Kernel::GCMarkedSet & marked )
1723 const_cast< Lang::Function * >( headFunction_.getPtr( ) )->gcMark( marked );
1724 dyn_->gcMark( marked );
1725 cont_->gcMark( marked );
1733 void
1734 Helpers::stroke_helper_3D( Kernel::EvalState * evalState, const RefCountPtr< const Lang::ElementaryPath3D > & path, Kernel::Arguments & args, bool fill, const Ast::SourceLocation & callLoc )
1736 RefCountPtr< const Lang::Function > arrowHead = args.getHandle( 1 )->getVal< const Lang::Function >( "< core function stroke: head >" );
1737 RefCountPtr< const Lang::Function > arrowTail = args.getHandle( 2 )->getVal< const Lang::Function >( "< core function stroke: tail >" );
1738 if( ( arrowHead == Lang::THE_NO_ARROW &&
1739 arrowTail == Lang::THE_NO_ARROW ) ||
1740 path->size( ) < 2 )
1742 Kernel::ContRef cont = evalState->cont_;
1743 cont->takeValue( Kernel::ValueRef( new Lang::PaintedPath3D( evalState->dyn_->getGraphicsState( ), path, fill ? "B" : "S" ) ),
1744 evalState );
1745 return;
1747 else
1749 /* The computation must continue outside here since functions are to be called, and resulting graphics collected.
1751 if( fill )
1753 throw Exceptions::NotImplemented( "Arrowheads in fill-stroke command." );
1756 if( arrowTail == Lang::THE_NO_ARROW )
1758 /* There's only an arrow at the head.
1760 evalState->cont_ = Kernel::ContRef( new Kernel::Stroke3DCont_head( evalState->dyn_->getGraphicsState( ), path, evalState->env_, evalState->dyn_, evalState->cont_, callLoc ) );
1761 arrowHead->call( evalState, path->reverse( ), callLoc );
1762 return;
1765 if( arrowHead == Lang::THE_NO_ARROW )
1767 /* There's only an arrow at the tail.
1769 evalState->cont_ = Kernel::ContRef( new Kernel::Stroke3DCont_tail( evalState->dyn_->getGraphicsState( ), path, evalState->env_, evalState->dyn_, evalState->cont_, callLoc ) );
1770 arrowHead->call( arrowTail, evalState, args.getHandle( 0 ), callLoc );
1771 return;
1774 evalState->cont_ = Kernel::ContRef( new Kernel::Stroke3DCont_both1( evalState->dyn_->getGraphicsState( ), path, arrowHead, evalState->env_, evalState->dyn_, evalState->cont_, callLoc ) );
1775 arrowTail->call( arrowTail, evalState, args.getHandle( 0 ), callLoc );
1776 return;
1781 void
1782 Kernel::registerCore_draw( Kernel::Environment * env )
1784 env->initDefineCoreFunction( new Lang::Core_spot( Lang::THE_NAMESPACE_Shapes_Graphics, "spot" ) );
1785 env->initDefineCoreFunction( new Lang::Core_stroke( Lang::THE_NAMESPACE_Shapes_Graphics, "stroke", false ) );
1786 env->initDefineCoreFunction( new Lang::Core_stroke( Lang::THE_NAMESPACE_Shapes_Graphics, "fillstroke", true ) );
1787 env->initDefineCoreFunction( new Lang::Core_fill( Lang::THE_NAMESPACE_Shapes_Graphics, "fill" ) );
1788 env->initDefineCoreFunction( new Lang::Core_fillstar( Lang::THE_NAMESPACE_Shapes_Graphics, "fillodd" ) );
1789 env->initDefineCoreFunction( new Lang::Core_facetnormal( Lang::THE_NAMESPACE_Shapes_Graphics3D, "facetnormal" ) );
1790 env->initDefineCoreFunction( new Lang::Core_facet( Lang::THE_NAMESPACE_Shapes_Graphics3D, "facet" ) );
1792 env->initDefineCoreFunction( new Lang::Core_bboxed( Lang::THE_NAMESPACE_Shapes_Layout, "bboxed" ) );
1793 env->initDefineCoreFunction( new Lang::Core_clip( Lang::THE_NAMESPACE_Shapes_Graphics, "clip", Lang::Core_clip::NONZERO_WINDING ) );
1794 env->initDefineCoreFunction( new Lang::Core_clip( Lang::THE_NAMESPACE_Shapes_Graphics, "clipodd", Lang::Core_clip::EVEN_ODD ) );
1796 env->initDefineCoreFunction( new Lang::Core_from3Dto2D( Lang::THE_NAMESPACE_Shapes_Geometry3D, "view" ) );
1797 env->initDefineCoreFunction( new Lang::Core_from2Dto3D( Lang::THE_NAMESPACE_Shapes_Geometry3D, "immerse" ) );
1798 env->initDefineCoreFunction( new Lang::Core_facing2Din3D( Lang::THE_NAMESPACE_Shapes_Graphics3D, "facing" ) );