G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsKnotVector.hpp
Go to the documentation of this file.
1
14#pragma once
15
16#include <gsIO/gsBase64.h>
17#include <gsIO/gsXml.h>
19
20namespace gismo
21{
22
23namespace internal
24{
25
29template<class T>
30class gsXml< gsKnotVector<T> >
31{
32private:
33 gsXml() { }
34
35public:
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
116template<typename T>
118{
119 return m_repKnots.begin();
120 //return m_repKnots.data();
121}
122
123template<typename T>
125{
126 return m_repKnots.end();
127 //return m_repKnots.data() + m_repKnots.size();
128}
129
130template<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
138template<typename T>
140{
141 upos += numLeftGhosts();
142 return m_repKnots.begin() + m_multSum[upos];
143 //return m_repKnots.data() + m_multSum[upos];
144}
145
146template<typename T>
147typename gsKnotVector<T>::reverse_iterator gsKnotVector<T>::rbegin() const
148{
149 return std::reverse_iterator<iterator>(end());
150}
151
152template<typename T>
154{
155 return std::includes(begin(), end(), other.begin(), other.end() );
156}
157
158template<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
171template<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
186template<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
200template<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
213template<typename T>
214const 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
228template<typename T>
229typename gsKnotVector<T>::reverse_iterator gsKnotVector<T>::rend() const
230{
231 return std::reverse_iterator<iterator>(begin());
232}
233
234template<typename T>
236{
237 return uiterator(*this,0,numLeftGhosts());
238}
239
240template<typename T>
242{
243 return uiterator::End(*this);
244}
245
246template<typename T>
247typename gsKnotVector<T>::reverse_uiterator gsKnotVector<T>::urbegin() const
248{
249 return reverse_uiterator(uend());
250}
251
252template<typename T>
253typename gsKnotVector<T>::reverse_uiterator gsKnotVector<T>::urend() const
254{
255 return reverse_uiterator(ubegin());
256}
257
258template<typename T>
260{
261 return smart_iterator(*this,0,numLeftGhosts());
262}
263
264template<typename T>
266{
267 return smart_iterator::End(*this);
268}
269
270template<typename T>
271typename gsKnotVector<T>::reverse_smart_iterator gsKnotVector<T>::rsbegin() const
272{
273 return reverse_smart_iterator(send());
274}
275
276template<typename T>
277typename 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
288template<typename T>
289gsKnotVector<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
301template<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
311template<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.
324template<typename T>
325void 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
346template<typename T>
347void 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
365template<typename T>
366void 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
375template<typename T>
376void 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
389template<typename T>
390void 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
402template<typename T>
403void 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
420template<typename T>
421typename 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
429template<typename T>
430typename 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
449template<typename T>
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
467template<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
492template <typename T>
493std::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
517template <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
526template <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
535template<typename T>
537{
538 return isConsistent(m_repKnots,m_multSum);
539}
540
541template<typename T>
542bool 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
575template<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
591template<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
602template<typename T>
603gsKnotVector<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
642template <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
692template<typename T>
693void 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
699template<typename T>
701{
702 return m_deg;
703}
704
705template<typename T>
707{
708 return uSize() == 0 ? -1 :
709 (std::max)(( ubegin() ).multiplicity(),
710 ( uend()-1 ).multiplicity()) - 1;
711}
712
713template<typename T>
714typename 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
723template<typename T>
724typename 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
732template<typename T>
733typename 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
745template<typename T>
747gsKnotVector<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
761template<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
769template<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
777template<typename T>
779gsKnotVector<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
793template<typename T>
794void gsKnotVector<T>::refineSpans( const multContainer & spanIndices, mult_t knotsPerSpan )
795{
796 refineSpans(spanIndices.begin(), spanIndices.end(), knotsPerSpan);
797}
798
799template <typename T>
800std::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
819template<typename T>
820void 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.
838template<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
849template<typename T>
850void 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
873template<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
902template<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
936template<typename T>
938{
939 increaseMultiplicity(i,true);
940 m_deg += i;
941}
942
943template<typename T>
945{
946 reduceMultiplicity(i,true);
947 m_deg -= i;
948}
949
950template <typename T>
951std::vector<T> gsKnotVector<T>::
952coarsen(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
990template<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
1024template<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
1033template <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
1047template <class T>
1048void 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
1065template< 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
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
Class for representing a knot vector.
Definition gsKnotVector.h:80
reverse_iterator rbegin() const
Returns reverse iterator pointing past the end of the repeated knots.
Definition gsKnotVector.hpp:147
uiterator ubegin() const
Returns unique iterator pointing to the beginning of the unique knots.
Definition gsKnotVector.hpp:235
void greville_into(gsMatrix< T > &result) const
Definition gsKnotVector.hpp:991
void reduceMultiplicity(const mult_t i=1, bool boundary=false)
Definition gsKnotVector.hpp:903
void degreeReduce(const short_t &i)
Converse to degreeElevate.
Definition gsKnotVector.hpp:944
void getUniformRefinementKnots(mult_t knotsPerSpan, knotContainer &result, mult_t mult=1) const
Definition gsKnotVector.hpp:1048
std::ostream & print(std::ostream &os=gsInfo) const
Definition gsKnotVector.hpp:493
size_t size() const
Number of knots (including repetitions).
Definition gsKnotVector.h:242
mult_t maxInteriorMultiplicity() const
Returns the maximum multiplicity in the interior.
Definition gsKnotVector.hpp:724
void swap(gsKnotVector &other)
Swaps with other knot vector.
Definition gsKnotVector.hpp:302
iterator begin() const
Returns iterator pointing to the beginning of the repeated knots.
Definition gsKnotVector.hpp:117
T maxIntervalLength() const
Returns the maximum interval length of the knot sequence.
Definition gsKnotVector.hpp:518
internal::gsKnotIterator< T > smart_iterator
Definition gsKnotVector.h:107
std::vector< T >::const_iterator iterator
Definition gsKnotVector.h:97
void reverse()
Better directly use affineTransformTo.
Definition gsKnotVector.hpp:468
iterator beginAt(mult_t upos) const
Definition gsKnotVector.hpp:131
void degreeElevate(const short_t &i=1)
Definition gsKnotVector.hpp:937
void uniformRefine(mult_t numKnots=1, mult_t mult=1)
Definition gsKnotVector.hpp:820
reverse_smart_iterator rsbegin() const
Returns the reverse smart iterator pointing past the end of the repeated knots.
Definition gsKnotVector.hpp:271
void initClamped(int degree, unsigned numKnots=2, unsigned mult_interior=1)
Definition gsKnotVector.hpp:693
void remove(uiterator uit, mult_t mult=1)
Definition gsKnotVector.hpp:347
void refineSpans(iterType begin, iterType end, mult_t knotsPerSpan)
Inserts knotsPerSpan knots between each two knots between begin and end.
Definition gsKnotVector.h:647
gsKnotVector knotUnion(const gsKnotVector &b) const
Computes the union of knot-vectors this and b.
Definition gsKnotVector.hpp:187
smart_iterator send() const
Returns the smart iterator pointing past the end of the repeated knots.
Definition gsKnotVector.hpp:265
reverse_smart_iterator rsend() const
Returns the reverse smart iterator pointing to the beginning of the repeated knots.
Definition gsKnotVector.hpp:277
void erase(const mult_t first, const mult_t last)
Removes the knots in the range [first,last)
Definition gsKnotVector.hpp:376
mult_t multiplicityIndex(mult_t i) const
Definition gsKnotVector.hpp:430
void trimLeft(const mult_t numKnots)
Removes the left-most numKnots from the knot-vector.
Definition gsKnotVector.hpp:390
bool check() const
Checks whether the knot vector is in a consistent state.
Definition gsKnotVector.hpp:536
int degree() const
Returns the degree of the knot vector.
Definition gsKnotVector.hpp:700
multContainer multiplicities() const
Returns vector of multiplicities of the knots.
Definition gsKnotVector.hpp:714
std::string detail() const
Return a string with detailed information on the knot vector.
Definition gsKnotVector.hpp:800
void supportIndex_into(const mult_t &i, gsMatrix< index_t > &result) const
Definition gsKnotVector.hpp:1066
gsKnotVector * clone() const
Returns a pointer to a copy.
Definition gsKnotVector.hpp:312
uiterator uend() const
Returns unique iterator pointing past the end of the unique knots.
Definition gsKnotVector.hpp:241
void insert(T knot, mult_t mult=1)
Inserts knot knot into the knot vector with multiplicity mult.
Definition gsKnotVector.hpp:325
reverse_iterator rend() const
Returns reverse iterator pointing to the beginning of the repeated knots.
Definition gsKnotVector.hpp:229
void difference(const gsKnotVector< T > &other, std::vector< T > &result) const
Computes the difference between this knot-vector and other.
Definition gsKnotVector.hpp:159
static bool isConsistent(const knotContainer &repKnots, const multContainer &multSums)
Sanity check.
Definition gsKnotVector.hpp:542
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
void addConstant(T amount)
Adds amount to all the knots.
Definition gsKnotVector.hpp:839
int deduceDegree() const
Definition gsKnotVector.hpp:706
mult_t multiplicity(T u) const
Definition gsKnotVector.hpp:421
internal::gsUKnotIterator< T > uiterator
Definition gsKnotVector.h:102
void trimRight(const mult_t numKnots)
Removes the right-most numKnots from the knot-vector.
Definition gsKnotVector.hpp:403
mult_t minInteriorMultiplicity() const
Returns the minimum multiplicity in the interior.
Definition gsKnotVector.hpp:733
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
smart_iterator sbegin() const
Returns the smart iterator pointing to the beginning of the repeated knots.
Definition gsKnotVector.hpp:259
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
void initUniform(T first, T last, unsigned interior, unsigned mult_ends, unsigned mult_interior, short_t degree=-1)
Definition gsKnotVector.hpp:643
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
gsKnotVector()
Empty constructor sets the degree to -1 and leaves the knots empty.
Definition gsKnotVector.h:157
iterator end() const
Returns iterator pointing past the end of the repeated knots.
Definition gsKnotVector.hpp:124
void increaseMultiplicity(const mult_t i=1, bool boundary=false)
Definition gsKnotVector.hpp:874
void centers_into(gsMatrix< T > &result) const
Definition gsKnotVector.hpp:1025
T minIntervalLength() const
Returns the minimum interval length of the knot sequence.
Definition gsKnotVector.hpp:527
uiterator uUpperBound(const T u) const
Returns an iterator pointing to the first knot which compares greater than u.
Definition gsKnotVector.hpp:763
void affineTransformTo(T newBeg, T newEnd)
Definition gsKnotVector.hpp:450
std::vector< T > coarsen(index_t knotRemove=1, index_t knotSkip=1, mult_t mul=-1)
Definition gsKnotVector.hpp:952
iterator endAt(mult_t upos) const
Definition gsKnotVector.hpp:139
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
gsMatrix< T > greville() const
Definition gsKnotVector.h:540
reverse_uiterator urend() const
Returns reverse unique iterator pointing to the beginning of the unique knots.
Definition gsKnotVector.hpp:253
gsKnotVector knotIntersection(const gsKnotVector &b) const
Computes the intersection of knot-vectors this and b.
Definition gsKnotVector.hpp:201
reverse_uiterator urbegin() const
Returns reverse unique iterator pointing past the end of the unique knots.
Definition gsKnotVector.hpp:247
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
T at(index_t i) const
Returns the i-th element of the vectorization of the matrix.
Definition gsMatrix.h:211
#define short_t
Definition gsConfig.h:35
#define index_t
Definition gsConfig.h:32
#define GISMO_ENSURE(cond, message)
Definition gsDebug.h:102
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Knot vector for B-splines.
Provides declaration of input/output XML utilities struct.
gsXmlNode * makeNode(const std::string &name, gsXmlTree &data)
Helper to allocate XML node.
Definition gsXml.cpp:54
gsXmlAttribute * makeAttribute(const std::string &name, const std::string &value, gsXmlTree &data)
Helper to allocate XML attribute.
Definition gsXml.cpp:37
The G+Smo namespace, containing all definitions for the library.
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,...
Definition gsMemory.h:368
S give(S &x)
Definition gsMemory.h:266
Struct that defines the boundary sides and corners and types of a geometric object.
Definition gsBoundary.h:56