00001 
00009 
00010 
00011 
00012 
00013 #include <ecl/linear_algebra.hpp> 
00014 #include "../../include/ecl/manipulators/waypoint.hpp"
00015 #include "../../include/ecl/manipulators/trajectory.hpp"
00016 #include <ecl/geometry/function_math.hpp>
00017 #include <ecl/geometry/polynomial.hpp>
00018 #include <ecl/math/simple.hpp>
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 namespace ecl
00030 {
00031 
00032 
00033 
00034 
00035 
00036 void Trajectory<JointAngles>::tensionSplineInterpolation(const double &tension) ecl_assert_throw_decl(StandardException)
00037 {
00038   bool result;
00039   unsigned int n = waypoints.size() - 1; 
00040 
00041   
00042   ecl_assert_throw(
00043       n+1 >= 5,
00044       StandardException(LOC,ConfigurationError,"Not enough waypoints for a tension spline interpolation (must be >= 5)."));
00045 
00046   result = validateWaypoints(5);
00047   ecl_assert_throw(
00048       result,
00049       StandardException(LOC,ConfigurationError,"Not all the waypoint maximum rates have been specified correctly (must be > 0.0)."));
00050 
00051   result = initialiseWaypointDurations();
00052   ecl_assert_throw( result,
00053                    StandardException(LOC,ConfigurationError,"A waypoint was configured with a zero duration."));
00054 
00055   
00056 
00057 
00058   clearSplines(); 
00059   for (unsigned int j = 0; j < dimension(); ++j)
00060   {
00061     spline_functions[j].resize(3, NULL);
00062   }
00063   Array<TensionSpline> tension_splines(dimension());
00064   Array<QuinticPolynomial> leading_quintics(dimension()), trailing_quintics(dimension());
00065 
00066   
00067 
00068 
00069   bool splines_constrained = false;
00070   while (!splines_constrained)
00071   {
00072     tension_splines = generateTensionSplines(tension, 0.0);
00073     
00074 
00075 
00076     Array<double> domain = tension_splines[0].domain();
00077     splines_constrained = true; 
00078     
00079     
00080     
00081     for (unsigned int i = 1; i < domain.size() - 1; ++i)
00082     { 
00083       for (unsigned int j = 0; j < dimension(); ++j)
00084       {
00085         double accel = fabs(tension_splines[j].dderivative(domain[i]));
00086         
00087 
00088 
00089 
00090 
00091 
00092 
00093         if (accel > max_accelerations[j])
00094         {
00095           splines_constrained = false;
00096           double slope_before = fabs(
00097               (waypoints[i].angles()[j] - waypoints[i - 1].angles()[j]) / waypoints[i - 1].duration());
00098           double slope_after = fabs(
00099               (waypoints[i + 1].angles()[j] - waypoints[i].angles()[j]) / waypoints[i].duration());
00100 
00101 
00102           if (slope_before > slope_after)
00103           {
00104             waypoints[i - 1].duration(waypoints[i - 1].duration() * 1.1); 
00105           }
00106           else
00107           {
00108             waypoints[i].duration(waypoints[i].duration() * 1.1); 
00109           }
00110 
00111           break;
00112         }
00113       }
00114     }
00115   }
00116   
00117 
00118 
00119   
00120   
00121   if (!waypoints[0].rates_configured())
00122   {
00123     waypoints[0].rates() = WayPoint<JointAngles>::JointDataArray::Constant(waypoints[0].dimension(), 0.0);
00124   }
00125   if (!waypoints[n].rates_configured())
00126   {
00127     waypoints[n].rates() = WayPoint<JointAngles>::JointDataArray::Constant(waypoints[n].dimension(), 0.0);
00128   }
00129 
00130   
00131 
00132 
00133   double leading_quintic_time = 0.0;
00134   bool quintic_constrained = false;
00135   while (!quintic_constrained)
00136   {
00137     quintic_constrained = true;
00138     for (unsigned int i = 1; i <= 5; ++i)
00139     {
00140       double t = i * waypoints[0].duration() / 10;
00141       
00142       tension_splines = generateTensionSplines(tension, t); 
00143       for (unsigned int j = 0; j < dimension(); ++j)
00144       {
00145         
00146         double y_dot = tension_splines[j].derivative(2 * t);
00147         double y = tension_splines[j](2 * t);
00148         
00149         double y_0 = waypoints[0].angles()[j];
00150         double y_0_dot = waypoints[0].rates()[j];
00151         leading_quintics[j] = QuinticPolynomial::Interpolation(0.0, y_0, y_0_dot, 0.0, 2 * t, y, y_dot, 0.0);
00152 
00153         
00154 
00155 
00156 
00157 
00158 
00159 
00160 
00161 
00162 
00163 
00164 
00165 
00166         if ((fabs(ecl::Maximum<CubicPolynomial>()(0.0, 2 * t, leading_quintics[j].derivative().derivative()))
00167             < fabs(max_accelerations[j]))
00168             && (fabs(ecl::Minimum<CubicPolynomial>()(0.0, 2 * t, leading_quintics[j].derivative().derivative()))
00169                 < fabs(max_accelerations[j])))
00170         {
00171           if (j == dimension() - 1)
00172           { 
00173             leading_quintic_time = 2 * t;
00174             
00175             quintic_constrained = true;
00176             i = 5;
00177           }
00178         }
00179         else
00180         { 
00181           if (i == 5)
00182           { 
00183             quintic_constrained = false;
00184           }
00185           break;
00186         }
00187       }
00188       if (!quintic_constrained)
00189       { 
00190 
00191         waypoints[0].duration(waypoints[0].duration() * 1.1); 
00192         break; 
00193       }
00194     }
00195   }
00196 
00197   
00198 
00199 
00200   double trailing_quintic_time_0 = 0.0;
00201   double trailing_quintic_time_f = 0.0;
00202   quintic_constrained = false;
00203   while (!quintic_constrained)
00204   {
00205     quintic_constrained = true;
00206     tension_splines = generateTensionSplines(tension, leading_quintic_time / 2);
00207     for (unsigned int i = 1; i <= 5; ++i)
00208     {
00209       double t = i * waypoints[n - 1].duration() / 10;
00210       double t_f = tension_splines[0].domain().back();
00211       for (unsigned int j = 0; j < dimension(); ++j)
00212       {
00213         double y_dot = tension_splines[j].derivative(t_f - t);
00214         double y = tension_splines[j](t_f - t);
00215         double y_f = waypoints[n].angles()[j];
00216         double y_f_dot = waypoints[n].rates()[j];
00217         trailing_quintics[j] = QuinticPolynomial::Interpolation(t_f - t, y, y_dot, 0.0, t_f + t, y_f, y_f_dot, 0.0);
00218 
00219         
00220 
00221 
00222 
00223 
00224 
00225 
00226 
00227 
00228 
00229 
00230 
00231 
00232         if ((fabs(Maximum<CubicPolynomial>()(t_f - t, t_f + t, trailing_quintics[j].derivative().derivative()))
00233             < fabs(max_accelerations[j]))
00234             && (fabs(Minimum<CubicPolynomial>()(t_f - t, t_f + t, trailing_quintics[j].derivative().derivative()))
00235                 < fabs(max_accelerations[j])))
00236         {
00237           if (j == dimension() - 1)
00238           { 
00239             trailing_quintic_time_0 = tension_splines[j].domain().back() - t;
00240             trailing_quintic_time_f = tension_splines[j].domain().back() + t;
00241             
00242             quintic_constrained = true;
00243             i = 5;
00244           }
00245         }
00246         else
00247         { 
00248           if (i == 5)
00249           { 
00250             quintic_constrained = false;
00251           }
00252           break;
00253         }
00254       }
00255       if (!quintic_constrained)
00256       { 
00257         waypoints[n - 1].duration(waypoints[n - 1].duration() * 1.1); 
00258         break;
00259       }
00260     }
00261   }
00262 
00263   
00264 
00265 
00266 
00267 
00268   
00269 
00270 
00271   trajectory_duration = trailing_quintic_time_f;
00272   for (unsigned int j = 0; j < dimension(); ++j)
00273   {
00274     spline_functions[j][0] = new SplineFunction<QuinticPolynomial>(0.0, leading_quintic_time, leading_quintics[j]);
00275     spline_functions[j][1] = new SplineFunction<TensionSpline>(leading_quintic_time, trailing_quintic_time_0,
00276                                                                tension_splines[j]);
00277     spline_functions[j][2] = new SplineFunction<QuinticPolynomial>(trailing_quintic_time_0, trailing_quintic_time_f,
00278                                                                    trailing_quintics[j]);
00279   }
00280 }
00281 
00282 void Trajectory<JointAngles>::linearSplineInterpolation() throw (StandardException)
00283 {
00284   if (!validateWaypoints(2))
00285   {
00286     throw StandardException(LOC, ConfigurationError,
00287                             "Not all the waypoint maximum rates have been specified correctly (must be > 0.0).");
00288   }
00289   if (!initialiseWaypointDurations())
00290   {
00291     throw StandardException(LOC, ConfigurationError, "A waypoint was configured with a zero duration.");
00292   }
00293 
00294   
00295 
00296 
00297   clearSplines(); 
00298   for (unsigned int j = 0; j < dimension(); ++j)
00299   {
00300     spline_functions[j].resize(1, NULL);
00301   }
00302   Array<SmoothLinearSpline> splines(dimension());
00303 
00304   
00305 
00306 
00307   bool splines_constrained = false;
00308   int n = waypoints.size() - 1;
00309   while (!splines_constrained)
00310   {
00311     try
00312     {
00313       splines = generateLinearSplines();
00314       splines_constrained = true;
00315 #ifdef DEBUG_LINEAR_INTERPOLATION
00316       std::cout << "Linear Interpolation: spline generation success" << std::endl;
00317 #endif
00318     }
00319     catch (DataException<int> &e)
00320     {
00321       
00322 
00323 
00324       if (e.data() <= 0)
00325       {
00326 #ifdef DEBUG_LINEAR_INTERPOLATION
00327         std::cout << "Linear Interpolation: spline generation failed trying to create pre-pseudo, stretching first segment" << std::endl;
00328 #endif
00329         waypoints[0].duration(waypoints[0].duration() * 1.1); 
00330       }
00331       else if (e.data() == 1)
00332       { 
00333 #ifdef DEBUG_LINEAR_INTERPOLATION
00334         std::cout << "Linear Interpolation: spline generation failed, stretching at corner " << e.data() << std::endl;
00335 #endif
00336         waypoints[0].duration(waypoints[0].duration() * 1.1); 
00337       }
00338       else if (e.data() >= n + 1)
00339       { 
00340 #ifdef DEBUG_LINEAR_INTERPOLATION
00341         std::cout << "Linear Interpolation: spline generation failed, stretching at corner " << e.data() << std::endl;
00342 #endif
00343         waypoints[n - 1].duration(waypoints[n - 1].duration() * 1.1); 
00344       }
00345       else if (e.data() >= n + 2)
00346       {
00347         
00348         waypoints[n - 1].duration(waypoints[n - 1].duration() * 1.1); 
00349 #ifdef DEBUG_LINEAR_INTERPOLATION
00350         std::cout << "Linear Interpolation: spline generation failed trying to create post-pseudo, stretching last segment" << std::endl;
00351 #endif
00352       }
00353       else
00354       {
00355 #ifdef DEBUG_LINEAR_INTERPOLATION
00356         std::cout << "Linear Interpolation: spline generation failed, stretching at corner " << e.data() << std::endl;
00357 #endif
00358         waypoints[e.data() - 2].duration(waypoints[e.data() - 2].duration() * 1.05); 
00359         waypoints[e.data() - 1].duration(waypoints[e.data() - 1].duration() * 1.05); 
00360       }
00361     }
00362   }
00363 
00364   
00365 
00366 
00367   trajectory_duration = splines[0].domain().back() - splines[0].domain().front();
00368   for (unsigned int j = 0; j < dimension(); ++j)
00369   {
00370     spline_functions[j][0] = new SplineFunction<SmoothLinearSpline>(0.0, splines[j].domain().back(), splines[j]);
00371   }
00372 }
00373 
00374 
00375 
00376 
00377 
00378 double Trajectory<JointAngles>::operator ()(const unsigned int& joint, const double& time)
00379     ecl_assert_throw_decl(StandardException)
00380 {
00381 
00382   double t_f = spline_functions[joint][spline_functions[joint].size() - 1]->domain()[1];
00383   ecl_assert_throw( ( time >= 0.0 ) && ( time <= t_f + 0.0001 ), StandardException(LOC,OutOfRangeError));
00384   unsigned int i;
00385   for (i = 0; i < spline_functions[joint].size(); ++i)
00386   {
00387     if (time <= spline_functions[joint][i]->domain()[1])
00388     {
00389       return (*(spline_functions[joint][i]))(time);
00390     }
00391   }
00392   
00393   return (*(spline_functions[joint][spline_functions[joint].size() - 1]))(t_f);
00394 }
00395 
00396 double Trajectory<JointAngles>::derivative(const unsigned int& joint, const double& time)
00397     ecl_assert_throw_decl(StandardException)
00398 {
00399 
00400   double t_f = spline_functions[joint][spline_functions[joint].size() - 1]->domain()[1];
00401   ecl_assert_throw( ( time >= 0.0 ) && ( time <= t_f + 0.0001 ), StandardException(LOC,OutOfRangeError));
00402   unsigned int i;
00403   for (i = 0; i < spline_functions[joint].size(); ++i)
00404   {
00405     if (time <= spline_functions[joint][i]->domain()[1])
00406     {
00407       return spline_functions[joint][i]->derivative(time);
00408       break;
00409     }
00410   }
00411   
00412   return spline_functions[joint][spline_functions[joint].size() - 1]->derivative(t_f);
00413 }
00414 
00415 double Trajectory<JointAngles>::dderivative(const unsigned int& joint, const double& time)
00416     ecl_assert_throw_decl(StandardException)
00417 {
00418 
00419   double t_f = spline_functions[joint][spline_functions[joint].size() - 1]->domain()[1];
00420   ecl_assert_throw( ( time >= 0.0 ) && ( time <= t_f + 0.0001 ), StandardException(LOC,OutOfRangeError));
00421   unsigned int i;
00422   for (i = 0; i < spline_functions[joint].size(); ++i)
00423   {
00424     if (time <= spline_functions[joint][i]->domain()[1])
00425     {
00426       return spline_functions[joint][i]->dderivative(time);
00427       break;
00428     }
00429   }
00430   
00431   return spline_functions[joint][spline_functions[joint].size() - 1]->dderivative(t_f);
00432 }
00433 
00434 
00435 
00436 
00437 
00438 bool Trajectory<JointAngles>::validateWaypoints(unsigned int min_no_waypoints)
00439 {
00440 
00441   unsigned int n = waypoints.size() - 1; 
00442   if (n + 1 < min_no_waypoints)
00443   {
00444     return false;
00445   }
00446 
00447   for (unsigned int i = 0; i < n; ++i)
00448   { 
00449     for (unsigned int j = 0; j < waypoints[i].nominalRates().size(); ++j)
00450     {
00451       if (waypoints[i].nominalRates()[j] <= 0.0)
00452       {
00453         return false;
00454       }
00455     }
00456   }
00457   return true;
00458 }
00459 
00460 bool Trajectory<JointAngles>::initialiseWaypointDurations()
00461 {
00462 
00463   unsigned int n = waypoints.size() - 1; 
00464 
00465   
00466 
00467   
00468   
00469   
00470   for (unsigned int i = 0; i < n; ++i)
00471   { 
00472     double max_duration = 0.0;
00473     for (unsigned int j = 0; j < dimension(); ++j)
00474     {
00475       double distance = fabs(waypoints[i + 1].angles()[j] - waypoints[i].angles()[j]);
00476       if (waypoints[i].nominalRates()[j] != 0.0)
00477       {
00478         double segment_duration = distance / waypoints[i].nominalRates()[j]; 
00479         if (segment_duration > max_duration)
00480         {
00481           max_duration = segment_duration;
00482         }
00483       }
00484     }
00485     if (max_duration > waypoints[i].duration())
00486     {
00487       waypoints[i].duration(max_duration);
00488     }
00489     if (waypoints[i].duration() == 0.0)
00490     {
00491       return false;
00492     }
00493   }
00494   return true;
00495 }
00496 
00497 void Trajectory<JointAngles>::clearSplines()
00498 {
00499   for (unsigned int joint = 0; joint < dimension(); ++joint)
00500   {
00501     for (unsigned int function = 0; function < spline_functions[joint].size(); ++function)
00502     {
00503       if (spline_functions[joint][function] != NULL)
00504       {
00505         delete spline_functions[joint][function];
00506         spline_functions[joint][function] = NULL;
00507       }
00508     }
00509     spline_functions[joint].clear();
00510   }
00511 }
00512 
00513 void Trajectory<JointAngles>::updateDuration()
00514 {
00515   double total_time = 0.0;
00516 
00517   for (unsigned int i = 0; i < waypoints.size() - 1; ++i)
00518   {
00519     total_time += waypoints[i].duration();
00520 
00521   }
00522 
00523   trajectory_duration = total_time;
00524 }
00525 
00526 Array<SmoothLinearSpline> Trajectory<JointAngles>::generateLinearSplines() throw (DataException<int> )
00527 {
00528   
00529   
00530   
00531 
00532   
00533   Array<SmoothLinearSpline> splines(dimension());
00534   unsigned int n = waypoints.size() - 1; 
00535   Array<double> waypoint_times(n + 3), values(n + 3); 
00536 
00537   
00538 
00539 
00540   
00541   
00542   if (!waypoints[0].rates_configured())
00543   {
00544     waypoints[0].rates() = WayPoint<JointAngles>::JointDataArray::Constant(waypoints[0].dimension(), 0.0);
00545   }
00546   if (!waypoints[n].rates_configured())
00547   {
00548     waypoints[n].rates() = WayPoint<JointAngles>::JointDataArray::Constant(waypoints[n].dimension(), 0.0);
00549   }
00550 
00551   
00552 
00553 
00554   
00555 
00556 
00557 
00558 
00559 
00560 
00561 
00562 
00563 
00564 
00565 
00566 
00567 
00568 
00569 
00570 
00571 
00572 
00573 
00574 
00575 
00576 
00577 
00578 
00579   std::vector<LinearFunction> initial_tangents; 
00580   std::vector<double> initial_angles, initial_rates;
00581   for (unsigned int j = 0; j < dimension(); ++j)
00582   {
00583     initial_angles.push_back(waypoints[0].angles()[j]);
00584     initial_rates.push_back(waypoints[0].rates()[j]);
00585     initial_tangents.push_back(LinearFunction::PointSlopeForm(0, initial_angles[j], initial_rates[j]));
00586   }
00587   std::vector<CartesianPoint2d, Eigen::aligned_allocator<CartesianPoint2d> > pseudo_points(dimension());
00588   std::vector<LinearFunction> nominal_rate_lines(dimension());
00589   WayPoint<JointAngles> pre_pseudo_waypoint(dimension());
00590   double t_pullback = 0.001; 
00591   double t_pullback_max_ = waypoints[0].duration();
00592   double t_pre_intersect_duration = 0.0; 
00593   bool acceleration_constraint_broken = true;
00594   while (acceleration_constraint_broken && (t_pullback <= t_pullback_max_))
00595   {
00596     
00597     
00598     t_pre_intersect_duration = t_pullback_max_ / 2;
00599     for (unsigned int j = 0; j < dimension(); ++j)
00600     {
00601       LinearFunction nominal_rate_line = LinearFunction::PointSlopeForm(
00602           t_pullback, initial_angles[j], -1 * ecl::psign(initial_rates[j]) * waypoints[0].nominalRates()[j]);
00603       CartesianPoint2d pseudo_point = LinearFunction::Intersection(initial_tangents[j], nominal_rate_line);
00604       if (pseudo_point.x() < t_pre_intersect_duration)
00605       {
00606         t_pre_intersect_duration = pseudo_point.x();
00607       }
00608       nominal_rate_lines[j] = nominal_rate_line;
00609     }
00610     acceleration_constraint_broken = false;
00611     for (unsigned int j = 0; j < dimension(); ++j)
00612     {
00613       CartesianPoint2d pseudo_point(t_pre_intersect_duration, initial_tangents[j](t_pre_intersect_duration));
00614       
00615       double pseudo_point_duration = t_pullback + waypoints[0].duration() - t_pre_intersect_duration;
00616       
00617       
00618       for (unsigned int i = 1; i <= 5; ++i)
00619       {
00620         double t_l = t_pre_intersect_duration - i * t_pre_intersect_duration / 5.0;
00621         double t_r = t_pre_intersect_duration + i * pseudo_point_duration / 10.0;
00622         LinearFunction segment = LinearFunction::Interpolation(pseudo_point.x(), pseudo_point.y(),
00623                                                                t_pullback + waypoints[0].duration(),
00624                                                                waypoints[1].angles()[j]);
00625         double y_0 = initial_tangents[j](t_l);
00626         double y_0_dot = initial_tangents[j].derivative(t_l);
00627         double y = segment(t_r);
00628         double y_dot = segment.derivative(t_r); 
00629         QuinticPolynomial quintic = QuinticPolynomial::Interpolation(t_l, y_0, y_0_dot, 0.0, t_r, y, y_dot, 0.0);
00630         if ((fabs(CubicPolynomial::Maximum(t_l, t_r, quintic.derivative().derivative())) < fabs(max_accelerations[j]))
00631             && (fabs(CubicPolynomial::Minimum(t_l, t_r, quintic.derivative().derivative())) < fabs(max_accelerations[j])))
00632         {
00633           acceleration_constraint_broken = false;
00634           break; 
00635         }
00636         if (i == 5)
00637         {
00638 #ifdef DEBUG_LINEAR_INTERPOLATION
00639           std::cout << "Linear Interpolation: pre psuedo point failed with acceleration checks [" << t_pre_intersect_duration << "][" << t_pullback << "]" << std::endl;
00640 #endif
00641           acceleration_constraint_broken = true;
00642         }
00643       }
00644     }
00645     t_pullback = t_pullback * 2; 
00646   }
00647   if (acceleration_constraint_broken)
00648   {
00649     throw DataException<int>(LOC, ConstructorError, "Max acceleration bound broken by pre pseudo point.", 0);
00650   }
00651   pre_pseudo_waypoint.duration(t_pullback + waypoints[0].duration() - t_pre_intersect_duration);
00652   for (unsigned int j = 0; j < dimension(); ++j)
00653   {
00654     pre_pseudo_waypoint.angles()[j] = initial_tangents[j](t_pre_intersect_duration);
00655   }
00656 #ifdef DEBUG_LINEAR_INTERPOLATION
00657   std::cout << "Linear Interpolation: pre psuedo point done!" << std::endl;
00658   std::cout << "                    : angles " << pre_pseudo_waypoint.angles() << std::endl;
00659   std::cout << "                    : pre pseudo duration " << t_pre_intersect_duration << std::endl;
00660   std::cout << "                    : modified first waypoint duration " << pre_pseudo_waypoint.duration() << std::endl;
00661 #endif
00662 
00663   
00664 
00665 
00666   std::vector<double> final_angles, final_rates;
00667   for (unsigned int j = 0; j < dimension(); ++j)
00668   {
00669     final_angles.push_back(waypoints[n].angles()[j]);
00670     final_rates.push_back(waypoints[n].rates()[j]);
00671     nominal_rate_lines[j] = LinearFunction::PointSlopeForm(
00672         0, final_angles[j], -1 * ecl::psign(final_rates[j]) * waypoints[n - 1].nominalRates()[j]);
00673   }
00674   std::vector<LinearFunction> final_tangents(dimension());
00675   WayPoint<JointAngles> post_pseudo_waypoint(dimension());
00676   double t_pullforward = 0.001; 
00677   double t_pullforward_max_ = waypoints[n - 1].duration();
00678   double t_post_intersect_duration = 0.0; 
00679   acceleration_constraint_broken = true;
00680   while (acceleration_constraint_broken && (t_pullforward <= t_pullforward_max_))
00681   {
00682     
00683     t_post_intersect_duration = 0.0;
00684     for (unsigned int j = 0; j < dimension(); ++j)
00685     {
00686       LinearFunction final_tangent = LinearFunction::PointSlopeForm(t_pullforward, final_angles[j], final_rates[j]);
00687       final_tangents[j] = final_tangent;
00688       CartesianPoint2d pseudo_point = LinearFunction::Intersection(final_tangents[j], nominal_rate_lines[j]);
00689       if (pseudo_point.x() > t_post_intersect_duration)
00690       {
00691         t_post_intersect_duration = pseudo_point.x();
00692       }
00693     }
00694     
00695     acceleration_constraint_broken = false;
00696     for (unsigned int j = 0; j < dimension(); ++j)
00697     {
00698       CartesianPoint2d pseudo_point(t_post_intersect_duration, final_tangents[j](t_post_intersect_duration));
00699       double pseudo_point_duration = t_pullforward - t_post_intersect_duration;
00700       for (unsigned int i = 1; i <= 5; ++i)
00701       {
00702         double t_l = t_post_intersect_duration - i * (waypoints[n - 1].duration() + t_post_intersect_duration) / 10.0;
00703         double t_r = t_post_intersect_duration + i * pseudo_point_duration / 5.0;
00704         LinearFunction segment = LinearFunction::Interpolation(-waypoints[n - 1].duration(),
00705                                                                waypoints[n - 1].angles()[j], pseudo_point.x(),
00706                                                                pseudo_point.y());
00707         double y_0 = segment(t_l);
00708         double y_0_dot = segment.derivative(t_l);
00709         double y = final_tangents[j](t_r);
00710         double y_dot = final_tangents[j].derivative(t_r);
00711         QuinticPolynomial quintic = QuinticPolynomial::Interpolation(t_l, y_0, y_0_dot, 0.0, t_r, y, y_dot, 0.0);
00712         if ((fabs(CubicPolynomial::Maximum(t_l, t_r, quintic.derivative().derivative())) < fabs(max_accelerations[j]))
00713             && (fabs(CubicPolynomial::Minimum(t_l, t_r, quintic.derivative().derivative())) < fabs(max_accelerations[j])))
00714         {
00715           acceleration_constraint_broken = false;
00716           break; 
00717         }
00718         if (i == 5)
00719         {
00720 #ifdef DEBUG_LINEAR_INTERPOLATION
00721           std::cout << "Linear Interpolation: post psuedo point failed with acceleration checks [" << t_post_intersect_duration << "][" << t_pullforward << "]" << std::endl;
00722 #endif
00723           acceleration_constraint_broken = true;
00724         }
00725       }
00726     }
00727     t_pullforward = t_pullforward * 2; 
00728   }
00729   if (acceleration_constraint_broken)
00730   {
00731     throw DataException<int>(LOC, ConstructorError, "Max acceleration bound broken by pre pseudo point.", 0);
00732   }
00733   post_pseudo_waypoint.duration(t_pullforward - t_post_intersect_duration);
00734   for (unsigned int j = 0; j < dimension(); ++j)
00735   {
00736     post_pseudo_waypoint.angles()[j] = final_tangents[j](t_post_intersect_duration);
00737   }
00738 #ifdef DEBUG_LINEAR_INTERPOLATION
00739   std::cout << "Linear Interpolation: post psuedo point done!" << std::endl;
00740   std::cout << "                    : angles " << post_pseudo_waypoint.angles() << std::endl;
00741   std::cout << "                    : modified last point duration " << waypoints[n-1].duration() + t_post_intersect_duration << std::endl;
00742   std::cout << "                    : post pseudo duration " << post_pseudo_waypoint.duration() << std::endl;
00743 #endif
00744 
00745   
00746 
00747 
00748   
00749   
00750   waypoint_times[0] = 0.0;
00751   waypoint_times[1] = t_pre_intersect_duration;
00752   waypoint_times[2] = t_pre_intersect_duration + pre_pseudo_waypoint.duration();
00753   for (unsigned int i = 2; i < n; ++i)
00754   {
00755     waypoint_times[i + 1] = waypoint_times[i] + waypoints[i - 1].duration();
00756   }
00757   waypoint_times[n + 1] = waypoint_times[n] + waypoints[n - 1].duration() + t_post_intersect_duration;
00758   waypoint_times[n + 2] = waypoint_times[n + 1] + post_pseudo_waypoint.duration();
00759 
00760 #ifdef DEBUG_LINEAR_INTERPOLATION
00761   std::cout << "Linear Interpolation: waypoint time estimates before interpolation: " << waypoint_times << std::endl;
00762 #endif
00763 
00764   for (unsigned int j = 0; j < dimension(); ++j)
00765   {
00766     
00767 
00768 
00769     values[0] = waypoints[0].angles()[j];
00770     values[1] = pre_pseudo_waypoint.angles()[j];
00771     for (unsigned int i = 2; i <= n; ++i)
00772     {
00773       values[i] = waypoints[i - 1].angles()[j];
00774     }
00775     values[n + 1] = post_pseudo_waypoint.angles()[j];
00776     values[n + 2] = waypoints[n].angles()[j];
00777 #ifdef DEBUG_LINEAR_INTERPOLATION
00778     std::cout << "Linear Interpolation: values[" << j << "]: " << values << std::endl;
00779 #endif
00780 
00781     
00782 
00783 
00784     try
00785     {
00786       splines[j] = SmoothLinearSpline::Interpolation(waypoint_times, values, max_accelerations[j]);
00787     }
00788     catch (DataException<int> &e)
00789     {
00790       throw DataException<int>(LOC, e);
00791     }
00792   }
00793 #ifdef DEBUG_LINEAR_INTERPOLATION
00794   for ( unsigned int j = 0; j < dimension(); ++j)
00795   {
00796     std::cout << "Linear Interpolation: discretised domain [" << j << "]: " << splines[j].domain() << std::endl;
00797   }
00798 #endif
00799   return splines;
00800 }
00801 
00802 Array<TensionSpline> Trajectory<JointAngles>::generateTensionSplines(const double& tension, const double initial_time)
00803 {
00804 
00805   Array<TensionSpline> tension_splines(dimension());
00806   unsigned int n = waypoints.size() - 1; 
00807   
00808   Array<double> waypoint_times(n + 1), values(n + 1);
00809   waypoint_times[0] = initial_time;
00810   for (unsigned int i = 1; i < n + 1; ++i)
00811   {
00812     waypoint_times[i] = waypoint_times[i - 1] + waypoints[i - 1].duration();
00813   }
00814 
00815   for (unsigned int j = 0; j < dimension(); ++j)
00816   {
00817     for (unsigned int i = 0; i < n + 1; ++i)
00818     {
00819       values[i] = waypoints[i].angles()[j];
00820     }
00821     tension_splines[j] = TensionSpline::Natural(waypoint_times, values, tension);
00822   }
00823   return tension_splines;
00824 }
00825 
00826 }