G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
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>
23
25//#include <gsNurbs/gsBSplineBasis.h>
27
28#include <gsNurbs/gsBSpline.h>
29
30
31
32namespace gismo {
33
34template <class T>
35std::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
50template <class T>
51void 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
81template <class T>
82typename 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
102template<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
119template<class T>
120typename 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
145template<class T>
146typename 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
179template<class T>
180typename 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
319template<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
352template<class T>
353std::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
373template <class T>
374typename 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
474template <class T>
476{
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
490template <class T>
491gsVolumeBlock<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
555template <class T>
556void 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
601template <class T>
602gsSolidHalfFace<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
823template <class T>
824std::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
865template <class T>
866void 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
972template <class T>
973void 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
A B-spline function of one argument, with arbitrary target dimension.
Definition gsBSpline.h:51
KnotVectorType & knots(const int i=0)
Returns a reference to the knot vector.
Definition gsBSpline.h:170
A closed loop given by a collection of curves.
Definition gsCurveLoop.h:37
static void adjustPolygonToUnitSquare(gsMatrix< T > &corners, T const margin)
Definition gsCurveLoop.hpp:384
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
gsMatrix< T > & coefs()
Definition gsGeometry.h:340
gsMatrix< T > support() const
Returns the range of parameters (same as parameterRange())
Definition gsGeometry.hpp:193
Class for representing a knot vector.
Definition gsKnotVector.h:80
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
Container class for a set of geometry patches and their topology, that is, the interface connections ...
Definition gsMultiPatch.h:100
Class representing a Planar domain with an outer boundary and a number of holes.
Definition gsPlanarDomain.h:44
Class for representing a solid made up of vertices, edges, faces, and volumes.
Definition gsSolid.h:33
std::vector< gsSolidHalfEdgeHandle > detectNonConvexEdges(std::vector< int > const &ncEdgeV1, std::vector< int > const &ncEdgeV2)
Define (TODO: detect automatically) nonconvex edges.
Definition gsSolid.hpp:353
gsMultiPatch< T > plotEdgeGraph()
plot edge graph
Definition gsSolid.hpp:475
void insertNewVertex(gsSolidHalfEdgeHandle he)
Insert a new vertex to an edge of the volume.
Definition gsSolid.hpp:866
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
gsSolidHalfFaceHandle addFace(std::vector< gsSolidHeVertexHandle > V)
Definition gsSolid.hpp:82
void checkStructure(bool checkVerts=false) const
sanity checks on the graph structure of the solid
Definition gsSolid.hpp:556
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
void handleImpedingEdges(gsSolidHalfEdgeHandle he)
If there are impeding edges that make the solid inseparatable along a given HE he,...
Definition gsSolid.hpp:973
void setHeMate()
Assigning mates for each HE
Definition gsSolid.hpp:320
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
virtual std::ostream & print(std::ostream &os) const
Prints the object as a string.
Definition gsSolid.hpp:35
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
std::vector< gsSolidHalfEdgeHandle > impedingEdges(gsSolidHalfEdgeHandle he) const
Definition gsSolid.hpp:824
gsSolidHalfFaceHandle splitFace(gsSolidHalfFaceHandle f, gsSolidHeVertexHandle startVertex, gsSolidHeVertexHandle endVertex, gsBSpline< T > *domainSpline)
Definition gsSolid.hpp:374
memory::shared_ptr< gsSurface > Ptr
Shared pointer for gsSurface.
Definition gsSurface.h:35
A tensor product of d B-spline functions, with arbitrary target dimension.
Definition gsTensorBSpline.h:45
memory::shared_ptr< gsTensorBSpline > Ptr
Shared pointer for gsTensorBSpline.
Definition gsTensorBSpline.h:59
Class for a trim surface.
Definition gsTrimSurface.h:34
A fixed-size, statically allocated 3D vector.
Definition gsVector.h:219
Represents a B-spline curve/function with one parameter.
Interface for gsCurveLoop class, representing a loop of curves, in anticlockwise order.
#define gsDebug
Definition gsDebug.h:61
#define gsWarn
Definition gsDebug.h:50
#define GISMO_UNUSED(x)
Definition gsDebug.h:112
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Knot vector for B-splines.
Provides declaration of the MultiPatch class.
Provides declaration of gsPlanarDomain class. The outer boundary (m_loops[0]) is a loop of curves,...
Represents a tensor-product B-spline patch.
Provides interface of gsTrimSurface class. Represents a trimmed surface (= spline "master surface" in...
The G+Smo namespace, containing all definitions for the library.
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