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, 2014 Henrik Tidefelt
21 #include "shapestypes.h"
22 #include "shapesexceptions.h"
24 #include "angleselect.h"
28 using namespace Shapes
;
33 Lang::CompositePath2D::computeElementaryPath( ) const
35 if( elementaryPath_
!= NullPtr
< const Lang::ElementaryPath2D
>( ) )
39 Lang::ElementaryPath2D
* pth
= new Lang::ElementaryPath2D
;
41 const double GAMMA_ANGLE
= 0.5;
43 Concrete::Coords2D
basePoint( 0, 0 );
45 std::stack
< const Lang::Value
* > nodeStack
;
46 nodeStack
.push( this );
47 while( ! nodeStack
.empty( ) )
49 const Lang::Value
* node
= nodeStack
.top( );
51 switch( node
->getTypeID( ) )
53 SINGLELOOP1( CLASSTREE1_Coords2D
, QUICKTYPECASE
)
55 const Lang::Coords2D
* coords
= dynamic_cast< const Lang::Coords2D
* >( node
);
56 /* We don't care if the point has an angle since there are no handles.
57 * Perhaps it should be an error.
60 const Lang::CornerCoords2D * tmp = dynamic_cast< const Lang::CornerCoords2D * >( coords );
63 newPoint->defaultAngle = tmp->a_;
66 Concrete::Coords2D
* newMid
= new Concrete::Coords2D( basePoint
, *coords
);
68 pth
->push_back( new Concrete::PathPoint2D( newMid
) );
71 SINGLELOOP1( CLASSTREE1_PathPoint2D
, QUICKTYPECASE
)
73 const Lang::PathPoint2D
* pathPoint
= reinterpret_cast< const Lang::PathPoint2D
* >( node
);
74 Concrete::Coords2D
* newMid
= new Concrete::Coords2D( basePoint
, *(pathPoint
->mid_
) );
76 Concrete::PathPoint2D
* newPoint
= new Concrete::PathPoint2D( newMid
);
79 const Lang::CornerCoords2D
* tmp
= dynamic_cast< const Lang::CornerCoords2D
* >( pathPoint
->mid_
.getPtr( ) );
82 newPoint
->defaultAngle_
= tmp
->a_
;
86 if( pathPoint
->rear_
!= NullPtr
< const Lang::Value
>( ) )
88 newPoint
->rear_
= new Concrete::Coords2D( 0, 0 );
90 typedef const Lang::Coords2D
* VariableHandle
;
91 VariableHandle typedHandle
= dynamic_cast< VariableHandle
>( pathPoint
->rear_
.getPtr( ) );
92 if( typedHandle
!= 0 )
94 *(newPoint
->rear_
) = Concrete::Coords2D( basePoint
, *typedHandle
);
95 Concrete::Length dx
= newPoint
->rear_
->x_
- newPoint
->mid_
->x_
;
96 Concrete::Length dy
= newPoint
->rear_
->y_
- newPoint
->mid_
->y_
;
97 newPoint
->rearAngle_
= atan2( dy
.offtype
< 1, 0 >( ), dx
.offtype
< 1, 0 >( ) );
98 newPoint
->rearModulus_
= hypotPhysical( dx
, dy
);
99 newPoint
->rearState_
= Concrete::PathPoint2D::COMPLETE
;
103 newPoint
->rearState_
= Concrete::PathPoint2D::UNFORCED_M
; // This is the normal case, the only exception being rectangular handles
104 pth
->allComplete_
= false;
106 typedef const Lang::PolarHandle2D
* VariableHandle
;
107 VariableHandle typedHandle
= dynamic_cast< VariableHandle
>( pathPoint
->rear_
.getPtr( ) );
108 if( typedHandle
!= 0 )
110 newPoint
->rearModulusPromise_
= typedHandle
->rPromise_
;
111 newPoint
->rearAngle_
= typedHandle
->a_
;
112 newPoint
->rearState_
|= Concrete::PathPoint2D::COMPLETE
; // This is just a no-op way of saying "keep it UNFORCED_M"
117 typedef const Lang::PolarHandle2DFree_a
* VariableHandle
;
118 VariableHandle typedHandle
= dynamic_cast< VariableHandle
>( pathPoint
->rear_
.getPtr( ) );
119 if( typedHandle
!= 0 )
121 newPoint
->rearModulusPromise_
= typedHandle
->rPromise_
;
122 newPoint
->rearState_
|= Concrete::PathPoint2D::FREE_ANGLE
;
127 typedef const Lang::PolarHandle2DFree_r
* VariableHandle
;
128 VariableHandle typedHandle
= dynamic_cast< VariableHandle
>( pathPoint
->rear_
.getPtr( ) );
129 if( typedHandle
!= 0 )
131 newPoint
->rearModulusPromise_
= typedHandle
->defaultModulus_
;
132 newPoint
->rearAngle_
= typedHandle
->a_
;
133 newPoint
->rearState_
|= Concrete::PathPoint2D::FREE_MODULUS
;
138 typedef const Lang::PolarHandle2DFree_ra
* VariableHandle
;
139 VariableHandle typedHandle
= dynamic_cast< VariableHandle
>( pathPoint
->rear_
.getPtr( ) );
140 if( typedHandle
!= 0 )
142 newPoint
->rearModulusPromise_
= typedHandle
->defaultModulus_
;
143 newPoint
->rearState_
|= Concrete::PathPoint2D::FREE
;
148 std::ostringstream msg
;
149 msg
<< "Unexpected type found in handle point: " << pathPoint
->rear_
->getTypeName( ) ;
150 throw Exceptions::InternalError( msg
);
155 if( pathPoint
->front_
!= NullPtr
< const Lang::Value
>( ) )
157 newPoint
->front_
= new Concrete::Coords2D( 0, 0 );
159 typedef const Lang::Coords2D
* VariableHandle
;
160 VariableHandle typedHandle
= dynamic_cast< VariableHandle
>( pathPoint
->front_
.getPtr( ) );
161 if( typedHandle
!= 0 )
163 *(newPoint
->front_
) = Concrete::Coords2D( basePoint
, *typedHandle
);
164 Concrete::Length dx
= newPoint
->front_
->x_
- newPoint
->mid_
->x_
;
165 Concrete::Length dy
= newPoint
->front_
->y_
- newPoint
->mid_
->y_
;
166 newPoint
->frontAngle_
= atan2( dy
.offtype
< 1, 0 >( ), dx
.offtype
< 1, 0 >( ) );
167 newPoint
->frontModulus_
= hypotPhysical( dx
, dy
);
168 newPoint
->frontState_
= Concrete::PathPoint2D::COMPLETE
;
172 newPoint
->frontState_
= Concrete::PathPoint2D::UNFORCED_M
;
173 pth
->allComplete_
= false;
175 typedef const Lang::PolarHandle2D
* VariableHandle
;
176 VariableHandle typedHandle
= dynamic_cast< VariableHandle
>( pathPoint
->front_
.getPtr( ) );
177 if( typedHandle
!= 0 )
179 newPoint
->frontModulusPromise_
= typedHandle
->rPromise_
;
180 newPoint
->frontAngle_
= typedHandle
->a_
;
181 newPoint
->frontState_
|= Concrete::PathPoint2D::COMPLETE
; // This is just a no-op way of saying "keep it UNFORCED_M"
186 typedef const Lang::PolarHandle2DFree_a
* VariableHandle
;
187 VariableHandle typedHandle
= dynamic_cast< VariableHandle
>( pathPoint
->front_
.getPtr( ) );
188 if( typedHandle
!= 0 )
190 newPoint
->frontModulusPromise_
= typedHandle
->rPromise_
;
191 newPoint
->frontState_
|= Concrete::PathPoint2D::FREE_ANGLE
;
196 typedef const Lang::PolarHandle2DFree_r
* VariableHandle
;
197 VariableHandle typedHandle
= dynamic_cast< VariableHandle
>( pathPoint
->front_
.getPtr( ) );
198 if( typedHandle
!= 0 )
200 newPoint
->frontModulusPromise_
= typedHandle
->defaultModulus_
;
201 newPoint
->frontAngle_
= typedHandle
->a_
;
202 newPoint
->frontState_
|= Concrete::PathPoint2D::FREE_MODULUS
;
207 typedef const Lang::PolarHandle2DFree_ra
* VariableHandle
;
208 VariableHandle typedHandle
= dynamic_cast< VariableHandle
>( pathPoint
->front_
.getPtr( ) );
209 if( typedHandle
!= 0 )
211 newPoint
->frontModulusPromise_
= typedHandle
->defaultModulus_
;
212 newPoint
->frontState_
|= Concrete::PathPoint2D::FREE
;
217 std::ostringstream msg
;
218 msg
<< "Unexpected type found in handle point: " << pathPoint
->front_
->getTypeName( ) ;
219 throw Exceptions::InternalError( msg
);
224 pth
->push_back( newPoint
);
227 SINGLELOOP1( CLASSTREE1_Path2D
, QUICKTYPECASE
)
229 const Lang::Path2D
* subPath
= reinterpret_cast< const Lang::Path2D
* >( node
);
230 subPath
->elementaryJob( & nodeStack
, pth
, & basePoint
);
235 std::ostringstream msg
;
236 msg
<< "Unexpected type found in subpath: " << node
->getTypeName( ) ;
237 throw Exceptions::InternalError( msg
);
242 if( pth
->allComplete_
)
248 /* Now, fill in all the missing angles.
252 Lang::ElementaryPath2D::iterator the_rend
= pth
->begin( );
254 Lang::ElementaryPath2D::iterator the_rbegin
= pth
->end( );
258 pth
->allComplete_
= true;
259 for( Lang::ElementaryPath2D::iterator i
= pth
->begin( );
263 if( ( (*i
)->rear_
== (*i
)->mid_
&&
264 (*i
)->front_
== (*i
)->mid_
) ||
265 isnan( (*i
)->defaultAngle_
) )
267 /* There are no handles at this point.
268 * Set angles in direction to neighboring coordinates
270 if( (*i
)->rearState_
& Concrete::PathPoint2D::FREE_ANGLE
)
272 Lang::ElementaryPath2D::iterator prev
= i
;
274 if( prev
== the_rend
)
278 Concrete::Length dxRear
= (*prev
)->mid_
->x_
- (*i
)->mid_
->x_
;
279 Concrete::Length dyRear
= (*prev
)->mid_
->y_
- (*i
)->mid_
->y_
;
280 (*i
)->rearAngle_
= atan2( dyRear
.offtype
< 1, 0 >( ), dxRear
.offtype
< 1, 0 >( ) );
281 (*i
)->rearState_
&= ~Concrete::PathPoint2D::FREE_ANGLE
;
283 if( (*i
)->frontState_
& Concrete::PathPoint2D::FREE_ANGLE
)
285 Lang::ElementaryPath2D::iterator next
= i
;
287 if( next
== pth
->end( ) )
289 next
= pth
->begin( );
291 Concrete::Length dxFront
= (*next
)->mid_
->x_
- (*i
)->mid_
->x_
;
292 Concrete::Length dyFront
= (*next
)->mid_
->y_
- (*i
)->mid_
->y_
;
293 (*i
)->frontAngle_
= atan2( dyFront
.offtype
< 1, 0 >( ), dxFront
.offtype
< 1, 0 >( ) );
294 (*i
)->frontState_
&= ~Concrete::PathPoint2D::FREE_ANGLE
;
299 if( (*i
)->front_
== (*i
)->mid_
300 || ( i
== the_rbegin
&& ! closed_
) )
302 /* There is only a rear handle at this point, or the front handle is unused at the
303 * end of an open path.
305 if( (*i
)->rearState_
& Concrete::PathPoint2D::UNFORCED_A
)
307 /* Put code for forcing the angle here
312 if( (*i
)->rearState_
& ( Concrete::PathPoint2D::FREE_MODULUS
| Concrete::PathPoint2D::UNFORCED_M
) )
314 pth
->allComplete_
= false;
317 if( ! ( (*i
)->rearState_
& Concrete::PathPoint2D::FREE_ANGLE
) )
319 if( ( i
== the_rbegin
&& ! closed_
) && ( (*i
)->frontState_
& Concrete::PathPoint2D::FREE_ANGLE
) )
321 /* Special case of ignored handle at end of open path. */
322 (*i
)->frontAngle_
= (*i
)->rearAngle_
+ M_PI
+ (*i
)->defaultAngle_
;
323 (*i
)->frontState_
&= ~Concrete::PathPoint2D::FREE_ANGLE
;
324 if( (*i
)->frontState_
& ( Concrete::PathPoint2D::FREE_MODULUS
| Concrete::PathPoint2D::UNFORCED_M
) )
326 pth
->allComplete_
= false;
331 (*i
)->rearState_
&= ~Concrete::PathPoint2D::FREE_ANGLE
;
333 Lang::ElementaryPath2D::iterator next
= i
;
335 if( next
== pth
->end( ) )
339 next
= pth
->begin( );
343 /* In this case we do something completely different.
345 Lang::ElementaryPath2D::iterator prev
= i
;
347 if( prev
== the_rend
)
349 throw Exceptions::MiscellaneousRequirement( "The angles of a singleton pathpoint cannot be determined." );
351 Concrete::Length dxRear
= (*prev
)->mid_
->x_
- (*i
)->mid_
->x_
;
352 Concrete::Length dyRear
= (*prev
)->mid_
->y_
- (*i
)->mid_
->y_
;
353 (*i
)->rearAngle_
= atan2( dyRear
.offtype
< 1, 0 >( ), dxRear
.offtype
< 1, 0 >( ) );
354 (*i
)->frontAngle_
= (*i
)->rearAngle_
+ M_PI
+ (*i
)->defaultAngle_
; /* Both angles must always be set, even where there is no handle. */
355 if( ! ( (*i
)->rearState_
& ( Concrete::PathPoint2D::FREE_MODULUS
| Concrete::PathPoint2D::UNFORCED_M
) ) )
357 (*i
)->rear_
->x_
= (*i
)->mid_
->x_
+ (*i
)->rearModulus_
* cos( (*i
)->rearAngle_
);
358 (*i
)->rear_
->y_
= (*i
)->mid_
->y_
+ (*i
)->rearModulus_
* sin( (*i
)->rearAngle_
);
359 (*i
)->rearState_
= Concrete::PathPoint2D::COMPLETE
;
361 (*i
)->frontState_
&= ~Concrete::PathPoint2D::FREE_ANGLE
;
362 if( (*i
)->frontState_
& ( Concrete::PathPoint2D::FREE_MODULUS
| Concrete::PathPoint2D::UNFORCED_M
) )
364 pth
->allComplete_
= false;
369 Concrete::Length dxFront
= (*next
)->mid_
->x_
- (*i
)->mid_
->x_
;
370 Concrete::Length dyFront
= (*next
)->mid_
->y_
- (*i
)->mid_
->y_
;
371 (*i
)->frontAngle_
= atan2( dyFront
.offtype
< 1, 0 >( ), dxFront
.offtype
< 1, 0 >( ) ); /* Both angles must always be set, even where there is no handle. */
372 (*i
)->rearAngle_
= (*i
)->frontAngle_
+ M_PI
- (*i
)->defaultAngle_
;
373 if( ! ( (*i
)->rearState_
& ( Concrete::PathPoint2D::FREE_MODULUS
| Concrete::PathPoint2D::UNFORCED_M
) ) )
375 (*i
)->rear_
->x_
= (*i
)->mid_
->x_
+ (*i
)->rearModulus_
* cos( (*i
)->rearAngle_
);
376 (*i
)->rear_
->y_
= (*i
)->mid_
->y_
+ (*i
)->rearModulus_
* sin( (*i
)->rearAngle_
);
377 (*i
)->rearState_
= Concrete::PathPoint2D::COMPLETE
;
381 if( (*i
)->rear_
== (*i
)->mid_
382 || ( i
== pth
->begin( ) && ! closed_
) )
384 /* There is only a front handle at this point, or the rear handle is unused at the
385 * beginning of an open path.
388 if( (*i
)->frontState_
& Concrete::PathPoint2D::UNFORCED_A
)
390 /* Put code for forcing the angle here
395 if( (*i
)->frontState_
& ( Concrete::PathPoint2D::FREE_MODULUS
| Concrete::PathPoint2D::UNFORCED_M
) )
397 pth
->allComplete_
= false;
400 if( ! ( (*i
)->frontState_
& Concrete::PathPoint2D::FREE_ANGLE
) )
402 if( ( i
== pth
->begin( ) && ! closed_
) && ( (*i
)->rearState_
& Concrete::PathPoint2D::FREE_ANGLE
) )
404 /* Special case of ignored handle at beginning of open path. */
405 (*i
)->rearAngle_
= (*i
)->frontAngle_
+ M_PI
- (*i
)->defaultAngle_
;
406 (*i
)->rearState_
&= ~Concrete::PathPoint2D::FREE_ANGLE
;
407 if( (*i
)->rearState_
& ( Concrete::PathPoint2D::FREE_MODULUS
| Concrete::PathPoint2D::UNFORCED_M
) )
409 pth
->allComplete_
= false;
414 (*i
)->frontState_
&= ~Concrete::PathPoint2D::FREE_ANGLE
;
416 Lang::ElementaryPath2D::iterator prev
= i
;
418 if( prev
== the_rend
)
426 /* In this case we do something completely different.
428 Lang::ElementaryPath2D::iterator next
= i
;
430 if( next
== pth
->end( ) )
432 throw Exceptions::MiscellaneousRequirement( "The angles of a singleton pathpoint cannot be determined." );
434 Concrete::Length dxFront
= (*next
)->mid_
->x_
- (*i
)->mid_
->x_
;
435 Concrete::Length dyFront
= (*next
)->mid_
->y_
- (*i
)->mid_
->y_
;
436 (*i
)->frontAngle_
= atan2( dyFront
.offtype
< 1, 0 >( ), dxFront
.offtype
< 1, 0 >( ) );
437 (*i
)->rearAngle_
= (*i
)->frontAngle_
+ M_PI
- (*i
)->defaultAngle_
; /* Both angles must always be set, even where there is no handle. */
438 if( ! ( (*i
)->frontState_
& ( Concrete::PathPoint2D::FREE_MODULUS
| Concrete::PathPoint2D::UNFORCED_M
) ) )
440 (*i
)->front_
->x_
= (*i
)->mid_
->x_
+ (*i
)->frontModulus_
* cos( (*i
)->frontAngle_
);
441 (*i
)->front_
->y_
= (*i
)->mid_
->y_
+ (*i
)->frontModulus_
* sin( (*i
)->frontAngle_
);
442 (*i
)->frontState_
= Concrete::PathPoint2D::COMPLETE
;
444 (*i
)->rearState_
&= ~Concrete::PathPoint2D::FREE_ANGLE
;
445 if( (*i
)->rearState_
& ( Concrete::PathPoint2D::FREE_MODULUS
| Concrete::PathPoint2D::UNFORCED_M
) )
447 pth
->allComplete_
= false;
452 Concrete::Length dxRear
= (*prev
)->mid_
->x_
- (*i
)->mid_
->x_
;
453 Concrete::Length dyRear
= (*prev
)->mid_
->y_
- (*i
)->mid_
->y_
;
454 (*i
)->rearAngle_
= atan2( dyRear
.offtype
< 1, 0 >( ), dxRear
.offtype
< 1, 0 >( ) ); /* Both angles must always be set, even where there is no handle. */
455 (*i
)->frontAngle_
= (*i
)->rearAngle_
+ M_PI
+ (*i
)->defaultAngle_
;
456 if( ! ( (*i
)->frontState_
& ( Concrete::PathPoint2D::FREE_MODULUS
| Concrete::PathPoint2D::UNFORCED_M
) ) )
458 (*i
)->front_
->x_
= (*i
)->mid_
->x_
+ (*i
)->frontModulus_
* cos( (*i
)->frontAngle_
);
459 (*i
)->front_
->y_
= (*i
)->mid_
->y_
+ (*i
)->frontModulus_
* sin( (*i
)->frontAngle_
);
460 (*i
)->frontState_
= Concrete::PathPoint2D::COMPLETE
;
466 /* We reach here if there are two handles at the point */
468 if( (*i
)->rearState_
& Concrete::PathPoint2D::UNFORCED_A
)
470 /* Put code for forcing the angle here
475 if( (*i
)->frontState_
& Concrete::PathPoint2D::UNFORCED_A
)
477 /* Put code for forcing the angle here
482 if( ( (*i
)->rearState_
| (*i
)->frontState_
) & ( Concrete::PathPoint2D::FREE_MODULUS
| Concrete::PathPoint2D::UNFORCED_M
) )
484 pth
->allComplete_
= false;
487 if( ! ( (*i
)->rearState_
& Concrete::PathPoint2D::FREE_ANGLE
) &&
488 ! ( (*i
)->frontState_
& Concrete::PathPoint2D::FREE_ANGLE
) )
490 /* Both handles have specified angles */
493 if( ! ( (*i
)->rearState_
& Concrete::PathPoint2D::FREE_ANGLE
) )
495 /* The rear handle has a specified angle, that may propagate to the front handle */
496 if( (*i
)->frontState_
& Concrete::PathPoint2D::FREE_ANGLE
)
498 (*i
)->frontAngle_
= (*i
)->rearAngle_
+ M_PI
+ (*i
)->defaultAngle_
;
499 (*i
)->frontState_
&= ~Concrete::PathPoint2D::FREE_ANGLE
;
503 if( ! ( (*i
)->frontState_
& Concrete::PathPoint2D::FREE_ANGLE
) )
505 /* Analogous to above */
506 if( (*i
)->rearState_
& Concrete::PathPoint2D::FREE_ANGLE
)
508 (*i
)->rearAngle_
= (*i
)->frontAngle_
+ M_PI
- (*i
)->defaultAngle_
;
509 (*i
)->rearState_
&= ~Concrete::PathPoint2D::FREE_ANGLE
;
514 /* None of the handles have specified angles */
516 Lang::ElementaryPath2D::iterator prev
= i
;
518 if( prev
== the_rend
)
522 Lang::ElementaryPath2D::iterator next
= i
;
524 if( next
== pth
->end( ) )
526 next
= pth
->begin( );
529 Concrete::Length dxRear
= (*prev
)->mid_
->x_
- (*i
)->mid_
->x_
;
530 Concrete::Length dyRear
= (*prev
)->mid_
->y_
- (*i
)->mid_
->y_
;
531 Concrete::Length dxFront
= (*next
)->mid_
->x_
- (*i
)->mid_
->x_
;
532 Concrete::Length dyFront
= (*next
)->mid_
->y_
- (*i
)->mid_
->y_
;
533 double angleRear
= atan2( dyRear
.offtype
< 1, 0 >( ), dxRear
.offtype
< 1, 0 >( ) );
534 double angleFront
= atan2( dyFront
.offtype
< 1, 0 >( ), dxFront
.offtype
< 1, 0 >( ) );
535 double weightRear
= pow( hypot( dxFront
.offtype
< 1, 0 >( ), dyFront
.offtype
< 1, 0 >( ) ), GAMMA_ANGLE
);
536 double weightFront
= pow( hypot( dxRear
.offtype
< 1, 0 >( ), dyRear
.offtype
< 1, 0 >( ) ), GAMMA_ANGLE
);
537 double a
= angleSelectNorm2( angleRear
, angleFront
- ( M_PI
+ (*i
)->defaultAngle_
), weightRear
, weightFront
);
538 (*i
)->rearAngle_
= a
;
539 (*i
)->frontAngle_
= a
+ M_PI
+ (*i
)->defaultAngle_
;
541 (*i
)->frontState_
&= ~Concrete::PathPoint2D::FREE_ANGLE
;
542 (*i
)->rearState_
&= ~Concrete::PathPoint2D::FREE_ANGLE
;
546 } // Done filling in angles.
549 /* Now, complete the path by filling in all the handle radii.
553 Lang::ElementaryPath2D::iterator the_rend
= pth
->begin( );
555 Lang::ElementaryPath2D::iterator the_rbegin
= pth
->end( );
558 pth
->allComplete_
= true;
559 for( Lang::ElementaryPath2D::iterator i
= pth
->begin( );
563 if( (*i
)->rear_
== (*i
)->mid_
&&
564 (*i
)->front_
== (*i
)->mid_
)
566 /* There are no handles at this point */
571 Lang::ElementaryPath2D::iterator prev
= i
;
573 if( prev
== the_rend
)
577 Lang::ElementaryPath2D::iterator next
= i
;
579 if( next
== pth
->end( ) )
581 next
= pth
->begin( );
584 if( (*i
)->front_
== (*i
)->mid_
585 || ( i
== the_rbegin
&& ! closed_
) )
587 /* There is only a rear handle at this point,
588 * or the front handle is ignored because it is at the end of an open path.
590 if( (*i
)->rearState_
== Concrete::PathPoint2D::COMPLETE
)
592 if( i
== the_rbegin
&& ! closed_
&& ( (*i
)->frontState_
& Concrete::PathPoint2D::FREE_MODULUS
) )
596 if( ( (*i
)->rearState_
& Concrete::PathPoint2D::UNFORCED_M
) != 0)
598 (*i
)->rearModulus_
= (*i
)->rearModulusPromise_
->force( *prev
, *i
, true );
600 (*i
)->rear_
->x_
= (*i
)->mid_
->x_
+ (*i
)->rearModulus_
* cos( (*i
)->rearAngle_
);
601 (*i
)->rear_
->y_
= (*i
)->mid_
->y_
+ (*i
)->rearModulus_
* sin( (*i
)->rearAngle_
);
603 if( i
== the_rbegin
&& ! closed_
&& ( (*i
)->frontState_
& Concrete::PathPoint2D::FREE_MODULUS
) )
605 /* Special case of unused handle, just propagate from other side. */
606 (*i
)->frontModulus_
= (*i
)->rearModulus_
;
607 (*i
)->front_
->x_
= (*i
)->mid_
->x_
+ (*i
)->frontModulus_
* cos( (*i
)->frontAngle_
);
608 (*i
)->front_
->y_
= (*i
)->mid_
->y_
+ (*i
)->frontModulus_
* sin( (*i
)->frontAngle_
);
612 if( (*i
)->rear_
== (*i
)->mid_
613 || ( i
== pth
->begin( ) && ! closed_
) )
615 /* There is only a front handle at this point,
616 * or the rear handle is ignored because it is at the beginning of an open path
618 if( (*i
)->frontState_
== Concrete::PathPoint2D::COMPLETE
)
620 if( i
== pth
->begin( ) && ! closed_
&& ( (*i
)->rearState_
& Concrete::PathPoint2D::FREE_MODULUS
) )
624 if( ( (*i
)->frontState_
& Concrete::PathPoint2D::UNFORCED_M
) != 0 )
626 (*i
)->frontModulus_
= (*i
)->frontModulusPromise_
->force( *i
, *next
, false );
628 (*i
)->front_
->x_
= (*i
)->mid_
->x_
+ (*i
)->frontModulus_
* cos( (*i
)->frontAngle_
);
629 (*i
)->front_
->y_
= (*i
)->mid_
->y_
+ (*i
)->frontModulus_
* sin( (*i
)->frontAngle_
);
631 if( i
== pth
->begin( ) && ! closed_
&& ( (*i
)->rearState_
& Concrete::PathPoint2D::FREE_MODULUS
) )
633 /* Special case of unused handle, just propagate from other side. */
634 (*i
)->rearModulus_
= (*i
)->frontModulus_
;
635 (*i
)->rear_
->x_
= (*i
)->mid_
->x_
+ (*i
)->rearModulus_
* cos( (*i
)->rearAngle_
);
636 (*i
)->rear_
->y_
= (*i
)->mid_
->y_
+ (*i
)->rearModulus_
* sin( (*i
)->rearAngle_
);
641 /* We reach here if there are two handles at the point */
643 if( (*i
)->rearState_
!= Concrete::PathPoint2D::COMPLETE
)
645 if( ! ( (*i
)->rearState_
& Concrete::PathPoint2D::FREE_MODULUS
) )
647 if( ( (*i
)->rearState_
& Concrete::PathPoint2D::UNFORCED_M
) != 0 )
649 (*i
)->rearModulus_
= (*i
)->rearModulusPromise_
->force( *prev
, *i
, true );
651 (*i
)->rear_
->x_
= (*i
)->mid_
->x_
+ (*i
)->rearModulus_
* cos( (*i
)->rearAngle_
);
652 (*i
)->rear_
->y_
= (*i
)->mid_
->y_
+ (*i
)->rearModulus_
* sin( (*i
)->rearAngle_
);
653 (*i
)->rearState_
= Concrete::PathPoint2D::COMPLETE
;
657 if( (*i
)->frontState_
!= Concrete::PathPoint2D::COMPLETE
)
659 if( ! ( (*i
)->frontState_
& Concrete::PathPoint2D::FREE_MODULUS
) )
661 if( ( (*i
)->frontState_
& Concrete::PathPoint2D::UNFORCED_M
) != 0)
663 (*i
)->frontModulus_
= (*i
)->frontModulusPromise_
->force( *i
, *next
, false );
665 (*i
)->front_
->x_
= (*i
)->mid_
->x_
+ (*i
)->frontModulus_
* cos( (*i
)->frontAngle_
);
666 (*i
)->front_
->y_
= (*i
)->mid_
->y_
+ (*i
)->frontModulus_
* sin( (*i
)->frontAngle_
);
667 (*i
)->frontState_
= Concrete::PathPoint2D::COMPLETE
;
671 if( (*i
)->rearState_
== Concrete::PathPoint2D::COMPLETE
&&
672 (*i
)->frontState_
== Concrete::PathPoint2D::COMPLETE
)
677 /* The only reason why a handle is not complete at this point is that it's modulus
678 * has not been determined.
680 if( (*i
)->rearState_
== Concrete::PathPoint2D::COMPLETE
)
682 /* The rear modulus is known, and may propagate to the other side. */
683 if( (*i
)->frontState_
& Concrete::PathPoint2D::FREE_MODULUS
)
685 (*i
)->frontModulus_
= (*i
)->rearModulus_
;
686 (*i
)->front_
->x_
= (*i
)->mid_
->x_
+ (*i
)->frontModulus_
* cos( (*i
)->frontAngle_
);
687 (*i
)->front_
->y_
= (*i
)->mid_
->y_
+ (*i
)->frontModulus_
* sin( (*i
)->frontAngle_
);
691 if( (*i
)->frontState_
== Concrete::PathPoint2D::COMPLETE
)
693 /* Analogous to the above */
694 if( (*i
)->rearState_
& Concrete::PathPoint2D::FREE_MODULUS
)
696 (*i
)->rearModulus_
= (*i
)->frontModulus_
;
697 (*i
)->rear_
->x_
= (*i
)->mid_
->x_
+ (*i
)->rearModulus_
* cos( (*i
)->rearAngle_
);
698 (*i
)->rear_
->y_
= (*i
)->mid_
->y_
+ (*i
)->rearModulus_
* sin( (*i
)->rearAngle_
);
703 /* We get here if both modulus are free.
704 * We first compute madulus for each individually, and then merge the two values somehow to make both equal in the end.
707 double rearModulus
= (*i
)->rearModulusPromise_
->force( *prev
, *i
, true );
708 double frontModulus
= (*i
)->frontModulusPromise_
->force( *i
, *next
, false );
709 double theModulus
= min( rearModulus
, frontModulus
);
710 (*i
)->rearModulus_
= theModulus
;
711 (*i
)->frontModulus_
= theModulus
;
712 (*i
)->front_
->x_
= (*i
)->mid_
->x_
+ (*i
)->frontModulus_
* cos( (*i
)->frontAngle_
);
713 (*i
)->front_
->y_
= (*i
)->mid_
->y_
+ (*i
)->frontModulus_
* sin( (*i
)->frontAngle_
);
714 (*i
)->rear_
->x_
= (*i
)->mid_
->x_
+ (*i
)->rearModulus_
* cos( (*i
)->rearAngle_
);
715 (*i
)->rear_
->y_
= (*i
)->mid_
->y_
+ (*i
)->rearModulus_
* sin( (*i
)->rearAngle_
);
719 } // Closing scope of the_rend and the_rbegin
729 elementaryPath_
= RefCountPtr
< const Lang::ElementaryPath2D
>( pth
);