Merge branch 'gh/maint-clean' into ht/-include
[shapes.git] / source / zbuftriangle.cc
blob24f5884c2f2fe4e9ad7753dfb38b99a492b0d8d8
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 "shapestypes.h"
22 #include "shapesexceptions.h"
23 #include "astexpr.h"
24 #include "consts.h"
25 #include "angleselect.h"
26 #include "astvar.h"
27 #include "astclass.h"
28 #include "statetypes.h"
29 #include "lighttypes.h"
30 #include "shadingtypes.h"
31 #include "globals.h"
32 #include "trianglefunctions.h"
33 #include "basicsimplex.h"
34 #include "zbufinternals.h"
35 #include "constructorrepresentation.h"
36 #include "warn.h"
38 #include <ctype.h>
39 #include <list>
40 #include <algorithm>
41 #include <limits>
43 using namespace Shapes;
46 #define SPLICEDEBUG( code ) // code
48 void
49 assertNotOverlapping( const std::list< Computation::ZBufTriangle > & disjointTriangles )
52 typedef typeof disjointTriangles ListType;
53 ListType::const_iterator last = disjointTriangles.end( );
54 --last;
55 for( ListType::const_iterator i = disjointTriangles.begin( ); i != last; ++i )
57 if( last->overlaps( *i ) )
59 throw Exceptions::InternalError( "assertNotOverlapping triggered" );
64 void
65 assertCounterClockwiseConvex( const Lang::ZBuf::PolyIndices & poly, const std::vector< Concrete::Coords2D > & cornerMem )
67 for( Lang::ZBuf::PolyIndices::const_iterator i0 = poly.begin( ); i0 != poly.end( ); ++i0 )
69 Lang::ZBuf::PolyIndices::const_iterator i1 = i0;
70 ++i1;
71 if( i1 == poly.end( ) )
73 i1 = poly.begin( );
75 Lang::ZBuf::PolyIndices::const_iterator i2 = i1;
76 ++i2;
77 if( i2 == poly.end( ) )
79 i2 = poly.begin( );
81 Concrete::UnitFloatPair inHat = cornerMem[ *i0 ].normalizedOrthogonal( cornerMem[ *i1 ] );
82 if( Concrete::inner( inHat, cornerMem[ *i2 ] - cornerMem[ *i1 ] ) < - Computation::theTrixelizeSplicingTol )
84 throw Exceptions::InternalError( "assertCounterClockwiseConvex triggered" );
90 Computation::ZBufTriangle::ZMap::ZMap( const Concrete::UnitFloatTriple & normal,
91 Concrete::Length m,
92 Concrete::Length tiebreaker,
93 Concrete::Length eyez )
94 : normal_( normal ), k_x_( normal_.x_ ), k_y_( normal_.y_ ), k_z_( normal_.z_ ), m_( m ),
95 eyezInv_( 1. / eyez ), tiebreaker_( tiebreaker ), eyez_( eyez )
96 { }
98 Concrete::Length
99 Computation::ZBufTriangle::ZMap::operator () ( const Concrete::Coords2D & p ) const
101 Concrete::Length tmp = k_x_ * p.x_ + k_y_ * p.y_;
102 return ( m_ - tmp ) / ( k_z_ - eyezInv_ * tmp );
105 void
106 Computation::ZBufTriangle::ZMap::writeToMatrices( double a[3], Concrete::Length * b ) const
108 a[0] = normal_.x_;
109 a[1] = normal_.y_;
110 a[2] = normal_.z_;
111 *b = m_;
114 Computation::SplicingLine::SplicingLine( const Concrete::Coords2D & p0, const Concrete::Coords2D & p1_sub_p0, bool isTriangleSide )
115 : isTriangleSide_( isTriangleSide ),
116 p0_( p0 ),
117 d_( p1_sub_p0.direction( ) ),
118 length_( p1_sub_p0.norm( ) ),
119 n_( Concrete::UnitFloatPair( -p1_sub_p0.y_.offtype< 1, 0 >( ), p1_sub_p0.x_.offtype< 1, 0 >( ) ) ), // Note that this will normalize n_. What if this fails?
120 r_( Concrete::inner( n_, p0 ) )
123 Computation::SplicingLine::SplicingLine( const Computation::SplicingLine & orig )
124 : isTriangleSide_( orig.isTriangleSide_ ),
125 p0_( orig.p0_ ),
126 d_( orig.d_ ),
127 length_( orig.length_ ),
128 n_( orig.n_ ),
129 r_( orig.r_ )
132 Computation::SplicingLine::SplicingLine( )
133 : isTriangleSide_( false ),
134 p0_( 0, 0 ),
135 d_( 1., 0., bool( ) ),
136 length_( 1 ),
137 n_( 0., -1., bool( ) ),
138 r_( 0 )
141 Concrete::Coords2D
142 Computation::SplicingLine::intersection( const Computation::SplicingLine & other ) const
144 Concrete::Length x;
145 Concrete::Length y;
147 const Concrete::UnitFloatPair & n2 = other.n_;
148 const Concrete::Length & r2 = other.r_;
151 double n_n1 = Concrete::inner( n_, n2 );
152 double n_n_ = Concrete::inner( n_, n_ );
153 double n2n2 = Concrete::inner( n2, n2 );
155 if( n_n1 * n_n1 > ( 1 - 1e-8 ) * ( n_n_ * n2n2 ) ) // This corresponds to an angle of approximately 0.01 degree.
157 throw "no intersection";
161 double invDet = static_cast< double >( 1 ) / ( n_.x_ * n2.y_ - n_.y_ * n2.x_ );
162 x = invDet * ( n2.y_ * r_ - n_.y_ * r2 );
163 y = invDet * ( - n2.x_ * r_ + n_.x_ * r2 );
165 Concrete::Coords2D res( x, y );
167 Concrete::Length c1 = Concrete::inner( d_, res - p0_ );
168 Concrete::Length c2 = Concrete::inner( other.d_, res - other.p0_ );
169 if( ( isTriangleSide_ && ( c1 < -Computation::theTrixelizeSplicingTol || c1 > length_ + Computation::theTrixelizeSplicingTol ) ) &&
170 ( other.isTriangleSide_ && ( c2 < -Computation::theTrixelizeSplicingTol || c2 > other.length_ + Computation::theTrixelizeSplicingTol ) ) )
172 throw "no intersection";
176 return res;
179 size_t
180 Computation::SplicingLine::nextLine( const Concrete::Coords2D * p, const Concrete::UnitFloatPair & n, const std::vector< Computation::SplicingLine > & lines ) const
182 // This algorithm is formulated without its own tolerances. It relies on the pointers to the intersection points;
183 // "nearby points" should be represented by the same pointer. If two points are represented by different memory
184 // locations, they are treated as positively separated in geometry as well.
186 SPLICEDEBUG( std::cerr << "nextLine at " << Lang::Coords2D( *p ) << " -> " << "( " << n.x_ << ", " << n.y_ << " )" << " : " );
187 // Note that n will be unit, so it can be used to compute lengths.
188 const Concrete::Coords2D & my_p = *p;
190 // back is parallel to this line, but not in the same halfspace as n.
191 // nOut is parallel to n_ but is turned so that it points out from the enclosed area.
192 // They will both be used to select among lines that intersect at the same point.
193 Concrete::UnitFloatPair back = d_;
194 if( Concrete::inner( back, n ) > 0 )
196 back = back.reverse( );
198 Concrete::UnitFloatPair nIn( back.y_, -back.x_ );
200 size_t res = 0;
201 Concrete::Length bestRes( HUGE_VAL );
202 const Concrete::Coords2D * bestPoint = 0;
203 size_t idx = 0;
204 typedef typeof intersections_ ListType;
205 for( ListType::const_iterator i = intersections_.begin( ); i != intersections_.end( ); ++i, ++idx )
207 if( *i == 0 || *i == p )
209 continue;
211 Concrete::Length tmp = Concrete::inner( n, **i - my_p );
212 if( *i == bestPoint )
214 // The lines are compared by direction.
215 Concrete::UnitFloatPair dOld = lines[res].d_;
216 if( Concrete::inner( nIn, dOld ) < 0 )
218 dOld = dOld.reverse( );
220 Concrete::UnitFloatPair dNew = lines[idx].d_;
221 if( Concrete::inner( nIn, dNew ) < 0 )
223 dNew = dNew.reverse( );
225 if( Concrete::inner( back, dNew ) > Concrete::inner( back, dOld ) )
227 bestRes = tmp;
228 // bestPoint is already equal to *i
229 SPLICEDEBUG( std::cerr << "{" << res << "->" << idx << "}" );
230 res = idx;
233 else if( tmp > Concrete::ZERO_LENGTH && tmp < bestRes )
235 bestRes = tmp;
236 bestPoint = *i;
237 SPLICEDEBUG( std::cerr << "{" << idx << "}" );
238 res = idx;
241 if( bestRes == Concrete::HUGE_LENGTH )
243 SPLICEDEBUG( std::cerr << "none" << std::endl );
244 throw "no intersection";
246 SPLICEDEBUG( std::cerr << *intersections_[res] << std::endl );
247 return res;
250 Concrete::Length
251 Computation::SplicingLine::distanceTo( const Concrete::Coords2D p ) const
253 return ( Concrete::inner( n_, p ) - r_ ).abs( );
258 Computation::ZBufTriangle::ZBufTriangle( const Computation::PaintedPolygon3D * painter, const RefCountPtr< const Computation::ZBufTriangle::ZMap > & zMap, const Concrete::Coords2D & p1, const Concrete::Coords2D & p2, const Concrete::Coords2D & p3 )
259 : painter_( painter ), zMap_( zMap )
261 points_.reserve( 3 );
262 points_.push_back( p1 );
263 points_.push_back( p2 );
264 points_.push_back( p3 );
267 Concrete::Length
268 Computation::ZBufTriangle::zAt( const Concrete::Coords2D & p ) const
270 return (*zMap_)( p );
273 bool
274 Computation::ZBufTriangle::isOnTopOfAt( const Computation::ZBufTriangle & other, const Concrete::Coords2D & p ) const
276 Concrete::Length zThis = zAt( p );
277 Concrete::Length zOther = other.zAt( p );
279 Concrete::Length tThis = zMap_->getTiebreaker( );
280 Concrete::Length tOther = other.zMap_->getTiebreaker( );
281 if( ( zThis - zOther ).abs( ) < std::max( tThis, tOther ) )
283 return zThis + tThis > zOther + tOther;
286 return zThis > zOther;
290 // This function does the test with the tolerance interpretation such that a true return value
291 // means that the triangles really overlaps by some positive amount.
292 bool
293 Computation::ZBufTriangle::overlaps( const Computation::ZBufTriangle & other ) const
295 const std::vector< Concrete::Coords2D > & pointSet_a( points_ );
296 const std::vector< Concrete::Coords2D > & pointSet_b( other.points_ );
298 /* Do the circle-circle check
301 Concrete::Coords2D ca( 0, 0 );
302 for( std::vector< Concrete::Coords2D >::const_iterator i = pointSet_a.begin( );
303 i != pointSet_a.end( );
304 ++i )
306 ca = ca + *i;
308 ca = ca * (1./3);
310 Concrete::Coords2D cb( 0, 0 );
311 for( std::vector< Concrete::Coords2D >::const_iterator i = pointSet_b.begin( );
312 i != pointSet_b.end( );
313 ++i )
315 cb = cb + *i;
317 cb = cb * (1./3);
319 Concrete::Length ra( 0 );
320 for( std::vector< Concrete::Coords2D >::const_iterator i = pointSet_a.begin( );
321 i != pointSet_a.end( );
322 ++i )
324 ra = std::max( ra, hypotPhysical( ca.x_ - i->x_, ca.y_ - i->y_ ) );
327 Concrete::Length rb( 0 );
328 for( std::vector< Concrete::Coords2D >::const_iterator i = pointSet_b.begin( );
329 i != pointSet_b.end( );
330 ++i )
332 rb = std::max( rb, hypotPhysical( cb.x_ - i->x_, cb.y_ - i->y_ ) );
335 Concrete::Length rSum = ra + rb;
336 if( rSum <= Computation::theTrixelizeOverlapTol )
338 return false;
340 if( ( rSum - Computation::theTrixelizeOverlapTol ) * ( rSum - Computation::theTrixelizeOverlapTol ) < ( ca.x_ - cb.x_ ) * ( ca.x_ - cb.x_ ) + ( ca.y_ - cb.y_ ) * ( ca.y_ - cb.y_ ) )
342 return false;
346 /* Now to the search for a separating line.
348 if( ! oneWayOverlap( pointSet_a, pointSet_b ) )
350 return false;
352 if( ! oneWayOverlap( pointSet_b, pointSet_a ) )
354 return false;
356 return true;
359 // To be consistent with the tolerance interpretation in ZBufTriangle::overlaps, which returns true only if the triangles
360 // overlaps by some positive amount, this function shall rather return false than true.
361 // This means that we should prefer not to unflag allOutside.
362 bool
363 Computation::ZBufTriangle::oneWayOverlap( const std::vector< Concrete::Coords2D > & poly1, const std::vector< Concrete::Coords2D > & poly2 )
365 // If a bug is fixed here, remember to fix ZBufLine::overlaps too!
367 for( std::vector< Concrete::Coords2D >::const_iterator i0 = poly1.begin( ); i0 != poly1.end( ); ++i0 )
369 std::vector< Concrete::Coords2D >::const_iterator i1 = i0;
370 ++i1;
371 if( i1 == poly1.end( ) )
373 i1 = poly1.begin( );
375 std::vector< Concrete::Coords2D >::const_iterator i2 = i1;
376 ++i2;
377 if( i2 == poly1.end( ) )
379 i2 = poly1.begin( );
382 const Concrete::Coords2D & p0( *i0 );
383 const Concrete::Coords2D & p1( *i1 );
385 const Concrete::Length txUnnormed = p1.x_ - p0.x_;
386 const Concrete::Length tyUnnormed = p1.y_ - p0.y_;
387 const Physical< -1, 0 > invNorm = 1. / hypotPhysical( txUnnormed, tyUnnormed );
388 // First we guess what's the inward direction
389 double inx( - invNorm * tyUnnormed );
390 double iny( invNorm * txUnnormed );
391 // Then we check if it needs to be reversed
393 const Concrete::Length dx = i2->x_ - p0.x_;
394 const Concrete::Length dy = i2->y_ - p0.y_;
395 if( dx * inx + dy * iny < Concrete::ZERO_LENGTH )
397 inx = -inx;
398 iny = -iny;
402 bool allOutside = true;
403 for( std::vector< Concrete::Coords2D >::const_iterator p = poly2.begin( ); p != poly2.end( ); ++p )
405 const Concrete::Length dx = p->x_ - p0.x_;
406 const Concrete::Length dy = p->y_ - p0.y_;
407 if( inx * dx + iny * dy > Computation::theTrixelizeOverlapTol )
409 allOutside = false;
410 break;
413 if( allOutside )
415 return false;
419 /* Note that this is only one part of the test, only if both symmetric tests return true do the
420 * polygons overlap.
422 return true;
425 // tol shall be positive, and gives the smallest acceptable distance from commonPoint to the intersection boundary.
426 bool
427 Computation::ZBufTriangle::overlaps( const ZBufTriangle & other, Concrete::Coords2D * commonPoint, Concrete::Length tol ) const
429 // We set up a linear program, and use simplex to solve it.
431 // The linear program is to maximize the distance from the common point to the intersection boundary,
432 // and if the distance becomes greater than tol during the search, we're happy without locating the optimum.
434 const size_t N_CONSTRAINTS = 7;
435 const size_t N_VARIABLES = 3;
437 static double c[ N_VARIABLES ] = { 0, 0, 1 };
438 static double a[ N_CONSTRAINTS * N_VARIABLES ] =
439 { 0, 0, 1,
440 0, 0, 1,
441 0, 0, 1,
442 0, 0, 1,
443 0, 0, 1,
444 0, 0, 1 };
445 static double b[ N_CONSTRAINTS ];
446 static double x[ N_VARIABLES ];
448 Concrete::Length xmin = HUGE_VAL;
449 Concrete::Length ymin = HUGE_VAL;
451 typedef typeof points_ ListType;
452 for( ListType::const_iterator i = points_.begin( ); i != points_.end( ); ++i )
454 xmin = std::min( xmin, i->x_ );
455 ymin = std::min( ymin, i->y_ );
457 for( ListType::const_iterator i = other.points_.begin( ); i != other.points_.end( ); ++i )
459 xmin = std::min( xmin, i->x_ );
460 ymin = std::min( ymin, i->y_ );
462 Concrete::Coords2D llCorner( xmin, ymin );
464 addTriangleConstraints( llCorner, & a[ 0 ], & b[ 0 ] );
465 other.addTriangleConstraints( llCorner, & a[ 9 ], & b[ 3 ] );
467 // bShift is the amount _added_ to the right hand side in order to make the initial point feasible.
468 // It is computed via its additive inverse, and then the sign is changed.
469 // (The initial point will be feasible if the right hand side has no negative elements.)
470 double bShift = b[ 0 ];
471 for( const double * src = & b[ 1 ]; src != b + N_CONSTRAINTS; ++src )
473 bShift = std::min( bShift, *src );
475 bShift = - bShift;
477 for( double * dst = & b[ 0 ]; dst != b + N_CONSTRAINTS; ++dst )
479 *dst += bShift;
483 double optRes;
484 bool res;
487 res = Computation::theTwoTriangleSimplex.maximize( & x[0],
488 & optRes, static_cast< double >( Concrete::Length::offtype( tol ) ) + bShift,
489 & c[0], & a[0], & b[0] );
491 catch( const char * ball )
493 throw Exceptions::InternalError( ball );
496 if( optRes < bShift )
498 std::ostringstream msg;
499 msg << "ZBufTriangle::overlaps: Simplex couldn't find a truly feasible point; " << optRes << " < " << bShift << "." ;
500 WARN_OR_THROW( Exceptions::InternalError( strrefdup( msg ), true ) );
503 commonPoint->x_ = xmin + Concrete::Length( x[ 0 ] );
504 commonPoint->y_ = ymin + Concrete::Length( x[ 1 ] );
506 return res;
509 // tol shall be positive, and gives the smallest acceptable distance from a common point on line to the intersection boundary.
510 bool
511 Computation::ZBufTriangle::overlapsAlong( const ZBufTriangle & other, const Computation::SplicingLine & line, Concrete::Length tol ) const
513 // This is much simpler than the simplex solution to the general overlap problem. Unfortunately, it doesn't seem like
514 // just keeping track of an upper and lower bound of the time along the line, since this will very often involve division
515 // by tiny numbers when line is parallel to any of the triangle sides.
517 // Instead, I keep track of two points points on the line, initialized far away in both directions. When comparing against
518 // a triangle side, four situations can occur, given by which of the points that satisfy the constraint. If none of the points
519 // satisfy the constraint, there is no intersection along the line. If both satisfy the constraint, the constraint does not
520 // further restrict the points. In the remaining case, the point which does not satisfy the constraint is moved to the border.
522 // The tolerance is implemented by changing all constraints by tol.
524 Concrete::Coords2D upper = line.p0_ + ( 0.1 * std::numeric_limits< double >::max( ) ) * line.d_;
525 Concrete::Coords2D lower = line.p0_ - ( 0.1 * std::numeric_limits< double >::max( ) ) * line.d_;
527 // It is convenient to use the halfspace intersection representation of the triangles, so some
528 // code is borrowed from ZBufTriangle::overlaps.
529 // However, this time only two out of the three variables are used.
530 const size_t N_CONSTRAINTS = 3;
531 const size_t N_VARIABLES = 3;
533 static double a[ N_CONSTRAINTS * N_VARIABLES ];
534 static double b[ N_CONSTRAINTS ];
535 double * bend = & b[ 0 ] + N_CONSTRAINTS;
537 Concrete::Coords2D llCorner( 0, 0 ); // This does not matter, so we may take the origin for instance
539 addTriangleConstraints( llCorner, & a[ 0 ], & b[ 0 ] );
540 // Here's how the tolerance is implemented. Since the coefficients in are normalized outward normals,
541 // The triangles are shrunk by tol in all directions by subtracting tol from b.
542 const double * srca = & a[0];
543 for( const double * srcb = & b[ 0 ]; srcb != bend; ++srcb, srca += N_VARIABLES )
545 Concrete::UnitFloatPair n( *( srca ), *( srca + 1 ), bool( ) );
546 Concrete::Length m = Concrete::Length( *srcb ) - tol;
547 bool upperInside = Concrete::inner( n, upper ) < m;
548 bool lowerInside = Concrete::inner( n, lower ) < m;
550 if( upperInside && lowerInside )
552 continue;
554 if( upperInside )
556 // Move lower.
557 // That is, with lower = line.p0_ + t * line.d_, for some t, it shall also satisfy
558 // Concrete::inner( n, lower ) == m
559 lower = line.p0_ + ( ( m - Concrete::inner( n, line.p0_ ) ) / Concrete::inner( n, line.d_ ) ) * line.d_;
560 continue;
562 if( lowerInside )
564 // Move upper, see above.
565 upper = line.p0_ + ( ( m - Concrete::inner( n, line.p0_ ) ) / Concrete::inner( n, line.d_ ) ) * line.d_;
566 continue;
568 // None of the points did satisfy the constraint. Infeasible. No overlap.
569 return false;
573 other.addTriangleConstraints( llCorner, & a[ 0 ], & b[ 0 ] );
574 const double * srca = & a[0];
575 for( const double * srcb = & b[ 0 ]; srcb != bend; ++srcb, srca += N_VARIABLES )
577 Concrete::UnitFloatPair n( *( srca ), *( srca + 1 ), bool( ) );
578 Concrete::Length m = Concrete::Length( *srcb ) - tol;
579 bool upperInside = Concrete::inner( n, upper ) < m;
580 bool lowerInside = Concrete::inner( n, lower ) < m;
582 if( upperInside && lowerInside )
584 continue;
586 if( upperInside )
588 // Move lower.
589 // That is, with lower = line.p0_ + t * line.d_, for some t, it shall also satisfy
590 // Concrete::inner( n, lower ) == m
591 lower = line.p0_ + ( ( m - Concrete::inner( n, line.p0_ ) ) / Concrete::inner( n, line.d_ ) ) * line.d_;
592 continue;
594 if( lowerInside )
596 // Move upper, see above.
597 upper = line.p0_ + ( ( m - Concrete::inner( n, line.p0_ ) ) / Concrete::inner( n, line.d_ ) ) * line.d_;
598 continue;
600 // None of the points did satisfy the constraint. Infeasible. No overlap.
601 return false;
605 return true;
608 void
609 Computation::ZBufTriangle::addTriangleConstraints( Concrete::Coords2D llCorner, double * a, double * b ) const
611 typedef typeof points_ ListType;
612 ListType::const_iterator i0 = points_.begin( );
613 ListType::const_iterator i1 = i0;
614 ++i1;
615 ListType::const_iterator i2 = i1;
616 ++i2;
618 // Note that a is increased by 3 since one position holds a constant 1.
619 for( ; i0 != points_.end( ); i1 = i2, i2 = i0, ++i0, a += 3, ++b )
621 // It's important that the normal be normalized, for otherwise the interpretation of the common slack (the third variable) will be wrong.
622 Concrete::UnitFloatPair n = i0->normalizedOrthogonal( *i1 );
624 if( Concrete::inner( n, *i2 - *i0 ) < 0 )
626 // The normal points out.
627 *a = n.x_;
628 *(a+1) = n.y_;
629 *b = Concrete::Length::offtype( Concrete::inner( n, *i0 - llCorner ) );
631 else
633 // The normal points in -- reverse everything.
634 *a = - n.x_;
635 *(a+1) = - n.y_;
636 *b = - Concrete::Length::offtype( Concrete::inner( n, *i0 - llCorner ) );
642 std::ostream &
643 Computation::operator << ( std::ostream & os, const Computation::ZBufTriangle & self )
645 std::vector< Concrete::Coords2D >::const_iterator i = self.points_.begin( );
646 os << *i << " -- " ;
647 ++i;
648 os << *i << " -- " ;
649 ++i;
650 os << *i ;
651 return os;
654 Concrete::Area
655 Computation::ZBufTriangle::area( ) const
657 return Computation::triangleArea( points_[ 0 ], points_[ 1 ], points_[ 2 ] );
660 bool
661 Computation::ZBufTriangle::contains( const Concrete::Coords2D & p ) const
663 for( std::vector< Concrete::Coords2D >::const_iterator i0 = points_.begin( ); i0 != points_.end( ); ++i0 )
665 std::vector< Concrete::Coords2D >::const_iterator i1 = i0;
666 ++i1;
667 if( i1 == points_.end( ) )
669 i1 = points_.begin( );
671 std::vector< Concrete::Coords2D >::const_iterator i2 = i1;
672 ++i2;
673 if( i2 == points_.end( ) )
675 i2 = points_.begin( );
678 const Concrete::Coords2D & p0( *i0 );
679 const Concrete::Coords2D & p1( *i1 );
681 const double tx = ( p1.x_ - p0.x_ ).offtype< 1, 0 >( );
682 const double ty = ( p1.y_ - p0.y_ ).offtype< 1, 0 >( );
683 bool counterClockwise; // true when ( p0, p1 ) are ordered counter-clockwise around the interior.
685 const Concrete::Length dx = i2->x_ - p0.x_;
686 const Concrete::Length dy = i2->y_ - p0.y_;
687 counterClockwise = ( ty * dx - tx * dy < Concrete::ZERO_LENGTH );
691 const Concrete::Length dx = p.x_ - p0.x_;
692 const Concrete::Length dy = p.y_ - p0.y_;
693 if( ( ty * dx - tx * dy > Concrete::ZERO_LENGTH ) == counterClockwise )
695 return false;
700 return true;
704 // The larger <tol>, the more often will this function return true.
705 bool
706 Computation::ZBufTriangle::contains( const Concrete::Coords2D & p, Concrete::Length tol ) const
708 for( std::vector< Concrete::Coords2D >::const_iterator i0 = points_.begin( ); i0 != points_.end( ); ++i0 )
710 std::vector< Concrete::Coords2D >::const_iterator i1 = i0;
711 ++i1;
712 if( i1 == points_.end( ) )
714 i1 = points_.begin( );
716 std::vector< Concrete::Coords2D >::const_iterator i2 = i1;
717 ++i2;
718 if( i2 == points_.end( ) )
720 i2 = points_.begin( );
723 const Concrete::Coords2D & p0( *i0 );
724 const Concrete::Coords2D & p1( *i1 );
726 const Concrete::UnitFloatPair d = p0.normalizedOrthogonal( p1 );
727 if( Concrete::inner( d, *i2 - p0 ) < Concrete::ZERO_LENGTH )
729 // d points out
730 if( Concrete::inner( d, p - p0 ) > tol )
732 return false;
735 else
737 // d points in
738 if( Concrete::inner( d, p - p0 ) < - tol )
740 return false;
745 return true;
748 void
749 Computation::ZBufTriangle::pushLines( std::vector< Computation::SplicingLine > * dst ) const
751 for( std::vector< Concrete::Coords2D >::const_iterator i0 = points_.begin( ); i0 != points_.end( ); ++i0 )
753 std::vector< Concrete::Coords2D >::const_iterator i1 = i0;
754 ++i1;
755 if( i1 == points_.end( ) )
757 i1 = points_.begin( );
759 pushIfUnique( dst, *i0, *i1 );
763 void
764 Computation::ZBufTriangle::pushIntersection( std::vector< Computation::SplicingLine > * dst, const Computation::ZBufTriangle & other ) const
766 Concrete::Coords3D p0( 0, 0, 0 );
767 Concrete::Coords3D p1( 0, 0, 0 );
768 if( intersectionLinePoints( other, & p0, & p1 ) )
770 pushIfUnique( dst, p0, p1, false );
774 bool
775 Computation::ZBufTriangle::intersection( const Computation::ZBufTriangle & other, Computation::SplicingLine * line ) const
777 Concrete::Coords3D p03D( 0, 0, 0 );
778 Concrete::Coords3D p13D( 0, 0, 0 );
779 if( intersectionLinePoints( other, & p03D, & p13D ) )
781 const Concrete::Coords2D p0 = p03D.make2DAutomatic( zMap_->eyez( ) );
782 const Concrete::Coords2D p1 = p13D.make2DAutomatic( zMap_->eyez( ) );
783 *line = Computation::SplicingLine( p0, p1 - p0, false );
784 return true;
786 return false;
790 bool
791 Computation::ZBufTriangle::intersectionLinePoints( const Computation::ZBufTriangle & other, Concrete::Coords3D * p0, Concrete::Coords3D * p1 ) const
793 double a0[3];
794 Concrete::Length b0;
795 zMap_->writeToMatrices( a0, & b0 );
797 double a1[3];
798 Concrete::Length b1;
799 other.zMap_->writeToMatrices( a1, & b1 );
801 Concrete::Coords3D ray( a0[1]*a1[2] - a0[2]*a1[1],
802 a0[2]*a1[0] - a0[0]*a1[2],
803 a0[0]*a1[1] - a0[1]*a1[0] );
805 // If the ray is zero, the planes are paralell, so there's no splicing line to add.
806 if( ray.normScalar( ) < 1e-5 )
808 return false;
811 size_t bestCol = 4;
813 double * src = a0;
814 double bestAbs = 0;
815 for( size_t col_i = 0; col_i < 3; ++col_i, ++src )
817 double tmp = fabs( *src );
818 if( tmp > bestAbs )
820 bestAbs = tmp;
821 bestCol = col_i;
825 // Here, one could check that bestCol has really been assigned.
826 // To test if it is unassigned, test for bestCol == 4.
829 const double f = a1[bestCol] / a0[bestCol];
830 double * src = a0;
831 double * dst = a1;
832 for( ; src != a0 + 3; ++src, ++dst )
834 *dst -= f * *src;
836 b1 -= f * b0;
839 // The remaining two columns of the second row can now be used to determine the other two components.
840 // Let secondCol point out the biggest remaining element in a1, and zeroCol point out the column containing the smallest
841 // (non-zero) element.
842 // First, we guess...
843 size_t secondCol;
844 size_t zeroCol;
845 switch( bestCol )
847 case 0:
848 secondCol = 1;
849 zeroCol = 2;
850 break;
851 case 1:
852 secondCol = 0;
853 zeroCol = 2;
854 break;
855 case 2:
856 secondCol = 0;
857 zeroCol = 1;
858 break;
859 default:
860 throw Exceptions::InternalError( "pushIntersection: Column switch out of range." );
862 // ... then correct the guess if it's wrong
863 if( fabs( a1[secondCol] ) < fabs( a1[zeroCol] ) )
865 size_t tmp = zeroCol;
866 zeroCol = secondCol;
867 secondCol = tmp;
870 Concrete::Length res[3];
871 // Now it's time to determine the first two components of the solution.
872 res[zeroCol] = Concrete::ZERO_LENGTH;
873 res[secondCol] = b1 / a1[secondCol];
875 // and then the final component follows by back-substitution:
876 b0 -= a0[secondCol] * res[secondCol];
877 res[bestCol] = b0 / a0[bestCol];
879 *p0 = Concrete::Coords3D( res[0], res[1], res[2] );
880 *p1 = *p0 + Concrete::SOME_LENGTH * ray.direction( );
882 return true;
885 void
886 Computation::ZBufTriangle::pushIfUnique( std::vector< Computation::SplicingLine > * dst, const Concrete::Coords3D p03D, const Concrete::Coords3D p13D, bool isTriangleSide ) const
888 const Concrete::Coords2D p0 = p03D.make2DAutomatic( zMap_->eyez( ) );
889 const Concrete::Coords2D p1 = p13D.make2DAutomatic( zMap_->eyez( ) );
890 typedef typeof *dst ListType;
891 for( ListType::const_iterator i = dst->begin( ); i != dst->end( ); ++i )
893 if( i->distanceTo( p0 ) < Computation::theTrixelizeSplicingTol && i->distanceTo( p1 ) < Computation::theTrixelizeSplicingTol )
895 return;
898 dst->push_back( Computation::SplicingLine( p0, p1 - p0, isTriangleSide ) );
901 namespace Shapes
903 typedef std::pair< const Concrete::Coords2D *, const Concrete::Coords2D * > VisitType;
905 namespace std
907 template< >
908 class less< Shapes::VisitType >
910 public:
911 bool operator () ( const Shapes::VisitType & p1,
912 const Shapes::VisitType & p2 )
914 if( p1.first < p2.first )
916 return true;
918 if( p2.first < p1.first )
920 return false;
922 return p1.second < p2.second;
927 void
928 Computation::ZBufTriangle::splice( const ZBufTriangle & tOld, const ZBufTriangle & tNew, std::list< Computation::ZBufTriangle > * oldDisjointTriangles, std::list< Computation::ZBufTriangle > * oldOccludedTriangles, std::list< Computation::ZBufTriangle > * newDisjointTriangles, std::list< Computation::ZBufTriangle > * newOccludedTriangles, std::list< Computation::ZBufTriangle > * triangleQueue )
930 SPLICEDEBUG( std::cerr << "==== Overlapping triangles ====" << std::endl
931 << " old: " << tOld << std::endl
932 << " new: " << tNew << std::endl );
934 // This function is only called if the triangles overlap
936 std::vector< Computation::SplicingLine > lines;
938 tOld.pushLines( & lines );
939 tNew.pushLines( & lines );
941 tOld.pushIntersection( & lines, tNew );
943 const size_t numberOfLines = lines.size( );
945 SPLICEDEBUG( std::cerr << "#needs circle" << std::endl
946 << "#needs centering" << std::endl
947 << std::endl
948 << "@width:0bp" << std::endl
949 << "|" << std::endl
950 << "{" << std::endl
951 << "res: Hot2D <<" << std::endl );
954 typedef typeof lines ListType;
955 for( ListType::iterator i = lines.begin( ); i != lines.end( ); ++i )
957 SPLICEDEBUG( std::cerr << "|** Line " << ( i - lines.begin( ) ) << ": " );
958 // SPLICEDEBUG( std::cerr << i->p0_ << " -- " << i->p0_ + i->d_ * i->length_ << std::endl );
959 SPLICEDEBUG( std::cerr << std::endl
960 << "res << stroke [] "
961 << " (" << Helpers::shapesFormat( i->p0_.x_ ) << "," << Helpers::shapesFormat( i->p0_.y_ )
962 << ")--(" << Helpers::shapesFormat( (i->p0_ + i->d_ * i->length_).x_ ) << "," << Helpers::shapesFormat( (i->p0_ + i->d_ * i->length_).y_ ) << ")"
963 << std::endl );
964 i->intersections_.resize( numberOfLines, 0 );
969 std::vector< Concrete::Coords2D > intersectionsMem;
970 intersectionsMem.reserve( numberOfLines * ( numberOfLines - 1 ) / 2 );
973 typedef typeof lines ListType;
974 size_t idx_i = 0;
975 for( ListType::iterator i = lines.begin( ); i != lines.end( ); ++i, ++idx_i )
977 SPLICEDEBUG( std::cerr << "|** Line " << idx_i << " intersections: " );
978 SPLICEDEBUG( std::cerr << std::endl );
979 ListType::const_iterator j = i;
980 size_t idx_j = idx_i;
981 ++j;
982 ++idx_j;
983 for( ; j != lines.end( ); ++j, ++idx_j )
987 Concrete::Coords2D tmp = i->intersection( *j );
988 typedef typeof intersectionsMem VectorType;
989 bool reuse = false;
990 // We try to reuse an old point. Not to save space, but to make the algorithm more robust by
991 // perhaps avoiding some corner cases this way...
992 for( VectorType::const_iterator k = intersectionsMem.begin( ); k != intersectionsMem.end( ); ++k )
994 if( ( tmp - *k ).norm( ) < Computation::theTrixelizeSplicingTol )
996 // SPLICEDEBUG( std::cerr << "<" << tmp << "> " );
997 SPLICEDEBUG( std::cerr << "|** reusing <" << tmp << "> " << std::endl );
998 reuse = true;
999 lines[ idx_i ].intersections_[ idx_j ] = & *k;
1000 lines[ idx_j ].intersections_[ idx_i ] = & *k;
1001 break;
1004 if( ! reuse )
1006 // SPLICEDEBUG( std::cerr << tmp << " " );
1007 SPLICEDEBUG( std::cerr << "res << [shift (" << Helpers::shapesFormat( tmp.x_ ) << "," << Helpers::shapesFormat( tmp.y_ ) << ")] [] stroke [] [circle 0.1mm]" << std::endl );
1008 intersectionsMem.push_back( tmp );
1009 lines[ idx_i ].intersections_[ idx_j ] = & intersectionsMem.back( );
1010 lines[ idx_j ].intersections_[ idx_i ] = & intersectionsMem.back( );
1013 catch( const char * )
1015 // SPLICEDEBUG( std::cerr << "(no-int)" << " " );
1016 SPLICEDEBUG( std::cerr << "|** (no-int)" << std::endl );
1019 SPLICEDEBUG( std::cerr << std::endl );
1023 SPLICEDEBUG( std::cerr << "res;" << std::endl
1024 << "bb: [bbox res]" << std::endl
1025 << "@<< [scale 19cm/[max [xmax bb]-[xmin bb] [ymax bb]-[ymin bb]]] [] res" << std::endl
1026 << "}" << std::endl );
1028 std::set< VisitType > visited;
1030 for( size_t start_a = 0; start_a < numberOfLines; ++start_a )
1032 if( ! lines[ start_a ].isTriangleSide_ )
1034 continue;
1036 for( size_t start_b = 0; start_b < numberOfLines; ++start_b )
1038 if( start_b == start_a )
1040 continue;
1042 SPLICEDEBUG( std::cerr << "From line " << start_a << " to line " << start_b << std::endl );
1043 const Concrete::Coords2D * p0 = lines[ start_a ].intersections_[ start_b ];
1044 if( p0 == 0 )
1046 SPLICEDEBUG( std::cerr << " No intersection" << std::endl );
1047 continue;
1049 Concrete::UnitFloatPair start_n = lines[ start_a ].n_;
1050 for( char start_n_i = 0; start_n_i < 2; ++start_n_i, start_n = start_n.reverse( ) )
1052 SPLICEDEBUG( std::cerr << " Starting direction " << static_cast< int >( start_n_i ) << std::endl );
1053 Concrete::UnitFloatPair n = start_n;
1054 size_t currentLine = start_b;
1055 size_t nextLine;
1058 nextLine = lines[ currentLine ].nextLine( p0, n, lines );
1059 SPLICEDEBUG( std::cerr << "Line " << currentLine << " --> " << nextLine << std::endl );
1061 catch( const char * ball )
1063 continue;
1065 const Concrete::Coords2D * p1 = lines[ currentLine ].intersections_[ nextLine ];
1066 if( visited.find( VisitType( p0, p1 ) ) != visited.end( ) )
1068 SPLICEDEBUG( std::cerr << *p0 << " --> " << *p1 << " already visited" << std::endl );
1069 continue;
1071 visited.insert( VisitType( p0, p1 ) );
1073 // visitedLines is used to tell when we have completed a polygon; when a line is visited a second time,
1074 // the polygon is complete. The first point is on start_b. start_a is only used to give a direction along
1075 // start_b.
1076 std::vector< bool > visitedLines;
1077 visitedLines.resize( numberOfLines, false );
1078 visitedLines[ currentLine ] = true;
1081 Concrete::UnitFloatPair oldn = n;
1082 n = lines[ currentLine ].n_;
1083 if( - oldn.y_ * n.x_ + oldn.x_ * n.y_ < 0 )
1085 n = n.reverse( );
1089 const Concrete::Coords2D * p2 = 0;
1091 currentLine = nextLine;
1094 nextLine = lines[ currentLine ].nextLine( p1, n, lines );
1095 SPLICEDEBUG( std::cerr << "Line " << currentLine << " --> " << nextLine << std::endl );
1097 catch( const char * ball )
1099 SPLICEDEBUG( std::cerr << "Line " << currentLine << " --> " << "infinity! (no enclosed region)" << std::endl );
1100 continue;
1102 p2 = lines[ currentLine ].intersections_[ nextLine ];
1103 visited.insert( VisitType( p1, p2 ) );
1104 visitedLines[ currentLine ] = true;
1106 // Here, we choose a way to compute a point well inside the *p0--*p1--*p2 triangle.
1107 // Using the mean is quick, but the incenter should be more robust.
1108 Concrete::Coords2D mean = (1./3) * ( *p0 + *p1 + *p2 );
1109 // Concrete::Coords2D mean = Computation::triangleIncenter( *p0, *p1, *p2 );
1111 // The following test never triggers, which is good.
1112 // if( tOld.contains( mean ) &&
1113 // ( ( ! tOld.contains( *p0, Computation::theTrixelizeSplicingTol ) ) ||
1114 // ( ! tOld.contains( *p1, Computation::theTrixelizeSplicingTol ) ) ||
1115 // ( ! tOld.contains( *p2, Computation::theTrixelizeSplicingTol ) ) ) )
1116 // {
1117 // throw Exceptions::InternalError( "ZBufTriangle::splice: tOld contains mean but not all corners!" );
1118 // }
1119 // if( tNew.contains( mean ) &&
1120 // ( ( ! tNew.contains( *p0, Computation::theTrixelizeSplicingTol ) ) ||
1121 // ( ! tNew.contains( *p1, Computation::theTrixelizeSplicingTol ) ) ||
1122 // ( ! tNew.contains( *p2, Computation::theTrixelizeSplicingTol ) ) ) )
1123 // {
1124 // throw Exceptions::InternalError( "ZBufTriangle::splice: tNew contains mean but not all corners!" );
1125 // }
1129 const Computation::ZBufTriangle * topTriangle = 0;
1130 bool reQueue = true;
1131 std::list< Computation::ZBufTriangle > * disjointDestination = 0; // this must be assigned when ( ! reQueue )
1132 if( tOld.contains( mean ) )
1134 reQueue = false;
1135 if( tNew.contains( mean ) )
1137 if( tOld.isOnTopOfAt( tNew, mean ) )
1139 topTriangle = & tOld;
1140 disjointDestination = oldDisjointTriangles;
1141 SPLICEDEBUG( std::cerr << "Part of tOld" << std::endl );
1143 else
1145 topTriangle = & tNew;
1146 disjointDestination = newDisjointTriangles;
1147 SPLICEDEBUG( std::cerr << "Part of tNew" << std::endl );
1150 else
1152 topTriangle = & tOld;
1153 disjointDestination = oldDisjointTriangles;
1154 SPLICEDEBUG( std::cerr << "Part of tOld" << std::endl );
1157 else
1159 if( tNew.contains( mean ) )
1161 topTriangle = & tNew;
1162 SPLICEDEBUG( std::cerr << "Part of tNew" << std::endl );
1164 else
1166 SPLICEDEBUG( std::cerr << "Outside painted area" << std::endl );
1167 continue;
1171 size_t undoSize;
1172 if( reQueue )
1174 undoSize = triangleQueue->size( );
1176 else
1178 undoSize = disjointDestination->size( );
1181 // This tolerance test assures that we don't produce tiny-tiny triangles.
1182 if( Computation::triangleArea( *p0, *p1, *p2 ) > Computation::theTrixelizeOverlapTol * Computation::triangleSemiPerimeter( *p0, *p1, *p2 ) )
1184 if( reQueue )
1186 triangleQueue->push_back( Computation::ZBufTriangle( topTriangle->painter_,
1187 topTriangle->zMap_,
1188 *p0, *p1, *p2) );
1190 else
1192 disjointDestination->push_back( Computation::ZBufTriangle( topTriangle->painter_,
1193 topTriangle->zMap_,
1194 *p0, *p1, *p2) );
1197 p1 = p2;
1200 Concrete::UnitFloatPair oldn = n;
1201 n = lines[ currentLine ].n_;
1202 if( - oldn.y_ * n.x_ + oldn.x_ * n.y_ < 0 )
1204 n = n.reverse( );
1208 bool insertTriangles = true;
1210 while( ! visitedLines[ nextLine ] )
1212 currentLine = nextLine;
1215 nextLine = lines[ currentLine ].nextLine( p1, n, lines );
1216 SPLICEDEBUG( std::cerr << "Line " << currentLine << " --> " << nextLine << std::endl );
1218 catch( const char * ball )
1220 SPLICEDEBUG( std::cerr << "Line " << currentLine << " --> " << "infinity! (no enclosed region)" << std::endl );
1221 insertTriangles = false;
1222 break;
1224 p2 = lines[ currentLine ].intersections_[ nextLine ];
1225 visited.insert( VisitType( p1, p2 ) );
1226 visitedLines[ currentLine ] = true;
1228 if( Computation::triangleArea( *p0, *p1, *p2 ) > Computation::theTrixelizeOverlapTol * Computation::triangleSemiPerimeter( *p0, *p1, *p2 ) )
1230 if( reQueue )
1232 triangleQueue->push_back( Computation::ZBufTriangle( topTriangle->painter_,
1233 topTriangle->zMap_,
1234 *p0, *p1, *p2) );
1236 else
1238 disjointDestination->push_back( Computation::ZBufTriangle( topTriangle->painter_,
1239 topTriangle->zMap_,
1240 *p0, *p1, *p2) );
1243 p1 = p2;
1246 Concrete::UnitFloatPair oldn = n;
1247 n = lines[ currentLine ].n_;
1248 if( - oldn.y_ * n.x_ + oldn.x_ * n.y_ < 0 )
1250 n = n.reverse( );
1254 if( insertTriangles )
1256 visited.insert( VisitType( p2, p0 ) );
1257 SPLICEDEBUG( std::cerr << "Found new region." << std::endl );
1259 else
1261 if( reQueue )
1263 while( triangleQueue->size( ) > undoSize )
1265 triangleQueue->pop_back( );
1268 else
1270 while( disjointDestination->size( ) > undoSize )
1272 disjointDestination->pop_back( );
1281 std::list< Computation::ZBufTriangle >::iterator
1282 Computation::ZBufTriangle::spliceAlong( const Computation::SplicingLine & line, std::list< Computation::ZBufTriangle > * dst ) const
1285 // Two of the triangle sides will be intersected by the line. A second line will have to be added to split the bottom
1286 // part of the splitted triangle in two triangles.
1287 // First two two intersections are identified along with the sides they belong to. Then the triangle corners can be identified
1288 // and the three triangles be created.
1290 // Let p0 be the point on the intersection of the intereced triangle sides.
1291 // Let pa be the intersection on the line p0--p1,
1292 // and pb be the intersection on the line p0--p2.
1294 // This variable holds each corner points (signed) distance to the line.
1295 Concrete::Length lineDists[ 3 ];
1297 Concrete::Length * distDst = & lineDists[ 0 ];
1298 for( std::vector< Concrete::Coords2D >::const_iterator i = points_.begin( ); i != points_.end( ); ++i, ++distDst )
1300 *distDst = Concrete::inner( line.n_, *i ) - line.r_;
1304 // However, the special case when the line intersects one of the corners will generate just two triangles. This case is
1305 // considered first.
1307 const Concrete::Length * distSrc = & lineDists[ 0 ];
1308 for( std::vector< Concrete::Coords2D >::const_iterator i = points_.begin( ); i != points_.end( ); ++i, ++distSrc )
1310 if( distSrc->abs( ) < Computation::theTrixelizeSplicingTol )
1312 // Here p0 coincides either of pa or pb, and here it is *i.
1313 // Let pa denote the intersection with the opposide triangle side.
1315 // Let p1 be *i1:
1316 std::vector< Concrete::Coords2D >::const_iterator i1 = i;
1317 ++i1;
1318 if( i1 == points_.end( ) )
1320 i1 = points_.begin( );
1323 // Let p2 be *i2:
1324 std::vector< Concrete::Coords2D >::const_iterator i2 = i1;
1325 ++i2;
1326 if( i2 == points_.end( ) )
1328 i2 = points_.begin( );
1331 // Parameterize the line segment from p1 to p2 as ( p1 + t * d )
1332 Concrete::Coords2D d = *i2 - *i1;
1333 // Then t can be computed easily using the equation of the line.
1334 Concrete::Coords2D pa = *i1 + ( ( line.r_ - Concrete::inner( line.n_, *i1 ) ) / Concrete::inner( line.n_, d ) ) * d;
1336 dst->push_back( Computation::ZBufTriangle( painter_,
1337 zMap_,
1338 *i1, *i, pa) );
1339 std::list< Computation::ZBufTriangle >::iterator res = dst->end( );
1340 --res;
1342 dst->push_back( Computation::ZBufTriangle( painter_,
1343 zMap_,
1344 *i2, *i, pa) );
1345 return res;
1350 // Turning the question of intersecting sides around, I search for the side which is not intersected by the line.
1351 // This side is identified by its both endpoints being on the same side of the line.
1352 // By now we assume that we don't run into corner cases when there's no clear cut.
1354 // Since only one line can avoid being intersected by the line, two distances will have the same sign, and the last
1355 // corner will have a distance to the line of the other sign. Hence, the product of all signs will be the sign of the corner
1356 // not belonging to the avoiding line.
1357 bool p0sign = ( lineDists[ 0 ] > 0 ) ^ ( lineDists[ 1 ] > 0 ) ^ ( lineDists[ 2 ] > 0 );
1360 const Concrete::Length * distSrc = & lineDists[ 0 ];
1361 for( std::vector< Concrete::Coords2D >::const_iterator i = points_.begin( ); i != points_.end( ); ++i, ++distSrc )
1363 if( ( *distSrc > 0 ) == p0sign )
1365 // We have p0 being *i
1367 // Let p1 be *i1:
1368 std::vector< Concrete::Coords2D >::const_iterator i1 = i;
1369 ++i1;
1370 if( i1 == points_.end( ) )
1372 i1 = points_.begin( );
1375 // Let p2 be *i1:
1376 std::vector< Concrete::Coords2D >::const_iterator i2 = i1;
1377 ++i2;
1378 if( i2 == points_.end( ) )
1380 i2 = points_.begin( );
1383 // Parameterize the line segment from p0 to p1 as ( p0 + ta * da )
1384 Concrete::Coords2D da = *i1 - *i;
1385 // Then ta can be computed easily using the equation of the line, and then inserted to obtain pa.
1386 Concrete::Coords2D pa = *i + ( ( line.r_ - Concrete::inner( line.n_, *i ) ) / Concrete::inner( line.n_, da ) ) * da;
1388 // Parameterize the line segment from p0 to p2 as ( p0 + tb * db )
1389 Concrete::Coords2D db = *i2 - *i;
1390 // Then tb can be computed easily using the equation of the line, and then inserted to obtain pb.
1391 Concrete::Coords2D pb = *i + ( ( line.r_ - Concrete::inner( line.n_, *i ) ) / Concrete::inner( line.n_, db ) ) * db;
1393 dst->push_back( Computation::ZBufTriangle( painter_,
1394 zMap_,
1395 *i, pa, pb) );
1396 std::list< Computation::ZBufTriangle >::iterator res = dst->end( );
1397 --res;
1399 dst->push_back( Computation::ZBufTriangle( painter_,
1400 zMap_,
1401 *i1, pa, pb) );
1402 dst->push_back( Computation::ZBufTriangle( painter_,
1403 zMap_,
1404 *i1, *i2, pb) );
1406 return res;
1411 throw Exceptions::InternalError( "Failed to identify p0 when splicing triangle along a line." );
1415 RefCountPtr< const Lang::ElementaryPath2D >
1416 Computation::ZBufTriangle::toPath( ) const
1418 Lang::ElementaryPath2D * res = new Lang::ElementaryPath2D;
1420 for( std::vector< Concrete::Coords2D >::const_iterator i = points_.begin( ); i != points_.end( ); ++i )
1422 res->push_back( new Concrete::PathPoint2D( i->x_, i->y_ ) );
1424 res->close( );
1426 return RefCountPtr< const Lang::ElementaryPath2D >( res );
1429 RefCountPtr< const Lang::Drawable2D >
1430 Computation::ZBufTriangle::debugFrame( ) const
1432 const Concrete::Coords2D & p1( points_[ 0 ] );
1433 const Concrete::Coords2D & p2( points_[ 1 ] );
1434 const Concrete::Coords2D & p3( points_[ 2 ] );
1436 SPLICEDEBUG( std::cerr << "Debug frame: " << p1 << " -- " << p2 << " -- " << p3 << std::endl ; )
1438 Kernel::GraphicsState * discStatePtr = new Kernel::GraphicsState( true );
1439 discStatePtr->cap_ = Lang::CapStyle::CAP_ROUND;
1440 discStatePtr->width_ = 2 * Computation::triangleArea( p1, p2, p3 ) / Computation::triangleSemiPerimeter( p1, p2, p3 );
1441 discStatePtr->strokingColor_ = painter_->getColor( );
1442 RefCountPtr< const Kernel::GraphicsState > discState( discStatePtr );
1444 Kernel::GraphicsState * frameStatePtr = new Kernel::GraphicsState( true );
1445 frameStatePtr->width_ = Concrete::Length( 0.2 );
1446 RefCountPtr< const Kernel::GraphicsState > frameState( frameStatePtr );
1448 Lang::ElementaryPath2D * pointPath = new Lang::ElementaryPath2D;
1449 const Concrete::Coords2D incenter = Computation::triangleIncenter( p1, p2, p3 );
1450 pointPath->push_back( new Concrete::PathPoint2D( incenter.x_, incenter.y_ ) );
1451 pointPath->push_back( new Concrete::PathPoint2D( incenter.x_, incenter.y_ ) );
1453 SPLICEDEBUG( std::cerr << " incenter: " << incenter << std::endl );
1454 SPLICEDEBUG( std::cerr << " radius: " << Lang::Length( discState->width_ ) << std::endl );
1456 return Helpers::newSolidTransparencyGroup( RefCountPtr< const Lang::Drawable2D >
1457 ( new Lang::PaintedPath2D( frameState, toPath( ), "S" ) ),
1458 RefCountPtr< const Lang::Drawable2D >
1459 ( new Lang::PaintedPath2D( discState, RefCountPtr< const Lang::ElementaryPath2D >( pointPath ), "S" ) ) );