G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsVolumeBlock.h
Go to the documentation of this file.
1 
15 #pragma once
16 
17 #include <gsModeling/gsSolid.h>
19 #include <gsModeling/gsFitting.h>
20 
21 #include <gsCore/gsVolume.h>
22 #include <gsCore/gsBoundary.h>
23 
24 
25 
26 namespace gismo {
27 
28 template <class T>
29 class gsVolumeBlock : public gsSolidElement<T>
30 {
31 public:
32  // to do change all types in gsModeling
33 
34  typedef gsSolidElement<T> SolidElement;
35  typedef typename SolidElement::scalar_t scalar_t;
36  typedef gsSolidHalfFace<T> HalfFace;
37  typedef gsSolidHalfEdge<T> HalfEdge;
38  typedef gsSolidHeVertex<T> Vertex;
39 
40 public:
41  gsVolumeBlock() : SolidElement() { }
42 
43  explicit gsVolumeBlock(int const& i) : SolidElement(i) { }
44 
45  explicit gsVolumeBlock(std::vector<HalfFace*> const & hfaces)
46  {
47  face = hfaces;
48  typename std::vector<HalfFace*>::const_iterator it;
49  for (it = hfaces.begin();it!=hfaces.end();++it)
50  {
51  (*it)->vol = this;
52  }
53  }
54 
55  virtual ~gsVolumeBlock()
56  { }
57 
58 public:
59 
66  boxSide getSideOfHexahedron(const unsigned faceId)
67  {
68  if (!isHexahedron())
69  {
70  GISMO_ERROR("VolumeBlock is not hexahedron.\n");
71  }
72 
73  HalfEdge* edge = face[0]->loop[0];
74  std::vector<HalfEdge* > hex; // hexahedrons initial HalfEdges
75  getHexEdges(hex, edge); // each side is presented with leading edge
76 
77  HalfFace* myFace = face[faceId];
78 
79  int sideIndex = -1; // resulting index of side - 1
80 
81  for (size_t edgeIndx = 0; edgeIndx < hex.size(); edgeIndx++)
82  {
83  HalfEdge* faceEdge = hex[edgeIndx];
84 
85  // checks if the edge e is in the face
86  HalfEdge* e = myFace->loop[0];
87  for (unsigned i = 0; i < 4; i++)
88  {
89  if (e == faceEdge)
90  {
91  sideIndex = static_cast<int>(edgeIndx);
92  }
93 
94  e = e->next;
95  }
96  }
97 
98  if (sideIndex == -1)
99  {
100  gsWarn << "Didn't transform face with id = " << faceId << "\n";
101  }
102 
103  return boxSide(sideIndex + 1);
104  }
105 
106 
107 
114  bool isHexahedron() const
115  {
116 
117  if (face.size() != 6)
118  {
119  return false;
120  }
121  else
122  {
123  for (unsigned idFace = 0; idFace != face.size(); idFace++)
124  {
125  HalfFace* myFace = face[idFace];
126 
127  if (1 < myFace->loopN())
128  {
129  gsWarn << "Input volume has a hole in its face. "
130  "Ignoring it...\n";
131  }
132 
133 
134  gsPlanarDomain<T>& domain = myFace->surf->domain();
135 
136  // first loop (loop(0)) describes outer boundary
137  gsCurveLoop<T>& curveLoop = domain.loop(0);
138 
139  if (curveLoop.numCurves() != 4)
140  return false;
141  }
142 
143  return true;
144  }
145  }
146 
148  gsTensorBSpline<3, T> getTensorBSplineVolume(int numSamplePoints,
149  int numInternalKnots,
150  int degree,
151  T lambda,
152  T eps)
153  {
154  if (!isHexahedron())
155  {
156  GISMO_ERROR("VolumeBlock is not hexahedron.\n"
157  "Function getVolume can not tranform VolumeBlock into "
158  "gsVolume if VolumeBlock is not hexahedron.\n");
159 
160  }
161 
162  gsMatrix<T> points;
163  gsMatrix<T> params;
164  //getUniformBoundaryPoints(numSamplePoints, params, points);
165  getUniformPoints(numSamplePoints, params, points, eps);
166 
167  gsKnotVector<T> kv1(0, 1, numInternalKnots, degree + 1, 1);
168  gsKnotVector<T> kv2(0, 1, numInternalKnots, degree + 1, 1);
169  gsKnotVector<T> kv3(0, 1, numInternalKnots, degree + 1, 1);
170 
171  gsTensorBSplineBasis<3, T> basis(kv1, kv2, kv3);
172 
173  gsDebugVar(kv1.detail());
174  gsDebugVar(basis);
175  gsFitting<T> fitting(params, points, basis);
176  fitting.compute(lambda);
177 
178  // maybee delete
179  std::vector<T> errors;
180  fitting.get_Error(errors, 1);
181  gsDebug << "Maximum error is: " << *std::max_element(errors.begin(),
182  errors.end())
183  << std::endl;
184 
185  // note gsFitting deletes the geomety in destructor
186  gsGeometry<T>* geo = fitting.result();
187 
188  gsTensorBSpline<3, T>* bspline = dynamic_cast<gsTensorBSpline<3, T>* > (geo);
189 
190  if (bspline == NULL)
191  {
192  GISMO_ERROR("Problems with casting gsGeometry to gsTensorBspline");
193  }
194 
195  return *bspline;
196  }
197 
198 
204  void getUniformPoints(const int n,
205  gsMatrix<T>& params,
206  gsMatrix<T>& points,
207  T eps)
208  {
209  gsMatrix<T> bParams, bPoints;
210  getUniformBoundaryPoints(n, bParams, bPoints, eps);
211 
212  typedef std::pair<std::pair<T, T>, T> tuple;
213 
214  // make a map for fast access
215  std::map<tuple, int> map;
216  for (int col = 0; col < bParams.cols(); col++)
217  {
218  tuple t = makeTuple(bParams(0, col), bParams(1, col), bParams(2, col));
219  map[t] = col;
220  }
221 
222  // save points at corners because they are used often
223  const gsVector<T> p000 = bPoints.col(map[makeTuple(0., 0., 0.)]);
224  const gsVector<T> p001 = bPoints.col(map[makeTuple(0., 0., 1.)]);
225  const gsVector<T> p010 = bPoints.col(map[makeTuple(0., 1., 0.)]);
226  const gsVector<T> p011 = bPoints.col(map[makeTuple(0., 1., 1.)]);
227  const gsVector<T> p100 = bPoints.col(map[makeTuple(1., 0., 0.)]);
228  const gsVector<T> p101 = bPoints.col(map[makeTuple(1., 0., 1.)]);
229  const gsVector<T> p110 = bPoints.col(map[makeTuple(1., 1., 0.)]);
230  const gsVector<T> p111 = bPoints.col(map[makeTuple(1., 1., 1.)]);
231 
232  const int numPoints = (n - 2) * (n - 2) * (n - 2) + bParams.cols();
233  params.resize(3, numPoints);
234  points.resize(3, numPoints);
235 
236  // Coons patch algorithm
237  int column = 0;
238  for (int indx = 1; indx != n - 1; indx++)
239  {
240  const T x = (indx * 1.0) / (n - 1);
241 
242  for (int indy = 1; indy != n - 1; indy++)
243  {
244  const T y = (indy * 1.0) / (n - 1);
245 
246  for (int indz = 1; indz != n - 1; indz++)
247  {
248  const T z = (indz * 1.0) / (n - 1);
249 
250  // parameters
251  params(0, column) = x;
252  params(1, column) = y;
253  params(2, column) = z;
254 
255  // points 3D Coons Patch Algorithm
256 
257  // interpolation of faces
258  const gsVector<T> A =
259  (1 - x) * bPoints.col(map[makeTuple(0, y, z)]) +
260  x * bPoints.col(map[makeTuple(1, y, z)]);
261 
262  const gsVector<T> B =
263  (1 - y) * bPoints.col(map[makeTuple(x, 0, z)]) +
264  y * bPoints.col(map[makeTuple(x, 1, z)]);
265 
266  const gsVector<T> C =
267  (1 - z) * bPoints.col(map[makeTuple(x, y, 0)]) +
268  z * bPoints.col(map[makeTuple(x, y, 1)]);
269 
270  // interpolation of boundary curves
271  const gsVector<T> AB =
272  (1 - x) * (1 - y) * bPoints.col(map[makeTuple(0, 0, z)]) +
273  (1 - x) * y * bPoints.col(map[makeTuple(0, 1, z)]) +
274  x * (1 - y) * bPoints.col(map[makeTuple(1, 0, z)]) +
275  x * y * bPoints.col(map[makeTuple(1, 1, z)]);
276 
277  const gsVector<T> BC =
278  (1 - y) * (1 - z) * bPoints.col(map[makeTuple(x, 0, 0)]) +
279  (1 - y) * z * bPoints.col(map[makeTuple(x, 0, 1)]) +
280  y * (1 - z) * bPoints.col(map[makeTuple(x, 1, 0)]) +
281  y * z * bPoints.col(map[makeTuple(x, 1, 1)]);
282 
283  const gsVector<T> AC =
284  (1 - x) * (1 - z) * bPoints.col(map[makeTuple(0, y, 0)]) +
285  (1 - x) * z * bPoints.col(map[makeTuple(0, y, 1)]) +
286  x * (1 - z) * bPoints.col(map[makeTuple(1, y, 0)]) +
287  x * z * bPoints.col(map[makeTuple(1, y, 1)]);
288 
289  // interpolation of corner points
290  const gsVector<T> ABC =
291  (1 - x) * ((1 - y) * ((1 - z) * p000 + z * p001) +
292  y * ((1 - z) * p010 + z * p011)) +
293  x * ((1 - y) * ((1 - z) * p100 + z * p101) +
294  y * ((1 - z) * p110 + z * p111));
295 
296  points.col(column) = A + B + C - AB - BC - AC + ABC;
297 
298  column++;
299  }
300  }
301  }
302 
303 
304  // append boundary points to
305  for (int col = 0; col < bPoints.cols(); ++col)
306  {
307  points.col(column) = bPoints.col(col);
308  params.col(column) = bParams.col(col);
309  column++;
310  }
311  }
312 
313 
318  void getUniformBoundaryPoints(const int n,
319  gsMatrix<T>& params3D,
320  gsMatrix<T>& points,
321  T eps = 1e-6)
322  {
323  HalfEdge* edge = face[0]->loop[0];
324  std::vector<HalfEdge* > hex; // hexahedrons initial HalfEdges
325  getHexEdges(hex, edge);
326 
327  int nmbOfPts = 6 * (n * n + 4); // 6 faces * number of points on faces
328  points .resize(3, nmbOfPts);
329  params3D.resize(3, nmbOfPts);
330 
331  gsVector<T> params1D(n);
332  for (int index = 0; index != n; index++)
333  {
334  params1D(index) = index * 1.0 / (n - 1);
335  }
336 
337  int column = 0;
338 
339  for (boxSide side = boxSide::getFirst(3); side<boxSide::getEnd(3); ++side )
340  {
341 
342  // this variable is true if we must turn around a curve loop in
343  // this side
344  bool turnAround = turnCurveLoopAround(side);
345  T fixedConstant = side.parameter() ? 1.0 : 0.0;
346 
347  // fixed - index of coordinate where parameter for this side has
348  // fixedConstant value
349  // first - index of coordinate where first curve in hexahedron has
350  // its range
351  // second - index of cooridnate where first curve in hexahedron is
352  // constant
353  int fixed = side.direction();
354  int first = (fixed == 0) ? 1 : 0;
355  int second = (fixed == 2) ? 1 : 2;
356 
357  if (fixed == 0) // east and west
358  {
359  int t = first;
360  first = second;
361  second = t;
362  }
363 
364 // gsDebug << "side: " << side << "\n"
365 // << "directions side: " << fixed << "\n"
366 // << "parameter: " << fixedConstant << "\n"
367 // << "first: " << first << "\n"
368 // << "seconde: " << second << "\n" << std::endl;
369 
370  std::vector<gsVector<T> > faceBoundaryParams;
371  HalfEdge* faceEdge = hex[side - 1];
372 
373 
374 
375  // compute uniform points on each curve
376  for (int curveId = 0; curveId < 4; curveId++)
377  {
378  HalfEdge* edge2 = faceEdge->moveAlongEdge(curveId);
379 
380  // gets index of a curve in Trimmed surface
381  int index = edge2->face->indexOfEdge(edge2);
382 
383  gsVector<T> params;
384  edge2->face->surf->getPhysicalyUniformCurveParameters(
385  0, index, n, params, eps);
386 
387 
388  gsMatrix<T> curvePoints;
389  edge2->face->surf->evalCurve_into(
390  0, index, params.transpose(), curvePoints);
391 
392 
393  bool turnCurve = turnCurveAround(turnAround, curveId);
394 
395  // curve has constant parameter along two dimensions
396  // (in parameter domain)
397  // - first constant is set by position of the face
398  // - second constant is set by position of the curve in
399  // curve loop
400  T curveConstant = 0.0;
401  if ( (turnAround && (curveId == 2 || curveId == 3)) ||
402  (!turnAround && (curveId == 1 || curveId == 2)) )
403  {
404  curveConstant = 1.0;
405  }
406 
407  // curveConstantIndex - index of parameter domain where curve
408  // is constant
409  // curveNonConstIndex - index of parameter domain where curve
410  // is not constant
411  int curveConstantIndex = first;
412  int curveNonConstIndex = second;
413  if (curveId == 0 || curveId == 2)
414  {
415  curveConstantIndex = second;
416  curveNonConstIndex = first;
417  }
418 
419 
420  for (int col = 0; col < n; col++)
421  {
422  params3D(fixed, column) = fixedConstant;
423  params3D(curveConstantIndex, column) = curveConstant;
424  params3D(curveNonConstIndex, column) = params1D(col);
425 
426  if (turnCurve)
427  {
428  points.col(column) = curvePoints.col(n - 1 - col);
429  }
430  else
431  {
432  points.col(column) = curvePoints.col(col);
433  }
434  column++;
435 
436 
437 // gsDebug << "side: " << side << " curveID: " << curveId
438 // << " turnCurve: " << turnCurve
439 // << " turnAround: " << turnAround << "\n"
440 // << "params: " << params3D.col(column - 1).transpose()
441 // << "\n"
442 // << "points: " << points.col(column - 1).transpose()
443 // << "\n" << std::endl;
444  }
445 
446  if (turnCurve)
447  {
448  params.reverseInPlace();
449  }
450 
451  faceBoundaryParams.push_back(params);
452  }
453 
454  // compute points in the interior of face
455 
456  // sometimes (depends on the orientation of the curve loop
457  // we must exchange 1 and 3 curve in coons patch algorithm
458  bool switch1and3curve = false;
459  if (side == boundary::east ||
460  side == boundary::front ||
461  side == boundary::north)
462  {
463  switch1and3curve = true;
464  }
465 
466  // first we compute parameter for surface via conns patch algorithm
467  // for given 4 boundary curves
468 
469  gsMatrix<T> cpParams; // coons patch parameters
470  modifiedCoonsPatch(hex[side - 1], faceBoundaryParams,
471  params1D, cpParams, switch1and3curve);
472 
473  gsMatrix<T> cpPoints;
474  faceEdge->face->surf->evalSurface_into(cpParams, cpPoints);
475 
476  // set global parameters and points
477  for (int indv = 0; indv != n - 2; indv++)
478  {
479  for (int indu = 0; indu != n - 2; indu++)
480  {
481  params3D(fixed, column) = fixedConstant;
482  params3D(first, column) = params1D(indu + 1);
483  params3D(second, column) = params1D(indv + 1);
484 
485  points.col(column) = cpPoints.col(indv * (n - 2) + indu);
486  column++;
487  }
488  }
489 
490  }
491  }
492 
493 
494 private:
495  static std::pair<std::pair<T, T>, T> makeTuple(T x, T y, T z)
496  {
497  return std::make_pair(std::make_pair(x, y), z);
498  }
499 
500 // static void printTuple(std::pair<std::pair<T, T>, T> tuple)
501 // {
502 // gsDebug << tuple.first.first << " " << tuple.first.second << " "
503 // << tuple.second;
504 // }
505 
519  void modifiedCoonsPatch(HalfEdge* edge,
520  const std::vector<gsVector<T> >& boundaryParams,
521  const gsVector<T>& params1D,
522  gsMatrix<T>& cpPoints,
523  const bool switch1and3curve)
524  {
525  int n = boundaryParams[0].size();
526  int m = boundaryParams[1].size();
527 
528  cpPoints.resize(2, (n - 2) * (m - 2));
529 
530  // eval all curves...
531  std::vector<gsMatrix<T> > values;
532  for (int curveId = 0; curveId != 4; curveId++)
533  {
534  HalfEdge* curveEdge = edge->moveAlongEdge(curveId);
535  int internalIndex = getInternalIndexOfCurve(curveEdge);
536  gsCurve<T>& curve = edge->face->surf->getCurve(0, internalIndex);
537 
538  gsMatrix<T> curvePoints;
539  curve.eval_into(boundaryParams[curveId].transpose(), curvePoints);
540  values.push_back(curvePoints);
541  }
542 
543  // save boundary points
544  gsVector<T> c00 = values[0].col(0);
545  gsVector<T> c01 = values[0].col(n - 1);
546 
547  gsVector<T> c20 = values[2].col(0);
548  gsVector<T> c21 = values[2].col(n - 1);
549 
550  // do the coons patch
551 
552  int column = 0;
553  // indv is index in "v direction", similar indu
554  for (int indv = 1; indv != n - 1; indv++) // ommit boundary
555  {
556  T v = params1D[indv];
557 
558 
559  for (int indu = 1; indu != m - 1; indu++)
560  {
561  T u = params1D[indu];
562  cpPoints.col(column) = (1 - v) * values[0].col(indu) +
563  v * values[2].col(indu)
564  - (1 - v) * (1 - u) * c00
565  - (1 - v) * u * c01
566  - v * (1 - u) * c20
567  - v * u * c21;
568 
569  gsVector<T> vec;
570  if (switch1and3curve)
571  {
572  vec = (1 - u) * values[3].col(indv) +
573  u * values[1].col(indv);
574  }
575  else
576  {
577  vec = (1 - u) * values[1].col(indv) +
578  u * values[3].col(indv);
579  }
580 
581  cpPoints.col(column) += vec;
582 
583 // gsDebug << "u: " << u << " v: " << v << "\n"
584 // << "indu: " << indu << " indv: " << indv << "\n"
585 // << "change1and2: " << switch1and3 << "\n";
586 
587 // gsMatrix<T> mat(2, 1);
588 // mat(0, 0) = cpPoints(0, column);
589 // mat(1, 0) = cpPoints(1, column);
590 // gsMatrix<T> res;
591 // edge->face->surf->evalSurface_into(mat, res);
592 
593 // gsDebug << "coons patch: " << res.transpose() << std::endl;
594 
595 // mat(0, 0) = values[0](0, indu);
596 // mat(1, 0) = values[0](1, indu);
597 // edge->face->surf->evalSurface_into(mat, res);
598 
599 // gsDebug << "curve0(indu): " << res.transpose() << std::endl;
600 
601 // mat(0, 0) = values[2](0, indu);
602 // mat(1, 0) = values[2](1, indu);
603 // edge->face->surf->evalSurface_into(mat, res);
604 
605 // gsDebug << "curve2(indu): " << res.transpose() << std::endl;
606 
607 // mat(0, 0) = values[1](0, indv);
608 // mat(1, 0) = values[1](1, indv);
609 // edge->face->surf->evalSurface_into(mat, res);
610 
611 // gsDebug << "curve1(indv): " << res.transpose() << std::endl;
612 
613 // mat(0, 0) = values[3](0, indv);
614 // mat(1, 0) = values[3](1, indv);
615 // edge->face->surf->evalSurface_into(mat, res);
616 
617 // gsDebug << "curve3(indv): " << res.transpose() << std::endl;
618 
619  column++;
620  }
621  }
622  }
623 
624 
629  static
630  bool turnCurveAround(const bool curveLoopAround, const int curveId)
631  {
632  if ( (!curveLoopAround && (curveId == 2 || curveId == 3)) ||
633  (curveLoopAround && (curveId == 0 || curveId == 3)) )
634  {
635  return true;
636  }
637  else
638  {
639  return false;
640  }
641  }
642 
643 
648  static
649  bool turnCurveLoopAround(boxSide side)
650  {
651  if (side == boundary::west ||
652  side == boundary::south ||
653  side == boundary::back)
654  {
655  return true;
656  }
657  else
658  {
659  return false;
660  }
661  }
662 
663 
664 
665 
667  int getInternalIndexOfCurve(HalfEdge* edge) const
668  {
669  return edge->face->indexOfEdge(edge);
670  }
671 
677  void getHexEdges(std::vector<HalfEdge*>& hex, HalfEdge* edge)
678  {
679  // set the west face as the first face of the volume
680  // and set the first edge of the west face as the first edge of the
681  // first face
682  hex.push_back(edge);
683 
684  hex.push_back(getEastEdge(edge));
685 
686  hex.push_back(getSouthEdge(edge));
687 
688  hex.push_back(getNorthEdge(edge));
689 
690  hex.push_back(getFrontEdge(edge));
691 
692  hex.push_back(getBackEdge(edge));
693 
694  }
695 
697  HalfEdge* getEastEdge(HalfEdge* edge)
698  {
699  edge = edge->next;
700  edge = edge->mate;
701  edge = edge->moveAlongEdge(2);
702  edge = edge->mate;
703  edge = edge->next;
704  return edge;
705  }
706 
708  HalfEdge* getSouthEdge(HalfEdge* edge)
709  {
710  edge = edge->mate;
711  edge = edge->prev;
712  return edge;
713  }
714 
716  HalfEdge* getNorthEdge(HalfEdge* edge)
717  {
718  edge = edge->moveAlongEdge(2);
719  edge = edge->mate;
720  edge = edge->next;
721  return edge;
722  }
723 
725  HalfEdge* getFrontEdge(HalfEdge* edge)
726  {
727  edge = edge->next;
728  edge = edge->mate;
729  edge = edge->next;
730  return edge;
731  }
732 
734  HalfEdge* getBackEdge(HalfEdge* edge)
735  {
736  edge = edge->prev;
737  edge = edge->mate;
738  edge = edge->prev;
739  return edge;
740  }
741 
742 
743 
744 public:
745  std::vector<HalfFace*> face;
746 };
747 
748 } // namespace gismo
#define gsDebug
Definition: gsDebug.h:61
static boxSide getFirst(short_t)
helper for iterating on sides of an n-dimensional box
Definition: gsBoundary.h:160
Provides structs and classes related to interfaces and boundaries.
Provides declaration of Volume abstract interface.
Provides declaration of data fitting algorithms by least squares approximation.
static boxSide getEnd(short_t dim)
helper for iterating on sides of an n-dimensional box
Definition: gsBoundary.h:176
#define gsWarn
Definition: gsDebug.h:50
Provides gsSolidElement class - interface for an element (vertex, edge or face) of a solid...
#define GISMO_ERROR(message)
Definition: gsDebug.h:118
Provides declaration of gsSolid class, a boundary-represented solid.