1 /** @file gsGeometry.h
2 
3     @brief Provides declaration of Geometry abstract interface.
4 
5     This file is part of the G+Smo library.
6 
7     This Source Code Form is subject to the terms of the Mozilla Public
8     License, v. 2.0. If a copy of the MPL was not distributed with this
9     file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11     Author(s): A. Mantzaflaris
12 */
13 
14 #pragma once
15 
16 #include <gsCore/gsFunction.h>
17 #include <gsCore/gsBoundary.h>
18 
19 
20 #define GISMO_BASIS_ACCESSORS \
21     Basis & basis() { return static_cast<Basis&>(*this->m_basis); } \
22     const Basis & basis() const { return static_cast<const Basis&>(*this->m_basis); }
23     // bool isProjective() const{ return Basis::IsRational; }
24 
25 namespace gismo
26 {
27 
28 /**
29     \brief
30     Abstract base class representing a geometry map.
31 
32     The combination of a basis with a coefficient matrix of the proper
33     size describes a function. Such objects are called geometries.
34 
35 
36     Note that geometries are, essentially, functions mapping from the
37     parameter domain to the physical space,
38 
39     \f[ G \ :\ \mathbb R^d \to \mathbb R^n \f]
40 
41     so that
42 
43     \f[ G(\hat x) = x \qquad \hat x \in \mathbb R^d, \ x \in \mathbb R^n \f]
44 
45     and therefore they derive from gsFunction. A gsGeometry can thus be
46     used wherever a gsFunction is expected.
47 
48     All geometry classes derive from the abstract base class
49     gsGeometry, see the \ref geometry.  In general, there is a
50     statically known one-to-one mapping between basis types and their
51     associated geometry types. For instance, when you ask a
52     gsBSplineBasis to create a geometry using some given coefficient
53     matrix, you will get back an instance of gsBSpline. In turn, the
54     basis that the gsBSpline object stores internally is of type
55     gsBSplineBasis.
56 
57     The parameter domain of the basis is also the parameter domain of
58     the geometry map, and has a certain source dimension \em d (see
59     gsGeometry::parDim()). Depending on the parameter domain
60     dimension, derived geometries inherit gsCurve, gsSurface, gsVolume
61     or gsBulk, for dimension 1,2,3 or 4, respectively.
62 
63     The dimension \em n of the resulting geometry,
64     i.e., of the image of the geometry map, is defined by the
65     size of the given coefficients, and may be larger than \em d
66     (see gsGeometry::geoDim()). $\,$
67 
68     For instance, for a B-spline basis (<em>d = 1</em>), we could
69     have coefficients of dimension <em>n = 1</em>, which results
70     in a parametrization of a 1-D interval, or we could have
71     coefficients of size <em>n = 3</em>, which results in a B-spline
72     curve in 3-D space.
73 
74     The coefficients are stored as an <em>s x n</em> matrix,
75     where \em s is the size of the basis, i.e., the number of
76     its basis functions.
77     Every row of the coefficient matrix is an *n*-dimensional control
78     point, i.e., the vector-valued coefficient for the associated
79     basis function.
80 
81     Evaluation at parameter values is done with
82     \ref func_eval_members "the Evaluation member functions" derived
83     from gsFunction.
84 
85     \tparam T coefficient type
86 
87     \ingroup function
88     \ingroup geometry
89     \ingroup Core
90 */
91 template<class T>
92 class gsGeometry : public gsFunction<T>
93 {
94 
95 public:
96     /// Shared pointer for gsGeometry
97     typedef memory::shared_ptr< gsGeometry > Ptr;
98 
99     /// Unique pointer for gsGeometry
100     typedef memory::unique_ptr< gsGeometry > uPtr;
101 
102     typedef T Scalar_t;
103 
104 public:
105 
106     /// @name Constructors
107     /// @{
108 
109     /// @brief Default constructor.  Note: Derived constructors (except for
110     /// the default) should assign \a m_basis to a valid pointer
gsGeometry()111     gsGeometry() :m_basis( NULL ), m_id(0)
112     { }
113 
114     /// @brief Constructor by a basis and coefficient vector
115     ///
116     /// Coefficients are given by \em{give(coefs) and they are
117     /// consumed, i.e. the \coefs variable will be empty after the call
gsGeometry(const gsBasis<T> & basis,gsMatrix<Scalar_t> coefs)118     gsGeometry( const gsBasis<T> & basis, gsMatrix<Scalar_t> coefs) :
119     m_basis(basis.clone().release()), m_id(0)
120     {
121         m_coefs.swap(coefs);
122         GISMO_ASSERT( basis.size() == m_coefs.rows(),
123                       "The coefficient matrix of the geometry (rows="<<m_coefs.rows()
124                       <<") does not match the number of basis functions in its basis("
125                       << basis.size() <<").");
126     }
127 
128     /// @brief Copy Constructor
gsGeometry(const gsGeometry & o)129     gsGeometry(const gsGeometry & o)
130     : m_coefs(o.m_coefs), m_basis(o.m_basis != NULL ? o.basis().clone().release() : NULL), m_id(o.m_id)
131     { }
132 
133     /// @}
134 
135     gsGeometry& operator=( const gsGeometry & o)
136     {
137         if ( this != &o )
138         {
139             m_coefs = o.m_coefs;
140             delete m_basis;
141             m_basis = o.basis().clone().release() ;
142             m_id = o.m_id;
143         }
144         return *this;
145     }
146 
~gsGeometry()147     virtual ~gsGeometry()
148     {
149         delete m_basis;
150     }
151 
152 #if EIGEN_HAS_RVALUE_REFERENCES
gsGeometry(gsGeometry && other)153     gsGeometry(gsGeometry&& other)
154     : m_coefs(std::move(other.m_coefs)), m_basis(other.m_basis),
155       m_id(std::move(other.m_id))
156     {
157         other.m_basis = NULL;
158     }
159     gsGeometry & operator=(gsGeometry&& other)
160     {
161         m_coefs.swap(other.m_coefs); other.m_coefs.clear();
162         delete m_basis;
163         m_basis = other.m_basis; other.m_basis = NULL;
164         m_id = std::move(other.m_id);
165         return *this;
166     }
167 #endif
168 
169 public:
170 
171     /**
172         @name Evaluation functions
173 
174         re-implemented from gsFunction, see also \ref func_eval_members
175         @{
176     */
177 
178     /** \brief Evaluate the function at points \a u into \a result.
179      *
180      * Let \em d be the dimension of the source space ( d = domainDim() ).\n
181      * Let \em n be the dimension of the image/target space ( n = targetDim() ).\n
182      * Let \em N denote the number of evaluation points.
183      *
184      * \param[in] u gsMatrix of size <em>d</em> x <em>N</em>, where each
185      * column of \em u represents one evaluation point.
186      * \param[out] result gsMatrix of size <em>n</em> x <em>N</em>, where each
187      * column of \em u represents the result of the function at the
188      * respective valuation point.
189      */
190     // Look at gsFunction class for documentation
eval_into(const gsMatrix<T> & u,gsMatrix<T> & result)191     void eval_into(const gsMatrix<T>& u, gsMatrix<T>& result) const
192     { this->basis().evalFunc_into(u, m_coefs, result); }
193 
194     /** \brief Evaluate derivatives of the function
195      * \f$f:\mathbb{R}^d\rightarrow\mathbb{R}^n\f$
196      * at points \a u into \a result.
197      *
198      * Let \em d be the dimension of the source space ( d = domainDim() ).\n
199      * Let \em n be the dimension of the image/target space ( n = targetDim() ).\n
200      * Let \em N denote the number of evaluation points.
201      *
202      * Let \f$ f:\mathbb R^2 \rightarrow \mathbb R^3 \f$, i.e.,
203      * \f$ f(x,y) = ( f^{(1)}(x,y), f^{(2)}(x,y), f^{(3)}(x,y) )^T\f$,\n
204      * and let
205      * \f$ u = ( u_1, \ldots, u_N) = ( (x_1,y_1)^T, \ldots, (x_N, y_N)^T )\f$.\n
206      * Then, \em result is of the form
207      * \f[
208      \left[
209      \begin{array}{cccc}
210         \partial_x f^{(1)}(u_1) & \partial_x f^{(1)}(u_2)
211            & \ldots & \partial_x f^{(1)}(u_N) \\
212         \partial_y f^{(1)}(u_1) & \partial_y f^{(1)}(u_2)
213            & \ldots & \partial_y f^{(1)}(u_N) \\
214         \partial_x f^{(2)}(u_1) & \partial_x f^{(2)}(u_2)
215            & \ldots & \partial_x f^{(2)}(u_N) \\
216         \partial_y f^{(2)}(u_1) & \partial_y f^{(2)}(u_2)
217            & \ldots & \partial_x f^{(2)}(u_N) \\
218         \partial_x f^{(3)}(u_1) & \partial_x f^{(3)}(u_2)
219            & \ldots & \partial_x f^{(3)}(u_N)\\
220         \partial_y f^{(3)}(u_1) & \partial_y f^{(3)}(u_2)
221            & \ldots & \partial_y f^{(3)}(u_N)
222      \end{array}
223      \right]
224      \f]
225      *
226      * \param[in] u gsMatrix of size <em>d</em> x <em>N</em>, where each
227      * column of \em u represents one evaluation point.
228      * \param[out] result gsMatrix of size <em>(d * n)</em> x <em>N</em>.
229      * Each row of \em result corresponds to one component in the target
230      * space and contains the gradients for each evaluation point,
231      * as row vectors, one after the other (see above for details on the format).
232      *
233      * \warning By default, gsFunction uses central finite differences
234      * with h=0.00001! One must override this function in derived
235      * classes to get proper results.
236      */
237     // Look at gsFunction class for documentation
deriv_into(const gsMatrix<T> & u,gsMatrix<T> & result)238     void deriv_into(const gsMatrix<T>& u, gsMatrix<T>& result) const
239     { this->basis().derivFunc_into(u, m_coefs, result); }
240 
241 
242     /** @brief Evaluate second derivatives of the function at points \a u into \a result.
243      *
244      * Let \em d be the dimension of the source space ( d = domainDim() ).\n
245      * Let \em n be the dimension of the image/target space ( n = targetDim() ).\n
246      * Let \em N denote the number of evaluation points.
247      *
248      * \param[in] u gsMatrix of size <em>d</em> x <em>N</em>, where each
249      * column of \em u represents one evaluation point.
250      * \param[out] result gsMatrix of size <em>(S*n)</em> x <em>N</em>,
251      * where <em>S=d*(d+1)/2</em>.\n
252      * Each column in \em result corresponds to one point (i.e., one column in \em u)\n
253      * and contains the following values (for <em>d=3</em>, <em>n=3</em>):\n
254      * \f$ (\partial_{xx} f^{(1)}, \partial_{yy} f^{(1)}, \partial_{zz} f^{(1)}, \partial_{xy} f^{(1)},
255        \partial_{xz} f^{(1)}, \partial_{yz} f^{(1)}, \partial_{xx} f^{(2)},\ldots,\partial_{yz} f^{(3)} )^T\f$
256      * \warning By default uses central finite differences with h=0.00001!
257      * One must override this function in derived
258      * classes to get proper results.
259      */
260     // Look at gsFunctionSet class for documentation
deriv2_into(const gsMatrix<T> & u,gsMatrix<T> & result)261     void deriv2_into(const gsMatrix<T>& u, gsMatrix<T>& result) const
262     { this->basis().deriv2Func_into(u, m_coefs, result); }
263 
evalAllDers_into(const gsMatrix<T> & u,int n,std::vector<gsMatrix<T>> & result)264     void evalAllDers_into(const gsMatrix<T> & u, int n,
265                           std::vector<gsMatrix<T> > & result) const
266     { this->basis().evalAllDersFunc_into(u, m_coefs, n, result); }
267 
268     /// @}
269 
270 
271     // Look at gsFunctionSet for documentation
272     virtual void compute(const gsMatrix<T> & in, gsFuncData<T> & out) const;
273 
274     /// \brief Evaluates if the geometry orientation coincide with the
275     /// ambient orientation.
276     /// This is computed in the center of the parametrization and will
277     /// fail to be meaningful if the geometry is singular.
278     /// returns one if codimension is not zero
orientation()279     int orientation() const
280     {
281         if ( parDim() == geoDim() )
282         {
283             const T val = gsFunction<T>::jacobian( parameterCenter() ).determinant();
284             return (T(0) < val) - (val < T(0));
285         }
286         return 1;
287     }
288 
289     /// @}
290 
291     /*************************************************************************/
292 
293     /// @name Accessors
294     /// @{
295 
296     /// \brief Returns a const reference to the basis of the geometry.
297     /// \note This function will return the derived concrete type of the basis.
298     virtual const gsBasis<T> & basis() const = 0;
299 
300     /// \brief Returns a reference to the basis of the geometry.
301     /// \note This function will return the derived concrete type of the basis.
302     virtual       gsBasis<T> & basis()       = 0;
303 
304     /// Dimension of the ambient physical space (overriding gsFunction::targetDim())
targetDim()305     short_t targetDim() const { return this->coefDim(); }
306 
307     /// Dimension \em n of the coefficients (control points)
coefDim()308     short_t coefDim() const { return static_cast<short_t>(m_coefs.cols()); }
309 
310     /// Dimension \em n of the absent physical space
geoDim()311     short_t geoDim() const { return this->coefDim(); }
312 
313     /// Dimension \em d of the parameter domain (overriding gsFunction::domainDim()).
domainDim()314     virtual short_t domainDim() const { return this->basis().domainDim(); }
315 
316     /// Dimension \em d of the parameter domain (same as domainDim()).
parDim()317     short_t parDim() const { return this->basis().domainDim(); }
318 
319     /// Co-dimension of the geometric object
coDim()320     short_t coDim() const { return coefDim()-this->basis().domainDim(); }
321 
322     /// Returns the range of parameters (same as parameterRange())
support()323     gsMatrix<T> support() const
324     { return this->basis().support(); }
325 
326     /// Returns the range of parameters as a matrix with two columns, [lower upper]
parameterRange()327     gsMatrix<T> parameterRange() const
328     { return this->basis().support(); }
329 
330     /// Returns a "central" point inside inside the parameter domain
parameterCenter()331     virtual gsMatrix<T> parameterCenter() const
332     {
333         // default impl. assumes convex support
334         gsMatrix<T> S = this->basis().support();
335         return ( S.col(0) + S.col(1) ) * T(0.5);
336     }
337 
338     /// Get coordinates of the boxCorner \a bc in the parameter domain
339     gsMatrix<T> parameterCenter( const boxCorner& bc );
340 
341     /// Get coordinates of the midpoint of the boxSide \a bs in the parameter domain
342     gsMatrix<T> parameterCenter( const boxSide& bs );
343 
344     /// Get back the side of point \a u
345     //boxSide sideOf(const gsVector<T> & u); //
346 
347     /// Check if points \a u also lie on the geometry and if required computes the if the points in \a u lie on one of the boundaries of the geometry
348     /**
349      *
350      * @param u Matrix of points of the form geoDim() x #points
351      * @param onG2 gsVector of booleans which indicate if the point is in the domain or outside
352      * @param preIm Matrix of preimages of the points u
353      * @param lookForBoundary if required the boundaries are computed the points in u lie on
354      * @return A std::vector of boxSides containing the numbers of the sides or zero if the points are in the interior
355      * If the flag lookForBoundary is not set then a vector containing anything will be returned
356      */
357     std::vector<boxSide> locateOn(const gsMatrix<T> & u, gsVector<bool> & onG2, gsMatrix<T> & preIm, bool lookForBoundary = false, real_t tol = 1.e-6) const; //
358 
359     // Whether the coefficients of this geometry are stored in projective or affine form
360     //virtual bool isProjective() const = 0;
361 
362     /// @}
363 
364     /*************************************************************************/
365 
366     /** @name Coefficient access functions
367 
368         These functions allow direct access to the coefficient matrix of the geometry.
369         @{
370     */
371 
372     /// Returns the coefficient matrix of  the geometry
373     /// Coefficient matrix of size coefsSize() x geoDim()
374     // todo: coefsSize() x (geoDim() + 1) if projective
coefs()375           gsMatrix<T> & coefs()       { return this->m_coefs; }
376 
377     /// Returns the coefficient matrix of  the geometry
coefs()378     const gsMatrix<T> & coefs() const { return this->m_coefs; }
379 
380     /// Returns the i-th coefficient of the geometry as a row expression
coef(index_t i)381     typename gsMatrix<T>::RowXpr       coef(index_t i)       { return m_coefs.row(i); }
382 
383     /// Returns the i-th coefficient of the geometry as a row expression
coef(index_t i)384     typename gsMatrix<T>::ConstRowXpr  coef(index_t i) const { return m_coefs.row(i); }
385 
386     /// Returns the j-th coordinate of the i-th coefficient of the geometry
coef(index_t i,index_t j)387     T & coef(index_t i, index_t j)
388     {
389         GISMO_ASSERT( ((i < m_coefs.rows()) && (j < m_coefs.cols()) ),
390                       "Coefficient or coordinate which is out of range requested.");
391         return m_coefs(i,j);
392     }
393 
394     /// Returns the j-th coordinate of the i-th coefficient of the geometry
coef(index_t i,index_t j)395     const T coef(index_t i, index_t j) const
396     {
397         GISMO_ASSERT( ((i < m_coefs.rows()) && (j < m_coefs.cols()) ),
398                       "Coefficient or coordinate which is out of range requested.");
399         return m_coefs(i,j);
400     }
401 
402     /// Set the coefficient matrix of the geometry, taking ownership of the matrix
setCoefs(gsMatrix<T> cc)403     void setCoefs(gsMatrix<T> cc) { this->m_coefs.swap(cc); }
404 
405     /// Return the number of coefficients (control points)
coefsSize()406     unsigned coefsSize() const { return m_coefs.rows(); }
407     // Warning: This can cause some clash while using periodic basis, since the ghost coefs are stored but ignored.
408 
409 
410 
411     /// @}
412 
413     /*************************************************************************/
414 
415     /** @name Transformation functions
416 
417         These functions apply various linear and affine transformations
418         to the coefficients.
419         @{
420     */
421 
422     /// Apply the given square matrix to every control point.
linearTransform(const gsMatrix<T> & mat)423     void linearTransform(const gsMatrix<T>& mat)
424     {
425         this->m_coefs = this->m_coefs * mat.transpose();
426     }
427 
428     /// Apply 3D Rotation by \a angle radians around axis \a axis
rotate(T angle,const gsVector<T,3> & axis)429     void rotate(T angle, const gsVector<T,3> & axis )
430     {
431         assert( geoDim() == 3 );
432         Eigen::Transform<T,3,Eigen::Affine>
433             rot( Eigen::AngleAxis<T> (angle,axis.normalized()) );
434         // To do: Simpler way to use transforms ?
435         this->m_coefs = (this->m_coefs.rowwise().homogeneous() *
436                          rot.matrix().transpose() ).leftCols(3) ;
437     }
438 
439     /// Apply 2D Rotation by \a angle radians
rotate(T angle)440     void rotate(T angle)
441     {
442         GISMO_ASSERT( geoDim() == 2, "Only for 2D");
443         Eigen::Rotation2D<T> rot(angle);
444         this->m_coefs *= rot.matrix().transpose();
445     }
446 
447     /// Apply Scaling by factor \a s
448     void scale(T s, int coord = -1)
449     {
450         if ( coord == -1) // Uniform scaling
451             this->m_coefs *= s;
452         else if ( coord <geoDim() )//scale coordinate coord
453             this->m_coefs.col(coord) *= s;
454     }
455 
456     /// Apply Scaling coord-wise by a vector v
scale(gsVector<T> const & v)457     void scale(gsVector<T> const & v)
458     {
459         GISMO_ASSERT( v.rows() == this->m_coefs.cols(), "Sizes do not agree." );
460         this->m_coefs.array().rowwise() *= v.array().transpose();
461     }
462 
463     /// Apply translation by vector v
translate(gsVector<T> const & v)464     void translate(gsVector<T> const & v)
465     {
466         this->m_coefs.rowwise() += v.transpose();
467     }
468 
469     /// \brief Returns the control point at corner \a c
470     typename gsMatrix<T>::RowXpr
471     coefAtCorner(boxCorner const & c);
472 
473     /// \brief Returns the control point at corner \a c
474     typename gsMatrix<T>::ConstRowXpr
475     coefAtCorner(boxCorner const & c) const;
476 
477     /// @}
478 
479     /*************************************************************************/
480 
481     /// @name Other miscellaneous functions
482     /// @{
483 
484     /// Refine the geometry uniformly, inserting \a numKnots new knots into each knot span
485     virtual void uniformRefine(int numKnots = 1, int mul=1) // todo: int dir = -1
486     {
487         this->basis().uniformRefine_withCoefs( m_coefs, numKnots, mul);
488     }
489 
490     /** \brief Refines the basis and adjusts the coefficients to keep the geometry the same.
491      *
492      * The syntax of \em boxes depends on the implementation in the
493      * underlying basis. See gsBasis::refineElements_withCoefs() for details.
494      */
refineElements(std::vector<index_t> const & boxes)495     void refineElements( std::vector<index_t> const & boxes )
496     {
497         this->basis().refineElements_withCoefs(this->m_coefs, boxes );
498     }
499 
coord(const index_t c)500     typename gsGeometry::uPtr coord(const index_t c) const {return this->basis().makeGeometry( this->coefs().col(c) ); }
501 
502     /// Embeds coefficients in 3D
embed3d()503     void embed3d()
504     {
505         embed(3);
506     }
507 
508     /// \brief Embeds coefficients in \a N dimensions
509     ///For the new dimensions zeros are added (or removed) on the
510     /// right (if \a pad_right is true) or on the left (if \a
511     /// pad_right is false)
512     void embed(index_t N, bool pad_right = true)
513     {
514         GISMO_ASSERT( N > 0, "Embed dimension must be positive");
515 
516         const index_t nc = N - m_coefs.cols();
517         if ( nc == 0 ) return;
518 
519         if (!pad_right && nc<0)
520             m_coefs.leftCols(N) = m_coefs.rightCols(N);
521         m_coefs.conservativeResize(Eigen::NoChange, N);
522 
523         if ( nc > 0 )
524         {
525             if (pad_right)
526                 m_coefs.rightCols(nc).setZero();
527             else
528             {
529                 m_coefs.rightCols(N-nc) = m_coefs.leftCols(N-nc);
530                 m_coefs.leftCols(nc).setZero();
531             }
532         }
533 #       ifndef NDEBUG
534         else gsWarn<<"Coefficients projected (deleted)..\n";
535 #       endif
536     }
537 
538     /// \brief Returns the degree wrt direction i
degree(const short_t & i)539     short_t degree(const short_t & i) const
540      //{ return this->basisComponent(i).degree(); };
541      { return this->basis().degree(i); }
542 
543     /// \brief Elevate the degree by the given amount \a i for the
544     /// direction \a dir. If \a dir is -1 then degree elevation is
545     /// done for all directions
546     virtual void degreeElevate(short_t const i = 1, short_t const dir = -1);
547 
548     /// \brief Reduces the degree by the given amount \a i for the
549     /// direction \a dir. If \a dir is -1 then degree reduction is
550     /// done for all directions
551     virtual void degreeReduce(short_t const i = 1, short_t const dir = -1);
552 
553     /// Compute the Hessian matrix of the coordinate \a coord
554     /// evaluated at points \a u
555     virtual void hessian_into(const gsMatrix<T>& u, gsMatrix<T> & result,
556                               index_t coord) const;
557 
558     /// Return the control net of the geometry
controlNet(gsMesh<T> & mesh)559     void controlNet( gsMesh<T> & mesh) const
560     { basis().connectivity(m_coefs, mesh); }
561 
562     /// @brief Computes the outer normals at parametric points \a u.
563     ///
564     /// Assumes that \a u is a list of points on the boundary of the geometry.
565     void outerNormal_into(const gsMatrix<T>& u, gsMatrix<T> & result) const;
566 
567     /// Get boundary of this geometry as a vector of new gsGeometry instances
568     std::vector<gsGeometry *> boundary() const;
569 
570     /// Get parametrization of boundary side \a s as a new gsGeometry uPtr.
571     typename gsGeometry::uPtr boundary(boxSide const& s) const;
572 
573     /// Computes and returns the interface with \a other as a new geometry
574     virtual typename gsGeometry::uPtr iface(const boundaryInterface & bi,
575                                             const gsGeometry & other) const;
576 
577     /// Get parametrization of box component \a bc as a new gsGeometry uPtr.
578     typename gsGeometry::uPtr component(boxComponent const& bc) const;
579 
GISMO_UPTR_FUNCTION_PURE(gsGeometry,clone)580     GISMO_UPTR_FUNCTION_PURE(gsGeometry, clone)
581 
582     /// Prints the object as a string.
583     virtual std::ostream &print(std::ostream &os) const
584     {
585         os << "Geometry "<< "R^"<< this->parDim() <<
586             " --> R^"<< this->geoDim()<< ", #control pnts= "<< coefsSize() <<
587             ": "<< coef(0) <<" ... "<< coef(this->coefsSize()-1);
588         os<<"\nBasis:\n" << this->basis() ;
589         return os;
590     }
591 
592     /// Merge the given \a other geometry into this one.
593     virtual void merge( gsGeometry * other );
594 
595     virtual void toMesh(gsMesh<T> & msh, int npoints) const;
596 
597     /// Updates the vertices of input \a mesh by evaluating the
598     /// geometry at vertices.
599     ///  Vertices of the new mesh are
600     ///
601     /// { geom(v) | v vertex of input mesh }
602     ///
603     void evaluateMesh(gsMesh<T>& mesh) const;
604 
605 
606     /// Splits the geometry 2^d parts, where each direction is divided into two parts in
607     /// in a uniform way, i.e., in the middle of the corresponding side. This method
608     /// allocated new space for each new geometry, the original one stays unchanged.
609     virtual std::vector<gsGeometry<T>* > uniformSplit(index_t dir =-1 ) const;
610 
611     /// @}
612 
613     /// Gives back an isoParametric slice of the geometry with fixed
614     /// \a par in direction \a dim_fixed as an gsGeometrySlice object.
615     gsGeometrySlice<T> getIsoParametricSlice(index_t dir_fixed, T par) const;
616 
617     /// Takes the physical \a points and computes the corresponding
618     /// parameter values.  If the point cannot be inverted (eg. is not
619     /// part of the geometry) the corresponding parameter values will be undefined
620     virtual void invertPoints(const gsMatrix<T> & points, gsMatrix<T> & result,
621                               const T accuracy = 1e-6,
622                               const bool useInitialPoint = false) const;
623 
624     /// Returns the parameters of closest point to \a pt
625     void closestPointTo(const gsVector<T> & pt,
626                         gsVector<T> & result,
627                         const T accuracy = 1e-6,
628                         const bool useInitialPoint = false) const;
629 
630     /// Sets the patch index for this patch
setId(const size_t i)631     void setId(const size_t i) { m_id = i; }
632 
633     /// Returns the patch index for this patch
id()634     size_t id() const { return m_id; }
635 
636 
637 protected:
swap(gsGeometry & other)638     void swap(gsGeometry & other)
639     {
640         std::swap(m_basis, other.m_basis);
641         m_coefs.swap(other.m_coefs);
642         std::swap(m_id, other.m_id);
643     }
644 
645 protected:
646 
647     /// Coefficient matrix of size coefsSize() x geoDim()
648     //todo: coefsSize() x (geoDim() + 1) if projective
649     gsMatrix<T> m_coefs;
650 
651     /// Pointer to the basis of this geometry
652     gsBasis<T> * m_basis;
653 
654     /// An auxiliary index for this geometry (eg. in case it is part
655     /// of a multi-patch object)
656     size_t m_id;
657 
658 }; // class gsGeometry
659 
660 /// Print (as string) operator to be used by all derived classes
661 template<class T>
662 std::ostream &operator<<(std::ostream &os, const gsGeometry<T>& b)
663 {return b.print(os); }
664 
665 } // namespace gismo
666 
667 #include <gsCore/gsCurve.h>
668 #include <gsCore/gsSurface.h>
669 #include <gsCore/gsVolume.h>
670 #include <gsCore/gsBulk.h>
671 
672 namespace gismo
673 {
674 
675 // Generic traits for geometry with dimension known at compile time
676 template <short_t d, typename T>
677 struct gsGeoTraits
678 {
679     typedef gsGeometry<T> GeometryBase;
680 };
681 
682 // Traits for curve
683 template <typename T>
684 struct gsGeoTraits<1,T>
685 {
686     typedef gsCurve<T> GeometryBase;
687 };
688 
689 // Traits for surface
690 template <typename T>
691 struct gsGeoTraits<2,T>
692 {
693     typedef gsSurface<T> GeometryBase;
694 };
695 
696 // Traits for volume
697 template <typename T>
698 struct gsGeoTraits<3,T>
699 {
700     typedef gsVolume<T> GeometryBase;
701 };
702 
703 // Traits for bulk
704 template <typename T>
705 struct gsGeoTraits<4,T>
706 {
707     typedef gsBulk<T> GeometryBase;
708 };
709 
710 } // namespace gismo
711 
712 
713 #ifndef GISMO_BUILD_LIB
714 #include GISMO_HPP_HEADER(gsGeometry.hpp)
715 #endif
716