Claw  1.7.3
curve.tpp
Go to the documentation of this file.
1 /*
2  CLAW - a C++ Library Absolutely Wonderful
3 
4  CLAW is a free library without any particular aim but being useful to
5  anyone.
6 
7  Copyright (C) 2005-2011 Julien Jorge
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22  contact: julien.jorge@gamned.org
23 */
29 #include <boost/math/special_functions/cbrt.hpp>
30 #include <boost/math/constants/constants.hpp>
31 
32 /*----------------------------------------------------------------------------*/
36 template<typename C, typename Traits>
38 {
39 
40 } // curve::control_point::control_point()
41 
42 /*----------------------------------------------------------------------------*/
48 template<typename C, typename Traits>
50 ( const coordinate_type& p )
51  : m_position(p), m_input_direction(p), m_output_direction(p)
52 {
53 
54 } // curve::control_point::control_point()
55 
56 /*----------------------------------------------------------------------------*/
65 template<typename C, typename Traits>
67 ( const coordinate_type& p, const coordinate_type& input_direction,
68  const coordinate_type& output_direction )
69  : m_position(p), m_input_direction(input_direction),
70  m_output_direction(output_direction)
71 {
72 
73 } // curve::control_point::control_point()
74 
75 /*----------------------------------------------------------------------------*/
79 template<typename C, typename Traits>
82 {
83  return m_position;
84 } // curve::control_point::get_position()
85 
86 /*----------------------------------------------------------------------------*/
91 template<typename C, typename Traits>
94 {
95  return m_input_direction;
96 } // curve::control_point::get_input_direction()
97 
98 /*----------------------------------------------------------------------------*/
103 template<typename C, typename Traits>
106 {
107  return m_output_direction;
108 } // curve::control_point::get_output_direction()
109 
110 
111 
112 
113 
114 /*----------------------------------------------------------------------------*/
121 template<typename C, typename Traits>
123 ( const coordinate_type& position, const section& s, const double t )
124  : m_position(position), m_section(s), m_date(t)
125 {
126 
127 } // curve::section::resolved_point::resolved_point()
128 
129 /*----------------------------------------------------------------------------*/
133 template<typename C, typename Traits>
134 const
137 {
138  return m_position;
139 } // curve::section::resolved_point::get_position()
140 
141 /*----------------------------------------------------------------------------*/
145 template<typename C, typename Traits>
148 {
149  return m_section;
150 } // curve::section::::resolved_point::get_section()
151 
152 /*----------------------------------------------------------------------------*/
156 template<typename C, typename Traits>
157 double
159 {
160  return m_date;
161 } // curve::section::resolved_point::get_date()
162 
163 
164 
165 
166 
167 
168 /*----------------------------------------------------------------------------*/
174 template<typename C, typename Traits>
176 ( const iterator_type& origin, const iterator_type& end )
177  : m_origin(origin), m_end(end)
178 {
179 
180 } // curve::section::section()
181 
182 /*----------------------------------------------------------------------------*/
187 template<typename C, typename Traits>
190 {
191  if ( m_origin == m_end )
192  return m_origin->get_position();
193 
194  const value_type x
195  ( evaluate
196  ( t, traits_type::get_x(m_origin->get_position()),
197  traits_type::get_x(m_origin->get_output_direction()),
198  traits_type::get_x(m_end->get_input_direction()),
199  traits_type::get_x(m_end->get_position()) ) );
200  const value_type y
201  ( evaluate
202  ( t, traits_type::get_y(m_origin->get_position()),
203  traits_type::get_y(m_origin->get_output_direction()),
204  traits_type::get_y(m_end->get_input_direction()),
205  traits_type::get_y(m_end->get_position()) ) );
206 
207  return traits_type::make_coordinate( x, y );
208 } // curve::section::get_point_at()
209 
210 /*----------------------------------------------------------------------------*/
215 template<typename C, typename Traits>
218 {
219  const value_type dx = evaluate_derived
220  ( t, traits_type::get_x(m_origin->get_position()),
221  traits_type::get_x(m_origin->get_output_direction()),
222  traits_type::get_x(m_end->get_input_direction()),
223  traits_type::get_x(m_end->get_position()) );
224 
225  const value_type dy = evaluate_derived
226  ( t, traits_type::get_y(m_origin->get_position()),
227  traits_type::get_y(m_origin->get_output_direction()),
228  traits_type::get_y(m_end->get_input_direction()),
229  traits_type::get_y(m_end->get_position()) );
230 
231  if ( dx == 0 )
232  return traits_type::make_coordinate( 0, (dy < 0) ? -1 : 1 );
233  else
234  return traits_type::make_coordinate( 1, dy / dx );
235 } // curve::section::get_tangent_at()
236 
237 /*----------------------------------------------------------------------------*/
244 template<typename C, typename Traits>
245 std::vector<typename claw::math::curve<C, Traits>::section::resolved_point>
247 ( value_type x, bool off_domain ) const
248 {
249  std::vector<resolved_point> result;
250 
251  if ( empty() )
252  return result;
253 
254  const std::vector<double> roots
255  ( get_roots
256  ( x, traits_type::get_x(m_origin->get_position()),
257  traits_type::get_x(m_origin->get_output_direction()),
258  traits_type::get_x(m_end->get_input_direction()),
259  traits_type::get_x(m_end->get_position() ) ) );
260 
261  for ( std::size_t i=0; i!=roots.size(); ++i )
262  result.push_back
263  ( resolved_point( get_point_at( roots[i] ), *this, roots[i] ) );
264 
265  ensure_ends_in_points
266  ( result,
267  (x == m_origin->get_position().x), (x == m_end->get_position().x) );
268 
269  if ( !off_domain )
270  return extract_domain_points( result );
271  else
272  return result;
273 } // curve::section::get_point_at_x()
274 
275 /*----------------------------------------------------------------------------*/
280 template<typename C, typename Traits>
283 {
284  return m_origin;
285 } // curve::section::get_origin()
286 
287 /*----------------------------------------------------------------------------*/
291 template<typename C, typename Traits>
293 {
294  return m_origin == m_end;
295 } // curve::section::empty()
296 
297 /*----------------------------------------------------------------------------*/
311 template<typename C, typename Traits>
314 ( double t, value_type origin, value_type output_direction,
315  value_type input_direction, value_type end ) const
316 {
317  const double dt(1 - t);
318 
319  return origin * dt * dt * dt
320  + 3 * output_direction * t * dt * dt
321  + 3 * input_direction * t * t * dt
322  + end * t * t * t;
323 } // curve::section::evaluate()
324 
325 /*----------------------------------------------------------------------------*/
339 template<typename C, typename Traits>
342 ( double t, value_type origin, value_type output_direction,
343  value_type input_direction, value_type end ) const
344 {
345  return - 3 * origin + 3 * output_direction
346  + (6 * origin - 12 * output_direction + 6 * input_direction) * t
347  + (-3 * origin + 9 * output_direction - 9 * input_direction + 3 * end)
348  * t * t;
349 } // curve::section::evaluate_derived()
350 
351 /*----------------------------------------------------------------------------*/
365 template<typename C, typename Traits>
367 ( std::vector<resolved_point>& p, bool ensure_origin, bool ensure_end ) const
368 {
369  double min_distance_origin( std::numeric_limits<double>::max() );
370  double min_distance_end( std::numeric_limits<double>::max() );
371  std::size_t origin_index(p.size());
372  std::size_t end_index(p.size());
373 
374  for ( std::size_t i=0; i!=p.size(); ++i )
375  {
376  const double distance_origin( std::abs( p[i].get_date() ) );
377 
378  if ( distance_origin <= min_distance_origin )
379  {
380  min_distance_origin = distance_origin;
381  origin_index = i;
382  }
383 
384  const double distance_end( std::abs( 1 - p[i].get_date() ) );
385 
386  if ( distance_end <= min_distance_end )
387  {
388  min_distance_end = distance_end;
389  end_index = i;
390  }
391  }
392 
393  if ( ensure_origin )
394  p[origin_index] = resolved_point( m_origin->get_position(), *this, 0.0 );
395 
396  if ( ensure_end )
397  p[end_index] = resolved_point( m_end->get_position(), *this, 1.0 );
398 } // curve::section::ensure_ends_in_points()
399 
400 /*----------------------------------------------------------------------------*/
405 template<typename C, typename Traits>
406 std::vector<typename claw::math::curve<C, Traits>::section::resolved_point>
408 ( const std::vector<resolved_point>& p ) const
409 {
410  std::vector<resolved_point> clean_result;
411 
412  for ( std::size_t i=0; i!=p.size(); ++i )
413  if ( (p[i].get_date() >= 0) && (p[i].get_date() <= 1) )
414  clean_result.push_back( p[i] );
415 
416  return clean_result;
417 } // curve::section::extract_domain_points()
418 
419 /*----------------------------------------------------------------------------*/
433 template<typename C, typename Traits>
434 std::vector<double>
436 ( value_type x, value_type origin, value_type output_direction,
437  value_type input_direction, value_type end ) const
438 {
439  const value_type a
440  (-origin + 3 * output_direction - 3 * input_direction + end );
441  const value_type b( 3 * origin - 6 * output_direction + 3 * input_direction );
442  const value_type c( -3 * origin + 3 * output_direction );
443  const value_type d( origin - x );
444 
445  if ( a == 0 )
446  return get_roots_degree_2(b, c, d);
447  else
448  return get_roots_degree_3(a, b, c, d);
449 } // curve::section::get_roots()
450 
451 /*----------------------------------------------------------------------------*/
459 template<typename C, typename Traits>
460 std::vector<double>
462 ( value_type a, value_type b, value_type c ) const
463 {
464  const value_type delta( b * b - 4 * a * c );
465 
466  std::vector<double> result;
467 
468  if ( delta == 0 )
469  result.push_back( - b / ( 2 * a ) );
470  else if ( delta > 0 )
471  {
472  result.push_back( (-b - std::sqrt(delta)) / (2 * a) );
473  result.push_back( (-b + std::sqrt(delta)) / (2 * a) );
474  }
475 
476  return result;
477 } // curve::section::get_roots_degree_2()
478 
479 /*----------------------------------------------------------------------------*/
488 template<typename C, typename Traits>
489 std::vector<double>
491 ( value_type a, value_type b, value_type c, value_type d ) const
492 {
493  // The following is the application of the method of Cardan
494 
495  const value_type p( -(b * b) / (3.0 * a * a) + c / a );
496  const value_type q
497  ( ( b / (27.0 * a) )
498  * ( (2.0 * b * b) / (a * a)
499  - 9.0 * c / a )
500  + d / a );
501 
502  const value_type delta( q * q + 4.0 * p * p * p / 27.0 );
503 
504  std::vector<double> result;
505 
506  if ( delta == 0 )
507  {
508  if ( p == 0 )
509  result.push_back(0);
510  else
511  {
512  result.push_back( 3.0 * q / p - b / (3.0 * a) );
513  result.push_back( - 3.0 * q / (2.0 * p) - b / (3.0 * a) );
514  }
515  }
516  else if ( delta > 0 )
517  {
518  result.push_back
519  ( boost::math::cbrt
520  ( (-q + std::sqrt(delta)) / 2.0 )
521  + boost::math::cbrt
522  ( (-q - std::sqrt(delta)) / 2.0 ) - b / (3.0 * a));
523  }
524  else
525  for ( std::size_t i=0; i!=3; ++i )
526  result.push_back
527  ( 2.0 * std::sqrt( -p / 3.0 )
528  * std::cos
529  ( std::acos( std::sqrt(27.0 / (- p * p * p)) * - q / 2.0 ) / 3.0
530  + 2.0 * i * boost::math::constants::pi<double>() / 3.0 )
531  - b / (3.0 * a));
532 
533  return result;
534 } // curve::section::get_roots_degree_3()
535 
536 
537 
538 
539 
540 
541 /*----------------------------------------------------------------------------*/
546 template<typename C, typename Traits>
548 {
549  m_points.push_back(p);
550 } // curve::push_back()
551 
552 /*----------------------------------------------------------------------------*/
557 template<typename C, typename Traits>
559 {
560  m_points.push_front(p);
561 } // curve::push_front()
562 
563 /*----------------------------------------------------------------------------*/
569 template<typename C, typename Traits>
571 ( const iterator& pos, const control_point& p )
572 {
573  m_points.insert( pos, p );
574 } // curve::insert()
575 
576 /*----------------------------------------------------------------------------*/
582 template<typename C, typename Traits>
585 {
586  const_iterator it(pos);
587  ++it;
588 
589  if ( it == end() )
590  return section( pos, pos );
591  else
592  return section( pos, it );
593 } // curve::get_section()
594 
595 /*----------------------------------------------------------------------------*/
604 template<typename C, typename Traits>
605 std::vector< typename claw::math::curve<C, Traits>::section::resolved_point >
607 ( value_type x, bool off_domain ) const
608 {
609  typedef std::vector<typename section::resolved_point> result_type;
610  result_type result;
611 
612  for ( const_iterator it=begin(); it!=end(); ++it )
613  {
614  const section s( get_section(it) );
615 
616  if ( !s.empty() )
617  {
618  const result_type new_points( s.get_point_at_x(x) );
619  result.insert( result.end(), new_points.begin(), new_points.end() );
620  }
621  }
622 
623  if ( off_domain )
624  {
625  const result_type before( get_point_at_x_before_origin(x) );
626  result.insert( result.begin(), before.begin(), before.end() );
627 
628  const result_type after( get_point_at_x_after_end(x) );
629  result.insert( result.end(), after.begin(), after.end() );
630  }
631 
632  return result;
633 } // curve::get_point_at_x()
634 
635 /*----------------------------------------------------------------------------*/
639 template<typename C, typename Traits>
642 {
643  return m_points.begin();
644 } // curve::begin()
645 
646 /*----------------------------------------------------------------------------*/
650 template<typename C, typename Traits>
653 {
654  return m_points.end();
655 } // curve::end()
656 
657 /*----------------------------------------------------------------------------*/
661 template<typename C, typename Traits>
664 {
665  return m_points.begin();
666 } // curve::begin()
667 
668 /*----------------------------------------------------------------------------*/
672 template<typename C, typename Traits>
675 {
676  return m_points.end();
677 } // curve::end()
678 
679 /*----------------------------------------------------------------------------*/
685 template<typename C, typename Traits>
686 std::vector< typename claw::math::curve<C, Traits>::section::resolved_point >
688 {
689  typedef std::vector<typename section::resolved_point> result_type;
690  result_type result;
691 
692  const section s( get_section(begin()) );
693 
694  if ( !s.empty() )
695  {
696  const result_type points( s.get_point_at_x(x, true) );
697 
698  for ( std::size_t i(0); i!=points.size(); ++i )
699  if ( points[i].get_date() < 0 )
700  result.push_back( points[i] );
701  }
702 
703  return result;
704 } // curve::get_point_at_x_before_origin()
705 
706 /*----------------------------------------------------------------------------*/
712 template<typename C, typename Traits>
713 std::vector< typename claw::math::curve<C, Traits>::section::resolved_point >
715 {
716  typedef std::vector<typename section::resolved_point> result_type;
717  result_type result;
718 
719  if ( m_points.size() < 2 )
720  return result;
721 
722  const_iterator it(end());
723  std::advance(it, -2);
724 
725  const section s( get_section( it ) );
726 
727  if ( !s.empty() )
728  {
729  const result_type points( s.get_point_at_x(x, true) );
730 
731  for ( std::size_t i(0); i!=points.size(); ++i )
732  if ( points[i].get_date() > 1 )
733  result.push_back( points[i] );
734  }
735 
736  return result;
737 } // curve::get_point_at_x_after_end()