G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsBSpline.hpp
Go to the documentation of this file.
1
15#pragma once
16
18#include <gsIO/gsXml.h>
20
21#include <gsCore/gsMultiPatch.h>
23
24namespace gismo
25{
26
27
28template<class T>
30{
31 // See also gsNurbs::merge().
32 // check geometric dimension
33 GISMO_ASSERT(this->geoDim()==otherG->geoDim(),
34 "gsNurbs: cannot merge curves in different spaces ( R^"
35 << this->geoDim() << ", R^" << otherG->geoDim() << " ).");
36
37 // check if the type of other is BSpline
38 gsBSpline * other = dynamic_cast<gsBSpline *>( otherG );
39 GISMO_ASSERT( other!=NULL, "Can only merge with B-spline curves.");
40 other= other->clone().release();
41
42 GISMO_ASSERT( this ->basis().isPeriodic() == false &&
43 other->basis().isPeriodic() == false,
44 "Cannot merge a closed curve with anything." );
45
46 // check degree
47 const short_t mDeg = this ->basis().degree();
48 const short_t oDeg = other->basis().degree();
49 const short_t deg = math::max(mDeg,oDeg);
50
51 other->gsBSpline::degreeElevate( deg - oDeg ); // degreeElevate(0) does nothing (and very quickly)
52 this ->gsBSpline::degreeElevate( deg - mDeg );
53
54 // check whether the resulting curve will be continuous
55 // TODO: ideally, the tolerance should be a parameter of the function
56 T tol = 1e-8;
57 gsMatrix<T> mValue = this ->eval(this ->support().col(1));
58 gsMatrix<T> oValue = other->eval(other->support().col(0));
59 bool continuous = gsAllCloseAbsolute(mValue,oValue,tol);
60
61 // merge knot vectors.
62 KnotVectorType& mKnots = this ->basis().knots();
63 KnotVectorType& oKnots = other->basis().knots();
64 T lastKnot = mKnots.last();
65 if (continuous) // reduce knot multiplicity
66 {
67 // TODO check for clamped knot vectors otherwise
68 // we should do knot insertion beforehands
69 mKnots.remove(lastKnot);
70 }// else there is a knot of multiplicity deg + 1 at the discontinuity
71
72 oKnots.addConstant(lastKnot-oKnots.first());
73 mKnots.append( oKnots.begin()+deg+1, oKnots.end());
74
75 // merge coefficients
76 unsigned n= this->coefsSize();
77 index_t skip = continuous ? 1 : 0;
78 this->m_coefs.conservativeResize( n + other->coefsSize() -skip, gsEigen::NoChange ) ;
79
80 this->m_coefs.block( n,0,other->coefsSize()-skip,other->geoDim() ) =
81 other->m_coefs.block( 1,0,other->coefsSize()-skip,other->geoDim() ) ;
82
83 delete other;
84}
85
86template<class T>
87gsBSpline<T> gsBSpline<T>::segmentFromTo(T u0, T u1, T tolerance) const
88{
89
90 GISMO_ASSERT(domainStart()-tolerance < u0 && u0 < domainEnd()+tolerance,
91 "starting point "<< u0 <<" not in the knot vector");
92 GISMO_ASSERT(domainStart()-tolerance < u1 && u1 < domainEnd()+tolerance,
93 "end point "<< u1 <<" not in the knot vector");
94
95 //First make a copy of the actual object, to allow const
96 gsBSpline<T> copy(*this);
97
98 // Extract a reference to the knots, the basis and coefs of the copy
99 KnotVectorType & knots = copy.basis().knots();
100
101 // some constants
102 const short_t p = basis().degree(); // degree
103 const index_t multStart = p + 1 - knots.multiplicity(u0); // multiplicity
104 const index_t multEnd = p + 1 - knots.multiplicity(u1); // multiplicity
105
106 // insert the knot, such that its multiplicity is p+1
107 if (multStart>0)
108 copy.insertKnot(u0, 0, multStart);
109 if (multEnd>0)
110 copy.insertKnot(u1, 0, multEnd );
111
112 gsMatrix<T>& coefs = copy.coefs();
113 const index_t tDim = coefs.cols();
114
115 // Split the coefficients
116 // find the number of coefs left from u0
117 const index_t nL = knots.uFind(u0).firstAppearance();
118 // find the number of coefs left from u1
119 index_t nL2 = knots.uFind(u1).firstAppearance();
120 bool isEnd = math::abs(u1 - this->domainEnd()) < tolerance;
121// if ( isEnd ) { nL2 += 1; } // Adjust for end parameter
122 if ( isEnd )
123 nL2 = copy.numCoefs(); // Adjust for end parameter
124
125 // Prepare control points for new geometry
126 gsMatrix<T> coefRes = coefs.block(nL, 0, nL2-nL, tDim);
127
128 // Prepare new knot vector
129 typename KnotVectorType::iterator itStart = knots.iFind(u0);
130 typename KnotVectorType::iterator itEnd = knots.iFind(u1) + (isEnd ? p + 1 : 0);
131 typename KnotVectorType::knotContainer matRes(itStart-p, itEnd+1);
132 KnotVectorType knotsRes(give(matRes), p);
133
134 return gsBSpline<T>(Basis(give(knotsRes)), give(coefRes));
135}
136
137template<class T>
139{
140 gsMultiPatch<T> bezierSegments;
141
142 gsBSpline<T> currentSegment(*this);
143 gsBSpline<T> leftPart;
144
145 for (auto iter = this->knots().ubegin() + 1; iter != this->knots().uend() - 1; ++iter)
146 {
147 currentSegment.splitAt(*iter, leftPart, currentSegment, tolerance);
148 bezierSegments.addPatch(leftPart);
149 }
150
151 bezierSegments.addPatch(currentSegment); // Add the last segment
152 return bezierSegments;
153}
154
155template<class T>
156std::vector<internal::gsCurveIntersectionResult<T>> gsBSpline<T>::intersect(const gsBSpline<T>& other,
157 T tolerance,
158 T curvatureTolerance) const
159{
160 std::vector<internal::gsBoundingBoxPair<T>> hulls = internal::getPotentialIntersectionRanges<T>(*this, other, curvatureTolerance);
161
162 std::vector<internal::gsCurveIntersectionResult<T>> results;
163 for (typename std::vector<internal::gsBoundingBoxPair<T>>::const_iterator hull = hulls.begin(); hull!=hulls.end(); hull++)
164 {
165 gsBSpline<T> crv1 = this->segmentFromTo(hull->b1.getRange().getMin(), hull->b1.getRange().getMax());
166 gsBSpline<T> crv2 = other.segmentFromTo(hull->b2.getRange().getMin(), hull->b2.getRange().getMax());
167
168 internal::gsCurveCurveDistanceSystem<T> obj(crv1, crv2);
169 gsVector<T,2> uv;
170 uv(0) = 0.5 * (crv1.domainStart() + crv1.domainEnd());
171 uv(1) = 0.5 * (crv2.domainStart() + crv2.domainEnd());
172 T distance = obj.compute(uv, tolerance);
173
174 if (distance < math::max( (T)1e-10, tolerance))
175 {
176 gsMatrix<T> uCrv1(1,1), uCrv2(1,1);
177 uCrv1(0,0) = uv(0);
178 uCrv2(0,0) = uv(1);
179 gsMatrix<T> pt = 0.5 * (crv1.eval(uCrv1) + crv2.eval(uCrv2));
180 internal::gsCurveIntersectionResult<T> result(uv(0), uv(1), pt);
181 results.push_back(result);
182 }
183 }
184
185 return results;
186}
187
188template<class T>
190{
191 index_t coefsSize = m_coefs.rows();
192
193 T len = (m_coefs.row(0)-m_coefs.row(coefsSize-1)).norm();
194 T total = 0.0;
195 for (index_t ipt = 0; ipt != coefsSize - 1; ++ipt)
196 {
197 T dist = (m_coefs.row(ipt) - m_coefs.row(ipt + 1)).norm();
198 total += dist;
199 }
200 return total / len;
201}
202
203template<class T>
205{
206 GISMO_UNUSED(dir);
207 if (i==0) return;
208 //if ( i==1)
209 //single knot insertion: Boehm's algorithm
210 //else
211 //knot with multiplicity: Oslo algorithm
212 if( this->basis().isPeriodic() )
213 {
214 int borderKnotMult = this->basis().borderKnotMult();
215 KnotVectorType & knots = this->knots();
216 unsigned deg = this->basis().degree();
217
218 GISMO_ASSERT( knot != knots[deg] && knot != knots[knots.size() - deg - 1],
219 "You are trying to increase the multiplicity of the p+1st knot but the code is not ready for that.\n");
220
221 // If we would be inserting to "passive" regions, we
222 // rather insert the knot into the mirrored part.
223 // Adjustment of the mirrored knots is then desirable.
224 if( knot < knots[deg - borderKnotMult + 1] )
225 {
226 knot += this->basis()._activeLength();
227 }
228 else if( knot > knots[knots.size() - deg + borderKnotMult - 2] )
229 {
230 knot -= this->basis()._activeLength();
231 }
232 // If necessary, we update the mirrored part of the knot vector.
233 if((knot < knots[2*deg + 1 - borderKnotMult]) || (knot >= knots[knots.size() - 2*deg - 2 + borderKnotMult]))
234 this->basis().enforceOuterKnotsPeriodic();
235
236 // We copy some of the control points to pretend for a while
237 // that the basis is not periodic.
238
239 //gsMatrix<T> trueCoefs = this->basis().perCoefs( this->coefs() );
240 gsBoehm( this->basis().knots(), this->coefs(), knot, i );
241 //this->coefs() = trueCoefs;
242 //this->coefs().conservativeResize( this->basis().size(), this->coefs().cols() );
243 }
244 else // non-periodic
245 gsBoehm( this->basis().knots(), this->coefs() , knot, i);
246}
247
248template<class T>
250{
251 insertKnot(knot,0,i);
252}
253
254template<class T>
255void gsBSpline<T>::splitAt(T u0, gsBSpline<T>& left, gsBSpline<T>& right, T tolerance) const
256{
257 GISMO_ASSERT(domainStart()-tolerance < u0 && u0 < domainEnd()+tolerance,
258 "splitting point "<< u0 <<" not in the knot vector");
259
260 left = segmentFromTo(this->domainStart(), u0, tolerance);
261 right = segmentFromTo(u0, this->domainEnd(), tolerance);
262}
263
264template<class T>
265bool gsBSpline<T>::isOn(gsMatrix<T> const &u, T tol) const
266{
267 GISMO_ASSERT( u.cols() == 1, "Expecting single point.");
269 gsMatrix<T> e;
270
271 for ( index_t k = 0; k != u.rows(); ++k)
272 {
273 std::vector<T> roots;
274 slv.allRoots(*this, roots, k, u(k,0) ) ;
275
276 if( roots.size()!=0 )
277 {
278 gsAsMatrix<T> xx(roots);
279 this->eval_into( xx, e );
280
281 //if( math::abs( e(!k,0)-u(!k,0) ) < tol )
282 for(index_t j=0; j!=e.cols(); j++)
283 if( ( e.col(j)-u ).norm() < tol )
284 return true;
285 }
286 }
287 return false;
288}
289
290template<class T>
291bool gsBSpline<T>::isPatchCorner(gsMatrix<T> const &v, T tol) const
292{
293 return (( v - m_coefs.row(0) ).squaredNorm() < tol ||
294 ( v - m_coefs.bottomRows(1)).squaredNorm() < tol );
295}
296
297template<class T>
299 gsVector<index_t,1> & curr,
300 T tol)
301{
302 if ((v - m_coefs.row(0)).squaredNorm() < tol)
303 curr[0] = 0;
304 else if ((v - m_coefs.bottomRows(1)).squaredNorm() < tol)
305 curr[0] = m_coefs.rows()-1;
306 else
307 {
308 curr[0] = m_coefs.rows(); // invalidate result
309 gsWarn<<"Point "<< v <<" is not an corner of the patch. (Call isPatchCorner() first!).\n";
310 }
311}
312
313
314template<class T>
316{
317 if ((v - m_coefs.row(0)).squaredNorm() < (T)(1e-3))
318 return;
319 else if ((v - m_coefs.bottomRows(1)).squaredNorm() < (T)(1e-3))
320 this->reverse();
321 else
322 gsWarn<<"Point "<< v <<" is not an endpoint of the curve.\n";
323}
324
325template<class T>
327{
328 if ((v - m_coefs.bottomRows(1)).squaredNorm() < (T)(1e-3))
329 return;
330 else if ((v - m_coefs.row(0)).squaredNorm() < (T)(1e-3))
331 this->reverse();
332 else
333 gsWarn<<"Point "<< v <<" is not an endpoint of the curve.\n";
334}
335
336template <class T>
337void gsBSpline<T>::swapDirections(const unsigned i, const unsigned j)
338{
339 GISMO_UNUSED(i);
340 GISMO_UNUSED(j);
341 GISMO_ASSERT( static_cast<int>(i) == 0 && static_cast<int>(j) == 0,
342 "Invalid basis components "<<i<<" and "<<j<<" requested" );
343}
344
345
346template<class T>
348{
349 GISMO_UNUSED(dir);
350 GISMO_ASSERT( (dir == -1) || (dir == 0),
351 "Invalid basis component "<< dir <<" requested for degree elevation" );
352
353 bspline::degreeElevateBSpline(this->basis(), this->m_coefs, i);
354}
355
356namespace internal
357{
358
360template<class T>
361class gsXml< gsBSpline<T> >
362{
363private:
364 gsXml() { }
365public:
366 GSXML_COMMON_FUNCTIONS(gsBSpline<T>);
367 static std::string tag () { return "Geometry"; }
368 static std::string type () { return "BSpline"; }
369
370 static gsBSpline<T> * get (gsXmlNode * node)
371 {
372 return getGeometryFromXml< gsBSpline<T> >(node);
373 }
374
375 static gsXmlNode * put (const gsBSpline<T> & obj,
376 gsXmlTree & data )
377 {
378 return putGeometryToXml< gsBSpline<T> >(obj,data);
379 }
380};
381
382
383}// namespace internal
384
385} // namespace gismo
Creates a mapped object or data pointer to a matrix without copying data.
Definition gsAsMatrix.h:32
Definition gsBSplineSolver.h:114
A B-spline function of one argument, with arbitrary target dimension.
Definition gsBSpline.h:51
void merge(gsGeometry< T > *otherG)
Merge other B-spline into this one.
Definition gsBSpline.hpp:29
bool isOn(gsMatrix< T > const &u, T tol=1e-3) const
Return true if point u is on the curve with tolerance tol.
Definition gsBSpline.hpp:265
void degreeElevate(short_t const i=1, short_t const dir=-1)
Elevate the degree by the given amount i for the direction dir. If dir is -1 then degree elevation is...
Definition gsBSpline.hpp:347
T pseudoCurvature() const
Definition gsBSpline.hpp:189
void setOriginCorner(gsMatrix< T > const &v)
Modifies the parameterization such that the point v is the starting point of the curve....
Definition gsBSpline.hpp:315
void insertKnot(T knot, index_t i=1)
Definition gsBSpline.hpp:249
gsMultiPatch< T > toBezier(T tolerance=1e-15) const
Definition gsBSpline.hpp:138
void splitAt(T u0, gsBSpline< T > &left, gsBSpline< T > &right, T tolerance=1e-15) const
Definition gsBSpline.hpp:255
void setFurthestCorner(gsMatrix< T > const &v)
Modifies the parameterization such that the point v is the ending point of the curve....
Definition gsBSpline.hpp:326
void findCorner(const gsMatrix< T > &v, gsVector< index_t, 1 > &curr, T tol=1e-3)
returns the tensor-index curr of the corner control point v, or an invalid index if the corner is not...
Definition gsBSpline.hpp:298
T domainEnd() const
Returns the end value of the domain of the basis.
Definition gsBSpline.h:167
bool isPatchCorner(gsMatrix< T > const &v, T tol=1e-3) const
Return true if point u is an endpoint (corner) of the curve with tolerance tol.
Definition gsBSpline.hpp:291
gsBSpline< T > segmentFromTo(T u0, T u1, T tolerance=1e-15) const
Definition gsBSpline.hpp:87
gsMatrix< T > m_coefs
Coefficient matrix of size coefsSize() x geoDim()
Definition gsGeometry.h:629
std::vector< internal::gsCurveIntersectionResult< T > > intersect(const gsBSpline< T > &other, T tolerance=1e-5, T curvatureTolerance=1+1e-6) const
Definition gsBSpline.hpp:156
T domainStart() const
Returns the starting value of the domain of the basis.
Definition gsBSpline.h:164
uPtr clone()
Clone methode. Produceds a deep copy inside a uPtr.
gsMatrix< T > eval(const gsMatrix< T > &u) const
Evaluate the function,.
Definition gsFunctionSet.hpp:120
Abstract base class representing a geometry map.
Definition gsGeometry.h:93
short_t geoDim() const
Dimension n of the absent physical space.
Definition gsGeometry.h:292
virtual const gsBasis< T > & basis() const =0
Returns a const reference to the basis of the geometry.
gsMatrix< T > support() const
Returns the range of parameters (same as parameterRange())
Definition gsGeometry.hpp:193
index_t coefsSize() const
Return the number of coefficients (control points)
Definition gsGeometry.h:371
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
index_t addPatch(typename gsGeometry< T >::uPtr g)
Add a patch from a gsGeometry<T>::uPtr.
Definition gsMultiPatch.hpp:211
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition gsVector.h:37
Implementation of common algorithms for B-splines.
#define short_t
Definition gsConfig.h:35
#define index_t
Definition gsConfig.h:32
Implementation of B Spline Curve/Curve intersection.
#define gsWarn
Definition gsDebug.h:50
#define GISMO_UNUSED(x)
Definition gsDebug.h:112
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Provides declaration of the MultiPatch class.
Provides implementation of generic XML functions.
Provides declaration of input/output XML utilities struct.
void degreeElevateBSpline(Basis_t &basis, gsMatrix< typename Basis_t::Scalar_t > &coefs, short_t m)
Increase the degree of a 1D B-spline from degree p to degree p + m.
Definition gsBSplineAlgorithms.h:224
The G+Smo namespace, containing all definitions for the library.
void gsBoehm(KnotVectorType &knots, Mat &coefs, T val, int r=1, bool update_knots=true)
Performs insertion of multiple knot on "knots" and coefficients "coefs".
Definition gsBoehm.hpp:29
T distance(gsMatrix< T > const &A, gsMatrix< T > const &B, index_t i=0, index_t j=0, bool cols=false)
compute a distance between the point number in the set and the point number <j> in the set ; by def...
bool gsAllCloseAbsolute(const matrix_t1 &a, const matrix_t2 &b, const typename matrix_t1::Scalar &tol)
tests if the difference between two matrices is bounded by tol in norm
Definition gsMath.h:465
S give(S &x)
Definition gsMemory.h:266