Update procedures
[shapes.git] / source / computeelementarypath.cc
blob5527cd457146753404adc9386a3c441234628388
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, 2014 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_
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
308 * ...
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;
329 continue;
331 (*i)->rearState_ &= ~Concrete::PathPoint2D::FREE_ANGLE;
333 Lang::ElementaryPath2D::iterator next = i;
334 ++next;
335 if( next == pth->end( ) )
337 if( closed_ )
339 next = pth->begin( );
341 else
343 /* In this case we do something completely different.
345 Lang::ElementaryPath2D::iterator prev = i;
346 --prev;
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;
366 continue;
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;
379 continue;
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
391 * ...
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;
412 continue;
414 (*i)->frontState_ &= ~Concrete::PathPoint2D::FREE_ANGLE;
416 Lang::ElementaryPath2D::iterator prev = i;
417 --prev;
418 if( prev == the_rend )
420 if( closed_ )
422 prev = the_rbegin;
424 else
426 /* In this case we do something completely different.
428 Lang::ElementaryPath2D::iterator next = i;
429 ++next;
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;
449 continue;
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;
462 continue;
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
471 * ...
475 if( (*i)->frontState_ & Concrete::PathPoint2D::UNFORCED_A )
477 /* Put code for forcing the angle here
478 * ...
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 */
491 continue;
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;
501 continue;
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;
511 continue;
514 /* None of the handles have specified angles */
516 Lang::ElementaryPath2D::iterator prev = i;
517 --prev;
518 if( prev == the_rend )
520 prev = the_rbegin;
522 Lang::ElementaryPath2D::iterator next = i;
523 ++next;
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( );
554 --the_rend;
555 Lang::ElementaryPath2D::iterator the_rbegin = pth->end( );
556 --the_rbegin;
558 pth->allComplete_ = true;
559 for( Lang::ElementaryPath2D::iterator i = pth->begin( );
560 i != pth->end( );
561 ++i )
563 if( (*i)->rear_ == (*i)->mid_ &&
564 (*i)->front_ == (*i)->mid_ )
566 /* There are no handles at this point */
568 continue;
571 Lang::ElementaryPath2D::iterator prev = i;
572 --prev;
573 if( prev == the_rend )
575 prev = the_rbegin;
577 Lang::ElementaryPath2D::iterator next = i;
578 ++next;
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 ) )
593 goto unused_front;
594 continue;
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_ );
602 unused_front:
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_ );
610 continue;
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 ) )
621 goto unused_rear;
622 continue;
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_ );
630 unused_rear:
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_ );
638 continue;
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 )
674 continue;
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_ );
689 continue;
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_ );
700 continue;
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
722 allComplete:
724 if( closed_ )
726 pth->close( );
729 elementaryPath_ = RefCountPtr< const Lang::ElementaryPath2D >( pth );