1 /** @file gsCurveLoop.hpp
2 
3     @brief Implementation of gsCurveLoop class.
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. Falini, A. Mantzaflaris, D.-M. Nguyen, M. Pauley
12 */
13 
14 #pragma once
15 
16 # include <gsModeling/gsCurveLoop.h>
17 # include <gsNurbs/gsKnotVector.h>
18 # include <gsNurbs/gsBSpline.h>
19 # include <gsNurbs/gsBSplineSolver.h>
20 # include <gsModeling/gsModelingUtils.hpp>
21 
22 namespace gismo
23 {
24 
25 template<class T>
gsCurveLoop(const std::vector<gsVector3d<T> * > points3D,const std::vector<bool>,T margin,gsVector3d<T> * outNormal)26 gsCurveLoop<T>::gsCurveLoop(const std::vector<gsVector3d<T> *> points3D, const std::vector<bool> , T margin, gsVector3d<T> *outNormal)
27 {
28     // attempt to choose a curve loop by using the plane of best fit
29     gsVector3d<T> resultNormal = initFrom3DPlaneFit(points3D, margin);
30     if(outNormal != NULL) *outNormal = resultNormal;
31 }
32 
33 template<class T>
gsCurveLoop(const std::vector<T> angles3D,const std::vector<T> lengths3D,const std::vector<bool> isConvex,T margin,const bool unitSquare)34 gsCurveLoop<T>::gsCurveLoop(const std::vector<T> angles3D, const std::vector<T> lengths3D, const std::vector<bool> isConvex, T margin, const bool unitSquare)
35 {
36     this->initFrom3DByAngles(angles3D, lengths3D, isConvex, margin, unitSquare);
37 }
38 
39 template<class T>
parameterOf(gsMatrix<T> const & u,int i,T & result,T tol)40 bool gsCurveLoop<T>::parameterOf(gsMatrix<T> const &u, int i, T & result, T tol)
41 {
42     gsBSplineSolver<T> slv;
43     gsMatrix<T> e;
44     gsBSpline<T> * c = dynamic_cast<gsBSpline<T> *>(m_curves[i]);
45 
46     if ( c !=0 )
47     {
48         std::vector<T> roots;
49         slv.allRoots(*c, roots, 0, u(0,0) ) ;
50 
51         if(roots.size()==0)
52             return false;
53 
54         gsAsMatrix<T> xx(roots);
55         m_curves[i]->eval_into( xx, e );
56 
57         for(index_t r=0; r!=e.cols(); r++)
58         {
59             //gsDebug<<"matrix e (1,r): "<< e(1,r) <<"\n";
60             if( math::abs(e( 1, r )-u(1,0))< tol )
61             {
62                 result = roots[r];
63                 return true;
64             }
65         }
66         return false;
67     }
68     else
69     {
70         gsWarn <<"isOnCurve only works for B-splines.\n";
71         return false;
72     }
73 }
74 
75 template<class T>
isOn(gsMatrix<T> const & u,T & paramResult,T tol)76 bool gsCurveLoop<T>::isOn(gsMatrix<T> const &u, T & paramResult, T tol )
77 {
78     for(int i=0; i<this->numCurves(); i++)
79         if( m_curves[i]->isOn(u, tol) )
80         {
81             this->parameterOf(u,i,paramResult,tol);
82             return true;
83           }
84             return false;
85 }
86 
87 template<class T>
is_ccw()88 bool gsCurveLoop<T>::is_ccw()
89 {
90     T result(0);
91 
92     for ( typename std::vector< gsCurve<T> *>::const_iterator it=
93               m_curves.begin(); it!= m_curves.end() ; it++ )
94     {
95         index_t nrows = (*it)->coefs().rows();
96         for(index_t i=0; i!=nrows-1;++i)
97             result +=(*it)->coefs()(i,0)* (*it)->coefs()(i+1,1)-
98                 (*it)->coefs()(i,1)* (*it)->coefs()(i+1,0);
99     }
100     return ( result > 0 );
101 }
102 
103 template<class T>
reverse()104 void gsCurveLoop<T>::reverse()
105 {
106     for ( typename std::vector< gsCurve<T> *>::const_iterator it=
107               m_curves.begin(); it!= m_curves.end() ; it++ )
108         (*it)->reverse();
109     gsCurve<T>* swap;
110     size_t size=m_curves.size();
111     for ( size_t i=0;i<size/2;i++)
112     {
113         swap = m_curves[i];
114         m_curves[i]=m_curves[size-i-1];
115         m_curves[size-i-1]=swap;
116     }
117 }
118 
119 template<class T>
translate(gsVector<T> const & v)120 void gsCurveLoop<T>::translate(gsVector<T> const & v)
121 {
122     for ( iterator it = m_curves.begin(); it != m_curves.end(); ++it)
123         (*it)->translate(v);
124 }
125 
126 template<class T>
singleCurve() const127 typename gsCurve<T>::uPtr gsCurveLoop<T>::singleCurve() const
128 {
129     typename std::vector< gsCurve<T> *>::const_iterator it;
130 
131     GISMO_ASSERT( m_curves.size(), "CurveLoop is empty.\n");
132     GISMO_ASSERT( m_curves.front(), "Something went wrong. Invalid pointer in gsCurveLoop member.\n");
133 
134     typename gsCurve<T>::uPtr loop = m_curves.front()->clone();
135 
136     for ( it= m_curves.begin()+1; it!= m_curves.end() ; it++ )
137     {
138         loop->merge( *it ) ;
139     }
140     return loop;
141 }
142 
143 template<class T>
normal(int const & c,gsMatrix<T> const & u)144 gsMatrix<T> gsCurveLoop<T>::normal( int const & c, gsMatrix<T> const & u )
145 {
146     int n = u.cols();
147     gsMatrix<T> result(2,n);
148 
149     for ( int i=0; i<n; ++i )
150     {
151         gsMatrix<T> b = m_curves[c]->deriv( u.col(i) ) ;
152         b.normalize(); // unit tangent vector
153         result(0,i) = b(1);
154         result(1,i) = -b(0);
155     }
156     return result;
157 }
158 
159 template<class T>
split(int startIndex,int endIndex,gsCurve<T> * newCurveThisFace,gsCurve<T> * newCurveNewFace)160 typename gsCurveLoop<T>::uPtr gsCurveLoop<T>::split(int startIndex, int endIndex,
161                                        gsCurve<T> * newCurveThisFace,
162                                        gsCurve<T> * newCurveNewFace)
163 {
164     int n = m_curves.size();
165     uPtr result(new gsCurveLoop<T>(newCurveNewFace));
166     for(int i = startIndex; i != endIndex; i = (i + 1) % n)
167     {
168         result->insertCurve(m_curves[i]);
169     }
170     if(startIndex < endIndex)
171     {
172         m_curves.erase(m_curves.begin() + startIndex, m_curves.begin() + endIndex);
173         if(startIndex == 0)
174         {
175             m_curves.push_back(newCurveThisFace);
176         }
177         else
178         {
179             m_curves.insert(m_curves.begin() + startIndex, newCurveThisFace);
180         }
181     }
182     else
183     {
184         m_curves.erase(m_curves.begin() + startIndex, m_curves.end());
185         m_curves.erase(m_curves.begin(), m_curves.begin() + endIndex);
186         m_curves.push_back(newCurveThisFace);
187     }
188     return result;
189 }
190 
191 template <class T>
lineIntersections(int const & direction,T const & abscissa)192 std::vector<T> gsCurveLoop<T>::lineIntersections(int const & direction , T const & abscissa)
193 {
194     // For now only Curve loops with ONE curve are supported
195     gsBSplineSolver<T> slv;
196     typename gsBSpline<T>::uPtr c = memory::convert_ptr<gsBSpline<T> >(singleCurve());
197     // = dynamic_cast<gsBSpline<T> *>(m_curves[0]))
198 
199     if ( c )
200     {
201         std::vector<T> result;
202         slv.allRoots(*c, result, direction, abscissa) ;
203         /*slv.allRoots(*c, result, direction, abscissa,1e-7,1000) ;*/
204         return result;
205     }
206     gsWarn<<"Could not get intersection for this type of curve!\n";
207     return std::vector<T>();
208 }
209 
210 template <class T>
sample(int npoints,int numEndPoints) const211 gsMatrix<T> gsCurveLoop<T>::sample(int npoints, int numEndPoints) const
212 {
213     GISMO_ASSERT(npoints>=2, "");
214     GISMO_ASSERT(numEndPoints>=0 && numEndPoints<=2, "");
215     int np; // new number of points
216     switch (numEndPoints)
217     {
218     case (0):
219         np = npoints-2;
220         break;
221     case (1):
222         np = npoints-1;
223         break;
224     case (2):
225         np = npoints;
226         break;
227     default:
228         np = 0;
229         break;
230     }
231 
232     gsMatrix<T> u(2, m_curves.size() * np);
233     int i=0;
234     gsMatrix<T> interval;
235     gsMatrix<T> pts(1,np);
236     gsMatrix<T> uCols(2,np);
237     T a,b;
238     int firstInd=0;
239     int secondInd=np-1;
240     if (numEndPoints==0) {firstInd=1;secondInd=npoints-2;}
241     typename std::vector< gsCurve<T> *>::const_iterator it;
242     for ( it= m_curves.begin(); it!= m_curves.end() ; it++ )
243     {
244         interval = (*it)->parameterRange();
245         a = interval(0,0);
246         b = interval(0,1);
247         for (int ii=firstInd;ii<=secondInd;ii++) pts(0,ii-firstInd)= a + T(ii)*(b-a)/(npoints-1);
248         (*it)->eval_into( pts, uCols );
249         u.middleCols( i * np,np ) = uCols;
250         i++ ;
251     };
252     return u;
253 }
254 
255 template <class T>
getBoundingBox()256 gsMatrix<T> gsCurveLoop<T>::getBoundingBox()
257 {
258     gsMatrix<T, 2, 2> result;
259     int numCurves = m_curves.size();
260     T offset = 0.0001;
261     assert(numCurves != 0); // bounding box does not exist if there are no curves
262     gsMatrix<T> *coefs = &(m_curves[0]->coefs());
263     result(0, 0) = coefs->col(0).minCoeff() - offset;
264     result(1, 0) = coefs->col(1).minCoeff() - offset;
265     result(0, 1) = coefs->col(0).maxCoeff() + offset;
266     result(1, 1) = coefs->col(1).maxCoeff() + offset;
267 
268     for(int i = 1; i < numCurves; i++)
269     {
270         coefs = &(m_curves[i]->coefs());
271         result(0, 0) = math::min(result(0, 0), coefs->col(0).minCoeff()-offset );
272         result(1, 0) = math::min(result(1, 0), coefs->col(1).minCoeff()-offset );
273         result(0, 1) = math::max(result(0, 1), coefs->col(0).maxCoeff()+offset );
274         result(1, 1) = math::max(result(1, 1), coefs->col(1).maxCoeff()+offset );
275     }
276     return result;
277 }
278 
279 template<class T>
approximatingPolygon(const std::vector<T> & signedAngles,const std::vector<T> & lengths,T margin,gsMatrix<T> & result)280 bool gsCurveLoop<T>::approximatingPolygon(const std::vector<T> &signedAngles, const std::vector<T> &lengths, T margin, gsMatrix<T> &result)
281 {
282     size_t n = signedAngles.size();
283     assert(lengths.size() == n);
284 
285     std::vector<T> scaledAngles(signedAngles); // copy
286     T totalAngle(0);
287     for(size_t i = 0; i < n; i++)
288     {
289         totalAngle += scaledAngles[i];
290     }
291     if(totalAngle <= 0)
292     {
293         gsWarn << "Treatment of non-positive total turning angle is not implemented.\n";
294         return false;
295     }
296     // Scale the turning angles so they add to 2 * pi. These will be the
297     // angles we use at each vertex in the domain.
298     T angleScale = T(2.0 * EIGEN_PI / totalAngle);
299     for(size_t i = 0; i < n; i++)
300     {
301         scaledAngles[i] *= angleScale;
302         if(math::abs(scaledAngles[i]) >= EIGEN_PI)
303         {
304             gsWarn << "Scaled turning angle exceeded pi, treatment of this has not been implemented.\n";
305             return false;
306         }
307     }
308 
309     // Compute the cumulative turning angle (i.e. the total angle turned
310     // by the time we reach a given vertex).
311     std::vector<T> cumulativeAngles(n);
312     cumulativeAngles[0] = 0;
313     for(size_t i = 1; i < n; i++)
314     {
315         cumulativeAngles[i] = cumulativeAngles[i - 1] + scaledAngles[i];
316     }
317 
318     // Build a matrix to provide the coefficients of the following
319     // constraints (RHS of equations is built later):
320     //   total change of x coordinate (as we go round the polygon) == 0;
321     //   total change of y coordinate (as we go round the polygon) == 0;
322     gsMatrix<T> constraintCoefs(2, n);
323     for(size_t j = 0; j < n; j++)
324     {
325         constraintCoefs(0, j) = math::cos(cumulativeAngles[j]);
326         constraintCoefs(1, j) = math::sin(cumulativeAngles[j]);
327     }
328 
329     // Find a critical point of the following cost function subject to the above constraints:
330     //   (1 / 2) * ( sum of (  (length i) / (original length i)  ) ^ 2 - 1 ).
331     gsMatrix<T> invL(n, n);
332     invL.setZero();
333     for(size_t i = 0; i < n; i++)
334     {
335         invL(i, i) = 1 / lengths[i];
336     }
337     gsMatrix<T> ones(n, 1);
338     ones.setOnes();
339     gsMatrix<T> constraintRhs(2, 1);
340     constraintRhs.setZero();
341 
342     gsMatrix<T> resultLengths = optQuadratic(invL, ones, constraintCoefs, constraintRhs);
343 
344     for(size_t j = 0; j < n; j++)
345     {
346         if(resultLengths(j, 0) <= 0)
347         {
348             gsWarn << "Could not compute satisfactory lengths for approximating polygon.\n";
349             return false;
350         }
351     }
352 
353     // Work out the positions of the corners of this polygon.
354     // (Corner n == corner 0). Initially, we put the first vertex at (0,0). Then
355     // we apply a scale & shift to fit it all inside the box [0,1]x[0,1].
356     result.resize(n, 2);
357     result(0, 0) = 0; // set up the first corner
358     result(0, 1) = 0;
359     for(size_t i = 1; i < n; i++) // set up corners other than the first
360     {
361         result(i, 0) = result(i - 1, 0) + resultLengths(i - 1) * math::cos(cumulativeAngles[i - 1]);
362         result(i, 1) = result(i - 1, 1) + resultLengths(i - 1) * math::sin(cumulativeAngles[i - 1]);
363     }
364     adjustPolygonToUnitSquare(result, margin);
365     return true;
366 }
367 
368 template<class T>
domainSizes() const369 std::vector<T> gsCurveLoop<T>::domainSizes() const
370 {
371     std::vector<T> result;
372     size_t n = m_curves.size();
373     for(size_t i = 0; i < n; i++)
374     {
375         gsMatrix<T> range = m_curves[i]->parameterRange();
376         GISMO_ASSERT(range.rows() == 1 && range.cols() == 2, "Expected 1x2 matrix for parameter range of curve");
377         result.push_back(range(0, 1) - range(0, 0));
378     }
379 
380     return result;
381 }
382 
383 template <class T>
adjustPolygonToUnitSquare(gsMatrix<T> & corners,T const margin)384 void gsCurveLoop<T>::adjustPolygonToUnitSquare(gsMatrix<T> &corners, T const margin)
385 {
386     assert(corners.cols() == 2);
387     size_t n = corners.rows();
388 
389     T minx = corners.col(0).minCoeff();
390     T maxx = corners.col(0).maxCoeff();
391     T miny = corners.col(1).minCoeff();
392     T maxy = corners.col(1).maxCoeff();
393 
394     T scaleFactor(1);
395     scaleFactor += margin * 2;
396     scaleFactor = 1 / scaleFactor / std::max(maxx - minx, maxy - miny);
397     gsMatrix<T> shiftVector(1, 2);
398     shiftVector << 0.5 - 0.5 * scaleFactor * (maxx + minx), 0.5 - 0.5 * scaleFactor * (maxy + miny);
399     for(size_t i = 0; i < n; i++)
400     {
401         corners.row(i) *= scaleFactor;
402         corners.row(i) += shiftVector;
403     }
404 }
405 
406 template<class T>
initFrom3DPlaneFit(const std::vector<gsVector3d<T> * > points3D,T margin)407 gsVector3d<T> gsCurveLoop<T>::initFrom3DPlaneFit(const std::vector<gsVector3d<T> *> points3D, T margin)
408 {
409     // attempt to construct a curve loop using the plane of best fit
410 
411     size_t n = points3D.size(); // number of corners
412     GISMO_ASSERT(n >= 3, "Must have at least 3 points to construct a polygon");
413 
414     freeAll(m_curves);
415     m_curves.clear();
416 
417     // find the center of mass of the points
418     gsVector3d<T> com;
419     com << 0, 0, 0;
420     for(size_t i = 0; i < n; i++)
421     {
422         com += *(points3D[i]);
423     }
424     com /= n;
425 
426     // construct a matrix with the shifted points
427     gsMatrix<T> shiftedPoints(3, n);
428     for(size_t i = 0; i < n; i++)
429     {
430         shiftedPoints.col(i) = *(points3D[i]) - com;
431     }
432 
433     // compute a singular value decomposition
434     Eigen::JacobiSVD< Eigen::Matrix<T, Dynamic, Dynamic> > svd(
435         shiftedPoints * shiftedPoints.transpose(), Eigen::ComputeFullU);
436 
437     // extract plane projection matrix from the svd
438     gsMatrix<T> svd_u(svd.matrixU());
439     GISMO_ASSERT(svd_u.rows() == 3 && svd_u.cols() == 3, "Unexpected svd matrix result");
440     gsMatrix<T> projMat = svd_u.block(0, 0, 3, 2).transpose();
441 
442     // project all the points down onto the plane, keep track of min, max of coords
443     std::vector< gsVector<T> > projPts;
444     gsMatrix<T> bbox(2, 2); // first column is min of each dimension, second column is max
445     for(size_t i = 0; i < n; i++)
446     {
447         gsVector<T> x = projMat * shiftedPoints.col(i);
448         projPts.push_back(x);
449         for(size_t d = 0; d < 2; d++)
450         {
451             if(i == 0 || x(d) < bbox(d, 0)) bbox(d, 0) = x(d);
452             if(i == 0 || x(d) > bbox(d, 1)) bbox(d, 1) = x(d);
453         }
454     }
455 
456     // scale and shift so everything fits inside the bounding box minus margin.
457     T scale = (1 - 2 * margin) / std::max((bbox(0, 1) - bbox(0, 0)), bbox(1, 1) - bbox(1, 0));
458     gsVector<T> shift(2);
459     shift << margin - scale * bbox(0, 0), margin - scale * bbox(1, 0);
460     for(size_t i = 0; i < n; i++)
461     {
462         projPts[i] = projPts[i] * scale + shift;
463     }
464 
465     // interpolate linearly
466     for(size_t i = 0; i < n; i++)
467     {
468         size_t i1 = (i + 1) % n;
469         gsMatrix<T> tcp(2, 2);
470         tcp << projPts[i](0), projPts[i](1), projPts[i1](0), projPts[i1](1);
471         this->insertCurve(new gsBSpline<T>( 0, 1, 0, 1, give(tcp) ));
472     }
473 
474     // return the normal to the plane of best fit. we could just grab the last
475     // column from svd_u but then we'd have to worry about the orientation.
476     gsVector3d<T> p1 = projMat.row(0);
477     gsVector3d<T> p2 = projMat.row(1);
478     return p1.cross(p2).normalized().transpose();
479 
480 }
481 
482 template<class T>
initFrom3DByAngles(const std::vector<gsVector3d<T> * > points3D,const std::vector<bool> isConvex,T margin)483 bool gsCurveLoop<T>::initFrom3DByAngles(const std::vector<gsVector3d<T> *> points3D, const std::vector<bool> isConvex, T margin)
484 {
485     size_t n = isConvex.size();
486     assert(n == points3D.size());
487 
488     std::vector<T> angles;
489     std::vector<T> lengths;
490 
491     for(size_t i = 0; i < n; i++)
492     {
493         gsVector3d<T> *prev = points3D[(i + n - 1) % n];
494         gsVector3d<T> *cur = points3D[i];
495         gsVector3d<T> *next = points3D[(i + 1) % n];
496 
497         gsVector3d<T> change0 = *cur - *prev;
498         gsVector3d<T> change1 = *next - *cur;
499         T length0 = change0.norm();
500         T length1 = change1.norm();
501         T acosvalue= change0.dot(change1) / length0 / length1;
502         if(acosvalue>1)
503             acosvalue=1;
504         else if(acosvalue<-1)
505             acosvalue=-1;
506         angles.push_back( math::acos( acosvalue));
507         lengths.push_back(length1);
508     }
509 
510     return initFrom3DByAngles(angles, lengths, isConvex, margin);
511 }
512 
513 template<class T>
initFromIsConvex(const std::vector<bool> isConvex,T margin)514 void gsCurveLoop<T>::initFromIsConvex(const std::vector<bool> isConvex, T margin)
515 {
516     // find the corners of a regular polygon
517     size_t np = isConvex.size();
518     gsMatrix<T> corners(np, 2);
519     for(size_t i = 0; i < np; i++)
520     {
521         T angle = (T)i * (T)EIGEN_PI * 2 / np;
522         corners(i, 0) = math::cos(angle);
523         corners(i, 1) = math::sin(angle);
524     }
525     // choose control points of cubic splines which ensure the correct angle signs
526     gsMatrix<T> cps(np * 4, 2);
527     for(size_t i = 0; i < np; i++)
528     {
529         size_t iprev = (i + np - 1) % np;
530         gsMatrix<T> prevPt = corners.row(iprev);
531         gsMatrix<T> u = corners.row(i);
532         gsMatrix<T> nextPt = corners.row((i + 1) % np);
533         cps.row(iprev * 4 + 3) = u;
534         cps.row(i * 4) = u;
535         if(isConvex[i])
536         {
537             cps.row(iprev * 4 + 2) = u + (prevPt - u) / 3;
538             cps.row(i * 4 + 1) = u + (nextPt - u) / 3;
539         }
540         else
541         {
542             cps.row(iprev * 4 + 2) = u - (nextPt - u) / 3;
543             cps.row(i * 4 + 1) = u - (prevPt - u) / 3;
544         }
545     }
546     // put all the control points inside a box
547     adjustPolygonToUnitSquare(cps, margin);
548     // construct the splines
549     curves().clear();
550     for(size_t i = 0; i < np; i++)
551     {
552         gsMatrix<T> tcp = cps.block(i * 4, 0, 4, 2);
553         this->insertCurve(new gsBSpline<T>( 0, 1, 0, 3, give(tcp) ));
554     }
555 }
556 
557 
558 template<class T>
initFrom3DByAngles(const std::vector<T> & angles3D,const std::vector<T> & lengths3D,const std::vector<bool> & isConvex,T margin,bool unitSquare)559 bool gsCurveLoop<T>::initFrom3DByAngles(const std::vector<T>& angles3D, const std::vector<T>& lengths3D, const std::vector<bool>& isConvex, T margin, bool unitSquare)
560 {
561     size_t n = isConvex.size();
562     assert(angles3D.size() == n);
563     assert(lengths3D.size() == n);
564 
565     freeAll(m_curves);
566     m_curves.clear();
567 
568     gsMatrix<T> corners4(4, 2);
569     if (unitSquare==true && n==4)
570     {
571         bool isAllConvex=true;
572         for (size_t i=0;i<4;i++) {if (isConvex.at(i)==false) {isAllConvex=false;break;}}
573         if (isAllConvex==true)
574         {
575             corners4<<0,0,1,0,1,1,0,1;
576             for(size_t i = 0; i < n; i++)
577             {
578                 gsMatrix<T> tcp(2, 2);
579                 tcp << corners4(i, 0), corners4(i, 1), corners4((i + 1) % n, 0), corners4((i + 1) % n, 1);
580                 this->insertCurve(new gsBSpline<T>( 0, 1, 0, 1, give(tcp) ));
581             }
582             return true;
583         }
584     }
585 
586     // compute the 2D angles corresponding to the 3D ones
587     std::vector<T> signedAngles(n);
588     for(size_t i = 0; i < n; i++)
589     {
590         signedAngles[i] = (isConvex[i]? 1: -1) * angles3D[i];
591     }
592 
593     gsMatrix<T> corners;
594     bool success = gsCurveLoop<T>::approximatingPolygon(signedAngles, lengths3D, margin, corners);
595     if(!success) return false;
596 
597     // create a loop of B-splines that are all straight lines.
598     for(size_t i = 0; i < n; i++)
599     {
600         gsMatrix<T> tcp(2, 2);
601         tcp << corners(i, 0), corners(i, 1), corners((i + 1) % n, 0), corners((i + 1) % n, 1);
602         this->insertCurve(new gsBSpline<T>( 0, 1, 0, 1, give(tcp) ));
603     }
604     return true;
605 }
606 
607 template<class T>
flip1(T minu,T maxu)608 void gsCurveLoop<T>::flip1(T minu, T maxu)
609 {
610     size_t nCur = m_curves.size();
611     T offset = minu + maxu;
612     for(size_t i = 0; i < nCur; i++)
613     {
614         gsMatrix<T> &coefs = m_curves[i]->coefs();
615         size_t ncp = coefs.rows();
616         for(size_t j = 0; j < ncp; j++)
617         {
618             coefs(j, 0) = offset - coefs(j, 0);
619         }
620     }
621 }
622 
623 template<class T>
splitCurve(size_t curveId,T lengthRatio)624 gsMatrix<T> gsCurveLoop<T>::splitCurve(size_t curveId, T lengthRatio)
625 {
626     GISMO_UNUSED(lengthRatio);
627     GISMO_ASSERT(lengthRatio>0 && lengthRatio<1, "the second parameter *lengthRatio* must be between 0 and 1");
628     GISMO_ASSERT(curveId < m_curves.size(), "the first parameter *curveID* exceeds the number of curves of the loop");
629     // the two vertices a and b of the curve curveId, counting counterclockwise from z+
630     gsMatrix<T> a(2,1),b(2,1),n(2,1);
631     gsMatrix<T> cp,tcp0(2,2),tcp1(2,2);
632     cp = curve(curveId).coefs();
633     //int deg = curve(curveId).degree();
634     int deg = curve(curveId).basis().degree(0);
635     //GISMO_ASSERT(deg==1,"Pls extend to code to curves of degree more than 1");
636     if (deg!=1)
637         gsWarn<<"Pls extend to code to curves of degree more than 1, degree 1 is temporarily used.\n";
638     a = cp.row(0);
639     b = cp.row(cp.rows() - 1);
640     //n = (1-lengthRatio)*a + lengthRatio*b; // new vertex
641     gsMatrix<T> supp = curve(curveId).support();
642     GISMO_ASSERT(supp.rows() == 1 && supp.cols() == 2, "Unexpected support matrix");
643     gsMatrix<T> u(1, 1);
644     u << (supp(0, 0) + supp(0, 1)) / 2;
645     curve(curveId).eval_into (u, n);
646     n.transposeInPlace();
647     // create the two new curves
648     tcp0 << a(0,0),a(0,1),n(0,0),n(0,1);
649     gsBSpline<T> * tcurve0 = new gsBSpline<T>( 0, 1, 0, 1, give(tcp0) );
650     tcp1 << n(0,0),n(0,1),b(0,0),b(0,1);
651     gsBSpline<T> * tcurve1 = new gsBSpline<T>( 0, 1, 0, 1, give(tcp1) );
652     // remove the original curve
653     removeCurve(m_curves.begin()+curveId);
654     // add the two new curves
655     m_curves.insert(m_curves.begin()+curveId,tcurve0);
656     m_curves.insert(m_curves.begin()+curveId+1,tcurve1);
657 
658     return n;
659 }
660 
661 template <class T>
removeCurves(iterator begin,iterator end)662 void gsCurveLoop<T>::removeCurves(iterator begin, iterator end)
663 {
664     // free the curves before removing them
665     freeAll(begin, end);
666     m_curves.erase(begin, end);
667 }
668 
669 }
670