Updating the changelog in the VERSION file, and version_sync.
[shapes.git] / source / computeelementarypath.cc
blobfb54e98e5e54114cb06ba156f017e1e67f8e1971
1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * any later version.
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008 Henrik Tidefelt
19 #include <cmath>
21 #include "shapestypes.h"
22 #include "shapesexceptions.h"
23 #include "consts.h"
24 #include "angleselect.h"
26 #include <stack>
28 using namespace Shapes;
29 using namespace std;
32 void
33 Lang::CompositePath2D::computeElementaryPath( ) const
35 if( elementaryPath_ != NullPtr< const Lang::ElementaryPath2D >( ) )
37 return;
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( );
50 nodeStack.pop( );
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 );
61 if( tmp != 0 )
63 newPoint->defaultAngle = tmp->a_;
66 Concrete::Coords2D * newMid = new Concrete::Coords2D( basePoint, *coords );
67 basePoint = *newMid;
68 pth->push_back( new Concrete::PathPoint2D( newMid ) );
70 break;
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_) );
75 basePoint = *newMid;
76 Concrete::PathPoint2D * newPoint = new Concrete::PathPoint2D( newMid );
79 const Lang::CornerCoords2D * tmp = dynamic_cast< const Lang::CornerCoords2D * >( pathPoint->mid_.getPtr( ) );
80 if( tmp != 0 )
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;
100 goto doneRear;
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"
113 goto doneRear;
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;
123 goto doneRear;
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;
134 goto doneRear;
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;
144 goto doneRear;
148 std::ostringstream msg;
149 msg << "Unexpected type found in handle point: " << pathPoint->rear_->getTypeName( ) ;
150 throw Exceptions::InternalError( msg );
153 doneRear:
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;
169 goto doneFront;
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"
182 goto doneFront;
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;
192 goto doneFront;
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;
203 goto doneFront;
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;
213 goto doneFront;
217 std::ostringstream msg;
218 msg << "Unexpected type found in handle point: " << pathPoint->front_->getTypeName( ) ;
219 throw Exceptions::InternalError( msg );
222 doneFront:
224 pth->push_back( newPoint );
226 break;
227 SINGLELOOP1( CLASSTREE1_Path2D, QUICKTYPECASE )
229 const Lang::Path2D * subPath = reinterpret_cast< const Lang::Path2D * >( node );
230 subPath->elementaryJob( & nodeStack, pth, & basePoint );
232 break;
233 default:
235 std::ostringstream msg;
236 msg << "Unexpected type found in subpath: " << node->getTypeName( ) ;
237 throw Exceptions::InternalError( msg );
242 if( pth->allComplete_ )
244 goto allComplete;
248 /* Now, fill in all the missing angles.
252 Lang::ElementaryPath2D::iterator the_rend = pth->begin( );
253 --the_rend;
254 Lang::ElementaryPath2D::iterator the_rbegin = pth->end( );
255 --the_rbegin;
258 pth->allComplete_ = true;
259 for( Lang::ElementaryPath2D::iterator i = pth->begin( );
260 i != pth->end( );
261 ++i )
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;
273 --prev;
274 if( prev == the_rend )
276 prev = the_rbegin;
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;
286 ++next;
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;
296 continue;
299 if( (*i)->front_ == (*i)->mid_ )
301 /* There is only a rear handle at this point */
302 if( (*i)->rearState_ & Concrete::PathPoint2D::UNFORCED_A )
304 /* Put code for forcing the angle here
305 * ...
309 if( (*i)->rearState_ & ( Concrete::PathPoint2D::FREE_MODULUS | Concrete::PathPoint2D::UNFORCED_M ) )
311 pth->allComplete_ = false;
314 if( ! ( (*i)->rearState_ & Concrete::PathPoint2D::FREE_ANGLE ) )
316 continue;
318 (*i)->rearState_ &= ~Concrete::PathPoint2D::FREE_ANGLE;
320 Lang::ElementaryPath2D::iterator next = i;
321 ++next;
322 if( next == pth->end( ) )
324 if( closed_ )
326 next = pth->begin( );
328 else
330 /* In this case we do something completely different.
332 Lang::ElementaryPath2D::iterator prev = i;
333 --prev;
334 if( prev == the_rend )
336 throw Exceptions::MiscellaneousRequirement( "The angles of a singleton pathpoint cannot be determined." );
338 Concrete::Length dxRear = (*prev)->mid_->x_ - (*i)->mid_->x_;
339 Concrete::Length dyRear = (*prev)->mid_->y_ - (*i)->mid_->y_;
340 (*i)->rearAngle_ = atan2( dyRear.offtype< 1, 0 >( ), dxRear.offtype< 1, 0 >( ) );
341 (*i)->frontAngle_ = (*i)->rearAngle_ + M_PI + (*i)->defaultAngle_; /* Both angles must always be set, even where there is no handle. */
342 if( ! ( (*i)->rearState_ & ( Concrete::PathPoint2D::FREE_MODULUS | Concrete::PathPoint2D::UNFORCED_M ) ) )
344 (*i)->rear_->x_ = (*i)->mid_->x_ + (*i)->rearModulus_ * cos( (*i)->rearAngle_ );
345 (*i)->rear_->y_ = (*i)->mid_->y_ + (*i)->rearModulus_ * sin( (*i)->rearAngle_ );
346 (*i)->rearState_ = Concrete::PathPoint2D::COMPLETE;
348 continue;
351 Concrete::Length dxFront = (*next)->mid_->x_ - (*i)->mid_->x_;
352 Concrete::Length dyFront = (*next)->mid_->y_ - (*i)->mid_->y_;
353 (*i)->frontAngle_ = atan2( dyFront.offtype< 1, 0 >( ), dxFront.offtype< 1, 0 >( ) ); /* Both angles must always be set, even where there is no handle. */
354 (*i)->rearAngle_ = (*i)->frontAngle_ + M_PI - (*i)->defaultAngle_;
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 continue;
363 if( (*i)->rear_ == (*i)->mid_ )
365 /* There is only a front handle at this point */
367 if( (*i)->frontState_ & Concrete::PathPoint2D::UNFORCED_A )
369 /* Put code for forcing the angle here
370 * ...
374 if( (*i)->frontState_ & ( Concrete::PathPoint2D::FREE_MODULUS | Concrete::PathPoint2D::UNFORCED_M ) )
376 pth->allComplete_ = false;
379 if( ! ( (*i)->frontState_ & Concrete::PathPoint2D::FREE_ANGLE ) )
381 continue;
383 (*i)->frontState_ &= ~Concrete::PathPoint2D::FREE_ANGLE;
385 Lang::ElementaryPath2D::iterator prev = i;
386 --prev;
387 if( prev == the_rend )
389 if( closed_ )
391 prev = the_rbegin;
393 else
395 /* In this case we do something completely different.
397 Lang::ElementaryPath2D::iterator next = i;
398 ++next;
399 if( next == pth->end( ) )
401 throw Exceptions::MiscellaneousRequirement( "The angles of a singleton pathpoint cannot be determined." );
403 Concrete::Length dxFront = (*next)->mid_->x_ - (*i)->mid_->x_;
404 Concrete::Length dyFront = (*next)->mid_->y_ - (*i)->mid_->y_;
405 (*i)->frontAngle_ = atan2( dyFront.offtype< 1, 0 >( ), dxFront.offtype< 1, 0 >( ) );
406 (*i)->rearAngle_ = (*i)->frontAngle_ + M_PI - (*i)->defaultAngle_; /* Both angles must always be set, even where there is no handle. */
407 if( ! ( (*i)->frontState_ & ( Concrete::PathPoint2D::FREE_MODULUS | Concrete::PathPoint2D::UNFORCED_M ) ) )
409 (*i)->front_->x_ = (*i)->mid_->x_ + (*i)->frontModulus_ * cos( (*i)->frontAngle_ );
410 (*i)->front_->y_ = (*i)->mid_->y_ + (*i)->frontModulus_ * sin( (*i)->frontAngle_ );
411 (*i)->frontState_ = Concrete::PathPoint2D::COMPLETE;
413 continue;
416 Concrete::Length dxRear = (*prev)->mid_->x_ - (*i)->mid_->x_;
417 Concrete::Length dyRear = (*prev)->mid_->y_ - (*i)->mid_->y_;
418 (*i)->rearAngle_ = atan2( dyRear.offtype< 1, 0 >( ), dxRear.offtype< 1, 0 >( ) ); /* Both angles must always be set, even where there is no handle. */
419 (*i)->frontAngle_ = (*i)->rearAngle_ + M_PI + (*i)->defaultAngle_;
420 if( ! ( (*i)->frontState_ & ( Concrete::PathPoint2D::FREE_MODULUS | Concrete::PathPoint2D::UNFORCED_M ) ) )
422 (*i)->front_->x_ = (*i)->mid_->x_ + (*i)->frontModulus_ * cos( (*i)->frontAngle_ );
423 (*i)->front_->y_ = (*i)->mid_->y_ + (*i)->frontModulus_ * sin( (*i)->frontAngle_ );
424 (*i)->frontState_ = Concrete::PathPoint2D::COMPLETE;
426 continue;
430 /* We reach here if there are two handles at the point */
432 if( (*i)->rearState_ & Concrete::PathPoint2D::UNFORCED_A )
434 /* Put code for forcing the angle here
435 * ...
439 if( (*i)->frontState_ & Concrete::PathPoint2D::UNFORCED_A )
441 /* Put code for forcing the angle here
442 * ...
446 if( ( (*i)->rearState_ | (*i)->frontState_ ) & ( Concrete::PathPoint2D::FREE_MODULUS | Concrete::PathPoint2D::UNFORCED_M ) )
448 pth->allComplete_ = false;
451 if( ! ( (*i)->rearState_ & Concrete::PathPoint2D::FREE_ANGLE ) &&
452 ! ( (*i)->frontState_ & Concrete::PathPoint2D::FREE_ANGLE ) )
454 /* Both handles have specified angles */
455 continue;
457 if( ! ( (*i)->rearState_ & Concrete::PathPoint2D::FREE_ANGLE ) )
459 /* The rear handle has a specified angle, that may propagate to the front handle */
460 if( (*i)->frontState_ & Concrete::PathPoint2D::FREE_ANGLE )
462 (*i)->frontAngle_ = (*i)->rearAngle_ + M_PI + (*i)->defaultAngle_;
463 (*i)->frontState_ &= ~Concrete::PathPoint2D::FREE_ANGLE;
465 continue;
467 if( ! ( (*i)->frontState_ & Concrete::PathPoint2D::FREE_ANGLE ) )
469 /* Analogous to above */
470 if( (*i)->rearState_ & Concrete::PathPoint2D::FREE_ANGLE )
472 (*i)->rearAngle_ = (*i)->frontAngle_ + M_PI - (*i)->defaultAngle_;
473 (*i)->rearState_ &= ~Concrete::PathPoint2D::FREE_ANGLE;
475 continue;
478 /* None of the handles have specified angles */
480 Lang::ElementaryPath2D::iterator prev = i;
481 --prev;
482 if( prev == the_rend )
484 prev = the_rbegin;
486 Lang::ElementaryPath2D::iterator next = i;
487 ++next;
488 if( next == pth->end( ) )
490 next = pth->begin( );
493 Concrete::Length dxRear = (*prev)->mid_->x_ - (*i)->mid_->x_;
494 Concrete::Length dyRear = (*prev)->mid_->y_ - (*i)->mid_->y_;
495 Concrete::Length dxFront = (*next)->mid_->x_ - (*i)->mid_->x_;
496 Concrete::Length dyFront = (*next)->mid_->y_ - (*i)->mid_->y_;
497 double angleRear = atan2( dyRear.offtype< 1, 0 >( ), dxRear.offtype< 1, 0 >( ) );
498 double angleFront = atan2( dyFront.offtype< 1, 0 >( ), dxFront.offtype< 1, 0 >( ) );
499 double weightRear = pow( hypot( dxFront.offtype< 1, 0 >( ), dyFront.offtype< 1, 0 >( ) ), GAMMA_ANGLE );
500 double weightFront = pow( hypot( dxRear.offtype< 1, 0 >( ), dyRear.offtype< 1, 0 >( ) ), GAMMA_ANGLE );
501 double a = angleSelectNorm2( angleRear, angleFront - ( M_PI + (*i)->defaultAngle_ ), weightRear, weightFront );
502 (*i)->rearAngle_ = a;
503 (*i)->frontAngle_ = a + M_PI + (*i)->defaultAngle_;
505 (*i)->frontState_ &= ~Concrete::PathPoint2D::FREE_ANGLE;
506 (*i)->rearState_ &= ~Concrete::PathPoint2D::FREE_ANGLE;
510 } // Done filling in angles.
513 /* Now, complete the path by filling in all the handle radii.
517 Lang::ElementaryPath2D::iterator the_rend = pth->begin( );
518 --the_rend;
519 Lang::ElementaryPath2D::iterator the_rbegin = pth->end( );
520 --the_rbegin;
522 pth->allComplete_ = true;
523 for( Lang::ElementaryPath2D::iterator i = pth->begin( );
524 i != pth->end( );
525 ++i )
527 if( (*i)->rear_ == (*i)->mid_ &&
528 (*i)->front_ == (*i)->mid_ )
530 /* There are no handles at this point */
532 continue;
535 Lang::ElementaryPath2D::iterator prev = i;
536 --prev;
537 if( prev == the_rend )
539 prev = the_rbegin;
541 Lang::ElementaryPath2D::iterator next = i;
542 ++next;
543 if( next == pth->end( ) )
545 next = pth->begin( );
548 if( (*i)->front_ == (*i)->mid_ )
550 /* There is only a rear handle at this point */
551 if( (*i)->rearState_ == Concrete::PathPoint2D::COMPLETE )
553 continue;
555 if( ( (*i)->rearState_ & Concrete::PathPoint2D::UNFORCED_M ) != 0)
557 (*i)->rearModulus_ = (*i)->rearModulusPromise_->force( *prev, *i, true );
559 (*i)->rear_->x_ = (*i)->mid_->x_ + (*i)->rearModulus_ * cos( (*i)->rearAngle_ );
560 (*i)->rear_->y_ = (*i)->mid_->y_ + (*i)->rearModulus_ * sin( (*i)->rearAngle_ );
561 continue;
563 if( (*i)->rear_ == (*i)->mid_ )
565 /* There is only a front handle at this point */
566 if( (*i)->frontState_ == Concrete::PathPoint2D::COMPLETE )
568 continue;
570 if( ( (*i)->frontState_ & Concrete::PathPoint2D::UNFORCED_M ) != 0 )
572 (*i)->frontModulus_ = (*i)->frontModulusPromise_->force( *i, *next, false );
574 (*i)->front_->x_ = (*i)->mid_->x_ + (*i)->frontModulus_ * cos( (*i)->frontAngle_ );
575 (*i)->front_->y_ = (*i)->mid_->y_ + (*i)->frontModulus_ * sin( (*i)->frontAngle_ );
576 continue;
579 /* We reach here if there are two handles at the point */
581 if( (*i)->rearState_ != Concrete::PathPoint2D::COMPLETE )
583 if( ! ( (*i)->rearState_ & Concrete::PathPoint2D::FREE_MODULUS ) )
585 if( ( (*i)->rearState_ & Concrete::PathPoint2D::UNFORCED_M ) != 0 )
587 (*i)->rearModulus_ = (*i)->rearModulusPromise_->force( *prev, *i, true );
589 (*i)->rear_->x_ = (*i)->mid_->x_ + (*i)->rearModulus_ * cos( (*i)->rearAngle_ );
590 (*i)->rear_->y_ = (*i)->mid_->y_ + (*i)->rearModulus_ * sin( (*i)->rearAngle_ );
591 (*i)->rearState_ = Concrete::PathPoint2D::COMPLETE;
595 if( (*i)->frontState_ != Concrete::PathPoint2D::COMPLETE )
597 if( ! ( (*i)->frontState_ & Concrete::PathPoint2D::FREE_MODULUS ) )
599 if( ( (*i)->frontState_ & Concrete::PathPoint2D::UNFORCED_M ) != 0)
601 (*i)->frontModulus_ = (*i)->frontModulusPromise_->force( *i, *next, false );
603 (*i)->front_->x_ = (*i)->mid_->x_ + (*i)->frontModulus_ * cos( (*i)->frontAngle_ );
604 (*i)->front_->y_ = (*i)->mid_->y_ + (*i)->frontModulus_ * sin( (*i)->frontAngle_ );
605 (*i)->frontState_ = Concrete::PathPoint2D::COMPLETE;
609 if( (*i)->rearState_ == Concrete::PathPoint2D::COMPLETE &&
610 (*i)->frontState_ == Concrete::PathPoint2D::COMPLETE )
612 continue;
615 /* The only reason why a handle is not complete at this point is that it's modulus
616 * has not been determined.
618 if( (*i)->rearState_ == Concrete::PathPoint2D::COMPLETE )
620 /* The rear modulus is known, and may propagate to the other side. */
621 if( (*i)->frontState_ & Concrete::PathPoint2D::FREE_MODULUS )
623 (*i)->frontModulus_ = (*i)->rearModulus_;
624 (*i)->front_->x_ = (*i)->mid_->x_ + (*i)->frontModulus_ * cos( (*i)->frontAngle_ );
625 (*i)->front_->y_ = (*i)->mid_->y_ + (*i)->frontModulus_ * sin( (*i)->frontAngle_ );
627 continue;
629 if( (*i)->frontState_ == Concrete::PathPoint2D::COMPLETE )
631 /* Analogous to the above */
632 if( (*i)->rearState_ & Concrete::PathPoint2D::FREE_MODULUS )
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_ );
638 continue;
641 /* We get here if both modulus are free.
642 * We first compute madulus for each individually, and then merge the two values somehow to make both equal in the end.
645 double rearModulus = (*i)->rearModulusPromise_->force( *prev, *i, true );
646 double frontModulus = (*i)->frontModulusPromise_->force( *i, *next, false );
647 double theModulus = min( rearModulus, frontModulus );
648 (*i)->rearModulus_ = theModulus;
649 (*i)->frontModulus_ = theModulus;
650 (*i)->front_->x_ = (*i)->mid_->x_ + (*i)->frontModulus_ * cos( (*i)->frontAngle_ );
651 (*i)->front_->y_ = (*i)->mid_->y_ + (*i)->frontModulus_ * sin( (*i)->frontAngle_ );
652 (*i)->rear_->x_ = (*i)->mid_->x_ + (*i)->rearModulus_ * cos( (*i)->rearAngle_ );
653 (*i)->rear_->y_ = (*i)->mid_->y_ + (*i)->rearModulus_ * sin( (*i)->rearAngle_ );
657 } // Closing scope of the_rend and the_rbegin
660 allComplete:
662 if( closed_ )
664 pth->close( );
667 elementaryPath_ = RefCountPtr< const Lang::ElementaryPath2D >( pth );