G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsMultiPatch.hpp
Go to the documentation of this file.
1
14#pragma once
15
16#include <gsCore/gsBasis.h>
17#include <gsCore/gsGeometry.h>
18#include <gsCore/gsDofMapper.h>
21#include <gsMesh2/gsSurfMesh.h>
24
26
27namespace gismo
28{
29
30template<class T>
31gsMultiPatch<T> gsMultiPatch<T>::coord(const index_t c) const
32{
33 gsMultiPatch<T> result;
34 for ( const_iterator it = m_patches.begin(); it != m_patches.end(); ++it )
35 {
36 result.addPatch( (*it)->coord(c) );
37 }
38 return result;
39}
40
41template<class T>
43 : BaseA( geo.parDim() )
44{
45 m_patches.push_back(geo.clone().release());
46 //m_patches[0]->setId(0); // Note: for the single-patch constructor the id remains unchanged
47 addBox();
48 this->addAutoBoundaries();
49}
50
51template<class T>
53 : BaseA( other ), BaseB( other ), m_patches( other.m_patches.size() )
54{
55 // clone all geometries
56 cloneAll( other.m_patches.begin(), other.m_patches.end(),
57 this->m_patches.begin());
58}
59
60#if EIGEN_HAS_RVALUE_REFERENCES
61
62template<class T>
64{
65 if (this!=&other)
66 {
67 freeAll(m_patches);
68 BaseA::operator=(other);
69 m_patches.resize(other.m_patches.size());
70 // clone all geometries
71 cloneAll( other.m_patches.begin(), other.m_patches.end(),
72 this->m_patches.begin());
73 }
74 return *this;
75}
76
77template<class T>
78gsMultiPatch<T>& gsMultiPatch<T>::operator=( gsMultiPatch&& other )
79{
80 freeAll(m_patches);
81 BaseA::operator=(give(other));
82 m_patches = give(other.m_patches);
83 return *this;
84}
85
86
87#endif
88
89template<class T>
90gsMultiPatch<T>::gsMultiPatch(PatchContainer & patches )
91 : BaseA( patches[0]->parDim(), patches.size() )
92{
93 m_patches.swap(patches); // patches are consumed
94 setIds();
95 this->addAutoBoundaries();
96}
97
98template<class T>
99gsMultiPatch<T>::gsMultiPatch( PatchContainer& patches,
100 const std::vector<patchSide>& boundary,
101 const std::vector<boundaryInterface>& interfaces )
102 : BaseA( patches[0]->parDim(), patches.size(), boundary, interfaces )
103{
104 m_patches.swap(patches); // patches are consumed
105 setIds();
106}
107
108template<class T>
110{
111 freeAll(m_patches);
112}
113
114template<class T>
116{
117 size_t id = 0;
118 for ( iterator it = m_patches.begin(); it != m_patches.end(); ++it )
119 {
120 ( *it )->setId( id++ );
121 }
122}
123
124template<class T>
125std::ostream& gsMultiPatch<T>::print(std::ostream& os) const
126{
127 if ( !this->empty() ) {
128 os << "gsMultiPatch (" << this->nPatches() << "): ";
129 os << "#Boundaries= " << nBoundary() << ", ";
130 os << "#Interfaces= " << nInterfaces() << ".\n";
131 } else {
132 os << "gsMultiPatch ( empty! ).\n";
133 }
134 return os;
135}
136
137template<class T>
138std::string gsMultiPatch<T>::detail() const
139{
140 std::ostringstream os;
141 print(os);
142 if ( nPatches() > 0 )
143 {
144 BaseA::print( os );
145 }
146 return os.str();
147}
148
149template<class T>
151{
152 GISMO_ASSERT( m_patches.size() > 0 , "Empty multipatch object.");
153 return m_patches[0]->geoDim();
154}
155
156template<class T>
158{
159 GISMO_ASSERT( m_patches.size() > 0 , "Empty multipatch object.");
160 return m_patches[0]->geoDim() - m_dim;
162
163template<class T>
166{
167 return m_patches[i]->basis().support();
168}
169
170template<class T>
172gsMultiPatch<T>::basis( size_t i ) const
173{
174 GISMO_ASSERT( i < m_patches.size(), "Invalid patch index requested from gsMultiPatch" );
175 return m_patches[i]->basis();
176}
177
178template<class T>
179std::vector<gsBasis<T> *> gsMultiPatch<T>::basesCopy(bool NoRational) const
180{
181 std::vector<gsBasis<T> *> bb;
182 bb.reserve(m_patches.size());
183
184 if (NoRational)
185 {
186 for ( const_iterator it = m_patches.begin();
187 it != m_patches.end(); ++it )
188 {
189 bb.push_back( (*it)->basis().source().clone().release() );
190 }
191 }
192 else
193 {
194 for ( const_iterator it = m_patches.begin();
195 it != m_patches.end(); ++it )
196 {
197 bb.push_back( (*it)->basis().clone().release() );
198 }
199 }
200 return bb ;
201}
202
203template<class T>
204void gsMultiPatch<T>::permute(const std::vector<short_t> & perm)
205{
206 gsAsVector<gsGeometry<T>*> a (m_patches);
207 a = gsEigen::PermutationMatrix<-1,-1,short_t>(gsAsConstVector<short_t>(perm)) * a;
208}
209
210template<class T>
212{
213 if ( m_dim == -1 )
214 {
215 m_dim = g->parDim();
216 } else
217 {
218 GISMO_ASSERT( m_dim == g->parDim(),
219 "Tried to add a patch of different dimension in a multipatch." );
220 }
221 index_t index = m_patches.size();
222 g->setId(index);
223 m_patches.push_back( g.release() ) ;
224 addBox();
225 return index;
226}
227
228template<class T>
230{
231 return addPatch(g.clone());
232}
234template<class T>
236{
237 const_iterator it
238 = std::find( m_patches.begin(), m_patches.end(), g );
239 GISMO_ASSERT( it != m_patches.end(), "Did not find the patch index." );
240 // note: should return g->patchId();
241 return it - m_patches.begin();
242}
244template<class T>
247{
248 int p1 = findPatchIndex( g1 );
249 int p2 = findPatchIndex( g2 );
250 BaseA::addInterface( p1, s1, p2, s2 );
251}
252
253template<class T>
255{
256 gsMatrix<T> coordinates;
257 m_patches[pc.patch]->eval_into(m_patches[pc.patch]->parameterCenter(pc),coordinates);
258 return coordinates;
259}
260
262template<class T>
264{
265 gsMatrix<T> coordinates;
266 m_patches[ps.patch]->eval_into(m_patches[ps.patch]->parameterCenter(ps),coordinates);
267 return coordinates;
268}
269
270template<class T>
271void gsMultiPatch<T>::uniformRefine(int numKnots, int mul, short_t const dir)
272{
273 for ( typename PatchContainer::const_iterator it = m_patches.begin();
274 it != m_patches.end(); ++it )
275 {
276 ( *it )->uniformRefine(numKnots, mul, dir);
277 }
278}
279
280
281template<class T>
282void gsMultiPatch<T>::degreeElevate(short_t const elevationSteps, short_t const dir)
283{
284 for ( typename PatchContainer::const_iterator it = m_patches.begin();
285 it != m_patches.end(); ++it )
286 {
287 ( *it )->degreeElevate(elevationSteps, dir);
288 }
290
291template<class T>
292void gsMultiPatch<T>::degreeIncrease(short_t const elevationSteps, short_t const dir)
293{
294 for ( typename PatchContainer::const_iterator it = m_patches.begin();
295 it != m_patches.end(); ++it )
296 {
297 ( *it )->degreeIncrease(elevationSteps, dir);
298 }
300
301template<class T>
302void gsMultiPatch<T>::degreeDecrease(int elevationSteps)
303{
304 for ( typename PatchContainer::const_iterator it = m_patches.begin();
305 it != m_patches.end(); ++it )
306 {
307 ( *it )->degreeDecrease(elevationSteps, -1);
309}
310
311template<class T>
312void gsMultiPatch<T>::degreeReduce(int elevationSteps)
313{
314 for ( typename PatchContainer::const_iterator it = m_patches.begin();
315 it != m_patches.end(); ++it )
316 {
317 ( *it )->degreeReduce(elevationSteps, -1);
318 }
319}
320
321template<class T>
323{
324 for ( typename PatchContainer::const_iterator it = m_patches.begin();
325 it != m_patches.end(); ++it )
326 {
327 ( *it )->uniformCoarsen(numKnots);
328 }
330
331template<class T>
333{
334 result.setZero(geoDim(),2);
335 if ( m_patches.size() == 0 )
336 return;
337
338 // to do: this is the bounding box of a gsGeometry, make a member function
339 result.col(0) = patch(0).coefs().colwise().minCoeff().transpose();
340 result.col(1) = patch(0).coefs().colwise().maxCoeff().transpose();
341
342 for (const_iterator it = begin()+1; it != end(); ++it)
343 {
344 const gsMatrix<T> & cc = (*it)->coefs();
345 result.col(0) = result.col(0).cwiseMin( cc.colwise().minCoeff().transpose() ) ;
346 result.col(1) = result.col(1).cwiseMax( cc.colwise().maxCoeff().transpose() ) ;
348}
349
350template<class T>
352{
353 int n;
354 if (dir == -1)
355 n = math::exp2(parDim());
356 else
357 n = 2;
358 std::vector<gsGeometry<T>*> result;
359 result.reserve(nPatches() * n);
360
361 for (size_t np = 0; np < nPatches(); ++np)
362 {
363 std::vector<gsGeometry<T>*> result_temp = m_patches[np]->uniformSplit(dir);
364 result.insert(result.end(), result_temp.begin(), result_temp.end());
365 }
366 gsMultiPatch<T> mp(result);
367 mp.computeTopology();
368 return mp;
369}
370
372/*
373 This is based on comparing a set of reference points of the patch
374 side and thus it implicitly assumes that the patch faces match
375*/
376template<class T>
377bool gsMultiPatch<T>::computeTopology( T tol, bool cornersOnly, bool)
378{
379 BaseA::clearTopology();
380
381 const size_t np = m_patches.size();
382 const index_t nCorP = 1 << m_dim; // corners per patch
383 const index_t nCorS = 1 << (m_dim-1); // corners per side
384
386 // Parametric coordinates of the reference points. These points
387 // are used to decide if two sides match.
388 // Currently these are the corner points and the side-centers
389 coor;
390 if (cornersOnly)
391 coor.resize(m_dim,nCorP);
392 else
393 coor.resize(m_dim,nCorP + 2*m_dim);
394
395 gsVector<bool> boxPar(m_dim);
396
397 // each matrix contains the physical coordinates of the reference points
398 std::vector<gsMatrix<T> > pCorners(np);
399
400 std::vector<patchSide> pSide; // list of all candidate patchSides to compare
401 pSide.reserve(np * 2 * m_dim);
402
403//# pragma omp parallel for private(supp, boxPar, !coor)
404 for (size_t p=0; p<np; ++p)
405 {
406 supp = m_patches[p]->parameterRange(); // the parameter domain of patch i
407
408 // Corners' parametric coordinates
409 for (boxCorner c=boxCorner::getFirst(m_dim); c<boxCorner::getEnd(m_dim); ++c)
410 {
411 boxPar = c.parameters(m_dim);
412 for (index_t i=0; i<m_dim;++i)
413 coor(i,c-1) = boxPar(i) ? supp(i,1) : supp(i,0);
414 }
415
416 if (!cornersOnly)
417 {
418 // Sides' centers parametric coordinates
419 index_t l = nCorP;
420 for (boxSide c=boxSide::getFirst(m_dim); c<boxSide::getEnd(m_dim); ++c)
421 {
422 const index_t dir = c.direction();
423 const index_t s = static_cast<index_t>(c.parameter());// 0 or 1
424
425 for (index_t i=0; i<m_dim;++i)
426 coor(i,l) = ( dir==i ? supp(i,s) :
427 (supp(i,1)+supp(i,0))/2.0 );
428 l++;
429 }
430 }
431
432 // Evaluate the patch on the reference points
433 m_patches[p]->eval_into(coor,pCorners[p]);
434
435 // Add all the patchSides of this patch to the candidate list
436 for (boxSide bs=boxSide::getFirst(m_dim); bs<boxSide::getEnd(m_dim); ++bs)
437 pSide.push_back(patchSide(p,bs));
438 }
439
440 gsVector<index_t> dirMap(m_dim);
441 gsVector<bool> matched(nCorS), dirOr(m_dim);
442 std::vector<boxCorner> cId1, cId2;
443 cId1.reserve(nCorS);
444 cId2.reserve(nCorS);
445
446 std::set<index_t> found;
447 for (size_t sideind=0; sideind<pSide.size(); ++sideind)
448 {
449 const patchSide & side = pSide[sideind];
450 for (size_t other=sideind+1; other<pSide.size(); ++other)
451 {
452 side .getContainedCorners(m_dim,cId1);
453 pSide[other].getContainedCorners(m_dim,cId2);
454 matched.setConstant(false);
455
456 // Check whether the side center matches
457 if (!cornersOnly)
458 if ( ( pCorners[side.patch ].col(nCorP+side-1 ) -
459 pCorners[pSide[other].patch].col(nCorP+pSide[other]-1)
460 ).norm() >= tol )
461 continue;
462
463 //t-junction
464 // check for matching vertices else
465 // invert the vertices of first side on the second and vise-versa
466 // if at least one vertex is found (at most 2^(d-1)), mark as interface
467
468 // Check whether the vertices match and compute direction
469 // map and orientation
470 if ( matchVerticesOnSide( pCorners[side.patch] , cId1, 0,
471 pCorners[pSide[other].patch], cId2,
472 matched, dirMap, dirOr, tol ) )
473 {
474 dirMap(side.direction()) = pSide[other].direction();
475 dirOr (side.direction()) = !( side.parameter() == pSide[other].parameter() );
476 BaseA::addInterface( boundaryInterface(side, pSide[other], dirMap, dirOr));
477 found.insert(sideind);
478 found.insert(other);
479 }
481 }
482
483 index_t k = 0;
484 found.insert(found.end(), pSide.size());
485 for (const auto & s : found)
487 for (;k<s;++k)
488 BaseA::addBoundary( pSide[k] );
489 ++k;
490 }
491
492 return true;
493}
494
495template <class T>
497{
498 for ( typename PatchContainer::const_iterator it = m_patches.begin();
499 it != m_patches.end(); ++it )
500 if ( -1 == (*it)->orientation() )
501 (*it)->toggleOrientation();
503 if (this->nInterfaces() || this->nBoundary() )
504 this->computeTopology();
505}
506
507template <class T>
509 const gsMatrix<T> &cc1, const std::vector<boxCorner> &ci1, index_t start,
510 const gsMatrix<T> &cc2, const std::vector<boxCorner> &ci2,
511 const gsVector<bool> &matched, gsVector<index_t> &dirMap,
512 gsVector<bool> &dirO, T tol, index_t reference)
513{
514 const bool computeOrientation = !(start&(start-1)) && (start != 0); // true if start is a power of 2
515 const bool setReference = start==0; // if we search for the first point then we set the reference
516
517 const short_t dim = static_cast<short_t>(cc1.rows());
518
519 index_t o_dir = 0, d_dir = 0;
520
521 gsVector<bool> refPar, newPar, newMatched;
522
523 if (computeOrientation)
524 {
525 // o_dir is the only direction in which the parameters differ between start and 0
526 const gsVector<bool> parStart = ci1[start].parameters(dim);
527 const gsVector<bool> parRef = ci1[0].parameters(dim);
528 for (; o_dir<dim && parStart(o_dir)==parRef(o_dir) ;) ++o_dir;
529 }
530
531 if (!setReference)
532 refPar = ci2[reference].parameters(dim);
533
534 for (size_t j=0;j<ci2.size();++j)
535 {
536 if( !matched(j) && (cc1.col(ci1[start]-1)-cc2.col(ci2[j]-1)).norm() < tol )
537 {
538 index_t newRef = (setReference) ? j : reference;
539 if (computeOrientation)
540 {
541 index_t count=0;
542 d_dir = 0;
543 newPar = ci2[j].parameters(dim);
544 for (index_t i=0; i< newPar.rows();++i)
545 {
546 if ( newPar(i)!=refPar(i) )
547 {
548 d_dir=i;
549 ++count;
550 }
551 }
552 if (count != 1)
553 {
554 // the match is wrong: we are mapping an edge to a diagonal
555 continue;
556 }
557 dirMap(o_dir) = d_dir;
558 dirO (o_dir) = (static_cast<index_t>(j) > reference);
559 }
560 if ( start + 1 == static_cast<index_t>( ci1.size() ) )
561 {
562 // we matched the last vertex, we are done
563 return true;
564 }
565 newMatched = matched;
566 newMatched(j) = true;
567 if (matchVerticesOnSide( cc1,ci1,start+1,cc2,ci2,newMatched,dirMap,dirO, tol,newRef))
568 return true;
569 }
570 }
571
572 return false;
573}
574
575
576template<class T>
578{
579 gsDofMapper mapper = getMapper(tol);
580
581 gsMatrix<T> meanVal;
582 std::vector<std::pair<index_t,index_t> > dof;
583 const index_t start = mapper.freeSize() - mapper.coupledSize();
584 const index_t end = mapper.freeSize();
585
586 for (index_t i = start; i!= end; ++i) // For all coupled DoFs
587 {
588 // Get the preimages of this global dof (as pairs (patch,index) )
589 mapper.preImage(i, dof);
590
591 // Compute the mean value
592 meanVal = m_patches[dof.front().first]->coef(dof.front().second);
593 for (size_t k = 1; k!=dof.size(); ++k)
594 meanVal += m_patches[dof[k].first]->coef(dof[k].second);
595 meanVal.array() /= dof.size();
596
597 // Set involved control points equal to their average value
598 for (size_t k = 0; k!=dof.size(); ++k)
599 m_patches[dof[k].first]->coef(dof[k].second) = meanVal;
600 }
601}
602
603template<class T>
605{
606 const T tol2 = tol*tol;
607 gsMatrix<index_t> bdr1, bdr2; // indices of the boundary control points
608
609 // Create a map which assigns to all meeting patch-local indices a
610 // unique global id
611 const index_t sz = m_patches.size();
612 gsVector<index_t> patchSizes(sz);
613 for (index_t i=0; i!= sz; ++i)
614 patchSizes[i] = m_patches[i]->coefsSize();
615
616 gsDofMapper mapper(patchSizes);
617
618 for ( const_iiterator it = iBegin(); it != iEnd(); ++it ) // for all interfaces
619 {
620 const gsGeometry<T> & p1 = *m_patches[it->first() .patch];
621 const gsGeometry<T> & p2 = *m_patches[it->second().patch];
622
623 // Grab boundary control points in matching configuration
624 p1.basis().matchWith(*it, p2.basis(), bdr1, bdr2);
625
626 bool warn = true;
627 //mapper.matchDofs(it->first().patch, bdr1, it->second().patch, bdr2);
628 for (index_t i = 0; i!= bdr1.size(); ++i )
629 {
630 if ( ( p1.coef(bdr1(i)) - p2.coef(bdr2(i)) ).squaredNorm() > tol2 )
631 {
632 if (warn)
633 {
634 gsWarn<<"Big gap detected between patches "<< it->first().patch
635 <<" and "<<it->second().patch <<"\n";
636 warn = false;
637 }
638 }
639 else
640 // Match the dofs on the interface
641 mapper.matchDof(it->first().patch, bdr1(i,0), it->second().patch, bdr2(i,0) );
642 }
643 }
644
645 // Finalize the mapper. At this point all patch-local dofs are
646 // mapped to unique global indices
647 mapper.finalize();
648 return mapper;
649}
650
651template<class T>
653{
654 GISMO_ASSERT(2==parDim(), "Works for surfaces only.");
655 gsDofMapper mapper = getMapper((T)1e-7);
656 gsSurfMesh mesh;
657 auto pid = mesh.add_vertex_property<index_t>("v:patch");
658 auto anchor = mesh.add_vertex_property<index_t>("v:anchor");
660 gsSurfMesh::Point pt(0,0,0);
661 const index_t gd = geoDim();
662 std::vector<std::pair<index_t,index_t> > pi = mapper.anyPreImages();
663 //std::pair<index_t,index_t> pi;
664
665 for (index_t j = 0; j!= mapper.size(); ++j)
666 {
667 //pi = mapper.anyPreImage(j);
668 gsGeometry<> & pp = patch(pi[j].first);
669 pt.topRows(gd) = pp.eval( pp.basis().anchor(pi[j].second) );
670 v = mesh.add_vertex( pt );
671 pid[v] = pi[j].first;
672 anchor[v] = pi[j].second;
673 }
674
675 size_t np = nPatches();
676 gsMatrix<> supp, coor;
677 gsVector<bool> boxPar(m_dim);
678 gsVector<index_t,2> cur, csize, strides;
679 GISMO_ENSURE( dynamic_cast<gsTensorBasis<2>*>(&patch(0).basis()), "Not a tensor basis");
680 static_cast<gsTensorBasis<2>&>(patch(0).basis()).stride_cwise(strides);
681 static_cast<gsTensorBasis<2>&>(patch(0).basis()).size_cwise (csize);
682 csize.array() -= 2;
683 gsSurfMesh::Vertex v1, v2, v3, v4;
684 for (size_t p=0; p<np; ++p)
685 {
686 // todo: basis->connectivityAtAnchors ++ basis->controlPolytope
687 gsTensorBasis<2>& pp = static_cast<gsTensorBasis<2>&>(patch(p).basis());
688 cur.setZero(2);
689 do
690 {
691 index_t ci = pp.index(cur);
692 v1 = gsSurfMesh::Vertex( mapper.index(ci, p) );
693 ci += strides[0];
694 v2 = gsSurfMesh::Vertex( mapper.index(ci, p) );
695 ci += strides[1];
696 v3 = gsSurfMesh::Vertex( mapper.index(ci, p) );
697 ci -= strides[0];
698 v4 = gsSurfMesh::Vertex( mapper.index(ci, p) );
699 mesh.add_quad(v1,v2,v3,v4);
700 } while (nextCubePoint(cur, csize));
701
702 }
703
704 return mesh;
705}
706
707template<class T> // to do: move to boundaryInterface
709{
710 if (scaling==0)
711 scaling=1;
712 gsMatrix<T> box1=m_patches[bi.first().patch ]->support();
713 gsMatrix<T> box2=m_patches[bi.second().patch]->support();
714 const index_t oDir1 = bi.first() .direction();
715 const index_t oDir2 = bi.second().direction();
716 const T len1=box1(oDir1,1)-box1(oDir1,0);
717
718 if (bi.second().parameter())
719 {
720 box2(oDir2,0)=box2(oDir2,1);
721 box2(oDir2,1)+=scaling*len1;
722 }
723 else
724 {
725 box2(oDir2,1)=box2(oDir2,0);
726 box2(oDir2,0)-=scaling*len1;
727 }
728
729 return gsAffineFunction<T>(bi.dirMap(bi.first()),bi.dirOrientation(bi.first()) ,box1,box2);
730}
731
732template<class T>
734{
735 GISMO_UNUSED(nsamples);
736 gsMultiPatch<T> result;
737 for ( typename PatchContainer::const_iterator it = m_patches.begin();
738 it != m_patches.end(); ++it )
739 {
740 result.addPatch( (*it)->approximateLinearly() );
741 }
742
743 result.gsBoxTopology::operator=(*this);//copy the original topology
744 return result;
745}
746
747template<class T>
749{
750 gsMultiBasis<T> multiBasis(*this);
751 bool changed = false;
752
753 std::vector<index_t> refEltsFirst;
754 std::vector<index_t> refEltsSecond;
755
756 // Find the areas/elements that do not match...
757 switch( this->dim() )
758 {
759 case 2:
760 changed = multiBasis.template repairInterfaceFindElements<2>( bi, refEltsFirst, refEltsSecond );
761 break;
762 case 3:
763 changed = multiBasis.template repairInterfaceFindElements<3>( bi, refEltsFirst, refEltsSecond );
764 break;
765 default:
766 GISMO_ASSERT(false,"wrong dimension");
767 }
768
769 // ...and if there are any found, refine the bases accordingly
770 if( changed )
771 {
772 if( refEltsFirst.size() > 0 )
773 {
774 int pi( bi.first().patch );
775 patch(pi).basis().refineElements_withCoefs( patch(pi).coefs(), refEltsFirst );
776 }
777 if( refEltsSecond.size() > 0 )
778 {
779 int pi( bi.second().patch );
780 patch(pi).basis().refineElements_withCoefs( patch(pi).coefs(), refEltsSecond );
781 }
782 }
783
784 return changed;
785}
786
787
788
789template<class T>
791 gsVector<index_t> & pids,
792 gsMatrix<T> & preim, const T accuracy) const
793{
794 pids.resize(points.cols());
795 pids.setConstant(-1); // -1 implies not in the domain
796 preim.resize(parDim(), points.cols());//uninitialized by default
797 gsMatrix<T> pt, pr, tmp;
798
799 for (index_t i = 0; i!=pids.size(); ++i)
800 {
801 pt = points.col(i);
802
803 for (size_t k = 0; k!= m_patches.size(); ++k)
804 {
805 pr = m_patches[k]->parameterRange();
806 m_patches[k]->invertPoints(pt, tmp, accuracy);
807 if ( (tmp.array() >= pr.col(0).array()).all()
808 && (tmp.array() <= pr.col(1).array()).all() )
809 {
810 pids[i] = k;
811 preim.col(i) = tmp;
812 break;
813 }
814 }
815 }
816}
817
818template<class T>
820 gsVector<index_t> & pid2, gsMatrix<T> & preim) const
821{
822 // Assumes points are found on pid1 and possibly on one more patch
823 pid2.resize(points.cols());
824 pid2.setConstant(-1); // -1 implies not in the domain
825 preim.resize(parDim(), points.cols());//uninitialized by default
826 gsMatrix<T> pt, pr, tmp;
827
828 for (index_t i = 0; i!=pid2.size(); ++i)
829 {
830 pt = points.col(i);
831
832 for (size_t k = 0; k!= m_patches.size(); ++k)
833 {
834 if (pid1==(index_t)k) continue; // skip pid1
835
836 pr = m_patches[k]->parameterRange();
837 m_patches[k]->invertPoints(pt, tmp);
838 if ( (tmp.array() >= pr.col(0).array()).all()
839 && (tmp.array() <= pr.col(1).array()).all() )
840 {
841 pid2[i] = k;
842 preim.col(i) = tmp;
843 break;
844 }
845 }
846 }
847}
848
849namespace
850{
851struct __closestPointHelper
852{
853 __closestPointHelper() : dist(math::limits::max()), pid(-1) { }
854 real_t dist;
855 index_t pid;
856 gsVector<> preim;
857};
858}
859
860template<class T> std::pair<index_t,gsVector<T> >
861gsMultiPatch<T>::closestPointTo(const gsVector<T> & pt,
862 const T accuracy) const
863{
864 std::pair<index_t,gsVector<T> > result;
865 this->closestDistance(pt,result,accuracy);
866 return result;
867}
868
869
870template<class T>
871T gsMultiPatch<T>::closestDistance(const gsVector<T> & pt,
872 std::pair<index_t,gsVector<T> > & result,
873 const T accuracy) const
874{
875 GISMO_ASSERT( pt.rows() == targetDim(), "Invalid input point." <<
876 pt.rows() <<"!="<< targetDim() );
877
878 gsVector<T> tmp;
879
880#ifndef _MSC_VER
881# pragma omp declare reduction(minimum : struct __closestPointHelper : omp_out = (omp_in.dist < omp_out.dist ? omp_in : omp_out) )
882 struct __closestPointHelper cph;
883# pragma omp parallel for default(shared) private(tmp) reduction(minimum:cph) //OpenMP 4.0, will not work on VS2019
884#else
885 struct __closestPointHelper cph;
886#endif
887 for (size_t k = 0; k < m_patches.size(); ++k)
888 {
889 // possible improvement: approximate dist: eval patch on a
890 // grid. find min distance between grid and pt
891
892 const T val = this->patch(k).closestPointTo(pt, tmp, accuracy);
893 if (cph.dist>val)
894 {
895 cph.dist = val; //need to be all in one struct for OMP
896 cph.pid = k;
897 cph.preim = tmp;
898 }
899 }
900 //gsInfo <<"--Pid="<<cph.pid<<", Dist("<<pt.transpose()<<"): "<< cph.dist <<"\n";
901 result = std::make_pair(cph.pid, give(cph.preim));
902 return cph.dist;
903}
904
905template<class T>
907 const index_t nsamples,
908 const T accuracy,
909 const bool directed)
910{
911 GISMO_ASSERT(this->nPatches()==other.nPatches(),"Number of patches should be the same, but this->nPatches()!=other.nPatches() -> "<<this->nPatches()<<"!="<<other.nPatches());
912 std::vector<T> result(this->nPatches());
913#pragma omp parallel
914{
915# ifdef _OPENMP
916 const int tid = omp_get_thread_num();
917 const int nt = omp_get_num_threads();
918# endif
919
920# ifdef _OPENMP
921 for ( size_t p=tid; p<this->nPatches(); p+=nt )
922# else
923 for ( size_t p=0; p<this->nPatches(); p++ )
924# endif
925 {
926 result.at(p) = this->patch(p).HausdorffDistance(other.patch(p),nsamples,accuracy,directed);
927 }
928}//omp parallel
929 return result;
930}
931
932template<class T>
934 const index_t nsamples,
935 const T accuracy,
936 bool directed)
937{
938 std::vector<T> distances = HausdorffDistance(other,nsamples,accuracy,directed);
939 return std::accumulate(distances.begin(), distances.end(), (T)( 0 ) ) / distances.size();
940}
941
942template<class T>
943void gsMultiPatch<T>::constructInterfaceRep()
944{
945 m_ifaces.clear();
946 for ( iiterator it = iBegin(); it != iEnd(); ++it ) // for all interfaces
947 {
948 const gsGeometry<T> & p1 = *m_patches[it->first() .patch];
949 const gsGeometry<T> & p2 = *m_patches[it->second().patch];
950 m_ifaces[*it] = p1.iface(*it,p2);
951 }//end for
952}
953
954template<class T>
956{
957 m_bdr.clear();
958 for ( biterator it = bBegin(); it != bEnd(); ++it ) // for all boundaries
959 {
960 const gsGeometry<T> & p1 = *m_patches[it->patch];
961 m_bdr[*it] = p1.boundary(*it);
962 }//end for
963}
964
965template<class T>
967{
968 m_ifaces.clear();
969 ifContainer ifaces = this->interfaces(l);
970 for ( iiterator it = ifaces.begin(); it != ifaces.end(); ++it ) // for all interfaces
971 {
972 const gsGeometry<T> & p1 = *m_patches[it->first() .patch];
973 const gsGeometry<T> & p2 = *m_patches[it->second().patch];
974 m_ifaces[*it] = p1.iface(*it,p2);
975 }//end for
976}
977
978template<class T>
980{
981 m_bdr.clear();
982 bContainer bdrs = this->boundaries(l);
983 for ( biterator it = bdrs.begin(); it != bdrs.end(); ++it ) // for all boundaries
984 {
985 const gsGeometry<T> & p1 = *m_patches[it->patch];
986 m_bdr[*it] = p1.boundary(*it);
987 }//end for
988}
989
990template<class T>
992{
993 for ( biterator it = bBegin(); it != bEnd(); ++it ) // for all boundaries
994 {
995 const gsGeometry<T> & p1 = *m_patches[it->patch];
996 m_sides[*it] = p1.boundary(*it);
997 }//end for
998
999 for ( iiterator it = iBegin(); it != iEnd(); ++it ) // for all interfaces
1000 {
1001 const gsGeometry<T> & p1 = *m_patches[it->first() .patch];
1002 const gsGeometry<T> & p2 = *m_patches[it->second().patch];
1003 m_sides[it->first()] = p1.boundary(it->first());
1004 m_sides[it->second()] = p2.boundary(it->second());
1005 }//end for
1006}
1007
1008template<class T>
1009std::map< std::array<size_t, 4>, internal::ElementBlock> gsMultiPatch<T>::BezierOperator() const
1010{
1011 GISMO_ENSURE( 2==domainDim(), "Anything other than bivariate splines is not yet supported!");
1012
1013 // Loop over all the elements of the given multipatch and collect all relevant
1014 // information in ElementBlocks. These will be grouped in a std::map
1015 // with respect to the number of active basis functions ( = NN/NCV )
1016 // of each Bezier element
1017 std::map<std::array<size_t, 4>, internal::ElementBlock> ElementBlocks;
1018
1019 gsMatrix<index_t> localActives, globalActives; // Active basis functions
1020 gsDofMapper mapper = getMapper((T)1e-7);
1021
1022 gsMatrix<T> quPoints, values;
1023 gsVector<T> quWeights;
1024 gsVector<index_t, 2> numNodes;
1025 gsMatrix<T> Bd;
1026 std::array<size_t, 4> key;
1027 std::vector<gsKnotVector<T> > kv(domainDim());
1028
1029 for (size_t p=0; p<nPatches(); ++p)
1030 {
1031 gsBasis<T> * basis = & patch(p).basis();
1032 // index_t NN; // Number of control points of the Bezier element // @hverhelst this is not used anywhere
1033
1034 // Create the Bezier Basis
1035 kv[0].initClamped(basis->degree(0));
1036 kv[1].initClamped(basis->degree(1));
1037 typename gsBasis<T>::uPtr bezBasis = gsBSplineBasis<T>::create(give(kv));
1038
1039 // Initialize the quadrature rule that will be used for fitting
1040 // the given basis with the Bezier basis
1041 numNodes << basis->degree(0)+1, basis->degree(1)+1 ;
1042 typename gsNewtonCotesRule<T>::uPtr QuRule;
1043 QuRule = gsNewtonCotesRule<T>::make(numNodes);
1044
1045 // Initialize an iterator over all the elements of the given basis
1046 typename gsBasis<T>::domainIter domIt = basis->makeDomainIterator();
1047
1048 // Calculate the collocation matrix of the Bezier Basis
1049 // It will be used to fit the Bez. Basis to the original basis' elements.
1050 Bd = bezBasis->collocationMatrix(bezBasis->anchors());
1051 auto solver = Bd.fullPivLu();
1052
1053 for (; domIt->good(); domIt->next() )
1054 {
1055 localActives = basis->active( domIt->center );
1056 globalActives.resizeLike(localActives);
1057 // Map every local active basis function to the global numbering
1058 for (index_t i=0; i<localActives.rows(); ++i)
1059 globalActives.at(i) = mapper.index(localActives.at(i), p);
1060
1061 key[0] = globalActives.rows();
1062 key[1] = basis->degree(0);
1063 key[2] = basis->degree(1);
1064 key[3] = 0; // TODO: if implemented for trivariates fix this
1065
1066 ElementBlocks[key].numElements += 1; // Increment the Number of Elements contained in the ElementBlock
1067 ElementBlocks[key].actives.push_back(globalActives); // Append the active basis functions ( = the Node IDs ) for this element.
1068 ElementBlocks[key].PR = basis->degree(0);
1069 ElementBlocks[key].PS = basis->degree(1);
1070 ElementBlocks[key].PT = 0; // TODO: if implemented for trivariates fix this
1071
1072 // Map the quadrature points to the current element.
1073 QuRule->mapTo( domIt->lowerCorner(), domIt->upperCorner(), quPoints, quWeights);
1074 basis->source().eval_into(quPoints, values); // Evaluate given basis at the mapped quadrature points
1075 // Append the local Bezier Extraction matrix to the ElementBlock.coefVectors
1076 ElementBlocks[key].coefVectors.push_back(solver.solve(values.transpose()).transpose());
1077 }
1078 }
1079
1080 return ElementBlocks;
1081}
1082
1083
1084template<class T>
1086{
1087 GISMO_ENSURE( 2==domainDim(), "Anything other than bivariate splines is not yet supported!");
1088 std::map<std::array<size_t, 4>, internal::ElementBlock> ElementBlocks = BezierOperator();
1089 gsMultiPatch<T> result;
1090
1091 // Get the map from patch-local to global indexing for the multi-patch
1092 gsDofMapper mapper = this->getMapper((T)1e-4);
1093
1094 // Get global coefficients of the multi patch. (i.e. without duplicates on the interfaces)
1095 gsMatrix<T> globalCoefs(mapper.size(), this->coefs().cols());
1096 globalCoefs.setZero();
1097 gsMatrix<T> globalWeights(mapper.size(), 1);
1098 globalWeights.setOnes();
1099
1100 // Loop over all patches
1101 for (size_t p = 0; p != this->nPatches(); p++)
1102 {
1103 for (index_t i=0; i != this->patch(p).coefs().rows(); ++i) // For every control point
1104 {
1105 globalCoefs.row(mapper.index(i,p)).leftCols(this->geoDim()) = this->patch(p).coefs().row(i);
1106 if (this->basis(p).isRational())
1107 globalWeights(mapper.index(i,p)) = this->basis(p).weights().at(i);
1108 }
1109 }
1110
1111 std::vector<gsKnotVector<T> > kv(domainDim());
1112 gsMatrix<> newCoefs, newWeights;
1113 for (auto const& pair : ElementBlocks)
1114 {
1115 internal::ElementBlock ElBlock = pair.second;
1116
1117 kv[0] = gsKnotVector<T>(0,1,0,ElBlock.PR+1);
1118 kv[1] = gsKnotVector<T>(0,1,0,ElBlock.PS+1);
1119 // coefs.setZero( (ElBlock.PR+1)*(ElBlock.PS+1), controlPoints.cols()-1 );
1120
1121 // Loop over all elements of the Element Block
1122 auto Ait = ElBlock.actives.begin(); // Actives Iterator
1123 auto Cit = ElBlock.coefVectors.begin(); // Coefficients Iteratos
1124
1125 for(; Ait != ElBlock.actives.end() && Cit != ElBlock.coefVectors.end(); ++Ait, ++Cit)
1126 {
1127 // If the weights are not all equal (Rational)
1128 if ( (globalWeights(Ait->asVector(),0).array() != globalWeights(Ait->asVector()(0),0)).any())
1129 {
1130 // As per Borden et al. 2010 "Isogeometric finite element data structures
1131 // based on Bézier extraction of NURBS", eq (79);
1132 newWeights = Cit->transpose() * globalWeights(Ait->asVector(),0);
1133 newCoefs = Cit->transpose() * globalWeights(Ait->asVector(),0).asDiagonal() * globalCoefs(Ait->asVector(),gsEigen::all);
1134 newCoefs = newCoefs.array().colwise() / newWeights.col(0).array();
1135 result.addPatch( gsNurbsBasis<T>::create(kv,newWeights)->makeGeometry(give(newCoefs)) );
1136 }
1137 else // If all weights are equal (Polynomial)
1138 {
1139 result.addPatch( gsBSplineBasis<T>::create(kv)->makeGeometry(
1140 Cit->transpose() * globalCoefs(Ait->asVector(),gsEigen::all) ) );
1141 }
1142 // bezier extraction operator * original control points
1143 }
1144 }
1145
1146 // result.computeTopology();
1147 return result;
1148}
1149} // namespace gismo
Struct which represents a certain side of a box.
Definition gsBoundary.h:85
bool parameter() const
Returns the parameter value (false=0=start, true=1=end) that corresponds to this side.
Definition gsBoundary.h:128
static boxSide getEnd(short_t dim)
helper for iterating on sides of an n-dimensional box
Definition gsBoundary.h:176
static boxSide getFirst(short_t)
helper for iterating on sides of an n-dimensional box
Definition gsBoundary.h:160
short_t direction() const
Returns the parametric direction orthogonal to this side.
Definition gsBoundary.h:113
Representation of an affine function.
Definition gsAffineFunction.h:30
Creates a mapped object or data pointer to a const vector without copying data.
Definition gsAsMatrix.h:285
Creates a mapped object or data pointer to a vector without copying data.
Definition gsAsMatrix.h:239
A univariate B-spline basis.
Definition gsBSplineBasis.h:700
A basis represents a family of scalar basis functions defined over a common parameter domain.
Definition gsBasis.h:79
gsSparseMatrix< T > collocationMatrix(gsMatrix< T > const &u) const
Computes the collocation matrix w.r.t. points u.
Definition gsBasis.hpp:191
virtual gsBasis::uPtr create() const
Create an empty basis of the derived type and return a pointer to it.
Definition gsBasis.hpp:532
memory::unique_ptr< gsBasis > uPtr
Unique pointer for gsBasis.
Definition gsBasis.h:89
gsMatrix< T > anchors() const
Returns the anchor points that represent the members of the basis. There is exactly one anchor point ...
Definition gsBasis.h:437
Defines a topological arrangement of a collection of "boxes" (e.g., parameter domains that map to phy...
Definition gsBoxTopology.h:39
void addAutoBoundaries()
Make all patch sides which are not yet declared as interface or boundary to a boundary.
Definition gsBoxTopology.cpp:75
void addBox(index_t i=1)
Add i new boxes.
Definition gsBoxTopology.h:198
Maintains a mapping from patch-local dofs to global dof indices and allows the elimination of individ...
Definition gsDofMapper.h:69
std::vector< std::pair< index_t, index_t > > anyPreImages(index_t comp=0) const
For all global index, this function assigns a pair (patch,dof) that maps to that global index.
Definition gsDofMapper.cpp:525
void finalize()
Must be called after all boundaries and interfaces have been marked to set up the dof numbering.
Definition gsDofMapper.cpp:240
void preImage(index_t gl, std::vector< std::pair< index_t, index_t > > &result) const
For gl being a global index, this function returns a vector of pairs (patch,dof) that contains all th...
Definition gsDofMapper.cpp:480
index_t size() const
Returns the total number of dofs (free and eliminated).
Definition gsDofMapper.h:421
void matchDof(index_t u, index_t i, index_t v, index_t j, index_t comp=0)
Couples dof i of patch u with dof j of patch v such that they refer to the same global dof at compone...
Definition gsDofMapper.cpp:99
index_t coupledSize() const
Returns the number of coupled (not eliminated) dofs.
Definition gsDofMapper.cpp:601
index_t freeSize() const
Returns the number of free (not eliminated) dofs.
Definition gsDofMapper.h:436
index_t index(index_t i, index_t k=0, index_t c=0) const
Returns the global dof index associated to local dof i of patch k.
Definition gsDofMapper.h:325
Interface for the set of functions defined on a domain (the total number of functions in the set equa...
Definition gsFunctionSet.h:219
uPtr clone()
Clone methode. Produceds a deep copy inside a uPtr.
gsMatrix< T > eval(const gsMatrix< T > &u) const
Evaluate the function,.
Definition gsFunctionSet.hpp:120
Abstract base class representing a geometry map.
Definition gsGeometry.h:93
std::vector< gsGeometry * > boundary() const
Get boundary of this geometry as a vector of new gsGeometry instances.
Definition gsGeometry.hpp:437
void setId(const size_t i)
Sets the patch index for this patch.
Definition gsGeometry.h:612
gsMatrix< T >::RowXpr coef(index_t i)
Returns the i-th coefficient of the geometry as a row expression.
Definition gsGeometry.h:346
memory::unique_ptr< gsGeometry > uPtr
Unique pointer for gsGeometry.
Definition gsGeometry.h:100
virtual const gsBasis< T > & basis() const =0
Returns a const reference to the basis of the geometry.
virtual gsGeometry::uPtr iface(const boundaryInterface &bi, const gsGeometry &other) const
Computes and returns the interface with other as a new geometry.
Definition gsGeometry.hpp:232
short_t parDim() const
Dimension d of the parameter domain (same as domainDim()).
Definition gsGeometry.hpp:190
Class for representing a knot vector.
Definition gsKnotVector.h:80
void initClamped(int degree, unsigned numKnots=2, unsigned mult_interior=1)
Definition gsKnotVector.hpp:693
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
Holds a set of patch-wise bases and their topology information.
Definition gsMultiBasis.h:37
Container class for a set of geometry patches and their topology, that is, the interface connections ...
Definition gsMultiPatch.h:100
bool repairInterface(const boundaryInterface &bi)
Checks if the interface is fully matching, and if not, repairs it.
Definition gsMultiPatch.hpp:748
void uniformCoarsen(int numKnots=1)
Coarsen uniformly all patches by removing numKnots in each knot-span.
Definition gsMultiPatch.hpp:322
void degreeElevate(short_t const elevationSteps=1, short_t const dir=-1)
Elevate the degree of all patches by elevationSteps, preserves smoothness.
Definition gsMultiPatch.hpp:282
void constructBoundaryRep()
Construct the boundary representation.
Definition gsMultiPatch.hpp:955
std::vector< T > HausdorffDistance(const gsMultiPatch< T > &other, const index_t nsamples=1000, const T accuracy=1e-6, const bool directed=false)
Construct the interface representation.
Definition gsMultiPatch.hpp:906
void degreeIncrease(short_t const elevationSteps=1, short_t const dir=-1)
Increase the degree of all patches by elevationSteps, preserves multiplicity.
Definition gsMultiPatch.hpp:292
PatchContainer const & patches() const
Returns a vector of patches // to do : replace by copies.
Definition gsMultiPatch.h:277
gsMultiPatch< T > approximateLinearly(index_t nsamples) const
Computes linear approximation of the patches using nsamples per direction.
Definition gsMultiPatch.hpp:733
gsMatrix< T > parameterRange(int i=0) const
Returns the range of parameter.
Definition gsMultiPatch.hpp:165
size_t findPatchIndex(gsGeometry< T > *g) const
Search for the given geometry and return its patch index.
Definition gsMultiPatch.hpp:235
std::map< std::array< size_t, 4 >, internal::ElementBlock > BezierOperator() const
Performs Bezier extraction on the multipatch.
Definition gsMultiPatch.hpp:1009
gsMatrix< T > pointOn(const patchCorner &pc)
Get coordinates of the patchCorner pc in the physical domain.
Definition gsMultiPatch.hpp:254
short_t coDim() const
Co-dimension of the geometry (must match for all patches).
Definition gsMultiPatch.hpp:157
gsAffineFunction< T > getMapForInterface(const boundaryInterface &bi, T scaling=0) const
construct the affine map that places bi.first() next to bi.second() and identifies the two matching s...
Definition gsMultiPatch.hpp:708
bool computeTopology(T tol=1e-4, bool cornersOnly=false, bool tjunctions=false)
Attempt to compute interfaces and boundaries automatically.
Definition gsMultiPatch.hpp:377
gsDofMapper getMapper(T tol) const
Used to get a mapper with unique vertices.
Definition gsMultiPatch.hpp:604
void locatePoints(const gsMatrix< T > &points, gsVector< index_t > &pids, gsMatrix< T > &preim, const T accuracy=1e-6) const
For each point in points, locates the parametric coordinates of the point.
Definition gsMultiPatch.hpp:790
index_t size() const
size
Definition gsMultiPatch.h:195
std::string detail() const
Prints the object as a string with extended details.
Definition gsMultiPatch.hpp:138
short_t geoDim() const
Dimension of the geometry (must match for all patches).
Definition gsMultiPatch.hpp:150
gsMultiPatch & operator=(gsMultiPatch other)
Assignment operator (uses copy-and-swap idiom)
Definition gsMultiPatch.h:129
gsMultiPatch()
Default empty constructor.
Definition gsMultiPatch.h:121
~gsMultiPatch()
Destructor.
Definition gsMultiPatch.hpp:109
gsGeometry< T > & patch(size_t i) const
Return the i-th patch.
Definition gsMultiPatch.h:292
index_t addPatch(typename gsGeometry< T >::uPtr g)
Add a patch from a gsGeometry<T>::uPtr.
Definition gsMultiPatch.hpp:211
void permute(const std::vector< short_t > &perm)
Permutes the patches according to perm.
Definition gsMultiPatch.hpp:204
void uniformRefine(int numKnots=1, int mul=1, short_t const dir=-1)
Refine uniformly all patches by inserting numKnots in each knot-span with multipliplicity mul.
Definition gsMultiPatch.hpp:271
void degreeReduce(int elevationSteps=1)
Reduce the degree of all patches by elevationSteps.
Definition gsMultiPatch.hpp:312
void fixOrientation()
Provides positive orientation for all patches.
Definition gsMultiPatch.hpp:496
gsBasis< T > & basis(const size_t i) const
Return the basis of the i-th patch.
Definition gsMultiPatch.hpp:172
void degreeDecrease(int elevationSteps=1)
Decrease the degree of all patches by elevationSteps.
Definition gsMultiPatch.hpp:302
void clear()
Clear (delete) all patches.
Definition gsMultiPatch.h:388
gsMultiPatch< T > uniformSplit(index_t dir=-1) const
Splits each patch uniformly in each direction (if dir = -1) into two new patches, giving a total numb...
Definition gsMultiPatch.hpp:351
void boundingBox(gsMatrix< T > &result) const
Returns a bounding box for the multipatch domain. The output result is a matrix with two columns,...
Definition gsMultiPatch.hpp:332
gsSurfMesh toMesh() const
Creates a surface mesh out of this multipatch.
Definition gsMultiPatch.hpp:652
std::ostream & print(std::ostream &os) const
Prints the object as a string.
Definition gsMultiPatch.hpp:125
gsMultiPatch< T > extractBezier() const
Extracts a Bezier representation of the current gsMultiPatch object.
Definition gsMultiPatch.hpp:1085
std::vector< gsBasis< T > * > basesCopy(bool numeratorOnly=false) const
Makes a deep copy of all bases and puts them in a vector.
Definition gsMultiPatch.hpp:179
size_t nPatches() const
Number of patches.
Definition gsMultiPatch.h:274
GISMO_DEPRECATED void addInterface(gsGeometry< T > *g1, boxSide s1, gsGeometry< T > *g2, boxSide s2)
Add an interface joint between side s1 of geometry g1 side s2 of geometry g2.
Definition gsMultiPatch.hpp:245
void closeGaps(T tol=1e-4)
Attempt to close gaps between the interfaces. Assumes that the topology is computed,...
Definition gsMultiPatch.hpp:577
static uPtr make(gsVector< index_t > const &numNodes, const unsigned digits=0)
Make function returning a smart pointer.
Definition gsNewtonCotesRule.h:44
A univariate NURBS basis.
Definition gsNurbsBasis.h:40
virtual void mapTo(const gsVector< T > &lower, const gsVector< T > &upper, gsMatrix< T > &nodes, gsVector< T > &weights) const
Maps quadrature rule (i.e., points and weights) from the reference domain to an element.
Definition gsQuadRule.h:177
A halfedge data structure for polygonal meshes.
Definition gsSurfMesh.h:46
Abstract base class for tensor product bases.
Definition gsTensorBasis.h:34
unsigned index(unsigned i, unsigned j, unsigned k=0) const
Definition gsTensorBasis.h:882
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition gsVector.h:37
bool nextCubePoint(Vec &cur, const Vec &end)
Iterate in lexigographic order through the points of the integer lattice contained in the cube [0,...
Definition gsCombinatorics.h:327
Implements an affine function.
Provides declaration of Basis abstract interface.
Provides combinatorial unitilies.
#define short_t
Definition gsConfig.h:35
#define index_t
Definition gsConfig.h:32
#define gsWarn
Definition gsDebug.h:50
#define GISMO_UNUSED(x)
Definition gsDebug.h:112
#define GISMO_ENSURE(cond, message)
Definition gsDebug.h:102
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Provides the gsDofMapper class for re-indexing DoFs.
Provides declaration of Geometry abstract interface.
Represents a NURBS basis with one parameter.
Creates a variety of quadrature rules.
Half edge mesh structure.
Provides declaration of TensorBasis class.
The G+Smo namespace, containing all definitions for the library.
void cloneAll(It start, It end, ItOut out)
Clones all pointers in the range [start end) and stores new raw pointers in iterator out.
Definition gsMemory.h:295
S give(S &x)
Definition gsMemory.h:266
void freeAll(It begin, It end)
Frees all pointers in the range [begin end)
Definition gsMemory.h:312
Struct which represents an interface between two patches.
Definition gsBoundary.h:650
patchSide & first()
first, returns the first patchSide of this interface
Definition gsBoundary.h:776
patchSide & second()
second, returns the second patchSide of this interface
Definition gsBoundary.h:782
Struct that defines the boundary sides and corners and types of a geometric object.
Definition gsBoundary.h:56
Struct which represents a certain corner of a hyper-cube.
Definition gsBoundary.h:292
static boxCorner getEnd(short_t dim)
helper for iterating on corners of an n-dimensional box
Definition gsBoundary.h:372
static boxCorner getFirst(short_t)
helper for iterating on corners of an n-dimensional box
Definition gsBoundary.h:356
Definition gsSurfMesh.h:104
Struct which represents a certain corner of a patch.
Definition gsBoundary.h:393
Struct which represents a certain side of a patch.
Definition gsBoundary.h:232
index_t patch
The index of the patch.
Definition gsBoundary.h:234