Changeset 96:5a75c0a06ee1 in rrlib_geometry


Ignore:
Timestamp:
01.10.2020 10:48:25 (2 months ago)
Author:
Tobias Föhst <foehst@…>
Branch:
14.08
Phase:
public
Message:

Postpones calculation of knot vector and padds splines of higher degree to get end point interpolation

Location:
curves
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • curves/tBSplineCurve.h

    r60 r96  
    9696  virtual const unsigned int NumberOfSegments() const; 
    9797 
    98   const std::vector<typename tSplineCurve::tParameter> &Knots() const 
    99   { 
    100     return this->knots; 
    101   } 
     98  /*! Get the knot vector for the current control points 
     99   * 
     100   * \note The knots are calculated on demand. Clear the vector if a control point changes! 
     101   */ 
     102  const std::vector<typename tSplineCurve::tParameter> &Knots() const; 
    102103 
    103104  template <typename TIterator> 
     
    122123private: 
    123124  /*! B-spline knot vector (#knots = #control points + degree + 1) */ 
    124   std::vector<typename tSplineCurve::tParameter> knots; 
     125  mutable std::vector<typename tSplineCurve::tParameter> knots; 
    125126  /*! Bezier control points used to evaluate b-spline curve which is converted to a set of bezier curves  */ 
    126   mutable std::vector<typename tShape::tPoint> bezier_control_point_cache; 
     127  mutable std::vector<typename tShape::tPoint> bezier_control_points; 
    127128  mutable unsigned int number_of_segments; 
    128129 
    129   /*! 
    130    * Calculate a uniform knot vector, this->knots will be modified 
     130  /*! Get control points for Bezier representation 
     131   * 
     132   * \note The control points are lazily calculated on demand. Clear the vector if a spline control point changes! 
    131133   */ 
    132   void CalculateKnotVector(); 
    133  
    134   /*! 
    135    * Calculate all Bezier control points by knot insertion, this->bezier_control_points will be modified 
    136    */ 
    137   void CalculateBezierControlPoints() const; 
     134  const std::vector<typename tShape::tPoint> &BezierControlPoints() const; 
    138135 
    139136  /*! 
  • curves/tBSplineCurve.hpp

    r89 r96  
    3434// Internal includes with "" 
    3535//---------------------------------------------------------------------- 
     36 
    3637//---------------------------------------------------------------------- 
    3738// Debugging 
     
    6667  tSplineCurve(), 
    6768  number_of_segments(-1) 
    68 { 
    69   this->CalculateKnotVector(); 
    70 } 
     69{} 
    7170 
    7271template<size_t Tdimension, typename TElement, unsigned int Tdegree> 
     
    8685  tSplineCurve(begin, end), 
    8786  number_of_segments(-1) 
    88 { 
    89   this->CalculateKnotVector(); 
    90 } 
     87{} 
    9188 
    9289//---------------------------------------------------------------------- 
     
    9693const unsigned int tBSplineCurve<Tdimension, TElement, Tdegree>::NumberOfSegments() const 
    9794{ 
     95  if (this->NumberOfControlPoints() == 0) 
     96  { 
     97    return 0; 
     98  } 
    9899  if (this->number_of_segments == static_cast<unsigned int>(-1)) 
    99100  { 
    100101    this->number_of_segments = 0; 
    101     for (size_t i = 0; i < this->knots.size() - 1; ++i) 
    102     { 
    103       if (this->knots[i] != this->knots[i + 1]) 
     102    for (size_t i = 1; i < this->Knots().size(); ++i) 
     103    { 
     104      if (this->Knots()[i - 1] != this->Knots()[i]) 
    104105      { 
    105106        this->number_of_segments++; 
     
    117118{ 
    118119  tSplineCurve::SetChanged(); 
    119   this->CalculateKnotVector(); 
    120   this->bezier_control_point_cache.clear(); 
     120  this->knots.clear(); 
     121  this->bezier_control_points.clear(); 
    121122  this->number_of_segments = -1; 
    122123} 
    123124 
    124 template<size_t Tdimension, typename TElement, unsigned int Tdegree> 
    125 void tBSplineCurve<Tdimension, TElement, Tdegree>::CalculateKnotVector() 
    126 { 
    127   this->knots.clear(); 
    128   assert(this->NumberOfControlPoints() > Tdegree); 
     125//---------------------------------------------------------------------- 
     126// tBSplineCurve Knots 
     127//---------------------------------------------------------------------- 
     128template<size_t Tdimension, typename TElement, unsigned int Tdegree> 
     129const std::vector<typename tSplineCurve<Tdimension, TElement, Tdegree>::tParameter> &tBSplineCurve<Tdimension, TElement, Tdegree>::Knots() const 
     130{ 
     131  if (!this->knots.empty()) 
     132  { 
     133    return this->knots; 
     134  } 
     135 
     136  assert(this->NumberOfControlPoints() > 0); 
     137  const auto cNUMBER_OF_CONTROL_POINTS = std::max<std::size_t>(Tdegree + 1, this->NumberOfControlPoints()); 
     138 
     139  assert(cNUMBER_OF_CONTROL_POINTS > Tdegree); 
    129140  // calculate knot vector 
    130   unsigned int length = this->NumberOfControlPoints() + Tdegree + 1; 
     141  unsigned int length = cNUMBER_OF_CONTROL_POINTS + Tdegree + 1; 
    131142  this->knots.reserve(length); 
    132143 
     
    137148      this->knots.push_back(0); 
    138149    } 
    139     else if ((Tdegree + 1) <= i && i <= this->NumberOfControlPoints()) 
     150    else if ((Tdegree + 1) <= i && i <= cNUMBER_OF_CONTROL_POINTS) 
    140151    { 
    141152      // inner knot vector (uniform) 
    142153      this->knots.push_back(1.0 / (this->NumberOfControlPoints() - Tdegree) * (i - Tdegree)); 
    143154    } 
    144     else if (i > this->NumberOfControlPoints()) 
     155    else if (i > cNUMBER_OF_CONTROL_POINTS) 
    145156    { 
    146157      this->knots.push_back(1.0); 
    147158    } 
    148159  } 
    149 } 
    150  
    151 template<size_t Tdimension, typename TElement, unsigned int Tdegree> 
    152 void tBSplineCurve<Tdimension, TElement, Tdegree>::CalculateBezierControlPoints() const 
    153 { 
    154   for (std::size_t i = 0, k = 1; k < this->knots.size(); ++i, ++k) 
    155   { 
    156     assert(this->knots[i] <= this->knots[k]); 
    157   } 
    158   this->bezier_control_point_cache.clear(); 
     160  return this->knots; 
     161} 
     162 
     163//---------------------------------------------------------------------- 
     164// tBSplineCurve BezierControlPoints 
     165//---------------------------------------------------------------------- 
     166template<size_t Tdimension, typename TElement, unsigned int Tdegree> 
     167const std::vector<typename tShape<Tdimension, TElement>::tPoint> &tBSplineCurve<Tdimension, TElement, Tdegree>::BezierControlPoints() const 
     168{ 
     169  if (!this->bezier_control_points.empty()) 
     170  { 
     171    return this->bezier_control_points; 
     172  } 
     173 
     174  for (std::size_t i = 1; i < this->Knots().size(); ++i) 
     175  { 
     176    assert(this->Knots()[i - 1] <= this->Knots()[i]); 
     177  } 
     178 
    159179  std::vector<typename tSplineCurve::tParameter> new_knots; 
    160   new_knots.reserve(this->knots.size() * Tdegree); 
    161   std::copy(this->knots.begin(), this->knots.end(), std::back_inserter(new_knots)); 
    162   std::copy(this->ControlPoints().begin(), this->ControlPoints().end(), std::back_inserter(this->bezier_control_point_cache)); 
     180  new_knots.reserve(this->Knots().size() * Tdegree); 
     181  std::copy(this->Knots().begin(), this->Knots().end(), std::back_inserter(new_knots)); 
     182  std::copy(this->ControlPoints().begin(), this->ControlPoints().end(), std::back_inserter(this->bezier_control_points)); 
     183  while (this->bezier_control_points.size() < Tdegree + 1) 
     184  { 
     185    this->bezier_control_points.push_back(this->bezier_control_points.back()); 
     186  } 
    163187 
    164188  typename tSplineCurve::tParameter knot = new_knots[0]; 
     
    177201        for (unsigned int s = multiplicity; s < Tdegree; s++) 
    178202        { 
    179           this->bezier_control_point_cache = InsertKnot((it - new_knots.begin()) - multiplicity, new_knots, knot, this->bezier_control_point_cache); 
     203          this->bezier_control_points = InsertKnot((it - new_knots.begin()) - multiplicity, new_knots, knot, this->bezier_control_points); 
    180204          new_knots.insert(it, knot); 
    181205        } 
     
    189213    } 
    190214  } 
    191 } 
    192  
     215  return this->bezier_control_points; 
     216} 
     217 
     218//---------------------------------------------------------------------- 
     219// tBSplineCurve InsertKnot 
     220//---------------------------------------------------------------------- 
    193221template<size_t Tdimension, typename TElement, unsigned int Tdegree> 
    194222std::vector<typename tBSplineCurve<Tdimension, TElement, Tdegree>::tShape::tPoint> tBSplineCurve<Tdimension, TElement, Tdegree>::InsertKnot(int at, const std::vector<typename tSplineCurve::tParameter> &knots_before_insertion, typename tSplineCurve::tParameter knot, const std::vector<typename tShape::tPoint> &control_points) 
     
    220248{ 
    221249  t /= this->NumberOfSegments() + this->knots.front() * (this->knots.back() - this->knots.front()); 
    222   assert((this->knots.front() <= t) && (t <= this->knots.back())); 
     250  assert((this->Knots().front() <= t) && (t <= this->Knots().back())); 
    223251  assert(this->NumberOfSegments() > 0); 
    224252  unsigned int segment = 0; 
    225   for (size_t i = 0; i < this->knots.size() - 1; ++i) 
    226   { 
    227     if (this->knots[i] != this->knots[i + 1]) 
    228     { 
    229       if (this->knots[i + 1] > t) 
     253  for (size_t i = 0; i < this->Knots().size() - 1; ++i) 
     254  { 
     255    if (this->Knots()[i] != this->Knots()[i + 1]) 
     256    { 
     257      if (this->Knots()[i + 1] > t) 
    230258      { 
    231259        return segment; 
     
    234262    } 
    235263  } 
    236   assert(t == this->knots.back()); 
     264  assert(t == this->Knots().back()); 
    237265  return this->NumberOfSegments() - 1; 
    238266} 
     
    245273{ 
    246274  t /= this->NumberOfSegments() + this->knots.front() * (this->knots.back() - this->knots.front()); 
    247   assert((this->knots.front() <= t) && (t <= this->knots.back())); 
     275  assert((this->Knots().front() <= t) && (t <= this->Knots().back())); 
    248276  assert(this->NumberOfSegments() > 0); 
    249277  unsigned int segment = 0; 
    250   for (size_t i = 0; i < this->knots.size() - 1; ++i) 
    251   { 
    252     if (this->knots[i] != this->knots[i + 1]) 
    253     { 
    254       if (this->knots[i + 1] > t) 
    255       { 
    256         return (t - this->knots[i]) / (this->knots[i + 1] - this->knots[i]); 
     278  for (size_t i = 0; i < this->Knots().size() - 1; ++i) 
     279  { 
     280    if (this->Knots()[i] != this->Knots()[i + 1]) 
     281    { 
     282      if (this->Knots()[i + 1] > t) 
     283      { 
     284        return (t - this->Knots()[i]) / (this->Knots()[i + 1] - this->Knots()[i]); 
    257285      } 
    258286      segment++; 
    259287    } 
    260288  } 
    261   assert(t == this->knots.back()); 
     289  assert(t == this->Knots().back()); 
    262290  return 1; 
    263291} 
     
    269297std::shared_ptr<const typename tSplineCurve<Tdimension, TElement, Tdegree>::tBezierCurve> tBSplineCurve<Tdimension, TElement, Tdegree>::CreateBezierCurveForSegment(unsigned int i) const 
    270298{ 
    271   if (this->bezier_control_point_cache.empty()) 
    272   { 
    273     this->CalculateBezierControlPoints(); 
    274   } 
    275299  std::vector<typename tShape::tPoint> segment_control_points; 
    276   std::copy(this->bezier_control_point_cache.begin() + i * Tdegree, this->bezier_control_point_cache.begin() + i * Tdegree + Tdegree + 1, std::back_inserter(segment_control_points)); 
     300  std::copy(this->BezierControlPoints().begin() + i * Tdegree, this->BezierControlPoints().begin() + i * Tdegree + Tdegree + 1, std::back_inserter(segment_control_points)); 
    277301  return std::shared_ptr<const typename tSplineCurve::tBezierCurve>(new typename tSplineCurve::tBezierCurve(segment_control_points.begin(), segment_control_points.end())); 
    278302} 
  • curves/tSplineCurve.hpp

    r69 r96  
    6767//---------------------------------------------------------------------- 
    6868template <size_t Tdimension, typename TElement, unsigned int Tdegree> 
    69 tSplineCurve<Tdimension, TElement, Tdegree>::tSplineCurve() : 
    70   control_points(Tdegree + 1, tShape::tPoint::Zero()) 
     69tSplineCurve<Tdimension, TElement, Tdegree>::tSplineCurve() 
    7170{ 
    7271  static_assert(Tdegree > 0, "The degree of spline curves must be greater than zero"); 
    73   assert(control_points.size() > Tdegree && "A spline curve needs at least degree + 1 control points"); 
    7472} 
    7573 
     
    8078  static_assert(Tdegree > 0, "The degree of spline curves must be greater than zero"); 
    8179  std::copy(begin, end, std::back_inserter(this->control_points)); 
    82   assert(control_points.size() > Tdegree && "A spline curve needs at least degree + 1 control points"); 
    8380} 
    8481 
     
    8885{ 
    8986  static_assert(Tdegree > 0, "The degree of spline curves must be greater than zero"); 
    90   static_assert(sizeof...(rest) + 2 > Tdegree, "A spline curve needs at least degree + 1 control points"); 
    9187  util::ProcessVariadicValues([this](const typename tShape::tPoint & x) 
    9288  { 
     
    9490  }, 
    9591  p1, p2, rest...); 
     92  while (this.control_points.size() <= Tdegree) 
     93  { 
     94    this->control_points.push_back(this->control_points.back()); 
     95  } 
    9696} 
    9797 
     
    155155const typename tShape<Tdimension, TElement>::tPoint tSplineCurve<Tdimension, TElement, Tdegree>::operator()(tParameter t) const 
    156156{ 
     157  if (this->NumberOfSegments() == 0) 
     158  { 
     159    throw std::runtime_error("Cannot evaluate an empty spline!"); 
     160  } 
    157161  assert((0 <= t) && (t <= this->NumberOfSegments())); 
    158162  std::shared_ptr<const tBezierCurve> bezier_curve = this->GetBezierCurveForParameter(t, t); 
Note: See TracChangeset for help on using the changeset viewer.