G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsSolid.hpp
Go to the documentation of this file.
1 
14 #pragma once
15 
16 #include <queue>
17 #include <set>
18 
19 #include <gsCore/gsMultiPatch.h>
20 #include <gsModeling/gsCurveLoop.h>
23 
24 #include <gsNurbs/gsKnotVector.h>
25 //#include <gsNurbs/gsBSplineBasis.h>
27 
28 #include <gsNurbs/gsBSpline.h>
29 
30 
31 
32 namespace gismo {
33 
34 template <class T>
35 std::ostream &gsSolid<T>::print(std::ostream &os) const
36 {
37  os<<"\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
38  os<<"A free-form solid modeled as a gsSolid:\n";
39  os<<"Number of volumes : "<< numVolumes <<"\n";
40  os<<"Number of half faces: "<< numHalfFaces <<"\n";
41  os<<"Number of half edges: "<< numHalfEdges <<"\n";
42  os<<"Number of vertices : "<< numVertices <<"\n";
43  // print a face
44  os<< *face[0];
45  os<<"vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
46  return os;
47 }
48 
49 
50 template <class T>
51 void gsSolid<T>::addHeVertex(scalar_t const& x, scalar_t const& y, scalar_t const& z)
52 {
53  gsSolidHeVertexHandle v = this->makeHeVertex(x,y,z);
54  vertex.push_back(v );
55  v->setId(numVertices++);
56 
57  if(!initialized) {
58  bb.pMax.x() = bb.pMin.x() = x;
59  bb.pMax.y() = bb.pMin.y() = y;
60  bb.pMax.z() = bb.pMin.z() = z;
61  initialized = true;
62  }
63  else {
64  if (bb.pMax.x() < x)
65  bb.pMax.x() = x;
66  if (bb.pMin.x() > x)
67  bb.pMin.x() = x;
68 
69  if (bb.pMax.y() < y)
70  bb.pMax.y() = y;
71  if (bb.pMin.y() > y)
72  bb.pMin.y() = y;
73 
74  if (bb.pMax.z() < z)
75  bb.pMax.z() = z;
76  if (bb.pMin.z() > z)
77  bb.pMin.z() = z;
78  };
79 }
80 
81 template <class T>
82 typename gsSolid<T>::gsSolidHalfFaceHandle gsSolid<T>::addFace(std::vector<gsSolidHeVertexHandle> V)
83 {
84  if (V.size() != 4) //{ gsDebug<<"\n The following initialization of trimmed surf does not work for less or more than 4 corners yet\n";};
85  {
86  return addFace_PlanarPolygon(V);
87  }
88 
89  gsMatrix<T> corner = gsMatrix<T>(4,3);
90  for (unsigned i=0; i<=3; i++)
91  {
92  for (unsigned xi=0;xi<=2;xi++)
93  {
94  corner(i,xi) = (V[i]->coords)[xi];
95  }
96  }
97  //gsTrimSurface<T>* tsurf = new gsTrimSurface<T>(corner, 3, 3, 3);
98  gsTrimSurface<T>* tsurf = new gsTrimSurface<T>(corner, 1, 1, 1);
99  return addFace(V,tsurf);
100 }
101 
102 template<class T>
104 {
105  //apaga os vertices
106  freeAll( vertex );
107 
108  //apaga as arestas
109  freeAll( edge );
110 
111  //apaga as faces
112  freeAll( face );
113 
114  //apaga as faces
115  freeAll( volume );
116 }
117 
118 
119 template<class T>
120 typename gsSolid<T>::gsSolidHalfFaceHandle gsSolid<T>::addFace(std::vector<gsSolidHeVertexHandle> V, gsTrimSurface<T> * tsurf)
121 {
122  gsSolidHalfFaceHandle f = new gsSolidHalfFace<T>();
123  f->surf = tsurf;
124  std::vector<gsSolidHalfEdgeHandle> H;
125  for ( typename std::vector<gsSolidHeVertexHandle>::iterator
126  it = V.begin(); it!= V.end(); ++it)
127  {
128  // initialize the half-edge associated with the vertex *it and the face f
129  gsSolidHalfEdgeHandle tempHe = this->makeSolidHalfEdge(*it,f);
130  tempHe->setId(numHalfEdges++);
131  H.push_back( tempHe );
132  edge.push_back( tempHe );
133  // assign the incident halfedge associated with the vertex *it to *it
134  // fist check if hed is already assigned to avoid doubling assignments
135  if (!(*it)->hed)
136  (*it)->hed = tempHe;
137 
138  }
139  f->setBoundary( H );
140  face.push_back(f);
141  f->setId(numHalfFaces++);
142  return f;
143 }
144 
145 template<class T>
146 typename gsSolid<T>::gsSolidHalfFaceHandle gsSolid<T>::addFace(std::vector< std::vector<gsSolidHeVertexHandle> > loopV, gsTrimSurface<T> * tsurf)
147 {
148  gsSolidHalfFaceHandle f = new gsSolidHalfFace<T>();
149  f->surf = tsurf;
150  std::vector<gsSolidHalfEdgeHandle> H;
151 
152  std::vector<gsSolidHeVertexHandle> V;
153  for ( size_t il=0; il<loopV.size(); il++)
154  {
155  V=loopV[il];
156  H.clear();
157  for ( typename std::vector<gsSolidHeVertexHandle>::iterator
158  it = V.begin(); it!= V.end(); ++it)
159  {
160  // initialize the half-edge associated with the vertex *it and the face f
161  gsSolidHalfEdgeHandle tempHe = this->makeSolidHalfEdge(*it,f);
162  tempHe->setId(numHalfEdges++);
163  H.push_back( tempHe );
164  edge.push_back( tempHe );
165  // assign the incident halfedge associated with the vertex *it to *it
166  // fist check if hed is already assigned to avoid doubling assignments
167  if (!(*it)->hed)
168  (*it)->hed = tempHe;
169  }
170  f->setBoundary( H );
171  }
172 
173  face.push_back(f);
174  f->setId(numHalfFaces++);
175  return f;
176 }
177 
179 template<class T>
180 typename gsSolid<T>::gsSolidHalfFaceHandle gsSolid<T>::addFace_PlanarPolygon(std::vector<gsSolidHeVertexHandle> V)
181 {
182  // make sure there are at least 3 vertices.
183  int faceVerts = V.size();
184  assert(faceVerts >= 3);
185 
186  // compute normal to plane and make sure all vertices are in the plane.
187  // (find a vertex with minimal x-coordinate, and minimal y in the case of a tie.
188  // this ensures that the vertex is convex.)
189  int minVert = faceVerts - 1;
190  for(int i = 0; i < faceVerts - 1; i++)
191  {
192  if(V[i]->coords(0) < V[minVert]->coords(0) ||
193  (V[i]->coords(0) <= V[minVert]->coords(0) && V[i]->coords(1) < V[minVert]->coords(1)))
194  {
195  //gsDebug << "\n" << V[i]->coords(0) << "," << V[i]->coords(1) << "," << V[i]->coords(2);
196  minVert = i;
197  }
198  }
199  gsVector3d<T> prevVector = V[(minVert + faceVerts - 1) % faceVerts]->coords - V[minVert]->coords;
200 
201  gsVector3d<T> normal(0, 0, 0);
202  int nextVertex = minVert;
203  while(normal.squaredNorm() == 0)
204  {
205  nextVertex = (nextVertex + 1) % faceVerts;
206  assert(nextVertex != minVert); // failed to find a vertex that is not collinear with minVert and the one before it.
207  normal = (V[nextVertex]->coords - V[minVert]->coords).cross(prevVector);
208  }
209  normal.normalize();
210  for(int i = 3; i < faceVerts; i++)
211  {
212  assert((V[i]->coords - V[0]->coords).dot(normal) == 0);
213  }
214  T normalCoord = normal.dot(V[0]->coords);
215  //gsDebug << "\nNormal coefs: " << normal << std::endl << normalCoord;
216 
217  // compute a good transformation that we can use to generate
218  // corners in the 2D domain. We make an
219  // arbitrary vector b1 orthogonal to normal, then cross product it with normal
220  // to produce a second vector b2. {b1, b2} form a basis for the plane.
221  // use the dot product of a vertex's coordinates with b1 and b2 to produce
222  // 2D coordinates.
223 
224  gsVector3d<T> a1(1, 0, 0), a2(0, 1, 0);
225  a1 = a1.cross(normal);
226  a2 = a2.cross(normal);
227  gsVector3d<T> b1, b2;
228  if(a1.squaredNorm() > a2.squaredNorm())
229  {
230  b1 = a1;
231  }
232  else
233  {
234  b1 = a2;
235  }
236  b1.normalize();
237  b2 = normal.cross(b1);
238 
239  //gsDebug << "\nbasis for plane. b1=" << b1 << ", b2="<< b2;
240 
241  // make a matrix containing a list of (transposed) corners in the domain.
242  // compute a good rectangle for the domain of the base surface. do this by
243  // finding the bounding box and enlarging it by a fixed amount (margin) on
244  // each side.
245  T margin(0.1);
246  T x, y;
247  gsMatrix<T> DomCor(faceVerts + 1, 2);
248  for(int i = 0; i < faceVerts; i++)
249  {
250  // compute x and y coords and insert them into the matrix DomCor
251  x = b1.dot(V[i]->coords);
252  y = b2.dot(V[i]->coords);
253  //gsDebug << "\nvertex " << i << " coords in domain: " << x << "," << y;
254  DomCor(i, 0) = x;
255  DomCor(i, 1) = y;
256  }
257  DomCor(faceVerts, 0) = DomCor(0, 0);
258  DomCor(faceVerts, 1) = DomCor(0, 1);
259 
260  // find min and max x and y values (before resizing the polygon)
261  T minx = DomCor.col(0).minCoeff();
262  T maxx = DomCor.col(0).maxCoeff();
263  T miny = DomCor.col(1).minCoeff();
264  T maxy = DomCor.col(1).maxCoeff();
265  T rangex = maxx - minx, rangey = maxy - miny;
266  T midx = (minx + maxx) / (T)(2), midy = (miny + maxy) / (T)(2);
267  T halfMaxRange = std::max(rangex, rangey) * (margin * (T)(2) + (T)(1)) / (T)(2);
268  minx -= rangex * margin;
269  maxx += rangex * margin;
270  miny -= rangey * margin;
271  maxy += rangey * margin;
272 
273  // resize and shift to be inside [0,1]x[0,1]
275 
276  //gsDebug << "\nDomain rectangular bounds: [" << minx << "," << maxx << "] x [" << miny << "," << maxy << "]";
277 
278  // create a trimming loop and construct a planar domain from it.
279  gsCurveLoop<T> * tloop = new gsCurveLoop<T>();
280  for(int i = 0; i < faceVerts; i++)
281  {
282  gsMatrix<T> tcp(2, 2);
283  tcp << DomCor(i, 0), DomCor(i, 1), DomCor(i + 1, 0), DomCor(i + 1, 1);
284  gsBSpline<T> * tcurve = new gsBSpline<T>( 0, 1, 0, 1, give(tcp) );
285  tloop->insertCurve(tcurve);
286  }
287  gsPlanarDomain<T> * domain1= new gsPlanarDomain<T>(tloop);
288 
289  // create the basis
290 
291  gsKnotVector<T> KV1 = gsKnotVector<T>(0, 1, 0, 2);//multiplicity at ends==1+1
292  gsKnotVector<T> KV2 = gsKnotVector<T>(0, 1, 0, 2);//multiplicity at ends==1+1
293 
294  // unused variables:
295  //gsBSplineBasis<T> * Bu= new gsBSplineBasis<T>(KV1);
296  //gsBSplineBasis<T> * Bv= new gsBSplineBasis<T>(KV2);
297 
298  // produce a 4x3 matrix with the control points
299  // to map the 2D domain linearly into 3D.
300  gsMatrix<T> pcp(4, 3);
301  for(int xi = 0; xi < 3; xi++) // loop over coordinates
302  {
303  pcp(0, xi) = normal[xi] * normalCoord + (midx - halfMaxRange) * b1[xi] + (midy - halfMaxRange) * b2[xi];
304  pcp(1, xi) = normal[xi] * normalCoord + (midx + halfMaxRange) * b1[xi] + (midy - halfMaxRange) * b2[xi];
305  pcp(2, xi) = normal[xi] * normalCoord + (midx - halfMaxRange) * b1[xi] + (midy + halfMaxRange) * b2[xi];
306  pcp(3, xi) = normal[xi] * normalCoord + (midx + halfMaxRange) * b1[xi] + (midy + halfMaxRange) * b2[xi];
307  }
308  //gsDebug << "\nControl point matrix: " << pcp << "\n";
309  //gsDebug << "\nPolygon points: " << DomCor << "\n";
310  typename gsTensorBSpline<2,T>::Ptr tp1(new gsTensorBSpline<2,T>(KV1, KV2, give(pcp)));
311 
312  // instantiate and add the half-face object.
313 
314  gsTrimSurface<T> * ts = new gsTrimSurface<T>(tp1, domain1);
315  return addFace(V, ts);
316 
317 }
318 
319 template<class T>
321 {
322  // Method in the meantime: consider each pair of halfedges and see if they are mates
323  // Todo: consider each pair of faces
324  unsigned int noMate(0); // number of mates
325  for (typename std::vector<gsSolidHalfEdgeHandle>::iterator it1=edge.begin(); it1!=edge.end()-1; ++it1)
326  {
327  for (typename std::vector<gsSolidHalfEdgeHandle>::iterator it2=it1+1; it2!=edge.end(); ++it2)
328  {
329  // a pair of half edges are mates iff the source of one of them is the target of the orther
330  gsSolidHeVertexHandle source1, source2, target1, target2;
331  source1 = (*it1)->source;
332  source2 = (*it2)->source;
333  target1 = (*it1)->next->source;
334  target2 = (*it2)->next->source;
335  if (source1 == target2 && source2 == target1)
336  {
337  noMate++;
338  (*it1)->mate = *it2;
339  (*it2)->mate = *it1;
340  }
341  }
342  }
343  // check if the number of mates is the same as the number of assignments
344  if (2*noMate!=edge.size())
345  {
346 // gsDebug <<"\n"<<"The number of assignments of HE mates (="<< noMate <<") is NOT equal to number of edges (not halfedges) (="<< edge.size()/2 <<"), this is most likely because of the wrong order of the vertices of a face "<<"\n";
347 
348  gsWarn << "The number of assignments of HE mates (="<< noMate <<") is NOT equal to number of edges (not halfedges) (="<< edge.size()/2 <<"), this is most likely because of the wrong order of the vertices of a face, or the model is not a manifold\n";
349  }
350 }
351 
352 template<class T>
353 std::vector< typename gsSolid<T>::gsSolidHalfEdgeHandle > gsSolid<T>::detectNonConvexEdges(std::vector<int> const & ncEdgeV1, std::vector<int> const & ncEdgeV2)
354 {
355  // Todo: detect nonconvex edges automatically
356  size_t nEdge = ncEdgeV1.size();
357  gsSolidHalfEdgeHandle he;
358  assert(nEdge==ncEdgeV2.size());
359  std::vector<gsSolidHalfEdgeHandle> nce;
360  for (size_t i=0;i<nEdge;i++)
361  {
362  he = this->getVertexFromID(ncEdgeV1[i])->getHalfEdge( this->getVertexFromID(ncEdgeV2[i]) );
363  he->is_convex = false;
364  he->mate->is_convex = false;
365  nce.push_back(he);
366  }
367  return nce;
368 }
369 
370 
371 
372 
373 template <class T>
374 typename gsSolid<T>::gsSolidHalfFaceHandle gsSolid<T>::splitFace(
375  gsSolidHalfFaceHandle f,
376  gsSolidHeVertexHandle startVertex, gsSolidHeVertexHandle endVertex, gsBSpline<T> *domainSpline)
377 {
378  checkStructure();
379 
380  int numEdges = f->surf->domain().outer().size();
381  // search for a half-edge on this face whose source is endVertex
382  gsSolidHalfEdgeHandle nextEdge = endVertex->getHalfEdgeOnFace(f, false);
383  gsSolidHalfEdgeHandle matesPrev = nextEdge->prev;
384  int nextEdgeIdx = f->indexOfEdge(nextEdge);
385  // search for a half-edge whose end vertex (next->source) is startVertex
386  gsSolidHalfEdgeHandle prevEdge = startVertex->getHalfEdgeOnFace(f, true);
387  gsSolidHalfEdgeHandle matesNext = prevEdge->next;
388  int prevEdgeIdx = f->indexOfEdge(prevEdge);
389  // create a new half-edge
390  gsSolidHalfEdgeHandle newHE = this->makeSolidHalfEdge(startVertex, f);
391  newHE->face = f;
392  newHE->setId(numHalfEdges++);
393 
394  // close off the first part of this face off along the new half-edge
395  newHE->prev = prevEdge;
396  newHE->next = nextEdge;
397  prevEdge->next = newHE;
398  nextEdge->prev = newHE;
399  // create the half-edge's mate
400  gsSolidHalfEdgeHandle mate = this->makeSolidHalfEdge(endVertex, f);
401  newHE->mate = mate;
402  mate->mate = newHE;
403  mate->setId(numHalfEdges++);
404 
405  // close off the second part
406  mate->prev = matesPrev;
407  mate->next = matesNext;
408  matesPrev->next = mate;
409  matesNext->prev = mate;
410  // build a collection of edges for the new face
411  std::vector<gsSolidHalfEdgeHandle> newFaceBoundary;
412  newFaceBoundary.push_back(mate);
413  gsSolidHalfEdgeHandle tempEdge;
414  for(tempEdge = matesNext; tempEdge != mate; tempEdge = tempEdge->next)
415  {
416  newFaceBoundary.push_back(tempEdge);
417  }
418 
419  // create a reverse spline of domainSpline
420  std::vector<T> origKnots = domainSpline->knots();
421  std::vector<T> mateKnots;
422  mateKnots.reserve( origKnots.size() );
423  T flipPoint = (*origKnots.begin()) + (*origKnots.rbegin());
424  for(int i = origKnots.size() - 1; i >= 0; i--)
425  {
426  mateKnots.push_back(flipPoint - origKnots[i]);
427  }
428  gsKnotVector<T> mateKV(domainSpline->knots().degree(), mateKnots.begin(), mateKnots.end());
429  gsMatrix<T> mateCoefs = domainSpline->coefs().colwise().reverse();
430  gsBSpline<T> * reverseSpline = new gsBSpline<T>(mateKV, give(mateCoefs));
431 
432  // split the domain for the new face off from the old one
433  typename gsPlanarDomain<T>::uPtr newDomain =
434  f->surf->domain().split((prevEdgeIdx + 1) % numEdges, nextEdgeIdx, domainSpline, reverseSpline);
435  if(prevEdgeIdx > nextEdgeIdx)
436  {
437  // if startVertex is the source of the first edge, or is later in the cycle than endVertex,
438  // then the new face will contain loop[0]. The easiest thing to do is to reset loop[0] to
439  // the new start of f's cycle.
440  f->loop[0] = nextEdge;
441  }
442  typename gsSurface<T>::Ptr newBaseSurface = f->surf->getTP();
443 
444  // create the new face
445  gsTrimSurface<T> * newTS = new gsTrimSurface<T>(newBaseSurface , newDomain.release());
446 
447  // add the new face using existing half-edges. (calling addFace would re-add the edges)
448  // gsSolidHalfFace<T> * newFace = addFace(newFaceBoundary, newTS);
449  edge.push_back( newHE );
450  edge.push_back( mate );
451 
452  gsSolidHalfFaceHandle newFace = new gsSolidHalfFace<T>();
453  newFace->surf = newTS;
454  newFace->setBoundary( newFaceBoundary );
455  face.push_back(newFace);
456  newFace->setId(numHalfFaces++);
457  newFace->vol = f->vol;
458  newFace->vol->face.push_back(newFace);
459 
460  // update all the half-edges on the new face
461  tempEdge = mate;
462  do
463  {
464  tempEdge->face = newFace;
465  tempEdge = tempEdge->next;
466  } while(tempEdge != mate);
467 
468  checkStructure();
469 
470  return newFace;
471 }
472 
473 
474 template <class T>
476 {
477  gsMultiPatch<T> mp;
478  std::vector<gsCurve<T>*> loopv;
479  for (unsigned i=0;i!=numHalfFaces;i++)
480  {
481  loopv = face[i]->surf->domain().outer().curves();
482  for (unsigned j=0;j!=loopv.size();j++)
483  {
484  mp.addPatch(*loopv[j]);
485  }
486  }
487  return mp;
488 }
489 
490 template <class T>
491 gsVolumeBlock<T> *gsSolid<T>::newVolume(gsSolidHalfFaceHandle startingFace)
492 {
493  // set up the new volume
494  gsVolumeHandle newVol = new gsVolumeBlock<T>;
495  volume.push_back(newVol);
496  newVol->setId(numVolumes++);
497  // TODO: set the new volume's faces, and update the old volume's faces.
498  //newVol->face.push(startingFace);
499  // start the queue off with a single face
500  std::queue<gsSolidHalfFaceHandle> unprocessed;
501  unprocessed.push(startingFace);
502  std::set<gsSolidHalfFaceHandle> seen;
503  seen.insert(startingFace);
504  // process the queue
505  while(!unprocessed.empty())
506  {
507  // grab first face off the queue
508  gsSolidHalfFaceHandle nextFace = unprocessed.front();
509  unprocessed.pop();
510  // set the face's volume
511  nextFace->vol = newVol;
512  newVol->face.push_back(nextFace);
513  size_t numLoops = nextFace->loop.size();
514  // add all neighbours to the queue, if they haven't already been seen
515  for(size_t i = 0; i < numLoops; i++)
516  {
517  gsSolidHalfEdgeHandle firstEdge = nextFace->loop[i];
518  gsSolidHalfEdgeHandle nextEdge = firstEdge;
519  do
520  {
521  gsSolidHalfFaceHandle neighbFace = nextEdge->mate->face;
522  if(seen.find(neighbFace) == seen.end())
523  {
524  unprocessed.push(neighbFace);
525  seen.insert(neighbFace);
526  }
527  nextEdge = nextEdge->next;
528  } while(nextEdge != firstEdge);
529  }
530  }
531 
532  // process every volume's list of faces, keeping only faces with matching volume.
533  unsigned foundFaces = 0;
534  GISMO_ASSERT(numVolumes == volume.size(), "Number of volumes does not match");
535  for(size_t idxV = 0; idxV < numVolumes; idxV++)
536  {
537  size_t outF = 0;
538  size_t numF = volume[idxV]->face.size();
539  for(size_t inF = 0; inF < numF; inF++)
540  {
541  if(volume[idxV]->face[inF]->vol == volume[idxV])
542  {
543  volume[idxV]->face[outF] = volume[idxV]->face[inF];
544  outF++;
545  foundFaces++;
546  }
547  }
548  volume[idxV]->face.resize(outF);
549  }
550  GISMO_ASSERT(foundFaces == face.size() && foundFaces == numHalfFaces,
551  "Failed to assign a volume for all faces.");
552  return newVol;
553 }
554 
555 template <class T>
556 void gsSolid<T>::checkStructure(bool checkVerts) const
557 {
558  GISMO_UNUSED(checkVerts);
559  size_t numEdges = edge.size();
560  for(size_t idxE = 0; idxE < numEdges; idxE++)
561  {
562  gsSolidHalfEdgeHandle e = edge[idxE];
563  if (e->mate->mate != e) gsWarn<< "Inconsistent solid graph.\n";
564  GISMO_ASSERT(e->prev->target() == e->source, "Inconsistent solid graph");
565  GISMO_ASSERT(e->mate->face->vol == e->face->vol, "Inconsistent solid graph");
566  GISMO_ASSERT(e->next->face == e->face, "Inconsistent solid graph");
567  GISMO_ASSERT(e->next->prev == e, "Inconsistent solid graph");
568  GISMO_ASSERT(e->prev->next == e, "Inconsistent solid graph");
569  }
570 
571  // check that the trimmed surface data matches the info we have about the face
572  for(size_t idxF = 0; idxF < numHalfFaces; idxF++)
573  {
574  gsSolidHalfFace<T> *f = face[idxF];
575  gsTrimSurface<T> *surf = f->surf;
576  size_t numLoops = surf->domain().numLoops();
577  GISMO_ASSERT(numLoops == f->loop.size(), "Number of holes in face does not match corresponding trimmed surface");
578  for(size_t loopNum = 0; loopNum < numLoops; loopNum++)
579  {
580  gsSolidHalfEdge<T> *e = f->loop[loopNum];
581  const gsCurveLoop<T> & curveLoop = surf->domain().loop(loopNum);
582  size_t numCurves = curveLoop.size();
583  for(size_t curveNum = 0; curveNum < numCurves; curveNum++)
584  {
585  gsMatrix<T> surfCoord = surf->vertexCoord(loopNum, curveNum);
586  GISMO_ASSERT(!checkVerts ||
587  (surfCoord - e->source->coords).norm() < 0.0001, "Vertices in surface do not match vertex coordinates");
588 
589  const gsMatrix<T>& thisCurveCoefs = curveLoop.curve(curveNum).coefs();
590  gsMatrix<T> thisCurveEnd = thisCurveCoefs.row(thisCurveCoefs.rows() - 1);
591  const gsMatrix<T>& nextCurveCoefs = curveLoop.curve((curveNum + 1) % numCurves).coefs();
592  gsMatrix<T> nextCurveStart = nextCurveCoefs.row(0);
593  GISMO_ASSERT((thisCurveEnd - nextCurveStart).norm() < 0.0001, "gsCurveLoop did not close up");
594  e = e->next;
595  }
596  GISMO_ASSERT(e == f->loop[loopNum], "Face's loop did not close up properly");
597  }
598  }
599 }
600 
601 template <class T>
602 gsSolidHalfFace<T> *gsSolid<T>::addFaceWithMate(const std::vector<gsSolidHeVertexHandle> &verts, gsTrimSurface<T> *surf)
603 {
604  GISMO_ASSERT(verts.size() >= 2, "Unexpected number of vertices in new face");
605  checkStructure();
606 
607  std::vector<gsSolidHeVertexHandle> reorderedVerts;
608  reorderedVerts.push_back(verts[verts.size() - 1]);
609  for(size_t iV = 0; iV < verts.size() - 1; iV++)
610  {
611  reorderedVerts.push_back(verts[iV]);
612  }
613 
614  surf->cleanEndpoints(0.0000001);
615 
616  // special check to make sure the corners of the new trimmed surface actually
617  // match the coordinates of the vertex.
618  size_t numLoops = surf->domain().numLoops();
619  for(size_t loopNum = 0; loopNum < numLoops; loopNum++)
620  {
621  size_t numCurves = surf->domain().loop(loopNum).size();
622  for(size_t curveNum = 0; curveNum < numCurves; curveNum++)
623  {
624  gsMatrix<T> surfCoord = surf->vertexCoord(loopNum, curveNum);
625  GISMO_ASSERT((surfCoord - reorderedVerts[curveNum]->coords).norm() < 0.0001, "Vertices in surface do not match vertex coordinates");
626  }
627  }
628 
629  typedef typename gsTensorBSplineBasis<2,T>::GeometryType MasterSurface;
630  // Create a new master surface by taking this surface's one and flipping one coordinate.
631  gsTrimSurface<T> *surfReverse = new gsTrimSurface<T>(surf->getTP()->clone().release(), surf->domain().clone().release());
632  gsMatrix<T> &surfRevCoefs = surfReverse->getTP()->coefs();
633  MasterSurface *genGeom = dynamic_cast<MasterSurface *>(surfReverse->getTP().get());
634  GISMO_ASSERT(genGeom != NULL, "This procedure requires a gsGenericGeometry");
635  gsMatrix<T> revSupp = surfReverse->getTP()->support();
636  GISMO_ASSERT(revSupp.cols() == 2, "Unexpected support");
637 
638  gsMatrix<T> testPt(2,4);
639  testPt << 0.75 * revSupp(0, 0) + 0.25 * revSupp(0, 1), 0.75 * revSupp(0, 0) + 0.25 * revSupp(0, 1), 0.25 * revSupp(0, 0) + 0.75 * revSupp(0, 1), 0.25 * revSupp(0, 0) + 0.75 * revSupp(0, 1),
640  0.75 * revSupp(1, 0) + 0.25 * revSupp(1, 1), 0.25 * revSupp(1, 0) + 0.75 * revSupp(1, 1), 0.75 * revSupp(1, 0) + 0.25 * revSupp(1, 1), 0.25 * revSupp(1, 0) + 0.75 * revSupp(1, 1);
641  gsMatrix<T> testVal1;
642  genGeom->eval_into(testPt, testVal1);
643 
644  unsigned totalCPs = surfRevCoefs.rows();
645  unsigned dim = surfRevCoefs.cols();
646  unsigned blockSize = genGeom->basis().component(0).size();
647  for(unsigned blockStart = 0; blockStart < totalCPs; blockStart += blockSize) // note step size
648  {
649  surfRevCoefs.block(blockStart, 0, blockSize, dim) =
650  surfRevCoefs.block(blockStart, 0, blockSize, dim).colwise().reverse().eval();
651  }
652 
653  // test that the surface has been correctly reversed
654  gsMatrix<T> testVal2;
655  testPt << 0.25 * revSupp(0, 0) + 0.75 * revSupp(0, 1), 0.25 * revSupp(0, 0) + 0.75 * revSupp(0, 1), 0.75 * revSupp(0, 0) + 0.25 * revSupp(0, 1), 0.75 * revSupp(0, 0) + 0.25 * revSupp(0, 1),
656  0.75 * revSupp(1, 0) + 0.25 * revSupp(1, 1), 0.25 * revSupp(1, 0) + 0.75 * revSupp(1, 1), 0.75 * revSupp(1, 0) + 0.25 * revSupp(1, 1), 0.25 * revSupp(1, 0) + 0.75 * revSupp(1, 1);
657 
658  genGeom->eval_into(testPt, testVal2);
659  gsMatrix<T> origCoefs = surf->getTP()->coefs();
660  gsMatrix<T> testRevCoefs = surfReverse->getTP()->coefs();
661  GISMO_ASSERT((testVal2 - testVal1).norm() < 0.0001, "Surface was not correctly reversed");
662 
663  // Create new trimming loops by starting with this surfaces's one and
664  // (i) reversing the whole loop
665  // (ii) flipping one coordinate
666  numLoops = surfReverse->domain().numLoops();
667  for(size_t loopNum = 0; loopNum < numLoops; loopNum++)
668  {
669  gsCurveLoop<T> & revCurveLoop = surfReverse->domain().loop(loopNum);
670  size_t numCurves = revCurveLoop.size();
671  for(size_t curveNum = 0; curveNum < numCurves; curveNum++)
672  {
673  gsGeometry<T> & thisCurve = revCurveLoop.curve(curveNum);
674  gsMatrix<T> &curveCoefs = thisCurve.coefs();
675  curveCoefs = curveCoefs.colwise().reverse().eval();
676  size_t rows = curveCoefs.rows();
677  for(size_t cpIdx = 0; cpIdx < rows; cpIdx++)
678  {
679  curveCoefs(cpIdx, 0) = revSupp(0, 0) + revSupp(0, 1) - curveCoefs(cpIdx, 0);
680  }
681  }
682 
683  // reverse order of curves in the curve loop
684  std::reverse( revCurveLoop.curves().begin(), revCurveLoop.curves().end() );
685  }
686 
687  // the following loop is only for debugging purposes: check that curves are joined
688  for(size_t loopNum = 0; loopNum < numLoops; loopNum++)
689  {
690  const gsCurveLoop<T> & revCurveLoop = surfReverse->domain().loop(loopNum);
691  size_t numCurves = revCurveLoop.size();
692  for(size_t curveNum = 0; curveNum < numCurves; curveNum++)
693  {
694  // make sure each curve starts where the previous one ends
695  const gsGeometry<T> & thisCurve = revCurveLoop.curve(curveNum);
696  const gsGeometry<T> & nextCurve = revCurveLoop.curve((curveNum + 1) % numCurves);
697  gsMatrix<T> thisSupp = thisCurve.support();
698  gsMatrix<T> nextSupp = nextCurve.support();
699  gsMatrix<T> thisEndPt = nextCurve.eval(nextSupp.col(0));
700  gsMatrix<T> nextStartPt = thisCurve.eval(thisSupp.col(1));
701  GISMO_ASSERT((thisEndPt - nextStartPt).norm() < 0.0001, "Invalid curve loop");
702  // make sure corresponding points on the opposite faces have the same location in space
703  gsMatrix<T> thisCoord = surfReverse->vertexCoord(loopNum, curveNum);
704  gsMatrix<T> otherCoord = surf->vertexCoord(loopNum, (numCurves - curveNum) % numCurves);
705  GISMO_ASSERT((otherCoord - thisCoord).norm() < 0.0001, "Mate faces do not have matching vertices");
706  GISMO_ASSERT((otherCoord - reorderedVerts[(numCurves - curveNum) % numCurves]->coords).norm() < 0.0001, "Vertices in surface do not match vertex coordinates");
707  }
708  }
709 
710  // record the edge where we will start the updating process
711  gsSolidHalfEdgeHandle startEdge = reorderedVerts[0]->getHalfEdge(reorderedVerts[1]);
712  // duplicate all of the relevant vertices
713  std::vector<gsSolidHeVertexHandle> newVerts, newVertsReverse;
714  for(typename std::vector<gsSolidHeVertexHandle>::const_iterator iter = reorderedVerts.begin(); iter != reorderedVerts.end(); iter++)
715  {
716  addHeVertex((*iter)->coords(0), (*iter)->coords(1), (*iter)->coords(2));
717  newVerts.push_back(vertex[numVertices - 1]);
718  }
719  // reverse vertices start with vertex 0 and go back the other way
720  newVertsReverse.push_back(newVerts[0]);
721  for(int i = newVerts.size() - 1; i > 0; i--) newVertsReverse.push_back(newVerts[i]);
722  // create the first new face using the already existing vertices
723  gsSolidHalfFaceHandle frontFace = addFace(reorderedVerts, surf);
724  // create its mate using the duplicate vertices and the reverse trim surface
725  gsSolidHalfFaceHandle backFace = addFace(newVertsReverse, surfReverse);
726  backFace->vol = NULL;
727  // set faces as each others' mates
728  frontFace->mate = backFace;
729  backFace->mate = frontFace;
730  // make sure none of the vertices along the loop have their "hed" pointing
731  // into the new volume
732  size_t vertNum, numVerts = reorderedVerts.size();
733  for(vertNum = 0; vertNum < numVerts; vertNum++)
734  {
735  gsSolidHeVertex<T> *thisVert = reorderedVerts[vertNum];
736  gsSolidHeVertex<T> *nextVert = reorderedVerts[(vertNum + 1) % numVerts];
737  while(thisVert->hed->next->source != nextVert)
738  {
739  thisVert->hed = thisVert->hed->mate->next;
740  GISMO_ASSERT(thisVert->hed->source == thisVert, "Inconsistent solid graph");
741  }
742  thisVert->hed = thisVert->hed->mate->next;
743  GISMO_ASSERT(thisVert->hed->source == thisVert, "Inconsistent solid graph");
744  }
745  // loop over half-edges "he" in the loop
746  gsSolidHalfEdge<T> *he = startEdge;
747  vertNum = 0;
748  gsSolidHalfEdgeHandle newFrontFaceEdge = frontFace->loop[0];
749  while(newFrontFaceEdge->source != reorderedVerts[0]) newFrontFaceEdge = newFrontFaceEdge->next;
750  gsSolidHalfEdgeHandle newBackFaceEdge = backFace->loop[0];
751  while(newBackFaceEdge->source != newVerts[1]) newBackFaceEdge = newBackFaceEdge->next;
752  do
753  {
754  // set mates for the new front face
755  he->mate->mate = newFrontFaceEdge;
756  newFrontFaceEdge->mate = he->mate;
757  // set mates for the new back face
758  he->mate = newBackFaceEdge;
759  newBackFaceEdge->mate = he;
760  // set volume for the new back face (new front face's volume will
761  // get set later when we chase round the volume)
762  GISMO_ASSERT(backFace->vol == NULL || backFace->vol == he->face->vol, "Inconsistent solid graph");
763  backFace->vol = he->face->vol;
764  // set source
765  GISMO_ASSERT(newFrontFaceEdge->source == reorderedVerts[vertNum], "Inconsistent solid graph");
766  GISMO_ASSERT(newBackFaceEdge->source == newVerts[(vertNum + 1) % numVerts], "Inconsistent solid graph");
767  //if(he->source->hed == he) he->source->hed = newFrontFaceEdge;
768  //he->source = newVerts[vertNum];
769  // set up for the next edge
770  newFrontFaceEdge = newFrontFaceEdge->next;
771  newBackFaceEdge = newBackFaceEdge->prev;
772  vertNum++;
773  gsSolidHeVertexHandle nextVert = reorderedVerts[(vertNum + 1) % numVerts];
774  // loop round the edges coming out of this vertex, updating their source to the
775  // new vertex and looking for the next edge in the loop.
776  while(true) {
777  he = he->next;
778  GISMO_ASSERT(he->source->hed->source == he->source, "Inconsistent solid graph");
779  if(he->source->hed == he) he->source->hed = newFrontFaceEdge;
780  he->source = newVerts[vertNum % numVerts];
781  if(he->next->source == nextVert || he == startEdge) break;
782  GISMO_ASSERT(he->source->hed->source == he->source, "Inconsistent solid graph");
783  GISMO_ASSERT(he->prev->target() == he->source, "Inconsistent solid graph");
784  he = he->mate;
785  }
786  } while(he != startEdge);
787  // add the newly created back face to its volume's list (the front face will
788  // be assigned to a new volume when we call newVolume)
789  GISMO_ASSERT(backFace->vol != NULL, "Could not find the volume for mate face");
790  backFace->vol->face.push_back(backFace);
791 
792  // chase all the faces in the new volume, setting their volume member correctly
793  newVolume(frontFace);
794 
795  checkStructure();
796 
797 
798  // TODO: the following not always true, only do this temporarily
799  gsSolidHalfEdge<T>* he0;
800  he0 = frontFace->loop[0];
801  he = he0;
802  for (size_t i=0;i<this->nHalfEdges();i++)
803  {
804  he->is_convex = true;
805  he->mate->is_convex = true;
806  if (he->target()==he0->source) break;
807  he = he->next;
808  }
809 
810  he0 = frontFace->mate->loop[0];
811  he = he0;
812  for (size_t i=0;i<this->nHalfEdges();i++)
813  {
814  he->is_convex = true;
815  he->mate->is_convex = true;
816  if (he->target()==he0->source) break;
817  he = he->next;
818  }
819 
820  return frontFace;
821 }
822 
823 template <class T>
824 std::vector<typename gsSolid<T>::gsSolidHalfEdgeHandle > gsSolid<T>::impedingEdges(gsSolidHalfEdgeHandle he) const
825 {
826  //int vol = he->face->vol->getId();
827  // collect vertices of the two faces incident to the HE
828  std::vector<gsSolidHeVertexHandle> v0,v1;
829  gsSolidHalfFaceHandle face0 = he->face;
830  gsSolidHalfFaceHandle face1 = he->mate->face;
831  v0 = face0->getVertices();
832  v1 = face1->getVertices();
833  // remove two vertices of the HE from the two vertex sets
834  typename std::vector<gsSolidHeVertexHandle>::iterator it,it0,it1;
835  for (it = v0.begin();it!=v0.end();++it)
836  {
837  if ( ((*it)==he->source) || ((*it)==he->target()) )
838  {it0 = it;break;}
839  }
840  v0.erase(it0, it0 + 2);
841  for (it = v1.begin();it!=v1.end();++it)
842  {
843  if ( ((*it)==he->source) || ((*it)==he->target()) )
844  {it0 = it;break;}
845  }
846  v1.erase(it0, it0 + 2);
847  // check if each vertex in v0 is connected by a HE to another in v1
848  std::vector<gsSolidHalfEdgeHandle> iHE,vHE;
849  typename std::vector<gsSolidHalfEdgeHandle>::iterator ite;
850  for (it0 = v0.begin();it0!=v0.end();++it0)
851  {
852  vHE = (*it0)->halfEdges();
853  for (ite = vHE.begin();ite!=vHE.end();++ite)
854  {
855  for (it1 = v1.begin();it1!=v1.end();++it1)
856  {
857  if ( (*ite)->target()== *it1) iHE.push_back(*ite);
858  }
859 
860  }
861  }
862  return iHE;
863 }
864 
865 template <class T>
866 void gsSolid<T>::insertNewVertex(gsSolidHalfEdgeHandle he)
867 {
868  checkStructure();
869  gsSolidHalfEdgeHandle hem = he->mate;
870  gsSolidHalfFaceHandle face0,face1;
871  face0 = he->face;
872  face1 = he->mate->face;
873  size_t nFace = this->nHalfFaces();
874  bool convex = he->is_convex;
875  int heLoopN = he->loopN();
876  int hemLoopN = hem->loopN();
877  // adapting trimming structure of the two incident faces: first, face0:
878  size_t he_tCurveID = face0->indexOfEdge(he);
879  size_t hem_tCurveID = face1->indexOfEdge(hem);
880  gsMatrix<T> mid0 = face0->surf->splitCurve(he->loopN(), he_tCurveID);
881  gsMatrix<T> space0;
882  face0->surf->getTP()->eval_into(mid0.transpose(), space0);
883  // TODO: deal with possibility that the new vertex is on an inner loop
884  T nearestParam = face1->surf->nearestPoint(0, hem_tCurveID, 10, 10, space0);
885  gsMatrix<T> mid1 = face1->surf->splitCurve(hem->loopN(), hem_tCurveID, nearestParam);
886  gsMatrix<T> space1;
887  face1->surf->getTP()->eval_into(mid1.transpose(), space1);
888  //GISMO_ASSERT((space0 - space1).norm() < 0.0001, "Midpoints of curves do not match");
889  //denote:
890  // he->source----------newV-----------he->target()
891  // s-----------n-------------t
892  gsSolidHeVertexHandle s,n,t;
893  // create new HeVertex located at the midpoint between the two new trimmed surface corners
894  n = new gsSolidHeVertex<T>(
895  0.5 * (space0(0, 0) + space1(0, 0)),
896  0.5 * (space0(1, 0) + space1(1, 0)),
897  0.5 * (space0(2, 0) + space1(2, 0)),
898  this->nVertices());
899  // add n to the vertex list
900  (this->vertex).push_back(n);
901 
902  // add four new HEs: sn,ns,nt,tn
903  s = he->source;
904  t = he->target();
905  gsSolidHalfEdgeHandle sn = new gsSolidHalfEdge<T>(s,face0,nFace,convex,heLoopN);
906  gsSolidHalfEdgeHandle nt = new gsSolidHalfEdge<T>(n,face0,nFace+1,convex,heLoopN);
907  gsSolidHalfEdgeHandle tn = new gsSolidHalfEdge<T>(t,face1,nFace+2,convex,hemLoopN);
908  gsSolidHalfEdgeHandle ns = new gsSolidHalfEdge<T>(n,face1,nFace+3,convex,hemLoopN);
909  //
910  he->prev->next = sn;
911  sn->next = nt;
912  nt->next = he->next;
913  he->next->prev = nt;
914  nt->prev = sn;
915  sn->prev = he->prev;
916  //
917  hem->prev->next = tn;
918  tn->next = ns;
919  ns->next = hem->next;
920  hem->next->prev = ns;
921  ns->prev = tn;
922  tn->prev = hem->prev;
923  //
924  sn->mate = ns;
925  ns->mate = sn;
926  nt->mate = tn;
927  tn->mate = nt;
928  //
929  n->hed = nt;
930  this->edge.push_back(sn);
931  this->edge.push_back(nt);
932  this->edge.push_back(tn);
933  this->edge.push_back(ns);
934 
935  // reassign pointers to each loop of a face
936  if ((face0->loop).at(he->loopN())==he) (face0->loop).at(he->loopN()) = sn;
937  if ((face1->loop).at(he->mate->loopN())==he->mate) (face1->loop).at(he->mate->loopN()) = tn;
938 
939  // reassign HE pointers of s and t
940  if (s->hed == he) s->hed = he->prev->mate;
941  if (t->hed == hem) t->hed = hem->prev->mate;
942 
943  // remove the HE with larger ID
944  int idmax = he->getId();
945  if (he->mate->getId()>idmax) idmax=he->mate->getId();
946  int idmin = he->getId();
947  if (he->mate->getId()<idmin) idmin=he->mate->getId();
948  // recalculate ID for HEs
949  for (size_t i = idmax+1; i < this->nHalfEdges(); i++)
950  {
951  this->edge[i]->setId(i-1);
952  }
953  this->edge.erase(this->edge.begin() + idmax);
954  // remove the HE with smaller ID
955  for (size_t i = idmin+1; i < this->nHalfEdges(); i++)
956  {
957  this->edge[i]->setId(i-1);
958  }
959  this->edge.erase(this->edge.begin() + idmin);
960  //
961  this->numVertices = this->nVertices();
962  this->numHalfEdges = this->nHalfEdges();
963  this->numHalfFaces = this->nHalfFaces();
964  this->numVolumes = this->nVolumes();
965  gsDebug<<"A new vertex is added to the halfedge with source: "<<*he->source<<
966  " and target: "<<*he->target()<<std::endl;
967  delete he;
968  delete hem;
969  checkStructure();
970 }
971 
972 template <class T>
973 void gsSolid<T>::handleImpedingEdges(gsSolidHalfEdgeHandle he)
974 {
975  typename std::vector<gsSolidHalfEdgeHandle> iHe;
976  iHe=this->impedingEdges(he);
977  typename std::vector<gsSolidHalfEdgeHandle>::const_iterator it;
978  if (iHe.empty()==false)
979  {
980  for (it=iHe.begin();it!=iHe.end();++it)
981  {
982  this->insertNewVertex(*it);
983  }
984  }
985  checkStructure();
986 }
987 
988 } // namespace
index_t addPatch(typename gsGeometry< T >::uPtr g)
Add a patch from a gsGeometry&lt;T&gt;::uPtr.
Definition: gsMultiPatch.hpp:210
Knot vector for B-splines.
Abstract base class representing a geometry map.
Definition: gsGeometry.h:92
A fixed-size, statically allocated 3D vector.
Definition: gsVector.h:218
Class for a trim surface.
Definition: gsTrimSurface.h:33
#define gsDebug
Definition: gsDebug.h:61
gsVolumeBlock< T > * newVolume(gsSolidHalfFaceHandle startingFace)
Starting with a specified face, chase round all the faces connected to it and move them to a new volu...
Definition: gsSolid.hpp:491
A tensor product of d B-spline functions, with arbitrary target dimension.
Definition: gsTensorBSpline.h:44
void insertNewVertex(gsSolidHalfEdgeHandle he)
Insert a new vertex to an edge of the volume.
Definition: gsSolid.hpp:866
void handleImpedingEdges(gsSolidHalfEdgeHandle he)
If there are impeding edges that make the solid inseparatable along a given HE he, this routine will create a new vertex on each impeding edges.
Definition: gsSolid.hpp:973
Provides interface of gsTrimSurface class. Represents a trimmed surface (= spline &quot;master surface&quot; in...
Represents a tensor-product B-spline patch.
S give(S &x)
Definition: gsMemory.h:266
gsMatrix< T > eval(const gsMatrix< T > &u) const
Evaluate the function,.
Definition: gsFunctionSet.hpp:120
void checkStructure(bool checkVerts=false) const
sanity checks on the graph structure of the solid
Definition: gsSolid.hpp:556
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
A B-spline function of one argument, with arbitrary target dimension.
Definition: gsBSpline.h:50
gsSolidHalfFaceHandle addFace_PlanarPolygon(std::vector< gsSolidHeVertexHandle > V)
Add a planar face, specified by a list of vertices that should all be in the same plane...
Definition: gsSolid.hpp:180
std::vector< gsSolidHalfEdgeHandle > detectNonConvexEdges(std::vector< int > const &ncEdgeV1, std::vector< int > const &ncEdgeV2)
Define (TODO: detect automatically) nonconvex edges.
Definition: gsSolid.hpp:353
#define gsWarn
Definition: gsDebug.h:50
Provides declaration of the MultiPatch class.
void addHeVertex(scalar_t const &x, scalar_t const &y, scalar_t const &z=0)
add coords to gsHeVertex, not yet pointers to HEs
Definition: gsSolid.hpp:51
void freeAll(It begin, It end)
Frees all pointers in the range [begin end)
Definition: gsMemory.h:312
Container class for a set of geometry patches and their topology, that is, the interface connections ...
Definition: gsMultiPatch.h:33
KnotVectorType & knots(const int i=0)
Returns a reference to the knot vector.
Definition: gsBSpline.h:170
gsSolidHalfFaceHandle splitFace(gsSolidHalfFaceHandle f, gsSolidHeVertexHandle startVertex, gsSolidHeVertexHandle endVertex, gsBSpline< T > *domainSpline)
Definition: gsSolid.hpp:374
void setHeMate()
Assigning mates for each HE.
Definition: gsSolid.hpp:320
gsSolidHalfFaceHandle addFace(std::vector< gsSolidHeVertexHandle > V)
Definition: gsSolid.hpp:82
Represents a B-spline curve/function with one parameter.
static void adjustPolygonToUnitSquare(gsMatrix< T > &corners, T const margin)
Definition: gsCurveLoop.hpp:384
gsMultiPatch< T > plotEdgeGraph()
plot edge graph
Definition: gsSolid.hpp:475
Class representing a Planar domain with an outer boundary and a number of holes.
Definition: gsPlanarDomain.h:43
memory::shared_ptr< gsSurface > Ptr
Shared pointer for gsSurface.
Definition: gsSurface.h:35
gsMatrix< T > support() const
Returns the range of parameters (same as parameterRange())
Definition: gsGeometry.hpp:193
#define GISMO_UNUSED(x)
Definition: gsDebug.h:112
Class for representing a solid made up of vertices, edges, faces, and volumes.
Definition: gsSolid.h:32
Class for representing a knot vector.
Definition: gsKnotVector.h:79
A closed loop given by a collection of curves.
Definition: gsCurveLoop.h:36
virtual std::ostream & print(std::ostream &os) const
Prints the object as a string.
Definition: gsSolid.hpp:35
memory::shared_ptr< gsTensorBSpline > Ptr
Shared pointer for gsTensorBSpline.
Definition: gsTensorBSpline.h:59
Interface for gsCurveLoop class, representing a loop of curves, in anticlockwise order.
gsSolidHalfFace< T > * addFaceWithMate(const std::vector< gsSolidHeVertexHandle > &Verts, gsTrimSurface< T > *surf)
Make a face that can be used as the mate of the given face, add both faces and split off a new volume...
Definition: gsSolid.hpp:602
std::vector< gsSolidHalfEdgeHandle > impedingEdges(gsSolidHalfEdgeHandle he) const
Definition: gsSolid.hpp:824
Provides declaration of gsPlanarDomain class. The outer boundary (m_loops[0]) is a loop of curves...
gsMatrix< T > & coefs()
Definition: gsGeometry.h:340