G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsKnotVector.hpp
Go to the documentation of this file.
1 
14 #pragma once
15 
16 #include <gsIO/gsBase64.h>
17 #include <gsIO/gsXml.h>
18 #include <gsNurbs/gsKnotVector.h>
19 
20 namespace gismo
21 {
22 
23 namespace internal
24 {
25 
29 template<class T>
30 class gsXml< gsKnotVector<T> >
31 {
32 private:
33  gsXml() { }
34 
35 public:
36  GSXML_COMMON_FUNCTIONS(gsKnotVector<T>)
37  GSXML_GET_POINTER(gsKnotVector<T>)
38  static std::string tag () { return "KnotVector"; }
39  static std::string type() { return ""; }
40 
41  static void get_into(gsXmlNode * node, gsKnotVector<T> & result)
42  {
43  // TODO: make it unused when possible.
44  int p = atoi(node->first_attribute("degree")->value() );
45 
46  typename gsKnotVector<T>::knotContainer knotValues;
47 
48  gsXmlAttribute * mode = node->first_attribute("mode");
49 
50  // Generate Knotvectors based on key
51  // mode: uniform, graded, ..
52  if (mode)
53  {
54  if ( !strcmp( mode->value(),"uniform") )
55  {
56  gsXmlAttribute * szc = node->first_attribute("csize");
57  GISMO_ENSURE(szc, "size of knot-vector coefficients is missing (csize attribute).");
58  index_t sz = atoi(szc->value());
59 
60  //gsXmlAttribute * mlt = node->first_attribute("mult");
61  //if mlt
62 
63  result = gsKnotVector<T>(0.0, 1.0, sz-p-1, p+1, 1, p);
64  return;
65  }
66  }
67 
68  // Read knots from list
69  gsXmlAttribute* format = node->first_attribute("format");
70  std::string format_flag = format ? format->value() : "ascii";
71  std::transform(format_flag.cbegin(), format_flag.cend(),
72  format_flag.begin(),
73  [](unsigned char c) { return std::tolower(c); });
74 
75  if (format_flag == "ascii") {
76  // Case: mode: none/default
77  std::istringstream str;
78  str.str(node->value());
79  for (T knot; gsGetReal(str, knot);) knotValues.push_back(knot);
80  } else {
81  Base64::DecodeIntoGsType(node->value(), format_flag, knotValues);
82  }
83  result = gsKnotVector<T>(give(knotValues), p);
84  }
85 
86  static gsXmlNode * put (const gsKnotVector<T> & obj, gsXmlTree & data)
87  {
88  // Write the knot values (for now WITH multiplicities)
89  std::ostringstream str;
90  str << std::setprecision(REAL_DIG+1);
91 
92  for ( typename gsKnotVector<T>::iterator it = obj.begin();
93  it != obj.end(); ++it )
94  {
95  str << *it <<" ";
96  }
97 
98  // Make a new XML KnotVector node
99  gsXmlNode * tmp = internal::makeNode("KnotVector", str.str(), data);
100  // Append the degree attribure
101  str.str(std::string());// clean the ostream
102  str<< obj.m_deg;
103  tmp->append_attribute( makeAttribute("degree", str.str(),data) );
104 
105  return tmp;
106  }
107 };
108 
109 }// namespace internal
110 
111 
112 //===============//
113 // iterator ends //
114 //===============//
115 
116 template<typename T>
118 {
119  return m_repKnots.begin();
120  //return m_repKnots.data();
121 }
122 
123 template<typename T>
125 {
126  return m_repKnots.end();
127  //return m_repKnots.data() + m_repKnots.size();
128 }
129 
130 template<typename T>
132 {
133  upos += numLeftGhosts();
134  return m_repKnots.begin() + (0 == upos ? 0 : m_multSum[upos-1]);
135  //return m_repKnots.data() + (0 == upos ? 0 : m_multSum[upos-1]);
136 }
137 
138 template<typename T>
140 {
141  upos += numLeftGhosts();
142  return m_repKnots.begin() + m_multSum[upos];
143  //return m_repKnots.data() + m_multSum[upos];
144 }
145 
146 template<typename T>
147 typename gsKnotVector<T>::reverse_iterator gsKnotVector<T>::rbegin() const
148 {
149  return std::reverse_iterator<iterator>(end());
150 }
151 
152 template<typename T>
154 {
155  return std::includes(begin(), end(), other.begin(), other.end() );
156 }
157 
158 template<typename T>
160  std::vector<T>& result) const
161 {
162  result.clear();
163  const int sz = other.size() - size();
164  result.reserve( std::abs(sz) );
165 
166  std::set_difference(begin(), end(),
167  other.begin(), other.end(),
168  std::back_inserter(result));
169 }
170 
171 template<typename T>
173  std::vector<T>& result) const
174 {
175  result.clear();
176  // Next line is ambiguous on MSVC (std does not overload "abs" for size_t)
177  // result.reserve(std::abs(other.size()-size()));
178  const int sz = other.size() - size();
179  result.reserve( std::abs(sz) );
180 
181  std::set_symmetric_difference(begin(), end(),
182  other.begin(), other.end(),
183  std::back_inserter(result));
184 }
185 
186 template<typename T>
188 {
189  const gsKnotVector<T> & a = *this;
190  knotContainer kv;
191  kv.reserve( (std::max)(a.size(),b.size()) );
192  std::set_union(a.m_repKnots.begin(), a.m_repKnots.end(),
193  b.m_repKnots.begin(), b.m_repKnots.end(), std::back_inserter(kv) );
194 
195  // const T newStart = math::min(*a.domainBegin(), *b.domainBegin() );
196  // const T newEnd = math::max(*a.domainEnd() , *b.domainEnd() );
197  return gsKnotVector<T>( give(kv), (std::max)(a.m_deg, b.m_deg) );
198 }
199 
200 template<typename T>
202 {
203  const gsKnotVector<T> & a = *this;
204  knotContainer kv;
205  kv.reserve( (std::min)(a.size(),b.size()) );
206  std::set_intersection(a.m_repKnots.begin(), a.m_repKnots.end(),
207  b.m_repKnots.begin(), b.m_repKnots.begin(), std::back_inserter(kv) );
208  return gsKnotVector<T>( give(kv), (std::min)(a.m_deg, b.m_deg) );
209 }
210 
211 /*
212 // trim to the minimal domain such that \a dbegin and \a dend are contained
213 template<typename T>
214 const gsKnotVector<T> & gsKnotVector<T>::trimDomain(const T dbegin, const T dend) const
215 {
216  iterator lpos = std::upper_bound(begin(), end(), dbegin) - 1; // *lpos<=dbegin
217  iterator rpos = std::lower_bound(begin(), end(), dend) ; // *rpos>=dend
218  diffptr_t l = lpos - begin() - m_deg ;
219  diffptr_t r = end() - rpos - m_deg - 1;
220  gsDebugVar(l);
221  gsDebugVar(r);
222 
223  return *this;
224 }
225 */
226 
227 
228 template<typename T>
229 typename gsKnotVector<T>::reverse_iterator gsKnotVector<T>::rend() const
230 {
231  return std::reverse_iterator<iterator>(begin());
232 }
233 
234 template<typename T>
236 {
237  return uiterator(*this,0,numLeftGhosts());
238 }
239 
240 template<typename T>
242 {
243  return uiterator::End(*this);
244 }
245 
246 template<typename T>
247 typename gsKnotVector<T>::reverse_uiterator gsKnotVector<T>::urbegin() const
248 {
249  return reverse_uiterator(uend());
250 }
251 
252 template<typename T>
253 typename gsKnotVector<T>::reverse_uiterator gsKnotVector<T>::urend() const
254 {
255  return reverse_uiterator(ubegin());
256 }
257 
258 template<typename T>
260 {
261  return smart_iterator(*this,0,numLeftGhosts());
262 }
263 
264 template<typename T>
266 {
267  return smart_iterator::End(*this);
268 }
269 
270 template<typename T>
271 typename gsKnotVector<T>::reverse_smart_iterator gsKnotVector<T>::rsbegin() const
272 {
273  return reverse_smart_iterator(send());
274 }
275 
276 template<typename T>
277 typename gsKnotVector<T>::reverse_smart_iterator gsKnotVector<T>::rsend() const
278 {
279  return reverse_smart_iterator(sbegin());
280 }
281 
282 
283 //==============//
284 // constructors //
285 //==============//
286 
287 
288 template<typename T>
289 gsKnotVector<T>::gsKnotVector( knotContainer knots, short_t degree)
290 {
291  knots.swap(m_repKnots);
292  rebuildMultSum();
293 
294  m_deg = (degree == - 1 ? deduceDegree() : degree);
295 
296  GISMO_ASSERT( check(), "Unsorted knots or invalid multiplicities." );
297 }
298 
299 
300 
301 template<typename T>
303 {
304  m_repKnots.swap( other.m_repKnots );
305  m_multSum.swap( other.m_multSum );
306  std::swap( m_deg, other.m_deg );
307 
308  GISMO_ASSERT(check(), "Unsorted knots or invalid multiplicities.");
309 }
310 
311 template<typename T>
313 {
314  return new gsKnotVector(*this);
315 }
316 
317 //========================//
318 // inserting and removing //
319 //========================//
320 
321 // TODO: Possibly insert(uniqIter) alias multiplicity increase.
322 // Then refactor this insert to use it.
323 // Maybe not worth the effort.
324 template<typename T>
325 void gsKnotVector<T>::insert( T knot, mult_t mult )
326 {
327  //size_t numKnots = size()+mult;
328  // GISMO_ENSURE( numKnots < std::numeric_limits<mult_t>::max(),
329  // "Too many knots." );
330 
331  uiterator uit = std::lower_bound(ubegin(), uend(), knot);
332  const mult_t fa = uit.firstAppearance();
333 
334  // update multiplicity sums
335  nonConstMultIterator upos = m_multSum.begin() + uit.uCardinalIndex();
336  if (upos==m_multSum.end() || *uit != knot) // knot value does not exist ?
337  upos = m_multSum.insert(upos, fa );
338  std::transform(upos, m_multSum.end(), upos, GS_BIND1ST(std::plus<mult_t>(), mult));
339 
340  // insert repeated knots
341  m_repKnots.insert(m_repKnots.begin() + fa, mult, knot);
342 
343  GISMO_ASSERT( check(), "Unsorted knots or invalid multiplicities." );
344 }
345 
346 template<typename T>
347 void gsKnotVector<T>::remove( uiterator uit, mult_t mult )
348 {
349  GISMO_ASSERT( uit.m_mlt == multSumData(),
350  "The iterator is invalid for this knot vector." );
351 
352  mult_t knotMult = uit.multiplicity();
353  mult_t toRemove = (std::min<mult_t>)(mult, knotMult);
354  nonConstMultIterator upos = m_multSum.begin() + uit.uCardinalIndex();
355 
356  nonConstIterator pos = m_repKnots.begin() + uit.firstAppearance();
357  m_repKnots.erase(pos, pos+toRemove);
358 
359  if( toRemove == knotMult )
360  upos = m_multSum.erase( upos );
361 
362  std::transform(upos, m_multSum.end(), upos, GS_BIND2ND(std::minus<mult_t>(),toRemove));
363 }
364 
365 template<typename T>
366 void gsKnotVector<T>::remove( const T knot, mult_t mult )
367 {
368  uiterator uit = std::lower_bound( ubegin(), uend(), knot );
369  if( uit != uend() && *uit == knot ) // value found ?
370  remove( uit, mult );
371  // Otherwise the knot is not present and we cannot remove it.
372 }
373 
374 
375 template<typename T>
376 void gsKnotVector<T>::erase(const mult_t first, const mult_t last)
377 {
378  m_repKnots.erase(m_repKnots.begin()+first, m_repKnots.begin()+last);
379  nonConstMultIterator fpos =
380  std::lower_bound(m_multSum.begin(), m_multSum.end(), first);
381  nonConstMultIterator lpos =
382  std::upper_bound(m_multSum.begin(), m_multSum.end(), last);
383  const mult_t numKnots = last - first;
384  *fpos = m_multSum.back() - numKnots;
385  lpos = m_multSum.erase(fpos + 1, lpos);
386  std::transform(lpos, m_multSum.end(), lpos, GS_BIND2ND(std::minus<mult_t>(),numKnots));
387 }
388 
389 template<typename T>
390 void gsKnotVector<T>::trimLeft(const mult_t numKnots)
391 {
392  // equiv:
393  //erase(0, numKnots);
394  //return;
395  m_repKnots.erase(m_repKnots.begin(), m_repKnots.begin()+numKnots);
396  nonConstMultIterator upos =
397  std::upper_bound(m_multSum.begin(), m_multSum.end(), numKnots);
398  upos = m_multSum.erase(m_multSum.begin(), upos);
399  std::transform(upos, m_multSum.end(), upos, GS_BIND2ND(std::minus<mult_t>(),numKnots));
400 }
401 
402 template<typename T>
403 void gsKnotVector<T>::trimRight(const mult_t numKnots)
404 {
405  // equiv:
406  //erase(m_multSum.back()-numKnots, m_multSum.back());
407  //return;
408  m_repKnots.resize(m_repKnots.size()-numKnots);
409  const mult_t newSum = m_multSum.back()-numKnots;
410  nonConstMultIterator upos =
411  std::lower_bound(m_multSum.begin(), m_multSum.end(), newSum) + 1;
412  m_multSum.erase(upos, m_multSum.end() );
413  m_multSum.back() = newSum;
414 }
415 
416 //================//
417 // multiplicities //
418 //================//
419 
420 template<typename T>
421 typename gsKnotVector<T>::mult_t gsKnotVector<T>::multiplicity( T u ) const
422 {
423  uiterator uit = std::lower_bound( ubegin(), uend(), u );
424  if( uit != uend() && *uit == u ) // value found ?
425  return uit.multiplicity();
426  return 0;
427 }
428 
429 template<typename T>
430 typename gsKnotVector<T>::mult_t gsKnotVector<T>::multiplicityIndex( mult_t knotIndex ) const
431 {
432  GISMO_ASSERT( knotIndex>=0 && static_cast<size_t>(knotIndex)<m_repKnots.size(),
433  "knotIndex " << knotIndex << "out of bounds [0,"
434  << m_repKnots.size() << ")." );
435 
436  iterator it = begin() + knotIndex;
437  iterator L = std::find_if(it,end(),GS_BIND1ST(std::not_equal_to<T>(),*it));
438  reverse_iterator F = std::find_if(reverse_iterator(it),rend(),
439  GS_BIND1ST(std::not_equal_to<T>(),*it));
440  return L-F.base();
441  // equivalent:
442  //return (sbegin() + knotIndex).multiplicity();
443 }
444 
445 //===========//
446 // modifiers //
447 //===========//
448 
449 template<typename T>
450 void gsKnotVector<T>::affineTransformTo(T newBeg, T newEnd)
451 {
452  GISMO_ASSERT(newEnd > newBeg+0.00001,
453  "Cannot transform the knot-vector to invalid interval ["<<newBeg<<","<<newEnd<<"].\n");
454 
455  const T beg = m_repKnots.front();
456  const T rr = (newEnd - newBeg) / (m_repKnots.back() - beg);
457  uiterator uit = ubegin();
458  uit.setValue(newBeg);
459  ++uit;
460  for (; uit != uend()-1; ++uit)
461  uit.setValue(newBeg + (*uit - beg) * rr);
462  uit.setValue(newEnd);
463 
464  GISMO_ASSERT( check(), "affineTransformTo() has produced an invalid knot vector.");
465 }
466 
467 template<typename T>
469 {
470  // Not implemented using affineTransformTo() because of efficiency
471  // and also to prevent accidental reversing.
472 
473  // reverse the multiplicity
474  std::reverse (m_multSum.begin(), m_multSum.end()-1);
475  std::transform(m_multSum.begin(), m_multSum.end()-1, m_multSum.begin(),
476  GS_BIND1ST(std::minus<mult_t>(), m_multSum.back() ) );
477 
478  // reverse the knots
479  std::reverse(m_repKnots.begin(), m_repKnots.end());
480  const T ab = m_repKnots.back() + m_repKnots.front();
481  for (uiterator uit = ubegin(); uit != uend(); ++uit)
482  uit.setValue( ab - uit.value() );
483 
484  GISMO_ASSERT( check(), "reverse() produced an invalid knot vector.");
485 }
486 
487 
488 //===============//
489 // miscellaneous //
490 //===============//
491 
492 template <typename T>
493 std::ostream & gsKnotVector<T>::print(std::ostream &os) const
494 {
495  os << "[ " ;
496  if ( size() > static_cast<size_t>(2*m_deg+8) )
497  {
498  for (iterator itr = begin(); itr != begin()+m_deg+3; ++itr)
499  os << *itr << " ";
500  os << "... ";
501  for (iterator itr = end()-m_deg-3; itr != end(); ++itr)
502  os << *itr << " ";
503  }
504  else
505  {
506  for (iterator itr = begin(); itr != end(); ++itr)
507  os << *itr << " ";
508  }
509  os << "] (deg=" << degree()
510  << ", size=" << size()
511  << ", minSpan=" << minIntervalLength()
512  << ", maxSpan=" << maxIntervalLength()
513  << ")";
514  return os;
515 }
516 
517 template <class T>
519 {
520  T hmax = 0.0;
521  for (uiterator it = ubegin(); it + 1 < uend(); ++it)
522  hmax = math::max(hmax, *(it+1) - *it );
523  return hmax;
524 }
525 
526 template <class T>
528 {
529  T hmin = std::numeric_limits<T>::max();
530  for (uiterator it = ubegin(); it + 1 < uend(); ++it)
531  hmin = math::min(hmin, *(it+1) - *it );
532  return hmin;
533 }
534 
535 template<typename T>
537 {
538  return isConsistent(m_repKnots,m_multSum);
539 }
540 
541 template<typename T>
542 bool gsKnotVector<T>::isConsistent( const knotContainer & repKnots,
543  const multContainer & multSum )
544 {
545  // check size
546  if (repKnots.size()==0)
547  {
548  if(multSum.size()==0)
549  return true;
550  else
551  return false;
552  }
553  if (repKnots.size()!= static_cast<size_t>(multSum.back()) )
554  return false;
555  // check order and multiplicities
556  T prev = repKnots.front();
557  mult_t uniqPos = 0;
558  for( typename knotContainer::const_iterator kit = repKnots.begin();
559  kit != repKnots.end();
560  ++kit )
561  {
562  if( *kit < prev ) // m_repKnots is locally decreasing.
563  return false;
564  else if( *kit > prev )
565  {
566  if( multSum[uniqPos] != static_cast<mult_t>(kit - repKnots.begin()) )
567  return false;
568  ++uniqPos;
569  prev = *kit;
570  }
571  }
572  return true;
573 }
574 
575 template<typename T>
577 {
578  m_multSum.clear();
579 
580  iterator bb=begin();
581  iterator it=begin();
582  iterator ee=end();
583 
584  while(it!=ee)
585  {
586  it = std::find_if(it,ee,GS_BIND1ST(std::not_equal_to<T>(),*it));
587  m_multSum.push_back(it-bb);
588  }
589 }
590 
591 template<typename T>
593  T last,
594  unsigned interior,
595  mult_t mult_ends,
596  mult_t mult_interior,
597  short_t degree)
598 {
599  initUniform( first, last, interior, mult_ends, mult_interior, degree );
600 }
601 
602 template<typename T>
603 gsKnotVector<T>::gsKnotVector( const knotContainer& uKnots,
604  int degree,
605  int regularity )
606 {
607  // The code is very similar to that of the constructor with first, last, ints, mult, mult.
608  GISMO_ASSERT( uKnots.front() < uKnots.back(),
609  "The first element in uknots has to be smaller than the last one." );
610 
611  mult_t mult_ends = degree + 1;
612  mult_t mult_interior = degree - regularity;
613 
614  m_repKnots.clear();
615  const size_t nKnots = uKnots.size() * mult_interior + 2 * (mult_ends-mult_interior);
616  //GISMO_ENSURE( nKnots < std::numeric_limits<mult_t>::max(),
617  // "Knot vector too big." );
618  m_repKnots.reserve( nKnots );
619  m_multSum.clear();
620  m_multSum.reserve( uKnots.size() );
621 
622  m_repKnots.insert( m_repKnots.end(), mult_ends, uKnots.front() );
623  m_multSum.push_back( mult_ends );
624 
625  // We iterate from the one past begin() to one before end().
626  typename knotContainer::const_iterator it = uKnots.begin();
627  for( it += 1; it != uKnots.end() - 1; ++it)
628  {
629  m_repKnots.insert( m_repKnots.end(), mult_interior, *it );
630  m_multSum.push_back( mult_interior + m_multSum.back() );
631  }
632 
633  m_repKnots.insert( m_repKnots.end(), mult_ends, uKnots.back() );
634  m_multSum.push_back( mult_ends + m_multSum.back() );
635 
636  //GISMO_ASSERT( check(), "Unsorted knots or invalid multiplicities." );
637 
638  // TODO remove
639  m_deg = (degree == - 1 ? deduceDegree() : degree);
640 }
641 
642 template <typename T>
644  T last,
645  unsigned interior,
646  unsigned mult_ends,
647  unsigned mult_interior,
648  short_t degree)
649 {
650  m_deg = (degree == - 1 ? mult_ends-1 : degree);
651 
652  const size_t nKnots = 2 * mult_ends + interior*mult_interior;
653  // GISMO_ENSURE( nKnots < std::numeric_limits<mult_t>::max(),
654  // "Knot vector too big." );
655  GISMO_ASSERT( first<last, //&& mult_ends<m_deg+2 && mult_interior<deg+2,
656  "The variable first has to be smaller than the variable last." );
657 
658  m_repKnots.clear();
659  m_repKnots.reserve( nKnots );
660  m_multSum .clear();
661  m_multSum .reserve(interior+2);
662 
663  const T h = (last-first) / (T)(interior+1);
664 
665  for(unsigned i = m_deg - mult_ends + 1, j=1; i!= 0; --i, ++j)
666  { // add left ghost knots
667  m_repKnots.push_back(first-(T)(i)*h);
668  m_multSum .push_back(j);
669  }
670 
671  m_repKnots.insert(m_repKnots.end(), mult_ends, first);
672  m_multSum .push_back(mult_ends + (m_multSum.empty() ? 0 : m_multSum.back()));
673 
674  for( unsigned i=1; i<=interior; ++i)
675  {
676  m_repKnots.insert( m_repKnots.end(), mult_interior, first + (T)(i)*h );
677  m_multSum .push_back( mult_interior + m_multSum.back() );
678  }
679 
680  m_repKnots.insert( m_repKnots.end(), mult_ends, last );
681  m_multSum .push_back( mult_ends + m_multSum.back() );
682 
683  for(unsigned i = 1; i!=m_deg - mult_ends + 2; ++i)
684  { // add right ghost knots
685  m_repKnots.push_back(last+(T)(i)*h);
686  m_multSum .push_back(m_multSum.back() + 1);
687  }
688 
689  GISMO_ASSERT( check(), "Unsorted knots or invalid multiplicities." );
690 }
691 
692 template<typename T>
693 void gsKnotVector<T>::initClamped(int degree, unsigned numKnots, unsigned mult_interior)
694 {
695  GISMO_ASSERT( numKnots > 1 , "Not enough knots.");
696  initUniform(0.0, 1.0, numKnots - 2, degree + 1, mult_interior, degree );
697 }
698 
699 template<typename T>
701 {
702  return m_deg;
703 }
704 
705 template<typename T>
707 {
708  return uSize() == 0 ? -1 :
709  (std::max)(( ubegin() ).multiplicity(),
710  ( uend()-1 ).multiplicity()) - 1;
711 }
712 
713 template<typename T>
714 typename gsKnotVector<T>::multContainer gsKnotVector<T>::multiplicities() const
715 {
716  multContainer result;
717  result.reserve(uSize());
718  for( uiterator uit = ubegin(); uit != uend(); ++uit )
719  result.push_back( uit.multiplicity() );
720  return result;
721 }
722 
723 template<typename T>
724 typename gsKnotVector<T>::mult_t gsKnotVector<T>::maxInteriorMultiplicity() const
725 {
726  mult_t result = 0;
727  for( uiterator uit = std::next(ubegin()); uit != std::prev(uend()); ++uit )
728  result = std::max(result,uit.multiplicity());
729  return result;
730 }
731 
732 template<typename T>
733 typename gsKnotVector<T>::mult_t gsKnotVector<T>::minInteriorMultiplicity() const
734 {
735  // No interior knots
736  if (uSize()==2)
737  return 0;
738 
739  mult_t result = m_deg+2;
740  for( uiterator uit = std::next(ubegin()); uit != std::prev(uend()); ++uit )
741  result = std::min(result,uit.multiplicity());
742  return result;
743 }
744 
745 template<typename T>
747 gsKnotVector<T>::uFind( const T u ) const
748 {
749  GISMO_ASSERT(size()>1,"Not enough knots."); // todo: check() --> size() > 2*m_deg+1
750  GISMO_ASSERT(inDomain(u), "Point "<< u <<" outside active area of the knot vector");
751 
752  // The last element is closed from both sides.
753  uiterator dend = domainUEnd();
754 
755  if (u==*dend) // knot at domain end ?
756  return --dend;
757  else
758  return std::upper_bound( domainUBegin(), dend, u ) - 1;
759 }
760 
761 template<typename T>
764 {
765  GISMO_ASSERT(inDomain(u), "Point outside active area of the knot vector");
766  return std::upper_bound( ubegin(), uend(), u );
767 }
768 
769 template<typename T>
772 {
773  GISMO_ASSERT(inDomain(u), "Point outside active area of the knot vector");
774  return std::lower_bound( ubegin(), uend(), u );
775 }
776 
777 template<typename T>
779 gsKnotVector<T>::iFind( const T u ) const
780 {
781  // GISMO_ASSERT done in uFind().
782  return begin() + uFind(u).lastAppearance();
783 
784  // equivalent
785  /*GISMO_ASSERT(inDomain(u), "Point outside active area of the knot vector");
786  iterator dend = domainEnd();
787  if ( u == *dend )
788  return --dend;
789  else
790  return std::upper_bound( domainBegin(), dend, u) - 1; */
791 }
792 
793 template<typename T>
794 void gsKnotVector<T>::refineSpans( const multContainer & spanIndices, mult_t knotsPerSpan )
795 {
796  refineSpans(spanIndices.begin(), spanIndices.end(), knotsPerSpan);
797 }
798 
799 template <typename T>
800 std::string gsKnotVector<T>::detail() const
801 {
802  std::stringstream osk, osm;
803  osk << "[ " ;
804  osm << "( " ;
805  for (uiterator itr = ubegin(); itr != uend(); ++itr)
806  {
807  osk << itr.value() << " ";
808  osm << itr.multiplicity() << " ";
809  }
810  osm <<")\n";
811  osk << "] ~ ";
812  osm << "deg="<<m_deg<< ", size="<<size() << ", uSize="<< uSize()
813  <<", minSpan="<< minIntervalLength()
814  <<", maxSpan="<< maxIntervalLength() <<"\n";
815 
816  return osk.str() + osm.str();
817 }
818 
819 template<typename T>
820 void gsKnotVector<T>::uniformRefine( mult_t numKnots, mult_t mult )
821 {
822  //GISMO_ASSERT( numKnots>=0, "Expecting non-negative number");
823  if( numKnots <= 0 ) return;
824 
825  const mult_t l = ( domainUBegin() - ubegin() ) * numKnots * mult;
826  const mult_t r = (uend() - domainUEnd() - 1 ) * numKnots * mult;
827 
828  knotContainer newKnots;
829  getUniformRefinementKnots(numKnots,newKnots,mult); // iterate instead of store ?
830  insert(newKnots.begin(),newKnots.end()); // complexity: newKnots.size() + size()
831 
832  if (0!=l) trimLeft (l);
833  if (0!=r) trimRight(r);
834 }
835 
836 
837 // TODO use affineTransformTo.
838 template<typename T>
840 {
841  // TODO add test
842  // With C++11, you can use:
843  // std::for_each( m_repKnots.begin(), m_repKnots.end(), [amount](T& k){ k+= amount;} );
844 
845  std::transform( m_repKnots.begin(), m_repKnots.end(), m_repKnots.begin(),
846  GS_BIND1ST(std::plus<T>(),amount) );
847 }
848 
849 template<typename T>
850 void gsKnotVector<T>::addConstant(T start, T amount)
851 {
852  typename std::vector<T>::iterator beg = m_repKnots.begin();
853  while (*beg < start)
854  beg++;
855 
856  // The last element is closed from both sides.
857  uiterator dend = domainUEnd();
858 
859  // If statement is needed because uFind gives back an iterator to the n-1 entry while the nth is required
860  if (start!=*dend)
861  {
862  uiterator uit = uFind(start);
863  for (; uit != uend(); ++uit)
864  uit.setValue(*uit + amount);
865  }
866  else
867  dend.setValue(*dend + amount);
868 
869 
870  GISMO_ASSERT( check(), "addConstant() has produced an invalid knot vector.");
871 }
872 
873 template<typename T>
875 {
876  GISMO_ASSERT( i>=0, "Expecting non-negative number");
877  size_t newSize = size() + i*(uSize()-2);
878  knotContainer tmp;
879  tmp.reserve(newSize);
880 
881  // fixme: should treat all boundary knots
882  tmp.insert(tmp.end(), m_multSum.front() + (boundary ? i : 0),
883  m_repKnots.front());
884 
885  // for all interior knots
886  uiterator uit = ubegin()+1;
887  for (; uit != uend()-1; ++uit)
888  tmp.insert(tmp.end(), i + uit.multiplicity(), *uit);
889 
890  // last knot
891  tmp.insert(tmp.end(), uit.multiplicity() + (boundary ? i : 0) , *uit);
892 
893  m_repKnots.swap(tmp);
894 
895  // update multiplicity sums
896  mult_t r = ( boundary ? 1 : 0 );
897  for (nonConstMultIterator m = m_multSum.begin(); m != m_multSum.end()-1; ++m)
898  *m += i * r++;
899  m_multSum.back() += i * (boundary ? r : r-1 );
900 }
901 
902 template<typename T>
904 {
905  GISMO_ASSERT( i>=0, "Expecting non-negative number");
906  knotContainer ktmp;
907  multContainer mtmp;
908  ktmp.reserve(size());
909  ktmp.reserve(uSize());
910 
911  // fixme: should treat all boundary knots
912  mult_t bm = boundary ? (std::max<mult_t>)(1,m_multSum.front()-i) : m_multSum.front();
913  mtmp.push_back(bm); // first knot
914  ktmp.insert(ktmp.end(), bm, m_repKnots.front());
915 
916  uiterator uit = ubegin() + 1;
917  for (; uit != uend()-1; ++uit) // for all interior knots
918  {
919  const mult_t m = uit.multiplicity() - i;
920  if ( m > 0 )
921  {
922  mtmp.push_back( m + mtmp.back() );
923  ktmp.insert(ktmp.end(), m, *uit);
924  }
925  }
926 
927  // last knot
928  bm = boundary ? (std::max<mult_t>)(1,uit.multiplicity()-i) : uit.multiplicity();
929  mtmp.push_back( bm + mtmp.back() );
930  ktmp.insert(ktmp.end(), bm, *uit);
931 
932  m_multSum .swap(mtmp);
933  m_repKnots.swap(ktmp);
934 }
935 
936 template<typename T>
938 {
939  increaseMultiplicity(i,true);
940  m_deg += i;
941 }
942 
943 template<typename T>
945 {
946  reduceMultiplicity(i,true);
947  m_deg -= i;
948 }
949 
950 template <typename T>
951 std::vector<T> gsKnotVector<T>::
952 coarsen(index_t knotRemove, index_t knotSkip, mult_t mul)
953 {
954  GISMO_ASSERT(knotRemove>=0 && knotSkip>0, "Invalid parameters to knot-coarsening.");
955 
956  // Special value -1
957  if (-1==mul) mul = m_deg+1;
958 
959  std::vector<T> coarseKnots, removedKnots;
960  if (0==knotRemove) return removedKnots;
961 
962  // knots to be removed
963  removedKnots.reserve( knotRemove * this->uSize() / (knotRemove+knotSkip) );
964 
965  uiterator it = domainUBegin() + 1;
966  uiterator last = domainUEnd();
967 
968  for(; it<last; it += knotSkip)
969  for(index_t c = 0; it!=last && c!=knotRemove; ++c, ++it)
970  removedKnots.insert(
971  removedKnots.end(),
972  (std::min<mult_t>)( mul, it.multiplicity() ),
973  it.value()
974  );
975 
976  // copy non-removed knots into coarseKnots
977  coarseKnots.reserve(m_repKnots.size()-removedKnots.size());
978  std::set_difference( m_repKnots.begin(), m_repKnots.end(),
979  removedKnots.begin(), removedKnots.end(),
980  std::back_inserter(coarseKnots) );
981 
982  coarseKnots.swap(m_repKnots);
983  rebuildMultSum();
984 
985  GISMO_ASSERT( check(), "Unsorted knots or invalid multiplicities." );
986 
987  return removedKnots;
988 }
989 
990 template<typename T>
992 {
993  iterator itr = begin() + 1;
994  result.resize(1, size()-m_deg-1 ) ;
995  unsigned i = 1;
996 
997  if ( m_deg!=0)
998  {
999  result(0,0) = std::accumulate( itr, itr+m_deg, (T)(0.0) ) / (T)(m_deg) ;
1000 
1001  if ( result(0,0) < *(itr-1) )// Ensure that the point is in range
1002  result(0,0) = *(itr-1);
1003 
1004  for (++itr; itr != end()-m_deg; ++itr, ++i )
1005  {
1006  result(0,i) = std::accumulate( itr, itr+m_deg, (T)(0.0) ) / (T)(m_deg) ;
1007  if ( result(0,i) == result(0,i-1) )
1008  {
1009  // perturbe point to remain inside the needed support
1010  result(0,i-1) -= (T)(1)/(T)(1000000000); // =mpq_class(1,1000000000);
1011  //to try: result(0,i-1) = math::nextafter(result(0,i-1), *result.data() );
1012  }
1013  }
1014 
1015  itr = end()-1;
1016  i -= 1;
1017  if ( result(0,i) > *(itr) )// Ensure that the point is in range
1018  result(0,i) = *(itr);
1019  }
1020  else
1021  copy_n(m_repKnots.data(), result.size(), result.data() );
1022 }
1023 
1024 template<typename T>
1026 {
1027  result.resize(1, numElements());
1028  index_t i = 0;
1029  for (uiterator it = domainUBegin(); it != domainUEnd(); ++it, ++i)
1030  result.at(i) = (*(it+1) + *it) / (T)(2);
1031 }
1032 
1033 template <class T>
1035 {
1036  // Copy pasted from gsKnotVector::greville(int).
1037  GISMO_ASSERT(i>=0 && static_cast<size_t>(i) < size()-m_deg-1,
1038  "Index of Greville point is out of range.");
1039  iterator itr = begin() + 1;
1040  return ( m_deg==0 ? *(itr+i-1) :
1041  std::accumulate( itr+i, itr+i+m_deg, (T)(0.0) ) / (T)(m_deg)
1042  // Special case C^{-1}
1043  - (*(itr+i) == *(itr+i+m_deg) ? 1e-10 : 0 )
1044  );
1045 }
1046 
1047 template <class T>
1048 void gsKnotVector<T>::getUniformRefinementKnots(mult_t knotsPerSpan, knotContainer& result, mult_t mult) const
1049 {
1050  // forward iterator ?
1051 
1052  result.clear();
1053  result.reserve( (uSize()-1) * knotsPerSpan * mult );
1054 
1055  T prev = m_repKnots.front();
1056  for( uiterator uit = ubegin()+1; uit != uend(); ++uit )
1057  {
1058  const T step = (*uit - prev)/(T)(knotsPerSpan+1);
1059  for( mult_t i = 1; i <= knotsPerSpan; ++ i)
1060  result.insert( result.end(), mult, prev + (T)(i)*step );
1061  prev=*uit;
1062  }
1063 }
1064 
1065 template< typename T>
1067  gsMatrix<index_t>& result) const
1068 {
1069  result.resize(1,2);
1070  smart_iterator it = sbegin() + i;
1071  result.at(0) = it.uIndex();
1072  it += m_deg+1;
1073  result.at(1) = it.uIndex();
1074 }
1075 
1076 } // namespace gismo
reverse_iterator rbegin() const
Returns reverse iterator pointing past the end of the repeated knots.
Definition: gsKnotVector.hpp:147
internal::gsUKnotIterator< T > uiterator
Definition: gsKnotVector.h:102
static bool isConsistent(const knotContainer &repKnots, const multContainer &multSums)
Sanity check.
Definition: gsKnotVector.hpp:542
gsKnotVector knotIntersection(const gsKnotVector &b) const
Computes the intersection of knot-vectors this and b.
Definition: gsKnotVector.hpp:201
Knot vector for B-splines.
multContainer multiplicities() const
Returns vector of multiplicities of the knots.
Definition: gsKnotVector.hpp:714
void affineTransformTo(T newBeg, T newEnd)
Definition: gsKnotVector.hpp:450
void refineSpans(iterType begin, iterType end, mult_t knotsPerSpan)
Inserts knotsPerSpan knots between each two knots between begin and end.
Definition: gsKnotVector.h:647
int deduceDegree() const
Definition: gsKnotVector.hpp:706
gsMatrix< T > greville() const
Definition: gsKnotVector.h:540
std::string detail() const
Return a string with detailed information on the knot vector.
Definition: gsKnotVector.hpp:800
void trimLeft(const mult_t numKnots)
Removes the left-most numKnots from the knot-vector.
Definition: gsKnotVector.hpp:390
smart_iterator sbegin() const
Returns the smart iterator pointing to the beginning of the repeated knots.
Definition: gsKnotVector.hpp:259
void initClamped(int degree, unsigned numKnots=2, unsigned mult_interior=1)
Definition: gsKnotVector.hpp:693
reverse_uiterator urbegin() const
Returns reverse unique iterator pointing past the end of the unique knots.
Definition: gsKnotVector.hpp:247
mult_t maxInteriorMultiplicity() const
Returns the maximum multiplicity in the interior.
Definition: gsKnotVector.hpp:724
#define short_t
Definition: gsConfig.h:35
reverse_uiterator urend() const
Returns reverse unique iterator pointing to the beginning of the unique knots.
Definition: gsKnotVector.hpp:253
void addConstant(T amount)
Adds amount to all the knots.
Definition: gsKnotVector.hpp:839
void trimRight(const mult_t numKnots)
Removes the right-most numKnots from the knot-vector.
Definition: gsKnotVector.hpp:403
void erase(const mult_t first, const mult_t last)
Removes the knots in the range [first,last)
Definition: gsKnotVector.hpp:376
reverse_smart_iterator rsend() const
Returns the reverse smart iterator pointing to the beginning of the repeated knots.
Definition: gsKnotVector.hpp:277
Struct that defines the boundary sides and corners and types of a geometric object.
Definition: gsBoundary.h:55
mult_t multiplicity(T u) const
Definition: gsKnotVector.hpp:421
void centers_into(gsMatrix< T > &result) const
Definition: gsKnotVector.hpp:1025
void supportIndex_into(const mult_t &i, gsMatrix< index_t > &result) const
Definition: gsKnotVector.hpp:1066
static void DecodeIntoGsType(const std::string &base64_string, const std::string &base_type_flag_, gsMatrix< ScalarType > &result)
Decode a string and copy into requested gismo Type.
Definition: gsBase64.h:355
S give(S &x)
Definition: gsMemory.h:266
size_t size() const
Number of knots (including repetitions).
Definition: gsKnotVector.h:242
#define index_t
Definition: gsConfig.h:32
#define GISMO_ENSURE(cond, message)
Definition: gsDebug.h:102
internal::gsKnotIterator< T > smart_iterator
Definition: gsKnotVector.h:107
std::vector< T >::const_iterator iterator
Definition: gsKnotVector.h:97
void greville_into(gsMatrix< T > &result) const
Definition: gsKnotVector.hpp:991
void insert(T knot, mult_t mult=1)
Inserts knot knot into the knot vector with multiplicity mult.
Definition: gsKnotVector.hpp:325
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
iterator iFind(const T u) const
Returns an iterator to the last occurrence of the knot at the beginning of the knot interval containi...
Definition: gsKnotVector.hpp:779
uiterator uFind(const T u) const
Returns the uiterator pointing to the knot at the beginning of the knot interval containing u...
Definition: gsKnotVector.hpp:747
void getUniformRefinementKnots(mult_t knotsPerSpan, knotContainer &result, mult_t mult=1) const
Definition: gsKnotVector.hpp:1048
T minIntervalLength() const
Returns the minimum interval length of the knot sequence.
Definition: gsKnotVector.hpp:527
gsKnotVector()
Empty constructor sets the degree to -1 and leaves the knots empty.
Definition: gsKnotVector.h:157
T at(index_t i) const
Returns the i-th element of the vectorization of the matrix.
Definition: gsMatrix.h:211
void degreeReduce(const short_t &i)
Converse to degreeElevate.
Definition: gsKnotVector.hpp:944
std::vector< T > coarsen(index_t knotRemove=1, index_t knotSkip=1, mult_t mul=-1)
Definition: gsKnotVector.hpp:952
mult_t minInteriorMultiplicity() const
Returns the minimum multiplicity in the interior.
Definition: gsKnotVector.hpp:733
std::ostream & print(std::ostream &os=gsInfo) const
Definition: gsKnotVector.hpp:493
void increaseMultiplicity(const mult_t i=1, bool boundary=false)
Definition: gsKnotVector.hpp:874
void uniformRefine(mult_t numKnots=1, mult_t mult=1)
Definition: gsKnotVector.hpp:820
uiterator ubegin() const
Returns unique iterator pointing to the beginning of the unique knots.
Definition: gsKnotVector.hpp:235
gsXmlAttribute * makeAttribute(const std::string &name, const std::string &value, gsXmlTree &data)
Helper to allocate XML attribute.
Definition: gsXml.cpp:37
uiterator uLowerBound(const T u) const
Returns a uiterator pointing to the first knot which does not compare less than u.
Definition: gsKnotVector.hpp:771
void copy_n(T begin, const size_t n, U *result)
Small wrapper for std::copy mimicking memcpy (or std::copy_n) for a raw pointer destination, copies n positions starting from begin into result. The latter is expected to have been allocated in advance.
Definition: gsMemory.h:368
void symDifference(const gsKnotVector< T > &other, std::vector< T > &result) const
Computes the symmetric difference between this knot-vector and other.
Definition: gsKnotVector.hpp:172
T maxIntervalLength() const
Returns the maximum interval length of the knot sequence.
Definition: gsKnotVector.hpp:518
bool check() const
Checks whether the knot vector is in a consistent state.
Definition: gsKnotVector.hpp:536
gsXmlNode * makeNode(const std::string &name, gsXmlTree &data)
Helper to allocate XML node.
Definition: gsXml.cpp:54
iterator beginAt(mult_t upos) const
Definition: gsKnotVector.hpp:131
void difference(const gsKnotVector< T > &other, std::vector< T > &result) const
Computes the difference between this knot-vector and other.
Definition: gsKnotVector.hpp:159
uiterator uUpperBound(const T u) const
Returns an iterator pointing to the first knot which compares greater than u.
Definition: gsKnotVector.hpp:763
void degreeElevate(const short_t &i=1)
Definition: gsKnotVector.hpp:937
uiterator uend() const
Returns unique iterator pointing past the end of the unique knots.
Definition: gsKnotVector.hpp:241
void reduceMultiplicity(const mult_t i=1, bool boundary=false)
Definition: gsKnotVector.hpp:903
void swap(gsKnotVector &other)
Swaps with other knot vector.
Definition: gsKnotVector.hpp:302
iterator end() const
Returns iterator pointing past the end of the repeated knots.
Definition: gsKnotVector.hpp:124
void reverse()
Better directly use affineTransformTo.
Definition: gsKnotVector.hpp:468
Class for representing a knot vector.
Definition: gsKnotVector.h:79
EIGEN_STRONG_INLINE abs_expr< E > abs(const E &u)
Absolute value.
Definition: gsExpressions.h:4486
mult_t multiplicityIndex(mult_t i) const
Definition: gsKnotVector.hpp:430
iterator begin() const
Returns iterator pointing to the beginning of the repeated knots.
Definition: gsKnotVector.hpp:117
void remove(uiterator uit, mult_t mult=1)
Definition: gsKnotVector.hpp:347
gsKnotVector * clone() const
Returns a pointer to a copy.
Definition: gsKnotVector.hpp:312
reverse_smart_iterator rsbegin() const
Returns the reverse smart iterator pointing past the end of the repeated knots.
Definition: gsKnotVector.hpp:271
smart_iterator send() const
Returns the smart iterator pointing past the end of the repeated knots.
Definition: gsKnotVector.hpp:265
gsKnotVector knotUnion(const gsKnotVector &b) const
Computes the union of knot-vectors this and b.
Definition: gsKnotVector.hpp:187
reverse_iterator rend() const
Returns reverse iterator pointing to the beginning of the repeated knots.
Definition: gsKnotVector.hpp:229
int degree() const
Returns the degree of the knot vector.
Definition: gsKnotVector.hpp:700
iterator endAt(mult_t upos) const
Definition: gsKnotVector.hpp:139
Provides declaration of input/output XML utilities struct.
bool includes(const gsKnotVector< T > &other) const
Returns true if every knot of other (counted with repetitions) is found within this knot-vector...
Definition: gsKnotVector.hpp:153
void initUniform(T first, T last, unsigned interior, unsigned mult_ends, unsigned mult_interior, short_t degree=-1)
Definition: gsKnotVector.hpp:643