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, 2010 Henrik Tidefelt
21 #include "shapestypes.h"
22 #include "shapesexceptions.h"
25 #include "angleselect.h"
28 #include "statetypes.h"
29 #include "lighttypes.h"
30 #include "shadingtypes.h"
32 #include "trianglefunctions.h"
33 #include "basicsimplex.h"
34 #include "zbufinternals.h"
35 #include "constructorrepresentation.h"
43 using namespace Shapes
;
46 #define SPLICEDEBUG( code ) // code
49 assertNotOverlapping( const std::list
< Computation::ZBufTriangle
> & disjointTriangles
)
52 typedef typeof disjointTriangles ListType
;
53 ListType::const_iterator last
= disjointTriangles
.end( );
55 for( ListType::const_iterator i
= disjointTriangles
.begin( ); i
!= last
; ++i
)
57 if( last
->overlaps( *i
) )
59 throw Exceptions::InternalError( "assertNotOverlapping triggered" );
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
;
71 if( i1
== poly
.end( ) )
75 Lang::ZBuf::PolyIndices::const_iterator i2
= i1
;
77 if( i2
== poly
.end( ) )
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
,
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
)
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
);
106 Computation::ZBufTriangle::ZMap::writeToMatrices( double a
[3], Concrete::Length
* b
) const
114 Computation::SplicingLine::SplicingLine( const Concrete::Coords2D
& p0
, const Concrete::Coords2D
& p1_sub_p0
, bool isTriangleSide
)
115 : isTriangleSide_( isTriangleSide
),
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_
),
127 length_( orig
.length_
),
132 Computation::SplicingLine::SplicingLine( )
133 : isTriangleSide_( false ),
135 d_( 1., 0., bool( ) ),
137 n_( 0., -1., bool( ) ),
142 Computation::SplicingLine::intersection( const Computation::SplicingLine
& other
) const
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";
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_
);
201 Concrete::Length
bestRes( HUGE_VAL
);
202 const Concrete::Coords2D
* bestPoint
= 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
)
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
) )
228 // bestPoint is already equal to *i
229 SPLICEDEBUG( std::cerr
<< "{" << res
<< "->" << idx
<< "}" );
233 else if( tmp
> Concrete::ZERO_LENGTH
&& tmp
< bestRes
)
237 SPLICEDEBUG( std::cerr
<< "{" << 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
);
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
);
268 Computation::ZBufTriangle::zAt( const Concrete::Coords2D
& p
) const
270 return (*zMap_
)( p
);
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.
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( );
310 Concrete::Coords2D
cb( 0, 0 );
311 for( std::vector
< Concrete::Coords2D
>::const_iterator i
= pointSet_b
.begin( );
312 i
!= pointSet_b
.end( );
319 Concrete::Length
ra( 0 );
320 for( std::vector
< Concrete::Coords2D
>::const_iterator i
= pointSet_a
.begin( );
321 i
!= pointSet_a
.end( );
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( );
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
)
340 if( ( rSum
- Computation::theTrixelizeOverlapTol
) * ( rSum
- Computation::theTrixelizeOverlapTol
) < ( ca
.x_
- cb
.x_
) * ( ca
.x_
- cb
.x_
) + ( ca
.y_
- cb
.y_
) * ( ca
.y_
- cb
.y_
) )
346 /* Now to the search for a separating line.
348 if( ! oneWayOverlap( pointSet_a
, pointSet_b
) )
352 if( ! oneWayOverlap( pointSet_b
, pointSet_a
) )
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.
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
;
371 if( i1
== poly1
.end( ) )
375 std::vector
< Concrete::Coords2D
>::const_iterator i2
= i1
;
377 if( i2
== poly1
.end( ) )
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
)
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
)
419 /* Note that this is only one part of the test, only if both symmetric tests return true do the
425 // tol shall be positive, and gives the smallest acceptable distance from commonPoint to the intersection boundary.
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
] =
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
);
477 for( double * dst
= & b
[ 0 ]; dst
!= b
+ N_CONSTRAINTS
; ++dst
)
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 ] );
509 // tol shall be positive, and gives the smallest acceptable distance from a common point on line to the intersection boundary.
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
)
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_
;
564 // Move upper, see above.
565 upper
= line
.p0_
+ ( ( m
- Concrete::inner( n
, line
.p0_
) ) / Concrete::inner( n
, line
.d_
) ) * line
.d_
;
568 // None of the points did satisfy the constraint. Infeasible. No overlap.
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
)
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_
;
596 // Move upper, see above.
597 upper
= line
.p0_
+ ( ( m
- Concrete::inner( n
, line
.p0_
) ) / Concrete::inner( n
, line
.d_
) ) * line
.d_
;
600 // None of the points did satisfy the constraint. Infeasible. No overlap.
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
;
615 ListType::const_iterator i2
= i1
;
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.
629 *b
= Concrete::Length::offtype( Concrete::inner( n
, *i0
- llCorner
) );
633 // The normal points in -- reverse everything.
636 *b
= - Concrete::Length::offtype( Concrete::inner( n
, *i0
- llCorner
) );
643 Computation::operator << ( std::ostream
& os
, const Computation::ZBufTriangle
& self
)
645 std::vector
< Concrete::Coords2D
>::const_iterator i
= self
.points_
.begin( );
655 Computation::ZBufTriangle::area( ) const
657 return Computation::triangleArea( points_
[ 0 ], points_
[ 1 ], points_
[ 2 ] );
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
;
667 if( i1
== points_
.end( ) )
669 i1
= points_
.begin( );
671 std::vector
< Concrete::Coords2D
>::const_iterator i2
= i1
;
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
)
704 // The larger <tol>, the more often will this function return true.
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
;
712 if( i1
== points_
.end( ) )
714 i1
= points_
.begin( );
716 std::vector
< Concrete::Coords2D
>::const_iterator i2
= i1
;
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
)
730 if( Concrete::inner( d
, p
- p0
) > tol
)
738 if( Concrete::inner( d
, p
- p0
) < - tol
)
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
;
755 if( i1
== points_
.end( ) )
757 i1
= points_
.begin( );
759 pushIfUnique( dst
, *i0
, *i1
);
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 );
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 );
791 Computation::ZBufTriangle::intersectionLinePoints( const Computation::ZBufTriangle
& other
, Concrete::Coords3D
* p0
, Concrete::Coords3D
* p1
) const
795 zMap_
->writeToMatrices( a0
, & b0
);
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 )
815 for( size_t col_i
= 0; col_i
< 3; ++col_i
, ++src
)
817 double tmp
= fabs( *src
);
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
];
832 for( ; src
!= a0
+ 3; ++src
, ++dst
)
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...
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
;
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( );
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
)
898 dst
->push_back( Computation::SplicingLine( p0
, p1
- p0
, isTriangleSide
) );
903 typedef std::pair
< const Concrete::Coords2D
*, const Concrete::Coords2D
* > VisitType
;
908 class less
< Shapes::VisitType
>
911 bool operator () ( const Shapes::VisitType
& p1
,
912 const Shapes::VisitType
& p2
)
914 if( p1
.first
< p2
.first
)
918 if( p2
.first
< p1
.first
)
922 return p1
.second
< p2
.second
;
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
948 << "@width:0bp" << 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_
) << ")"
964 i
->intersections_
.resize( numberOfLines
, 0 );
969 std::vector
< Concrete::Coords2D
> intersectionsMem
;
970 intersectionsMem
.reserve( numberOfLines
* ( numberOfLines
- 1 ) / 2 );
973 typedef typeof lines ListType
;
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
;
983 for( ; j
!= lines
.end( ); ++j
, ++idx_j
)
987 Concrete::Coords2D tmp
= i
->intersection( *j
);
988 typedef typeof intersectionsMem VectorType
;
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
);
999 lines
[ idx_i
].intersections_
[ idx_j
] = & *k
;
1000 lines
[ idx_j
].intersections_
[ idx_i
] = & *k
;
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_
)
1036 for( size_t start_b
= 0; start_b
< numberOfLines
; ++start_b
)
1038 if( start_b
== start_a
)
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
];
1046 SPLICEDEBUG( std::cerr
<< " No intersection" << std::endl
);
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
;
1058 nextLine
= lines
[ currentLine
].nextLine( p0
, n
, lines
);
1059 SPLICEDEBUG( std::cerr
<< "Line " << currentLine
<< " --> " << nextLine
<< std::endl
);
1061 catch( const char * ball
)
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
);
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
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 )
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
);
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 ) ) ) )
1117 // throw Exceptions::InternalError( "ZBufTriangle::splice: tOld contains mean but not all corners!" );
1119 // if( tNew.contains( mean ) &&
1120 // ( ( ! tNew.contains( *p0, Computation::theTrixelizeSplicingTol ) ) ||
1121 // ( ! tNew.contains( *p1, Computation::theTrixelizeSplicingTol ) ) ||
1122 // ( ! tNew.contains( *p2, Computation::theTrixelizeSplicingTol ) ) ) )
1124 // throw Exceptions::InternalError( "ZBufTriangle::splice: tNew contains mean but not all corners!" );
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
) )
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
);
1145 topTriangle
= & tNew
;
1146 disjointDestination
= newDisjointTriangles
;
1147 SPLICEDEBUG( std::cerr
<< "Part of tNew" << std::endl
);
1152 topTriangle
= & tOld
;
1153 disjointDestination
= oldDisjointTriangles
;
1154 SPLICEDEBUG( std::cerr
<< "Part of tOld" << std::endl
);
1159 if( tNew
.contains( mean
) )
1161 topTriangle
= & tNew
;
1162 SPLICEDEBUG( std::cerr
<< "Part of tNew" << std::endl
);
1166 SPLICEDEBUG( std::cerr
<< "Outside painted area" << std::endl
);
1174 undoSize
= triangleQueue
->size( );
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
) )
1186 triangleQueue
->push_back( Computation::ZBufTriangle( topTriangle
->painter_
,
1192 disjointDestination
->push_back( Computation::ZBufTriangle( topTriangle
->painter_
,
1200 Concrete::UnitFloatPair oldn
= n
;
1201 n
= lines
[ currentLine
].n_
;
1202 if( - oldn
.y_
* n
.x_
+ oldn
.x_
* n
.y_
< 0 )
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;
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
) )
1232 triangleQueue
->push_back( Computation::ZBufTriangle( topTriangle
->painter_
,
1238 disjointDestination
->push_back( Computation::ZBufTriangle( topTriangle
->painter_
,
1246 Concrete::UnitFloatPair oldn
= n
;
1247 n
= lines
[ currentLine
].n_
;
1248 if( - oldn
.y_
* n
.x_
+ oldn
.x_
* n
.y_
< 0 )
1254 if( insertTriangles
)
1256 visited
.insert( VisitType( p2
, p0
) );
1257 SPLICEDEBUG( std::cerr
<< "Found new region." << std::endl
);
1263 while( triangleQueue
->size( ) > undoSize
)
1265 triangleQueue
->pop_back( );
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.
1316 std::vector
< Concrete::Coords2D
>::const_iterator i1
= i
;
1318 if( i1
== points_
.end( ) )
1320 i1
= points_
.begin( );
1324 std::vector
< Concrete::Coords2D
>::const_iterator i2
= i1
;
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_
,
1339 std::list
< Computation::ZBufTriangle
>::iterator res
= dst
->end( );
1342 dst
->push_back( Computation::ZBufTriangle( painter_
,
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
1368 std::vector
< Concrete::Coords2D
>::const_iterator i1
= i
;
1370 if( i1
== points_
.end( ) )
1372 i1
= points_
.begin( );
1376 std::vector
< Concrete::Coords2D
>::const_iterator i2
= i1
;
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_
,
1396 std::list
< Computation::ZBufTriangle
>::iterator res
= dst
->end( );
1399 dst
->push_back( Computation::ZBufTriangle( painter_
,
1402 dst
->push_back( Computation::ZBufTriangle( painter_
,
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_
) );
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" ) ) );