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
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
21 #include "shapestypes.h"
22 #include "shapesexceptions.h"
25 #include "angleselect.h"
28 #include "elementarycoords.h"
34 using namespace Shapes
;
41 RefCountPtr
< const Lang::Class
> Lang::Void::TypeID( new Lang::SystemFinalClass( strrefdup( "Void" ) ) );
45 Lang::Void::show( std::ostream
& os
) const
50 Lang::Symbol::NameTableType
Lang::Symbol::nameTable
;
51 Lang::Symbol::ReverseTableType
Lang::Symbol::reverseTable
;
52 int Lang::Symbol::nextUnique
= -1;
54 /* The following global variables used to be in globals.cc, but now they are here to ensure they get initialized after the static variables in Lang::Symbol.
56 RefCountPtr
< const Lang::Symbol
> Kernel::THE_NAVIGATION_SYMBOL( ".navigation" ); /* Note that the leading dot puts this symbol aside all user-symbols. */
57 RefCountPtr
< const Lang::Symbol
> Kernel::THE_ANNOTATION_SYMBOL( ".annotation" ); /* Note that the leading dot puts this symbol aside all user-symbols. */
59 Lang::Symbol::Symbol( )
65 DISPATCHIMPL( Symbol
);
67 Lang::Symbol::Symbol( int key
)
71 throw Exceptions::InternalError( "Only the key 0 may be used when creating symbols with a given key." );
76 Lang::Symbol::Symbol( const char * name
)
78 NameTableType::const_iterator i
= nameTable
.find( name
);
79 if( i
!= nameTable
.end( ) )
85 const char * nameCopy
= strdup( name
);
86 key_
= nameTable
.size( ) + 1;
87 nameTable
[ nameCopy
] = key_
;
88 reverseTable
.insert( ReverseTableType::value_type( key_
, RefCountPtr
< const char >( nameCopy
) ) );
93 Lang::Symbol::operator == ( const Symbol
& other
) const
95 return key_
== other
.key_
;
99 Lang::Symbol::operator != ( const Symbol
& other
) const
101 return key_
!= other
.key_
;
105 Lang::Symbol::operator < ( const Symbol
& other
) const
107 return key_
< other
.key_
;
111 Lang::Symbol::operator > ( const Symbol
& other
) const
113 return key_
> other
.key_
;
117 Lang::Symbol::operator <= ( const Symbol
& other
) const
119 return key_
<= other
.key_
;
123 Lang::Symbol::operator >= ( const Symbol
& other
) const
125 return key_
>= other
.key_
;
129 Lang::Symbol::isUnique( ) const
134 RefCountPtr
< const char >
135 Lang::Symbol::name( ) const
139 ReverseTableType::const_iterator i
= reverseTable
.find( key_
);
140 if( i
== reverseTable
.end( ) )
142 throw Exceptions::InternalError( "The reverse symbol table did not include the sought key." );
148 return strrefdup( "<unique>" );
150 return strrefdup( "<dummy>" );
153 RefCountPtr
< const char >
154 Lang::Symbol::nameFromKey( KeyType key
)
158 throw Exceptions::MiscellaneousRequirement( "If is forbidden to ask for the name of a unique symbol." );
160 ReverseTableType::const_iterator i
= reverseTable
.find( key
);
161 if( i
== reverseTable
.end( ) )
163 throw Exceptions::InternalError( "The reverse symbol table did not include the sought key." );
169 RefCountPtr
< const Lang::Class
> Lang::Symbol::TypeID( new Lang::SystemFinalClass( strrefdup( "Symbol" ) ) );
170 TYPEINFOIMPL( Symbol
);
173 Lang::Symbol::show( std::ostream
& os
) const
186 DISPATCHIMPL( Float
);
188 RefCountPtr
< const Lang::Class
> Lang::Float::TypeID( new Lang::SystemFinalClass( strrefdup( "Float" ) ) );
189 TYPEINFOIMPL( Float
);
192 Lang::Float::show( std::ostream
& os
) const
200 RefCountPtr
< const Lang::Class
> Lang::Integer::TypeID( new Lang::SystemFinalClass( strrefdup( "Integer" ) ) );
201 TYPEINFOIMPL( Integer
);
204 Lang::Integer::show( std::ostream
& os
) const
210 Lang::Length::Length( double val )
211 : isOffset_( false ), val_( val )
214 Lang::Length::Length( bool isOffset, double val )
215 : isOffset_( _isOffset ), val_( _val )
218 DISPATCHIMPL( Length
);
221 Lang::Length::get( Concrete::Length baseLength
) const
225 return baseLength
+ val_
;
231 Lang::Length::get( ) const
235 throw Exceptions::MiscellaneousRequirement( "Offset lengths are not allowed here." );
241 Lang::Length::getScalar( Concrete::Length baseLength
) const
245 return ( baseLength
+ val_
).offtype
< 1, 0 >( );
247 return val_
.offtype
< 1, 0 >( );
251 Lang::Length::getScalar( ) const
255 throw Exceptions::MiscellaneousRequirement( "Offset lengths are not allowed here." );
257 return val_
.offtype
< 1, 0 >( );
261 Lang::Length::operator + ( const Lang::Length
& term
) const
265 throw Exceptions::MiscellaneousRequirement( "The right term in a length addition must not be offset." );
267 return Lang::Length( isOffset_
, val_
+ term
.val_
);
271 Lang::Length::operator - ( const Lang::Length
& term
) const
275 throw Exceptions::MiscellaneousRequirement( "The right term in a length subtraction must not be offset." );
277 return Lang::Length( isOffset_
, val_
- term
.val_
);
280 RefCountPtr
< const Lang::Class
> Lang::Length::TypeID( new Lang::SystemFinalClass( strrefdup( "Length" ) ) );
281 TYPEINFOIMPL( Length
);
284 Lang::Length::show( std::ostream
& os
) const
291 Lang::operator << ( std::ostream
& os
, const Lang::Length
& self
)
297 os
<< self
.val_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
306 DISPATCHIMPL( Boolean
);
308 RefCountPtr
< const Lang::Class
> Lang::Boolean::TypeID( new Lang::SystemFinalClass( strrefdup( "Boolean" ) ) );
309 TYPEINFOIMPL( Boolean
);
312 Lang::Boolean::show( std::ostream
& os
) const
325 Lang::String::~String( )
328 DISPATCHIMPL( String
);
330 RefCountPtr
< const Lang::Class
> Lang::String::TypeID( new Lang::SystemFinalClass( strrefdup( "String" ) ) );
331 TYPEINFOIMPL( String
);
333 Kernel::VariableHandle
334 Lang::String::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
336 if( strcmp( fieldID
, "bytecount" ) == 0 )
338 return Helpers::newValHandle( new Lang::Integer( bytecount_
) );
340 if( strcmp( fieldID
, "UTF8?" ) == 0 )
342 const unsigned char * src
= reinterpret_cast< const unsigned char * >( val_
.getPtr( ) );
343 const unsigned char * end
= src
+ bytecount_
;
345 for( ; src
< end
; ++src
)
347 if( ( ( *src
^ 0x00 ) & 0x80 ) == 0 )
351 if( ( ( *src
^ 0xC0 ) & 0xE0 ) == 0 )
354 if( ( ( *src
^ 0x80 ) & 0xC0 ) != 0 )
361 if( ( ( *src
^ 0xE0 ) & 0xF0 ) == 0 )
364 if( ( ( *src
^ 0x80 ) & 0xC0 ) != 0 )
370 if( ( ( *src
^ 0x80 ) & 0xC0 ) != 0 )
377 if( ( ( *src
^ 0xE0 ) & 0xF8 ) == 0 )
380 if( ( ( *src
^ 0x80 ) & 0xC0 ) != 0 )
386 if( ( ( *src
^ 0x80 ) & 0xC0 ) != 0 )
392 if( ( ( *src
^ 0x80 ) & 0xC0 ) != 0 )
402 if( src
!= end
|| *src
!= '\0' )
406 return Helpers::newValHandle( new Lang::Boolean( res
) );
408 throw Exceptions::NonExistentMember( getTypeName( ), fieldID
);
412 Lang::String::show( std::ostream
& os
) const
414 os
<< val_
.getPtr( ) ;
418 Lang::Continuation::Continuation( const Kernel::ContRef
& cont
)
422 Lang::Continuation::~Continuation( )
425 RefCountPtr
< const Lang::Class
> Lang::Continuation::TypeID( new Lang::SystemFinalClass( strrefdup( "Backtrace" ) ) );
426 TYPEINFOIMPL( Continuation
);
428 Kernel::VariableHandle
429 Lang::Continuation::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
431 if( strcmp( fieldID
, "up" ) == 0 )
433 Kernel::ContRef res
= cont_
->up( );
434 if( res
== NullPtr
< Kernel::Continuation
>( ) )
436 throw Exceptions::MiscellaneousRequirement( "The top continuation has no parent." );
438 return Helpers::newValHandle( new Lang::Continuation( res
) );
440 else if( strcmp( fieldID
, "top?" ) == 0 )
442 Kernel::ContRef res
= cont_
->up( );
443 return ( res
== NullPtr
< Kernel::Continuation
>( ) ) ? Kernel::THE_TRUE_VARIABLE
: Kernel::THE_FALSE_VARIABLE
;
445 throw Exceptions::NonExistentMember( getTypeName( ), fieldID
);
449 Lang::Continuation::show( std::ostream
& os
) const
451 os
<< "( backtrace to use in error messages )" ;
455 Lang::Continuation::gcMark( Kernel::GCMarkedSet
& marked
)
457 cont_
->gcMark( marked
);
461 Lang::Exception::Exception( const Ast::SourceLocation
& loc
, const RefCountPtr
< const Lang::Symbol
> & kind
, const RefCountPtr
< const Lang::String
> & source
, const RefCountPtr
< const Lang::Value
> & details
, const RefCountPtr
< const char > & message
, const Kernel::ContRef
& cont
, Interaction::ExitCode exitCode
)
462 : loc_( loc
), kind_( kind
), source_( source
), details_( details
), message_( message
), cont_( cont
), exitCode_( exitCode
)
465 Lang::Exception::Exception( const RefCountPtr
< const Lang::Symbol
> & kind
, const RefCountPtr
< const Lang::String
> & source
, const RefCountPtr
< const Lang::Value
> & details
, const RefCountPtr
< const char > & message
, const Kernel::ContRef
& cont
, Interaction::ExitCode exitCode
)
466 : loc_( cont
->traceLoc( ) ), kind_( kind
), source_( source
), details_( details
), message_( message
), cont_( cont
), exitCode_( exitCode
)
469 Lang::Exception::~Exception( )
472 RefCountPtr
< const Lang::Class
> Lang::Exception::TypeID( new Lang::SystemFinalClass( strrefdup( "Exception" ) ) );
473 TYPEINFOIMPL( Exception
);
475 Kernel::VariableHandle
476 Lang::Exception::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
478 if( strcmp( fieldID
, "kind" ) == 0 )
480 return Kernel::VariableHandle( new Kernel::Variable( kind_
) );
482 else if( strcmp( fieldID
, "source" ) == 0 )
484 return Kernel::VariableHandle( new Kernel::Variable( source_
) );
486 else if( strcmp( fieldID
, "details" ) == 0 )
488 return Kernel::VariableHandle( new Kernel::Variable( details_
) );
490 else if( strcmp( fieldID
, "backtrace" ) == 0 )
492 return Helpers::newValHandle( new Lang::Continuation( cont_
) );
494 throw Exceptions::NonExistentMember( getTypeName( ), fieldID
);
498 Lang::Exception::show( std::ostream
& os
) const
504 Lang::Exception::gcMark( Kernel::GCMarkedSet
& marked
)
506 const_cast< Lang::Value
* >( details_
.getPtr( ) )->gcMark( marked
);
507 const_cast< Kernel::Continuation
* >( cont_
.getPtr( ) )->gcMark( marked
);
511 Lang::FloatPair::FloatPair( const Concrete::UnitFloatPair
& orig
)
512 : x_( orig
.x_
), y_( orig
.y_
)
516 DISPATCHIMPL( FloatPair
);
518 Kernel::VariableHandle
519 Lang::FloatPair::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
521 if( strcmp( fieldID
, "x" ) == 0 )
523 return Helpers::newValHandle( new Lang::Float( x_
) );
525 if( strcmp( fieldID
, "y" ) == 0 )
527 return Helpers::newValHandle( new Lang::Float( y_
) );
529 throw Exceptions::NonExistentMember( getTypeName( ), fieldID
);
532 RefCountPtr
< const Lang::Class
> Lang::FloatPair::TypeID( new Lang::SystemFinalClass( strrefdup( "FloatPair" ) ) );
533 TYPEINFOIMPL( FloatPair
);
535 RefCountPtr
< const Lang::FloatPair
>
536 Lang::FloatPair::transformed( const Lang::Transform2D
& tf
) const
538 return RefCountPtr
< const Lang::FloatPair
>
539 ( new Lang::FloatPair( tf
.xx_
* x_
+ tf
.xy_
* y_
, tf
.yx_
* x_
+ tf
.yy_
* y_
) );
543 Lang::FloatPair::show( std::ostream
& os
) const
545 os
<< "( " << x_
<< ", " << y_
<< " )" ;
548 Lang::FloatTriple::FloatTriple( const Concrete::UnitFloatTriple
& orig
)
549 : x_( orig
.x_
), y_( orig
.y_
), z_( orig
.z_
)
552 DISPATCHIMPL( FloatTriple
);
554 Kernel::VariableHandle
555 Lang::FloatTriple::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
557 if( strcmp( fieldID
, "x" ) == 0 )
559 return Helpers::newValHandle( new Lang::Float( x_
) );
561 if( strcmp( fieldID
, "y" ) == 0 )
563 return Helpers::newValHandle( new Lang::Float( y_
) );
565 if( strcmp( fieldID
, "z" ) == 0 )
567 return Helpers::newValHandle( new Lang::Float( z_
) );
569 throw Exceptions::NonExistentMember( getTypeName( ), fieldID
);
572 RefCountPtr
< const Lang::Class
> Lang::FloatTriple::TypeID( new Lang::SystemFinalClass( strrefdup( "FloatTriple" ) ) );
573 TYPEINFOIMPL( FloatTriple
);
575 RefCountPtr
< const Lang::FloatTriple
>
576 Lang::FloatTriple::transformed( const Lang::Transform3D
& tf
) const
578 return RefCountPtr
< const Lang::FloatTriple
>
579 ( new Lang::FloatTriple( tf
.xx_
* x_
+ tf
.xy_
* y_
+ tf
.xz_
* z_
,
580 tf
.yx_
* x_
+ tf
.yy_
* y_
+ tf
.yz_
* z_
,
581 tf
.zx_
* x_
+ tf
.zy_
* y_
+ tf
.zz_
* z_
) );
585 Lang::FloatTriple::show( std::ostream
& os
) const
587 os
<< "( " << x_
<< ", " << y_
<< ", " << z_
<< " )" ;
591 Lang::Coords2D::Coords2D( const Lang::Coords2D
& orig
)
592 : x_( orig
.x_
), y_( orig
.y_
)
595 Lang::Coords2D::Coords2D( const Lang::Length
& x
, const Lang::Length
& y
)
599 Lang::Coords2D::Coords2D( const Concrete::Length
& x
, const Concrete::Length
& y
)
603 DISPATCHIMPL( Coords2D
);
605 Kernel::VariableHandle
606 Lang::Coords2D::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
608 if( strcmp( fieldID
, "x" ) == 0 )
610 return Helpers::newValHandle( new Lang::Length( x_
) );
612 if( strcmp( fieldID
, "y" ) == 0 )
614 return Helpers::newValHandle( new Lang::Length( y_
) );
616 throw Exceptions::NonExistentMember( getTypeName( ), fieldID
);
620 Lang::Coords2D::transformedPtr( const Lang::Transform2D
& tf
) const
622 Concrete::Length tmpx
= x_
.get( );
623 Concrete::Length tmpy
= y_
.get( );
624 return new Lang::Coords2D( tf
.xx_
* tmpx
+ tf
.xy_
* tmpy
+ tf
.xt_
, tf
.yx_
* tmpx
+ tf
.yy_
* tmpy
+ tf
.yt_
);
627 RefCountPtr
< const Lang::Geometric2D
>
628 Lang::Coords2D::transformed( const Lang::Transform2D
& tf
, const RefCountPtr
< const Lang::Geometric2D
> & self
) const
630 return RefCountPtr
< const Lang::Geometric2D
>( transformedPtr( tf
) );
633 RefCountPtr
< const Lang::Geometric3D
>
634 Lang::Coords2D::to3D( const RefCountPtr
< const Lang::Geometric2D
> & self
) const
636 return RefCountPtr
< const Lang::Coords3D
>( new Lang::Coords3D( x_
, y_
, Lang::Length( Concrete::Length( 0 ) ) ) );
639 RefCountPtr
< const Lang::Class
> Lang::Coords2D::TypeID( new Lang::SystemFinalClass( strrefdup( "Coords2D" ) ) );
640 TYPEINFOIMPL( Coords2D
);
643 Lang::Coords2D::show( std::ostream
& os
) const
645 os
<< "( " << x_
<< ", " << y_
<< " )" ;
649 Lang::operator << ( std::ostream
& os
, const Lang::Coords2D
& self
)
651 os
<< "( " << self
.x_
<< ", " << self
.y_
<< " )" ;
656 Lang::CornerCoords2D::CornerCoords2D( const Lang::Length
& x
, const Lang::Length
& y
, double a
)
657 : Lang::Coords2D( x
, y
), a_( a
)
660 Lang::CornerCoords2D::CornerCoords2D( const Concrete::Length
& x
, const Concrete::Length
& y
, double a
)
661 : Lang::Coords2D( x
, y
), a_( a
)
664 RefCountPtr
< const Lang::Class
> Lang::CornerCoords2D::TypeID( new Lang::SystemFinalClass( strrefdup( "CornerCoords2D" ) ) );
665 DISPATCHIMPL( CornerCoords2D
);
667 Kernel::VariableHandle
668 Lang::CornerCoords2D::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
670 if( strcmp( fieldID
, "x" ) == 0 )
672 return Helpers::newValHandle( new Lang::Length( x_
) );
674 if( strcmp( fieldID
, "y" ) == 0 )
676 return Helpers::newValHandle( new Lang::Length( y_
) );
678 if( strcmp( fieldID
, "a" ) == 0 )
680 return Helpers::newValHandle( new Lang::Float( a_
) );
682 throw Exceptions::NonExistentMember( getTypeName( ), fieldID
);
685 Lang::CornerCoords2D
*
686 Lang::CornerCoords2D::transformedPtr( const Lang::Transform2D
& tf
) const
688 Concrete::Length tmpx
= x_
.get( );
689 Concrete::Length tmpy
= y_
.get( );
690 return new Lang::CornerCoords2D( tf
.xx_
* tmpx
+ tf
.xy_
* tmpy
+ tf
.xt_
, tf
.yx_
* tmpx
+ tf
.yy_
* tmpy
+ tf
.yt_
, a_
);
693 RefCountPtr
< const Lang::Geometric2D
>
694 Lang::CornerCoords2D::transformed( const Lang::Transform2D
& tf
, const RefCountPtr
< const Lang::Geometric2D
> & self
) const
696 return RefCountPtr
< const Lang::Geometric2D
>( transformedPtr( tf
) );
699 RefCountPtr
< const Lang::Geometric3D
>
700 Lang::CornerCoords2D::to3D( const RefCountPtr
< const Lang::Geometric2D
> & self
) const
702 throw Exceptions::MiscellaneousRequirement( "Corner coordinates cannot move into 3D space." );
705 TYPEINFOIMPL( CornerCoords2D
);
708 Lang::Coords3D::Coords3D( const Lang::Coords3D
& orig
)
709 : x_( orig
.x_
), y_( orig
.y_
), z_( orig
.z_
)
712 Lang::Coords3D::Coords3D( const Lang::Length
& x
, const Lang::Length
& y
, const Lang::Length
& z
)
713 : x_( x
), y_( y
), z_( z
)
716 Lang::Coords3D::Coords3D( const Concrete::Length
& x
, const Concrete::Length
& y
, const Concrete::Length
& z
)
717 : x_( x
), y_( y
), z_( z
)
720 DISPATCHIMPL( Coords3D
);
722 Kernel::VariableHandle
723 Lang::Coords3D::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
725 if( strcmp( fieldID
, "x" ) == 0 )
727 return Helpers::newValHandle( new Lang::Length( x_
) );
729 if( strcmp( fieldID
, "y" ) == 0 )
731 return Helpers::newValHandle( new Lang::Length( y_
) );
733 if( strcmp( fieldID
, "z" ) == 0 )
735 return Helpers::newValHandle( new Lang::Length( z_
) );
737 throw Exceptions::NonExistentMember( getTypeName( ), fieldID
);
741 Lang::Coords3D::transformedPtr( const Lang::Transform3D
& tf
) const
743 Concrete::Length tmpx
= x_
.get( );
744 Concrete::Length tmpy
= y_
.get( );
745 Concrete::Length tmpz
= z_
.get( );
746 return new Lang::Coords3D( tf
.xx_
* tmpx
+ tf
.xy_
* tmpy
+ tf
.xz_
* tmpz
+ tf
.xt_
,
747 tf
.yx_
* tmpx
+ tf
.yy_
* tmpy
+ tf
.yz_
* tmpz
+ tf
.yt_
,
748 tf
.zx_
* tmpx
+ tf
.zy_
* tmpy
+ tf
.zz_
* tmpz
+ tf
.zt_
);
751 RefCountPtr
< const Lang::Geometric3D
>
752 Lang::Coords3D::transformed( const Lang::Transform3D
& tf
, const RefCountPtr
< const Lang::Geometric3D
> & self
) const
754 return RefCountPtr
< const Lang::Geometric3D
>( transformedPtr( tf
) );
757 RefCountPtr
< const Lang::Coords2D
>
758 Lang::Coords3D::make2D( Concrete::Length eyez
) const
760 if( eyez
< Concrete::HUGE_LENGTH
)
762 return RefCountPtr
< const Lang::Coords2D
>( new Lang::Coords2D( x_
.get( ) * ( eyez
/ ( eyez
- z_
.get( ) ) ),
763 y_
.get( ) * ( eyez
/ ( eyez
- z_
.get( ) ) ) ) );
765 return RefCountPtr
< const Lang::Coords2D
>( new Lang::Coords2D( x_
.get( ),
770 RefCountPtr
< const Lang::Geometric2D
>
771 Lang::Coords3D::to2D( const Kernel::PassedDyn
& dyn
, const RefCountPtr
< const Lang::Geometric3D
> & self
) const
773 return make2D( dyn
->getEyeZ( ) );
776 RefCountPtr
< const Lang::Class
> Lang::Coords3D::TypeID( new Lang::SystemFinalClass( strrefdup( "Coords3D" ) ) );
777 TYPEINFOIMPL( Coords3D
);
780 Lang::Coords3D::show( std::ostream
& os
) const
782 os
<< "( " << x_
<< ", " << y_
<< ", " << z_
<< " )" ;
786 Lang::operator << ( std::ostream
& os
, const Lang::Coords3D
& self
)
788 os
<< "( " << self
.x_
<< ", " << self
.y_
<< ", " << self
.z_
<< " )" ;