Merge branch 'gh/maint-clean' into ht/-include
[shapes.git] / source / facetnormals.cc
blob32e51e389a3682eb03467e51231ff0688dcf3d7e
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 "drawabletypes.h"
20 #include "lighttypes.h"
21 #include "astclass.h"
22 #include "constructorrepresentation.h"
23 #include "globals.h"
25 using namespace Shapes;
28 Lang::FacetNormalGray::FacetNormalGray( const Concrete::Coords3D & position,
29 const RefCountPtr< const Lang::SpecularReflection > & reflections,
30 const Concrete::UnitFloatTriple & reflectionUnitNormal,
31 const Concrete::Gray lightMultiply,
32 const RefCountPtr< const Lang::SpecularReflection > & autoScattering,
33 const Concrete::Gray autoIntensity )
34 : position_( position ),
35 reflections_( reflections ),
36 reflectionUnitNormal_( reflectionUnitNormal ),
37 lightMultiply_( lightMultiply ),
38 autoScattering_( autoScattering ),
39 autoIntensity_( autoIntensity )
40 { }
42 Lang::FacetNormalGray::~FacetNormalGray( )
43 { }
45 RefCountPtr< const Lang::Class > Lang::FacetNormalGray::TypeID( new Lang::SystemFinalClass( strrefdup( "FacetNormalGray" ) ) );
46 TYPEINFOIMPL( FacetNormalGray );
48 Concrete::Gray
49 Lang::FacetNormalGray::compute( const Concrete::Coords3D & point, const Concrete::UnitFloatTriple normal, const Lang::Transform3D & tf, const Concrete::Length eyez, const std::list< RefCountPtr< const Lang::LightSource > > & lights ) const
51 // Here, we must remember that the lights, but only the lights, are already transformed!
53 Concrete::UnitFloatTriple tf_normal = tf.transformPlaneUnitNormal( reflectionUnitNormal_ );
54 // Concrete::Coords3D tf_position( position_.transformed( tf ) );
55 double grayVal = autoScattering_->illuminate( point, eyez, tf_normal, autoIntensity_ ).gr_;
57 typedef typeof lights ListType;
58 for( ListType::const_iterator i = lights.begin( ); i != lights.end( ); ++i )
60 double tmp = 0;
62 typedef const Lang::GrayLight LightType;
63 LightType * light = dynamic_cast< LightType * >( i->getPtr( ) );
64 if( light != 0 )
66 tmp = reflections_->illuminate( point, eyez, tf_normal, *light ).gr_;
67 goto foundLightType;
71 typedef const Lang::RGBLight LightType;
72 LightType * light = dynamic_cast< LightType * >( i->getPtr( ) );
73 if( light != 0 )
75 tmp = reflections_->illuminate( point, eyez, tf_normal, *light ).mean( );
76 goto foundLightType;
79 throw Exceptions::InternalError( "A strange type of light." );
80 foundLightType:
81 tmp *= lightMultiply_.gr_;
82 grayVal += tmp;
83 if( grayVal > 1 )
85 grayVal = 1;
86 break;
90 return Concrete::Gray( grayVal );
93 Concrete::Gray
94 Lang::FacetNormalGray::compute( const Concrete::Coords3D & point, const Lang::Transform3D & tf, const Concrete::Length eyez, const std::list< RefCountPtr< const Lang::LightSource > > & lights ) const
96 return compute( point, reflectionUnitNormal_, tf, eyez, lights );
99 Concrete::Gray
100 Lang::FacetNormalGray::getDebugColor( ) const
102 return lightMultiply_;
105 RefCountPtr< const Lang::FacetNormalGray >
106 Lang::FacetNormalGray::transformed( const Lang::Transform3D & tf ) const
108 return RefCountPtr< const Lang::FacetNormalGray >
109 ( new Lang::FacetNormalGray( position_.transformed( tf ),
110 reflections_,
111 tf.transformPlaneUnitNormal( reflectionUnitNormal_ ),
112 lightMultiply_,
113 autoScattering_,
114 autoIntensity_ ) );
118 void
119 Lang::FacetNormalGray::gcMark( Kernel::GCMarkedSet & marked )
121 const_cast< Lang::SpecularReflection * >( reflections_.getPtr( ) )->gcMark( marked );
122 const_cast< Lang::SpecularReflection * >( autoScattering_.getPtr( ) )->gcMark( marked );
126 Lang::FacetNormalRGB::FacetNormalRGB( const Concrete::Coords3D & position,
127 const RefCountPtr< const Lang::SpecularReflection > & reflections,
128 const Concrete::UnitFloatTriple & reflectionUnitNormal,
129 const Concrete::RGB & lightMultiply,
130 const RefCountPtr< const Lang::SpecularReflection > & autoScattering,
131 const Concrete::RGB & autoIntensity )
132 : position_( position ),
133 reflections_( reflections ),
134 reflectionUnitNormal_( reflectionUnitNormal ),
135 lightMultiply_( lightMultiply ),
136 autoScattering_( autoScattering ),
137 autoIntensity_( autoIntensity )
140 Lang::FacetNormalRGB::~FacetNormalRGB( )
143 RefCountPtr< const Lang::Class > Lang::FacetNormalRGB::TypeID( new Lang::SystemFinalClass( strrefdup( "FacetNormalRGB" ) ) );
144 TYPEINFOIMPL( FacetNormalRGB );
146 Concrete::RGB
147 Lang::FacetNormalRGB::compute( const Concrete::Coords3D & point, const Concrete::UnitFloatTriple normal, const Lang::Transform3D & tf, const Concrete::Length eyez, const std::list< RefCountPtr< const Lang::LightSource > > & lights ) const
149 // Should be analogous to FacetNormalGray::compute.
151 Concrete::UnitFloatTriple tf_normal = tf.transformPlaneUnitNormal( reflectionUnitNormal_ );
152 // Concrete::Coords3D tf_position( position_.transformed( tf ) );
153 Concrete::RGB val = autoScattering_->illuminate( point, eyez, tf_normal, autoIntensity_ );
155 typedef typeof lights ListType;
156 for( ListType::const_iterator i = lights.begin( ); i != lights.end( ); ++i )
158 Concrete::RGB tmp( 0, 0, 0);
160 typedef const Lang::GrayLight LightType;
161 LightType * light = dynamic_cast< LightType * >( i->getPtr( ) );
162 if( light != 0 )
164 double a = reflections_->illuminate( point, eyez, tf_normal, *light ).gr_;
165 tmp = Concrete::RGB( a, a, a );
166 goto foundLightType;
170 typedef const Lang::RGBLight LightType;
171 LightType * light = dynamic_cast< LightType * >( i->getPtr( ) );
172 if( light != 0 )
174 tmp = reflections_->illuminate( point, eyez, tf_normal, *light );
175 goto foundLightType;
178 throw Exceptions::InternalError( "A strange type of light." );
179 foundLightType:
180 tmp.r_ *= lightMultiply_.r_;
181 tmp.g_ *= lightMultiply_.g_;
182 tmp.b_ *= lightMultiply_.b_;
183 val = val.addNoCheck( tmp );
184 bool doBreak = true;
185 if( val.r_ > 1 )
187 val.r_ = 1;
189 else
191 doBreak = false;
193 if( val.g_ > 1 )
195 val.g_ = 1;
197 else
199 doBreak = false;
201 if( val.b_ > 1 )
203 val.b_ = 1;
205 else
207 doBreak = false;
209 if( doBreak )
211 break;
215 return val;
218 Concrete::RGB
219 Lang::FacetNormalRGB::compute( const Concrete::Coords3D & point, const Lang::Transform3D & tf, const Concrete::Length eyez, const std::list< RefCountPtr< const Lang::LightSource > > & lights ) const
221 return compute( point, reflectionUnitNormal_, tf, eyez, lights );
224 Concrete::RGB
225 Lang::FacetNormalRGB::getDebugColor( ) const
227 return lightMultiply_;
230 RefCountPtr< const Lang::FacetNormalRGB >
231 Lang::FacetNormalRGB::transformed( const Lang::Transform3D & tf ) const
233 return RefCountPtr< const Lang::FacetNormalRGB >
234 ( new Lang::FacetNormalRGB( position_.transformed( tf ),
235 reflections_,
236 tf.transformPlaneUnitNormal( reflectionUnitNormal_ ),
237 lightMultiply_,
238 autoScattering_,
239 autoIntensity_ ) );
242 void
243 Lang::FacetNormalRGB::gcMark( Kernel::GCMarkedSet & marked )
245 const_cast< Lang::SpecularReflection * >( reflections_.getPtr( ) )->gcMark( marked );
246 const_cast< Lang::SpecularReflection * >( autoScattering_.getPtr( ) )->gcMark( marked );
250 Computation::FacetInterpolatorGray::~FacetInterpolatorGray( )
254 Computation::FacetInterpolatorGray1::~FacetInterpolatorGray1( )
257 RefCountPtr< const Lang::Gray >
258 Computation::FacetInterpolatorGray1::compute( const Lang::Transform3D & tf, const std::list< RefCountPtr< const Lang::LightSource > > & lights, const Concrete::Coords3D & point, const Concrete::Length eyez ) const
260 return RefCountPtr< const Lang::Gray >( new Lang::Gray( n1_->compute( point, tf, eyez, lights ) ) );
263 RefCountPtr< const Lang::Gray >
264 Computation::FacetInterpolatorGray1::getDebugColor( ) const
266 return RefCountPtr< const Lang::Gray >( new Lang::Gray( n1_->getDebugColor( ) ) );
269 RefCountPtr< const Computation::FacetInterpolatorGray >
270 Computation::FacetInterpolatorGray1::transformed( const Lang::Transform3D & tf ) const
272 return RefCountPtr< const Computation::FacetInterpolatorGray >
273 ( new FacetInterpolatorGray1( n1_->transformed( tf ) ) );
277 void
278 Computation::FacetInterpolatorGray1::gcMark( Kernel::GCMarkedSet & marked )
280 const_cast< Lang::FacetNormalGray * >( n1_.getPtr( ) )->gcMark( marked );
284 Computation::FacetInterpolatorGray2::FacetInterpolatorGray2( const RefCountPtr< const Lang::FacetNormalGray > & n1,
285 const RefCountPtr< const Lang::FacetNormalGray > & n2 )
286 : n1_( n1 ), n2_( n2 ),
287 d_( 0 ), t_( 0, 0, 0, bool( ) ), m_( 0 ),
288 rotationDirection_( 0, 0, 0, bool( ) )
290 Concrete::Coords3D r = n2_->position( ) - n1_->position( );
291 d_ = r.norm( );
292 t_ = r.direction( d_ );
293 m_ = Concrete::inner( t_, n1_->position( ) );
295 angle_ = acos( Concrete::inner( n1_->normal( ), n2_->normal( ) ) );
298 rotationDirection_ = Concrete::crossDirection( n1_->normal( ), n2_->normal( ) );
300 catch( const NonLocalExit::CrossDirectionOfParallel & ball )
302 if( angle_ > 3 )
304 throw Exceptions::MiscellaneousRequirement( "The facet normals on a facet must not point in opposite directions." );
306 rotationDirection_ = Concrete::UnitFloatTriple( 1, 0, 0, bool( ) );
310 Computation::FacetInterpolatorGray2::~FacetInterpolatorGray2( )
313 RefCountPtr< const Lang::Gray >
314 Computation::FacetInterpolatorGray2::compute( const Lang::Transform3D & tf, const std::list< RefCountPtr< const Lang::LightSource > > & lights, const Concrete::Coords3D & point, const Concrete::Length eyez )
315 const
317 double w2 = ( Concrete::inner( t_, point ) - m_ ) / d_;
318 double w1 = 1 - w2;
320 // The following may not be efficient, but it was easy to code by copying code from Core_rotate3D.
321 // I've got the feeling that this is much better done using geometric algebra based on Clifford algebra.
323 Concrete::UnitFloatTriple normal = n1_->normal( ).rotate( rotationDirection_, w2 * angle_ );
325 Concrete::Gray c1 = n1_->compute( point, normal, tf, eyez, lights ).mulNoCheck( w1 );
326 Concrete::Gray c2 = n2_->compute( point, normal, tf, eyez, lights ).mulNoCheck( w2 );
327 Concrete::Gray res = c1.addNoCheck( c2 );
328 if( res.gr_ < 0 )
330 res.gr_ = 0;
332 else if( res.gr_ > 1 )
334 res.gr_ = 1;
336 return RefCountPtr< const Lang::Gray >( new Lang::Gray( res ) );
339 RefCountPtr< const Lang::Gray >
340 Computation::FacetInterpolatorGray2::getDebugColor( ) const
342 return RefCountPtr< const Lang::Gray >( new Lang::Gray( n1_->getDebugColor( ) ) );
345 RefCountPtr< const Computation::FacetInterpolatorGray >
346 Computation::FacetInterpolatorGray2::transformed( const Lang::Transform3D & tf ) const
348 return RefCountPtr< const Computation::FacetInterpolatorGray >
349 ( new FacetInterpolatorGray2( n1_->transformed( tf ),
350 n2_->transformed( tf ) ) );
353 void
354 Computation::FacetInterpolatorGray2::gcMark( Kernel::GCMarkedSet & marked )
356 const_cast< Lang::FacetNormalGray * >( n1_.getPtr( ) )->gcMark( marked );
357 const_cast< Lang::FacetNormalGray * >( n2_.getPtr( ) )->gcMark( marked );
361 Computation::FacetInterpolatorGray3::FacetInterpolatorGray3( const RefCountPtr< const Lang::FacetNormalGray > & n1,
362 const RefCountPtr< const Lang::FacetNormalGray > & n2,
363 const RefCountPtr< const Lang::FacetNormalGray > & n3 )
364 : n1_( n1 ), n2_( n2 ), n3_( n3 ),
365 p1_( n1_->position( ) ), p2_( n2_->position( ) ), p3_( n3_->position( ) ),
366 d1_( 0, 0, 0, bool( ) ), d2_( 0, 0, 0, bool( ) ), d3_( 0, 0, 0, bool( ) )
369 Concrete::Coords3D r12 = p2_ - p1_;
370 Concrete::Coords3D r23 = p3_ - p2_;
371 Concrete::Coords3D r31 = p1_ - p3_;
373 d1_ = ( p2_ + r23 * ( Concrete::innerScalar( r23, p1_ - p2_ ) / Concrete::innerScalar( r23, r23 ) ) - p1_ ).direction( );
374 d2_ = ( p3_ + r31 * ( Concrete::innerScalar( r31, p2_ - p3_ ) / Concrete::innerScalar( r31, r31 ) ) - p2_ ).direction( );
375 d3_ = ( p1_ + r12 * ( Concrete::innerScalar( r12, p3_ - p1_ ) / Concrete::innerScalar( r12, r12 ) ) - p3_ ).direction( );
377 // The lengs are obtained by projecting any of the other two points on the direction:
378 l1_ = Concrete::inner( d1_, p2_ - p1_ );
379 l2_ = Concrete::inner( d2_, p3_ - p2_ );
380 l3_ = Concrete::inner( d3_, p1_ - p3_ );
383 Computation::FacetInterpolatorGray3::~FacetInterpolatorGray3( )
386 RefCountPtr< const Lang::Gray >
387 Computation::FacetInterpolatorGray3::compute( const Lang::Transform3D & tf, const std::list< RefCountPtr< const Lang::LightSource > > & lights, const Concrete::Coords3D & point, const Concrete::Length eyez )
388 const
390 // #define USE_CONVEX_COMBINATION
391 #ifdef USE_CONVEX_COMBINATION
392 // This is another way to assign initial weights. The symmetry is not obvious, but
393 // follows if we note that the convex combination of the corners
394 // (1-(w2+w3)) * p1_ + w2 * p2_ + w3 * p3_
395 // that result in <point> is unique inside the triangle, and then this is extended to all the plane.
397 Concrete::Coords3D b = point - p1_;
398 Concrete::Coords3D a1 = p2_ - p1_;
399 Concrete::Coords3D a2 = p3_ - p1_;
400 const Physical< 2, 0 > a11 = Concrete::inner( a1, a1 );
401 const Physical< 2, 0 > a12 = Concrete::inner( a2, a1 );
402 const Physical< 2, 0 > a22 = Concrete::inner( a2, a2 );
403 const Physical< 2, 0 > b1 = Concrete::inner( a1, b );
404 const Physical< 2, 0 > b2 = Concrete::inner( a2, b );
405 const Physical< 4, 0 > det = ( a11 * a22 - a12 * a12 );
406 if( det.abs( ) < 1e-8 )
408 // The surface has no area, so the color shouldn't matter.
409 return Lang::THE_BLACK;
411 Physical< -4, 0 > invDet = 1. / det;
412 double w2 = invDet * ( a22 * b1 - a12 * b2 );
413 double w3 = invDet * ( - a12 * b1 + a11 * b2 );
414 double w1 = 1 - ( w2 + w3 );
415 // Inside the triangle, this will do nothing by construction. However, outside the triangle we want to avoid negative weights, maybe...
416 // Or maybe negative weights are OK?
417 w1 = std::max( 0., w1 );
418 w2 = std::max( 0., w2 );
419 w3 = std::max( 0., w3 );
420 #else
421 // This is one way to assign initial weights. It is symmetric in construction.
423 double w1 = std::max( 0., 1 - static_cast< double >( Concrete::inner( d1_, point - p1_ ) / l1_ ) );
424 double w2 = std::max( 0., 1 - static_cast< double >( Concrete::inner( d2_, point - p2_ ) / l2_ ) );
425 double w3 = std::max( 0., 1 - static_cast< double >( Concrete::inner( d3_, point - p3_ ) / l3_ ) );
426 #endif
429 double sumInv = 1 / ( w1 + w2 + w3 );
430 w1 *= sumInv;
431 w2 *= sumInv;
432 w3 *= sumInv;
434 const Concrete::UnitFloatTriple & n1 = n1_->normal( );
435 const Concrete::UnitFloatTriple & n2 = n2_->normal( );
436 const Concrete::UnitFloatTriple & n3 = n3_->normal( );
438 // Here we do the ugly linear interpolation, and let the UnitFloatTriple constructor normalize the result.
439 Concrete::UnitFloatTriple normal( w1 * n1.x_ + w2 * n2.x_ + w3 * n3.x_,
440 w1 * n1.y_ + w2 * n2.y_ + w3 * n3.y_,
441 w1 * n1.z_ + w2 * n2.z_ + w3 * n3.z_ );
443 Concrete::Gray c1 = n1_->compute( point, normal, tf, eyez, lights ).mulNoCheck( w1 );
444 Concrete::Gray c2 = n2_->compute( point, normal, tf, eyez, lights ).mulNoCheck( w2 );
445 Concrete::Gray c3 = n3_->compute( point, normal, tf, eyez, lights ).mulNoCheck( w3 );
447 Concrete::Gray res = c1.addNoCheck( c2 ).addNoCheck( c3 );
448 if( res.gr_ < 0 )
450 res.gr_ = 0;
452 else if( res.gr_ > 1 )
454 res.gr_ = 1;
456 return RefCountPtr< const Lang::Gray >( new Lang::Gray( res ) );
459 RefCountPtr< const Lang::Gray >
460 Computation::FacetInterpolatorGray3::getDebugColor( ) const
462 return RefCountPtr< const Lang::Gray >( new Lang::Gray( n1_->getDebugColor( ) ) );
465 RefCountPtr< const Computation::FacetInterpolatorGray >
466 Computation::FacetInterpolatorGray3::transformed( const Lang::Transform3D & tf ) const
468 return RefCountPtr< const Computation::FacetInterpolatorGray >
469 ( new FacetInterpolatorGray3( n1_->transformed( tf ),
470 n2_->transformed( tf ),
471 n3_->transformed( tf ) ) );
474 void
475 Computation::FacetInterpolatorGray3::gcMark( Kernel::GCMarkedSet & marked )
477 const_cast< Lang::FacetNormalGray * >( n1_.getPtr( ) )->gcMark( marked );
478 const_cast< Lang::FacetNormalGray * >( n2_.getPtr( ) )->gcMark( marked );
479 const_cast< Lang::FacetNormalGray * >( n3_.getPtr( ) )->gcMark( marked );
483 Computation::FacetInterpolatorRGB::~FacetInterpolatorRGB( )
487 Computation::FacetInterpolatorRGB1::~FacetInterpolatorRGB1( )
490 RefCountPtr< const Lang::RGB >
491 Computation::FacetInterpolatorRGB1::compute( const Lang::Transform3D & tf, const std::list< RefCountPtr< const Lang::LightSource > > & lights, const Concrete::Coords3D & point, const Concrete::Length eyez ) const
493 return RefCountPtr< const Lang::RGB >( new Lang::RGB( n1_->compute( point, tf, eyez, lights ) ) );
496 RefCountPtr< const Lang::RGB >
497 Computation::FacetInterpolatorRGB1::getDebugColor( ) const
499 return RefCountPtr< const Lang::RGB >( new Lang::RGB( n1_->getDebugColor( ) ) );
502 RefCountPtr< const Computation::FacetInterpolatorRGB >
503 Computation::FacetInterpolatorRGB1::transformed( const Lang::Transform3D & tf ) const
505 return RefCountPtr< const Computation::FacetInterpolatorRGB >
506 ( new FacetInterpolatorRGB1( n1_->transformed( tf ) ) );
510 void
511 Computation::FacetInterpolatorRGB1::gcMark( Kernel::GCMarkedSet & marked )
513 const_cast< Lang::FacetNormalRGB * >( n1_.getPtr( ) )->gcMark( marked );
517 Computation::FacetInterpolatorRGB2::FacetInterpolatorRGB2( const RefCountPtr< const Lang::FacetNormalRGB > & n1,
518 const RefCountPtr< const Lang::FacetNormalRGB > & n2 )
519 : n1_( n1 ), n2_( n2 ),
520 d_( 0 ), t_( 0, 0, 0, bool( ) ), m_( 0 ),
521 rotationDirection_( 0, 0, 0, bool( ) )
523 Concrete::Coords3D r = n2_->position( ) - n1_->position( );
524 d_ = r.norm( );
525 t_ = r.direction( d_ );
526 m_ = Concrete::inner( t_, n1_->position( ) );
528 angle_ = acos( Concrete::inner( n1_->normal( ), n2_->normal( ) ) );
531 rotationDirection_ = Concrete::crossDirection( n1_->normal( ), n2_->normal( ) );
533 catch( const NonLocalExit::CrossDirectionOfParallel & ball )
535 if( angle_ > 3 )
537 throw Exceptions::MiscellaneousRequirement( "The facet normals on a facet must not point in opposite directions." );
539 rotationDirection_ = Concrete::UnitFloatTriple( 1, 0, 0, bool( ) );
543 Computation::FacetInterpolatorRGB2::~FacetInterpolatorRGB2( )
546 RefCountPtr< const Lang::RGB >
547 Computation::FacetInterpolatorRGB2::compute( const Lang::Transform3D & tf, const std::list< RefCountPtr< const Lang::LightSource > > & lights, const Concrete::Coords3D & point, const Concrete::Length eyez )
548 const
550 double w2 = ( Concrete::inner( t_, point ) - m_ ) / d_;
551 double w1 = 1 - w2;
553 // The following may not be efficient, but it was easy to code by copying code from Core_rotate3D.
554 // I've got the feeling that this is much better done using geometric algebra based on Clifford algebra.
556 Concrete::UnitFloatTriple normal = n1_->normal( ).rotate( rotationDirection_, w2 * angle_ );
558 Concrete::RGB c1 = n1_->compute( point, normal, tf, eyez, lights ).mulNoCheck( w1 );
559 Concrete::RGB c2 = n2_->compute( point, normal, tf, eyez, lights ).mulNoCheck( w2 );
560 Concrete::RGB res = c1.addNoCheck( c2 );
561 if( res.r_ < 0 )
563 res.r_ = 0;
565 else if( res.r_ > 1 )
567 res.r_ = 1;
569 if( res.g_ < 0 )
571 res.g_ = 0;
573 else if( res.g_ > 1 )
575 res.g_ = 1;
577 if( res.b_ < 0 )
579 res.b_ = 0;
581 else if( res.b_ > 1 )
583 res.b_ = 1;
585 return RefCountPtr< const Lang::RGB >( new Lang::RGB( res ) );
588 RefCountPtr< const Lang::RGB >
589 Computation::FacetInterpolatorRGB2::getDebugColor( ) const
591 return RefCountPtr< const Lang::RGB >( new Lang::RGB( n1_->getDebugColor( ) ) );
594 RefCountPtr< const Computation::FacetInterpolatorRGB >
595 Computation::FacetInterpolatorRGB2::transformed( const Lang::Transform3D & tf ) const
597 return RefCountPtr< const Computation::FacetInterpolatorRGB >
598 ( new FacetInterpolatorRGB2( n1_->transformed( tf ),
599 n2_->transformed( tf ) ) );
602 void
603 Computation::FacetInterpolatorRGB2::gcMark( Kernel::GCMarkedSet & marked )
605 const_cast< Lang::FacetNormalRGB * >( n1_.getPtr( ) )->gcMark( marked );
606 const_cast< Lang::FacetNormalRGB * >( n2_.getPtr( ) )->gcMark( marked );
610 Computation::FacetInterpolatorRGB3::FacetInterpolatorRGB3( const RefCountPtr< const Lang::FacetNormalRGB > & n1,
611 const RefCountPtr< const Lang::FacetNormalRGB > & n2,
612 const RefCountPtr< const Lang::FacetNormalRGB > & n3 )
613 : n1_( n1 ), n2_( n2 ), n3_( n3 ),
614 p1_( n1_->position( ) ), p2_( n2_->position( ) ), p3_( n3_->position( ) ),
615 d1_( 0, 0, 0, bool( ) ), d2_( 0, 0, 0, bool( ) ), d3_( 0, 0, 0, bool( ) )
618 Concrete::Coords3D r12 = p2_ - p1_;
619 Concrete::Coords3D r23 = p3_ - p2_;
620 Concrete::Coords3D r31 = p1_ - p3_;
622 d1_ = ( p2_ + r23 * ( Concrete::innerScalar( r23, p1_ - p2_ ) / Concrete::innerScalar( r23, r23 ) ) - p1_ ).direction( );
623 d2_ = ( p3_ + r31 * ( Concrete::innerScalar( r31, p2_ - p3_ ) / Concrete::innerScalar( r31, r31 ) ) - p2_ ).direction( );
624 d3_ = ( p1_ + r12 * ( Concrete::innerScalar( r12, p3_ - p1_ ) / Concrete::innerScalar( r12, r12 ) ) - p3_ ).direction( );
626 // The lengs are obtained by projecting any of the other two points on the direction:
627 l1_ = Concrete::inner( d1_, p2_ - p1_ );
628 l2_ = Concrete::inner( d2_, p3_ - p2_ );
629 l3_ = Concrete::inner( d3_, p1_ - p3_ );
632 Computation::FacetInterpolatorRGB3::~FacetInterpolatorRGB3( )
635 RefCountPtr< const Lang::RGB >
636 Computation::FacetInterpolatorRGB3::compute( const Lang::Transform3D & tf, const std::list< RefCountPtr< const Lang::LightSource > > & lights, const Concrete::Coords3D & point, const Concrete::Length eyez )
637 const
639 // #define USE_CONVEX_COMBINATION
640 #ifdef USE_CONVEX_COMBINATION
641 // This is another way to assign initial weights. The symmetry is not obvious, but
642 // follows if we note that the convex combination of the corners
643 // (1-(w2+w3)) * p1_ + w2 * p2_ + w3 * p3_
644 // that result in <point> is unique inside the triangle, and then this is extended to all the plane.
646 Concrete::Coords3D b = point - p1_;
647 Concrete::Coords3D a1 = p2_ - p1_;
648 Concrete::Coords3D a2 = p3_ - p1_;
649 const Physical< 2, 0 > a11 = Concrete::inner( a1, a1 );
650 const Physical< 2, 0 > a12 = Concrete::inner( a2, a1 );
651 const Physical< 2, 0 > a22 = Concrete::inner( a2, a2 );
652 const Physical< 2, 0 > b1 = Concrete::inner( a1, b );
653 const Physical< 2, 0 > b2 = Concrete::inner( a2, b );
654 const Physical< 4, 0 > det = ( a11 * a22 - a12 * a12 );
655 if( det.abs( ) < 1e-8 )
657 // The surface has no area, so the color shouldn't matter.
658 return Lang::THE_BLACK;
660 Physical< -4, 0 > invDet = 1. / det;
661 double w2 = invDet * ( a22 * b1 - a12 * b2 );
662 double w3 = invDet * ( - a12 * b1 + a11 * b2 );
663 double w1 = 1 - ( w2 + w3 );
664 // Inside the triangle, this will do nothing by construction. However, outside the triangle we want to avoid negative weights, maybe...
665 // Or maybe negative weights are OK?
666 w1 = std::max( 0., w1 );
667 w2 = std::max( 0., w2 );
668 w3 = std::max( 0., w3 );
669 #else
670 // This is one way to assign initial weights. It is symmetric in construction.
672 double w1 = std::max( 0., 1 - static_cast< double >( Concrete::inner( d1_, point - p1_ ) / l1_ ) );
673 double w2 = std::max( 0., 1 - static_cast< double >( Concrete::inner( d2_, point - p2_ ) / l2_ ) );
674 double w3 = std::max( 0., 1 - static_cast< double >( Concrete::inner( d3_, point - p3_ ) / l3_ ) );
675 #endif
678 double sumInv = 1 / ( w1 + w2 + w3 );
679 w1 *= sumInv;
680 w2 *= sumInv;
681 w3 *= sumInv;
683 const Concrete::UnitFloatTriple & n1 = n1_->normal( );
684 const Concrete::UnitFloatTriple & n2 = n2_->normal( );
685 const Concrete::UnitFloatTriple & n3 = n3_->normal( );
687 // Here we do the ugly linear interpolation, and let the UnitFloatTriple constructor normalize the result.
688 Concrete::UnitFloatTriple normal( w1 * n1.x_ + w2 * n2.x_ + w3 * n3.x_,
689 w1 * n1.y_ + w2 * n2.y_ + w3 * n3.y_,
690 w1 * n1.z_ + w2 * n2.z_ + w3 * n3.z_ );
692 Concrete::RGB c1 = n1_->compute( point, normal, tf, eyez, lights ).mulNoCheck( w1 );
693 Concrete::RGB c2 = n2_->compute( point, normal, tf, eyez, lights ).mulNoCheck( w2 );
694 Concrete::RGB c3 = n3_->compute( point, normal, tf, eyez, lights ).mulNoCheck( w3 );
696 Concrete::RGB res = c1.addNoCheck( c2 ).addNoCheck( c3 );
697 if( res.r_ < 0 )
699 res.r_ = 0;
701 else if( res.r_ > 1 )
703 res.r_ = 1;
705 if( res.g_ < 0 )
707 res.g_ = 0;
709 else if( res.g_ > 1 )
711 res.g_ = 1;
713 if( res.b_ < 0 )
715 res.b_ = 0;
717 else if( res.b_ > 1 )
719 res.b_ = 1;
721 return RefCountPtr< const Lang::RGB >( new Lang::RGB( res ) );
724 RefCountPtr< const Lang::RGB >
725 Computation::FacetInterpolatorRGB3::getDebugColor( ) const
727 return RefCountPtr< const Lang::RGB >( new Lang::RGB( n1_->getDebugColor( ) ) );
730 RefCountPtr< const Computation::FacetInterpolatorRGB >
731 Computation::FacetInterpolatorRGB3::transformed( const Lang::Transform3D & tf ) const
733 return RefCountPtr< const Computation::FacetInterpolatorRGB >
734 ( new FacetInterpolatorRGB3( n1_->transformed( tf ),
735 n2_->transformed( tf ),
736 n3_->transformed( tf ) ) );
739 void
740 Computation::FacetInterpolatorRGB3::gcMark( Kernel::GCMarkedSet & marked )
742 const_cast< Lang::FacetNormalRGB * >( n1_.getPtr( ) )->gcMark( marked );
743 const_cast< Lang::FacetNormalRGB * >( n2_.getPtr( ) )->gcMark( marked );
744 const_cast< Lang::FacetNormalRGB * >( n3_.getPtr( ) )->gcMark( marked );