//=========================================================================== // GoTools Core - SINTEF Geometry Tools Core library, version 2.0.1 // // Copyright (C) 2000-2007, 2010 SINTEF ICT, Applied Mathematics, Norway. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation version 2 of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., // 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. // // Contact information: E-mail: tor.dokken@sintef.no // SINTEF ICT, Department of Applied Mathematics, // P.O. Box 124 Blindern, // 0314 Oslo, Norway. // // Other licenses are also available for this software, notably licenses // for: // - Building commercial software. // - Building software whose source code you wish to keep private. //=========================================================================== 00106 #ifndef DBG 00107 const bool dbg = false; 00108 #endif 00109 00110 if (!degenerate_triangle(vert_p[c1], vert_p[c2], vert_p[c3] DBG_FLAG)) 00111 { 00112 mesh.push_back(c1); 00113 mesh.push_back(c2); 00114 mesh.push_back(c3); 00115 } 00116 else 00117 if (dbg) 00118 { 00119 printf(" add_triangle(): Not adding triangle. Degenerate.\n"); 00120 printf("\n"); 00121 printf(" hold on; plot(%f, %f, 'ro', 'markersize', 10, 'linewidth', 2);\n", vert_p[c1][0], vert_p[c1][1]); 00122 printf(" plot(%f, %f, 'go', 'markersize', 10, 'linewidth', 2);\n", vert_p[c2][0], vert_p[c2][1]); 00123 printf(" plot(%f, %f, 'bo', 'markersize', 10, 'linewidth', 2); hold off\n", vert_p[c3][0], vert_p[c3][1]); 00124 printf("\n"); 00125 // const bool tmp = degenerate_triangle(vert_p[c1], vert_p[c2], vert_p[c3] DBG_FLAG); 00126 } 00127 }

std::vector< CurveLoop > Go::allBoundarySfLoops ( boost::shared_ptr< ParamSurface >  surf,
double  degenerate_epsilon 
)

Definition at line 99 of file SurfaceTools.C.

References outerBoundarySfLoop().

00102 {
00103   boost::shared_ptr<SplineSurface> spline_sf = 
00104     boost::shared_dynamic_cast<SplineSurface, ParamSurface>(surf);
00105 
00106   if (spline_sf.get())
00107     {
00108       // There is only one boundary loop...
00109       std::vector<CurveLoop> cvloopvec;
00110       cvloopvec.push_back(outerBoundarySfLoop(surf, degenerate_epsilon));
00111       return cvloopvec;
00112     }
00113   else
00114     {
00115       // VSK, 1109. A similar problem as for spline surface occurs for
00116       // elementary surfaces, but it is currently not handled
00117       // VSK, 0510. Add the surface back pointer
00118       vector<CurveLoop> cv_loops = surf->allBoundaryLoops(degenerate_epsilon);
00119       if (cv_loops.size() == 0)
00120         return cv_loops;
00121 
00122       if (cv_loops[0].size() == 0)
00123         return cv_loops;
00124 
00125       shared_ptr<CurveOnSurface> cv = 
00126         shared_dynamic_cast<CurveOnSurface,ParamCurve>(cv_loops[0][0]);
00127       if (cv.get())
00128         return cv_loops; // Already curve on surface curves
00129 
00130       vector<CurveLoop> cv_loops2;
00131       for (size_t kj=0; kj<cv_loops.size(); ++kj)
00132         {
00133           int nmb_cvs = cv_loops[kj].size();
00134           vector< shared_ptr< ParamCurve > >  vec;
00135           for (int ki=0; ki<nmb_cvs; ++ki)
00136             {
00137               shared_ptr<ParamCurve> sfcv = 
00138                 shared_ptr<ParamCurve>(new CurveOnSurface(surf, cv_loops[kj][ki], false));
00139               vec.push_back(sfcv);
00140             }
00141           cv_loops2.push_back(CurveLoop(vec, degenerate_epsilon));
00142         }
00143       return cv_loops2;
00144     }
00145 }

int Go::analyzePeriodicity ( const BsplineBasis &  basis,
double  knot_tol = 1e-12 
)

Analyze periodicity of basis based on number of repeating knots.

The return value is -1 if there is no repeating (or order-tuple end knots), up to k if there are (order-1-k)-tuple end knots and sufficient repeats for a C^k curve. This is mostly a helper function for the curve and surface analysis functions.

Parameters:
basis reference to the BsplineBasis to analyze
knot_tol the tolerance used when comparing knots and knot intervals
Returns:
-1 if there is no repeating (or order-tuple end knots), up to k if there are (order-1-k)-tuple end knots and sufficient repeats for a C^k curve.

Definition at line 114 of file GeometryTools.C.

References Go::BsplineBasis::begin(), Go::BsplineBasis::endMultiplicity(), Go::BsplineBasis::endparam(), Go::BsplineBasis::numCoefs(), Go::BsplineBasis::order(), and Go::BsplineBasis::startparam().

00116 {
00117     // Check if the first knots are repeated
00118     // (translated) at the end.
00119     // We must first find our 'target' number of repeats,
00120     // by checking the multiplicity of the startparam() knot.
00121     int emul = basis.endMultiplicity(true);
00122     if (basis.endMultiplicity(false) != emul) {
00123         return -1;
00124     }
00125     int k = basis.order();
00126     int n = basis.numCoefs();
00127     double delta = basis.endparam() -  basis.startparam();
00128     std::vector<double>::const_iterator kn = basis.begin();
00129     int i = 1;
00130     for (; i < k-emul+1; ++i) {
00131         double d1 = kn[n+emul-1+i] - kn[k-1+i];
00132         double d2 = kn[n-i] - kn[k-emul-i];
00133         // We only allow minimal floating point errors
00134         if (std::max(std::abs(d1-delta), std::abs(d2-delta)) > knot_tol) {
00135             break;
00136         }
00137     }
00138     return i - 2;
00139 }

int Go::analyzePeriodicity ( const SplineSurface &  sf,
int  direction,
double  knot_tol = 1e-12 
)

Analyze periodicity of surface based on number of repeating knots and control points.

The return value is -1 if the surface edges are disjoint, otherwise k if sf is C^k continuous across the seam. These are sufficient but not necessary conditions for periodicity, so it is possible that a call to analyzePeriodicityDerivs() will yield a higher degree of periodicity. The current implementation is quite slow, and not optimized for speed.

Parameters:
sf reference to the SplineSurface to be analyzed
direction specify 'direction' to be '0' to check for periodicity in the first parameter direction, or '1' to check the second parameter direction.
knot_tol the tolerance used when comparing knot intervals
Returns:
-1 if the surface edges are disjoint, otherwise k if the

Definition at line 100 of file GeometryTools.C.

References analyzePeriodicity(), representSurfaceAsCurve(), and THROW.

00102 {
00103     if (direction < 0 || direction > 1) {
00104         THROW("Error in direction parameter. Must be 0 or 1.");
00105     }
00106     // Make a hypercurve from this surface.
00107     // Direction parameter is one more for representSurface...() :-P
00108     boost::shared_ptr<SplineCurve> cv
00109         = representSurfaceAsCurve(sf, direction + 1);
00110     return analyzePeriodicity(*cv, knot_tol);
00111 }

int Go::analyzePeriodicity ( const SplineCurve &  cv,
double  knot_tol = 1e-12 
)

Analyze periodicity of curve based on number of repeating knots and control points.

The return value is -1 if the curve ends are disjoint, otherwise k if cv is C^k continuous. These are sufficient but not necessary conditions for periodicity, so it is possible that a call to analyzePeriodicityDerivs() will yield a higher degree of periodicity.

Parameters:
cv the curve to analyse
knot_tol the tolerance used when comparing knot intervals.
Returns:
-1 if the curve ends are disjoint, or k if the curve is proven to be C^k continuous.

Definition at line 51 of file GeometryTools.C.

References Go::SplineCurve::basis(), Go::SplineCurve::coefs_begin(), Go::SplineCurve::dimension(), Go::SplineCurve::numCoefs(), Go::SplineCurve::rational(), and Go::SplineCurve::rcoefs_begin().

Referenced by analyzePeriodicity(), Go::SplineCurve::appendSelfPeriodic(), and main().

00053 {
00054     // Analyze the knot vectors for periodicity.
00055     // That is, check if the first knots are repeated
00056     // (translated) at the end.
00057     int basper = analyzePeriodicity(cv.basis(), knot_tol);
00058     if (basper == -1) return -1;
00059 
00060     // Analyze the coefficient vector for periodicity.
00061     // The (basper+1) first must equal the (basper+1) last.
00062     int n = cv.numCoefs() - basper - 1;
00063     int dim = cv.dimension();
00064     std::vector<double>::const_iterator c = cv.coefs_begin();
00065     if (cv.rational()) {
00066         ++dim;
00067         c = cv.rcoefs_begin();
00068     }
00069     for (int i = 0; i < basper + 1; ++i) {
00070         for (int dd = 0; dd < dim; ++dd) {
00071             if (c[dim*i + dd] != c[dim*(i+n) + dd]) {
00072                 return -1;
00073             }
00074         }
00075     }
00076     return basper;
00077 }

int Go::analyzePeriodicityDerivs ( const SplineSurface &  sf,
int  direction,
int  max_derivs,
double  tol = 1e-14 
)

Analyze periodicity of surface based on evaluating derivatives at opposing ends of the surface.

The return value is -1 if the surface edges are disjoint, otherwise k if sf is C^k continuous across the seam. These are sufficient but not necessary conditions for periodicity, so it is possible that a call to analyzePeriodicityDerivs() will yield a higher degree of periodicity. The current implementation is quite slow, and not optimized for speed.

Parameters:
sf the SplineSurface to analyze for periodicity
direction the parameter direction to check for periodicity (0 to check in the first parameter direction, 1 to check in the second.
max_derivs the maximum of computed derivatives (the analysis cannot detect continuities beyond this value
tol the tolerance used when comparing points and derivatives for approximate equality.
Returns:
-1 if the surface edges are disjoint, or k if the surface is proven to be C^k continuous across the seam.

Definition at line 81 of file GeometryTools.C.

References analyzePeriodicityDerivs(), representSurfaceAsCurve(), and THROW.

00086 {
00087     if (direction < 0 || direction > 1) {
00088         THROW("Error in direction parameter. Must be 0 or 1.");
00089     }
00090     // Make a hypercurve from this surface.
00091     // Direction parameter is one more for representSurface...() :-P
00092     boost::shared_ptr<SplineCurve> cv
00093         = representSurfaceAsCurve(sf, direction + 1);
00094     return analyzePeriodicityDerivs(*cv, max_derivs, tol);
00095 }

int Go::analyzePeriodicityDerivs ( const ParamCurve &  cv,
int  max_derivs,
double  tol = 1e-14 
)

Analyze periodicity of curve based on evaluating derivatives at both endpoints.

The return value is -1 if the curve ends are disjoint, otherwise k if cv is C^k continuous. A maximum of max_derivs derivatives are computed, so the analysis cannot yield a higher return value then max_derivs. The tolerance is the amount the point and derivatives are allowed to be different at the two ends. The default is quite tight!

Parameters:
cv the curve to be analyzed for periodicity
max_derivs the maximum of computed derivatives (the analysis can not detect continuities beyond this value).
tol the tolerance used when comparing points and derivatives for approximate equality
Returns:
-1 if the curve ends are disjoint, k if the curve is proven to be C^k continuous.

Definition at line 32 of file GeometryTools.C.

References Go::ParamCurve::endparam(), Go::ParamCurve::point(), and Go::ParamCurve::startparam().

Referenced by analyzePeriodicityDerivs(), and main().

00034 {
00035     // Compute derivatives at start and end.
00036     std::vector<Point> ptsbeg(max_derivs + 1);
00037     std::vector<Point> ptsend(max_derivs + 1);
00038     cv.point(ptsbeg, cv.startparam(), max_derivs);
00039     cv.point(ptsend, cv.endparam(), max_derivs);
00040 
00041     // Compare computed points
00042     int i = 0;
00043     for (; i <= max_derivs; ++i) {
00044         double diff = ptsbeg[i].distInf(ptsend[i]);
00045         if (diff > tol) break;
00046     }
00047     return i - 1;
00048 }

template<typename T >
T Go::area ( const Array< T, 3 > *  c  )  [inline]

Computes the area of a 2-dimensional triangle.

Input is an array of corner points. Same function also exists for 2-dimensional triangles.

Definition at line 73 of file Volumes.h.

References Go::Array< T, Dim >::cross(), and Go::Array< T, Dim >::length().

00074 {
00075     // Using the one-half cross product rule
00076     Array<T, 3> d0 = c[1] - c[0];
00077     Array<T, 3> d1 = c[2] - c[0];
00078     Array<T, 3> crossprod = d0.cross(d1);
00079     return 0.5 * crossprod.length();
00080 }

template<typename T >
T Go::area ( const Array< T, 2 > *  c  )  [inline]

Computes the area of a 2-dimensional triangle.

Input is an array of corner points. Same function also exists for 3-dimensional triangles.

Definition at line 66 of file Volumes.h.

References simplex_volume().

Referenced by Go::SmoothSurf::approxOrigRational(), Go::BoundedSurface::area(), Go::SplineSurface::areaDiagonalCross(), Go::BaryCoordSystemTriangle3D::BaryCoordSystemTriangle3D(), evaluateMinCurvatureRadius(), main(), and Go::SmoothSurf::setOptimizeRational().

00067 { return simplex_volume(c); }

void Go::averageBoundaryCoefs ( boost::shared_ptr< SplineSurface > &  srf1,
int  bd1,
bool  keep_first,
boost::shared_ptr< SplineSurface > &  srf2,
int  bd2,
bool  keep_second,
bool  found_corner1,
Point  corner1,
bool  found_corner2,
Point  corner2,
bool  opposite 
)

Average specified boundary coefficients between two spline surfaces to ensure a C0 transition.

Definition at line 1214 of file GeometryTools.C.

References unifySurfaceSplineSpace().

01219 {
01220     // Make sure that the parameter directions of the two surfaces correspond
01221     // Let the coefficients with constant v-parameter be the ones to average
01222     if (bd1 <= 1)
01223         srf1->swapParameterDirection();
01224     if (bd2 <= 1)
01225         srf2->swapParameterDirection();
01226 
01227     if (opposite)
01228         srf2->reverseParameterDirection(true);
01229 
01230     // Make sure that the parameter interval in u-direction is unique
01231     double umin1 = srf1->startparam_u();
01232     double umax1 = srf1->endparam_u();
01233     double umin2 = srf2->startparam_u();
01234     double umax2 = srf2->endparam_u();
01235     double ptol = 1.0e-12;
01236     if (fabs(umin1-umin2) > ptol || fabs(umax1-umax2) > ptol)
01237     {
01238         double umin = 0.5*(umin1 + umin2);
01239         double umax = 0.5*(umax1 + umax2);
01240     
01241         srf1->setParameterDomain(umin, umax, srf1->startparam_v(), srf1->endparam_v());
01242         srf2->setParameterDomain(umin, umax, srf2->startparam_v(), srf2->endparam_v());
01243     }
01244 
01245     // Ensure the same spline space in the u-direction
01246     vector<shared_ptr<SplineSurface> > sfs(2);
01247     sfs[0] = srf1;
01248     sfs[1] = srf2;
01249     unifySurfaceSplineSpace(sfs, ptol, 1);
01250     srf1 = sfs[0];
01251     srf2 = sfs[1];
01252 
01253     // Check degeneracy
01254     double deg_tol = 1.0e-6;
01255     bool b1, r1, t1, l1, b2, r2, t2, l2;
01256     bool degen1 = srf1->isDegenerate(b1, r1, t1, l1, deg_tol);
01257     bool degen2 = srf2->isDegenerate(b2, r2, t2, l2, deg_tol);
01258     degen1 = (bd1 == 1 || bd1 == 3) ? t1 : b1;
01259     degen2 = (bd2 == 1 || bd2 == 3) ? t2 : b2;
01260     // Replace the specified boundary coefficients with the average ones. It is either the first
01261     // or the last row of coefficients
01262     // Be careful not to destroy degenerate boundaries
01263     int dim = srf1->dimension();
01264     vector<double>::iterator c1 = srf1->coefs_begin();
01265     int in1 = srf1->numCoefs_u();
01266     vector<double>::iterator c2 = srf2->coefs_begin();
01267     if (bd1 == 1 || bd1 == 3)
01268         c1 += (srf1->numCoefs_v()-1)*in1*dim;
01269     if (bd2 == 1 || bd2 == 3)
01270         c2 += (srf2->numCoefs_v()-1)*in1*dim;
01271 
01272     // Check if the corner information corresponds to the boundary orientation
01273     vector<double> d1(dim), d2(dim);
01274     vector<double>::iterator c3 = c1;
01275     vector<double>::iterator c4 = c1 + (in1-1)*dim;
01276     for (int kr=0; kr<dim; kr++, c3++, c4++)
01277     {
01278         d1[kr] = *c3;
01279         d2[kr] = *c4;
01280     }
01281     Point pt1(d1.begin(), d1.end());
01282     Point pt2(d2.begin(), d2.end());
01283     if ((found_corner1 && found_corner2 && pt1.dist(corner1) > pt1.dist(corner2)) ||
01284         (!found_corner1 && pt1.dist(corner2) < pt2.dist(corner2)) ||
01285         (!found_corner2 && pt2.dist(corner1) < pt1.dist(corner1)))
01286     {
01287         // Switch 
01288         std::swap(found_corner1,found_corner2);
01289         std::swap(corner1,corner2);
01290     }
01291 
01292     if (!(degen1 && degen2))
01293     {
01294         for (int ki=0; ki<in1*dim; ki++, c1++, c2++)
01295         {
01296             bool start = (ki==0 || ki==1 || ki==2);
01297             bool end = (ki==in1*dim-3 || ki==in1*dim-2 || ki==in1*dim-1);
01298             if (start && l1 && l2)
01299                 continue;
01300             if (end && r1 && r2)
01301                 continue;
01302             double tmid = 0.5*((*c1) + (*c2));
01303             if (start && found_corner1)
01304                 tmid = corner1[ki%dim];
01305             if (end && found_corner2)
01306                 tmid = corner2[ki%dim];
01307             if (keep_first || degen1 || (start && l1) || (end && r1))
01308                 tmid = *c1;
01309             if (keep_second || degen2 || (start && l2) || (end && r2))
01310                 tmid = *c2;
01311             *c1 = tmid;
01312             *c2 = tmid;
01313         }
01314     }
01315 
01316     if (srf1->rational())
01317       {
01318         // This fix will not work for all configuration of rational surfaces.
01319         // Update the rational coefficients with respect to the divided
01320         // ones
01321         c1 = srf1->coefs_begin();
01322         vector<double>::iterator r1 = srf1->rcoefs_begin();
01323         int kn = srf1->numCoefs_u()*srf1->numCoefs_v();
01324         for (int ki=0; ki<kn; ++ki)
01325           {
01326             for (int kr=0; kr<dim; ++kr)
01327               r1[kr] = c1[kr]*r1[dim];
01328             c1 += dim;
01329             r1 += (dim+1);
01330           }
01331       }
01332 
01333     if (srf2->rational())
01334       {
01335         // This fix will not work for all configuration of rational surfaces.
01336         // Update the rational coefficients with respect to the divided
01337         // ones
01338         c2 = srf2->coefs_begin();
01339         vector<double>::iterator r2 = srf2->rcoefs_begin();
01340         int kn = srf2->numCoefs_u()*srf2->numCoefs_v();
01341         for (int ki=0; ki<kn; ++ki)
01342           {
01343             for (int kr=0; kr<dim; ++kr)
01344               r2[kr] = c2[kr]*r2[dim];
01345             c2 += dim;
01346             r2 += (dim+1);
01347           }
01348       }
01349 
01350      // Set the surfaces back to the initial parameter domain
01351     if (fabs(umin1-umin2) > ptol || fabs(umax1-umax2) > ptol)
01352     {
01353         srf1->setParameterDomain(umin1, umax1, srf1->startparam_v(), srf1->endparam_v());
01354         srf2->setParameterDomain(umin2, umax2, srf2->startparam_v(), srf2->endparam_v());
01355     }
01356     
01357     if (opposite)
01358         srf2->reverseParameterDirection(true);
01359 
01360     if (bd1 <= 1)
01361         srf1->swapParameterDirection();
01362     if (bd2 <= 1)
01363         srf2->swapParameterDirection();
01364 
01365 
01366 }

template<typename SquareMatrix >
void Go::backwardSubstitution ( const SquareMatrix &  U,
std::vector< double > *  x,
int  num_unknowns 
) [inline]

Using backward substitution to calculate x on the system Ux = b, where U is an upper triangular matrix with unitary diagonal.

Parameters:
U The upper triangular matrix. The actually used class must support the operation [][] and return 'double'.
x At function invocation, x should point to a vector of doubles, containing the vector 'b'. On successful completion of the function, this vector will contain the solution for x.
num_unknowns The system size (number of unknowns).

Definition at line 167 of file LUDecomp_implementation.h.

00169 {
00170     const int dim = int(x[0].size());
00171     for (int dd = 0; dd < dim; ++dd) {
00172         x[num_unknowns-1][dd] /= A[num_unknowns-1][num_unknowns-1];
00173     }
00174     for (int i = num_unknowns - 2; i >= 0; --i) {
00175         for (int j = i+1; j < num_unknowns; ++j) {
00176             for (int dd = 0; dd < dim; ++dd) {
00177                 x[i][dd] -= A[i][j] * x[j][dd];
00178             }
00179         }
00180         for (int dd = 0; dd < dim; ++dd) {
00181             x[i][dd] /= A[i][i];
00182         }
00183     }
00184 }

template<typename SquareMatrix , typename T >
void Go::backwardSubstitution ( const SquareMatrix &  U,
T *  x,
int  num_unknowns 
) [inline]

Using backward substitution to calculate x on the system Ux = b, where U is an upper triangular matrix with unitary diagonal.

Parameters:
U The upper triangular matrix. The actually used class must support the operation [][] and return 'double'.
x At function invocation, x should point to an array of T, containing the vector 'b'. On successful completion of the function, this array will contain the solution for x.
num_unknowns The system size (number of unknowns).

Definition at line 153 of file LUDecomp_implementation.h.

Referenced by Go::SmoothCurve::equationSolve(), and LUsolveSystem().

00155 {
00156     x[num_unknowns-1] /= A[num_unknowns-1][num_unknowns-1];
00157     for (int i = num_unknowns - 2; i >= 0; --i) {
00158         for (int j = i+1; j < num_unknowns; ++j) {
00159             x[i] -= A[i][j] * x[j];
00160         }
00161         x[i] /= A[i][i];
00162     }
00163 }

double Go::binom ( int  n,
int  i 
) [inline]

Computes the binomial coefficient: n! / (i! (n-i)!).

Definition at line 25 of file binom.h.

Referenced by curve_ratder(), Go::SplineSurface::normalSurface(), quadrinomial(), surface_ratder(), and trinomial().

00026 {
00027     if (i < 0 || i > n)
00028         return 0.0;
00029 
00030     static std::vector<std::vector<double> > pascals_triangle(10);
00031     static bool first_time = true;
00032     if (first_time) {
00033         first_time = false;
00034         pascals_triangle.resize(1);
00035         pascals_triangle[0].resize(1);
00036         pascals_triangle[0][0] = 1;
00037     }
00038     int old_size = pascals_triangle.size();
00039     if (old_size < n+1) {
00040         // We must expand the triangle
00041         pascals_triangle.resize(n+1);
00042         // Compute the terms of the new rows
00043         for (int nr = old_size; nr < n+1; ++nr) {
00044             pascals_triangle[nr].resize(nr+1);
00045             pascals_triangle[nr][0] = 1.0;
00046             for (int j = 1; j < nr; ++j) {
00047                 pascals_triangle[nr][j]
00048                     = pascals_triangle[nr-1][j-1] + pascals_triangle[nr-1][j];
00049             }
00050             pascals_triangle[nr][nr] = 1.0;
00051         }
00052     }
00053     return pascals_triangle[n][i];
00054 }

template<class Functor >
double Go::brent_minimize ( const Functor &  f,
double  a,
double  b,
double  c,
double &  parmin,
const double  rel_tolerance = std::sqrt(std::numeric_limits<double>::epsilon()) 
) [inline]

Definition at line 44 of file brent_minimize.h.

References f(), Go::FunctionMinimizer< Functor >::getPar(), and Go::FunctionMinimizer< Functor >::linminBrent().

00049 {
00050     Fun2Fun<Functor> f2(f, a, c);
00051     Go::FunctionMinimizer<Fun2Fun<Functor> > fmin(1, f2, &a, rel_tolerance);
00052     Go::Point dir(1);
00053     dir[0] = 1.0;
00054     double bracket[3];
00055     double fval_brak[3];
00056     bracket[0] = 0.0;
00057     bracket[1] = b-a;
00058     bracket[2] = c-a;
00059     fval_brak[0] = f(a);
00060     fval_brak[1] = f(b);
00061     fval_brak[2] = f(c);
00062     double minimum = fmin.linminBrent(dir, bracket, fval_brak);
00063     parmin = fmin.getPar(0);
00064     return minimum;
00065 }

bool Go::checkConstantCoef ( SplineCurve &  cv,
int  idx,
double  val,
double  max_dist,
double  tol 
)

Check if a curve coefficient is equal to a constant in a specified dimension provided it already lies close.

Definition at line 303 of file GeometryTools.C.

References Go::SplineCurve::coefs_begin(), Go::SplineCurve::dimension(), and Go::SplineCurve::numCoefs().

00309 {
00310     int ncoef = cv.numCoefs();
00311     int dim = cv.dimension();
00312     vector<double>::const_iterator coef = cv.coefs_begin();
00313 
00314     if (idx >= dim)
00315         return false;   // Question does not make sense
00316 
00317     bool identical = true;
00318     for (int ki=0; ki<ncoef; ki++, coef+=dim)
00319     {
00320         double d1 = fabs(coef[idx]-val);
00321         if (d1 > max_dist)
00322             return false;   // Curve does not lie close the given value
00323         if (d1 > tol)
00324             identical = false;
00325     }
00326     return (!identical);
00327 }

int Go::closest_in_array ( const double *  pt,
const double *  array,
int  n,
int  dim 
)

Find the point in an array closest to the given base point (measured in the usual, Euclidean distance).

Parameters:
pt pointer to the base point (of dimension 'n')
array pointer to the array in which we will search
n number of elements in the array
dim dimension of the elements/base point

Definition at line 48 of file Utils.C.

References distance_squared().

00050 {
00051     double best_dist2 = distance_squared(pt, pt+dim, array);
00052     int best_index = 0;
00053     double dist2;
00054     for (int i = 1; i < n; ++i) {
00055         dist2 = distance_squared(pt, pt+dim, array + i*dim);
00056         if (dist2 < best_dist2) {
00057             best_dist2 = dist2;
00058             best_index = i;
00059         }
00060     }
00061     return best_index;
00062 }

double GO_API Go::closest_on_line_segment ( const Vector3D &  pt,
const Vector3D &  beg,
const Vector3D &  end 
)

Find the closest point on a line segment to a given point.

Parameters:
pt the point for which we want to find the closest point on the line segment
beg the start point of the line segment
end the end point of the line segment
Returns:
the barycentric coordinate of the closest point on the line segment (number between 0 and 1, where 0 is the start point and 1 is the end point)

Definition at line 250 of file Utils.C.

References Go::Array< T, Dim >::dist2().

Referenced by closest_on_triangle().

00254 {
00255     double t = ((pt-beg)*(end-beg))/beg.dist2(end);
00256     if (t < 0) return 0;
00257     if (t > 1) return 1;
00258     return t;
00259 }

void Go::closest_on_rectgrid ( const double *  pt,
const double *  array,
int  u_min,
int  u_max,
int  v_min,
int  v_max,
int  nmb_coefs_u,
double &  clo_u,
double &  clo_v 
)

Find an approximate closest point on a sub-grid of a rectangular grid of 3-dimensional points.

The method used is to 'triangulate' the grid, and locate the closest point on this triangulation. We imagine that the parametrization of the sub-grid is from 'u_min' to 'u_max' along each row and from 'v_min' to 'v_max' along each column.

Parameters:
pt the point we want to search the closest point for
array pointer to the array of 3D-points; coordinates should be stored consecutively in a row-wise fashion.
u_min lowest column index of the subgrid we want to search
u_max highest column index of the subgrid we want to search
v_min lowest row index of the subgrid we want to search
v_max highest row index of the subgrid we want to search
nmb_coefs_u total number of columns in the complete grid (necessary to know in order to determine how far to jump to get to the next row in the subgrid.
clo_u upon function return; the u-parameter of the closest point, using the parametrization explained above.
clo_v upon function return; the v-parameter of the closest point, using the parametrization explained above.

Definition at line 137 of file Utils.C.

References closest_on_triangle(), and Go::Array< T, Dim >::setValue().

00142 {
00143     // m is number of columns
00144     // n is number of rows
00145     // in array, the column index runs fastest.
00146 
00147     // For each (not necessarily planar) quadrangle, split into 2
00148     // triangles. Then find distance to triangle, and closest point
00149     // in triangle.
00150 
00151     Vector3D pnt(pt);
00152     Vector3D p[4];
00153     Vector3D tri[3];
00154 
00155     Vector3D umask1(0, 1, 0);
00156     Vector3D umask2(1, 1, 0);
00157     Vector3D vmask1(0, 0, 1);
00158     Vector3D vmask2(0, 1, 1);
00159 
00160     double bestdist2 = 1e100;
00161     double best_u = 0;
00162     double best_v = 0;
00163 
00164     for (int i = u_min; i < u_max; ++i) {
00165         for (int j = v_min; j < v_max; ++j) {
00166             // Pick the corner points counterclockwise
00167             p[0].setValue(array + (j*nmb_coefs_u + i)*3);
00168             p[1].setValue(array + (j*nmb_coefs_u + i+1)*3);
00169             p[2].setValue(array + ((j+1)*nmb_coefs_u + i+1)*3);
00170             p[3].setValue(array + ((j+1)*nmb_coefs_u + i)*3);
00171             // Lower triangle, points 0, 1, 3.
00172             tri[0] = p[0];
00173             tri[1] = p[1];
00174             tri[2] = p[3];
00175             double clo_dist2;
00176             Vector3D cltri = closest_on_triangle(pnt, tri, clo_dist2);
00177             if (clo_dist2 < bestdist2) {
00178                 best_u = i + umask1*cltri;
00179                 best_v = j + vmask1*cltri;
00180                 bestdist2 = clo_dist2;
00181             }
00182             // Upper triangle, points 1, 2, 3.
00183             tri[0] = p[1];
00184             tri[1] = p[2];
00185             tri[2] = p[3];
00186             cltri = closest_on_triangle(pnt, tri, clo_dist2);
00187             if (clo_dist2 < bestdist2) {
00188                 best_u = i + umask2*cltri;
00189                 best_v = j + vmask2*cltri;
00190                 bestdist2 = clo_dist2;
00191             }
00192         }
00193     }
00194     clo_u = best_u;
00195     clo_v = best_v;
00196     int ii = min(int(floor(clo_u)), u_max - 1);
00197     int jj = min(int(floor(clo_v)), v_max - 1);
00198     p[0].setValue(array + (jj*nmb_coefs_u + ii)*3);
00199     p[1].setValue(array + (jj*nmb_coefs_u + ii+1)*3);
00200     p[2].setValue(array + ((jj+1)*nmb_coefs_u + ii+1)*3);
00201     p[3].setValue(array + ((jj+1)*nmb_coefs_u + ii)*3);
00202 }

void Go::closest_on_rectgrid ( const double *  pt,
const double *  array,
int  m,
int  n,
double &  clo_u,
double &  clo_v 
)

Find an approximate closest point on a rectangular grid of 3-dimensional points.

The method used is to 'triangulate' the grid, and locate the closest point on this triangulation. We imagine that the point grid is uniformly parametrized from 0 to m-1 along each row and from 0 to n-1 along each column, and we refer to these parameters as 'u' and 'v'.

Parameters:
pt the point we want to search the closest point for
array pointer to the array of 3D-points; coordinates should be stored consecutively in a row-wise fashion.
m number of columns in the point array
n number of rows in the point array
clo_u upon function return; the u-parameter of the closest point, using the parametrization explained above.
clo_v upon function return; the v-parameter of the closest point, using the parametrization explained above.

Definition at line 66 of file Utils.C.

References closest_on_triangle(), and Go::Array< T, Dim >::setValue().

00070 {
00071     // m is number of columns
00072     // n is number of rows
00073     // in array, the column index runs fastest.
00074 
00075     // For each (not necessarily planar) quadrangle, split into 2
00076     // triangles. Then find distance to triangle, and closest point
00077     // in triangle.
00078 
00079     Vector3D pnt(pt);
00080     Vector3D p[4];
00081     Vector3D tri[3];
00082 
00083     Vector3D umask1(0, 1, 0);
00084     Vector3D umask2(1, 1, 0);
00085     Vector3D vmask1(0, 0, 1);
00086     Vector3D vmask2(0, 1, 1);
00087 
00088     double bestdist2 = 1e100;
00089     double best_u = 0;
00090     double best_v = 0;
00091 
00092     for (int col = 0; col < m-1; ++col) {
00093         for (int row = 0; row < n-1; ++row) {
00094             // Pick the corner points counterclockwise
00095             p[0].setValue(array + (row*m + col)*3);
00096             p[1].setValue(array + (row*m + col+1)*3);
00097             p[2].setValue(array + ((row+1)*m + col+1)*3);
00098             p[3].setValue(array + ((row+1)*m + col)*3);
00099             // Lower triangle, points 0, 1, 3.
00100             tri[0] = p[0];
00101             tri[1] = p[1];
00102             tri[2] = p[3];
00103             double clo_dist2;
00104             Vector3D cltri = closest_on_triangle(pnt, tri, clo_dist2);
00105             if (clo_dist2 < bestdist2) {
00106                 best_u = col + umask1*cltri;
00107                 best_v = row + vmask1*cltri;
00108                 bestdist2 = clo_dist2;
00109             }
00110             // Upper triangle, points 1, 2, 3.
00111             tri[0] = p[1];
00112             tri[1] = p[2];
00113             tri[2] = p[3];
00114             cltri = closest_on_triangle(pnt, tri, clo_dist2);
00115             if (clo_dist2 < bestdist2) {
00116                 best_u = col + umask2*cltri;
00117                 best_v = row + vmask2*cltri;
00118                 bestdist2 = clo_dist2;
00119             }
00120         }
00121     }
00122     clo_u = best_u;
00123     clo_v = best_v;
00124     int i = int(floor(clo_u));
00125     if (i >= m-1)
00126         i = m-2;
00127     int j = int(floor(clo_v));
00128     if (j >= n-1)
00129         j = n-2;
00130     p[0].setValue(array + (j*m + i)*3);
00131     p[1].setValue(array + (j*m + i+1)*3);
00132     p[2].setValue(array + ((j+1)*m + i+1)*3);
00133     p[3].setValue(array + ((j+1)*m + i)*3);
00134 }

Vector3D GO_API Go::closest_on_triangle ( const Vector3D &  pt,
const Vector3D  tri[3],
double &  clo_dist2 
)

Find the closest point on a triangle, in barycentric coordinates.

Parameters:
pt the point for which we want to find the closest point on the triangle
tri the triangle, specified by its three corners
clo_dist2 the squared Euclidean distance from 'pt' to the closest point in the triangle.
Returns:
the barycentric coordinates of the closest point on the triangle

Definition at line 205 of file Utils.C.

References Go::BaryCoordSystemTriangle3D::baryToCart(), Go::BaryCoordSystemTriangle3D::cartToBary(), closest_on_line_segment(), Go::Array< T, Dim >::dist2(), and Go::Array< T, Dim >::normalize().

Referenced by closest_on_rectgrid().

00209 {
00210     // Project the point to the triangle plane.
00211     Vector3D norm = (tri[1]-tri[0]) % (tri[2]-tri[0]);
00212     norm.normalize();
00213     Vector3D diff = pt-tri[0];
00214     Vector3D proj_pt = pt - (diff*norm)*norm;
00215     double proj_dist2 = (diff*norm)*(diff*norm);
00216     BaryCoordSystemTriangle3D cs(tri);
00217     Vector3D bc = cs.cartToBary(proj_pt);
00218     bool allpos = true;
00219     double bestdist2 = 1e100;
00220     Vector3D bestb;
00221     for (int i = 0; i < 3; ++i) {
00222         if (bc[i] < 0) {
00223             allpos = false;
00224             // Closest point may be on the segment given
00225             // by the two other points.
00226             double lp = closest_on_line_segment(proj_pt,
00227                                                 tri[(i+1)%3],
00228                                                 tri[(i+2)%3]);
00229             Vector3D b;
00230             b[i] = 0;
00231             b[(i+1)%3] = 1.0 - lp;
00232             b[(i+2)%3] = lp;
00233             Vector3D realpt = cs.baryToCart(b);
00234             double dist2 = proj_pt.dist2(realpt);
00235             if (dist2 < bestdist2) {
00236                 bestb = b;
00237                 bestdist2 = dist2;
00238             }
00239         }
00240     }
00241     if (allpos) {
00242         bestb = bc;
00243         bestdist2 = 0;
00244     }
00245     clo_dist2 = bestdist2 + proj_dist2;
00246     return bestb;
00247 }

void Go::closestPtCurves ( SplineCurve *  cv1,
SplineCurve *  cv2,
double  epsge,
double &  par1,
double &  par2,
double &  dist 
)

Compute the closest point between two curves.

Parameters:
cv1 pointer to the first curve
cv2 pointer to the second curve
epsge geometrical tolerance
Return values:
par1 parameter of the closest point in the first curve
par2 parameter of the closest point in the second curve
dist distance between the curves at the closest point
void Go::closestPtCurves ( const ParamCurve cv1,
const ParamCurve cv2,
double  tmin1,
double  tmax1,
double  tmin2,
double  tmax2,
double  seed1,
double  seed2,
double &  par1,
double &  par2,
double &  dist,
Point ptc1,
Point ptc2 
)

Newton iteration on the distance function between two curves to find a closest point or an intersection point.

The solution is restricted to the intervals [tmin1,tmax1] and [tmin2,tmax2] in the first and second curves's parameter domain. Ported from the sisl function s1770.

Parameters:
cv1 Curve number one.
cv2 Curve number two.
tmin1 Min. parameter value. First curve
tmax1 Max. parameter value. First curve
tmin2 Min. parameter value. Second curve
tmax2 Max. parameter value. Second curve
seed1 Start point for iteration along curve number one.
seed2 Start point for iteration along curve number two.
Return values:
par1 Parameter value of the first curve's point.
par2 Parameter value of the second curve's point.
dist Distance between the points.
ptc1 Point on curve number one.
ptc2 Point on curve number two.

Definition at line 88 of file closestPtCurves.C.

References Go::FunctionMinimizer< Functor >::fval(), Go::FunctionMinimizer< Functor >::getPar(), minimise_conjugated_gradient(), and Go::ParamCurve::point().

00102 {
00103     const double TOL = 1.0e-8;
00104     double seed[2];
00105     seed[0] = u_seed;
00106     seed[1] = v_seed;
00107     double minpar[2];
00108     minpar[0] = umin;
00109     minpar[1] = vmin;
00110     double maxpar[2];
00111     maxpar[0] = umax;
00112     maxpar[1] = vmax;
00113 
00114     // establing distance function to minimize
00115     CrvDistFun distfun(cv1, cv2, minpar, maxpar);
00116 
00117     // minimize the distance function
00118     FunctionMinimizer<CrvDistFun> funmin(2, distfun, seed, TOL);
00119     minimise_conjugated_gradient(funmin);//, 3); // number of iterations in each cycle
00120 
00121     // calculate and copy results
00122     par1 = funmin.getPar(0);
00123     par2 = funmin.getPar(1);
00124     dist = sqrt(funmin.fval());
00125     ptc1 = cv1->point(par1);
00126     ptc2 = cv2->point(par2);
00127 }

void Go::closestPtCurves ( const ParamCurve cv1,
const ParamCurve cv2,
double &  par1,
double &  par2,
double &  dist,
Point ptc1,
Point ptc2 
)

Compute a closest point or an intersection point between two curves.

Ported from the sisl-functions s1770, s1770_s9corr, s1770_s9dir

Parameters:
cv1 Curve number one.
cv2 Curve number two.
Return values:
par1 Parameter value of the first curve's point.
par2 Parameter value of the second curve's point.
dist Distance between the points.
ptc1 Point on curve number one.
ptc2 Point on curve number two.

Definition at line 49 of file closestPtCurves.C.

References Class_SplineCurve, computeSeedCvCv(), DEBUG_ERROR_IF, Go::GeomObject::dimension(), Go::ParamCurve::endparam(), Go::GeomObject::instanceType(), and Go::ParamCurve::startparam().

00055 {
00056 
00057   DEBUG_ERROR_IF(cv1->dimension()!=cv2->dimension(), "Dimension mismatch.");
00058 
00059   double seed1, seed2;
00060   double tmin1,tmax1,tmin2,tmax2;
00061 
00062   // Use all of the parameter domain.
00063   tmin1 = cv1->startparam();
00064   tmax1 = cv1->endparam();
00065   tmin2 = cv2->startparam();
00066   tmax2 = cv2->endparam();
00067  
00068   if (cv1->instanceType() == Class_SplineCurve &&
00069       cv2->instanceType() == Class_SplineCurve) {
00070       const SplineCurve *pc1 = dynamic_cast<const SplineCurve*>(cv1);
00071       const SplineCurve *pc2 = dynamic_cast<const SplineCurve*>(cv2);
00072 
00073     // Compute seed values
00074     computeSeedCvCv(pc1, pc2, seed1, seed2);
00075   }
00076   else {
00077     seed1 = 0.5*(tmin1+tmax1);
00078     seed2 = 0.5*(tmin2+tmax2);
00079   }
00080 
00081   // Iterate for closest point
00082   closestPtCurves(cv1,cv2,tmin1,tmax1,tmin2,tmax2,seed1,seed2,par1,par2,
00083                   dist,ptc1,ptc2);
00084 
00085 }

void Go::closestPtCurves2D ( ParamCurve *  cv1,
ParamCurve *  cv2,
double  aepsge,
double  tmin1,
double  tmax1,
double  tmin2,
double  tmax2,
double  seed1,
double  seed2,
int  method,
bool  quick,
double &  par1,
double &  par2,
double &  dist,
Point &  ptc1,
Point &  ptc2,
int &  istat 
)

Newton iteration on the distance function between two curves in 2D to find a closest point or an intersection point.

The solution is restricted to the intervals [tmin1,tmax1] and [tmin2,tmax2] in the first and second curves's parameter domain. Ported from the sisl-function s1770_2D.

Parameters:
cv1 Curve number one.
cv2 Curve number two.
aepsge Geometry resolution.
tmin1 Min. parameter value. First curve
tmax1 Max. parameter value. First curve
tmin2 Min. parameter value. Second curve
tmax2 Max. parameter value. Second curve
seed1 Start point for iteration along curve number one.
seed2 Start point for iteration along curve number two.
method 1 or 2. Using the the method in s1770_2D, starting with order one or two. method=3 uses the method from s1770 (order one).
quick Reduce requirement on exactness.
Return values:
par1 Parameter value of the first curve's point.
par2 Parameter value of the second curve's point.
dist Distance in space between the points.
ptc1 Point on curve number one.
ptc2 Point on curve number two.
istat =1 Intersection. =2 Minimum value. =3 Nothing found.

Definition at line 26 of file closestPtCurves2D.C.

References DEBUG_ERROR_IF, Go::GeomObject::dimension(), Go::ParamCurve::endparam(), Go::ParamCurve::point(), and Go::ParamCurve::startparam().

00033              : Newton iteration on the distance function between
00034 *              two curves in 2D to find a closest point or an 
00035 *              intersection point.
00036 *
00037 *
00038 * INPUT      : cv1     - Pointer to the first curve in the intersection.
00039 *              cv2     - Pointer to the second curve in the intersection.
00040 *              aepsge  - Geometry resolution.
00041 *              tmin1   - Start parameter value of the first curve.
00042 *              tmax1   - End parameter value of the first curve.
00043 *              tmin2   - Start parameter value of the second curve.
00044 *              tmax2   - End parameter value of the second curve.
00045 *              seed1   - Start parameter value of the iteration on
00046 *                        the first curve.
00047 *              seed2   - Start parameter value of the iteration on
00048 *                        the second curve.
00049 *
00050 *
00051 *
00052 * OUTPUT     : par1    - Parameter value of of first curve in intersection
00053 *                        point.
00054 *              par2    - Parameter value of of second curve in intersection
00055 *                        point.
00056 *              dist    - Distance in space between the points.
00057 *              ptc1    - Point on curve number one.
00058 *              ptc2    - Point on curve number two.
00059 *              istat   - status messages.
00060 *                                = 1   : Intersection found.
00061 *                                = 2   : A minimum distance found.
00062 *                                = 3   : Nothing found.
00063 *
00064 *
00065 * METHOD     : Newton iteration in two parameter directions.
00066 *
00067 *********************************************************************
00068 */
00069 {
00070   const double DZERO = (double)0.0;
00071   const int dim = cv1->dimension();
00072   DEBUG_ERROR_IF(dim != cv2->dimension(), "Dimension mismatch.");
00073   DEBUG_ERROR_IF(dim != 2, "Only implemented for 2D");
00074 
00075 
00076   // Estimated start values  
00077   Point par_val(seed1, seed2);
00078 
00079   // Parameter end points
00080   double aend1 = cv1->endparam();
00081   double aend2 = cv2->endparam();
00082 
00083   double delta[2];          // Parameter interval of the curves. 
00084   delta[0] = aend1 - cv1->startparam();
00085   delta[1] = aend2 - cv2->startparam();
00086 
00087   //  double tprev = MAXDOUBLE;
00088   bool from_right;
00089   int alt_method;
00090   if (method==2)
00091     alt_method=1;
00092   else
00093     alt_method=method;
00094 
00095   int order;
00096   if (method==2)
00097     order=2;
00098   else
00099     order=1;
00100 
00101   // Evaluate 0-2.st derivatives of both curves.
00102   std::vector<Point> sval1(3,Point(0.0,0.0)), sval2(3,Point(0.0,0.0));
00103   from_right = (par_val[0] == aend1) ? false : true;
00104   cv1->point(sval1, par_val[0], 2, from_right);
00105   from_right = (par_val[1] == aend2) ? false : true;
00106   cv2->point(sval2, par_val[1], 2, from_right);
00107 
00108   Point d(2), c_d(2), nc_d(2);  // Distances between old and new parameter-
00109                                 // value in the two parameter directions.
00110   Point normal_cv1(dim), normal_cv2(dim);  // Curve normals 
00111   Point diff(dim), prev_diff(dim);  //Difference vector between the curves.
00112 
00113  // Compute the distance vector, value and the new step.
00114   double det;
00115   int kstat;
00116   nextStep2D(dist, diff, c_d, det, kstat,  sval1, sval2, method);
00117 
00118   if (kstat == 1) {
00119     // Singular matrix. Try second order.
00120     if (order!=2) {
00121       order=2;
00122       method=2;
00123       nextStep2D(dist, diff, c_d, det, kstat,  sval1, sval2, method);
00124     }
00125     if (kstat == 1) {
00126       // Singular matrix.
00127       if (dist > aepsge)  
00128         // Singularity (closest point) found.
00129         singular(cv1,cv2,par_val,dist,quick,aepsge,c_d[0],diff,sval1,sval2,
00130                  tmin1,tmin2,tmax1,tmax2);
00131       setReturnValues(par_val,cv1,cv2,aepsge,istat,par1,par2,dist,ptc1,ptc2);
00132       return;
00133     }
00134   }
00135 
00136   if (method == 4) {
00137     secant2D(cv1,cv2,par_val,dist,kstat,c_d[0],aepsge,
00138              tmin1,tmin2,tmax1,tmax2);
00139     setReturnValues(par_val,cv1,cv2,aepsge,istat,par1,par2,dist,ptc1,ptc2);
00140     return;
00141   }
00142 
00143   
00144   double prev_dist;         // Previous difference between the curves.
00145   int max_it = 20;          // Maximum number of iterations.
00146   int sing = 0;             // Mark that singularity has ocured.
00147   int p_dir;                // Changing direction in par-space.
00148   int keep_order = 0;
00149   int corr = 0;
00150   int div2 = 0;
00151   int g_up,ng_up,g_dir;     // Changing direction in geometric space.   
00152 
00153   if(quick)
00154     max_it=10;
00155 
00156   // Adjust the step size if we are not inside the parameter interval
00157   d = c_d;
00158   normal_cv1[0] = -sval1[1][1];  normal_cv1[1] = sval1[1][0];  // Only 2D
00159   normal_cv2[0] = -sval2[1][1];  normal_cv2[1] = sval2[1][0];
00160   g_up =  (diff*normal_cv2 >= 0.0) ? 1 : -1;
00161   g_up += (diff*normal_cv1 >= 0.0) ? 10 : -10;
00162   insideParamDomain2D(d,par_val,tmin1,tmax1,tmin2,tmax2,corr);
00163 
00164   prev_dist = dist;
00165   prev_diff = diff;
00166 
00167 
00168   // Start of iteration to find the intersection point
00169   int knbit;
00170   for (knbit = 0; knbit < max_it; knbit++) {
00171     par_val+=d;
00172 
00173     // Test if the current method is OK, or should we change method?
00174     while (1) {
00175       // Evaluate derivatives of curve
00176       from_right = (par_val[0] == aend1) ? false : true;
00177       cv1->point(sval1, par_val[0], order, from_right);
00178       from_right = (par_val[1] == aend2) ? false: true;
00179       cv2->point(sval2, par_val[1], order, from_right);
00180       
00181       // Compute the distanse vector and value and the new step.
00182       nextStep2D(dist, diff, nc_d, det, kstat,  sval1, sval2, method);
00183       if (kstat == 1) {
00184         // Singular matrix.
00185         sing++;
00186         if (order==2) {
00187           if (dist>aepsge)
00188             // Singularity (closest point) found.
00189             singular(cv1,cv2,par_val,dist,quick,aepsge,nc_d[0],diff,
00190                      sval1,sval2,tmin1,tmin2,tmax1,tmax2);
00191           setReturnValues(par_val,cv1,cv2,aepsge,istat,par1,par2,dist,ptc1,ptc2);
00192           return;
00193         } 
00194         else {
00195           order=2;  // Use more terms in the series expansion
00196           method=2;
00197         }
00198       }
00199       else {
00200         // Normal to curve 1
00201         normal_cv1[0] = -sval1[1][1];  normal_cv1[1] = sval1[1][0];
00202         // Normal to curve 2
00203         normal_cv2[0] = -sval2[1][1];  normal_cv2[1] = sval2[1][0];
00204 
00205         // Have normal and difference vectors the same direction ?
00206         ng_up = (diff*normal_cv2 >= 0.0) ? 1 : -1;
00207         ng_up += (diff*normal_cv1 >= 0.0) ? 10 : -10;
00208 
00209         // g_dir=1 if we have not changed position to the other side
00210         // of the intersection point. 0 if changed.
00211         g_dir = (ng_up+g_up != 0);
00212 
00213         // p_dir=1 if the steps in the parameter interval continues
00214         // in the same direction. 0 if direction has changed.
00215         p_dir = (c_d[0]*nc_d[0] >= DZERO &&
00216                  c_d[1]*nc_d[1] >= DZERO);
00217         
00218         if (order!=2 && g_dir && (!p_dir || dist > 0.4*prev_dist)
00219             && !keep_order) {           // Few terms in the series expansion.
00220           if (!quick && div2) div2 = 0; // Not good enough convergence. 
00221           order=2;                      // Change method.
00222           method=2;
00223         }
00224         else if (order==2 && !g_dir) { // Max terms in the series expansion.
00225           if (sing) {        // Found closest point?
00226             if (dist>aepsge)
00227               singular(cv1,cv2,par_val,dist,quick,aepsge,nc_d[0],diff,
00228                        sval1,sval2,tmin1,tmin2,tmax1,tmax2);
00229 
00230             setReturnValues(par_val,cv1,cv2,aepsge,istat,par1,par2,dist,
00231                             ptc1,ptc2);
00232             return;
00233           }
00234           if (div2) div2 = 0; // Closest point not found. Change method
00235           order=1;             
00236           method=alt_method;
00237         }
00238         else {                   // Decreasing distance. 
00239           keep_order = 0;        // Continue with current method.
00240           if (sing) sing = 0;    
00241           break;
00242         }
00243       }
00244     } // end while(1)
00245 
00246 
00247     // We have decided method and computed a new step.
00248     // Test if we are inside the intervals, and if the iteration is
00249     // converging fast enough.
00250     if (corr)
00251       if (!(p_dir && g_dir)) corr = 0;
00252     
00253     if (dist < prev_dist || p_dir) {
00254       // Adjust if we are not inside the parameter interval.
00255 
00256         g_up = ng_up;
00257         d = c_d = nc_d;
00258         insideParamDomain2D(d,par_val,tmin1,tmax1,tmin2,tmax2,corr);
00259 
00260         prev_dist = dist;
00261         prev_diff = diff;
00262 
00263         // if (corr > 3) break;
00264 
00265         if (corr > 2 ||
00266             ((fabs(d[0]/std::max(par_val[0],delta[0])) <= REL_COMP_RES) &&
00267              (fabs(d[1]/std::max(par_val[1],delta[1])) <= REL_COMP_RES)))
00268           break;
00269         if (div2) div2 = 0;
00270 
00271         if (corr > 1 && order==2) {
00272           keep_order = 1;
00273           order=1;
00274           method=alt_method;
00275         }
00276      }
00277      else if (corr > 2 ||
00278               ((fabs(d[0]/std::max(par_val[0],delta[0])) <= REL_COMP_RES) &&
00279                (fabs(d[1]/std::max(par_val[1],delta[1])) <= REL_COMP_RES)))
00280        break;
00281      else {
00282        // Not converging, adjust and try again.
00283        if (dist > prev_dist && div2 > 5)
00284          break;
00285        if (quick && dist > prev_dist && div2 > 3)
00286          break;
00287        div2++;                   // Try half of the step length
00288        par_val -= d;
00289        d[0] *= 0.5;  d[1] *=0.5;
00290      }
00291   }
00292 
00293 
00294   // Iteration stopped, test if point found is within resolution
00295 
00296   if (fabs(det)<0.1) {
00297     if (order < 2) {      // Make sure we have enough derivatives for
00298       order=2;            // further computations
00299       method=2;
00300       
00301       from_right = (par_val[0] == aend1) ? false : true;
00302       cv1->point(sval1, par_val[0], order, from_right);
00303       from_right = (par_val[1] == aend2) ? false : true;
00304       cv2->point(sval2, par_val[1], order, from_right);
00305     }
00306     singular(cv1,cv2,par_val,dist,quick,aepsge,d[0],diff,sval1,sval2,
00307              tmin1,tmin2,tmax1,tmax2);
00308   }
00309 
00310   setReturnValues(par_val,cv1,cv2,aepsge, istat,par1,par2,dist,ptc1,ptc2);
00311 
00312   // Iteration completed.
00313 
00314 
00315 }

void Go::closestPtCurveSurf ( ParamCurve pcurve,
ParamSurface psurf,
double  aepsge,
double  astart1,
double  estart2[],
double  aend1,
double  eend2[],
double  anext1,
double  enext2[],
double &  cpos1,
double  gpos2[],
double &  dist,
Point pt_cv,
Point pt_su,
int &  istat,
bool  second_order = false 
)

Newton iteration on the distance function between a curve and a surface to find a closest point or an intersection point.

The solution is restricted to the interval [astart1,aend1] in the curves's parameter domain and [estart2[],eend2[]] in the surface's parameter domain. Ported from the sisl-function s1772.

Parameters:
pcurve Pointer to the curve in the intersection.
psurf Pointer to the surface in the intersection.
aepsge Geometry resolution.
astart1 Start parameter value of the curve.
estart2[] Start parameter values of surface.
aend1 End parameter value of the curve.
eend2[] End parameter values of the surface.
anext1 Start point for iteration along curve number one.
enext2[] Start parameter values of the iteration on the surface.
second_order if 'true' the function will attempt a second-order method directly.
Return values:
cpos1 Parameter value of the curve in the intersection point.
gpos2[] Parameter values of the surface in the intersection point.
dist Distance between the points.
pt_cv The point on the curve.
pt_su The point on the surface.
istat =1 Intersection. =2 Minimum value. =3 Nothing found.

Definition at line 123 of file closestPtCurveSurf.C.

References Go::ParamSurface::containingDomain(), Go::Point::cross(), DEBUG_ERROR_IF, Go::GeomObject::dimension(), Go::ParamCurve::endparam(), insideParamDomain(), nextStep(), Go::ParamSurface::point(), Go::ParamCurve::point(), Go::ParamCurve::startparam(), Go::RectDomain::umax(), Go::RectDomain::umin(), Go::RectDomain::vmax(), and Go::RectDomain::vmin().

00131              : Newton iteration on the distance function between
00132 *              a curve and a surface to find a closest point
00133 *              or an intersection point.
00134 *              Ported from the sisl-function s1772.
00135 *
00136 *
00137 * INPUT      : pcurve    - Pointer to the curve in the intersection.
00138 *              psurf     - Pointer to the surface in the intersection.
00139 *              aepsge    - Geometry resolution.
00140 *              astart1   - Start parameter value of the curve.
00141 *              estart2[] - Start parameter values of surface.
00142 *              aend1     - End parameter value of the curve.
00143 *              eend2[]   - End parameter values of the surface.
00144 *              anext1    - Start parameter value of the iteration on
00145 *                          the curve.
00146 *              enext2[]  - Start parameter values of the iteration on
00147 *                          the surface.
00148 *
00149 *
00150 * OUTPUT     : cpos1   - Parameter value of the curve in the intersection
00151 *                        point.
00152 *              gpos2[] - Parameter values of the surface in the
00153 *                        intersection point.
00154 *              dist    - Distance between the points.
00155 *              pt_cv   - The point on the curve.
00156 *              pt_su   - The point on the surface.
00157 *              istat   - status messages 
00158 *                                = 1   : Intersection found.
00159 *                                = 2   : A minimum distance found.
00160 *                                = 3   : Nothing found.
00161 *
00162 *
00163 * METHOD     : Newton iteration in tree parameter directions.
00164 *
00165 *********************************************************************
00166 */ 
00167 {
00168 
00169   const int dim = pcurve->dimension();
00170   DEBUG_ERROR_IF(dim != psurf->dimension(), "Dimension mismatch.");
00171   DEBUG_ERROR_IF(dim != 3, "Only implemented for 3D");
00172 
00173 
00174  // Parameter interval of surface and curve 
00175   Point delta(3);
00176   delta[0]=psurf->containingDomain().umax() - psurf->containingDomain().umin();
00177   delta[1]=psurf->containingDomain().vmax() - psurf->containingDomain().vmin();
00178   delta[2]=pcurve->endparam() - pcurve->startparam();
00179 
00180 
00181   int knbit;                // Number of iterations.
00182   int p_dir;                // Changing direction in par-space.
00183   int g_up,ng_up,g_dir;     // Changing direction in geometric space.
00184   int order;                // Order of method.
00185   int sing = 0;             // Mark that singularity has occured.
00186   int left[3];              // Variables used in the evaluator.
00187   Point d(3);               // Clipped distances between old and new par.
00188                             // value in the tree parameter directions.
00189   Point c_d(3);             // Computed distances ....
00190   Point nc_d(3);            // New computed distances ....
00191   double prev_dist;         // Previous difference between curve and surface.
00192   Point par_val(3);         // Parameter values
00193   Point norm_vec(dim);      // Normal vector to the surface
00194   Point diff(dim);          // Difference vector between points.
00195   int corr = 0, div2 = 0;
00196   std::vector<Point> c0(3,Point(dim)), s0(6,Point(dim));
00197 
00198   par_val[0] = enext2[0];
00199   par_val[1] = enext2[1];
00200   par_val[2] = anext1;
00201 
00202   left[0]=left[1]=left[2]=0;
00203 
00204   bool from_right;
00205   int ki, kstat;
00206 
00207 
00208   for (ki=1; ki<3; ki++) {
00209       if (second_order && ki==1)
00210           continue;
00211     order=ki;
00212 
00213     // Evaluate 0-order derivatives of curve
00214     from_right = (par_val[2] == aend1) ? false : true;
00215     pcurve->point(c0, par_val[2], order, from_right);
00216 
00217    // Evaluate 0-order derivatives of surface
00218     psurf->point(s0, par_val[0], par_val[1], order);
00219 
00220     // Compute the distance vector, value and the new step.
00221     nextStep(dist,diff,c_d,kstat,c0,s0,order);
00222 
00223     // Surface's normal vector
00224     norm_vec=s0[1].cross(s0[2]);
00225 
00226     if (kstat == 1) { // Singular matrix
00227       if (order == 2) {
00228         singular(pcurve,psurf,par_val,dist,aepsge,c_d[0],diff,norm_vec,c0,
00229                  s0, astart1,estart2,aend1,eend2);
00230         setReturnValues(par_val,pcurve,psurf,aepsge,istat,cpos1,gpos2,dist,
00231                         pt_cv,pt_su);
00232         istat += 10;
00233         return;
00234       }
00235     }
00236     else break;
00237   }
00238 
00239 
00240   // Adjust the step size if we are not inside the parameter interval
00241 
00242   g_up =  (diff*norm_vec >= DZERO) ? 1 : -1;
00243   d = c_d;
00244   insideParamDomain(d,par_val, astart1,aend1,estart2,eend2,corr);
00245 
00246   prev_dist = dist;
00247 
00248   // Start of iteration to find the intersection point
00249   const int max_it=30;
00250   for (knbit = 0; knbit < max_it; knbit++) {
00251     par_val+=d;
00252 
00253     // Test if the current method is OK, or should we change method?
00254     while (1) {
00255       // Evaluate derivatives of the curve
00256       from_right = (par_val[2] == aend1) ? false : true;
00257       pcurve->point(c0, par_val[2], order, from_right);
00258 
00259       // Evaluate derivatives of the surface
00260       psurf->point(s0, par_val[0], par_val[1], order);      
00261 
00262       // Compute the distanse vector and value and the new step.
00263       nextStep(dist,diff,nc_d,kstat,c0,s0,order);
00264       if (kstat == 1) {
00265         // Singular matrix.
00266         sing++;
00267         if (order==2) {
00268           // Singularity (closest point) found.
00269           singular(pcurve,psurf,par_val,dist,aepsge,nc_d[0],diff,
00270                    norm_vec,c0,s0, astart1,estart2,aend1,eend2);
00271           setReturnValues(par_val,pcurve,psurf,aepsge,istat,cpos1,gpos2,dist,
00272                           pt_cv,pt_su);
00273           istat += 10;
00274           return;
00275         } 
00276         else
00277           order=2;  // Use more terms in the series expansion
00278       }
00279       else {
00280         norm_vec=s0[1].cross(s0[2]);
00281         
00282         // Have normal and difference vectors the same direction ?
00283         ng_up = (diff*norm_vec >= DZERO) ? 1 : -1;
00284         
00285         // g_dir=1 if we have not changed position to the other side
00286         // of the intersection point. 0 if changed.
00287         g_dir = (ng_up+g_up != 0);
00288         
00289         // p_dir=1 if the steps in the parameter interval continues
00290         // in the same direction. 0 if direction has changed.
00291         p_dir = (c_d*nc_d >= DZERO);
00292         
00293         if (order!=2 && g_dir && (!p_dir || dist > 0.3*prev_dist)) {
00294           if (div2)            // Few terms in the series expansion.
00295             div2 = 0;          // Not good enough convergence. 
00296           order=2;             // Change method.
00297         }
00298         else if (order==2 && !g_dir) { // Max terms in the series expansion.
00299           if (sing) {        // Found closest point?
00300             singular(pcurve,psurf,par_val,dist,aepsge,nc_d[0],diff,
00301                      norm_vec,c0,s0, astart1,estart2,aend1,eend2);
00302             setReturnValues(par_val,pcurve,psurf,aepsge,istat,cpos1,gpos2,dist,
00303                             pt_cv,pt_su);
00304             istat += 10;
00305             return;
00306           }
00307           if (div2)
00308             div2 = 0; // Closest point not found. Change method
00309           order=1;             
00310         }
00311         else {           // Decreasing distance. 
00312           if (sing)      // Continue with current method. 
00313             sing = 0;
00314           break;
00315         }
00316       }
00317     } // end while(1)
00318     
00319  
00320     // We have decided method and computed a new step.
00321     // Test if we are inside the intervals, and if the iteration is
00322     // converging fast enough.
00323     if (corr)
00324       if (!(p_dir && g_dir))
00325         corr = 0;
00326     
00327     if (dist < prev_dist) {
00328       // Adjust if we are not inside the parameter interval.
00329       if (div2)
00330         div2 = 0;
00331       g_up = ng_up;
00332       d = c_d = nc_d;
00333       insideParamDomain(d,par_val, astart1,aend1,estart2,eend2,corr);
00334 
00335       prev_dist = dist;
00336 
00337 
00338       if (corr > 3) 
00339         break;
00340     }
00341     else if ( corr > 3 ||
00342               ((fabs(d[0]/delta[0]) <= REL_COMP_RES) &&
00343                (fabs(d[1]/delta[1]) <= REL_COMP_RES) &&
00344                (fabs(d[2]/delta[2]) <= REL_COMP_RES)))
00345       break;
00346     else {
00347       // Not converging, adjust and try again.
00348       if (corr)
00349         corr++;
00350 
00351       if (dist > prev_dist && div2)
00352         break;
00353       div2++;                   // Try half of the step length
00354       par_val -= d;
00355       d[0] *= 0.5;  d[1] *=0.5; d[2] *=0.5;
00356     }
00357 
00358   }
00359 
00360   // end of iteration.
00361 
00362 
00363   setReturnValues(par_val,pcurve,psurf,aepsge, istat,cpos1,gpos2,dist,
00364                   pt_cv,pt_su);
00365 
00366 
00367 }

void Go::closestPtCurveSurf ( ParamCurve pcurve,
ParamSurface psurf,
double  aepsge,
double  astart1,
double  aend1,
RectDomain domain,
double  anext1,
double  enext2[],
double &  cpos1,
double  gpos2[],
double &  dist,
Point pt_cv,
Point pt_su,
bool  second_order = false 
)

Newton iteration on the distance function between a curve and a surface to find a closest point or an intersection point.

The solution is restricted to the interval [astart1,aend1] in the curves's parameter domain and [estart2[],eend2[]] in the surface's parameter domain. Ported from the sisl-function s1772.

Parameters:
pcurve Pointer to the curve in the intersection.
psurf Pointer to the surface in the intersection.
aepsge Geometry resolution.
astart1 Start parameter value of the curve.
aend1 End parameter value of the curve.
domain the parametric domain of interest of the surface
anext1 Start point for iteration along curve number one.
enext2[] Start parameter values of the iteration on the surface.
second_order if 'true' the function will attempt a second-order method directly.
Return values:
cpos1 Parameter value of the curve in the intersection point.
gpos2[] Parameter values of the surface in the intersection point.
dist Distance between the points.
pt_cv The point on the curve.
pt_su The point on the surface.

Definition at line 62 of file closestPtCurveSurf.C.

References DEBUG_ERROR_IF, Go::FunctionMinimizer< Functor >::fval(), Go::FunctionMinimizer< Functor >::getPar(), minimise_conjugated_gradient(), Go::ParamSurface::point(), Go::ParamCurve::point(), Go::RectDomain::umax(), Go::RectDomain::umin(), Go::RectDomain::vmax(), and Go::RectDomain::vmin().

00069 {
00070   int status = 0;
00071   double rel_comp_res = 1.0e-15;
00072   double sstart[2], send[2];
00073   sstart[0] = domain->umin();
00074   sstart[1] = domain->vmin();
00075   send[0] = domain->umax();
00076   send[1] = domain->vmax();
00077   closestPtCurveSurf(pcurve, psurf, aepsge, astart1, sstart, aend1, 
00078                      send, anext1, enext2, cpos1, gpos2, dist,
00079                      pt_cv, pt_su, status, second_order);
00080   DEBUG_ERROR_IF(status < 0,"Error in closest point");
00081 
00082   if (status >= 10 && dist > rel_comp_res && !second_order)
00083   {
00084       // Iteration encountered a singularity. Try fallback iteration
00085     const double TOL = 1.0e-8;
00086     double seed[3], minpar[3], maxpar[3];
00087     double dist2;
00088     minpar[0] = sstart[0];
00089     minpar[1] = sstart[1];
00090     minpar[2] = astart1;
00091     maxpar[0] = send[0];
00092     maxpar[1] = send[1];
00093     maxpar[2] = aend1;
00094     seed[0] = gpos2[0];
00095     seed[1] = gpos2[1];
00096     seed[2] = cpos1;
00097 
00098     CrvSrfDistFun distfun(psurf, pcurve, minpar, maxpar);
00099     FunctionMinimizer<CrvSrfDistFun> funmin(3, distfun, seed, TOL);
00100     minimise_conjugated_gradient(funmin);//, 3); // number of iterations in each cycle
00101 
00102     dist2 = sqrt(funmin.fval());
00103     if (dist2 < dist)
00104     {
00105         dist = dist2;
00106         cpos1 = funmin.getPar(2);
00107         gpos2[0] = funmin.getPar(0);
00108         gpos2[1] = funmin.getPar(1);
00109 
00110         pcurve->point(pt_cv, cpos1);
00111         psurf->point(pt_su, gpos2[0], gpos2[1]);
00112 
00113         status = (dist <= aepsge) ? 1 : 2;
00114     }
00115     else 
00116         status = status % 10;
00117   }
00118 
00119 }

void Go::closestPtSislCurves ( SplineCurve *  cv1,
SplineCurve *  cv2,
double  epsge,
double &  par1,
double &  par2,
double &  dist 
)

Definition at line 19 of file closestPtSislCurves.C.

References ALWAYS_ERROR_IF, Go::SplineCurve::basis(), Go::BsplineBasis::begin(), Go::SplineCurve::coefs_begin(), Go::SplineCurve::coefs_end(), Curve2SISL(), Go::SplineCurve::dimension(), Go::Point::dist(), Go::SplineCurve::endparam(), Go::SplineCurve::order(), Go::SplineCurve::point(), and Go::SplineCurve::startparam().

00026 {
00027 
00028   // Make guess point to the iteration
00029   // Find position of closest vertices
00030   std::vector<double>::const_iterator co1 = cv1->coefs_begin();
00031   std::vector<double>::const_iterator co2 = cv2->coefs_begin();
00032   std::vector<double>::const_iterator co3;
00033   std::vector<double>::const_iterator co12 = cv1->coefs_end();
00034   std::vector<double>::const_iterator co22 = cv2->coefs_end();
00035   int dim = cv1->dimension();
00036   double td, tmin=1.0e8;
00037   int minidx1=0, minidx2=0;
00038   int ki, k1, k2;
00039   for (k1=0; co1<co12; co1+=dim, k1++)
00040     for (k2=0, co3=co2; co3<co22; co3+=dim, k2++)
00041       {
00042         for (td=0.0, ki=0; ki<dim; ki++)
00043           td += (co1[ki]-co3[ki])*(co1[ki]-co3[ki]);
00044         if (td < tmin)
00045           {
00046             tmin = td;
00047             minidx1 = k1;
00048             minidx2 = k2;
00049           }
00050       }
00051 
00052   // Estimate parameter value of vertices
00053   std::vector<double>::const_iterator st;
00054   int kk = cv1->order();
00055 
00056   for (k1=minidx1+1, st=cv1->basis().begin(), par1=0.0;
00057        k1<minidx1+kk; par1+=st[k1], k1++);
00058   par1 /=(double)(kk-1);
00059 
00060   kk = cv2->order();
00061   for (k1=minidx2+1, st=cv2->basis().begin(), par2=0.0;
00062        k1<minidx2+kk; par2+=st[k1], k1++);
00063   par2 /=(double)(kk-1);
00064 
00065   // Make sisl curves and call sisl.
00066   SISLCurve *pc1 = Curve2SISL(*cv1, false);
00067   SISLCurve *pc2 = Curve2SISL(*cv2, false);
00068 
00069   // Iterate for closest point
00070   int stat = 0;
00071   s1770(pc1, pc2, epsge, cv1->startparam(), cv2->startparam(), 
00072         cv1->endparam(), cv2->endparam(), par1, par2, &par1, &par2, 
00073         &stat);
00074   ALWAYS_ERROR_IF(stat<0,"Error in closest point, code: " << stat);
00075 
00076 
00077   Point pt1, pt2;
00078   cv1->point(pt1, par1);
00079   cv2->point(pt2, par2);
00080   dist = pt1.dist(pt2);
00081 
00082   if (pc1 != 0) freeCurve(pc1);
00083   if (pc2 != 0) freeCurve(pc2);
00084 }

void Go::closestPtSurfSurfPlane ( const std::vector< Point > &  epoint,
const std::vector< Point > &  epnt1,
const std::vector< Point > &  epnt2,
const Point &  epar1,
const Point &  epar2,
const ParamSurface *  psurf1,
const ParamSurface *  psurf2,
double  aepsge,
std::vector< Point > &  gpnt1,
std::vector< Point > &  gpnt2,
Point &  gpar1,
Point &  gpar2,
int &  jstat,
AlgorithmChoice  algo = FUNCTIONAL 
)

Newton iteration on the distance function between two surfaces and a plane to find a closest point or an intersection point.

Ported from the sisl-function s9iterate.

Parameters:
epoint - Vector of Points containing parts of plane description. epoint[0] contains a point in the plane. epoint[1] contains the normal vector to the plane.
epnt1 0-2 Derivatives + normal of start point for iteration in first surface.
epnt2 0-2 Derivatives + normal of start point for iteration in second surface.
epar1 Parameter pair of start point in first surface.
epar2 Parameter pair of start point in second surface.
psurf1 Pointer to the first surface.
psurf2 Pointer to the second surface.
aepsge Absolute tolerance.
gpnt1 0-2 Derivatives + normal of result of iteration in first surface.
gpnt2 0-2 Derivatives + normal of result of iteration in second surface.
gpar1 Parameter pair of result of iteration in first surface.
gpar2 Parameter pair of result of iteration in second surface.
jstat =1 Intersection. =2 Minimum value. =3 Nothing found.
algo choose whether the implementation of the algorithm should be based on general function minimization, or a geometric approach

Definition at line 20 of file closestPtSurfSurfPlane.C.

References closestPtSurfSurfPlaneFunctional(), closestPtSurfSurfPlaneGeometrical(), and GEOMETRICAL.

Referenced by Go::IntCrvEvaluator::evaluate().

00035 {
00036     if (algo == GEOMETRICAL) {
00037         closestPtSurfSurfPlaneGeometrical(epoint, 
00038                                           epnt1, 
00039                                           epnt2, 
00040                                           epar1, 
00041                                           epar2, 
00042                                           psurf1, 
00043                                           psurf2, 
00044                                           aepsge, 
00045                                           gpnt1, 
00046                                           gpnt2, 
00047                                           gpar1, 
00048                                           gpar2, 
00049                                           jstat);
00050     } else {
00051         // algo == FUNCTIONAL
00052         closestPtSurfSurfPlaneFunctional(epoint, 
00053                                           epnt1, 
00054                                           epnt2, 
00055                                           epar1, 
00056                                           epar2, 
00057                                           psurf1, 
00058                                           psurf2, 
00059                                           aepsge, 
00060                                           gpnt1, 
00061                                           gpnt2, 
00062                                           gpar1, 
00063                                           gpar2, 
00064                                           jstat);
00065     }
00066 }

void Go::closestPtSurfSurfPlaneFunctional ( const std::vector< Point > &  epoint,
const std::vector< Point > &  epnt1,
const std::vector< Point > &  epnt2,
const Point epar1,
const Point epar2,
const ParamSurface psurf1,
const ParamSurface psurf2,
double  aepsge,
std::vector< Point > &  gpnt1,
std::vector< Point > &  gpnt2,
Point gpar1,
Point gpar2,
int &  jstat 
)

This is the functional-based implementation of closestPtSurfSurfPlane.

It is called from the function above (closestPtSurfSurfPlane()) if it is called with algo = FUNCTIONAL. The user can also choose to call this function directly. The parameter description is the same as in closestPtSurfSurfPlane().

Definition at line 83 of file closestPtSurfSurfPlane_functional.C.

References Go::FunctionMinimizer< Functor >::getPar(), minimise_conjugated_gradient(), and Go::ParamSurface::point().

Referenced by closestPtSurfSurfPlane().

00095 {
00096     // we formulate the problem as minimizing f(x) + c_k P(x), where f(x) is the distance
00097     // of the points in surface 1 and surface 2, and P(x) is the distance to the plane.
00098     // The criteria that the points must be lying in the plane is approached as the 
00099     // multiplicative constant c_k increases.  By choosing a sufficiently high value
00100     // for c_k, we expect to converge within the specified tolerance. 
00101 
00102     gpar1 = gpar2 = Point(2);
00103     gpnt1.resize(3); gpnt2.resize(3);
00104 
00105     const Point plane_normal = epoint[1] / epoint[1].length();
00106 
00107     double C = 1; // = compute_constraint_multiplier(plane_normal, epnt1, epnt2, aepsge);
00108 
00109     double dist_to_plane, old_dist_to_plane;
00110     double seed[4];
00111     seed[0] = epar1[0]; seed[1] = epar1[1];
00112     seed[2] = epar2[0]; seed[3] = epar2[1];
00113 
00114     dist_to_plane = numeric_limits<double>::max();
00115 
00116     while(true) {
00117         old_dist_to_plane = dist_to_plane;
00118         
00119         // make function object here
00120         SurfDistFun distfun(psurf1, psurf2, C, epoint[0], plane_normal);
00121         
00122         // specify function minimizer
00123         FunctionMinimizer<SurfDistFun> dfmin(4, distfun, seed, aepsge);
00124         
00125         // use conjugated gradient algorithm to minimize this function
00126         minimise_conjugated_gradient(dfmin);//, 5); // number of iterations in each cycle
00127         
00128         dist_to_plane = 
00129             compute_distance_to_plane(psurf1->point(dfmin.getPar(0), dfmin.getPar(1)),
00130                                       psurf2->point(dfmin.getPar(2), dfmin.getPar(3)),
00131                                       epoint[0],
00132                                       plane_normal);
00133         
00134         if ( (dist_to_plane < aepsge) || (dist_to_plane >= old_dist_to_plane)) {
00135             // we will quit the loop at this point
00136             gpar1[0] = dfmin.getPar(0);
00137             gpar1[1] = dfmin.getPar(1);
00138             gpar2[0] = dfmin.getPar(2);
00139             gpar2[1] = dfmin.getPar(3);
00140             
00141             gpnt1.resize(3);
00142             gpnt2.resize(3);
00143             psurf1->point(gpnt1, gpar1[0], gpar1[1], 1);
00144             psurf2->point(gpnt2, gpar2[0], gpar2[1], 1);
00145             
00146             if (dist_to_plane < aepsge) {
00147                 jstat = (gpnt1[0].dist(gpnt2[0]) < aepsge) ? 1 : 2;
00148             } else {
00149                 // we are not able to converge properly to plane
00150                 jstat = 3;
00151             }
00152 
00153             // to fulfill the contract that second derivatives and normal should also
00154             // be computed, we will do that here.  Note, however, that these values
00155             // were used nowhere else in this algorithm.
00156             gpnt1.resize(7);
00157             gpnt2.resize(7);
00158             psurf1->point(gpnt1, gpar1[0], gpar1[1], 2);
00159             psurf2->point(gpnt2, gpar2[0], gpar2[1], 2);
00160             gpnt1[6] = gpnt1[1].cross(gpnt1[2]); // nb: not normalized here!
00161             gpnt2[6] = gpnt2[1].cross(gpnt2[2]); // nb: not normalized here!
00162             return;
00163         }
00164         
00165         cout << "multiplying C!  New C is : " << C * 10 << endl;
00166         C *= 10; // if we redo the loop, we need to augment the value of C
00167         copy(dfmin.getPar(), dfmin.getPar() + 4, seed);
00168     } 
00169 }

void Go::closestPtSurfSurfPlaneGeometrical ( const std::vector< Point > &  epoint,
const std::vector< Point > &  epnt1,
const std::vector< Point > &  epnt2,
const Point &  epar1,
const Point &  epar2,
const ParamSurface *  psurf1,
const ParamSurface *  psurf2,
double  aepsge,
std::vector< Point > &  gpnt1,
std::vector< Point > &  gpnt2,
Point &  gpar1,
Point &  gpar2,
int &  jstat 
)

This is the geometrically-based implementation of closestPtSurfSurfPlane.

It is called from the function above (closestPtSurfSurfPlane()) if it is called with algo = GEOMETRICAL. The user can also choose to call this function directly. The parameter description is the same as in closestPtSurfSurfPlane().

Definition at line 41 of file closestPtSurfSurfPlane_geometrical.C.

References Go::ParamSurface::containingDomain(), DEBUG_ERROR_IF, Go::GeomObject::dimension(), Go::Point::length(), Go::RectDomain::lowerLeft(), nextStep(), Go::ParamSurface::normal(), Go::ParamSurface::point(), Go::Point::swap(), and Go::RectDomain::upperRight().

Referenced by closestPtSurfSurfPlane().

00054              : To iterate to an intersection point between two surfaces
00055 *              and a plane.
00056 *              Ported from the sisl function s9iterate.
00057 *
00058 *
00059 *
00060 * INPUT      : epoint - Vector of Points containing parts of plane description.
00061 *                       epoint[0] contains a point in the plane.
00062 *                       epoint[1] contains the normal vector to the plane
00063 *              epnt1  - 0-2 Derivatives + normal of start point for
00064 *                       iteration in first surface
00065 *              epnt2  - 0-2 Derivatives + normal of start point for
00066 *                       iteration in second surface
00067 *              epar1  - Parameter pair of start point in first surface
00068 *              epar2  - Parameter pair of start point in second surface
00069 *              psurf1 - Pointer to the first surface
00070 *              psurf2 - Pointer to the second surface
00071 *              aepsge - Absolute tolerance
00072 *
00073 *
00074 * OUTPUT     : gpnt1  - 0-2 Derivatives + normal of result of iteration
00075 *                       in first surface
00076 *              gpnt2  - 0-2 Derivatives + normal of result of iteration
00077 *                       in second surface
00078 *              gpar1  - Parameter pair of result of iteration in first surface
00079 *              gpar2  - Parameter pair of result of iteration in second
00080 *                       surface
00081 *              jstat  - status messages  
00082 *                       = 3      : Iteration diverged or too many iterations
00083 *                       = 2      : iteration converged, singular point found
00084 *                       = 1      : ok, iteration converged
00085 *
00086 *
00087 * METHOD     :
00088 *
00089 * USE        : The function is only working in 3-D
00090 *
00091 
00092 *
00093 *********************************************************************
00094 */
00095 {
00096     const int kdim = psurf1->dimension();
00097     DEBUG_ERROR_IF(kdim != psurf2->dimension(), "Dimension mismatch.");
00098     DEBUG_ERROR_IF(kdim != 3, "The function is only working i 3-D");
00099 
00100 
00101 
00102     int kcont;              /* Indicator telling if iteration is not finished */
00103     int kder = 2;           /* Derivative indicator                           */
00104     int kstat1;             /* Status variable                                */
00105     int kstat2;             /* Status variable                                */
00106     int knbit;              /* Counter for number of iterations               */
00107     int kmaxit = 100;       /* Maximal number of iterations allowed           */
00108     Point sdiff(kdim);      /* Difference between two vectors                 */
00109     double tdum3;           /* Dummy variables                                */
00110     double tdist=0;         /* Distance between two points in iteration       */
00111     Point normal_vec(3);    /* Surface normal vector                          */
00112     Point delta(2);         /* Parameter step values in the iteration         */
00113   
00114     // Make description of intersection plane
00115 
00116     const Point& spoint = epoint[0];    // Point in the intersection plane.
00117     const Point& snorm  = epoint[1];    // Normal vector of intersection plane
00118 
00119     // determining parameter domain (only rectangular domain - trimmed surfaces not supported
00120     const RectDomain pdom1 = psurf1->containingDomain();
00121     const RectDomain pdom2 = psurf2->containingDomain();
00122     const Vector2D lower_left_1 = pdom1.lowerLeft();
00123     const Vector2D lower_left_2 = pdom2.lowerLeft();
00124     const Vector2D upper_right_1 = pdom1.upperRight();
00125     const Vector2D upper_right_2 = pdom2.upperRight();
00126 
00127     // Copy input variables to output variables
00128 
00129     for (int i=0; i<7; i++) {
00130         gpnt1[i] = epnt1[i];
00131         gpnt2[i] = epnt2[i];
00132     }
00133 
00134     gpar1 = epar1;
00135     gpar2 = epar2;
00136 
00137     // new values of gpnt1 and gpnt2
00138     vector<Point> gpnt1_new(7);
00139     vector<Point> gpnt2_new(7);
00140     Point gpar1_new, gpar2_new;
00141 
00142     // At the start of the iteration the two points gpnt1 and gpnt2 might be very
00143     // close since we in most cases start from a point on the intersection curve.
00144   
00145     kcont = 1;
00146     knbit = 0;
00147   
00148     while (kcont) {
00149     
00150         // Put a parametric representation of the tangent plane of surface 1
00151         // into the implicit representation of the tangent plane of surface 2 
00152         // and also into the implicit representation of the intersection plane.
00153         // The solution of the equation system is the next step along
00154         // the two parameter directions of surface 1.    
00155 
00156         nextStep(gpnt1,gpnt2,snorm,spoint, delta,kstat1);
00157         gpar1_new = gpar1 + delta;
00158         //gpar1 += delta;       
00159         
00160         // Put a parametric representation of the tangent plane of surface 2
00161         // into the implicit representation of the tangent plane of surface 1 
00162         // and also into the implicit representation of the intersection plane.
00163         // The solution of the equation system is the next step along
00164         // the two parameter directions of surface 2.
00165 
00166         nextStep(gpnt2,gpnt1,snorm,spoint, delta,kstat2);
00167         gpar2_new = gpar2 + delta;
00168         //gpar2 += delta;
00169 
00170         // domain checks, kick parameters back into domain!  @@ does this always work?
00171         for (int i = 0; i < 2; ++i) {
00172             gpar1_new[i] = std::max(gpar1_new[i], lower_left_1[i]);
00173             gpar1_new[i] = std::min(gpar1_new[i], upper_right_1[i]);
00174             gpar2_new[i] = std::max(gpar2_new[i], lower_left_2[i]);
00175             gpar2_new[i] = std::min(gpar2_new[i], upper_right_2[i]);
00176         }       
00177 
00178         //  Calculate values of new points and normal vector on surface 1.
00179 
00180         psurf1->point(gpnt1_new, gpar1_new[0], gpar1_new[1], kder);
00181         psurf1->normal(normal_vec, gpar1_new[0], gpar1_new[1]);
00182         gpnt1_new[6]=normal_vec;
00183 
00184         //   If the surface normal has zero length no use in continuing
00185         if (normal_vec.length() == 0.0) {
00186             jstat=3;
00187             break;
00188         }      
00189 
00190         //  Calculate values of new points and normal vector on surface 2.
00191 
00192         psurf2->point(gpnt2_new, gpar2_new[0], gpar2_new[1], kder);
00193         psurf2->normal(normal_vec, gpar2_new[0], gpar2_new[1]);
00194         gpnt2_new[6]=normal_vec;      
00195 
00196         //  If the surface normal has zero length no use in continuing
00197         if (normal_vec.length() == 0.0) {
00198             jstat=3;
00199             break;
00200         }
00201 
00202 
00203         // Make difference between the two points, 
00204         //   and calculate length of difference
00205         sdiff = gpnt1_new[0];
00206         sdiff -= gpnt2_new[0];
00207     
00208         tdum3 = sdiff.length();      
00209         if (tdum3 < TOL) {
00210             // Length is zero. Iteration has converged.
00211             kcont = 0;
00212             jstat = 1;
00213             break;
00214         }
00215       
00216         if (knbit==0) {
00217             // First iteration inititate distance variable, if the equation
00218             // systems were not singular
00219       
00220             if (kstat1 || kstat2) {
00221                 jstat=3;
00222                 break;
00223             }
00224             tdist = tdum3;
00225             knbit = 1;
00226         } else {
00227             // More than one iteration done, stop if distance is not decreasing.
00228             // Then decide if we converge distance between the points is within
00229             // the tolerance and the last step had singular or none singular
00230             // equation systems.
00231       
00232             knbit = knbit + 1;
00233             if (tdum3 >= tdist) {
00234                 // Distance is not decreasing
00235                 if (tdist <= aepsge) {
00236                     // Distance within tolerance
00237                     if (kstat1 || kstat2) {
00238                         // Singular equation system
00239                         jstat=2;
00240                         return; // return without swapping new results to old
00241                         //break;
00242                     }
00243                     else {
00244                         // Nonsingular equation system
00245                         jstat=1;
00246                         return; // return without swapping new results to old
00247                         //break;
00248                     }
00249                 }
00250                 else {
00251                     // Distance is not within tolerance, divergence
00252                     jstat=3;
00253                     return; // return without swapping new results to old
00254                     //break;
00255                 }
00256             }
00257             //      Distance still decreasing
00258             tdist = tdum3;
00259         }
00260       
00261         //  Make sure that not too many iterations are being done
00262         if (knbit > kmaxit) {
00263             jstat=3;
00264             break;
00265         }
00266         gpnt1_new.swap(gpnt1);
00267         gpnt2_new.swap(gpnt2);
00268         // Hmm, seems to need an old-fashioned swap here in order to
00269         // get rid of and internal compiler error on gcc 4.2.4 in
00270         // optimized mode. @jbt
00271         Point tmp = gpar1_new;
00272         gpar1_new = gpar1;
00273         gpar1 = tmp;
00274         tmp = gpar2_new;
00275         gpar2_new = gpar2;
00276         gpar2 = tmp;
00277 //      gpar1_new.swap(gpar1);
00278 //      gpar2_new.swap(gpar2);
00279     }  // while (kcont)
00280 
00281     // If we got here, we want to keep the newly calculated values before returning.
00282     // Effectuating swap.
00283     gpnt1_new.swap(gpnt1);
00284     gpnt2_new.swap(gpnt2);
00285     gpar1_new.swap(gpar1);
00286     gpar2_new.swap(gpar2);
00287 
00288 }

void Go::computeFirstFundamentalForm ( const ParamSurface &  sf,
double  u,
double  v,
int  derivs,
std::vector< double > &  form 
)

Computes the coefficients of the first fundamental form.

The returned values are stored { E F G [Eu Fu Gu Ev Fv Gv [Euu Fuu Guu Euv Fuv Guv Evv Fvv Gvv [...] ] ] }. Only one derivative is implemented so far.

Parameters:
sf reference to the concerned surface
u first parameter of point where we want to compute the first fundamental form
v second parameter of point where we want to compute the first fundamental form
derivs number of (partial) derivatives of the first fundamental form that we want to include in the result. So far, only the computation of the first derivative is actually implemented.
form the computed values, on the format described above

Definition at line 25 of file CurvatureAnalysis.C.

References Go::ParamSurface::point(), and THROW.

00029 {
00030     int sz = (derivs + 1)*(derivs + 2)/2;
00031     form.resize(3*sz);
00032     std::vector<Point> pts((derivs + 2)*(derivs + 3)/2);
00033     // To evaluate k derivatives of E, F, G we need k+1 derivatives
00034     // of the surface.
00035     sf.point(pts, u, v, derivs + 1);
00036     // Compute the first few terms
00037     form[0] = pts[1]*pts[1];
00038     form[1] = pts[1]*pts[2];
00039     form[2] = pts[2]*pts[2];
00040     if (derivs > 0) {
00041         form[3] = 2.0*pts[1]*pts[3];
00042         form[4] = pts[1]*pts[4] + pts[2]*pts[3];
00043         form[5] = 2.0*pts[2]*pts[4];
00044         form[6] = 2.0*pts[1]*pts[4];
00045         form[7] = pts[1]*pts[5] + pts[2]*pts[4];
00046         form[8] = 2.0*pts[2]*pts[5];
00047     }
00048     // Using the 2-variable Leibniz rule,
00049     // we could eventually compute the higher derivatives.
00050     for (int i = 2; i <= derivs; ++i) {
00051         THROW("Higher derivatives of E, F, G not implemented.");
00052     }
00053 }

template<class PtrToCurveType >
double Go::computeLoopGap ( const std::vector< PtrToCurveType > &  curves  )  [inline]

Computes the largest gap in the loop specified by the vector of curves.

Definition at line 186 of file CurveLoop.h.

References Go::Point::dist(), and THROW.

Referenced by Go::CurveLoop::fixInvalidLoop(), and Go::CurveLoop::setCurves().

00188 {
00189 
00190     // Here, we should check that the given curves indeed are forming a
00191     // loop, so every endpoint is within space_epsilon of the start of the
00192     // next curve.
00193     // Also, we make sure that all curves have the same dimension
00194     // and that the curves are of the same type
00195     if ((curves.size() == 0) || (curves[0] == NULL))
00196         return -1.0;
00197 
00198     int dim = curves[0]->dimension();
00199 //     ClassType type = curves[0]->instanceType();
00200     int n = curves.size();
00201     int i;
00202     for (i = 1; i < n; ++i) {
00203         if (curves[i] == NULL)
00204             return -1.0;
00205         if (curves[i]->dimension() != dim) {
00206             THROW("Curves do not have the same dimension.");
00207         }
00208 //      if (curves[i]->instanceType() != type) {
00209 //          THROW("Not all curves are of the same type.");
00210 //      }
00211     }
00212     Point startp(dim);
00213     Point endp(dim);
00214     double maxdist = -1.0;
00215     double dist;
00216     for (i = 1; i < n; ++i) {
00217         curves[i-1]->point(endp, curves[i-1]->endparam());
00218         curves[i]->point(startp, curves[i]->startparam());
00219         dist = endp.dist(startp);
00220         if (dist > maxdist) maxdist = dist;
00221     }
00222     curves[n-1]->point(endp, curves[n-1]->endparam());
00223     curves[0]->point(startp, curves[0]->startparam());
00224     dist = endp.dist(startp);
00225     if (dist > maxdist) maxdist = dist;
00226     return maxdist;
00227 }

void Go::computeSecondFundamentalForm ( const ParamSurface &  sf,
double  u,
double  v,
double  form1[3],
double  form2[3] 
)

Computes the coefficients of the first and second fundamental forms.

The returned values are stored { E F G } in form1 and { e f g } in form2. This function cannot compute derivatives.

Parameters:
sf reference to the concerned surface
u first parameter of point where we want to compute the fundamental forms.
v second parameter of point where we want to compute the fundamental forms
form1 the values associated with the first fundamental form will be returned here.
form2 the values associated with the second fundamental form will be returned here.

Definition at line 57 of file CurvatureAnalysis.C.

References Go::ParamSurface::normal(), and Go::ParamSurface::point().

Referenced by curvatures(), and principalCurvatures().

00062 {
00063     // To evaluate both fundamental forms, we need the second
00064     // derivatives and the normal.
00065     std::vector<Point> pts(6);
00066     Point normal;
00067     sf.point(pts, u, v, 2);
00068     sf.normal(normal, u, v);
00069     // Compute the first few terms
00070     form1[0] = pts[1]*pts[1];
00071     form1[1] = pts[1]*pts[2];
00072     form1[2] = pts[2]*pts[2];
00073     form2[0] = normal*pts[3];
00074     form2[1] = normal*pts[4];
00075     form2[2] = normal*pts[5];
00076 }

void Go::computeSeedCvCv ( const SplineCurve pc1,
const SplineCurve pc2,
double &  seed1,
double &  seed2 
)

Computes initial start points for iteration along the curves.

Parameters:
pc1 Curve number one.
pc2 Curve number two.
Return values:
seed1 Start point for iteration along curve number one.
seed2 Start point for iteration along curve number two.

Definition at line 338 of file closestPtCurves.C.

References Go::SplineCurve::basis(), Go::BsplineBasis::begin(), Go::SplineCurve::coefs_begin(), Go::SplineCurve::coefs_end(), DEBUG_ERROR_IF, Go::SplineCurve::dimension(), and Go::SplineCurve::order().

Referenced by closestPtCurves().

00341 {
00342 
00343   // Make guess point to the iteration.
00344   // Find position of closest vertices
00345   std::vector<double>::const_iterator co1 = cv1->coefs_begin();
00346   std::vector<double>::const_iterator co2 = cv2->coefs_begin();
00347   std::vector<double>::const_iterator co3;
00348   std::vector<double>::const_iterator co12 = cv1->coefs_end();
00349   std::vector<double>::const_iterator co22 = cv2->coefs_end();
00350 
00351   const int dim = cv1->dimension();
00352   DEBUG_ERROR_IF(dim!=cv2->dimension(), "Dimension mismatch.");
00353   double td, tmin=1.0e8;
00354   int minidx1=0, minidx2=0;
00355   int ki, k1, k2;
00356   for (k1=0; co1<co12; co1+=dim, k1++) {
00357     for (k2=0, co3=co2; co3<co22; co3+=dim, k2++) {
00358       for (td=0.0, ki=0; ki<dim; ki++)
00359         td += (co1[ki]-co3[ki])*(co1[ki]-co3[ki]);
00360       if (td < tmin) {
00361         tmin = td;
00362         minidx1 = k1;
00363         minidx2 = k2;
00364       }
00365     }
00366   }
00367 
00368   // Estimate parameter value of vertices
00369   std::vector<double>::const_iterator st;
00370   int kk = cv1->order();
00371   for (k1=minidx1+1, st=cv1->basis().begin(), seed1=0.0;
00372        k1<minidx1+kk; seed1+=st[k1], k1++);
00373   seed1 /= (double)(kk-1);
00374   kk = cv2->order();
00375   for (k1=minidx2+1, st=cv2->basis().begin(), seed2=0.0;
00376        k1<minidx2+kk; seed2+=st[k1], k1++);
00377   seed2 /= (double)(kk-1);
00378 
00379 }

void Go::construct_corner_lists ( boost::shared_ptr< SplineSurface srf,
vector< boost::shared_ptr< SplineCurve > > &  crv_set,
const vector< Vector3D > &  vert,
const vector< Vector2D > &  vert_p,
const vector< Vector3D > &  norm,
const vector< int > &  mesh,
const vector< vector< Vector3D > > &  trim_curve_all,
const vector< vector< Vector3D > > &  trim_curve_p_all,
const int  dn,
const int  dm,
const double  bd_res_ratio,
const double  eps,
const double  cosangle_limit,
const double  pt_edge_degen_limit,
const double  pt_mult_def,
const double  min_corner_dist,
const double  max_corner_dist,
vector< int > &  skip_quad,
vector< vector< Vector3D > > &  quad_corner_trim_curve,
vector< vector< Vector2D > > &  quad_corner_trim_curve_p,
int &  quad_corners 
)

Definition at line 1412 of file spline2mesh.C.

References M_PI, Go::Array< T, Dim >::normalize(), and THROW.

Referenced by make_trimmed_mesh().

01432   {
01433     // 090130: "Corner-handling", 1st step: Identify quads needing special treatment, i.e. extra refinement.
01434     // 090203: Note that we really want to avoid making almost-degenerate triangles...
01435     //         Hmm... This should really be something relative to the extent of the quad...
01436     //const double delta=1e-8; // See above.
01437     skip_quad=vector<int>(dn*dm, 0);
01438     quad_corner_trim_curve.resize(dn*dm);
01439     quad_corner_trim_curve_p.resize(dn*dm);
01440 
01441     const double u0=srf->startparam_u();
01442     const double u1=srf->endparam_u();
01443     const double v0=srf->startparam_v();
01444     const double v1=srf->endparam_v();
01445     const double dv=(v1-v0)/dm, du=(u1-u0)/dn;
01446 
01447 #ifdef DBG
01448     // 100222: Producing matlab-scripts for debugging.
01449     {
01450       const double u02=vert_p[0][0], v02=vert_p[0][1];
01451       const double u12=vert_p[(dn+1)*(dm+1)-1][0], v12=vert_p[(dn+1)*(dn+1)-1][1];
01452       if (fabs(u02-u0)>eps) THROW("Huh?!");
01453       if (fabs(u12-u1)>eps) THROW("Huh?!");
01454       if (fabs(v02-v0)>eps) THROW("Huh?!");
01455       if (fabs(v12-v1)>eps) THROW("Huh?!");
01456       printf("Parameter domain: [%g, %g] x [%g, %g]\n", u02, u12, v02, v12);
01457     }
01458     FILE *f1=fopen("c1.m", "w"); // corners in quads
01459     FILE *f2=fopen("c2.m", "w"); // corner skipped due to small angle
01460     FILE *f3=fopen("c3.m", "w"); // corner skipped, is a duplicate
01461     FILE *f4=fopen("c4.m", "w"); // all points
01462     fprintf(f1, "hold on\ngrid on\n");
01463     fprintf(f2, "hold on\ngrid on\n");
01464     fprintf(f3, "hold on\ngrid on\n");
01465     fprintf(f4, "hold on\ngrid on\n");
01466 #endif
01467 
01468     for (int curve=0; curve<int(crv_set.size()); curve++)
01469       {
01470 #ifdef CLC_DBG
01471         printf("curve %d\n", curve);
01472 #endif
01473         const vector<Vector3D> &trim_curve_p=trim_curve_p_all[curve];
01474         const vector<Vector3D> &trim_curve=trim_curve_all[curve];
01475         Vector2D last_dir(1.0, 0.0); // Will be kept normalized. The initial value will not be used,
01476         // ref. 'a_first_point_added'
01477         bool a_first_point_added=false;
01478         Vector2D last_used_p(0.0, 0.0);
01479         const int contour_points=trim_curve_p.size();
01480 
01481         for (int i=0; i<contour_points; i++)
01482           {
01483             double u=trim_curve_p[i][0], v=trim_curve_p[i][1];
01484 //        const int /* ip1=(i+1)%contour_points, */ im1=(i+contour_points-1)%contour_points;
01485 #ifdef CLC_DBG
01486             printf("  i=%4d u=%7.3f, v=%7.3f", i, u, v);
01487 #endif
01488             if ((u>=u0) && (u<=u1) && (v>=v0) && (v<=v1))
01489               {
01490                 const int p=std::min(int(floor((v-v0)/dv)), dm-1), q=std::min(int(floor((u-u0)/du)), dn-1);
01491                 const int vert_indx=p*(dn+1)+q, quad_indx=p*dn+q;
01492                 const double &u_left=vert_p[vert_indx][0], &v_left=vert_p[vert_indx][1];
01493                 const double &u_right=vert_p[vert_indx+dn+2][0], &v_right=vert_p[vert_indx+dn+2][1];
01494 //            if (u<u_left)
01495 //              {
01496 //                printf("\nu=%g, u_left=%g\n", u, u_left);
01497 //                THROW("Huh?!");
01498 //              }
01499 //            if (v<v_left) THROW("Huh?!");
01500 //            if ((u>u_right) && (q<n-1)) THROW("Huh?!");
01501 //            if ((v>v_right) && (p<n-1)) THROW("Huh?!");
01502                 // Note that due to rounding errors, discrete arithmetic, or floor's behaviour, u or v might
01503                 // actually be outside the quads parameter (sub)domain. This should only happen on the right and
01504                 // upper rim...
01505                 // 090219: Doing a small adjustment for this...
01506                 u=std::min(std::max(u_left, u), u_right);
01507                 v=std::min(std::max(v_left, v), v_right);
01508               
01509                 // Need two things: 1) angle!=pi, 2) not duplicate point. And 3) not on the edges.
01510                 // 090218: New criterium: Accumulating angle changes.
01511                 // 090220: Taking care of weeding out duplicates in the calling function. (?)
01512               
01513                 if ( ((u-u_left<pt_edge_degen_limit) || (u_right-u<pt_edge_degen_limit) || 
01514                       (v-v_left<pt_edge_degen_limit) || (v_right-v<pt_edge_degen_limit)    ) && (0) )
01515                   {
01516                     //printf("  quad-corner too close to edge to split.\n");
01517                     // 090202: Hmmm... On second thought... We should still split here, it's just that we
01518                     //         shouldn't split into four new triangles.
01519                     // 090203: Hmm... On third thought... It's ok *not* to "corner split" here, because
01520                     //         everything will be ok when we do the "ordinary" curve-splitting later. The
01521                     //         point about the corners is to force splitting in the corner, and when the
01522                     //         corner happens to be on a mesh-edge, this will happen automagically!
01523                     // 090203: Note that even if we end up here, the angle, distance to previous point
01524                     //         etc. may still not warrant a splitting. This is likely often the case when the
01525                     //         trimming curve follows an edge of the surface!
01526                     // 090203: No! If we don't add a corner even though on an edge, splitting may not occur
01527                     //         later either.  (But why not? Was this not solved with the "boundary-fix" some
01528                     //         time earlier?)  Another solution is to split, and then remove (or not add)
01529                     //         degenerate triangles...
01530                   }
01531                 else
01532                   {
01533                     const Vector2D current_p(trim_curve_p[i][0], trim_curve_p[i][1]);
01534                     const Vector2D previous_p = 
01535                       i>0 ? Vector2D(trim_curve_p[i-1][0], trim_curve_p[i-1][1]) : Vector2D(1e99, 1e99);
01536                     const double dist_since_last_used_p=sqrt((current_p-last_used_p)*(current_p-last_used_p));
01537                     const double dist_since_prev_p=sqrt((current_p-previous_p)*(current_p-previous_p));
01538                  
01539 #ifdef DBG
01540                     fprintf(f4, "plot(%f, %f, 'kd', 'markersize', 5);\n", current_p[0], current_p[1]);
01541 #endif
01542  
01543                     if ( (dist_since_prev_p>pt_mult_def) // a new distinct point
01544                          || (!a_first_point_added) )
01545                       {
01546                         const double cosangle = (last_dir*(current_p-last_used_p))/dist_since_last_used_p;
01547                         // (Note: We have made sure 'dist_since_last_used_p' is non-zero!)
01548 #ifdef CLC_DBG
01549                         printf(" [%7.3f %7.3f   %7.3f %7.3f]", last_dir[0], last_dir[1],
01550                                current_p[0]-last_used_p[0], current_p[1]-last_used_p[1]);
01551                         printf(" angle=%7.3f", acos(std::min(cosangle, 1.0))/M_PI*180.0);
01552                         printf(" cosangle=%6.3f", cosangle);
01553 #endif
01554 //                    if ( ((cosangle<cosangle_limit) || (b*b>max_corner_dist*max_corner_dist)) && 
01555 //                         (b*b>min_corner_dist*max_corner_dist) )
01556                         if ((cosangle<cosangle_limit) || (!a_first_point_added))
01557                           {
01558                             //const Vector2D previous_p(trim_curve_p[im1][0], trim_curve_p[im1][1]);
01559 //                        if ( (current_p-previous_p)*(current_p-previous_p) < 1e-15*1e-15 )
01560 //                          {
01561 // #ifdef DBG
01562 //                            printf(" skipping point, same as previous. ");
01563 // #endif
01564 //                          }
01565 //                        else
01566 //                          {
01567                             // Now we flag the quad as being split, and append the corner to the quad's list.
01568                             //printf("dist from previous: %g ", sqrt((current_p-previous_p)*(current_p-previous_p)));
01569                             skip_quad[quad_indx]=1;
01570                             quad_corner_trim_curve[quad_indx].push_back(trim_curve[i]);
01571                             quad_corner_trim_curve_p[quad_indx].push_back(current_p);
01572                             quad_corners++;
01573                             last_dir=current_p-last_used_p;
01574 //printf("\n last_dir 1 =%g %g\n", last_dir[0], last_dir[1]);
01575                             last_dir.normalize();
01576 //printf("\n last_dir 2 =%g %g\n", last_dir[0], last_dir[1]);
01577                             last_used_p=current_p;
01578                             a_first_point_added=true;
01579 #ifdef DBG
01580                             fprintf(f1, "plot(%f, %f, 'm*');\n", current_p[0], current_p[1]);
01581                             char *tmpstr=new char[100];
01582                             sprintf(tmpstr, "%d", i);
01583                             fprintf(f1, "text(%f, %f, '%s');\n", current_p[0], current_p[1]+0.00005, tmpstr);
01584 #  ifdef CLC_DBG
01585                             printf(" (c1) USED");
01586 #  endif
01587 #endif
01588 //                          }
01589                           }
01590 #ifdef DBG
01591                         else
01592                           {
01593                             fprintf(f2, "plot(%f, %f, 'b+');\n", current_p[0], current_p[1]);
01594                             char *tmpstr=new char[100];
01595                             sprintf(tmpstr, "%d", i);
01596                             fprintf(f2, "text(%f, %f, '%s');\n", current_p[0], current_p[1]+0.00010, tmpstr);
01597 #  ifdef CLC_DBG
01598                             printf(" (c2) TOO SMALL ANGLE");
01599 #  endif
01600                           }
01601 #endif
01602                       }
01603                     else
01604                       {
01605                         // Use it, but not if already used!!!!
01606                         if (dist_since_last_used_p>1e-14)
01607                           {
01608                           
01609 #ifdef DBG
01610                             fprintf(f3, "plot(%f, %f, 'go', 'markersize', 4);\n", current_p[0], current_p[1]);
01611                             char *tmpstr=new char[100];
01612                             sprintf(tmpstr, "%d", i);
01613                             fprintf(f3, "text(%f, %f, '%s');\n", current_p[0], current_p[1]+0.00015, tmpstr);
01614 #  ifdef CLC_DBG
01615                             printf(" (c3) DUPLICATE: %f", dist_since_last_used_p);
01616 #  endif
01617 #endif
01618                       
01619                             // Multiple point, definitely use this one, since we assume it is due to a kink in
01620                             // the curve.
01621                             skip_quad[quad_indx]=1;
01622                             quad_corner_trim_curve[quad_indx].push_back(trim_curve[i]);
01623                             quad_corner_trim_curve_p[quad_indx].push_back(current_p);
01624                             quad_corners++;
01625                             last_dir=current_p-last_used_p;
01626 //printf("\n last_dir 3 =%g %g\n", last_dir[0], last_dir[1]);
01627                             last_dir.normalize();
01628 //printf("\n last_dir 4 =%g %g\n", last_dir[0], last_dir[1]);
01629                             last_used_p=current_p;
01630                             a_first_point_added=true;
01631                           }
01632 //                    else
01633 //                      {
01634 //                        printf("\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ %f\n", dist_since_last_used_p);
01635 //                      }
01636                       
01637                       }
01638                   }
01639               } // end of if-test ensuring that [u, v] is in the parameter domain.
01640 #ifdef CLC_DBG
01641             printf("\n");
01642 #endif
01643           } // end of i-loop over points on curve 'curve'.
01644       } // end of 'curve'-loop
01645   
01646 #ifdef DBG
01647     fprintf(f1, "hold off\n");
01648     fprintf(f2, "hold off\n");
01649     fprintf(f3, "hold off\n");
01650     fprintf(f4, "hold off\n");
01651     fclose(f1);
01652     fclose(f2);
01653     fclose(f3);
01654     fclose(f4);
01655 #endif
01656   }

bool Go::cornerToCornerSfs ( shared_ptr< ParamSurface >  sf1,
shared_ptr< CurveOnSurface >  sf_cv1,
shared_ptr< ParamSurface >  sf2,
shared_ptr< CurveOnSurface >  sf_cv2,
double  tol 
)

Definition at line 267 of file SurfaceTools.C.

References Go::Point::dist(), Go::RectDomain::umax(), Go::RectDomain::umin(), Go::RectDomain::vmax(), and Go::RectDomain::vmin().

00273   {
00274   int bd1, bd2;  // Specifies the surface boundaries corresponding to 
00275   // the current edges
00276   // 0 = umin, 1 = umax, 2 = vmin,  3 = vmax
00277   bool same_orient1, same_orient2;
00278   bd1 = sf_cv1->whichBoundary(tol, same_orient1);
00279   bd2 = sf_cv2->whichBoundary(tol, same_orient2);
00280   if (bd1 < 0 || bd2 < 0)
00281     return false;  // Adjacency not along boundary
00282 
00283   // Get surface parameters at corners
00284   RectDomain dom1 = sf1->containingDomain();
00285   RectDomain dom2 = sf2->containingDomain();
00286   double corn1_1[2], corn1_2[2], corn2_1[2], corn2_2[2];
00287   if (bd1 == 0 || bd1 == 1)
00288     {
00289       if (bd1 == 0)
00290         corn1_1[0] = corn1_2[0] = dom1.umin();
00291       else
00292         corn1_1[0] = corn1_2[0] = dom1.umax();
00293       corn1_1[1] = dom1.vmin();
00294       corn1_2[1] = dom1.vmax();
00295     }
00296   else if (bd1 == 2 || bd1 == 3)
00297     {
00298       if (bd1 == 2)
00299         corn1_1[1] = corn1_2[1] = dom1.vmin();
00300       else
00301         corn1_1[1] = corn1_2[1] = dom1.vmax();
00302       corn1_1[0] = dom1.umin();
00303       corn1_2[0] = dom1.umax();
00304     }
00305   if (bd2 == 0 || bd2 == 1)
00306     {
00307       if (bd2 == 0)
00308         corn2_1[0] = corn2_2[0] = dom2.umin();
00309       else
00310         corn2_1[0] = corn2_2[0] = dom2.umax();
00311       corn2_1[1] = dom2.vmin();
00312       corn2_2[1] = dom2.vmax();
00313     }
00314   else if (bd2 == 2 || bd2 == 3)
00315     {
00316       if (bd2 == 2)
00317         corn2_1[1] = corn2_2[1] = dom2.vmin();
00318       else
00319         corn2_1[1] = corn2_2[1] = dom2.vmax();
00320       corn2_1[0] = dom2.umin();
00321       corn2_2[0] = dom2.umax();
00322     }
00323    
00324   // Evaluate surface corners
00325   Point pt1 = sf1->point(corn1_1[0], corn1_1[1]);
00326   Point pt2 = sf1->point(corn1_2[0], corn1_2[1]);
00327   Point pt3 = sf2->point(corn2_1[0], corn2_1[1]);
00328   Point pt4 = sf2->point(corn2_2[0], corn2_2[1]);
00329   
00330   if (pt1.dist(pt3) > tol && pt1.dist(pt4) > tol)
00331     return false;
00332   if (pt2.dist(pt3) > tol && pt2.dist(pt4) > tol)
00333     return false;
00334   if (pt3.dist(pt1) > tol && pt3.dist(pt2) > tol)
00335     return false;
00336   if (pt4.dist(pt1) > tol && pt4.dist(pt2) > tol)
00337     return false;
00338   
00339   return true;
00340   }

bool Go::cornerToCornerSfs ( boost::shared_ptr< ParamSurface >  sf1,
boost::shared_ptr< CurveOnSurface >  sf_cv1,
boost::shared_ptr< ParamSurface >  sf2,
boost::shared_ptr< CurveOnSurface >  sf_cv2,
double  tol 
)
double Go::curvatureRadius ( const std::vector< Point > &  der,
std::vector< Point > &  unitder 
)

Help functions in related to curvature.

Given position, first and second derivative of a curve passing through a point, compute the unit tangent, curvature vector and curvature radius of this curve.

Definition at line 28 of file CurvatureUtils.C.

References ASSERT, ltol, and THROW.

Referenced by getHermiteData(), and minimalCurvatureRadius().

00035 {
00036   
00037 //     Let c = c(w) be a parameterized curve.
00038 //     The curvature vector is defined as the derivative of the unit tangent
00039 //     vector with respect to the arc length a. If we don't have an arclength
00040 //     parametrization then this parametrization can be written as a function
00041 //     of the arc length w = w(a). By using the kernel rule for differentiation
00042 //     we get:
00043    
00044 //            d            d       dw   d    c'(w)    dw   d    c'(w)      da
00045 //     k(a) = -- T(w(a)) = -- T(w) -- = -- ---------- -- = -- ---------- / --
00046 //            da           dw      da   dw sqrt(c'c') da   dw sqrt(c'c')   dw
00047       
00048 //            d       c'(w)                c"        c' (c'c'')
00049 //            -- ----------------- =   ---------- - ------------- 
00050 //            dw sqrt(c'(w) c'(w))     sqrt(c'c')   sqrt(c'c')**3
00051      
00052 //            da
00053 //            -- = sqrt(c'c')
00054 //            dw 
00055 
00056   // Assuming 2D or 3D
00057   ASSERT(der.size() >= 3);
00058   ASSERT(der[0].dimension() == 2 || der[0].dimension() == 3);
00059 
00060   // Initiate output vector
00061   int ki;
00062   unitder.resize(3);
00063   for (ki=0; ki<3; ki++)
00064     unitder[ki] = der[ki];
00065 
00066   double length = unitder[1].length();
00067   if (length < ltol)
00068       return -1;
00069 
00070   unitder[1].normalize();
00071   
00072   // Check tangent length
00073   if (length < ltol)
00074     THROW("Tangent of length zero");
00075    
00076   // Make curvature vector
00077   double dum1 = (der[2] * unitder[1])/length;
00078   unitder[2] = (der[2]/length - unitder[1]*dum1)/length;
00079 
00080   // Make curvature radius
00081   double dum2 = unitder[2].length();
00082   if (dum2 < ltol)
00083     return -1;
00084   else
00085     return 1.0/dum2;
00086 }

void Go::curvatureRadiusPoints ( const SplineCurve &  curve,
double  curveRad,
std::vector< double > &  pos 
)

Definition at line 33 of file Curvature.C.

References Go::SplineInterpolator::basis(), Go::SplineCurve::basis(), Go::BsplineBasis::begin(), Curve2SISL(), Go::SplineCurve::derivCurve(), Go::SplineInterpolator::interpolate(), Go::BsplineBasis::knotMultiplicity(), Go::BsplineBasis::knotsSimple(), Go::Point::length2(), Go::BsplineBasis::order(), and Go::SplineInterpolator::setBasis().

Referenced by main().

00037 {
00038   
00039   BsplineBasis basis = curve.basis();
00040   int order = basis.order();
00041   int new_order = 6 * order - 11;
00042 
00043   vector<double> knots_simple;
00044   vector<double> new_knots;
00045   basis.knotsSimple(knots_simple);
00046 
00047   for (size_t i = 0; i < knots_simple.size(); ++i)
00048     {
00049       int old_mult = basis.knotMultiplicity(knots_simple[i]);
00050       int new_mult = 5 * order - 9 + old_mult;
00051       if (old_mult >= order-1) new_mult -= 2 - order + old_mult;
00052       for (int j = 0; j < new_mult; ++j) new_knots.push_back(knots_simple[i]);
00053     }
00054 
00055   int num_coefs = new_knots.size() - new_order;
00056 
00057   BsplineBasis new_basis(new_order, new_knots.begin(), new_knots.end());
00058 
00059   vector<double> coefs_par; // Parameter values for the coefs (Greville)
00060   vector<double> coefs;
00061 
00062   shared_ptr<SplineCurve> d_curve(curve.derivCurve(1));
00063   shared_ptr<SplineCurve> dd_curve(d_curve->derivCurve(1));
00064 
00065   for (int i = 0; i < num_coefs; )
00066     {
00067       int knot_pos = i + 1;
00068       while (knot_pos < int(new_knots.size()) && new_knots[knot_pos-1] == new_knots[knot_pos])
00069         ++knot_pos;
00070       double step = (new_knots[knot_pos] - new_knots[knot_pos-1]) / double(knot_pos - i);
00071       double tpar = new_knots[knot_pos-1] + step/2.0;
00072       for (;i < knot_pos; ++i)
00073         {
00074           coefs_par.push_back(tpar);
00075           tpar += step;
00076         }
00077     }
00078 
00079   for (int i = 0; i < num_coefs; ++i)
00080     {
00081       double tpar = coefs_par[i];
00082       Point d_p, dd_p;
00083       d_curve->point(d_p, tpar);
00084       dd_curve->point(dd_p, tpar);
00085       double d_p_length2 = d_p.length2();
00086 
00087       coefs.push_back( (d_p % dd_p).length2() * curveRad * curveRad - d_p_length2*d_p_length2*d_p_length2);
00088     }
00089 
00090   vector<double> curvature_coefs;
00091   vector<double> dummy_tangents;
00092   vector<int> dummy_index;
00093   SplineInterpolator interpolator;
00094   interpolator.setBasis(new_basis);
00095   interpolator.interpolate(coefs_par, coefs, dummy_index,
00096                            dummy_tangents, curvature_coefs);
00097 
00098   shared_ptr<SplineCurve> curvature_curve(
00099     new SplineCurve(num_coefs, new_order,
00100                     interpolator.basis().begin(),
00101                     curvature_coefs.begin(), 1));
00102 
00103   SISLCurve *num_sisl = Curve2SISL(*(curvature_curve.get()), false);
00104   SISLObject *qo1 = 0;
00105   SISLObject *qo2 = 0;
00106   SISLPoint *qp = 0;
00107   double spoint[1];
00108   spoint[0] = 0.0;
00109   int kstat = 0;
00110   SISLIntdat *qintdat = 0;
00111   double aepsge = 1.0e-9;
00112 
00113   if (!(qo1 = newObject(SISLCURVE))) goto error101;
00114   qo1 -> c1 = num_sisl;
00115   qo1 -> o1 = qo1;
00116 
00117   if (!(qo2 = newObject(SISLPOINT))) goto error101;
00118   spoint[0] = 0.0;
00119   if(!(qp = newPoint(spoint,1,1))) goto error101;
00120   qo2 -> p1 = qp;
00121 
00122   sh1761(qo1,qo2,aepsge,&qintdat,&kstat);
00123   if (kstat < 0) goto error101;
00124 
00125   if (qintdat)
00126   {
00127       for (int i = 0; i < qintdat->ipoint; ++i)
00128           pos.push_back(qintdat->vpoint[i]->epar[0]);
00129   }
00130 
00131  error101:
00132   if (qo1)     freeObject(qo1);
00133   if (qo2)     freeObject(qo2);
00134   if (qintdat) freeIntdat(qintdat);
00135 }

void Go::curvatures ( const ParamSurface &  sf,
double  u,
double  v,
double &  K,
double &  H 
)

Computes the Gaussian (K) and mean (H) curvatures.

Parameters:
sf reference to the concerned surface
u first parameter of point where we want to carry out computation
v second parameter of point where weh want to carry out computation
K value of Gaussian curvature returned here
H value of mean curvature returned here

Definition at line 80 of file CurvatureAnalysis.C.

References computeSecondFundamentalForm().

00084 {
00085     double I[3];
00086     double II[3];
00087     computeSecondFundamentalForm(sf, u, v, I, II);
00088     double denom = I[0]*I[2]-I[1]*I[1];
00089     K = (II[0]*II[2]-II[1]*II[1])/denom;
00090     H = (II[0]*I[2]-2*II[1]*I[1]+II[2]*I[0])/(2*denom);
00091 }

SISLCurve * Go::Curve2SISL ( const SplineCurve &  cv,
bool  copy = true 
)

Convert a SplineCurve to a SISLCurve.

Parameters:
cv the SplineCurve to convert
copy if 'true', then the generated SISLCurve will have its own copy of the coefficient information contained in 'cv'. Otherwise, it will share this information with 'cv' (ie. it will only contain a pointer into the corresponding storage array in 'cv'.
Returns:
A newly generated SISLCurve that describes the same curve as 'cv'. The user assumes ownership and is responsible for cleaning up (which means calling the SISL function freeCurve(...) on the pointer when it should be destroyed).

Definition at line 23 of file SISLconversion.C.

References Go::SplineCurve::basis(), Go::BsplineBasis::begin(), Go::SplineCurve::coefs_begin(), Go::SplineCurve::dimension(), Go::SplineCurve::numCoefs(), Go::SplineCurve::order(), Go::SplineCurve::rational(), and Go::SplineCurve::rcoefs_begin().

Referenced by closestPtSislCurves(), curvatureRadiusPoints(), intersect2Dcurves(), intersectCurvePoint(), intersectcurves(), main(), and minimalCurvatureRadius().

00024 {
00025     std::vector<double>::const_iterator coef;
00026     int kind;
00027     if (cv.rational()) {
00028         coef = cv.rcoefs_begin();
00029         kind = 2;
00030     } else {
00031         coef = cv.coefs_begin();
00032         kind = 1;
00033     }
00034     return newCurve(cv.numCoefs(), cv.order(),
00035                     const_cast<double*>(&(*(cv.basis().begin()))),
00036                     const_cast<double*>(&(*coef)),
00037                     kind, cv.dimension(), copy);
00038 }

SISLCurve * Go::Curve2SISL_rat ( const SplineCurve &  cv  ) 

Convert a SplineCurve to a rational SISLCurve Arrays are copied.

Definition at line 42 of file SISLconversion.C.

References Go::SplineCurve::basis(), Go::BsplineBasis::begin(), Go::SplineCurve::coefs_begin(), Go::SplineCurve::dimension(), Go::SplineCurve::numCoefs(), Go::SplineCurve::order(), Go::SplineCurve::rational(), and Go::SplineCurve::rcoefs_begin().

00043 {
00044     std::vector<double>::const_iterator coef;
00045     int kind = 2;
00046     if (cv.rational()) 
00047       {
00048         coef = cv.rcoefs_begin();
00049         return newCurve(cv.numCoefs(), cv.order(),
00050                         const_cast<double*>(&(*(cv.basis().begin()))),
00051                         const_cast<double*>(&(*coef)),
00052                         kind, cv.dimension(), 1);
00053       }
00054     else 
00055       {
00056         coef = cv.coefs_begin();
00057         int in = cv.numCoefs();
00058         int dim = cv.dimension();
00059         vector<double> sc(in*(dim+1));
00060         int ki;
00061         for (ki=0; ki<in; ++ki, coef+=dim)
00062           {
00063             std::copy(coef, coef+dim, sc.begin()+ki*(dim+1));
00064             sc[ki*(dim+1)+dim] = 1.0;
00065           }
00066         return newCurve(cv.numCoefs(), cv.order(),
00067                         const_cast<double*>(&(*(cv.basis().begin()))),
00068                         const_cast<double*>(&(sc[0])),
00069                         kind, cv.dimension(), 1);
00070       }
00071 }

void Go::curve_ratder ( double const   eder[],
int  idim,
int  ider,
double  gder[] 
)

This function takes as input the position and a certain number of derivatives in homogenous space of a point on a rational curve.

It outputs the position and derivatives of this point in non-homogenous ("ordinary") space. (Corresponds to s6ratder in SISL)

Parameters:
eder pointer to the array where the point's position and derivatives in homogenous coordinates (input) are consecutively stored
idim the dimension of the non-homogenous space
ider the number of derivatives sought (0 means that we only want to convert the position to non-homogenous coordinates).
gder pointer to the array where the result will be written (in same order as 'eder').

Definition at line 22 of file ratder.C.

References ALWAYS_ERROR_IF, binom(), and sum().

Referenced by Go::SplineCurve::point().

00026              : To calculate the ider derivatives of a rational
00027 
00028 *              point described in homogenous coordinates
00029 *
00030 * INPUT      : eder    - The derivatives in homogenous coordinates
00031 *                        In sequence:
00032 *                         Position (x,y,...h)
00033 *                         1st der (x,y,...h)
00034 *                         2nd der (x,y,...h)
00035 *                         etc.
00036 *              idim    - The dimension of the non homogenous space
00037 *              ider    - The number of input derivatives
00038 *
00039 *
00040 * OUTPUT     : gder    - The derivatives in the nonhomogenous space
00041 *
00042 *
00043 * METHOD     :  The curve P(u) can be written as the quotient
00044 *               P(u) = T(u) / w(u) where T and w are ordinary splines.
00045 *               The dimensions of T and w are idim and 1
00046 *               respectively. The array eder contains position
00047 *               and derivatives of the idim+1 dimensional curve
00048 *               (T(u),w(u)).
00049 *
00050 *               Now, since wP = T, we find, by the Leibnitz formula,
00051 *
00052 *                 k
00053 *                         k!     (k-i) (i)         (k)
00054 *                sum   -------- w     P       =   T    .
00055 *                      i!(k-i)!
00056 *                i=0
00057 *
00058 *               Therefore
00059 *
00060 *
00061 *                   --         k-1                      --
00062 *             (k)   |   (k)             k!     (k-i) (i) |
00063 *            P    = |  T    -  sum   -------- w     P    | / w .
00064 *                   |                i!(k-i)!            |
00065 *                   --         i=0                      --
00066 *
00067 *               This formula is applied recursively to evaluate P's derivatives.
00068 *
00069 *                                                          MF.
00070 *
00071 * CALLS      :
00072 *
00073 * WRITTEN BY : Tor Dokken, SI, Oslo, Norway. 1988-des-1988
00074 * REVISED BY : Michael Floater, SI, 30/9/91 Removed division by t=1.
00075 * REWRITTEN BY : Michael Floater, SI, 16/12/91. New algorithm.
00076 * REWRITTEN BY : Michael Floater, SI, 25/8/92. Extend to arbitrary
00077 *                   number of derivatives (by Leibnitz). Finally!
00078 * REVISED BY : Paal Fugelli, SINTEF, 07/07-94. Added free'ing of binom and
00079 *              initiation to SISL_NULL to avoid memory leakage.
00080 * REVISED BY : Atgeirr F Rasmussen, SINTEF, 06/04/2001. Go and C++-ified.
00081 * 
00082 *********************************************************************
00083 */
00084 {
00085   double w0;           /* The denominator.                       */
00086   int ki;              /* Count through dimensions.              */
00087   int id;              /* Count through derivatives.             */
00088   std::vector<double> binom;
00089   double sum;          /* Binomial (Leibnitz) expansion.         */
00090   int idimp1;          /* idim + 1.                              */
00091   int iw;              /* Pointer to a weight.                   */
00092   int igder;           /* Pointer to already calculated derivs.  */
00093   int i,j,k;           /* Counters.                              */
00094   int iwfix;           /* Initial value of iw in Leibnitz loop.  */
00095 
00096   ALWAYS_ERROR_IF(ider<0, "Less than zero derivatives ?!?");
00097   ALWAYS_ERROR_IF(idim<1, "Less than zero derivatives ?!?");
00098 
00099   idimp1 = idim + 1;
00100 
00101   /* Find denominator. */
00102 
00103   w0 = eder[idim];
00104   if (fabs(w0)<1e-13) w0 = (double)1.0; // Maybe we should throw instead?
00105 
00106   /* Set up initial binomial coefficient (1). */
00107 
00108   binom.resize(ider+1);
00109 
00110   binom[0] = 1;
00111 
00112   /* Calculate position first. */
00113 
00114   for(ki=0; ki<idim; ki++)
00115   {
00116       gder[ki] = eder[ki] / w0;
00117   }
00118 
00119 
00120 
00121   /* Then derivatives if there are any. */
00122 
00123   for(id=1,j=idim,k=idimp1; id<=ider; id++,k++)
00124   {
00125       /* Calculate the new row of binomial coefficients. */
00126 
00127       binom[id] = 1;
00128 
00129       for(i=id-1; i>=1; i--)
00130       {
00131           binom[i] += binom[i-1];
00132       }
00133 
00134 
00135       /* Run through the idim dimensions, calculating each
00136          coefficient of the id'th derivative of
00137          the rational curve (in gder). */
00138 
00139       iwfix = k + idim;
00140 
00141       for(ki=0; ki<idim; ki++,j++,k++)
00142       {
00143           /* Calculate the Leibnitz sum (the binomial
00144              coefficient in the first term is always 1). */
00145 
00146           sum = eder[iwfix] * gder[ki];
00147 
00148           for(i=1,igder=idim+ki,iw=iwfix-idimp1;
00149           i<id;
00150           i++,igder+=idim,iw-=idimp1)
00151           {
00152               sum += (double)binom[i] * eder[iw] * gder[igder];
00153           }
00154 
00155           gder[j] = (eder[k] - sum) / w0;
00156 
00157       }
00158 
00159   }
00160 
00161   /* Done. */
00162 
00163 }

void Go::curveKinks ( const SplineCurve &  cv,
double  tol,
double  ang_tol,
std::vector< double > &  c1_disconts,
std::vector< double > &  g1_disconts 
)

Find parameter values where a curve is G1- or C1-discontinuous.

Definition at line 906 of file GeometryTools.C.

References Go::SplineCurve::basis(), Go::BsplineBasis::cNDiscontinuities(), Go::SplineCurve::dimension(), and Go::SplineCurve::point().

00908 {
00909 
00910     // Get candidate discontinuity parameters
00911     vector<double> cand_disconts;
00912     cv.basis().cNDiscontinuities(cand_disconts, 1);
00913 
00914     // Compare results of left- and right evaluation in the candidates
00915     int der = 1;
00916     int dim = cv.dimension();
00917     vector<Point> pnt_left(2, Point(dim)), pnt_right(2, Point(dim));
00918     for (size_t ki=0; ki<cand_disconts.size(); ++ki)
00919     {
00920         cv.point(pnt_left, cand_disconts[ki], der, false);
00921         cv.point(pnt_right, cand_disconts[ki], der, true);
00922         if (pnt_left[1].dist(pnt_right[1]) > tol)
00923             c1_disconts.push_back(cand_disconts[ki]);
00924         
00925         if (pnt_left[1].angle(pnt_right[1]) > ang_tol ||
00926             pnt_left[1]*pnt_right[1] < 0.0)
00927             g1_disconts.push_back(cand_disconts[ki]);
00928     }
00929 }

boost::shared_ptr< SplineCurve > Go::curveSum ( const SplineCurve &  crv1,
double  fac1,
const SplineCurve &  crv2,
double  fac2,
double  num_tol = 1e-05 
)

Addition of two signed SplineCurves, i.e.

this function can also be used for subtraction. The curves is assumed to live on the same parameter domain, but may have different knot vectors. resulting curve = fac1 * crv1 + fac2 * crv2

Parameters:
crv1 the first of the curves to be added
fac1 multiplicative factor of the first curve
crv2 the second of the curves to be added
fac2 multiplicative factor of the second curve
num_tol tolerance used when unifying the spline spaces in which 'crv1' and 'crv2' lie.
Returns:
shared pointed to a newly created SplineCurve which is the sum of 'crv1' and 'crv2'.

Definition at line 18 of file curveSum.C.

References ALWAYS_ERROR_IF, Go::SplineCurve::clone(), Go::SplineCurve::endparam(), Go::SplineCurve::rational(), Go::SplineCurve::startparam(), THROW, and unifyCurveSplineSpace().

Referenced by Go::CrossTanOffDist::CrossTanOffDist().

00026   {
00027     // Check input
00028     ALWAYS_ERROR_IF(fabs(crv1.startparam() - crv2.startparam()) > num_tol ||
00029                 fabs(crv1.endparam() - crv2.endparam()) > num_tol,
00030                 "Inconsistent parameter domain.");
00031 
00032     // For the time being
00033     if (crv1.rational() || crv2.rational()) {
00034         THROW("Sum of rational curves is not impelemented");
00035     }
00036 
00037     // Make copy of curves
00038     vector<shared_ptr<SplineCurve> > curves;
00039     curves.reserve(2);
00040     shared_ptr<SplineCurve> cv;
00041 // #ifdef _MSC_VER
00042 //     cv = shared_ptr<SplineCurve>(dynamic_cast<SplineCurve*>(crv1.clone()));
00043 // #else
00044     cv = shared_ptr<SplineCurve>(crv1.clone());
00045 // #endif
00046     curves.push_back(cv);
00047 // #ifdef _MSC_VER
00048 //     cv = shared_ptr<SplineCurve>(dynamic_cast<SplineCurve*>(crv2.clone()));
00049 // #else
00050     cv = shared_ptr<SplineCurve>(crv2.clone());
00051 // #endif
00052     curves.push_back(cv);
00053 
00054     // Make sure that the curves live on the same knot vector
00055 //     double tol = 0.00001;
00056     try {
00057         unifyCurveSplineSpace(curves, num_tol);
00058     } catch (...) {
00059         THROW("Failed unifying spline spaces!");
00060     }
00061 
00062     // Add signed coefficients
00063     vector<double> coefs;
00064     int nmb_coefs = curves[0]->numCoefs();
00065     int dim = curves[0]->dimension();
00066     coefs.resize(dim*nmb_coefs);
00067     int ki;
00068     std::vector<double>::iterator c1 = curves[0]->coefs_begin();
00069     std::vector<double>::iterator c2 = curves[1]->coefs_begin();
00070     for (ki=0; ki<dim*nmb_coefs; ki++)
00071       coefs[ki] = fac1*c1[ki] + fac2*c2[ki];
00072 
00073     // Create output curve
00074     boost::shared_ptr<SplineCurve>
00075         curvesum(new SplineCurve(nmb_coefs, 
00076                                  curves[0]->order(),
00077                                  curves[0]->basis().begin(),
00078                                  &coefs[0], 
00079                                  dim,
00080                                  false));
00081     return curvesum;
00082   }

bool Go::degenerate_triangle ( const Vector2D c1,
const Vector2D c2,
const Vector2D c3 
)

Definition at line 1191 of file 2dpoly_for_s2m.C.

References f().

Referenced by add_triangle(), split_triangle(), and trim_a_triangle().

01196   {
01197 #ifndef DBG
01198     const bool dbg = false;
01199 #endif
01200 
01201     // const double eps=1e-14;
01202     const double eps=1e-9;
01203     const double eps_squared=eps*eps;
01204   
01205     Vector2D e=c2-c1, f=c3-c1;
01206     const double e_len_squared=e*e, f_len_squared=f*f, g_len_squared=(c2-c3)*(c2-c3);
01207 
01208     if (dbg) printf("      degen_tri: edge lengths: %f %f %f\n", sqrt(e*e), sqrt(f*f), sqrt(g_len_squared));
01209 
01210     if ( (e_len_squared<eps_squared) || (f_len_squared<eps_squared) || (g_len_squared<eps_squared) )
01211       return true;
01212 
01213     // Ok, even if all lengths are non-zero, it may still be degenerate. Then the area will be zero.
01214     // 
01215     // 100219: Hmm... come to think of it, this test should be the only one needed...  But on the other hand,
01216     //         if we use the division below, we must still test on the size of the denominator, so we might as
01217     //         well keep it as it is. (Or maybe exchange the whole thing for an area-test?!)
01218 
01219     const double ef=(e*f)/sqrt(e_len_squared*f_len_squared);
01220     
01221     if (dbg) printf("      degen_tri: ef=%e, fabs(ef)-1.0=%e\n", ef, fabs(ef)-1.0);
01222     
01223     if (fabs(fabs(ef)-1.0) < eps)
01224       return true;
01225     
01226     return false;
01227   }

bool Go::degenerateToCurve ( const SplineSurface &  srf,
bool  dir_u,
double  tol 
)

Check if a given spline surface degnerates to a curve within a given tolerance.

Definition at line 230 of file GeometryTools.C.

References Go::SplineSurface::coefs_begin(), Go::SplineSurface::dimension(), distance_squared(), Go::SplineSurface::numCoefs_u(), and Go::SplineSurface::numCoefs_v().

00232 {
00233     // For each row of coefficients in the appropriate parameter
00234     // direction, make a rough over estimate of the curve length by
00235     // computing the length of the control polygon. Check if this length
00236     // exceeds the given tolerance.
00237     int nmb1 = (dir_u) ? srf.numCoefs_u() : srf.numCoefs_v();
00238     int nmb2 = (dir_u) ? srf.numCoefs_v() : srf.numCoefs_u();
00239     int dim = srf.dimension();
00240     vector<double>::const_iterator coefs = srf.coefs_begin();
00241     int ki, kj;
00242     int kr1 = (dir_u) ? dim : nmb2*dim;
00243     int kr2 = (dir_u) ? nmb1*dim : dim;
00244     for (kj=0; kj<nmb2; kj++)
00245     {
00246         vector<double>::const_iterator c1 = coefs + kr2;
00247         double tlen = 0.0;
00248         for (ki=1; ki<nmb1; ki++, c1+=kr1)
00249         {
00250             double d1 = distance_squared(&c1[0], &c1[0]+dim, &c1[0]+dim);
00251             tlen += d1;
00252         }
00253         if (tlen > tol)
00254             break;
00255     }
00256 
00257     return (kj < nmb2) ? false : true;
00258 }

template<typename T >
T Go::determinantOf ( const Array< T, 3 > *  a  )  [inline]

Calculates the determinant of a 3 x 3 matrix, represented in memory as a sequence of 3 Array s of length 3.

Same function also exists for 2 x 2 matrices.

Definition at line 40 of file Volumes.h.

00041 {
00042     return 
00043         a[0][0] * (a[1][1] * a[2][2] - a[2][1] * a[1][2]) -
00044         a[0][1] * (a[1][0] * a[2][2] - a[2][0] * a[1][2]) +
00045         a[0][2] * (a[1][0] * a[2][1] - a[2][0] * a[1][1]);
00046 };

template<typename T >
T Go::determinantOf ( const Array< T, 2 > *  a  )  [inline]

Calculates the determinant of a 2 x 2 matrix, represented in memory as a sequence of 2 Array s of length 2.

Same function also exists for 3 x 3 matrices.

Definition at line 30 of file Volumes.h.

Referenced by simplex_volume().

00031 {
00032     return a[0][0] * a[1][1] - a[1][0] * a[0][1];
00033 };

template<typename ForwardIterator >
go_iterator_traits<ForwardIterator>::value_type Go::distance_squared ( ForwardIterator  first1,
ForwardIterator  last1,
ForwardIterator  first2 
) [inline]

distance_squared

Definition at line 136 of file Utils.h.

Referenced by closest_in_array(), and degenerateToCurve().

00139         {
00140             typename go_iterator_traits<ForwardIterator>::value_type sum = 0;
00141             for (; first1 != last1; ++first1, ++first2)
00142                 sum += (*first1 - *first2)*(*first1 - *first2);
00143             return sum;
00144         }

template<typename InputStream >
InputStream& Go::eatwhite ( InputStream &  is  )  [inline]

eat white space

Definition at line 175 of file Utils.h.

00176         {
00177             char c;
00178             while (is.get(c)) {
00179                 if (isspace(c)==0) {
00180                     is.putback(c);
00181                     break;
00182                 }
00183             }
00184             return is;
00185         }

void Go::estimateIsoCurveLength ( const SplineSurface &  srf,
bool  dir_u,
double  par,
double &  length 
)

estimate the length of an iso-curve on the surface

Parameters:
srf the surface containing the iso-curve
dir_u 'true' if the iso-curve is along the first parameter (second parameter fixed), 'false' if it is the first parameter that is fixed.
par parameter value for the fixed parameter
length returns the estimated length of the iso-curve

Definition at line 204 of file GeometryTools.C.

References Go::Point::dist(), Go::SplineSurface::endparam_u(), Go::SplineSurface::endparam_v(), Go::SplineSurface::startparam_u(), and Go::SplineSurface::startparam_v().

00207 {
00208   int nptsample = 5;
00209   length = 0;
00210   int ki;
00211   double sfpar[2];
00212   double ta = (dir_u) ? srf.startparam_u() : srf.startparam_v();
00213   double tb = (dir_u) ? srf.endparam_u() : srf.endparam_v();
00214   double tint = (tb - ta)/(double)(nptsample-1);
00215   int idxc = (dir_u) ? 1 : 0; // Index of constant parameter, i.e. par
00216   int idxv = 1 - idxc;
00217   sfpar[idxc] = par;
00218   sfpar[idxv] = ta;
00219   Point pt1, pt2;
00220   pt1 = srf.ParamSurface::point(sfpar[0],sfpar[1]);
00221   for (ki=1, sfpar[idxv]+=tint; ki<nptsample; ki++, sfpar[idxv]+=tint)
00222     {
00223       pt2 = srf.ParamSurface::point(sfpar[0],sfpar[1]);
00224       length += pt1.dist(pt2);
00225       pt1 = pt2;
00226     }
00227 }

void Go::estimateSurfaceSize ( const ParamSurface &  srf,
double &  length_u,
double &  length_v,
double *  area = NULL 
)

Rough estimate of the size of a parametric surface.

Parameters:
srf the surface we want to estimate the size of
length_u the estimated average length of the surface, moving along the first parameter
length_v the estimated average length of the surface, moving along the second parameter

Definition at line 144 of file GeometryTools.C.

References Go::ParamSurface::containingDomain(), Go::Point::dist(), Go::ParamSurface::point(), Go::RectDomain::umax(), Go::RectDomain::umin(), Go::RectDomain::vmax(), and Go::RectDomain::vmin().

Referenced by evaluateMinCurvatureRadius(), and Go::TesselatorUtils::getResolution().

00147 {
00148   const int ncvsample = 3;
00149   const int nptsample = 5;
00150   length_u = length_v = 0.0;
00151 
00152   int ki, kj;
00153   double umin, vmin, umax, vmax;
00154   if (area)
00155     {
00156       umin = area[0];
00157       umax = area[1];
00158       vmin = area[2];
00159       vmax = area[3];
00160     }
00161   else
00162     {
00163       RectDomain domain = srf.containingDomain();
00164       umin = domain.umin();
00165       vmin = domain.vmin();
00166       umax = domain.umax();
00167       vmax = domain.vmax();
00168     }
00169   double uint = (umax - umin)/(double)(ncvsample-1);
00170   double vint = (vmax - vmin)/(double)(nptsample-1);
00171 
00172   double par_u, par_v;
00173   Point pt1, pt2;
00174   for (ki=0, par_u=umin; ki<ncvsample; ki++, par_u+=uint)
00175     {
00176       par_v = vmin;
00177       pt1 = srf.point(par_u, par_v);
00178       for (kj=1; kj<=nptsample; kj++, par_v+=vint)
00179         {
00180           pt2 = srf.point(par_u, par_v);
00181           length_v += pt1.dist(pt2);
00182           pt1 = pt2;
00183         }
00184     }
00185   length_v /= (double)ncvsample;
00186   
00187   uint = (umax - umin)/(double)(nptsample-1);
00188   vint = (vmax - vmin)/(double)(ncvsample-1);
00189   for (ki=0, par_v=vmin; ki<ncvsample; ki++, par_v+=vint)
00190     {
00191       par_u = umin;
00192       pt1 = srf.point(par_u, par_v);
00193       for (kj=1; kj<=nptsample; kj++, par_u+=uint)
00194         {
00195           pt2 = srf.point(par_u, par_v);
00196           length_u += pt1.dist(pt2);
00197           pt1 = pt2;
00198         }
00199     }
00200   length_u /= (double)ncvsample;
00201 }

void Go::evaluateMinCurvatureRadius ( const ParamSurface &  sf,
double  star_u,
double  end_u,
double  start_v,
double  end_v,
double  tolerance,
std::vector< double > &  param_u,
std::vector< double > &  param_v,
std::vector< std::vector< double > > &  curvs,
double &  mincurv,
double &  minpos_u,
double &  minpos_v,
bool  initialize 
)

Definition at line 348 of file CurvatureAnalysis.C.

References area(), estimateSurfaceSize(), Go::ParamSurface::inDomain(), Go::ParamSurface::isIsoTrimmed(), MAXDOUBLE, and principalCurvatures().

Referenced by minimalCurvatureRadius().

00358 {
00359   int minCells = 3;
00360   int maxCells = 20;
00361 
00362   double area[4];
00363   area[0] = start_u;
00364   area[1] = end_u;
00365   area[2] = start_v;
00366   area[3] = end_v;
00367 
00368   double len_u, len_v;
00369   estimateSurfaceSize(sf, len_u, len_v, area);
00370 
00371   double huge_rad = MAXDOUBLE;
00372   double tol2 = 10.0*tolerance;
00373   int pts_u = int (len_u / tol2) + 1;
00374   int pts_v = int (len_v / tol2) + 1;
00375 
00376   double iso_trim_tol = 0.0001*std::min(end_u - start_u, end_v - start_v);
00377   iso_trim_tol = std::max(iso_trim_tol, 1.0e-7);
00378 
00379   bool iso_trimmed = sf.isIsoTrimmed(iso_trim_tol);
00380 
00381   pts_u = min(maxCells, max(minCells, pts_u));
00382   pts_v = min(maxCells, max(minCells, pts_v));
00383 
00384   param_u.resize(pts_u);
00385   param_v.resize(pts_v);
00386   curvs.resize(pts_u);
00387 
00388   double step_u = (end_u - start_u)/double(pts_u-1);
00389   double step_v = (end_v - start_v)/double(pts_v-1);
00390 
00391   double pos_u = start_u;
00392   for (int i = 0; i < pts_u; pos_u += step_u, ++i)
00393     {
00394       curvs[i].resize(pts_v);
00395       param_u[i] = pos_u;
00396 
00397       double pos_v = start_v;
00398       for (int j = 0; j < pts_v; pos_v += step_v, ++j)
00399         {
00400           if (i==0) param_v[j] = pos_v;
00401           double curveRad;
00402           if (iso_trimmed || sf.inDomain(pos_u, pos_v))
00403           {
00404 //            double gauss_curv, mean_curv;
00405 //            curvatures(sf, pos_u, pos_v, gauss_curv, mean_curv);
00406 //            if (gauss_curv < 0.0) gauss_curv = -gauss_curv;
00407 //            if (gauss_curv < 1e-12) gauss_curv = 1e-12;
00408 //            curveRad = 1.0 / gauss_curv;
00409 
00410               // Evaluate principal curvatures
00411               Point d1, d2;
00412               double k1, k2;
00413               principalCurvatures(sf, pos_u, pos_v, k1, d1, k2, d2);
00414               double kmax = std::max(fabs(k1), fabs(k2));
00415               curveRad = (kmax > 1.0e-12) ? 1.0 / kmax : MAXDOUBLE;
00416           }
00417           else 
00418               curveRad = huge_rad;
00419 
00420           curvs[i][j] = curveRad;
00421           if ( (i==0 && j==0 && initialize) || curveRad < mincurv)
00422             {
00423               mincurv = curveRad;
00424               minpos_u = pos_u;
00425               minpos_v = pos_v;
00426             }
00427         }
00428 
00429     }
00430 
00431 }

int Go::extremalPtSurfSurf ( ParamSurface *  psurf1,
ParamSurface *  psurf2,
int  constraints[2],
double  constraints_par[2],
double  limit[],
double  enext[],
double  gpos[],
double  angle_tol 
)

Finds one point in each surface where the two normals are parallel to each other and to the difference vector between the two points.

The edge info makes it possible to constrain the search to an ISO-curve in one of or both surfaces. Ported from the sisl-function shsing_ext.

METHOD :  - Start with a guess value (u,v) in domain of surface 1 (S(u,v))
      (a) - Find domain value (r,t) of closest point (to S(u,v) in surface 2 (Q(r,t))
          - If vf1(u,v) = <Su,Normal(Q> and vf2(u,v)= <Sv,Normal(Q> is small enough  stop
                 (<,> means scalar prod.)
          - Find du and dv by taylorizing vf1 and vf2.
            This include finding the derivatives of the closest point function (r(u,v),t(u,v))
            with respect to u and v. (called h(u,v) in article, see comments in shsing_s9dir)
          - u:= u+du v:= v+dv, goto (a)

   
REFERENCES : Solutions of tangential surface and curve intersections.
             R P Markot and R L Magedson
             Computer-Aided Design; vol. 21, no 7 sept. 1989, page 421-429
   
Parameters:
psurf1 Pointer to the first surface.
psurf2 Pointer to the second surface
constraints Constraints flag.

  • constraints
    1. constraints[0] Constraint 1. surface
    2. constraints[1] Constraint 2. surface
  • constraints values
    1. -1 : No constraints.
    2. 0 : Constant in 1. par direction
    3. 1 : Constant in 2. par direction

------------------ or ----------------

Parameters:
constraints_par Constraints parameters.

  1. constraints_par[0] Constraints parameter 1. surface.
  2. constraints_par[1] Constraints parameter 2. surface.
limit - Parameter borders of both surfaces.

  1. limit[0] - limit[1] Parameter interval. 1. surface 1. direction.
  2. limit[2] - limit[3] Parameter interval. 1. surface 2. direction.
  3. limit[4] - limit[5] Parameter interval. 2. surface 1. direction.
  4. limit[6] - limit[7] Parameter interval. 2. surface 2. direction.
enext Parameter start value for iteration(4 values).
angle_tol The angular tolerance for success.
gpos Parameter values of the found singularity(4 values).
Returns:
Status message. =1 Extremum found. = 0 Extremum NOT found.

Definition at line 49 of file extremalPtSurfSurf.C.

References Go::Point::angle_smallest(), Go::ParamSurface::closestPoint(), DEBUG_ERROR_IF, Go::GeomObject::dimension(), insideParamDomain(), nextStep(), Go::ParamSurface::normal(), Go::Point::normalize(), Go::ParamSurface::point(), and THROW.

00056              : To find one point in each surface where the two normals
00057 *              are parallel to each other and to the difference vector
00058 *              between the two points.
00059 *              The edge info makes it possible to constrain the search
00060 *              to an ISO-curve in one of or both surfaces.
00061 *
00062 * INPUT      : psurf1 - Pointer to first surface
00063 *              psurf2 - Pointer to second surface
00064 *              constraints[0]- Constraint 1. surface
00065 *              constraints[1]- Constraint 2. surface
00066 *                       = -1 No constraints
00067 *                       =  0 Constant in 1. par direction
00068 *                       =  1 constant in 2. par direction
00069 *
00070 *                           Example constrains == 0
00071 *
00072 *                           -----------------
00073 *                           !     |          !
00074 *                           !     |          !
00075 *                           !     |          !
00076 *                           !     |          !
00077 *                           !     |          !
00078 *                           !     |          !
00079 *                           -----------------
00080 *                                 ^
00081 *                                 |
00082 *                                 constraints_par
00083 *              constraints_par[0]- Constraints parameter 1. surface
00084 *              constraints_par[1]- Constraints parameter 2. surface
00085 *
00086 *              limit  - Parameter borders of both surfaces.
00087 *                       limit[0] - limit[1] Parameter interval 1.  surface 1. direction.
00088 *                       limit[2] - limit[3] Parameter interval 1.  surface 2. direction.
00089 *                       limit[4] - limit[5] Parameter interval 2.  surface 1. direction.
00090 *                       limit[6] - limit[7] Parameter interval 2.  surface 2. direction.
00091 *              enext     - Parameter start value for iteration(4 values).
00092 *              angle_tol - The angular tolerance for success.
00093 *
00094 * OUTPUT     : gpos    - Parameter values of the found singularity.(4 values)
00095 *              kstat   - status messages
00096 *                                = 1   : Extremum found.
00097 *                                = 0   : Extremum NOT found.
00098 *
00099 *
00100 * METHOD     :  - Start with a guess value (u,v) in domain of surface 1 (S(u,v))
00101 *           (a) - Find domain value (r,t) of closest point (to S(u,v) in surface 2 (Q(r,t))
00102 *               - If vf1(u,v) = <Su,Normal(Q> and vf2(u,v)= <Sv,Normal(Q> is small enough  stop
00103 *                      (<,> means scalar prod.)
00104 *               - Find du and dv by taylorizing vf1 and vf2.
00105 *                 This include finding the derivatives of the closest point function (r(u,v),t(u,v))
00106 *                 with respect to u and v. (called h(u,v) in article, see comments in nextStep)
00107 *               - u:= u+du v:= v+dv, goto (a)
00108 *
00109 *
00110 * REFERENCES : Solutions of tangential surface and curve intersections.
00111 *              R P Markot and R L Magedson
00112 *              Computer-Aided Design; vol. 21, no 7 sept. 1989, page 421-429
00113 *
00114 *
00115 *********************************************************************
00116 */
00117 {
00118   int kstat = 0;            /* Local status variable.                      */
00119   int ki;                   /* Loop control                                */
00120   int kp;                   /* Loop control                                */
00121   const int kder=2;         /* Order of derivatives to be calulated        */
00122   const int kdim=3;         /* Dimension of space the surface lies in      */
00123   int knbit;                /* Number of iterations                        */
00124   double tdelta[4];         /* Length of parameter intervals.              */
00125   double tdist;             /* The current norm of the cross product       */
00126                             /* between the two normals                     */
00127   double tprev;             /* The current norm of the cross product  ?    */
00128                             /* between the two normals                     */
00129   double td[2],t1[2],tdn[2];/* Distances between old and new parameter     */
00130                             /* value in the two parameter directions.     */
00131   std::vector<Point> sval1(7,Point(kdim)); /* Value ,first and second      */
00132                                            /* derivative of first surface  */
00133   Point& snorm1=sval1[6];    /* Normal vector of firstrface                */
00134   std::vector<Point> sval2(7,Point(kdim)); /* Value ,first and second      */
00135                                            /* derivative of second surface */
00136   Point& snorm2=sval2[6];   /* Normal vector of second surface             */
00137   double snext[4];          /* Parameter values                            */
00138   double start[2];          /* Parameters limit of second surface, used in */
00139                             /* call to closest point                       */
00140   double end[2];            /* Parameters limit of second surface, used in */
00141                             /* call to closest point                       */
00142   double guess[2];          /* Start point for closest point iteration     */
00143   Point& ppoint=sval1[0];   /* Contains the current position in first      */
00144                             /* surface used in closest point iteration     */
00145   double min_tol = (double)10000.0*REL_COMP_RES;
00146   int max_iter=20;          /* Maximal number of iteration allowed         */
00147   double limit_corr[8];     /* Copy of limit with edge constraints         */
00148   double clo_dist;          /* Distance between point and closest point    */
00149   Point clo_pt(3);          /* Closest point                               */
00150   /* --------------------------------------------------------------------- */
00151 
00152   // Test input.
00153   DEBUG_ERROR_IF(kdim != psurf1->dimension(), "Dimension mismatch.");
00154   DEBUG_ERROR_IF(kdim != psurf2->dimension(), "Dimension mismatch.");
00155 
00156   // Fetch referance numbers from the serach intervals for the surfaces.
00157   tdelta[0] = limit[1] - limit[0];
00158   tdelta[1] = limit[3] - limit[2];
00159   tdelta[2] = limit[5] - limit[4];
00160   tdelta[3] = limit[7] - limit[6];
00161 
00162   // Set limit values, used in closest point iteration
00163   start[0] = limit[4];
00164   start[1] = limit[6];
00165   end[0]   = limit[5];
00166   end[1]   = limit[7];
00167 
00168   // Take into account edge constraints
00169   for (int i=0;i<8;i++)
00170     limit_corr[i]=limit[i];    
00171 
00172   for (ki=0,kp=0;ki<2;ki++,kp+=4) {
00173     switch (constraints[ki])
00174     {
00175     case -1:
00176       break;
00177     case 0:
00178       limit_corr[kp]    = limit_corr[kp+1] = constraints_par[ki];
00179       break;
00180     case 1:
00181       limit_corr[kp+2] = limit_corr[kp+3] = constraints_par[ki];
00182       break;
00183     default:
00184       THROW("Wrong constraint: " << constraints[ki]);
00185 
00186       break;
00187     }
00188   }
00189 
00190   Vector2D corner1(limit_corr[4],limit_corr[6]);
00191   Vector2D corner2(limit_corr[5],limit_corr[7]);
00192   RectDomain rect_dom2(corner1,corner2);
00193 
00194   // Collapsed ?
00195   for (ki=0;ki<4;ki++) 
00196     tdelta[ki] = max (tdelta[ki], min_tol);
00197 
00198   // Initiate output variables.
00199   for (ki=0;ki<4;ki++)
00200     gpos[ki] = enext[ki];
00201 
00202   for (ki=0;ki<4;ki++) {
00203     // Snap to the limit box
00204     gpos[ki] = max(gpos[ki], limit_corr[2*ki]);
00205     gpos[ki] = min(gpos[ki], limit_corr[2*ki+1]);
00206   }
00207 
00208   //  Evaluate 0.-2. derivatives of first surface
00209   psurf1->point(sval1,gpos[0],gpos[1],kder);
00210   psurf1->normal(snorm1,gpos[0], gpos[1]);
00211 
00212   //  Get closest point in second surface.
00213   guess[0] = gpos[2];
00214   guess[1] = gpos[3];
00215   psurf2->closestPoint(ppoint,gpos[2],gpos[3],clo_pt,clo_dist,
00216                        REL_PAR_RES, &rect_dom2,guess);
00217   //                   REL_COMP_RES, &rect_dom2,guess);    @bsp
00218 
00219 
00220   //  Evaluate 0.-2. derivatives of second surface
00221   psurf2->point(sval2,gpos[2],gpos[3],kder);
00222   psurf2->normal(snorm2,gpos[2], gpos[3]);
00223 
00224   //  Get length of normal cross product
00225   //s6crss(snorm1,snorm2,temp);
00226   //tprev = s6length(temp,kdim,&kstat);
00227   //  temp = SIX_norm(snorm1);
00228   //  temp = SIX_norm(snorm2);
00229 
00230   // Angle between the normal vectors
00231   snorm1.normalize();
00232   snorm2.normalize();
00233   tprev = snorm1.angle_smallest(snorm2);
00234 
00235   // Compute the Newton stepdistance vector in first surface.
00236   nextStep(td,sval1,sval2);
00237 
00238   // Adjust if we are not inside the parameter intervall.
00239   for (ki=0;ki<2;ki++)
00240     t1[ki] = td[ki];
00241   insideParamDomain(t1,gpos,limit_corr);
00242 
00243 
00244   // Iteratation loop.
00245 
00246   for (knbit = 0; knbit < max_iter; knbit++) {
00247 
00248     snext[0] = gpos[0] + t1[0];
00249     snext[1] = gpos[1] + t1[1];
00250 
00251     // Evaluate 0.-2. derivatives of first surface
00252     psurf1->point(sval1,snext[0],snext[1],kder);
00253     psurf1->normal(snorm1,snext[0], snext[1]);
00254     sval1[6]=snorm1;
00255 
00256     //   Get closest point in second surface.
00257     guess[0] = gpos[2];
00258     guess[1] = gpos[3];
00259     psurf2->closestPoint(ppoint,snext[2],snext[3],clo_pt,clo_dist,
00260                          REL_PAR_RES, &rect_dom2,guess);
00261     //                   REL_COMP_RES, &rect_dom2,guess);   @bsp
00262     
00263     // Since the last 2 values in snext has been changed in closestPoint:
00264     for (ki=2;ki<4;ki++) {
00265       // Snap to the limit box
00266       snext[ki] = max(snext[ki], limit_corr[2*ki]);
00267       snext[ki] = min(snext[ki], limit_corr[2*ki+1]);
00268     }
00269 
00270     //  Evaluate 0.-2. derivatives of second surface
00271     psurf2->point(sval2,snext[2],snext[3],kder);
00272     psurf2->normal(snorm2,snext[2], snext[3]);
00273     sval2[6]=snorm2;
00274 
00275  
00276     // Get length of normal cross product
00277     // s6crss(snorm1,snorm2,temp);
00278     // tdist = s6length(temp,kdim,&kstat);
00279     //temp = SIX_norm(snorm1);
00280     //temp = SIX_norm(snorm2);
00281     //tdist = s6ang(snorm1,snorm2,3);
00282     snorm1.normalize();
00283     snorm2.normalize();
00284     tdist = snorm1.angle_smallest(snorm2);
00285     
00286     // Compute the Newton stepdistance vector.
00287     nextStep(tdn,sval1,sval2);
00288 
00289     if (tdist <= tprev) {
00290 
00291       // Ordinary converging.
00292       
00293       for (ki=0;ki<4;ki++)
00294         gpos[ki] = snext[ki];
00295       
00296       td[0] = t1[0] = tdn[0];
00297       td[1] = t1[1] = tdn[1];
00298 
00299       
00300       // Adjust if we are not inside the parameter interval.
00301       insideParamDomain(t1,gpos,limit_corr);
00302       
00303       tprev = tdist;
00304       
00305       if ((fabs(t1[0]/tdelta[0]) <= REL_COMP_RES) &&
00306           (fabs(t1[1]/tdelta[1]) <= REL_COMP_RES)) {
00307 
00308         gpos[0] += t1[0];
00309         gpos[1] += t1[1];
00310         // Evaluate 0.-2. derivatives of first surface
00311         psurf1->point(sval1,gpos[0],gpos[1],kder);
00312         psurf1->normal(snorm1,gpos[0], gpos[1]);
00313         sval1[6]=snorm1;
00314         
00315         
00316         // Get closest point in second surface.
00317         guess[0] = gpos[2];
00318         guess[1] = gpos[3];
00319         psurf2->closestPoint(ppoint,gpos[2],gpos[3],clo_pt,clo_dist,
00320                              REL_PAR_RES, &rect_dom2,guess);
00321         //                           REL_COMP_RES, &rect_dom2,guess);
00322         break;
00323       }
00324     }
00325 
00326     else {
00327       
00328       // Not converging, half step length and try again.
00329       
00330       for (ki=0;ki<2;ki++) 
00331         t1[ki] *= 0.5;
00332     }
00333   }
00334 
00335   // Iteration stopped, test if point is extremum
00336   // Unsure about what is right here , angle between normals and difference vector ??
00337   if (tprev <= angle_tol)
00338     kstat = 1;
00339   else
00340     kstat = 0;
00341 
00342 
00343   /*
00344   // Test if the iteration is close to a knot
00345   if (fabs(gpos[0] - psurf1->et1[kleftt])/tdelta[0] < min_tol)
00346     gpos[0] = psurf1->et1[kleftt];
00347   else if (fabs(gpos[0] - psurf1->et1[kleftt+1])/tdelta[0] < min_tol)
00348     gpos[0] = psurf1->et1[kleftt+1];
00349 
00350   if (fabs(gpos[1] - psurf1->et2[klefts])/tdelta[1] < min_tol)
00351     gpos[1] = psurf1->et2[klefts];
00352   else if (fabs(gpos[1] - psurf1->et2[klefts+1])/tdelta[1] < min_tol)
00353     gpos[1] = psurf1->et2[klefts+1];
00354 
00355   if (fabs(gpos[2] - psurf2->et1[kleftu])/tdelta[2] < min_tol)
00356     gpos[2] = psurf2->et1[kleftu];
00357   else if (fabs(gpos[2] - psurf2->et1[kleftu+1])/tdelta[2] < min_tol)
00358     gpos[2] = psurf2->et1[kleftu+1];
00359 
00360   if (fabs(gpos[3] - psurf2->et2[kleftv])/tdelta[3] < min_tol)
00361     gpos[3] = psurf2->et2[kleftv];
00362   else if (fabs(gpos[3] - psurf2->et2[kleftv+1])/tdelta[3] < min_tol)
00363     gpos[3] = psurf2->et2[kleftv+1];
00364   */
00365 
00366   // Iteration completed.
00367   return kstat;
00368 }

double Go::factorial ( int  n  )  [inline]

computes n! (n factorial)

Definition at line 57 of file binom.h.

00058 {
00059     double res = 1;
00060     for (int i = 2; i <= n; ++i) {
00061         res *= i;
00062     }
00063     return res;
00064 }

void Go::findDominant ( const SplineSurface &  surface,
Vector3D &  dominant_u,
Vector3D &  dominant_v 
)

Finds the "dominant u- and v-vectors" for a surface, defined to be the sum of all the vectors pointing from one control point to the next in the u- and v-directions.

Parameters:
surface the surface we want to analyze
dominant_u returns the dominant u-vector for the surface
dominant_v returns the dominant v-vector for the surface

Definition at line 26 of file GGUdominant.C.

References Go::SplineSurface::coefs_begin(), Go::SplineSurface::numCoefs_u(), and Go::SplineSurface::numCoefs_v().

00029 {
00030     int nu = surface.numCoefs_u();
00031     int nv = surface.numCoefs_v();
00032     vector<double>::const_iterator start = surface.coefs_begin();
00033     Vector3D temp;
00034     // Dominant in u-direction
00035     dominant_u = Vector3D(0.0, 0.0, 0.0);
00036     for (int j = 0; j < nv; ++j) {
00037         for (int dd = 0; dd < 3; ++dd) {
00038             temp[dd] = *(start + 3*(nu*j + (nu-1)) + dd)
00039                 - *(start + 3*(nu*j) + dd);
00040         }
00041         dominant_u += temp;
00042     }
00043     // Dominant in v-direction
00044     dominant_v = Vector3D(0.0, 0.0, 0.0);
00045     for (int i = 0; i < nu; ++i) {
00046         for (int dd = 0; dd < 3; ++dd) {
00047             temp[dd] = *(start + 3*(nu*(nv-1) + i) + dd)
00048                 - *(start + 3*i + dd);
00049         }
00050         dominant_v += temp;
00051     }
00052 
00053     return;
00054 }

template<typename SquareMatrix >
void Go::forwardSubstitution ( const SquareMatrix &  L,
std::vector< double > *  x,
int  num_unknowns 
) [inline]

Using forward substitution to calculate x on the system Lx = b, where L is a lower triangular matrix with unitary diagonal.

Parameters:
L The lower triangular matrix. The actually used class must support the operation [][] and return 'double'.
x At function invocation, x should point to a vector of doubles, containing the vector 'b'. On successful completion of the function, this vector will contain the solution for x.
num_unknowns The system size (number of unknowns).

Definition at line 138 of file LUDecomp_implementation.h.

00140 {
00141     const int dim = int(x[0].size());
00142     for (int i = 1; i < num_unknowns; ++i) {
00143         for (int j = 0; j < i; ++j) {
00144             for (int dd = 0; dd < dim; ++dd) {
00145                 x[i][dd] -= A[i][j] * x[j][dd];
00146             }
00147         }
00148     }
00149 }

template<typename SquareMatrix , typename T >
void Go::forwardSubstitution ( const SquareMatrix &  L,
T *  x,
int  num_unknowns 
) [inline]

Using forward substitution to calculate x on the system Lx = b, where L is a lower triangular matrix with unitary diagonal.

Parameters:
L The lower triangular matrix. The actually used class must support the operation [][] and return 'double'.
x At function invocation, x should point to an array of T, containing the vector 'b'. On successful completion of the function, this array will contain the solution for x.
num_unknowns The system size (number of unknowns).

Definition at line 126 of file LUDecomp_implementation.h.

Referenced by Go::SmoothCurve::equationSolve(), and LUsolveSystem().

00128 {
00129     for (int i = 1; i < num_unknowns; ++i) {
00130         for (int j = 0; j < i; ++j) {
00131             x[i] -= A[i][j] * x[j];
00132         }
00133     }
00134 }

template<typename Functor >
double Go::gaussian_quadrature ( Functor &  f,
double  a,
double  b 
) [inline]

Routine to calculate the integral of the functor f from a to b using Gaussian quadrature with W=1 and N=10.

Definition at line 85 of file Integration.h.

References f().

Referenced by gaussian_quadrature2D().

00086 {
00087     static double x[] = { 0.1488743389, 
00088                           0.4333953941,
00089                           0.6794095682, 
00090                           0.8650633666, 
00091                           0.9739065285 };
00092     static double weight[] = { 0.2955242247, 
00093                                0.2692667193,
00094                                0.2190863625, 
00095                                0.1494513491, 
00096                                0.0666713443 };
00097 
00098     double midpt = 0.5 * (b + a);
00099     double half_length = 0.5 * (b - a);
00100     double scaled_result = double(0);
00101     double step = double(0);
00102     for (int i = 0; i < 5; ++i) {
00103         step = half_length * x[i];
00104         scaled_result += weight[i] * (f(midpt + step) + f(midpt - step));
00105     }
00106     // rescale result to correspond to actual interval size
00107     return scaled_result * half_length; 
00108 }

template<typename Functor2D >
double Go::gaussian_quadrature2D ( Functor2D &  f,
double  ax,
double  bx,
double  ay,
double  by 
) [inline]

Routine to integrate the two-dimensional functor f over the rectangle defined by ax, bx, ay and by.

Uses Gaussian quadrature.

Definition at line 148 of file Integration.h.

References gaussian_quadrature().

00150 {
00151     Integrate2ndFunctor<Functor2D> fu(f, ay, by);
00152     return gaussian_quadrature(fu, ax, bx);
00153 }

void Go::GaussQuadInner ( const BsplineBasis basis,
int  ider,
double  lim1,
double  lim2,
double ***  integral 
)

Compute all definite integrals of inner products of derivatives of B-splines up to a given order where the differentiation is of the same order for both B-splines.

The interval of integration are equal to the parameter intervals of the surface in the current par. dir.

Parameters:
basis B-spline basis.
ider Number of derivatives to compute.
lim1 Start of parameter interval.
lim2 End of parameter interval.
integral Computed integrals.

Definition at line 95 of file Integrate.C.

References Go::BsplineBasis::begin(), Go::BsplineBasis::computeBasisValues(), Go::BsplineBasis::lastKnotInterval(), Go::BsplineBasis::numCoefs(), and Go::BsplineBasis::order().

Referenced by Go::SmoothCurve::setOptim(), Go::SmoothSurfSet::setOptimize(), Go::SmoothCurveSet::setOptimize(), and Go::SmoothSurf::setOptimizeNonrational().

00103                   : Compute all definite integrals of inner products of
00104    //               derivatives of B-splines up to a given order where the
00105    //               differentiation is of the same order for both B-splines.
00106    //               The interval of integration are equal to the parameter
00107    //               intervals of the surface in the current par. dir.
00108    //
00109    //     Calls   : BsplineBasis::computeBasisValues  -
00110    //                                      Compute derivatives of B-splines.
00111    //
00112    //     Written by : Vibeke Skytt,  SINTEF SI,  09.93. (04.02)
00113    //--------------------------------------------------------------------------
00114 {
00115    int ki, kp, k1, k2, kl, kr;
00116    int kder;
00117    int kind;
00118    int kleft;
00119    double ta, tb;
00120    double tval;
00121    double tpar;
00122    int ik = basis.order();
00123    int in = basis.numCoefs();
00124    vector<double>::const_iterator et = basis.begin();
00125    vector<double> sbder(ik*(ider+1), 0.0);
00126 
00127    /* Traverse all knot intervals inside the limits of integration, computing
00128       the integral of the inner product of two B-splines defined in this
00129       interval.    */
00130 
00131    kind = (ik-1 < 5) ? ik-1 : 5;
00132    for (kl=ik-1; kl<in; kl++)
00133    {
00134       ta = et[kl];
00135       tb = et[kl+1];
00136       if (tb <= lim1 || ta >= lim2) continue;
00137 
00138       for (kr=0; kr<indices[kind]; kr++)
00139       {
00140          /* Compute parameter value in which to evaluate B-splines.  */
00141 
00142          tpar = 0.5*(sample[kind][kr]*(tb-ta) + tb + ta);
00143 
00144          /* Evaluate B-splines and derivatives of B-splines. */
00145 
00146          basis.computeBasisValues(tpar, &sbder[0], ider);
00147          kleft = basis.lastKnotInterval();
00148 
00149          for (ki=kleft-ik+1, k1=0; ki<=kleft; ki++, k1++)
00150             for (kp=ki, k2=k1; kp<=kleft; kp++, k2++)
00151                for (kder=0; kder<=ider; kder++)
00152                {
00153                   tval = (double)0.5*(tb-ta)*weight[kind][kr]*
00154                      sbder[k1*(ider+1)+kder]*sbder[k2*(ider+1)+kder];
00155 
00156                   integral[kder][ki][kp] += tval;
00157                   if (kp > ki) integral[kder][kp][ki] += tval;
00158                }
00159       }
00160    }
00161 }

void Go::GaussQuadInner2 ( const BsplineBasis basis,
int  ider,
double  lim1,
double  lim2,
double **  integral 
)

Compute all definite integrals of inner products of derivatives of B-splines up to a given order where the differentiation is of the same order for both B-splines.

The interval of integration are equal to the parameter intervals of the surface in the current par. dir.

Parameters:
basis B-spline basis.
ider Number of derivatives to compute.
lim1 Start of parameter interval.
lim2 End of parameter interval.
integral Computed integrals.

Definition at line 241 of file Integrate.C.

References Go::BsplineBasis::begin(), Go::BsplineBasis::computeBasisValues(), Go::BsplineBasis::lastKnotInterval(), Go::BsplineBasis::numCoefs(), and Go::BsplineBasis::order().

00249                   : Compute all definite integrals of inner products of
00250    //               derivatives of B-splines of a given order where the
00251    //               differentiation is of the same order for both B-splines.
00252    //               The interval of integration are equal to the parameter
00253    //               intervals of the surface in the current par. dir.
00254    //
00255    //     Calls   : BsplineBasis::computeBasisValues  -
00256    //                                      Compute derivatives of B-splines.
00257    //
00258    //     Written by : Vibeke Skytt,  SINTEF SI,  08.96. (04.02)
00259    //--------------------------------------------------------------------------
00260 {
00261    int ki, kp, k1, k2, kl, kr;
00262    int kind;
00263    double ta, tb;
00264    double tval;
00265    double tpar;
00266    int kleft;
00267    int ik = basis.order();
00268    int in = basis.numCoefs();
00269    vector<double>::const_iterator et = basis.begin();
00270    vector<double> sbder(ik*(ider+1), 0.0);
00271 
00272    /* Traverse all knot intervals inside the limits of integration, computing
00273       the integral of the inner product of two B-splines defined in this
00274       interval.    */
00275 
00276    kind = (ik-1 < 5) ? ik-1 : 5;
00277    for (kl=ik-1; kl<in; kl++)
00278    {
00279       ta = et[kl];
00280       tb = et[kl+1];
00281       if (tb <= lim1 || ta >= lim2) continue;
00282 
00283       for (kr=0; kr<indices[kind]; kr++)
00284       {
00285          /* Compute parameter value in which to evaluate B-splines.  */
00286 
00287          tpar = 0.5*(sample[kind][kr]*(tb-ta) + tb + ta);
00288 
00289          /* Evaluate B-splines and derivatives of B-splines. */
00290 
00291          basis.computeBasisValues(tpar, &sbder[0], ider);
00292          kleft = basis.lastKnotInterval();
00293 
00294          for (ki=kleft-ik+1, k1=0; ki<=kleft; ki++, k1++)
00295             for (kp=ki, k2=k1; kp<=kleft; kp++, k2++)
00296             {
00297               tval = (double)0.5*(tb-ta)*weight[kind][kr]*
00298                      sbder[k1*(ider+1)+ider]*sbder[k2*(ider+1)+ider];
00299 
00300               integral[ki][kp] += tval;
00301               if (kp > ki) integral[kp][ki] += tval;
00302             }
00303       }
00304    }
00305 }

void Go::GaussQuadInnerFlat ( const BsplineBasis basis,
int  derivs,
int  start_der,
int  gap,
double  lim1,
double  lim2,
std::vector< double > &  integral 
)

Compute all definite integrals of inner products of derivatives of B-splines up to a given order where the gap between the order of differentiation on the first and second B-spline is constant.

The interval of integration are equal to the parameter intervals of the surface in the current par. dir.

Parameters:
basis B-spline basis.
derivs Number of derivatives to compute.
gap Difference between derivation order.
start_der First derivative to compute.
lim1 Start of parameter interval.
lim2 End of parameter interval.
integral Computed integrals.

Definition at line 167 of file Integrate.C.

References Go::BsplineBasis::begin(), Go::BsplineBasis::computeBasisValues(), Go::BsplineBasis::lastKnotInterval(), Go::BsplineBasis::numCoefs(), and Go::BsplineBasis::order().

00177                : Compute all definite integrals of inner products of
00178 //                  derivatives of B-splines up to a given order where the
00179 //               gap between the order of differentiation on the first and
00180 //               second B-spline is constant.
00181 //               The computation starts at a specified derivation depths,
00182 //               assuming the lower derivation order integrals are
00183 //               already found.
00184 //               The interval of integration are equal to the parameter
00185 //               intervals of the surface in the current par. dir.
00186 //
00187 //     Calls   : BsplineBasis::computeBasisValues  -
00188 //                                      Compute derivatives of B-splines.
00189 //
00190 //     Written by : Kjell Fredrik Pettersen, SINTEF IKT, 2009-12-16, based on
00191 //                  GaussQuadInner()
00192 //--------------------------------------------------------------------------
00193 {
00194   int order = basis.order();
00195   int n_coefs = basis.numCoefs();
00196   vector<double>::const_iterator et = basis.begin();
00197   vector<double> sbder(order*(derivs+gap+1), 0.0);
00198 
00199   /* Traverse all knot intervals inside the limits of integration, computing
00200      the integral of the inner product of two B-splines defined in this
00201      interval.    */
00202 
00203   int kind = (order-1 < 5) ? order-1 : 5;
00204   for (int k = order - 1; k < n_coefs; ++k)   // For every Bezier segment
00205     {
00206       double ta = et[k];
00207       double tb = et[k + 1];
00208       if (tb <= lim1 || ta >= lim2) continue;
00209 
00210       for (int l = 0; l < indices[kind]; ++l)  // For every sample value in segment
00211         {
00212           /* Compute parameter value in which to evaluate B-splines.  */
00213 
00214           double tpar = 0.5 * (sample[kind][l]*(tb-ta) + tb + ta);
00215 
00216           /* Evaluate B-splines and derivatives of B-splines. */
00217 
00218           basis.computeBasisValues(tpar, &sbder[0], derivs+gap);
00219           int left = basis.lastKnotInterval();
00220 
00221           for (int i = left - order + 1, k1 = 0; i <= left; ++i, ++k1)  // For every first B-spline
00222             for (int j = i, k2 = k1; j <= left; ++j, ++k2)     // For every second B-spline
00223               for (int der = start_der; der <= derivs; ++der)  // For every derivation order
00224                 {
00225                   double tval = 0.5 * (tb-ta) * weight[kind][l]
00226                     * sbder[k1*(derivs+gap+1)+der+gap] * sbder[k2*(derivs+gap+1)+der];
00227                   double tval_oposite = 0.5 * (tb-ta) * weight[kind][l]
00228                     * sbder[k1*(derivs+gap+1)+der] * sbder[k2*(derivs+gap+1)+der+gap];
00229 
00230                   integral[j-i+order-1 + (2*order-1)*(i + n_coefs*der)] += tval;
00231                   if (j > i)
00232                     integral[i-j+order-1 + (2*order-1)*(j + n_coefs*der)] += tval_oposite;
00233                 }
00234         }
00235     }
00236 }

void Go::GaussQuadInnerRational ( const BsplineBasis basis,
int  ider,
double  lim1,
double  lim2,
shared_ptr< SplineCurve bspline_curve,
double ***  integral 
)

Definition at line 309 of file Integrate.C.

References Go::BsplineBasis::begin(), Go::BsplineBasis::knotInterval(), Go::BsplineBasis::numCoefs(), and Go::BsplineBasis::order().

00318                   : Compute all definite integrals of inner products of
00319    //               derivatives of rational B-splines up to a given order where the
00320    //               differentiation is of the same order for both B-splines.
00321    //               The interval of integration are equal to the parameter
00322    //               intervals of the surface in the current par. dir.
00323    //
00324    //     Calls   : BsplineBasis::computeBasisValues  -
00325    //                                      Compute derivatives of B-splines.
00326    //
00327    //     Written by : Kjell Fredrik Pettersen, 2009-11-26, based on
00328    //                  GaussQuadInnerRational by Vibeke Skytt,  SINTEF SI,  09.93. (04.02)
00329    //--------------------------------------------------------------------------
00330 {
00331    int ki, kp, k1, k2, kl, kr;
00332    int kder;
00333    int kind;
00334    int kleft;
00335    double ta, tb;
00336    double tval;
00337    double tpar;
00338    int ik = basis.order();
00339    int in = basis.numCoefs();
00340    vector<double>::const_iterator et = basis.begin();
00341    vector<double> sbder(ik*(ider+1), 0.0);
00342 
00343    vector<double>::iterator bspl_it = bspline_curve->rcoefs_begin();
00344    vector<Point> pts(ider+1);
00345    for (int i = 0; i <= ider; ++i)
00346      pts[i] = Point(1);
00347    
00348    /* Traverse all knot intervals inside the limits of integration, computing
00349       the integral of the inner product of two B-splines defined in this
00350       interval.    */
00351 
00352    kind = (ik-1 < 5) ? ik-1 : 5;
00353    for (kl=ik-1; kl<in; kl++)
00354    {
00355       ta = et[kl];
00356       tb = et[kl+1];
00357       if (tb <= lim1 || ta >= lim2) continue;
00358 
00359       for (kr=0; kr<indices[kind]; kr++)
00360       {
00361          /* Compute parameter value in which to evaluate B-splines.  */
00362 
00363          tpar = 0.5*(sample[kind][kr]*(tb-ta) + tb + ta);
00364 
00365          /* Evaluate B-splines and derivatives of B-splines. */
00366 
00367          kleft = basis.knotInterval(tpar);
00368          for (ki=kleft-ik+1, k1=0; ki<=kleft; ki++, k1++)
00369            {
00370              bspl_it[ki*2] = 1.0;
00371              bspline_curve->point(pts, tpar, ider);
00372              for (int i = 0; i <= ider; ++i)
00373                sbder[k1*(ider+1)+i] = pts[i][0];
00374              bspl_it[ki*2] = 0.0;
00375            }
00376 
00377          for (ki=kleft-ik+1, k1=0; ki<=kleft; ki++, k1++)
00378             for (kp=ki, k2=k1; kp<=kleft; kp++, k2++)
00379                for (kder=0; kder<=ider; kder++)
00380                {
00381                   tval = (double)0.5*(tb-ta)*weight[kind][kr]*
00382                      sbder[k1*(ider+1)+kder]*sbder[k2*(ider+1)+kder];
00383 
00384                   integral[kder][ki][kp] += tval;
00385                   if (kp > ki) integral[kder][kp][ki] += tval;
00386                }
00387       }
00388    }
00389 }

void Go::GaussQuadInnerRational ( const BsplineBasis &  basis,
int  ider,
double  lim1,
double  lim2,
boost::shared_ptr< SplineCurve >  bspline_curve,
double ***  integral 
)

Compute all definite integrals of inner products of derivatives of rational B-splines up to a given order where the differentiation is of the same order for both B-splines.

The interval of integration are equal to the parameter intervals of the surface in the current par. dir.

Parameters:
basis B-spline basis.
ider Number of derivatives to compute.
lim1 Start of parameter interval.
lim2 End of parameter interval.
bspline_curve 1-dim rational 0-function defining weights
coefs Wieghts for denominator function
integral Computed integrals.

Referenced by Go::SmoothCurve::setOptim().

void Go::GaussQuadValues ( const BsplineBasis basis,
std::vector< double > &  parameters,
std::vector< double > &  par_weights 
)

Functions used to compute integrals of inner products of B-splines.

Store parameters and weights used for numerical integration by Gauss quadrature. All parameter values for all Bezier segments are stored in parameters, while the weights within an interval is stored only once in weights. Thus, the lenght of weights gives the number of samples for each Bezier segment.

Parameters:
basis B-spline basis
parameters Parameter values for all points
par_weights Weight for each parameter

Definition at line 59 of file Integrate.C.

References Go::BsplineBasis::begin(), Go::BsplineBasis::numCoefs(), and Go::BsplineBasis::order().

Referenced by Go::SmoothSurf::approxOrigRational(), Go::SmoothSurf::setOptimizeRational(), and Go::SmoothSurf::setRationalCnAtSeem().

00065                   : Store parameters and weights used for numerical integration
00066    //               by Gauss quadrature. All parameter values for all Bezier segments
00067    //               are stored in parameters, while the weights within an interval is
00068    //               stored only once in weights. Thus, the lenght of weights gives
00069    //               the number of samples for each Bezier segment.
00070    //--------------------------------------------------------------------------
00071 {
00072    int ord = basis.order();
00073    int ncoef = basis.numCoefs();
00074    int kind = (ord-1 < 5) ? ord-1 : 5;
00075 
00076    int w_size = indices[kind];
00077    parameters.resize(w_size * (ncoef-ord+1));
00078    par_weights.resize(w_size);
00079 
00080    for (int i = 0; i < w_size; ++i)
00081      par_weights[i] = 0.5 * weight[kind][i];
00082 
00083    vector<double>::const_iterator it = basis.begin();
00084    for (int i = 0, par_pos = 0; i < ncoef-ord+1; ++i)
00085      {
00086        double int_start = it[i+ord-1];
00087        double int_end = it[i+ord];
00088        for (int j = 0; j < w_size; ++j, ++par_pos)
00089          parameters[par_pos] = 0.5 * (sample[kind][j]*(int_end-int_start) + int_end + int_start);
00090      }
00091 }

bool Go::getCoefEnumeration ( boost::shared_ptr< SplineSurface >  sf,
int  bd,
std::vector< int > &  enumeration 
)

Definition at line 415 of file SurfaceTools.C.

00418   {
00419     if (bd < 0 || bd > 3)
00420       return false;
00421 
00422     int kn1 = sf->numCoefs_u();
00423     int kn2 = sf->numCoefs_v();
00424 
00425     int nmb = (bd == 0 || bd == 1) ? kn2 : kn1;
00426     enumeration.resize(nmb);
00427     int start = (bd == 0 || bd == 2) ? 0 :
00428       ((bd == 1) ? kn1-1 : kn1*(kn2-1));
00429     int del = (bd == 0 || bd == 1) ? kn1 : 1;
00430 
00431     int ki, idx;
00432     for (ki=0, idx=start; ki<nmb; ++ki, idx+=del)
00433       enumeration[ki] = idx;
00434 
00435     return true;
00436   }

bool Go::getCorrCoefEnum ( shared_ptr< SplineSurface >  sf1,
shared_ptr< SplineSurface >  sf2,
int  bd1,
int  bd2,
bool  same_orient,
vector< pair< int, int > > &  enumeration 
)

Definition at line 377 of file SurfaceTools.C.

00382   {
00383     int kn1 = sf1->numCoefs_u();
00384     int kn2 = sf1->numCoefs_v();
00385     int kn3 = sf2->numCoefs_u();
00386     int kn4 = sf2->numCoefs_v();
00387 
00388     int nmb1 = (bd1 == 0 || bd1 == 1) ? kn2 : kn1;
00389     int nmb2 = (bd2 == 0 || bd2 == 1) ? kn4 : kn3;
00390     if (nmb1 != nmb2)
00391       return false;  // No correspondence
00392 
00393     enumeration.resize(nmb1);
00394     int start1 = (bd1 == 0 || bd1 == 2) ? 0 :
00395       ((bd1 == 1) ? kn1-1 : kn1*(kn2-1));
00396     int del1 = (bd1 == 0 || bd1 == 1) ? kn1 : 1;
00397 
00398     int start2 = (bd2 == 0 || bd2 == 2) ? 0 :
00399       ((bd2 == 1) ? kn3-1 : kn3*(kn4-1));
00400     int del2 = (bd2 == 0 || bd2 == 1) ? kn3 : 1;
00401     if (!same_orient)
00402       {
00403         start2 += (nmb2-1)*del2;
00404         del2 *= -1;
00405       }
00406 
00407     int ki, idx1, idx2;
00408     for (ki=0, idx1=start1, idx2=start2; ki<nmb1; ++ki, idx1+=del1, idx2+=del2)
00409       enumeration[ki] = make_pair(idx1, idx2);
00410  
00411     return true;
00412  }

bool Go::getCorrCoefEnum ( boost::shared_ptr< SplineSurface >  sf1,
boost::shared_ptr< SplineSurface >  sf2,
int  bd1,
int  bd2,
bool  same_orient,
std::vector< std::pair< int, int > > &  enumeration 
)
double Go::getCurrentTime (  ) 

Number of seconds since some (probably system-dependent) epoch.

Definition at line 98 of file timeutils.C.

Referenced by Go::CPUclock::CPUclock(), Go::CPUclock::getInterval(), Go::CPUclock::getTime(), and main().

00100     {
00101 #ifdef WIN32
00102 #ifndef _WIN32_WCE
00103         _ftime(&timeb_ptr_);
00104         return timeb2seconds(&timeb_ptr_);
00105 #else
00106         // Might overrun every month...
00107         SYSTEMTIME s;
00108         GetSystemTime(&s);
00109         return 0.001*s.wMilliseconds + s.wSecond + 60.0*s.wMinute
00110             + 3600.0*s.wHour + 3600.0*24.0*s.wDay;
00111 #endif
00112 #else
00113 #ifdef __GNUC__
00114         timeval t;
00115         gettimeofday(&t,0);
00116         return t.tv_sec + 1e-6*t.tv_usec;
00117 #else
00118         timespec time_spec_;
00119         clock_gettime(CLOCK_REALTIME, &time_spec_);
00120         return timespec2seconds(&time_spec_);
00121 #endif
00122 #endif
00123     }

void Go::getGnJoints ( const CurveLoop &  loop,
const std::vector< double > &  cont,
std::vector< std::vector< double > > &  gn_joints 
)

Partition a given CurveLoop into segments where each segment is at least G^n continuous (currently supporting up to G2 continuity).

Parameters:
loop the CurveLoop to analyze
cont the tolerance used for defining continuity. cont[0] is the tolerance used for defining the G^0 continuity, cont[1] is used for checking G^1 continuity, etc. The length of this vector also determines 'n' ('n' is equal to cont.size() - 1).
gn_joints a vector of a vector, reporting the result of the analysis. The outer vector contains one entry per curve in the CurveLoop. This entry contains the parameters for which that curve must be split in order to obtain G^n segments. NB: the start- and end parameters are NOT included here, as opposed to the result obtained from the other getGnJoints() function. The exception to this is when there is an G^n discontinuity at the transition between the curve 'i-1' and curve 'i' in the CurveLoop. To indicate this, the start parameter value for curve 'i' will be included in the corresponding entry in 'gn_joints'.

Definition at line 541 of file GeometryTools.C.

References ASSERT, getGnJoints(), and Go::CurveLoop::size().

00544 {
00545     int n = cont.size() - 1;
00546 
00547     int ki, kj;
00548     vector<vector<double> > poss_disc;
00549     for (ki = 0; ki < loop.size(); ++ki) {
00550         vector<double> gn_joints;
00551         getGnJoints(*(loop[ki]), cont, gn_joints);
00552         poss_disc.push_back(gn_joints);
00553     }
00554 
00555     // We then must check cont between consecutive segments.
00556     int pds = poss_disc.size();
00557     for (ki = 0; ki < pds; ++ki) {
00558         int fi = ki;
00559         int si = (fi + 1)%pds;
00560         vector<Point> from_left = loop[fi]->ParamCurve::point(poss_disc[fi].back(), n, false);
00561         vector<Point> from_right = loop[si]->ParamCurve::point(poss_disc[si].front(), n);
00562         ASSERT(int(from_left.size()) == n+1);
00563         for (kj = 0; kj < n+1; ++kj) {
00564             if (kj != 0) {
00565                 from_left[kj].normalize();
00566                 from_right[kj].normalize();
00567             }
00568             double dist = from_left[kj].dist(from_right[kj]);
00569             if (dist > cont[kj])
00570                 break;
00571         }
00572         poss_disc[fi].erase(poss_disc[fi].end() - 1);
00573         if (kj == n+1) {
00574             poss_disc[si].erase(poss_disc[si].begin());
00575         }
00576     }
00577 
00578     gn_joints = poss_disc;
00579 }

void Go::getGnJoints ( const ParamCurve &  curve,
const std::vector< double > &  cont,
std::vector< double > &  gn_joints 
)

Partition the given curve into segments where each segment is at least G^n continuous (currently supporting up to G2 continuity).

Parameters:
curve the curve to analyze
cont the tolerance used for defining continuity. cont[0] is the tolerance used for defining the G^0 continuity, cont[1] is used for checking G^1 continuity, etc. The length of this vector also determines 'n' ('n' is equal to cont.size() - 1).
Return values:
gn_joints returns the parameter values where one segment stops and the next begins. The vector will at least contain two values (the start and end parameter of the curve).

Definition at line 393 of file GeometryTools.C.

References Go::Point::angle_smallest(), ASSERT, Go::SplineCurve::basis(), Go::BsplineBasis::begin(), Class_CurveOnSurface, Class_SplineCurve, Go::SplineCurve::endparam(), Go::GeomObject::instanceType(), Go::Point::length(), M_PI, MESSAGE, Go::SplineCurve::order(), Go::CurveOnSurface::parameterCurve(), Go::CurveOnSurface::parPref(), Go::CurveOnSurface::spaceCurve(), Go::SplineCurve::startparam(), Go::SplineCurve::subCurve(), and THROW.

Referenced by getGnJoints().

00395 {
00396     int n = cont.size() - 1;
00397     // If input should be of higher order we should let kink be a corr vector.
00398     ASSERT(n >= 0 && n < 3); // Currently only implemented for pos, tangent and 2nd order geom cont.
00399 
00400     int ki;
00401     vector<double> poss_disc; // We store all possible discontinuities.
00402 
00403     // We begin by extracting all parameter values (knots) which 
00404     const SplineCurve* spline_cv;
00405     if (curve.instanceType() == Class_SplineCurve) {
00406         spline_cv = dynamic_cast<const SplineCurve*>(&curve);
00407     } else if (curve.instanceType() == Class_CurveOnSurface) {
00408         const CurveOnSurface* cv_on_sf = dynamic_cast<const CurveOnSurface*>(&curve);
00409         if (cv_on_sf->parPref()) {
00410             spline_cv = dynamic_cast<const SplineCurve*>((cv_on_sf->parameterCurve()).get());
00411         } else {
00412             spline_cv = dynamic_cast<const SplineCurve*>((cv_on_sf->spaceCurve()).get());
00413         }
00414     } else {
00415         THROW("Unexpected curve type!");
00416     }
00417     ASSERT(spline_cv != 0);
00418     int order = spline_cv->order();
00419     vector<double>::const_iterator iter = spline_cv->basis().begin() + order;
00420     int mult = order - n; // If mult equal knots, we split.
00421     while ((iter < spline_cv->basis().end()) && (iter[0] != spline_cv->endparam())) {
00422         if (iter[mult-1] == iter[0]) {
00423             poss_disc.push_back(iter[0]);
00424             iter += mult;
00425         } else {
00426             ++iter;
00427         }
00428     }
00429 
00430     // We loop through all possible discontinuities, checking the value.
00431     gn_joints.push_back(spline_cv->startparam());
00432     int pds = poss_disc.size();
00433     for (ki = 0; ki < pds; ++ki) {
00434         vector<Point> from_left = spline_cv->ParamCurve::point(poss_disc[ki], n, false);
00435         vector<Point> from_right = spline_cv->ParamCurve::point(poss_disc[ki], n);
00436         ASSERT(int(from_left.size()) == n+1);
00437         double dist = from_left[0].dist(from_right[0]);
00438         if (dist > cont[0]) // Testing for G0 cont
00439           {
00440             gn_joints.push_back(poss_disc[ki]);
00441             continue;
00442           }
00443 
00444         if (n > 0) { // Testing for G1 cont (direction of tangents).
00445             from_left[1].normalize();
00446             from_right[1].normalize();
00447             dist = from_left[1].dist(from_right[1]);
00448             if (dist > cont[1])
00449               {
00450                 gn_joints.push_back(poss_disc[ki]);
00451                 continue;
00452               }
00453 
00454             if (n > 1) { // Testing for G2 cont
00455                 // (We may not need to split into segments, but as the algorithm expects 
00456                 // it we do anyway.
00457                 // Would be smarter to save segments as we proceed, but since when was
00458                 // speed an issue ...)
00459                 shared_ptr<SplineCurve> left_seg
00460                     (spline_cv->subCurve(spline_cv->startparam(), poss_disc[ki]));
00461                 shared_ptr<SplineCurve> right_seg
00462                     (spline_cv->subCurve(poss_disc[ki], spline_cv->endparam()));
00463 
00464                 // Let b1, b2 & b3 be the last 3 ctrl pts on left seg, and c0, c1, c2 the
00465                 // first 3 ctrl pts
00466                 // on the right seg. Since we are guaranteed G0 cont we know that b0 = c0.
00467                 // Assuming they are coplanar, we define d as the intersection point
00468                 // between the lines given by (b1, b2) & (c1, c2) (i.e. passing through the pts).
00469                 // If all pts are colinear we let d = b0 (= c0).
00470                 // Defining
00471                 // r_- = ratio(b1, b2, d)
00472                 // r   = ratio(b2, b3, c1) (= ratio(b2, c0, c1)
00473                 // r_+ = ratio(d, c1, c2),
00474                 // where ratio(a, b, c) = |b-a|/|c-b| for the colinear pts a, b & c.
00475                 // By [Gerald Farin: Curves and Surfaces for CAGD, 12.2 (p.182)] G2 continuity is
00476                 // given by the formula
00477                 // r^2 = r_- * r_+.
00478                 // Using the sinus sentence we calculate the unknown |d - b2| & |c1 - d|.
00479                 int dim = left_seg->dimension();
00480                 Point b1(left_seg->coefs_end() - 3*dim, left_seg->coefs_end() - 2*dim);
00481                 Point b2(left_seg->coefs_end() - 2*dim, left_seg->coefs_end() - dim);
00482                 Point b3(left_seg->coefs_end() - dim, left_seg->coefs_end());
00483                 Point c0(right_seg->coefs_begin(), right_seg->coefs_begin() + dim);
00484                 Point c1(right_seg->coefs_begin() + dim, right_seg->coefs_begin() + 2*dim);
00485                 Point c2(right_seg->coefs_begin() + 2*dim, right_seg->coefs_begin() + 3*dim);
00486 
00487                 Point left_dir = b2 - b1;
00488                 Point mid_dir = c1 - b2;
00489                 Point right_dir = c1 - c2;
00490                 double ang_left, ang_right;
00491                 try {
00492                   ang_left = left_dir.angle_smallest(mid_dir);
00493                   ang_right = right_dir.angle_smallest(mid_dir);
00494                 }
00495                 catch ( ... ) {
00496                   MESSAGE("Failed computing angle between joints, skipping.");
00497                   continue;
00498                 }
00499                 double ang_mid = M_PI - ang_left - ang_right;
00500                 double sin_left = sin(ang_left);
00501                 double sin_right = sin(ang_right);
00502                 double sin_mid = sin(ang_mid);
00503                 double ratio_left = left_dir.length()*sin_mid/(mid_dir.length()*sin_right);
00504                 double ratio_mid = b2.dist(b3)/c0.dist(c1);
00505                 double ratio_right = mid_dir.length()*sin_left/(right_dir.length()*sin_mid);
00506 
00507                 double error = ratio_mid*ratio_mid - ratio_left*ratio_right;
00508                 if (error > cont[2]) // @@sbr Not sure what estimate to apply.
00509                   {
00510                     gn_joints.push_back(poss_disc[ki]);
00511                     continue;
00512                   }
00513             }
00514         }
00515         // Since we got here all tests passed! This is NOT a segment
00516         // gn_joints.push_back(poss_disc[ki]);
00517     }
00518     gn_joints.push_back(spline_cv->endparam());
00519 
00520     // We run through gn_joints checking length of segments.
00521     if (gn_joints.size() > 2) {
00522         for (ki = 0; ki < int(gn_joints.size()) - 1; ++ki) {
00523             double segment_length =
00524                 curve.ParamCurve::estimatedCurveLength(gn_joints[ki], gn_joints[ki+1], 1000);
00525             if (segment_length < cont[0]) {
00526                 if (ki == 0) {
00527                     gn_joints.erase(gn_joints.begin() + ki + 1);
00528                 } else {
00529                     gn_joints.erase(gn_joints.begin() + ki);
00530                 }
00531                 --ki;
00532             }
00533             if (gn_joints.size() == 2) {
00534                 break;
00535             }
00536         }
00537     }
00538 }

void Go::getHermiteData ( const std::vector< Point > &  der1,
const std::vector< Point > &  der2,
double &  parint,
double &  len1,
double &  len2 
)

Given position, first and second derivative in both ends of an Hermite segment, compute parameter interval and tangent lengths in order to stay close to a circular segment.

Definition at line 146 of file CurvatureUtils.C.

References curvatureRadius(), ltol, and tanLenFromRadius().

00153 {
00154   // First compute unit tangent, curvature and curvature radius
00155   vector<Point> unitder1, unitder2;
00156   double crad1, crad2;
00157   crad1 = curvatureRadius(der1, unitder1);
00158   crad2 = curvatureRadius(der2, unitder2);
00159   
00160   // Compute the angle between the unit tangents
00161   double angle = unitder1[1].angle(unitder2[1]);
00162   angle = fabs(angle);
00163 
00164   // Compute distance between endpoints
00165   parint = der1[0].dist(der2[0]);
00166 
00167   // Compute tangent lengths
00168   if (angle < ltol || crad1 < 0.0)
00169     len1 = parint/3.0;
00170   else
00171     len1 = tanLenFromRadius(crad1, angle);
00172 
00173   if (angle < ltol || crad2 < 0.0)
00174     len2 = parint/3.0;
00175   else
00176     len2 = tanLenFromRadius(crad2, angle);
00177 
00178   // Make sure that the tangent does not explode due to numeric errors,
00179   // and make a controlled tangent when the radius is zero or almost zero
00180   double max_dist;
00181   if (angle < 0.1)              
00182     max_dist = (double)0.35*parint;
00183   else if (angle < 0.35)        
00184     max_dist = (double)0.40*parint;
00185   else if (angle < 0.75)        
00186     max_dist = (double)0.50*parint;
00187   else                  
00188     max_dist = (double)0.70*parint;
00189 
00190   if ( len1 > max_dist) 
00191     len1 = max_dist;
00192   if ( len2 > max_dist) 
00193     len2 = max_dist;
00194 
00195 }

double Go::getKnotAtLargestInterval ( const BsplineBasis &  basis  ) 

Definition at line 1183 of file GeometryTools.C.

References getLargestParameterInterval(), and interval().

Referenced by insertKnotsEvenly().

01185 {
01186     const pair<double, double> interval = 
01187         getLargestParameterInterval(basis);
01188     double new_knot = 0.5*(interval.first+interval.second);
01189 
01190     return new_knot;
01191 }

pair< double, double > Go::getLargestParameterInterval ( const BsplineBasis &  basis  ) 

Definition at line 1196 of file GeometryTools.C.

References Go::BsplineBasis::begin(), and Go::BsplineBasis::end().

Referenced by getKnotAtLargestInterval().

01198 {
01199     double largest = 0.0;
01200     std::vector<double>::const_iterator index;
01201     for (std::vector<double>::const_iterator knot = basis.begin();
01202          knot != basis.end()-1; ++knot) {
01203         if ( (*(knot+1) - *knot) > largest) {
01204             largest = *(knot+1) - *knot;
01205             index = knot;
01206         }
01207     }
01208 
01209     return pair<double, double>(*index, *(index+1));
01210 }

std::vector< double > Go::getRotationMatrix ( const Point &  unit_axis_dir,
double  alpha 
)

Compute the elements of the matrix describing a rotation or a given number of radians around a given axis going through the origin.

Parameters:
unit_axis_dir this vector defines the axis of rotation. It must be of unit length, although this is not checked by the function.
alpha the angle of rotation, in radians
Returns:
a vector containing the matrix elements of the corresponding rotation matrix, stored row-wise.

Definition at line 1127 of file GeometryTools.C.

References ASSERT, and Go::Point::dimension().

Referenced by rotatePoint().

01129 {
01130     ASSERT(unit_rot_axis.dimension() == 3); // We're working in 3D space.
01131     std::vector<double> return_matrix(9);
01132     // Using the notation in 'Computational Gemoetry for Design and Manufacture'.
01133     double u1 = unit_rot_axis[0];
01134     double u2 = unit_rot_axis[1];
01135     double u3 = unit_rot_axis[2];
01136     double cos_a = cos(alpha);
01137     double sin_a = sin(alpha);
01138 
01139     return_matrix[0] = u1*u1 + cos_a*(1 - u1*u1);
01140     return_matrix[1] = u1*u2*(1 - cos_a) - u3*sin_a;
01141     return_matrix[2] = u3*u1*(1 - cos_a) + u2*sin_a;
01142     return_matrix[3] = u1*u2*(1 - cos_a) + u3*sin_a;
01143     return_matrix[4] = u2*u2 + cos_a*(1 - u2*u2);
01144     return_matrix[5] = u2*u3*(1 - cos_a) - u1*sin_a;
01145     return_matrix[6] = u3*u1*(1 - cos_a) - u2*sin_a;
01146     return_matrix[7] = u2*u3*(1 - cos_a) + u1*sin_a;
01147     return_matrix[8] = u3*u3 + cos_a*(1 - u3*u3);
01148 
01149     return return_matrix;
01150 }

bool Go::getSfAdjacencyInfo ( shared_ptr< ParamSurface >  sf1,
shared_ptr< CurveOnSurface >  sf_cv1,
shared_ptr< ParamSurface >  sf2,
shared_ptr< CurveOnSurface >  sf_cv2,
double  tol,
int &  bd1,
int &  bd2,
bool &  same_orient 
)

Definition at line 343 of file SurfaceTools.C.

00350   {
00351     // bd1, bd2:
00352     // 0 = umin, 1 = umax, 2 = vmin,  3 = vmax
00353     bool same_orient1, same_orient2;
00354     bd1 = sf_cv1->whichBoundary(tol, same_orient1);
00355     bd2 = sf_cv2->whichBoundary(tol, same_orient2);
00356     if (bd1 < 0 || bd2 < 0)
00357       return false;  // Adjacency not along boundary
00358 
00359     Point f1_p1 = sf_cv1->faceParameter(sf_cv1->startparam());
00360     Point f1_p2 = sf_cv1->faceParameter(sf_cv1->endparam());
00361     Point f2_p1 = sf_cv2->faceParameter(sf_cv2->startparam());
00362     Point f2_p2 = sf_cv2->faceParameter(sf_cv2->endparam());
00363     bool opposite = false;
00364     Point p1 = sf1->ParamSurface::point(f1_p1[0], f1_p1[1]);
00365     Point p2 = sf1->ParamSurface::point(f1_p2[0], f1_p2[1]);
00366     Point p3 = sf2->ParamSurface::point(f2_p1[0], f2_p1[1]);
00367     Point p4 = sf2->ParamSurface::point(f2_p2[0], f2_p2[1]);
00368     if ((p2 - p1)*(p4 -p3) < 0.0)
00369       opposite = true;
00370     if ((same_orient1 && !same_orient2) || (!same_orient1 && same_orient2))
00371       opposite = !opposite;
00372     same_orient = !opposite;
00373     return true;
00374    }

bool Go::getSfAdjacencyInfo ( boost::shared_ptr< ParamSurface >  sf1,
boost::shared_ptr< CurveOnSurface >  sf_cv1,
boost::shared_ptr< ParamSurface >  sf2,
boost::shared_ptr< CurveOnSurface >  sf_cv2,
double  tol,
int &  bd1,
int &  bd2,
bool &  same_orient 
)
SISLSurf * Go::GoSurf2SISL ( const SplineSurface &  sf,
bool  copy = true 
)

Convert a SplineSurface to a SISLSurface.

Parameters:
sf the SplineSurface to convert
copy if 'true', then the generated SISLSurf will have its own copy of the coefficient information contained in 'sf'. Otherwise, it will share this information with 'sf' (ie. it will only contain a pointer into the corresponding storage array in 'sf'.
Returns:
a newly generated SISLSurf that describes the same surface as 'sf'. The user assumes ownership and is responsible for cleaning up (which means calling the SISL function freeSurf(...) on the pointer when it should be destroyed).

Definition at line 91 of file SISLconversion.C.

References Go::SplineSurface::basis_u(), Go::SplineSurface::basis_v(), Go::BsplineBasis::begin(), Go::SplineSurface::coefs_begin(), Go::SplineSurface::dimension(), Go::SplineSurface::numCoefs_u(), Go::SplineSurface::numCoefs_v(), Go::SplineSurface::order_u(), Go::SplineSurface::order_v(), Go::SplineSurface::rational(), and Go::SplineSurface::rcoefs_begin().

Referenced by main(), and sisleval().

00092 {
00093     std::vector<double>::const_iterator coefsstart;
00094     int ikind;
00095     if (sf.rational()) {
00096         coefsstart = sf.rcoefs_begin();
00097         ikind = 2;
00098     } else {
00099         coefsstart = sf.coefs_begin();
00100         ikind = 1;
00101     }
00102     return newSurf(sf.numCoefs_u(), sf.numCoefs_v(),
00103                    sf.order_u(), sf.order_v(),
00104                    const_cast<double*>(&(*(sf.basis_u().begin()))),
00105                    const_cast<double*>(&(*(sf.basis_v().begin()))),
00106                    const_cast<double*>(&(*coefsstart)),
00107                    ikind, sf.dimension(), copy);
00108 }

template<typename ForwardIterator >
go_iterator_traits<ForwardIterator>::value_type Go::inner ( ForwardIterator  first,
ForwardIterator  last,
ForwardIterator  second 
) [inline]

inner product

Definition at line 162 of file Utils.h.

Referenced by Go::CoonsPatchGen::blendcoef(), Go::MatrixXD< double, Dim >::mult(), Go::MatrixXD< double, Dim >::operator*(), Go::ParamCurve::s1771_s9del(), Go::SplineSurface::s1773(), Go::SplineSurface::s1773_s9dir(), and Go::SolveBCG::solve().

00165         {
00166             typename go_iterator_traits<ForwardIterator>::value_type sum = 0;
00167             for (; first != last; ++first, ++second)
00168                 sum += (*first)*(*second);
00169             return sum;
00170         }

void Go::insertKnotsEvenly ( BsplineBasis &  basis,
double  tmin,
double  tmax,
int  num_knots,
double  knot_diff_tol = 1e-05 
)

Definition at line 1166 of file GeometryTools.C.

References getKnotAtLargestInterval(), Go::BsplineBasis::insertKnot(), and Go::BsplineBasis::subBasis().

01169 {
01170     BsplineBasis sub_basis = basis.subBasis(tmin, tmax, knot_diff_tol);
01171     vector<double> new_knots;
01172     for (int i=0; i<num_knots; ++i) {
01173         double new_knot = getKnotAtLargestInterval(sub_basis);
01174         sub_basis.insertKnot(new_knot);
01175         new_knots.push_back(new_knot);
01176     }
01177 
01178     basis.insertKnot(new_knots);
01179 }

void Go::insertKnotsEvenly ( BsplineBasis &  basis,
int  num_knots 
)

Definition at line 1155 of file GeometryTools.C.

References getKnotAtLargestInterval(), and Go::BsplineBasis::insertKnot().

01157 {
01158     for (int i=0; i<num_knots; ++i) {
01159         double new_knot = getKnotAtLargestInterval(basis);
01160         basis.insertKnot(new_knot);
01161     }
01162 }

void Go::insideParamDomain ( double &  delta,
double  acoef,
double  astart,
double  aend 
)

Adjust delta to satisfy:

\[ astart \leq acoef+delta \leq aend \]

Ported from the sisl function s1770_s9corr.

Definition at line 384 of file closestPtCurves.C.

Referenced by closestPtCurveSurf(), and extremalPtSurfSurf().

00387 {
00388   // Make sure that the corrected parameters still lies in the domain.
00389   //  astart <= acoef+delta <= aend
00390 
00391   if (acoef + delta < astart)
00392     delta = astart - acoef;
00393   else if (acoef + delta > aend)
00394     delta = aend - acoef;
00395 }

void Go::intersect2Dcurves ( const ParamCurve *  cv1,
const ParamCurve *  cv2,
double  epsge,
vector< pair< double, double > > &  intersections,
vector< int > &  pretopology,
vector< pair< pair< double, double >, pair< double, double > > > &  int_crvs 
)

Definition at line 65 of file intersect2Dcurves.C.

References ALWAYS_ERROR_IF, Class_SplineCurve, Curve2SISL(), Go::GeomObject::dimension(), Go::GeomObject::instanceType(), and MESSAGE_IF.

00075 {
00076 
00077   // First make sure that the curves are spline curves.
00078   ALWAYS_ERROR_IF(cv1->instanceType() != Class_SplineCurve ||
00079               cv2->instanceType() != Class_SplineCurve,
00080                   " Intersection between general parametric curves is not implemented.");
00081 
00082   MESSAGE_IF(cv1->dimension() != 2,
00083                 "Dimension different from 2, pretopology not reliable.");
00084 
00085   // Make sisl curves and call sisl.
00086   SISLCurve *pc1 = Curve2SISL(*(dynamic_cast<const SplineCurve*>(cv1)), false);
00087   SISLCurve *pc2 = Curve2SISL(*(dynamic_cast<const SplineCurve*>(cv2)), false);
00088 
00089   int kntrack = 0;
00090   int trackflag = 0;  // Do not make tracks.
00091   SISLTrack **track =0;
00092   int knpt=0, kncrv=0;
00093   double *par1=0, *par2=0;
00094   int *pretop = 0;
00095   SISLIntcurve **vcrv = 0;
00096   int stat = 0;
00097   sh1857(pc1, pc2, 0.0, epsge, trackflag, &kntrack, &track,
00098          &knpt, &par1, &par2, &pretop, &kncrv, &vcrv, &stat);
00099 
00100   ALWAYS_ERROR_IF(stat<0,"Error in intersection, code: " << stat);
00101 
00102 
00103   // Remember intersections points. 
00104   int ki;
00105   for (ki=0; ki<knpt; ki++)
00106     {
00107       intersections.push_back(std::make_pair(par1[ki],par2[ki]));
00108       pretopology.insert(pretopology.end(), pretop+4*ki, pretop+4*(ki+1));
00109     }
00110 
00111   // Remember intersection curves
00112   for (ki=0; ki<kncrv; ++ki)
00113     int_crvs.push_back(std::make_pair(std::make_pair(vcrv[ki]->epar1[0], vcrv[ki]->epar2[0]), 
00114                                       std::make_pair(vcrv[ki]->epar1[vcrv[ki]->ipoint-1],
00115                                                      vcrv[ki]->epar2[vcrv[ki]->ipoint-1])));
00116 
00117   if (kncrv > 0)
00118     freeIntcrvlist(vcrv, kncrv);
00119 
00120   if (par1 != 0) free(par1);
00121   if (par2 != 0) free(par2);
00122   if (pc1 != 0) freeCurve(pc1);
00123   if (pc2 != 0) freeCurve(pc2);
00124   if (pretop != 0) free(pretop);
00125 }

void Go::intersect2Dcurves ( const ParamCurve *  cv1,
const ParamCurve *  cv2,
double  epsge,
std::vector< std::pair< double, double > > &  intersections,
std::vector< int > &  pretopology,
std::vector< std::pair< std::pair< double, double >, std::pair< double, double > > > &  int_crvs 
)

Intersect two 2D spline curves.

Collect intersection parameters and pretopology information.

Parameters:
cv1 pointer to the first 2D curve
cv2 pointer to the second 2D curve
epsge geometrical tolerance
Return values:
intersections this vector will contain the parameter pairs of the found intersections (one vector entry per intersection. The two parameters in the pair<> correspond to the parameter value in 'cv1' and 'cv2' for a particular intersection.
pretopology vector containing a pretopology indicator for each detected intersection point. There is one entry per intersection point.

Referenced by Go::CurveBoundedDomain::findPcurveInsideSegments(), and Go::BoundedUtils::intersectWithSurface().

void Go::intersectCurvePoint ( const ParamCurve *  crv,
Point  pnt,
double  epsge,
vector< double > &  intersections,
vector< pair< double, double > > &  int_crvs 
)

Definition at line 26 of file intersect2Dcurves.C.

References ALWAYS_ERROR_IF, Go::Point::begin(), Class_SplineCurve, Curve2SISL(), Go::GeomObject::instanceType(), and Go::Point::size().

00034 {
00035   // First make sure that the curve is a spline curve
00036   ALWAYS_ERROR_IF(crv->instanceType() != Class_SplineCurve,
00037                   " Intersection involving general parametric curves is not implemented.");
00038 
00039   // Make sisl curve and call sisl.
00040   SISLCurve *pc = Curve2SISL(*(dynamic_cast<const SplineCurve*>(crv)), false);
00041 
00042   int knpt=0, kncrv=0;
00043   double *par=0;
00044   SISLIntcurve **vcrv = 0;
00045   int stat = 0;
00046   s1871(pc, pnt.begin(), pnt.size(), epsge, &knpt, &par, &kncrv, &vcrv, &stat);
00047   ALWAYS_ERROR_IF(stat<0,"Error in intersection, code: " << stat);
00048 
00049 
00050   // Remember intersections points. 
00051   if (knpt > 0)
00052     intersections.insert(intersections.end(), par, par+knpt);
00053 
00054   // Remember intersection curves
00055   for (int ki=0; ki<kncrv; ++ki)
00056     int_crvs.push_back(std::make_pair(vcrv[ki]->epar1[0], vcrv[ki]->epar1[vcrv[ki]->ipoint-1]));
00057 
00058   if (kncrv > 0)
00059     freeIntcrvlist(vcrv, kncrv);
00060 
00061   if (par != 0) free(par);
00062   if (pc) freeCurve(pc);
00063 }

void Go::intersectCurvePoint ( const ParamCurve *  crv,
Point  pnt,
double  epsge,
std::vector< double > &  intersections,
std::vector< std::pair< double, double > > &  int_crvs 
)

Referenced by Go::CurveBoundedDomain::isOnBoundary().

void Go::intersectcurves ( SplineCurve *  cv1,
SplineCurve *  cv2,
double  epsge,
std::vector< std::pair< double, double > > &  intersections 
)

Intersect two spline curves.

Collect intersection parameters.

Parameters:
cv1 pointer to the first spline curve
cv2 pointer to the second spline curve
epsge geometrical tolerance
Return values:
intersections this vector will contain the parameter pairs of the found intersections (one vector entry per intersection. The two parameters in the pair<> correspond to the parameter value in 'cv1' and 'cv2' for a particular intersection.

Definition at line 19 of file intersectcurves.C.

References ALWAYS_ERROR_IF, and Curve2SISL().

00026 {
00027 
00028   // Make sisl curves and call sisl.
00029   SISLCurve *pc1 = Curve2SISL(*cv1, false);
00030   SISLCurve *pc2 = Curve2SISL(*cv2, false);
00031 
00032   int kntrack = 0;
00033   int trackflag = 0;  // Do not make tracks.
00034   SISLTrack **track =0;
00035   int knpt=0, kncrv=0;
00036   double *par1=0, *par2=0;
00037   int *pretop = 0;
00038   SISLIntcurve **intcrvs = 0;
00039   int stat = 0;
00040   sh1857(pc1, pc2, 0.0, epsge, trackflag, &kntrack, &track,
00041          &knpt, &par1, &par2, &pretop, &kncrv, &intcrvs, &stat);
00042 
00043   ALWAYS_ERROR_IF(stat<0,"Error in intersection, code: " << stat);
00044 
00045 
00046   // Remember intersections points. The intersection curves are
00047   // skipped.
00048   int ki;
00049   for (ki=0; ki<knpt; ki++)
00050     {
00051       intersections.push_back(std::make_pair(par1[ki],par2[ki]));
00052     }
00053 
00054   if (kncrv > 0)
00055     freeIntcrvlist(intcrvs, kncrv);
00056 
00057   if (par1 != 0) free(par1);
00058   if (par2 != 0) free(par2);
00059   if (pc1 != 0) freeCurve(pc1);
00060   if (pc2 != 0) freeCurve(pc2);
00061 }

int Go::is_inside ( const std::vector< Vector3D > &  trim_curve_p,
const std::vector< int > &  contour,
const double  u,
const double  v 
)

Definition at line 1065 of file 2dpoly_for_s2m.C.

References DBG_FLAG, and point_inside_contour().

Referenced by make_trimmed_mesh(), and trim_a_triangle().

01072   {
01073 #ifndef DBG
01074     // const bool dbg=false; // This way, all tests on 'dbg' is removed compile-time when DBG is not defined.
01075 #endif
01076 
01077 
01078     // test 100212
01079 
01080     if (contour.size()==0)
01081       return 0;
01082   
01083 #if 0 // 021012
01084 
01085     const double * const vertices = &trim_curve_p[0][0];
01086 
01087   
01088     vector<int> cont;
01089     cont.push_back(contour[0]);
01090     for (int i=0; i<int(contour.size()); i++)
01091       {
01092         const int j = (i+1)%int(contour.size());
01093         const double &a=vertices[contour[i]], &b=vertices[contour[i]+1];
01094         const double &c=vertices[contour[j]], &d=vertices[contour[j]+1];
01095         const double len_squared = (a-c)*(a-c) + (b-d)*(b-d);
01096         const double eps = 1e-8;
01097         if ( len_squared < eps*eps )
01098           {
01099             if (dbg)
01100               printf("is_inside preprocessing: HUH?! Segment with length %e, duplicate corner! REMOVING IT\n",
01101                      sqrt(len_squared));
01102           }
01103         else
01104           cont.push_back(contour[i]);
01105       }
01106 
01107 
01108     for (int s=2; s<=10; s++)
01109       {
01110         vector<int> cont2;
01111         cont2.push_back(cont[0]);
01112         for (int i=0; i<int(cont.size()); i++)
01113           {
01114             const int j = (i+1)%int(cont.size());
01115             const double &a=vertices[cont[i]], &b=vertices[cont[i]+1];
01116             const double &c=vertices[cont[j]], &d=vertices[cont[j]+1];
01117             const double len_squared = (a-c)*(a-c) + (b-d)*(b-d);
01118             const double eps = 1e-8;
01119             if ( len_squared < eps*eps )
01120               {
01121                 if (dbg)
01122                   printf("is_inside prep STAGE %d : HUH?! Segment %d with length %e, duplicate corner! REMOVING IT\n",
01123                          s, i, sqrt(len_squared));
01124               }
01125             else
01126               cont2.push_back(cont[i]);
01127           }
01128         cont=cont2;
01129       }
01130   
01131     return point_inside_contour(u, v, &trim_curve_p[0][0], cont, dbg);
01132 #endif
01133   
01134 
01135 
01136 
01137     // 100212: The const_cast not needed any more.
01138     //return point_inside_contour(u, v, &trim_curve_p[0][0], const_cast<vector<int> &>(contour), dbg);
01139     return point_inside_contour(u, v, &trim_curve_p[0][0], contour DBG_FLAG);
01140   }

int Go::is_on_contour ( const std::vector< Vector3D > &  trim_curve_p,
const std::vector< int > &  contour,
const double  u,
const double  v 
)

Definition at line 1170 of file 2dpoly_for_s2m.C.

References DBG_FLAG, and point_on_contour().

Referenced by make_trimmed_mesh(), split_quad(), and trim_a_triangle().

01175   {
01176     return point_on_contour(u, v, &trim_curve_p[0][0], const_cast<vector<int> &>(contour) DBG_FLAG);
01177   }

bool Go::is_on_corner ( const std::vector< Vector3D > &  trim_curve_p,
const std::vector< int > &  contour,
const double  u,
const double  v 
)

Definition at line 1154 of file 2dpoly_for_s2m.C.

References point_on_contour_corner().

01155   {
01156     return point_on_contour_corner(u, v, &trim_curve_p[0][0], const_cast<vector<int> &>(contour));
01157   }

bool Go::isCoincident ( const ParamCurve &  cv1,
const ParamCurve &  cv2,
double  epsge 
)

Returns true if the curves are approximately coincident (that is, they have the same parameter space and overlap in space).

The function uses a (possibly high) number of closest point calculations to check for spatial coincidence.

Parameters:
cv1 the first curve to check for coincidence
cv2 the second curve to check for coincidence
epsge the tolerance for specifying what we mean by approximately coincident
Returns:
'true' if the curves are found to be approximately coincident, 'false' otherwise.

Definition at line 934 of file GeometryTools.C.

References Go::ParamCurve::closestPoint(), Go::Point::dist(), Go::ParamCurve::endparam(), Go::ParamCurve::estimatedCurveLength(), Go::ParamCurve::point(), and Go::ParamCurve::startparam().

00936 {
00937   // Check endpoints
00938   double ta1 = cv1.startparam();
00939   double tb1 = cv1.endparam();
00940   double ta2 = cv2.startparam();
00941   double tb2 = cv2.endparam();
00942 
00943   Point pnt1 = cv1.point(ta1); 
00944   Point pnt2 = cv1.point(tb1);
00945   Point pnt3 = cv2.point(ta2);
00946   Point pnt4 = cv2.point(tb2);
00947   
00948   if (std::min(pnt1.dist(pnt3), pnt1.dist(pnt4)) > epsge ||
00949       std::min(pnt2.dist(pnt3), pnt2.dist(pnt4)) > epsge)
00950     return false;
00951 
00952   // Endpoints matching. Check the inner.
00953   bool same = (pnt1.dist(pnt3) < pnt1.dist(pnt4));
00954 
00955   double length = cv1.estimatedCurveLength();
00956   int nmb_test = std::min(500, (int)(length/epsge));
00957   double del = (tb1 - ta1)/(int)(nmb_test + 1);
00958   double del2 = (tb2 - ta2)/(int)(nmb_test + 1);
00959   double tpar, tpar2, seed, dist;
00960   int ki;
00961   for (ki=0, tpar=ta1+del; ki<nmb_test; ki++, tpar+=del)
00962     {
00963       seed = (same) ? ta2 + (ki+1)*del2 : tb2 - (ki+1)*del2;
00964       pnt1 = cv1.point(tpar);
00965       cv2.closestPoint(pnt1, ta2, tb2, tpar2, pnt2, dist, &seed);
00966       if (dist > epsge)
00967         return false;
00968     }
00969 
00970   return true;
00971 }

void Go::iterateCornerPos ( Point &  vertex,
vector< pair< shared_ptr< ParamSurface >, Point > >  sfs,
double  tol 
)

Definition at line 217 of file SurfaceTools.C.

References Go::Point::dist(), and Go::Point::setValue().

00221 {
00222   Point prev, curr;
00223   curr = vertex;
00224   double wgt_fac = 10.0;
00225   double wgt = 1.0;
00226   double wgt_sum;
00227   int max_iter = 10;
00228   int kr = 0;
00229 
00230   // Iterate until the vertex point doesn't move
00231   do
00232     {
00233       prev = curr;
00234       curr.setValue(0.0);
00235       wgt_sum = 0.0;
00236 
00237       for (size_t ki=0; ki<sfs.size(); ++ki)
00238         {
00239           double seed[2];
00240           double clo_u, clo_v, clo_dist;
00241           Point clo_pt;
00242           seed[0] = sfs[ki].second[0];
00243           seed[1] = sfs[ki].second[1];
00244           sfs[ki].first->closestPoint(prev, clo_u, clo_v, clo_pt,
00245                                       clo_dist, 0.001*tol, NULL, seed);
00246 
00247           // Check if the surface is elementary
00248           shared_ptr<ElementarySurface> elemsf = 
00249             shared_dynamic_cast<ElementarySurface, ParamSurface>(sfs[ki].first);
00250           double curr_wgt = (elemsf.get()) ? wgt*wgt_fac : wgt;
00251           curr += curr_wgt*clo_pt;
00252           wgt_sum += curr_wgt;
00253 
00254           sfs[ki].second = Point(clo_u, clo_v);
00255         }
00256       curr /= wgt_sum;
00257       kr++;
00258       if (kr > max_iter)
00259         break;
00260     }
00261   while (prev.dist(curr) > tol);
00262 
00263   vertex = curr;
00264 }

void Go::iterateCornerPos ( Point &  vertex,
std::vector< std::pair< boost::shared_ptr< ParamSurface >, Point > >  sfs,
double  tol 
)
boost::shared_ptr<SplineSurface> Go::joinPatches ( const vector< shared_ptr< SplineSurface > > &  patches,
const SplineSurface &  spline_space 
)

Definition at line 663 of file GeometryTools.C.

References Go::SplineSurface::appendSurface(), Go::SplineSurface::basis_u(), Go::SplineSurface::basis_v(), Go::SplineSurface::clone(), Go::SplineSurface::endparam_u(), Go::SplineSurface::endparam_v(), Go::BsplineBasis::knotIntervalFuzzy(), Go::BsplineBasis::knotMultiplicity(), Go::SplineSurface::makeBernsteinKnotsU(), Go::SplineSurface::makeBernsteinKnotsV(), Go::BsplineBasis::numCoefs(), and Go::BsplineBasis::order().

00666 {
00667     // As we want to know how many patches there exist in u- and v-direction we
00668     // insert knots into copy of input sf.
00669     SplineSurface cp_spline_sf = spline_space;
00670 
00671     cp_spline_sf.makeBernsteinKnotsU();
00672     cp_spline_sf.makeBernsteinKnotsV();
00673 
00674     const BsplineBasis& orig_basis_u = spline_space.basis_u();
00675     const BsplineBasis& orig_basis_v = spline_space.basis_v();
00676     const BsplineBasis& basis_u = cp_spline_sf.basis_u();
00677     const BsplineBasis& basis_v = cp_spline_sf.basis_v();
00678 
00679     // Assuming both input basises are represented with Bezier knots.
00680     // (i.e. all knots should have mult equal to degree).
00681     int num_u = basis_u.numCoefs();
00682     int num_v = basis_v.numCoefs();
00683     int order_u = basis_u.order();
00684     int order_v = basis_v.order();
00685     int numpat_u = num_u / order_u; //num_u + 1 - order_u
00686     int numpat_v = num_v / order_v;; //num_v + 1 - order_v;
00687 
00688     bool repar = false; // @@sbr Alternatively we could update input knots (spline_space) as we append.
00689     double fuzzy_tol = 1e-06;
00690     SplineSurface* total_sf;
00691     for (int ki = 0; ki < numpat_v; ++ki) {
00692         SplineSurface sf_u = *patches[ki*numpat_u];
00693         for (int kj = 1; kj <numpat_u; ++kj) {
00694             // @@sbr Perhaps make sure that we are not fooled by numerical noise?
00695             // suppose this could be done somewhat more efficient, but it'll do for now.
00696             double knot_u = sf_u.endparam_u();
00697             orig_basis_u.knotIntervalFuzzy(knot_u, fuzzy_tol);
00698             int mult_u = orig_basis_u.knotMultiplicity(knot_u);
00699             int cont = order_u - mult_u - 1;
00700             double dist;
00701             sf_u.appendSurface(patches[ki*numpat_u+kj].get(), 1, cont, dist, repar);
00702         }
00703 
00704         if (ki == 0) {
00705             total_sf = sf_u.clone();
00706         } else {
00707             double knot_v = total_sf->endparam_v();
00708             orig_basis_v.knotIntervalFuzzy(knot_v, fuzzy_tol);
00709             int mult_v = orig_basis_v.knotMultiplicity(knot_v);
00710             int cont = order_v - mult_v - 1;
00711             double dist;
00712             total_sf->appendSurface(&sf_u, 2, cont, dist, repar);
00713         }
00714     }
00715 
00716     return boost::shared_ptr<SplineSurface>(total_sf);
00717 }

boost::shared_ptr<SplineSurface> GO_API Go::joinPatches ( const std::vector< boost::shared_ptr< SplineSurface > > &  patches,
const SplineSurface &  spline_space 
)

Join patches with continuity according to input basis_u & basis_v.

The patches are assumed to be in Bezier form, and form a continuous set. There should be num_u x num_v patches, where num_u = numcoefs_u/order_u and num_v = numcoefs_v/order_v (as given by basis_u and basis_v).

Referenced by Go::SurfaceCreators::mult1DSurfaces().

template<typename SquareMatrix >
void Go::LUDecomp ( SquareMatrix &  mat,
int  num_rows,
int *  perm,
bool &  parity 
) [inline]

LU decomposition algorithm, based on Crout's algorithm.

Parameters:
mat The matrix to be decomposed. The actually used class must support the operation [][] and return 'double'.
num_rows Number of rows (which is also equal to the number of columns).
perm Should point to an n-sized array where the permutation is written.
parity Value upon function completion is 'true' if the number of row interchanges was pair. 'false' otherwise.

Definition at line 27 of file LUDecomp_implementation.h.

References sum().

Referenced by Go::SmoothCurve::equationSolve(), and LUsolveSystem().

00029 {
00030     parity = true; // as for now, number of row transpositions is 0, evidently
00031     const int num_cols = num_rows; // for clarity (should be optimized away by compiler...)
00032 
00033     // filling out perm with sequence 0, 1,...
00034     for (int k = 0; k < num_rows; k++)
00035         perm[k] = k;
00036 
00037     // determining scaling factor of each row
00038     std::vector<double> scaling(num_rows, 0);
00039     for (int i = 0; i < num_rows; ++i) {
00040         for (int j = 0; j < num_cols; ++j) {
00041             double temp = fabs(mat[i][j]);
00042             if (temp > scaling[i]) {
00043                 scaling[i] = temp; // scaling[i] is max. absolute elem on row i.
00044             }
00045         }
00046         if (scaling[i] == 0) {
00047             throw std::runtime_error("Unable to LU decompose matrix.  Null row detected.");
00048         } else {
00049             scaling[i] = double(1) / scaling[i];
00050         }
00051      }
00052 
00053     // executing Crout's algorithm
00054     for (int j = 0; j < num_cols; ++j) {
00055         // determining elements of UPPER matrix on this column
00056         for (int i = 0; i < j; ++i) {
00057             double sum = mat[i][j];
00058             for (int k = 0; k <= i-1; ++k) {
00059                 sum -= mat[i][k] * mat[k][j];
00060             }
00061             mat[i][j] = sum;
00062         }
00063 
00064         // compute rest of this column, before division by pivot
00065         double pivot_val = 0;
00066         int pivot_row = j;
00067         for (int i = j; i < num_rows; ++i) {
00068             double sum = mat[i][j];
00069             for (int k = 0; k <= j-1; ++k) {
00070                 sum -= mat[i][k] * mat[k][j];
00071             }
00072             mat[i][j] = sum;
00073             double temp = std::fabs(sum * scaling[i]);
00074             if (temp > pivot_val) {
00075                 pivot_val = temp;
00076                 pivot_row = i;
00077             }
00078         }
00079 
00080         if (mat[pivot_row][j] == 0) {
00081             throw std::runtime_error("Unable to LU decompose singular matrix.");
00082         }
00083 
00084         // permute rows to position pivot correctly
00085         if (pivot_row != j) {
00086             for (int k = 0; k < num_cols; ++k) {
00087                 std::swap(mat[pivot_row][k], mat[j][k]);
00088             }
00089             parity = !parity;
00090             std::swap(scaling[j], scaling[pivot_row]);
00091             std::swap(perm[j], perm[pivot_row]);
00092         }
00093         
00094         if (j < num_rows - 1) {
00095             // dividing LOWER matrix elements by pivot
00096             pivot_val = double(1) / mat[j][j]; // inverse value, without scaling
00097             for (int i = j+1; i < num_rows; ++i) {
00098                 mat[i][j] *= pivot_val; 
00099             }
00100         }
00101     }
00102 }

template<typename SquareMatrix , typename T >
void Go::LUsolveSystem ( SquareMatrix &  A,
int  num_unknowns,
T *  vec 
) [inline]

Solve the system Ax = b for x, using LU decomposition of the matrix A.

Upon successful completion of the function, the matrix A will be LU decomposed, and the solution x will be computed and stored at the memory area pointed to by the last argument.

Parameters:
A The system matrix A. The actually used class must support the operation [][] and return 'double'.
num_unknowns Number of unknowns in the equation system.
vec At function invocation, 'vec' should point to an array of T, containing the vector 'b'. On successful completion of the function, this array will contain the solution for x.

Definition at line 107 of file LUDecomp_implementation.h.

References backwardSubstitution(), forwardSubstitution(), and LUDecomp().

Referenced by Go::SplineInterpolator::interpolate(), and Go::SplineApproximator::interpolate().

00109 {
00110     bool parity;
00111     std::vector<int> permutation(num_unknowns);
00112     
00113     LUDecomp(A, num_unknowns, &permutation[0], parity);
00114 
00115     // permuting b
00116     std::vector<T> vec_old(vec, vec + num_unknowns);
00117     for (int i = 0; i < num_unknowns; ++i) {
00118         swap(vec[i], vec_old[permutation[i]]);
00119     }
00120     forwardSubstitution(A, vec, num_unknowns);
00121     backwardSubstitution(A, vec, num_unknowns);
00122 }

void Go::make_coef_array_from_rational_coefs ( const double *  rationals,
double *  coefs,
int  num_coefs,
int  dim 
)

convert an array of rational coefficients to an array of nonrational coefficients

Parameters:
rationals pointer to the array of rational coefficients
coefs pointer to the array where the nonrational coefficients are to be written
num_coefs total number of coefficients
dim dimension of coefficients (not counting the rational component).

Definition at line 262 of file Utils.C.

Referenced by Go::SplineSurface::updateCoefsFromRcoefs(), and Go::SplineCurve::updateCoefsFromRcoefs().

00267 {
00268     for (int i = 0; i < num_coefs; ++i) {
00269         double w = from[dim];
00270         if (w != 1.0) {
00271             for (int dd = 0; dd < dim; ++dd) {
00272                 to[dd] = from[dd]/w;
00273             }
00274         } else {
00275             for (int dd = 0; dd < dim; ++dd) {
00276                 to[dd] = from[dd];
00277             }
00278         }
00279         from += dim+1;
00280         to += dim;
00281     }
00282     
00283 }

void Go::make_trimmed_mesh ( boost::shared_ptr< SplineSurface srf,
std::vector< boost::shared_ptr< SplineCurve > > &  crv_set,
std::vector< Vector3D > &  vert,
std::vector< Vector2D > &  vert_p,
std::vector< int > &  bd,
std::vector< Vector3D > &  norm,
std::vector< int > &  mesh,
std::vector< Vector3D > &  trim_curve,
std::vector< Vector3D > &  trim_curve_p,
const int  dn,
const int  dm,
double  bd_res_ratio 
)

Definition at line 1671 of file spline2mesh.C.

References add_triangle(), ASSERT2, Go::Point::begin(), construct_corner_lists(), Go::Point::cross(), is_inside(), is_on_contour(), Go::Point::length(), M_PI, MESSAGE, Go::Array< T, Dim >::normalize(), normalize(), pt_inside_tri(), s2m_with_boundary, Go::Point::setValue(), split_quad(), THROW, and trim_a_triangle_soup().

Referenced by Go::ParametricSurfaceTesselator::tesselate().

01677                                                                                    : Not in use
01678                          vector<int> &mesh,
01679                          vector< Vector3D > &trim_curve_0,      // Output
01680                          vector< Vector3D > &trim_curve_p_0,    // Output
01681                          const int dn,                          // Initially dn+1 nodes in the u-direction
01682                          const int dm,                          // Initially dm+1 nodes in the v-direction
01683                          //vector< Vector3D > &extra_v,         // 090130: Not in use
01684                          double bd_res_ratio)
01685   {
01686     const double duplicate_tolerance = 1e-8; // 100210: Absolute number. Was 1e-12.
01687 
01688     vert.resize((dn+1)*(dm+1));
01689     vert_p.resize((dn+1)*(dm+1));
01690     bd.resize((dn+1)*(dm+1));
01691     norm.resize((dn+1)*(dm+1));
01692     mesh.resize(0);
01693 
01694     const double u0=srf->startparam_u();
01695     const double u1=srf->endparam_u();
01696     const double v0=srf->startparam_v();
01697     const double v1=srf->endparam_v();
01698     int i, j;
01699     const double ustep = (u1 - u0)/(dn-1);
01700     const double vstep = (v1 - v0)/(dm-1);
01701   
01702     //--------------------------------------------------------------------------------------------------------------
01703     //
01704     // Discretizing the trim curve...
01705     // 040621: We use the 'trim_curve_p' to store parameter pairs with z=0.0 in the form of triples for the
01706     //         points in 'trim_curve'.
01707     // 081208: Now discretizing a set of curves.
01708     //
01709     //--------------------------------------------------------------------------------------------------------------
01710 
01711     vector< vector<Vector3D> > trim_curve_all(crv_set.size()), trim_curve_p_all(crv_set.size());
01712     for (int c=0; c<int(crv_set.size()); c++)
01713       {
01714         vector<Vector3D> &trim_curve   = trim_curve_all[c];
01715         vector<Vector3D> &trim_curve_p = trim_curve_p_all[c];
01716 
01717         boost::shared_ptr<SplineCurve> crv = crv_set[c];
01718 
01719         vector<double> corner_pars;
01720         int kk = crv->order();
01721         int kn = crv->numCoefs();
01722         std::vector<double>::iterator st = crv->knotsBegin();
01723         int kstat = 0;
01724         corner_pars.push_back(st[kk-1]);
01725         int knot_ind = kk;
01726         while (knot_ind < kn)
01727           {
01728             int knot_mult = 1;
01729             while (st[knot_ind] == st[knot_ind+knot_mult])
01730               ++knot_mult;
01731             if (kstat < 0)
01732               {
01733                 THROW("Unexpected incident.");
01734               }
01735             if (knot_mult > kk - 2) // A kink
01736               corner_pars.push_back(st[knot_ind]);
01737           
01738             knot_ind += knot_mult;
01739           }
01740       
01741         corner_pars.push_back(st[kn]);
01742       
01743          int n2 = 200/(corner_pars.size() - 1); //200; //std::max(200, 4*n); @@sbr Should be const.
01744 
01745         // 100212: For debugging/testing:
01746         // int n2 = 30/(corner_pars.size() - 1); //200; //std::max(200, 4*n); @@sbr Should be const.
01747 
01748         for (i = 0; i < int(corner_pars.size()) - 1; ++i)
01749           {
01750             double t0=corner_pars[i];
01751             double t1=corner_pars[i+1];
01752             double tstep = (t1 - t0)/(n2-1);
01753             //   for (i=0; i<n2; i++)
01754             double t = t0;
01755             double ref_step = tstep;
01756           
01757             while (t <= t1)
01758               {
01759                 //       double t=i/double(n2); // Assuming the curve is closed, so we don't
01760                 // need t==1.0...
01761                 //       t = ( crv->et[crv->ik-1] * (1.0-t) + 
01762                 //          crv->et[crv->in]   * t          );
01763               
01764                 Point result; 
01765                 Point result2;
01766                 crv->point(result, t);
01767               
01768                 if ((bd_res_ratio > 0.0) && (trim_curve_p.size() > 0) &&
01769                     ((fabs(trim_curve_p[trim_curve_p.size()-1][0] - result[0]) > bd_res_ratio*ustep) ||
01770                      (fabs(trim_curve_p[trim_curve_p.size()-1][1] - result[1]) > bd_res_ratio*vstep)))
01771                   {
01772                     t -= ref_step; // Return to t of last approved parameter pt.
01773                     ref_step *= 0.5;
01774                     t += ref_step;
01775                   }
01776                 else
01777                   // 090219: We only allow a point to be added if it is distinctly different from the last one
01778                   //         added!
01779                   {
01780 //                if ( (trim_curve_p.size()==0) ||
01781 //                     ( ((result[0]-trim_curve_p[trim_curve_p.size()-1][0])*
01782 //                        (result[1]-trim_curve_p[trim_curve_p.size()-1][1]) ) > 1e-14*1e-14 ) )
01783                     {
01784                       trim_curve_p.push_back(Vector3D(result[0], result[1], 0.0));
01785 //                    printf("added %g %g\n", result[0], result[1]);
01786                       srf->point(result2, result[0], result[1]);
01787                       trim_curve.push_back(Vector3D(result2.begin()));
01788                     }
01789                     if (t == t1)
01790                       break;
01791                     t += tstep;
01792                     if (t > t1) {
01793                       tstep = t1 - (t - tstep);
01794                       t = t1;
01795                     }
01796                     ref_step = tstep;
01797                   }
01798 //            printf("==================== t=%g\n", t);
01799               }
01800           }
01801       } // closing of loop over the curves
01802 
01803 
01804 
01805 #ifdef DBG
01806     // 100222: Just to separate different runs from one another...
01807     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
01808     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
01809     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
01810 #endif
01811 
01812   
01813 
01814 
01815 #ifdef DBG
01816     puts("====================================================================================================");
01817     printf("Weeding out duplicates from contours, tolerance=%e\n", duplicate_tolerance);
01818 #endif
01819     
01820     //--------------------------------------------------------------------------------------------------------------
01821     //
01822     // 090220: Weeding out duplicates. Note that we want the duplicates taken out for the lists used for the
01823     //         insideness-testing routines, but we want them in for the corner construction! Hence... making two
01824     //         sets of lists...
01825     // 100212: There was a bug here, when more than two points were equal, duplicates would survive.
01826     //
01827     //--------------------------------------------------------------------------------------------------------------
01828 
01829     vector< vector<Vector3D> > trim_curve_all_orig=trim_curve_all, trim_curve_p_all_orig=trim_curve_p_all;
01830 
01831     for (int c=0; c<int(crv_set.size()); c++)
01832       {
01833         // printf("Length before: %d %d\n", int(trim_curve_all[c].size()), int(trim_curve_p_all[c].size()));
01834 
01835         ASSERT2(trim_curve_all[c].size()>0, printf("Should not be here with degenerate curve.\n"));
01836         ASSERT2(trim_curve_p_all[c].size()>0, printf("Should not be here with degenerate curve.\n"));
01837 
01838         vector<Vector3D> trim_curve, trim_curve_p;
01839         trim_curve.push_back(trim_curve_all[c][0]);
01840         trim_curve_p.push_back(trim_curve_p_all[c][0]);
01841         
01842         for (int i=1; i<int(trim_curve_all[c].size()); i++)
01843           {
01844             const double last_u = trim_curve_p[trim_curve.size()-1][0];
01845             const double last_v = trim_curve_p[trim_curve.size()-1][1];
01846             const double dist_squared = ( (trim_curve_p_all[c][i][0]-last_u) * (trim_curve_p_all[c][i][0]-last_u) + 
01847                                           (trim_curve_p_all[c][i][1]-last_v) * (trim_curve_p_all[c][i][1]-last_v)   );
01848             if ( dist_squared > duplicate_tolerance*duplicate_tolerance )
01849               {
01850                 // printf("%3d:%5d: prev point was (%f, %f), new is (%f, %f), dist=%e, pushing.\n",
01851                 // c, i, last_u, last_v, trim_curve_p_all[c][i][0], trim_curve_p_all[c][i][1], sqrt(dist_squared));
01852                 trim_curve.push_back(trim_curve_all[c][i]);
01853                 trim_curve_p.push_back(trim_curve_p_all[c][i]);
01854               }
01855             // else
01856             // printf("%3d:%5d: dist = %e, point skipped\n", c, i, sqrt(dist_squared));
01857           }
01858 
01859         // printf("Length after:  %d %d\n", int(trim_curve.size()), int(trim_curve_p.size()));
01860 
01861         // 100212: Must now handle the first point! It can still be coincident with the last one.
01862         const double last_u = trim_curve_p[trim_curve.size()-1][0];
01863         const double last_v = trim_curve_p[trim_curve.size()-1][1];
01864         const double dist_squared = ( (trim_curve_p[0][0]-last_u) * (trim_curve_p[0][0]-last_u) + 
01865                                       (trim_curve_p[0][1]-last_v) * (trim_curve_p[0][1]-last_v)   );
01866         if ( dist_squared <= duplicate_tolerance*duplicate_tolerance )
01867           {
01868             trim_curve.pop_back();
01869             trim_curve_p.pop_back();
01870           }
01871 
01872         // Finally, we replace the original curves with the new ones.
01873         trim_curve_p_all[c] = trim_curve_p;
01874         trim_curve_all[c] = trim_curve;
01875 
01876         // printf("Length after:  %d %d\n", int(trim_curve.size()), int(trim_curve_p.size()));
01877       }
01878 
01879 
01880 
01881   
01882     //--------------------------------------------------------------------------------------------------------------
01883     //
01884     // 100212: A check to make sure we have no duplicates.
01885     //
01886     //--------------------------------------------------------------------------------------------------------------
01887 
01888     {
01889       bool duplicates_found = false;
01890       for (int c=0; c<int(crv_set.size()); c++)
01891         {
01892           vector<Vector3D> &trim_curve   = trim_curve_all[c];
01893           vector<Vector3D> &trim_curve_p = trim_curve_p_all[c];
01894           
01895           for (int i=0; i<int(trim_curve.size()); i++)
01896             {
01897               const int im1 = (i-1+trim_curve.size())%trim_curve.size();
01898               const double dist_to_previous = 
01899                 sqrt( (trim_curve_p[i][0]-trim_curve_p[im1][0])*(trim_curve_p[i][0]-trim_curve_p[im1][0]) + 
01900                       (trim_curve_p[i][1]-trim_curve_p[im1][1])*(trim_curve_p[i][1]-trim_curve_p[im1][1])   );
01901 
01902               // printf("%2d:%5d: dist = %e\n", c, i, dist_to_previous);
01903               if ( dist_to_previous <= duplicate_tolerance )
01904                 {
01905 #ifdef DBG
01906                   printf("%2d:%5d: DUPLICATE POINT! dist_to_previous = %e\n", c, i, dist_to_previous);
01907 #endif
01908                   duplicates_found = true;
01909                 }
01910             }
01911         }
01912       if (duplicates_found)
01913         MESSAGE("\n\n  WARNING: Something is fishy. At this point all duplicates should have been eliminated.\n"
01914                 "  This may lead to a funny mesh...\n\n");
01915     }
01916     
01917     
01918     
01919 
01920     //--------------------------------------------------------------------------------------------------------------
01921     //
01922     // Setting up the structure for fast inside-testing, and the 'contour' cursor array.
01923     // 081208: Again, extending to a set of contours...
01924     // 100212: The "fast inside-testing" stuff is long gone.
01925     //
01926     //--------------------------------------------------------------------------------------------------------------
01927 
01928     vector< vector<int> > contour_all(crv_set.size());
01929     for (int c=0; c<int(crv_set.size()); c++)
01930       {
01931         vector<int> &contour = contour_all[c];
01932         const vector<Vector3D> &trim_curve_p = trim_curve_p_all[c];
01933       
01934         contour.resize(trim_curve_p.size());
01935         for (i=0; i<(int)trim_curve_p.size(); i++)
01936           contour[i]=3*i;
01937       }
01938   
01939 #ifdef DBG
01940     // Just printing out matlab-code for rendering of all contours.
01941     if (1)
01942       for (int c=0; c<int(crv_set.size()); c++)
01943         {
01944           const vector<int> &contour           = contour_all[c];
01945           const vector<Vector3D> &trim_curve_p = trim_curve_p_all[c];
01946 
01947           char *tmp=new char[1000];
01948           sprintf(tmp, "d%d.m", c);
01949           FILE *f=fopen(tmp, "w");
01950           for (int i=0; i<int(trim_curve_p.size())-1; i++)
01951             {
01952               const double &x0 = trim_curve_p[contour[i]/3  ][0], &y0=trim_curve_p[contour[i]/3  ][1];
01953               const double &x1 = trim_curve_p[contour[i]/3+1][0], &y1=trim_curve_p[contour[i]/3+1][1];
01954               fprintf(f, "line([%f; %f], [%f; %f], 'color', 'b', 'linewidth', 3);\n", x0, x1, y0, y1);
01955             }
01956           fclose(f);
01957         }
01958 #endif
01959 
01960 
01961   
01962     //--------------------------------------------------------------------------------------------------------------
01963     //
01964     // Cache'ing all 'is_inside' results...
01965     // 081208: Again, extending to a set of contours...
01966     //
01967     // 100210: It seems like a (harmless) "bug" that the 'vert-arrays are filled once for every curve.
01968     //
01969     //--------------------------------------------------------------------------------------------------------------
01970 
01971     vector< vector<int> > inside_all(crv_set.size());
01972     for (int c=0; c<int(crv_set.size()); c++)
01973       {
01974         const vector<int> &contour = contour_all[c];
01975         const vector<Vector3D> &trim_curve_p = trim_curve_p_all[c];
01976         vector<int> &inside = inside_all[c];
01977         inside = vector<int>((dn+1)*(dm+1));
01978         double uv[2], s;
01979         vector<Point> res(3);
01980         Point nrm;
01981 
01982         ASSERT2(srf->dimension()==3, printf("Huh?! dim=%d\n", srf->dimension()));
01983 
01984         for (i=0; i<=dm; i++)
01985           {
01986             double t=i/double(dm);
01987             uv[1]=v0*(1.0-t) + v1*t;
01988             for (j=0; j<=dn; j++)
01989               {
01990                 s=j/double(dn);
01991                 uv[0]=u0*(1.0-s) + u1*s;
01992               
01993                 inside[i*(dn+1)+j] = is_inside(trim_curve_p, contour, uv[0], uv[1]);
01994                 
01995                 // 090115:
01996                 if (s2m_with_boundary)
01997                   inside[i*(dn+1)+j] |= is_on_contour(trim_curve_p, contour, uv[0], uv[1]);
01998 
01999                 // 090203: Enable this to see the trimming curve inside the untrimmed surface, for debugging purposes.
02000                 // 100210: This does not work, or this enabling is not enough.
02001                 // inside[i*(dn+1)+j] = 1; // !!!
02002                 
02003                 srf->point(res, uv[0], uv[1], 1);
02004                 nrm = res[1].cross(res[2]);
02005 
02006                 // 100210: Why on earth is this done for every curve?!
02007                 vert[i*(dn+1)+j] = Vector3D(res[0].begin());
02008                 vert_p[i*(dn+1)+j] = Vector2D(uv);
02009 
02010                 bd[i*(dn+1)+j]= (i==0 || i==dm || j==0 || j==dn) ? 1 : 0;
02011                 if (nrm.length() < 1.0e-12)
02012                   nrm.setValue(0.0, 0.0, 1.0);
02013                 norm[i*(dn+1)+j] = Vector3D(nrm.begin());
02014                 norm[i*(dn+1)+j].normalize();
02015               }
02016           }
02017       }
02018 
02019 
02020 #ifdef DBG
02021     {
02022       FILE *f5=fopen("r1.m", "w"); // regular mesh
02023       fprintf(f5, "hold on\ngrid on\n");
02024       for (int i=0; i<dm; i++)
02025         for (int j=0; j<=dn; j++)
02026           fprintf(f5, "line([%f; %f], [%f; %f], 'color', 'k');\n", 
02027                   vert_p[i*(dn+1)+j][0], vert_p[(i+1)*(dn+1)+j][0],
02028                   vert_p[i*(dn+1)+j][1], vert_p[(i+1)*(dn+1)+j][1]);
02029       for (int i=0; i<=dm; i++)
02030         for (int j=0; j<dn; j++)
02031           fprintf(f5, "line([%f; %f], [%f; %f], 'color', 'k');\n", 
02032                   vert_p[i*(dn+1)+j][0], vert_p[i*(dn+1)+j+1][0],
02033                   vert_p[i*(dn+1)+j][1], vert_p[i*(dn+1)+j+1][1]);
02034       fprintf(f5, "hold off\n");
02035       fclose(f5);
02036     }
02037 #endif
02038 
02039 
02040   
02041     //--------------------------------------------------------------------------------------------------------------
02042     //
02043     // 090130: We want to preserve corner points on the contour. The idea: Identify all quads containing such
02044     //         corners, then treat these quads separately: Split in the first corner, producing four new
02045     //         triangles. These must then be processed further, until they contain no corner points. Then these
02046     //         triangles must still be processed the "old way".
02047     // 
02048     // 090203: Note that by checking that we do not make degenerate primitives, it does not become as important
02049     //         to check for duplicate corner points any more.
02050     //
02051     //--------------------------------------------------------------------------------------------------------------
02052 
02053 
02054     const double pt_edge_degen_limit=1e-6;      // 090203: Should really be relative to the extent of the
02055                                                 //         geometry.  Used to avoid constructing
02056                                                 //         almost-degenerate polygons. Applied in the
02057                                                 //         parameter domain.
02058 
02059 //     const double cosangle_limit=             // 090203: The angle must be greater than this for a "corner"
02060 //      cos(M_PI/180.0);
02061      const double cosangle_limit=               // 090203: The angle must be greater than this for a "corner"
02062        cos(M_PI/180.0*0.1);                     //         to be defined as a corner, i.e., for splitting to
02063                                                 //         be done.
02064 
02065     const double pt_mult_def=1e-14;             // 090203: In the parameter domain, two points closer than
02066                                                 //         this are identified.
02067   
02068     const double eps=1e-13;                       // 090203: Used for zero-tests for distances in the parameter domain.
02069 
02070     //const double tau=1e-12;                     // 090203: Used for zero-tests for distances in the geometric space.
02071 
02072     const double max_corner_dist=                       // 090218: When corners are this far away, they are used no matter what
02073       100.0*std::max((u1-u0)/dn, (v1-v0)/dm);           //         the angle is. Must be larger than 'min_corner_dist'.
02074 
02075     const double min_corner_dist=                       // 090219: When corners are this close, they are not used no
02076       0.5*std::min((u1-u0)/dn, (v1-v0)/dm);             //         matter what the angle is.
02077 
02078 
02079 
02080 
02081 
02082 #ifdef DBG
02083     puts("====================================================================================================");
02084     puts("Generating list of corners to force splitting in.");
02085 #endif
02086 
02087 
02088 
02089     // 090218: Each of these will have dim nxn. 
02090     vector<int> skip_quad;                              // Contains a 1 if quad is to be skipped, i.e., it is
02091                                                         // replaced by custom list of triangles, since it did
02092                                                         // contain corners or such.
02093 
02094     vector< vector<Vector3D> > quad_corner_trim_curve;  // The 3D corner point, fetched from the proper
02095                                                         // trimming curve. Is this really used afterward?
02096                                                         // Yes. Need it for updating 'vert'.
02097 
02098     vector< vector<Vector2D> > quad_corner_trim_curve_p;        // The 2D parameter corner point, constructed from a
02099     // 3D point by ignoring the third coordinate. Fetched
02100     // from the proper trimming curve. Not smart to call
02101     // it '...trim_curve...', should have been just
02102     // 'quad_corner_p' or something...
02103 
02104     int quad_corners=0;
02105     construct_corner_lists(srf, crv_set, vert, vert_p, norm, mesh,
02106                            trim_curve_all_orig, trim_curve_p_all_orig,
02107                            dn, dm, bd_res_ratio, eps, cosangle_limit, pt_edge_degen_limit, pt_mult_def, min_corner_dist,
02108                            max_corner_dist, skip_quad, quad_corner_trim_curve, quad_corner_trim_curve_p, quad_corners);
02109   
02110   
02111 
02112 
02113 
02114     //--------------------------------------------------------------------------------------------------------------
02115     //
02116     // 100210: Ok, in this stage, quads containing corners are split. They are initially split into four
02117     //         triangles, which may again be further split in the innermost loop. This is to take care of cases
02118     //         where quads contain more than just one "corner points".
02119     //
02120     //--------------------------------------------------------------------------------------------------------------
02121 
02122 #ifdef CORNER_SPLITTING
02123 
02124 #ifdef DBG
02125     puts("====================================================================================================");
02126     printf("\"Pre-splitting\" mesh, %d corners was found.\n", quad_corners);
02127 #endif
02128   
02129     //
02130     // 090206: We build structures like 'quad_corner' for needed data. The problem with the "merged list"
02131     //         approach is that information for each curve, like where it ends, must be preserved. This is
02132     //         because the curves are closed.
02133     //
02134 
02135     // Now splitting first quads, then triangles.
02136 
02137 #ifdef DBG
02138     printf("dn=%d, dm=%d\n", dn, dm);
02139 #endif
02140     for (int i=0; i<dn*dm; i++)
02141       {
02142         //       printf("i=%3d: corners: %d\n", i, int(quad_corner[i].size()));
02143         if (quad_corner_trim_curve_p[i].size()>0)
02144           {
02145             // First, split the quad.
02146           
02147             const int p=i/dn, q=i%dn;
02148           
02149             vert.push_back(quad_corner_trim_curve[i][0]);
02150             vert_p.push_back(quad_corner_trim_curve_p[i][0]);
02151             bd.push_back(1);
02152             // Unfortunately, we don't have any normals readily available. What we can do, is to just take the
02153             // average of the quad. What we *should* do, is to evaluate the surface...
02154             {
02155               Vector3D new_norm = norm[p*(dn+1)+q] + norm[p*(dn+1)+q+1] + norm[(p+1)*(dn+1)+q] + norm[(p+1)*(dn+1)+q+1];
02156               new_norm.normalize();
02157               norm.push_back(new_norm);
02158             }
02159           
02160             int first_new_triangle=mesh.size()/3;
02161           
02162             // printf("i=%d, p=%d, q=%d, ndx=%d: splitting this quad in %g, %g.\n", i, p, q, p*(n+1)+q,
02163             //    vert_p[vert_p.size()-1][0], vert_p[vert_p.size()-1][1]);
02164           
02165             add_triangle(vert_p, mesh, vert.size()-1, (p+1)*(dn+1)+q  ,  p   *(dn+1)+q  );
02166             add_triangle(vert_p, mesh, vert.size()-1, (p+1)*(dn+1)+q+1, (p+1)*(dn+1)+q  );
02167             add_triangle(vert_p, mesh, vert.size()-1,  p   *(dn+1)+q+1, (p+1)*(dn+1)+q+1);
02168             add_triangle(vert_p, mesh, vert.size()-1,  p   *(dn+1)+q  ,  p   *(dn+1)+q+1);
02169           
02170             // Now, if there are more corners, we have to go through the triangles. And we have to do this again
02171             // for each new corner, and apply the split-testing and eventual splitting to all newly generated
02172             // triangles also. We assume that only one triangle can contain a given corner, so when a corner is
02173             // used, it does not need to be tested for again.
02174           
02175             if (int(quad_corner_trim_curve_p[i].size())>1)
02176               {
02177               
02178                 //printf("  Corners in total: %d, continuing with triangle-splitting.\n", int(quad_corner[i].size()));
02179               
02180                 for (int j=1; j<int(quad_corner_trim_curve_p[i].size()); j++)
02181                   {
02182                     bool done_splitting=false;
02183                     // 100210: Seems to be enough to enable this to skip the triangle-splitting stage.
02184                     // done_splitting=true;
02185 
02186                     Vector2D &corner = quad_corner_trim_curve_p[i][j];
02187                     //printf("    j=%d, checking corner %f, %f.\n", j, corner[0], corner[1]);
02188                   
02189                     // Ok, must now check, and possibly split triangles from 'first_new_triangle'.
02190                     // Note that we quit after we split, since we want to start over again asap.
02191                     for (int k=first_new_triangle; (k<int(mesh.size())/3) && (!done_splitting); k++)
02192                       {
02193                         //printf("      k=%d\n", k);
02194                         if (
02195                           pt_inside_tri(corner, vert_p[mesh[3*k]], vert_p[mesh[3*k+1]], vert_p[mesh[3*k+2]])
02196                           // && (pt_dist_from_tri_edge(corner, vert_p[mesh[3*k]], 
02197                           // vert_p[mesh[3*k+1]], vert_p[mesh[3*k+2]])
02198                           // > pt_edge_degen_limit)
02199                           // 090204: This test caused corners on the outer boundary not to trigger
02200                           //         splitting. Enabling this test is probably not a good idea, unless these
02201                           //         splitting causes other problems...
02202                           )
02203                           // Splitting the triangle.
02204                           {
02205                             //printf("      splitting, i=%d, j=%d, k=%d.\n", i, j, k);
02206                             vert.push_back(quad_corner_trim_curve[i][j]);
02207                             vert_p.push_back(corner);
02208                             bd.push_back(1);
02209                             const int a=mesh[3*k], b=mesh[3*k+1], c=mesh[3*k+2];
02210                             // Unfortunately, we don't have any normals readily available. What we can do, is
02211                             // to just take the average of the quad. What we should do, is to evaluate the
02212                             // surface...
02213                             {
02214                               Vector3D tmp = norm[a] + norm[b] + norm[c];
02215                               tmp.normalize();
02216                               norm.push_back(tmp);
02217                             }
02218                             mesh.erase(mesh.begin()+3*k, mesh.begin()+3*k+3);
02219                             add_triangle(vert_p, mesh, vert.size()-1, a, b);
02220                             add_triangle(vert_p, mesh, vert.size()-1, b, c);
02221                             add_triangle(vert_p, mesh, vert.size()-1, c, a);
02222                             done_splitting=true; // No need to check more triangles for a corner already used.
02223                             // 090204: Hmm... maybe not entirely true. If splitting was done on an edge, there may
02224                             //         be a triangle on the other side of that edge that also needs splitting...?!
02225                           }
02226                       }
02227                   }
02228               }
02229           }
02230       }
02231   
02232 #endif // end of #ifdef CORNER_SPLITTING
02233 
02234 #ifdef DBG
02235     vector<char> col(mesh.size()/3, 'g');
02236 #endif
02237   
02238 
02239 
02240 
02241 #ifdef SPLIT_NON_CORNER_QUADS
02242 
02243 #ifdef DBG
02244     puts("====================================================================================================");
02245     puts("Splitting remaining quads according to the first trimming curve.");
02246 #endif
02247 
02248     for (i=0; i<dm; i++)
02249       for (j=0; j<dn; j++)
02250         if (!skip_quad[i*dn+j])
02251           {
02252             // if ( (inside1[i*(n+1)+j]!=0) && (inside1[i*(n+1)+j]!=1) )
02253             // MESSAGE("noe er muffens, inside1 er hverken 0 eller 1?!");
02254             // if ( (inside[i*(n+1)+j]!=0) && (inside[i*(n+1)+j]!=1) )
02255             // MESSAGE("noe er muffens, inside er hverken 0 eller 1?!");
02256           
02257             int s=((inside_all[0][ i   *(dn+1)+j  ] << 3) +     // 8
02258                    (inside_all[0][ i   *(dn+1)+j+1] << 2) +     // 4
02259                    (inside_all[0][(i+1)*(dn+1)+j  ] << 1) +     // 2
02260                    (inside_all[0][(i+1)*(dn+1)+j+1] << 0));     // 1
02261 //        if (s!=0) // ((i==6) && (j==17))
02262 //          printf("s=%d, i=%d, j=%d\n", s, i, j);
02263           
02264 // 090216: keeping all to test if the missing triangle was made at all. Ok, it was made, but then wrongly split here.
02265 //s=15;
02266           
02267 // 090216: checking the lower right corner for debugging of problematic quad...
02268 //if ((fabs(vert_p[i*(n+1)+j+1][0]-.01)<1e-5) && (fabs(vert_p[i*(n+1)+j+1][1]-0.65)<1e-5))
02269 //  if ((i==12) && (j==3))
02270 //    printf("oooooooooooooooooooooooooooooooooooooooooooooooooo> s=%d\n", s), s=15;
02271           
02272             // 100223: Shit! Didn't realize this override was here... This means that all the quad-splitting
02273             //         code below is actually not used... Wonder when this was done...
02274             s=15;
02275             
02276             switch (s)
02277               {
02278               case 15:
02279                 // The whole rectangle is inside.
02280               {
02281                 add_triangle(vert_p, mesh, (i+1)*(dn+1)+j, i*(dn+1)+j  ,  i   *(dn+1)+j+1);
02282                 add_triangle(vert_p, mesh, (i+1)*(dn+1)+j, i*(dn+1)+j+1, (i+1)*(dn+1)+j+1);
02283               }
02284               break;
02285               //-------------------------------------------------------------------
02286               case 10:
02287                 // The two left (smaller u, smaller j) points are inside.
02288               {
02289                 //               first segm this col
02290                 vector<int> si0; si0.push_back(i  ); si0.push_back(i+1);
02291                 vector<int> sj0; sj0.push_back(j  ); sj0.push_back(j  );
02292                 vector<int> si1; si1.push_back(i  ); si1.push_back(i+1);
02293                 vector<int> sj1; sj1.push_back(j+1); sj1.push_back(j+1);
02294                 //
02295                 //   s0[1]   B    s1[1] (Husk: i+1 er her!)
02296                 //      o----x------o
02297                 //      |           |
02298                 //      |           |
02299                 //      |           |
02300                 //      o----x------o
02301                 //   s0[0]   A    s1[0] (Husk: i er her!)
02302                 //
02303                 split_quad(i+1, j,              // s0[1]
02304                            i, j,                // s0[0]
02305                            -1, -1,
02306                            // Then the two intersection points are
02307                            si0, sj0, si1,       // somewhere on s0[0]-s1[0] (A) and
02308                            sj1,         // somewhere on s0[1]-s1[1] (B).
02309                            srf, vert, vert_p, bd, norm, mesh, dn, dm,
02310                            trim_curve_p_all[0], contour_all[0], s2m_with_boundary);
02311               }
02312               break;
02313               //-------------------------------------------------------------------
02314               case 5:
02315                 // The two right (larger u, larger j) points are inside.
02316               {
02317                 //               first segm this col
02318                 vector<int> si0; si0.push_back(i+1); si0.push_back(i  );
02319                 vector<int> sj0; sj0.push_back(j  ); sj0.push_back(j  );
02320                 vector<int> si1; si1.push_back(i+1); si1.push_back(i  );
02321                 vector<int> sj1; sj1.push_back(j+1); sj1.push_back(j+1);
02322                 //
02323                 //   s0[0]   A    s1[0] (Husk: i+1 er her!)
02324                 //      o----x------o
02325                 //      |           |
02326                 //      |           |
02327                 //      |           |
02328                 //      o----x------o
02329                 //   s0[1]   B    s1[1] (Husk: i er her!)
02330                 //
02331                 split_quad(i, j+1,              // s1[1]
02332                            i+1, j+1,    // s1[0]
02333                            -1, -1,
02334                            // Then the two intersection points are
02335                            si0, sj0, si1,       // somewhere on s0[0]-s1[0] (A) and
02336                            sj1,         // somewhere on s0[1]-s1[1] (B).
02337                            srf, vert, vert_p, bd, norm, mesh, dn, dm,
02338                            trim_curve_p_all[0], contour_all[0], s2m_with_boundary);
02339               }
02340               break;
02341               //-------------------------------------------------------------------
02342               case 12:
02343                 // The two lower (smaller v, smaller i) points are inside.
02344               {
02345                 // (si0[0], sj0[0]) - (si1[0], sj1[0]) is the first segment, etc.
02346                 //               first segm this col
02347                 vector<int> si0; si0.push_back(i  ); si0.push_back(i+1);
02348                 vector<int> sj0; sj0.push_back(j+1); sj0.push_back(j  );
02349                 vector<int> si1; si1.push_back(i+1); si1.push_back(i  );
02350                 vector<int> sj1; sj1.push_back(j+1); sj1.push_back(j  );
02351                 //
02352                 //   s0[1]        s1[0] (Husk: i+1 er her!)
02353                 //      o-----------o
02354                 //      |           |
02355                 //    B x           x A
02356                 //      |           |
02357                 //      o-----------o
02358                 //   s1[1]        s0[0] (Husk: i er her!)
02359                 //
02360                 split_quad(i, j,                // s1[1]
02361                            i, j+1,              // s0[0]
02362                            -1, -1,
02363                            // Then the two intersection points are
02364                            si0, sj0, si1,       // somewhere on s0[0]-s1[0] (A) and
02365                            sj1,         // somewhere on s0[1]-s1[1] (B).
02366                            srf, vert, vert_p, bd, norm, mesh, dn, dm,
02367                            trim_curve_p_all[0], contour_all[0], s2m_with_boundary);
02368               }
02369               break;
02370               //-------------------------------------------------------------------
02371               case 1:
02372                 // The upper, right (larger i, larger j) point is inside.
02373               {
02374                 //               first segm this col
02375                 vector<int> si0; si0.push_back(i+1); si0.push_back(i+1);
02376                 vector<int> sj0; sj0.push_back(j+1); sj0.push_back(j+1);
02377                 vector<int> si1; si1.push_back(i+1); si1.push_back(i  );
02378                 vector<int> sj1; sj1.push_back(j  ); sj1.push_back(j+1);
02379                 //
02380                 //   s1[0]     A  s0[0]=s0[1]
02381                 //      o-------x---o
02382                 //      |        \  |
02383                 //      |         \ x B
02384                 //      |           |
02385                 //      o-----------o
02386                 //                s1[1]
02387                 //
02388                 split_quad(i+1, j+1,    // s0[0]
02389                            -1, -1, -1, -1,
02390                            // Then the two intersection points are
02391                            si0, sj0, si1,       // somewhere on s0[0]-s1[0] (A) and
02392                            sj1,         // somewhere on s0[1]-s1[1] (B).
02393                            srf, vert, vert_p, bd, norm, mesh, dn, dm,
02394                            trim_curve_p_all[0], contour_all[0], s2m_with_boundary);
02395               }
02396               break;
02397               //-------------------------------------------------------------------
02398               case 4:
02399                 // The lower, right (smaller i, larger j) point is inside.
02400               {
02401                 //               first segm this col
02402                 vector<int> si0; si0.push_back(i+1); si0.push_back(i  );
02403                 vector<int> sj0; sj0.push_back(j+1); sj0.push_back(j  );
02404                 vector<int> si1; si1.push_back(i  ); si1.push_back(i  );
02405                 vector<int> sj1; sj1.push_back(j+1); sj1.push_back(j+1);
02406                 split_quad(i, j+1,
02407                            -1, -1, -1, -1,
02408                            // Then the two intersection points are
02409                            si0, sj0, si1,       // somewhere on s0[0]-s1[0] (A) and
02410                            sj1,         // somewhere on s0[1]-s1[1] (B).
02411                            srf, vert, vert_p, bd, norm, mesh, dn, dm,
02412                            trim_curve_p_all[0], contour_all[0], s2m_with_boundary);
02413               }
02414               break;
02415               //-------------------------------------------------------------------
02416               case 8:
02417                 // The lower, left (smaller i, smaller j) point is inside.
02418               {
02419                 //               first segm this col
02420                 vector<int> si0; si0.push_back(i  ); si0.push_back(i  );
02421                 vector<int> sj0; sj0.push_back(j  ); sj0.push_back(j  );
02422                 vector<int> si1; si1.push_back(i  ); si1.push_back(i+1);
02423                 vector<int> sj1; sj1.push_back(j+1); sj1.push_back(j  );
02424                 split_quad(i, j,
02425                            -1, -1, -1, -1,
02426                            // Then the two intersection points are
02427                            si0, sj0, si1,       // somewhere on s0[0]-s1[0] (A) and
02428                            sj1,         // somewhere on s0[1]-s1[1] (B).
02429                            srf, vert, vert_p, bd, norm, mesh, dn, dm,
02430                            trim_curve_p_all[0], contour_all[0], s2m_with_boundary);
02431               }
02432               break;
02433               //-------------------------------------------------------------------
02434               case 2:
02435                 // The upper, left (larger i, smaller j) point is inside.
02436               {
02437                 //               first segm this col
02438                 vector<int> si0; si0.push_back(i+1); si0.push_back(i+1);
02439                 vector<int> sj0; sj0.push_back(j  ); sj0.push_back(j  );
02440                 vector<int> si1; si1.push_back(i  ); si1.push_back(i+1);
02441                 vector<int> sj1; sj1.push_back(j  ); sj1.push_back(j+1);
02442                 split_quad(i+1, j,
02443                            -1, -1, -1, -1,
02444                            // Then the two intersection points are
02445                            si0, sj0, si1,       // somewhere on s0[0]-s1[0] (A) and
02446                            sj1,         // somewhere on s0[1]-s1[1] (B).
02447                            srf, vert, vert_p, bd, norm, mesh, dn, dm,
02448                            trim_curve_p_all[0], contour_all[0], s2m_with_boundary);
02449               }
02450               break;
02451               //-------------------------------------------------------------------
02452               case 3:
02453                 // The two upper points are inside.
02454               {
02455                 // Same as for 12, but swapped the two segments.
02456                 // Also using (i+1, j+1) and (i+1, j) as the inside points.
02457                 vector<int> si0; si0.push_back(i+1); si0.push_back(i  );
02458                 vector<int> sj0; sj0.push_back(j  ); sj0.push_back(j+1);
02459                 vector<int> si1; si1.push_back(i  ); si1.push_back(i+1);
02460                 vector<int> sj1; sj1.push_back(j  ); sj1.push_back(j+1);
02461                 split_quad(i+1, j+1,    // s1[1]
02462                            i+1, j,              // s0[0]
02463                            -1, -1,
02464                            // Then the two intersection points are
02465                            si0, sj0, si1,       // somewhere on s0[0]-s1[0] (A) and
02466                            sj1,         // somewhere on s0[1]-s1[1] (B).
02467                            srf, vert, vert_p, bd, norm, mesh, dn, dm,
02468                            trim_curve_p_all[0], contour_all[0], s2m_with_boundary);
02469               }
02470               break;
02471               //-------------------------------------------------------------------
02472               case 14:
02473                 // All except the upper right point are inside.
02474               {
02475                 //               first segm this col
02476                 vector<int> si0; si0.push_back(i+1); si0.push_back(i+1);
02477                 vector<int> sj0; sj0.push_back(j+1); sj0.push_back(j+1);
02478                 vector<int> si1; si1.push_back(i  ); si1.push_back(i+1);
02479                 vector<int> sj1; sj1.push_back(j+1); sj1.push_back(j  );
02480                 split_quad(i, j,                //
02481                            i+1, j,      //
02482                            i, j+1,      //
02483                            // Then the two intersection points are
02484                            si0, sj0,    // somewhere on s0[0]-s1[0] (A) and
02485                            si1, sj1,    // somewhere on s0[1]-s1[1] (B).
02486                            srf, vert, vert_p, bd, norm, mesh, dn, dm,
02487                            trim_curve_p_all[0], contour_all[0], s2m_with_boundary);
02488               }
02489               break;
02490               //-------------------------------------------------------------------
02491               case 11:
02492                 // All except the lower right point are inside.
02493               {
02494                 //               first segm this col
02495                 vector<int> si0; si0.push_back(i  ); si0.push_back(i  );
02496                 vector<int> sj0; sj0.push_back(j+1); sj0.push_back(j+1);
02497                 vector<int> si1; si1.push_back(i  ); si1.push_back(i+1);
02498                 vector<int> sj1; sj1.push_back(j  ); sj1.push_back(j+1);
02499                 split_quad(i+1, j,      //
02500                            i+1, j+1,    //
02501                            i, j,                //
02502                            // Then the two intersection points are
02503                            si0, sj0,    // somewhere on s0[0]-s1[0] (A) and
02504                            si1, sj1,    // somewhere on s0[1]-s1[1] (B).
02505                            srf, vert, vert_p, bd, norm, mesh, dn, dm,
02506                            trim_curve_p_all[0], contour_all[0], s2m_with_boundary);
02507               }
02508               break;
02509               //-------------------------------------------------------------------
02510               case 7:
02511                 // All except the lower left point are inside.
02512               {
02513                 //               first segm this col
02514                 vector<int> si0; si0.push_back(i  ); si0.push_back(i  );
02515                 vector<int> sj0; sj0.push_back(j  ); sj0.push_back(j  );
02516                 vector<int> si1; si1.push_back(i+1); si1.push_back(i  );
02517                 vector<int> sj1; sj1.push_back(j  ); sj1.push_back(j+1);
02518                 split_quad(i+1, j+1,    //
02519                            i, j+1,      //
02520                            i+1, j,      //
02521                            // Then the two intersection points are
02522                            si0, sj0,    // somewhere on s0[0]-s1[0] (A) and
02523                            si1, sj1,    // somewhere on s0[1]-s1[1] (B).
02524                            srf, vert, vert_p, bd, norm, mesh, dn, dm,
02525                            trim_curve_p_all[0], contour_all[0], s2m_with_boundary);
02526               }
02527               break;
02528               //-------------------------------------------------------------------
02529               case 13:
02530                 // All except the upper left point are inside.
02531               {
02532                 //               first segm this col
02533                 vector<int> si0; si0.push_back(i+1); si0.push_back(i+1);
02534                 vector<int> sj0; sj0.push_back(j  ); sj0.push_back(j  );
02535                 vector<int> si1; si1.push_back(i+1); si1.push_back(i  );
02536                 vector<int> sj1; sj1.push_back(j+1); sj1.push_back(j  );
02537                 split_quad(i, j+1,      //
02538                            i, j,        //
02539                            i+1, j+1,    //
02540                                         // Then the two intersection points are
02541                            si0, sj0,    // somewhere on s0[0]-s1[0] (A) and
02542                            si1, sj1,    // somewhere on s0[1]-s1[1] (B).
02543                            srf, vert, vert_p, bd, norm, mesh, dn, dm,
02544                            trim_curve_p_all[0], contour_all[0], s2m_with_boundary);
02545               }
02546               break;
02547               //-------------------------------------------------------------------
02548               }
02549           }
02550 
02551 #ifdef DBG
02552     while (col.size()<mesh.size()/3)
02553       col.push_back('r');
02554 #endif
02555   
02556 #endif // end of #ifdef SPLIT_NON_CORNER_QUADS
02557 
02558 
02559 
02560 
02561 
02562 #ifdef SPLIT_TRIANGLES_AT_OUTER_CURVE
02563 
02564 #  ifdef DBG
02565     puts("====================================================================================================");
02566     puts("Splitting all triangles just generated, according to the first trimming curve.");
02567 #  endif
02568 
02569     //
02570     // 090203: Here we need a new pass to split triangles produced by the new "corner-stuff", and now we should
02571     //         split according to the first trimming curve, only. (Note, this all is based on the assumption
02572     //         that we should keep whatever is *inside* curve 0, and *outside* curves 1, 2, ...)
02573     // 
02574     // 090203: Hmm... maybe this code can somehow be combined with the stage below, for more compact code?!
02575     //
02576     // 090203: Have a suspicion that h.g2 produces a denegerate triangle in this part of the code.
02577     //
02578 
02579     for (int c=0; c<std::min(1, int(crv_set.size())); c++)
02580       trim_a_triangle_soup(srf, vert, vert_p, bd, norm, trim_curve_p_all[c], contour_all[c], mesh
02581 #  ifdef DBG
02582                            , col
02583 #  endif
02584         );
02585   
02586 #endif // end of #ifdef SPLIT_TRIANGLES_AT_OUTER_CURVE
02587 
02588 
02589 
02590 
02591 
02592 #ifdef SPLIT_TRIANGLES_AT_INNER_CURVES
02593 
02594 #ifdef DBG
02595     puts("====================================================================================================");
02596     puts("Splitting triangles according to the second and further trimming curves.");
02597 #endif
02598 
02599     //printf("Triangles added in 'make_trimmed_mesh': %d\n", int(mesh.size())/3);
02600 
02601     //
02602     // 081208: Adding a post-processing step in which we take into consideration further trimming curves. Now we
02603     //         have a mesh consisting of a number of triangles. We loop through all of them, and split them
02604     //         similarly to what was done with the first trimming curve above.
02605     //
02606     //         (For max code reuse, clarity and orthogonality, we should really replace the above, older code,
02607     //         with a pass similar to the one following below.)
02608     //
02609     //         First a version without the cached inside-results, since these are kind of messed up now, when we
02610     //         must free us from the regular grid... can be fixed later...
02611     //          
02612     //           081210: What the h... did I mean by this? Shouldn't using the cached values be
02613     //                   straightforward?!
02614     //
02615     // 081210: Note that the number of vertices are not reduced, even when it could be. Should be relatively
02616     //         easy to add a pass for doing such reduction later, if needed...
02617     //
02618 
02619 #ifdef DBG
02620     printf("\n\n================================================== crv_set.size=%d\n\n\n", int(crv_set.size()));
02621 #endif
02622 
02623     for (int c=1; c<int(crv_set.size()); c++)
02624       //for (int c=3; c<5; c++)
02625         {
02626 #ifdef DBG
02627           printf("----------==========########## trimming against inner curve %d (range=[%d, %d]) ##########==========----------\n", c, 1, int(crv_set.size())-1);
02628 #endif
02629           trim_a_triangle_soup(srf, vert, vert_p, bd, norm, trim_curve_p_all[c], contour_all[c], mesh,
02630 #ifdef DBG
02631                                col,
02632 #endif
02633                                true);
02634         }
02635       
02636 #endif // end of #ifdef SPLIT_TRIANGLES_AT_INNER_CURVES
02637 
02638 
02639 
02640 
02641 #if 0
02642 
02643 #  if 1
02644   
02645     // 100210: What was this?!?! probably some debugging... Seems to have been used for some hardcoded inner
02646     //         trimming curves... (number 2 and 3..)
02647   
02648     trim_a_triangle_soup(srf, vert, vert_p, bd, norm, trim_curve_p_all[2], contour_all[2], mesh, col, true);
02649     {
02650       FILE *f=fopen("e1.m", "w");
02651       for (int i=0; i<int(trim_curve_p_all[2].size())-1; i++)
02652         {
02653           const double &x0=trim_curve_p_all[2][contour_all[2][i]/3  ][0];
02654           const double &y0=trim_curve_p_all[2][contour_all[2][i]/3  ][1];
02655           const double &x1=trim_curve_p_all[2][contour_all[2][i]/3+1][0];
02656           const double &y1=trim_curve_p_all[2][contour_all[2][i]/3+1][1];
02657           fprintf(f, "line([%f; %f], [%f; %f], 'color', 'r', 'linewidth', 3);\n", x0, x1, y0, y1);
02658         }
02659       fclose(f);
02660     }
02661 #  endif
02662 
02663     puts("####################################################################################################");
02664     puts("####################################################################################################");
02665     puts("####################################################################################################");
02666   
02667   
02668 #  if 0
02669     trim_a_triangle_soup(srf, vert, vert_p, bd, norm, trim_curve_p_all[3], contour_all[3], mesh, col, true);
02670     {
02671       FILE *f=fopen("e2.m", "w");
02672       for (int i=0; i<int(trim_curve_p_all[3].size())-1; i++)
02673         {
02674           const double &x0=trim_curve_p_all[3][contour_all[3][i]/3  ][0];
02675           const double &y0=trim_curve_p_all[3][contour_all[3][i]/3  ][1];
02676           const double &x1=trim_curve_p_all[3][contour_all[3][i]/3+1][0];
02677           const double &y1=trim_curve_p_all[3][contour_all[3][i]/3+1][1];
02678           fprintf(f, "line([%f; %f], [%f; %f], 'color', 'r', 'linewidth', 3);\n", x0, x1, y0, y1);
02679         }
02680       fclose(f);
02681     }
02682 #  endif
02683   
02684 #endif
02685 
02686 
02687 
02688 
02689 
02690 
02691 #ifdef DBG
02692 
02693     //--------------------------------------------------------------------------------------------------------------
02694     //
02695     // 100210: Showing all remaining triangles. Colour coding:
02696     //          
02697     //           yellow: 
02698     //           green:
02699     //           red:
02700     //           cyan:
02701     //           magenta:
02702     //
02703     //--------------------------------------------------------------------------------------------------------------
02704 
02705     FILE *f=fopen("vis.m", "w");
02706     fprintf(f, "clf\n");
02707     for (int i=0; i<int(mesh.size())/3; i++)
02708       {
02709         const int u=0, v=1;
02710 #if 0
02711         if ( (vert_p[mesh[3*i]][u] > -40) &&
02712              (vert_p[mesh[3*i]][u] < -10) &&
02713              (vert_p[mesh[3*i]][v] >  25) &&
02714              (vert_p[mesh[3*i]][v] <  60)    )
02715 #endif
02716           {
02717             fprintf(f, "patch([%f; %f; %f], [%f; %f; %f], '%c');\n",
02718                     vert_p[mesh[3*i]][u], vert_p[mesh[3*i+1]][u], vert_p[mesh[3*i+2]][u], 
02719                     vert_p[mesh[3*i]][v], vert_p[mesh[3*i+1]][v], vert_p[mesh[3*i+2]][v], col[i]);
02720             fprintf(f, "line([%f; %f; %f; %f], [%f; %f; %f; %f], 'color', 'k');\n",
02721                     vert_p[mesh[3*i]][u], vert_p[mesh[3*i+1]][u], vert_p[mesh[3*i+2]][u], vert_p[mesh[3*i]][u], 
02722                     vert_p[mesh[3*i]][v], vert_p[mesh[3*i+1]][v], vert_p[mesh[3*i+2]][v], vert_p[mesh[3*i]][v]);
02723           }
02724       }
02725     fprintf(f, "zoom on\n");
02726     fprintf(f, "grid on\n");
02727     // fprintf(f, "axis('equal');\n");
02728     fprintf(f, "xlabel('u');\n");
02729     fprintf(f, "ylabel('v');\n");
02730     fprintf(f, "title('"
02731             "green   = post-corner-splitting\\newline"
02732             "red=post-first-curve-quad-splitting\\newline"
02733             "cyan    = post-outer-curve-triangle-splitting, first iteration\\newline"
02734             "magenta = post-inner-curve-triangle-splitting, first iteration\\newline"
02735             "yellow  = post-inner-curve-triangle-splitting\\newline"
02736             "blue    = post-outer-curve-triangle-splitting');\n");
02737     // fprintf(f, "set(gca, 'ydir', 'reverse');\n"); // 100210: To get the same view as default 'goview'.
02738     fclose(f);
02739   
02740 #endif
02741       
02742 
02743 
02744 
02745     //
02746     // 081210: Note that it does not make as much sense as before to return these now, if we have more than one
02747     //         trimming curve. But the caller is probably not using them... As it is, we return only for the
02748     //         outer trimming curve.
02749     //
02750     trim_curve_0   = trim_curve_all[0];
02751     trim_curve_p_0 = trim_curve_p_all[0];
02752 
02753     return;
02754   }

void Go::makeBdDegenerate ( SplineSurface &  srf,
int  bd_idx 
)

Make a specified surface boundary exactly degenerate.

Definition at line 261 of file GeometryTools.C.

References Go::SplineSurface::coefs_begin(), Go::SplineSurface::dimension(), Go::SplineSurface::numCoefs_u(), and Go::SplineSurface::numCoefs_v().

00263 {
00264     bool dir_u = (bd_idx == 2 || bd_idx == 3);
00265     int nmb1 = (dir_u) ? srf.numCoefs_u() : srf.numCoefs_v();
00266     int nmb2 = (dir_u) ? srf.numCoefs_v() : srf.numCoefs_u();
00267     int dim = srf.dimension();
00268     vector<double>::iterator coefs = srf.coefs_begin();
00269     int kr1 = (dir_u) ? dim : nmb1*dim;
00270 
00271     // First compute mean coefficient
00272     vector<double>::iterator c1 = coefs;
00273     if (bd_idx == 3)
00274         c1 += (nmb2-1)*nmb1*dim;
00275     if (bd_idx == 1)
00276         c1 += (nmb2-1)*dim;
00277 
00278     vector<double> deg_pt(dim, 0.0);
00279     for (int ki=0; ki<nmb1; ki++, c1+=kr1)
00280     {
00281         vector<double>::iterator d1 = c1;
00282         for (int kj=0; kj<dim; kj++, d1++)
00283             deg_pt[kj] += c1[kj];
00284     }
00285     for (int kj=0; kj<dim; kj++)
00286         deg_pt[kj] /= (double)nmb1;
00287 
00288     c1 = coefs;
00289     if (bd_idx == 3)
00290         c1 += (nmb2-1)*nmb1*dim;
00291     if (bd_idx == 1)
00292         c1 += (nmb2-1)*dim;
00293 
00294     for (int ki=0; ki<nmb1; ki++, c1+=kr1)
00295     {
00296         vector<double>::iterator d1 = c1;
00297         for (int kj=0; kj<dim; kj++, d1++)
00298             c1[kj] = deg_pt[kj];
00299     }
00300 }

void Go::makeUnionKnots ( std::vector< BsplineBasis > &  bbasis,
double  tol,
std::vector< double > &  union_knots 
)

Compute the union of a set of knot vectors.

Definition at line 138 of file unifyCurveSplineSpace.C.

Referenced by unifyCurveSplineSpace().

00140   {
00141     union_knots.clear();
00142 
00143   vector< std::vector<double>::const_iterator > c_ptr;
00144   vector< std::vector<double>::const_iterator > c_end;
00145   int nmb_crv = bbasis.size();
00146   c_ptr.resize(nmb_crv);
00147   c_end.resize(nmb_crv);
00148   int ki;
00149   for (ki=0; ki<nmb_crv; ki++)
00150     {
00151       c_ptr[ki] = bbasis[ki].begin();
00152       c_end[ki] = bbasis[ki].end();
00153     }
00154 
00155   double min_knot, knot;
00156   int max_mult, mult;
00157   while (true)
00158     {
00159       // More knots?
00160       for (ki=0; ki<nmb_crv; ki++)
00161         if (c_ptr[ki] < c_end[ki])
00162           break;
00163 
00164       if (ki == nmb_crv)
00165         break;  // All knots collected
00166 
00167       min_knot = c_ptr[ki][0];
00168       for (ki=1; ki<nmb_crv; ki++)
00169       {
00170           if (c_ptr[ki] != c_end[ki]) {
00171               knot = c_ptr[ki][0];
00172               min_knot = std::min(min_knot, knot);
00173           }
00174       }
00175        
00176       mult = 0;
00177       max_mult = 1;
00178       for (ki=0; ki<nmb_crv; ki++)
00179         {
00180           knot = c_ptr[ki][0];
00181           if (knot < min_knot + tol)
00182             for (mult=0; c_ptr[ki]<c_end[ki] && c_ptr[ki][0]==knot; 
00183                  mult++, c_ptr[ki]++);
00184           max_mult = std::max(max_mult, mult);
00185         }
00186 
00187       for (ki=0; ki<max_mult; ki++)
00188         union_knots.push_back(min_knot);
00189     }
00190   }

void Go::minimalCurvatureRadius ( const ParamSurface &  sf,
double  tolerance,
double &  mincurv,
double &  pos_u,
double &  pos_v,
double  degenerate_eps,
double  curv_tol = 1.0e-3 
)

Definition at line 215 of file CurvatureAnalysis.C.

References Go::ParamSurface::containingDomain(), evaluateMinCurvatureRadius(), Go::ParamSurface::isDegenerate(), Go::RectDomain::umax(), Go::RectDomain::umin(), Go::RectDomain::vmax(), and Go::RectDomain::vmin().

00223 {
00224     const RectDomain& dom = sf.containingDomain();
00225     double start_u = dom.umin();
00226     double end_u = dom.umax();
00227     double start_v = dom.vmin();
00228     double end_v = dom.vmax();
00229 
00230     // Modify domain at degenerate boundaries
00231     bool b, r, t, l;
00232     bool is_degen = sf.isDegenerate(b, r, t, l, degenerate_eps);
00233     if (is_degen)
00234     {
00235         double par_eps = 1.0e-4;  // @@@ VSK, dec 08. Rather arbitrary
00236         double fac = 1.0e-3;
00237         if (b)
00238             start_v += std::min(par_eps, fac*(end_v-start_v));
00239         if (r)
00240             end_u -= std::min(par_eps, fac*(end_u-start_u));
00241         if (t)
00242             end_v -= std::min(par_eps, fac*(end_v-start_v));
00243         if (l)
00244             start_u += std::min(par_eps, fac*(end_u-start_u));
00245     }
00246 
00247   vector<double> param_u;
00248   vector<double> param_v;
00249   vector<vector<double> > curvs;
00250 
00251   evaluateMinCurvatureRadius(sf,
00252                              start_u, end_u, start_v, end_v,
00253                              tolerance,
00254                              param_u, param_v, curvs,
00255                              mincurv, pos_u, pos_v,
00256                              true);
00257 
00258   /*
00259   // Make an interpolated surface interpolated_surf over the curvatures
00260 
00261   // Intersect by level plane defined by mincurv
00262   vector<shared_ptr<SplineCurve> > level_curve =
00263     intersect( aPlane, interpolated_surf);
00264 
00265   // Group curves into a set level_curves in two dimensions, answering to "boundingbox"
00266 
00267   for (int i = 0; i < level_curve.size() ++i)
00268     {
00269       BoundingBox b = level_curve[i].boundingBox();
00270       double box_start_u = max(start_u, b.low()[0] - tol);
00271       double box_end_u = min(end_u, b.high()[0] - tol);
00272       double box_start_v = max(start_v, b.low()[1] - tol);
00273       double box_end_v = min(end_v, b.high()[1] - tol);
00274       
00275       param_u.resize(0);
00276       param_v.resize(0);
00277       curvs.resize(0);
00278 
00279       local_tol = tolerance * min ((box_end_u - box_start_u) / (start_u-end_u),
00280                                    (box_end_v - box_start_v) / (start_v-end_v));
00281       local_tol = max(local_tol, 0.1*tolerance);
00282 
00283       evaluateMinCurvatureRadius(sf,
00284                                  box_start_u, box_end_u, box_start_v, box_end_v,
00285                                  local_tol,
00286                                  param_u, param_v, curvs,
00287                                  mincurv, pos_u, pos_v,
00288                                  false);
00289     }
00290   */
00291 
00292   // Rerun and make a finer evaluation round local minima
00293   vector<double> dummy_u;
00294   vector<double> dummy_v;
00295   vector<vector<double> > dummy_curvs;
00296 
00297   //double local_tol = 2.0 * tolerance * tolerance / max(end_u-start_u, end_v-start_v);
00298   double local_tol = tolerance/(double)(std::max(param_u.size(), param_v.size()));
00299   local_tol = min(local_tol, tolerance);
00300   double step_u = (end_u-start_u) / (param_u.size() - 1);
00301   double step_v = (end_v-start_v) / (param_v.size() - 1);
00302 
00303   for (int i = 0; i < (int)param_u.size(); ++i)
00304     {
00305       int i_prev = i - (i>0);
00306       int i_next = i + (i < (int)param_u.size()-1);
00307       for (int j = 0; j < (int)param_v.size(); ++j)
00308         {
00309           int j_prev = j - (j>0);
00310           int j_next = j + (j < (int)param_v.size()-1);
00311           double local_curv = curvs[i][j];
00312           if (local_curv > curvs[i_next][j] ||
00313               local_curv > curvs[i_prev][j] ||
00314               local_curv > curvs[i][j_next] ||
00315               local_curv > curvs[i][j_prev] ||
00316               local_curv > curvs[i_next][j_next] ||
00317               local_curv > curvs[i_next][j_prev] ||
00318               local_curv > curvs[i_prev][j_next] ||
00319               local_curv > curvs[i_prev][j_prev])
00320             continue;
00321           double limit = 2.0 * local_curv - mincurv + curv_tol*mincurv;
00322           bool rand_i = i==i_next || i == i_prev;
00323           bool rand_j = j==j_next || j == j_prev;
00324           if (!rand_i && curvs[i_prev][j]<limit && curvs[i_next][j]<limit) continue;
00325           if (!rand_j && curvs[i][j_prev]<limit && curvs[i][j_next]<limit) continue;
00326           if (!rand_i && !rand_j && curvs[i_prev][j_prev]<limit && curvs[i_next][j_next]<limit) continue;
00327           if (!rand_i && !rand_j && curvs[i_prev][j_next]<limit && curvs[i_next][j_prev]<limit) continue;
00328 
00329           dummy_u.resize(0);
00330           dummy_v.resize(0);
00331           dummy_curvs.resize(0);
00332           evaluateMinCurvatureRadius(sf,
00333                                      start_u+double(i_prev)*step_u,
00334                                      start_u+double(i_next)*step_u,
00335                                      start_v+double(j_prev)*step_v,
00336                                      start_v+double(j_next)*step_v,
00337                                      local_tol,
00338                                      dummy_u, dummy_v, dummy_curvs,
00339                                      mincurv, pos_u, pos_v,
00340                                      false);
00341         }
00342     }
00343 
00344 }

void Go::minimalCurvatureRadius ( const SplineCurve &  curve,
double &  mincurv,
double &  pos 
)

Definition at line 140 of file Curvature.C.

References Go::SplineInterpolator::basis(), Go::SplineCurve::basis(), Go::BsplineBasis::begin(), curvatureRadius(), Curve2SISL(), Go::SplineCurve::derivCurve(), Go::BsplineBasis::endparam(), Go::SplineInterpolator::interpolate(), Go::BsplineBasis::knotMultiplicity(), Go::BsplineBasis::knotsSimple(), Go::Point::length(), MAXDOUBLE, Go::BsplineBasis::order(), Go::SplineInterpolator::setBasis(), and Go::BsplineBasis::startparam().

Referenced by main().

00144 {
00145   // Find the spline function for the numerator in the derivate of the square of the curvature
00146 
00147   BsplineBasis basis = curve.basis();
00148   int order = basis.order();
00149   int new_order = 6 * order - 14;
00150 
00151   if (new_order < 0)    // Straight line
00152     {
00153       mincurv = MAXDOUBLE;
00154       pos = (basis.startparam() + basis.endparam()) / 2.0;
00155       return;
00156     }
00157 
00158   vector<double> knots_simple;
00159   vector<double> new_knots;
00160   basis.knotsSimple(knots_simple);
00161 
00162   for (size_t i = 0; i < knots_simple.size(); ++i)
00163     {
00164       int old_mult = basis.knotMultiplicity(knots_simple[i]);
00165       int new_mult = 5 * order - 11 + old_mult;
00166       if (old_mult >= order-2) new_mult -= 3 - order + old_mult;
00167       for (int j = 0; j < new_mult; ++j) new_knots.push_back(knots_simple[i]);
00168     }
00169 
00170   int num_coefs = new_knots.size() - new_order;
00171 
00172   BsplineBasis new_basis(new_order, new_knots.begin(), new_knots.end());
00173 
00174   vector<double> coefs_par; // Parameter values for the coefs (Greville)
00175   vector<double> coefs;
00176 
00177   shared_ptr<SplineCurve> d_curve(curve.derivCurve(1));
00178   shared_ptr<SplineCurve> dd_curve(d_curve->derivCurve(1));
00179   shared_ptr<SplineCurve> ddd_curve(dd_curve->derivCurve(1));
00180 
00181   for (int i = 0; i < num_coefs; )
00182     {
00183       int knot_pos = i + 1;
00184       while (knot_pos < int(new_knots.size()) && new_knots[knot_pos-1] == new_knots[knot_pos])
00185         ++knot_pos;
00186       double step = (new_knots[knot_pos] - new_knots[knot_pos-1]) / double(knot_pos - i);
00187       double tpar = new_knots[knot_pos-1] + step/2.0;
00188       for (;i < knot_pos; ++i)
00189         {
00190           coefs_par.push_back(tpar);
00191           tpar += step;
00192         }
00193     }
00194 
00195   for (int i = 0; i < num_coefs; ++i)
00196     {
00197       double tpar = coefs_par[i];
00198       Point d_p, dd_p, ddd_p;
00199       d_curve->point(d_p, tpar);
00200       dd_curve->point(dd_p, tpar);
00201       ddd_curve->point(ddd_p, tpar);
00202 
00203       coefs.push_back( (d_p % dd_p) * (d_p % (ddd_p * (d_p * d_p) - dd_p * 3 * (d_p * dd_p))) );
00204     }
00205 
00206   vector<double> numerator_coefs;
00207   vector<double> dummy_tangents;
00208   vector<int> dummy_index;
00209   SplineInterpolator interpolator;
00210   interpolator.setBasis(new_basis);
00211   interpolator.interpolate(coefs_par, coefs, dummy_index,
00212                            dummy_tangents, numerator_coefs);
00213 
00214   shared_ptr<SplineCurve> numerator_curve(
00215     new SplineCurve(num_coefs, new_order,
00216                     interpolator.basis().begin(),
00217                     numerator_coefs.begin(), 1));
00218 
00219   SISLCurve *num_sisl = Curve2SISL(*(numerator_curve.get()), false);
00220   SISLObject *qo1 = 0;
00221   SISLObject *qo2 = 0;
00222   SISLPoint *qp = 0;
00223   double spoint[1];
00224   spoint[0] = 0.0;
00225   int kstat = 0;
00226   SISLIntdat *qintdat = 0;
00227   double aepsge = 1.0e-9;
00228 
00229   bool mincurvFound = false;
00230   vector<double> extremalParametervalues;
00231 
00232   if (!(qo1 = newObject(SISLCURVE))) goto error101;
00233   qo1 -> c1 = num_sisl;
00234   qo1 -> o1 = qo1;
00235 
00236   if (!(qo2 = newObject(SISLPOINT))) goto error101;
00237   spoint[0] = 0.0;
00238   if(!(qp = newPoint(spoint,1,1))) goto error101;
00239   qo2 -> p1 = qp;
00240 
00241   sh1761(qo1,qo2,aepsge,&qintdat,&kstat);
00242   if (kstat < 0) goto error101;
00243 
00244 
00245   if (qintdat)
00246   {
00247       for (int i = 0; i < qintdat->ipoint; ++i)
00248           extremalParametervalues.push_back(qintdat->vpoint[i]->epar[0]);
00249   }
00250 
00251   for (size_t i = 0; i < knots_simple.size(); ++i)
00252     extremalParametervalues.push_back(knots_simple[i]);
00253 
00254   for (size_t i = 0; i < extremalParametervalues.size(); ++i)
00255     {
00256       Point d_p, dd_p;
00257       d_curve->point(d_p, extremalParametervalues[i]);
00258       dd_curve->point(dd_p, extremalParametervalues[i]);
00259       double curv_numerator = (d_p % dd_p).length();
00260       double curv_denominator = d_p.length();
00261       curv_denominator = curv_denominator * curv_denominator * curv_denominator;
00262       if (curv_numerator <= curv_denominator * 1.0e-9) continue;
00263 
00264       double curvatureRadius = curv_denominator/curv_numerator;    // Same as 1/curvature
00265       if (!mincurvFound || curvatureRadius < mincurv)
00266         {
00267           mincurvFound = true;
00268           mincurv = curvatureRadius;
00269           pos = extremalParametervalues[i];
00270 
00271         }
00272     }
00273 
00274  error101:
00275   if (qo1)     freeObject(qo1);
00276   if (qo2)     freeObject(qo2);
00277   if (qintdat) freeIntdat(qintdat);
00278 
00279 
00280 }

template<class Functor >
void Go::minimise_conjugated_gradient ( FunctionMinimizer< Functor > &  dfmin  )  [inline]

This is the algorithm for minimising a function taking multiple parameters, using the conjugated gradient method.

It is used in conjunction with the FunctionMinimizer class. Documentation for both can be found here: FunctionMinimizer

Definition at line 53 of file GeneralFunctionMinimizer_implementation.h.

References Go::FunctionMinimizer< Functor >::atMax(), Go::FunctionMinimizer< Functor >::atMin(), Go::FunctionMinimizer< Functor >::fval(), Go::FunctionMinimizer< Functor >::grad(), Go::Point::length2(), Go::FunctionMinimizer< Functor >::minimize(), and Go::FunctionMinimizer< Functor >::numPars().

Referenced by Go::SplineSurface::closestPoint(), closestPtCurves(), closestPtCurveSurf(), closestPtSurfSurfPlaneFunctional(), and Go::ParamSurface::singularity().

00055 {
00056     const double TOL = std::numeric_limits<double>::epsilon(); //1.0e-8;
00057     const double EPS = 1.0e-10;
00058     // minimising the 'dfmin' function using conjugated gradients.
00059     const int N = dfmin.numPars();
00060     Point gradient(N), old_gradient(N), dir(N);
00061     dfmin.grad(old_gradient);
00062     dir = -old_gradient;
00063     double old_val = dfmin.fval();
00064     while(true) {
00065 
00066         // make sure direction is not uphill (is this already guaranteed??)
00067         // and truncating it if we are at the border of the domain
00068         if (dir * old_gradient > 0) {
00069             dir *= -1;
00070         }
00071         for (int i = 0; i < N; ++i) {
00072             if ((dfmin.atMin(i) && dir[i] < 0) || (dfmin.atMax(i) && dir[i] > 0)) {
00073                 dir[i] = 0;
00074                 // conjugate gradient value is broken since we modified dir.
00075                 // Restarting cycle.
00076             }
00077         }
00078 
00079         // minimize along this direction
00080         bool hit_domain_edge = false;
00081         double new_val = dfmin.minimize(dir, hit_domain_edge); 
00082         if (2.0 * fabs(new_val - old_val) <= TOL  * (fabs(new_val) + fabs(old_val)+ EPS)) {
00083             // we have reached a minimum
00084             break;
00085         } else {
00086             old_val = new_val;
00087         }
00088 
00089         // choose new direction 
00090         dfmin.grad(gradient);
00091         if (!hit_domain_edge) {
00092             // we are still in a conjugated gradient cycle.  Choose new direction 
00093             // using conjugated gradients (Polak-Ribiere variant)
00094 
00095             Point diff = gradient - old_gradient;
00096             double factor = gradient * diff / old_gradient.length2();
00097             Point dir_saved = dir;
00098             dir *= factor;
00099             dir -= gradient;
00100 
00101             if (dir * old_gradient > 0) {
00102                 dir *= -1;
00103             }
00104 
00105             bool on_boundary = false;
00106             for (int i = 0; i != N; ++i) {
00107                 if ((dfmin.atMin(i) && dir[i] < 0) || (dfmin.atMax(i) && dir[i] > 0)) {
00108                     on_boundary = true;
00109                     gradient[i] = old_gradient[i] = 0;  
00110                     dir_saved[i] = 0; // we will have to recalculated 'dir' based on this vector
00111                 }
00112             }
00113 
00114             if (on_boundary) {
00115                 // the direction we choose will take us out of the domain.  Reduce problem
00116                 // to conjugated gradient in a lower dimension.
00117                 dir = dir_saved;
00118                 diff = gradient - old_gradient;
00119                 factor = gradient * diff / old_gradient.length2();
00120                 dir *= factor;
00121                 dir -= gradient;        
00122             } 
00123             old_gradient = gradient;
00124         } else {
00125             // We ran into an edge of the domain.  Re-initialising conjugate
00126             // gradient method using steepest descent.
00127             dir = - gradient;
00128             for (int i = 0; i != N; ++i) {
00129                 if ((dfmin.atMin(i) && dir[i] < 0) || (dfmin.atMax(i) && dir[i] > 0)) {
00130                     dir[i] = 0;
00131                     gradient[i] = 0;
00132                 }
00133             }
00134             old_gradient = gradient;
00135         }
00136     }
00137 }

bool Go::negativeProj ( const SplineSurface &  surface,
const Array< Vector3D, 2 > &  refvector,
const double  eps = 0.0 
)

Returns true if any vector difference between neighboring control points in the u- or v-directions has negative projection on the given reference vector.

Parameters:
surface the SplineSurface containing the control points
refvector the vector onto which we carry out the projection
eps toleance used when defining whether a vector has a negative projection onto 'refvector' (the scalar product must be less than -eps).
Returns:
'true' if we have found a difference between neighboring control points that has a negative projection on the reference vector.

Definition at line 58 of file GGUdominant.C.

References Go::SplineSurface::coefs_begin(), Go::SplineSurface::numCoefs_u(), and Go::SplineSurface::numCoefs_v().

00062 {
00063     int num_u = surface.numCoefs_u();
00064     int num_v = surface.numCoefs_v();
00065     Vector3D temp;
00066     int i = 0, j = 0;
00067     while (i < num_u-1) {
00068         j = 0;
00069         while (j < num_v) {
00070             temp[0] = *(surface.coefs_begin() + 3*(num_u*j + i+1))
00071                 - *(surface.coefs_begin() + 3*(num_u*j + i));
00072             temp[1] = *(surface.coefs_begin() + 3*(num_u*j + i+1) + 1)
00073                 - *(surface.coefs_begin() + 3*(num_u*j + i) + 1);
00074             temp[2] = *(surface.coefs_begin() + 3*(num_u*j + i+1) + 2)
00075                 - *(surface.coefs_begin() + 3*(num_u*j + i) + 2);
00076             // Positive tolerance means that there must be a small
00077             // _nonzero_ negative projection before it is reported as
00078             // negative!
00079             if (temp * refvector[0] < -eps)
00080                 return true;
00081             ++j;
00082         }
00083         ++i;
00084     }
00085     i = 0;
00086     while (i < num_u) {
00087         j = 0;
00088         while (j < num_v-1) {
00089             temp[0] = *(surface.coefs_begin() + 3*(num_u*(j+1) + i))
00090                 - *(surface.coefs_begin() + 3*(num_u*j + i));
00091             temp[1] = *(surface.coefs_begin() + 3*(num_u*(j+1) + i) + 1)
00092                 - *(surface.coefs_begin() + 3*(num_u*j + i) +1);
00093             temp[2] = *(surface.coefs_begin() + 3*(num_u*(j+1) + i) + 2)
00094                 - *(surface.coefs_begin() + 3*(num_u*j + i) + 2);
00095             // Positive tolerance means that there must be a small
00096             // _nonzero_ negative projection before it is reported as
00097             // negative!
00098             if (temp * refvector[1] < -eps)
00099                 return true;
00100             ++j;
00101         }
00102         ++i;
00103     }
00104 
00105     return false;
00106 }

void Go::nextStep ( double &  cdist,
double &  cdiff1,
double &  cdiff2,
std::vector< Point > &  eval1,
std::vector< Point > &  eval2 
)

Computes the distance vector and value beetween a point on the first curve and a point on the second curve.

And computes a next step on both curves. This is equivalent to the nearest way to the parameter plane in the tangent plane from a point in the distance surface between two curves. Ported from the sisl function s1770_s9dir. METHOD : The method is to compute the parameter distance to the points on both tangents which is closest to each other. The difference vector beetween these points are orthogonal to both tangents. If the distance vector beetween the two points on the curve is "diff" and the two derivative vectors are "der1" and "der2", and the two wanted parameter distances are "dt1" and "dt2", then we get the following system of equations:

      <dt1*der1+dist-dt2*der2,der2> = 0
      <dt1*der1+dist-dt2*der2,der1> = 0
   	       This is further:
    
    | -<der1,der2>   <der2,der2> |  | dt1 |   | <diff,der2> |
    |                            |  |     | = |             |
    | -<der1,der1>   <der1,der2> |  | dt2 |   | <diff,der1> |
   

The solution of this matrix equation dt1,dt2 are returned in the parameters cdiff1,cdiff2.

Definition at line 400 of file closestPtCurves.C.

References Go::Point::length().

Referenced by closestPtCurveSurf(), closestPtSurfSurfPlaneGeometrical(), and extremalPtSurfSurf().

00403 {
00404   const double TOL = 1.0e-12;
00405 
00406   Point& p1 = eval1[0];  // Value
00407   Point& d1 = eval1[1];  // 1. derivative
00408 
00409   Point& p2 = eval2[0];
00410   Point& d2 = eval2[1]; 
00411 
00412   Point gdiff = p1 - p2;  // Distance vector
00413   cdist = gdiff.length(); // Length of distance vector
00414 
00415   double t1,t2,t3,t4,t5;   // Variables in equation system
00416   // scalar products
00417   t1 = d1*d1;
00418   t2 = d1*d2;
00419   t3 = d2*d2;
00420   t4 = gdiff*d1;
00421   t5 = gdiff*d2;
00422 
00423   double tdet = t2*t2 - t1*t3;  // Determinant
00424 
00425   //  double delta_t1, delta_t2;
00426   if (fabs(tdet) < TOL) {
00427     cdiff1 = 0.0;
00428     cdiff2 = 0.0;
00429   }
00430   else {   // Using Cramer's rule to find the solution of the system
00431     cdiff1 =  (t4*t3 - t5*t2)/tdet;
00432     cdiff2 =  (t2*t4 - t1*t5)/tdet;
00433   }
00434 }

template<typename ForwardIterator >
void Go::normalize ( ForwardIterator  first,
ForwardIterator  last 
) [inline]

normalize makes the length of a vector 1.0

Definition at line 149 of file Utils.h.

References sum_squared().

Referenced by make_trimmed_mesh().

00151         {
00152             typename go_iterator_traits<ForwardIterator>::value_type d
00153                 = sqrt(sum_squared(first, last));
00154             d = 1.0/d;
00155             for (; first != last; ++first)
00156                 (*first) *= d;
00157         }

void Go::normalNoise ( double *  res,
double  mean_err,
int  num_samples 
)

Gives a certain number of random samples drawn from the normal distribution.

Parameters:
res a pointer to the array where the resulting samples should be written.
mean_err the sigma parameter to the normal distribution.
num_samples the desired number of samples (should also be the size of the array pointed to by res.

Definition at line 25 of file randomnoise.C.

00027 {
00028     double scale_factor = double(2) / double(RAND_MAX);
00029     double v1, v2, r2, fact;
00030     for (int i = 0; i < num_samples; i+=2) {
00031         do {
00032             v1 = double(rand()) * scale_factor - 1;
00033             v2 = double(rand()) * scale_factor - 1;
00034             r2 = v1 * v1 + v2 * v2;
00035         } while (r2 > 1 || r2 == double(0) || false);
00036         // we now know that the point (v1, v2) is within the unit circle, away from 0
00037         fact = sqrt(- 2 * log(r2)/r2);
00038         fact *= mean_err;
00039         res[i] = v1 * fact;
00040         if (i+1 < num_samples) {
00041             res[i+1] = v2 * fact;
00042         }
00043     }
00044 }

void Go::objsToFile ( vector< shared_ptr< GeomObject > > &  geom_objs,
char *  to_file 
)

Definition at line 103 of file SplineDebugUtils.C.

00105 {
00106     std::ofstream debug(to_file);
00107     for (size_t ki = 0; ki < geom_objs.size(); ++ki) {
00108         if (geom_objs[ki].get() != 0) {
00109             geom_objs[ki]->writeStandardHeader(debug);
00110             geom_objs[ki]->write(debug);
00111         }
00112     }
00113 }

void GO_API Go::objsToFile ( std::vector< boost::shared_ptr< GeomObject > > &  geom_objs,
char *  to_file 
)

writes the geometric objects (with header) to the specified file name.

Parameters:
geom_objs the objects to write to file.
to_file the file name to which the objects will be written.
void Go::objToFile ( GeomObject *  geom_obj,
char *  to_file 
)

writes the geometric object (with header) to the specified file name.

Parameters:
geom_obj the object to write to file.
to_file the file name to which the object will be written.

Definition at line 91 of file SplineDebugUtils.C.

References Go::Streamable::write(), and Go::GeomObject::writeStandardHeader().

00093 {
00094     if (geom_obj) {
00095         std::ofstream debug(to_file);
00096         geom_obj->writeStandardHeader(debug);
00097         geom_obj->write(debug);
00098     }
00099 }

Rational Go::operator* ( const Rational &  r1,
const Rational  r2 
)

Definition at line 132 of file Rational.h.

00133 {
00134     Rational res = r1;
00135     res *= r2;
00136     return res;
00137 }

Point Go::operator* ( double  d,
const Point &  p 
) [inline]

The product of a vector and a scalar.

Definition at line 497 of file Point.h.

00498     { return p*d; }

template<class T , int Dim>
Array<T, Dim> Go::operator* ( const Array< double, Dim > &  a,
const T  b 
) [inline]

Definition at line 145 of file BaryCoordSystem.h.

00146 {
00147     Array<T, Dim> result;
00148     for (int i = 0; i < Dim; ++i) {
00149         result[i] = a[i] * b;
00150     }
00151     return result;
00152 }

template<typename T , int Dim>
Go::Array<T, Dim> Go::operator* ( d,
const Go::Array< T, Dim > &  v 
) [inline]

The product of a vector and a scalar.

Definition at line 414 of file Array.h.

00415     { return v*d; }

Rational Go::operator+ ( const Rational &  r1,
const Rational  r2 
)

Definition at line 118 of file Rational.h.

00119 {
00120     Rational res = r1;
00121     res += r2;
00122     return res;
00123 }

Rational Go::operator- ( const Rational &  r1,
const Rational  r2 
)

Definition at line 125 of file Rational.h.

00126 {
00127     Rational res = r1;
00128     res -= r2;
00129     return res;
00130 }

Rational Go::operator/ ( const Rational &  r1,
const Rational  r2 
)

Definition at line 139 of file Rational.h.

00140 {
00141     Rational res = r1;
00142     res /= r2;
00143     return res;
00144 }

bool Go::operator< ( const Point &  p1,
const Point &  p2 
) [inline]

Definition at line 509 of file Point.h.

References DEBUG_ERROR_IF, and Go::Point::dimension().

00510     {
00511         const int dim = p1.dimension();
00512         DEBUG_ERROR_IF(p2.dimension() != dim, "Dimension Mismatch");
00513         for (int i = dim-1; i >= 0; --i) {
00514             if (p1[i] > p2[i]) return false;
00515             if (p1[i] < p2[i]) return true;
00516         }
00517         return false;
00518     }

std::ostream& Go::operator<< ( std::ostream &  os,
const Rational &  p 
)

Definition at line 146 of file Rational.h.

References Go::Rational::write().

00147 {
00148     p.write(os);
00149     return os;
00150 }

std::ostream& Go::operator<< ( std::ostream &  os,
const Go::Point v 
) [inline]

Stream insertion for Point.

Definition at line 505 of file Point.h.

References Go::Point::write().

00506     { v.write(os); return os; }

template<typename T , int Dim>
std::ostream& Go::operator<< ( std::ostream &  os,
const MatrixXD< T, Dim > &  m 
) [inline]

Specialization of the determinant function for the 1x1 case.

Terminates the det() template recursion. output operator

Definition at line 432 of file MatrixXD.h.

00433     {
00434         for (int i = 0; i < Dim; ++i) {
00435             for (int j = 0; j < Dim; ++j) {
00436                 os <<  m(i,j) << ' ';
00437             }
00438             os << '\n';
00439         }
00440         return os;
00441     }

template<typename T , int Dim>
std::ostream& Go::operator<< ( std::ostream &  os,
const Go::Array< T, Dim > &  v 
) [inline]

Stream insertion for Array.

Definition at line 424 of file Array.h.

00425     { v.write(os); return os; }

std::ostream& Go::operator<< ( std::ostream &  os,
const Go::Streamable obj 
) [inline]

Definition at line 54 of file Streamable.h.

References Go::Streamable::write().

00056 {
00057     obj.write(os);
00058     return os;
00059 }

std::istream& Go::operator>> ( std::istream &  is,
Go::Point v 
) [inline]

Stream extraction for Point.

Definition at line 501 of file Point.h.

References Go::Point::read().

00502     { v.read(is); return is; }

template<typename T , int Dim>
std::istream& Go::operator>> ( std::istream &  is,
Go::Array< T, Dim > &  v 
) [inline]

Stream extraction for Array.

Definition at line 419 of file Array.h.

References Go::Array< T, Dim >::read().

00420     { v.read(is); return is; }

std::istream& Go::operator>> ( std::istream &  is,
Go::Streamable obj 
) [inline]

Definition at line 47 of file Streamable.h.

References ALWAYS_ERROR_IF, and Go::Streamable::read().

00048 {
00049     ALWAYS_ERROR_IF(is.eof(), "End of file reached. Cannot read.");
00050     obj.read(is);
00051     return is;
00052 }

template<class PtrToCurveType >
void Go::orientCurves ( const std::vector< PtrToCurveType > &  curves,
std::vector< int > &  permutation,
std::vector< bool > &  reversed,
double  neighbour_tol,
bool  assume_manifold = true 
) [inline]

This function sorts and orients a set of curves so that curves whose endpoints coincide will be ordered consecutively, and eventually 'reversed' so that startpoints meet endpoints.

It is assumed that the set of curves given constitute one or several manifolds, ie., that there will not be cases where three or more endpoints meet at a common point (this would make the above mentionned ordering impossible).

Parameters:
curves a vector containing the set of (pointers to) curves to be analysed. It is expected that they constitute one or more 1-manifolds.
permutation upon return, this vector will contain a permutation of the indices to the input curves such that after this permutation, curves whose endpoints are connected will become 'consecutive'.
reversed upon return, this vector, whose length will be equal to that of 'curves' and 'permutation', will contain bool values. If curve at position 'i' in the 'curves' vector needs to be reversed in order to connect startpoint-to-endpoint with its neighbours, then the corresponding value in 'reversed' will be 'true', and 'false' if no reversal is necessary.
neighbour_tol the tolerance used when checking for coincident points.
assume_manifold if the user specifies 'true', then the manifold property will be assumed, but will not be explicitly checked. If 'false' is specified, then the input will be checked for consistency with respect to this, and an exception will be cast if the manifold condition is violated.

Definition at line 43 of file orientCurves.h.

References Go::Point::dist(), and THROW.

Referenced by Go::CurveLoop::fixInvalidLoop().

00049 {
00050     // registering all points
00051     int i, num_seg = curves.size();
00052     std::vector<Point> endpoints(2 * num_seg);
00053     for (i = 0; i < num_seg; ++i) {
00054         curves[i]->point(endpoints[2 * i + 0], curves[i]->startparam());
00055         curves[i]->point(endpoints[2 * i + 1], curves[i]->endparam());
00056     }
00057 
00058     // detecting connections
00059     std::vector<int> connected_to(2 * num_seg, -1);
00060     for (i = 0; i < 2 * num_seg; ++i) {
00061         if (connected_to[i] == -1 || !assume_manifold) {
00062             Point& p1 = endpoints[i];
00063             bool found = (connected_to[i] != -1);
00064             // this point has not been checked for connections yet
00065             for (int j = i+1; j < 2 * num_seg; ++j) {
00066                 if (connected_to[j] == -1) {
00067                     if (p1.dist(endpoints[j]) < neighbour_tol) {
00068                         // we consider these points to be connected
00069                         connected_to[i] = j;
00070                         connected_to[j] = i;
00071                         if (assume_manifold) {
00072                             break;
00073                         } else if (found == true) {
00074                             THROW("Multiple connected points detected in "
00075                                   " orientCurves().  Not a 1-manifold!" );
00076                         } else { 
00077                             found = true;
00078                         }
00079                     }
00080                 }
00081             }
00082         }
00083     }
00084 
00085     // Making the permutation std::vector
00086     permutation.clear();
00087     permutation.reserve(num_seg);
00088     reversed.clear();
00089     reversed.reserve(num_seg);
00090     std::vector<bool> visited(2*num_seg, false);
00091     // First handle all open chains
00092     for (i = 0; i < 2*num_seg; ++i) {
00093         if (!visited[i] && connected_to[i] == -1) {
00094             int current = i;
00095             do {
00096                 permutation.push_back(current/2);
00097                 bool current_parity = (current%2 == 0);
00098                 int partner = current_parity ? current + 1 : current - 1;
00099                 reversed.push_back(!current_parity);
00100                 visited[current] = true;
00101                 visited[partner] = true;
00102                 current = connected_to[partner];
00103             } while (current != -1);
00104         }
00105     }
00106     // Then all closed chains (loops)
00107     for (i = 0; i < 2*num_seg; ++i) {
00108         if (!visited[i]) {
00109             int current = i;
00110             do {
00111                 permutation.push_back(current/2);
00112                 bool current_parity = (current%2 == 0);
00113                 int partner = current_parity ? current + 1 : current - 1;
00114                 reversed.push_back(!current_parity);
00115                 visited[current] = true;
00116                 visited[partner] = true;
00117                 current = connected_to[partner];
00118             } while (current != i);
00119         }
00120     }
00121 }

void Go::osloalg ( int  ij,
int  imy,
int  ik,
int  in,
int *  jpl,
int *  jfi,
int *  jla,
double *  et,
double *  etau,
double *  galfa 
)

Corresponds to s1701 in SISL This function computes in a compact format a line in the discrete B-spline matrix converting between an orginal basis "etau" and a new basis "et".

Parameters:
ij The index of the new vertice
imy An index on etau, where the input value are to be etau(imy) <= et(ij) < etau(imy + 1).
ik The order of the B-spline.
in The number of the orginal vertices.
et The new knot vector.
etau The old knot vector.
et An array ep(ik) to local use. Such that we do not need to allocate the array locally after each call.
jpl The negativ difference between the index in galfa and the real knot inserten matrix.
jfi The index of the first element in the line j in the the real knot inserten matrix whice is not zero. The element with the index (jfi+jpl) in galfa is the same as the element with index jfi in the real line j in the knot inserten matrix.
jla The index of the last element in the line j in the real knot inserten matrix whice is not zero. The element with the index (jla+jpl) in galfa is the same as the element with index jla in the real line j in the knot inserten matrix.
galfa A compressed line in the knot inserten matrix.

Definition at line 20 of file osloalg.C.

Referenced by Go::SplineCurve::insertKnot(), and refmatrix().

00028              : To compute in a compact format a line in the discrete
00029 *              B-spline matrix converting between an orginal basis
00030 *              "etau" and a new basis "et".
00031 *
00032 *
00033 *
00034 * INPUT    : ij     - The index of the new vertice
00035 *            imy    - An index on etau, where the input value are to be
00036 *                     etau(imy) <= et(ij) < etau(imy + 1).
00037 *            ik     - The order of the B-spline.
00038 *            in     - The number of the orginal vertices.
00039 *            et     - The new knot vector.
00040 *            etau   - The old knot vector.
00041 *            ep     - An array ep(ik) to local use. Such that we
00042 *                     do not need to allocate the array locally after
00043 *                     each call.
00044 *
00045 *
00046 *
00047 * OUTPUT   : jpl    - The negativ difference between the index in galfa
00048 *                     and the real knot inserten matrix.
00049 *            jfi    - The index of the first element in the line j in the
00050 *                     the real knot inserten matrix whice is not zero.
00051 *                     The element with the index (jfi+jpl) in galfa
00052 *                     is the same as the element with index jfi in
00053 *                     the real line j in the knot inserten matrix.
00054 *            jla    - The index of the last element in the line j in the
00055 *                     real knot inserten matrix whice is not zero.
00056 *                     The element with the index (jla+jpl) in galfa
00057 *                     is the same as the element with index jla in
00058 *                     the real line j in the knot inserten matrix.
00059 *            galfa  - A compressed line in the knot inserten matrix.
00060 *            jstat  - status messages
00061 *                                         > 0      : warning
00062 *                                         = 0      : ok
00063 *                                         < 0      : error
00064 *
00065 *
00066 * METHOD     : Using the Oslo-algorithm
00067 *
00068 *
00069 * REFERENCES : Making The Oslo algorithm more efficient.
00070 *              by  T.Lyche and K.Moerken.
00071 *              SIAM J.NUMER.ANAL  Vol. 23, No. 3, June 1986.
00072 *
00073 *-
00074 * CALLS      :
00075 *
00076 * WRITTEN BY : Arne Laksaa, SI, 88-11.
00077 * REVISED BY : Atgeirr F Rasmussen, Sintef, 06/04/2001. Go-ified.
00078 *
00079 **********************************************************************/
00080 {
00081   int kp;                  /* Control variable in loop.     */
00082   int kv,kkv;              /* Help variables.               */
00083   double *ah;              /* Help pointer to galfa.        */
00084   double tbeta,tbeta1;     /* Help variables.               */
00085   double td1,td2;          /* Help variables.               */
00086   double *tu;              /* Pointer to the knot vector.   */
00087 
00088   std::vector<double> epvec(ik);
00089   double* ep = &epvec[0];
00090   
00091   /* Correction of imy to be sure that the the old knot etau(imy)
00092      is not passing the new knot et(ij). */
00093   
00094   kp=ij+1; kkv=ij+ik; in--;
00095   while ((et[kp] == etau[imy]) && kp<kkv) {kp++; imy--;}
00096   
00097   
00098   /* Counting the old and the new knot and copying the new knots
00099      in the area between et(ij) and et(ij+ik) in the array ep. */
00100   
00101   for (kp=imy+1,kv=0,ij++; ij<kkv; ij++)
00102     if (et[ij] == etau[kp]) kp++;
00103     else      ep[kv++] = et[ij];
00104   
00105   
00106   /* Compute the negativ difference between the index in galfa and
00107      the real knot inserten matrix. */
00108   
00109   *jpl=ik-imy-1;
00110   
00111   
00112   /* Changing the galfa so we may use the index in the real matrix. */
00113   
00114   galfa += *jpl;
00115   
00116   
00117   /* Initialise the last element. */
00118   
00119   galfa[imy] = 1;
00120   
00121   
00122   /* Here we go one time for each new knot from et(j+1)
00123      until et(j+k) we insert. */
00124   
00125   for (kp=0,kkv=ik-kv,ij=in+kv-1,in +=ik; kp<kv; kp++,kkv++,ep++)
00126     {
00127       /* The initialising:  The two first are not changing.
00128          kkv = ik-kv , the nuber of old knots in the field.
00129          This variabel is counting up to ik
00130          (the order) during the loops.
00131          ij = in+kv-1, minus the maximum of kp it
00132          gives the index of the last
00133          orginal vertices.
00134          in = in+kv-1, the index of the last element in et. */
00135       
00136       
00137       /* Here we note the special case where we are at the
00138          start of the matrix and we does not have a k-touple
00139          knot at this end. */
00140       
00141       if (kp>=imy) tbeta1=(*ep - *etau)*(*galfa)/(etau[kkv] - *etau);
00142       else         tbeta1=0;
00143       
00144       *jfi=(1>imy-kp) ? 1 : imy-kp;
00145       *jla=(imy < ij-kp) ? imy : ij-kp;
00146       
00147       
00148       /* For details about this loop look in the reference. */
00149       
00150       for (et=etau+ *jfi,tu=etau+ *jla,ah=galfa+ *jfi; et<=tu; et++,ah++)
00151         {
00152           td1 = *ep - *et;
00153           td2 = et[kkv] - *ep;
00154           tbeta = *ah/(td1+td2);
00155           *(ah-1) = td2*tbeta + tbeta1;
00156           tbeta1 = td1*tbeta;
00157         }
00158       
00159       
00160       /* Here we note the special case where we are at the
00161          end of the matrix and we does not have a k-touple
00162          knot at this end. */
00163       
00164       if (*jla<imy)
00165         {
00166           et = etau + in;
00167           *(ah-1) = tbeta1+(*et-*ep)*(*ah)/(*et - *(tu+1));
00168         } else  *(ah-1) = tbeta1;
00169     }
00170   
00171   
00172   /* Adjusting the index of first and last in galfa. */
00173   
00174   if (kv) (*jfi)--;
00175   else   *jfi = *jla = imy;
00176   
00177   if ((*jfi)<0) *jfi = 0;
00178   if ((*jla)>in-ik) *jla = in-ik;
00179   
00180 }

CurveLoop Go::outerBoundarySfLoop ( boost::shared_ptr< ParamSurface >  surf,
double  degenerate_epsilon 
)

Definition at line 12 of file SurfaceTools.C.

References Go::CurveLoop::size().

Referenced by allBoundarySfLoops().

00015 {
00016   // It is convenient to let boundary loops be described as CurveOnSurface
00017   // to store as much information as possible. Due to problems with shared_ptr, 
00018   // this is not possible from within SplineSurface.
00019   // This function is implemented to get around this problem
00020 
00021   boost::shared_ptr<SplineSurface> spline_sf = 
00022     boost::shared_dynamic_cast<SplineSurface, ParamSurface>(surf);
00023 
00024   if (spline_sf.get())
00025     {
00026       // Spline surface
00027       // Test for degeneracy.
00028       bool deg[4];
00029       spline_sf->isDegenerate(deg[0], deg[1], deg[2], deg[3], degenerate_epsilon);
00030       std::vector< shared_ptr< ParamCurve > >  vec;
00031       for (int edgenum = 0; edgenum < 4; ++edgenum) {
00032         if (!deg[edgenum]) {
00033           // Fetch geometry curve
00034           shared_ptr<ParamCurve> edgecurve (spline_sf->edgeCurve(edgenum));
00035 
00036           // Construct curve on surface with knowledge about what it is
00037           int pardir = (edgenum == 1 || edgenum == 3) ? 1 : 2;
00038           double parval;
00039           int boundary;
00040           if (edgenum == 0)
00041             {
00042               parval = spline_sf->startparam_v();
00043               boundary = 2;
00044             }
00045           else if (edgenum == 1)
00046             {
00047               parval = spline_sf->endparam_u();
00048               boundary = 1;
00049             }
00050           else if (edgenum == 2)
00051             {
00052               parval = spline_sf->endparam_v();
00053               boundary = 3;
00054             }
00055           else
00056             {
00057               parval = spline_sf->startparam_u();
00058               boundary = 0;
00059             }
00060           shared_ptr<ParamCurve> sfcv = 
00061             shared_ptr<ParamCurve>(new CurveOnSurface(surf, edgecurve, pardir, 
00062                                                       parval, boundary));
00063           if (edgenum == 2 || edgenum == 3)
00064             sfcv->reverseParameterDirection();
00065           vec.push_back(sfcv);
00066         }
00067       }
00068 
00069       return CurveLoop(vec, degenerate_epsilon);
00070     }
00071   else
00072     {
00073       // VSK, 1109. A similar problem as for spline surface occurs for
00074       // elementary surfaces, but it is currently not handled
00075       // VSK, 0510. Add the surface back pointer
00076       CurveLoop cv_loop = surf->outerBoundaryLoop(degenerate_epsilon);
00077       int nmb_cvs = cv_loop.size();
00078       if (nmb_cvs == 0)
00079         return cv_loop;
00080 
00081       shared_ptr<CurveOnSurface> cv = 
00082         shared_dynamic_cast<CurveOnSurface,ParamCurve>(cv_loop[0]);
00083       if (cv.get())
00084         return cv_loop; // Already curve on surface curves
00085 
00086       // Make new loop with curve-on-surface curves 
00087       vector< shared_ptr< ParamCurve > >  vec;
00088       for (int ki=0; ki<nmb_cvs; ++ki)
00089         {
00090           shared_ptr<ParamCurve> sfcv = 
00091             shared_ptr<ParamCurve>(new CurveOnSurface(surf, cv_loop[ki], false));
00092           vec.push_back(sfcv);
00093         }
00094       return CurveLoop(vec, degenerate_epsilon);
00095     }
00096 }

bool Go::point_inside_contour ( const double  x0,
const double  y0,
const double *const   vertices,
const std::vector< int > &  contour 
) [inline]

Definition at line 274 of file 2dpoly_for_s2m.C.

Referenced by is_inside().

00281   {
00282 #ifndef DBG
00283     const bool dbg=false; // This way, all tests on 'dbg' is removed compile-time when DBG is not defined.
00284 #endif
00285 
00286     //
00287     // At last we enter the old loop for counting intersections.
00288     //
00289     // 090117: Note that the rest of the code is very similar to 'segment_contour_intersection_for_s2m'. In
00290     //         fact, we could have called that one. (Maybe we should have?) The difference is that now we know
00291     //         that the segment is horizontal, (the ray,) and hence the code here can be made (slightly) simpler
00292     //         and faster. One disadvantage is that the two functions (this and
00293     //         'segment_contour_intersection_for_s2m') must agree on how to handle degenerate cases and so
00294     //         on. Otherwise strange problems will occur.
00295 
00296     int crossings=0;
00297 
00298     // const double eps=1e-8; // 100210: Increasing from 1e-12 to 1e-10.
00299     
00300     const double abs_eps = 1e-8;        // 100223: Trying to convert to these
00301     // const double snap_eps = 1e-5;
00302 
00303     const int n=contour.size();
00304   
00305     if (dbg)
00306       printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ n=%d\n", n);
00307 
00308     for (int i=0; i<n; i++)
00309       {
00310         const int j=(i+1)%n, pre_i=(i+n-1)%n;
00311         const double &preb=vertices[contour[pre_i]+1];
00312         const double &prea=vertices[contour[pre_i]];
00313         const double &a=vertices[contour[i]], &b=vertices[contour[i]+1];
00314         const double &c=vertices[contour[j]], &d=vertices[contour[j]+1];
00315       
00316         const double len_squared = (a-c)*(a-c) + (b-d)*(b-d);
00317         if ( (len_squared<abs_eps*abs_eps) && (dbg) )
00318           printf("\n\n  HUH?! Segment with length %e, duplicate corner!\n\n\n", sqrt(len_squared));
00319 
00320 //      if (dbg)
00321 //        printf("  i=%3d: a=%g b=%g c=%g d=%g y0=%g abs_eps=%g !horiz=%d y0-inrange=%d(%d)\n", 
00322 //               i, a, b, c, d, y0, abs_eps, 
00323 //               (fabs(b-d)>abs_eps),
00324 //               ((b-abs_eps<=y0) && (y0<d-abs_eps)),
00325 //               ((d+abs_eps<y0) && (y0<b+abs_eps)));
00326 //      if ( dbg && ((i==77) || (i==79)) )
00327 //        {
00328 //          printf("\n\n\nhold on; plot(%f, %f, 'md', 'markersize', 10, 'linewidth', 3); hold off;\n", x0, y0);
00329 //          printf("line([%f; %f], [%f; %f], 'color', 'm', 'linewidth', 5);\n\n\n", a, c, b, d);
00330 //        }
00331         
00332         //
00333         // 100223: Remember, crossings are counted when occuring at the *start* of segments, not the ends,
00334         //         *except* when the curve has a vertical turn in this "start", i.e., there is a corner
00335         //         "pointing" upward or downward.
00336         //
00337 
00338         const bool not_horizontal_segment = fabs(b-d) > abs_eps;
00339         const bool y0_in_range_1 = (b-y0<=abs_eps) && (abs_eps<d-y0);   // y0 in [b-eps, d-eps)
00340         const bool y0_in_range_2 = (abs_eps<y0-d) && (y0-b<=abs_eps);   // y0 in (d+eps, b+eps]
00341         const bool y0_in_range = y0_in_range_1 || y0_in_range_2;
00342 
00343         if ( not_horizontal_segment && y0_in_range )
00344           {
00345             const double t=(y0-b)/(d-b);        // Where on the segment does the ray cross? t=0 for b, and t=1 for d.
00346           
00347             if (dbg)
00348               printf("  i=%3d: a=%g b=%g c=%g d=%g y0=%g abs_eps=%g !horiz=%d y0-inrange=%d %d\n", 
00349                      i, a, b, c, d, y0, abs_eps, 
00350                      not_horizontal_segment, y0_in_range_1, y0_in_range_2);
00351             
00352             const bool interior = ((t>=abs_eps) && (t<=(1.0-abs_eps)));
00353             const bool start = (fabs(t)<=abs_eps);
00354             const bool going_up = ((preb<b) && (b<d));
00355             const bool going_down = ((preb>b) && (b>d));
00356             const bool not_turning_vertically = going_up || going_down;
00357             const bool actually_crossing = (interior || (start && not_turning_vertically));
00358             const double intersection_x = a+t*(c-a);
00359             if (dbg)
00360               printf("\n\n          t=%g, interior: %d, start: %d, going_up: %d, going_down: %d, "
00361                      "actually_crossing: %d, inters_x: %g",
00362                      t, interior, start, going_up, going_down, actually_crossing, intersection_x);
00363             if (dbg)
00364               printf("\n          preb=%g, b=%g, d=%g    x-values: %g %g %g", preb, b, d, prea, a, c);
00365             if ( actually_crossing && (intersection_x > x0+abs_eps) )
00366               {
00367                 crossings++;
00368                 if (dbg) printf(", CROSSES ");
00369                 if (dbg)
00370                   {
00371                     printf("\n\n\nhold on; plot(%f, %f, 'md', 'markersize', 10, 'linewidth', 3); hold off;\n", x0, y0);
00372                     printf("line([%f; %f], [%f; %f], 'color', 'm', 'linewidth', 5);\n\n\n", a, c, b, d);
00373                   }
00374               }
00375             else
00376               if (dbg)
00377                 {
00378                   if (actually_crossing)
00379                     printf("\n          intersection_x too small: %e vs. x0=%e, inters_x-x0=%e", 
00380                            intersection_x, x0, intersection_x-x0);
00381                   printf("\n\n\nhold on; plot(%f, %f, 'bd', 'markersize', 10, 'linewidth', 3); hold off;\n", x0, y0);
00382                   printf("line([%f; %f], [%f; %f], 'color', 'b', 'linewidth', 5);\n\n\n", a, c, b, d);
00383                 }
00384             if (dbg) printf("\n");
00385           }
00386       
00387       }
00388     if (dbg) printf("  Crossings in total: %d, i.e., %s\n", crossings, ((crossings & 1)==1) ? "INSIDE" : "OUTSIDE");
00389   
00390     return ((crossings & 1)==1);
00391   }

bool Go::point_on_contour ( const double  x0,
const double  y0,
const double *const   vertices,
const vector< int > &  contour 
) [inline]

Definition at line 438 of file 2dpoly_for_s2m.C.

Referenced by is_on_contour().

00444   {
00445 #ifndef DBG
00446     const bool dbg=false; // This way, all tests on 'dbg' is removed compile-time when DBG is not defined.
00447 #endif
00448 
00449     //const double eps=1e-12;   // 090115: Used for zero-tests for degeneracy and parallellity tests.
00450     // 090203: Here it is also used for testing if a point is on a curve segment.
00451     //const double eps=1e-8;    // 090203: Need 1e-8 for proper meshing of 'bin_p1_3.g2'.
00452     //const double eps=1e-6;    // 100213: See comments below.
00453     const double eps=1e-5;      // 100214: Reverting to 1e-8, think the need to have 1e-6 is really another problem
00454                                 // 100218: Keeping 1e-5 after discussion with Vibeke.
00455 
00456     const double tau=1e-12;     // 090115: Used for zero-tests for distances in the parameter domain.
00457                                 // 100214: Changed from 1e-14 to 1e-12, not needed right now, but 1e-14 seems small.
00458 
00459     const int n=contour.size();
00460     if (dbg) printf("  point_on_contour for (%f, %f), %d segments.\n", x0, y0, n);
00461     for (int i=0; i<n; i++)
00462       {
00463         const int j=(i+1)%n;
00464         const double &x2=vertices[contour[i]], &y2=vertices[contour[i]+1];
00465         const double &x3=vertices[contour[j]], &y3=vertices[contour[j]+1];
00466         const double contour_segment_length_squared = (x3-x2)*(x3-x2) + (y3-y2)*(y3-y2);
00467 
00468         if (contour_segment_length_squared>tau*tau)
00469           {
00470             // We project (x0, y0) onto the segment, and measure the distance.
00471             // The projection will be (x2, y2) + s*[(x3, y3)-(x2, y2)].
00472             const double s = ( (x0-x2)*(x3-x2) + (y0-y2)*(y3-y2) ) / contour_segment_length_squared;
00473 
00474             // 100213: Hmm... Checking for s in (-tau, 1+tau) is no good, if 1+tau==1. Better to use (-eps,
00475             //         1+eps) when eps is larger than tau, but this does not solve the problem! Which is that
00476             //         's' is not a measure of distance. Should rather use
00477             //         s*sqrt(contour_segment_length_squared)! 
00478             //
00479             // 100214: But, then, remember that the interval should be [0,
00480             //         sqrt(contour_segment_length_squared)].
00481             //
00482             // 100213: Hmm again. Seems that 1e-8 (and 1e-7!) for some reason is too restrictive. (How can this
00483             //         be?!)  Changing to 1e-6. 
00484             //
00485             // 100214: Suspect that the reason for 1e-8 being to large is that something else is really wrong
00486             //         with the contour of the test case. (Folding back onto itself or something strange?!)
00487 
00488             const double s2 = s * sqrt(contour_segment_length_squared);
00489 
00490             if ( (dbg) && (0) )
00491               {
00492                 printf("    %3d: (x2, y2) = (%f, %f), (x3, y3) = (%f, %f)\n", i, x2, y2, x3, y3);
00493                 printf("line([%f; %f], [%f; %f], 'color', 'y', 'linewidth', 5);\n", x2, x3, y2, y3);
00494                 printf("         s=%f, s2=%f\n", s, s2);
00495               }
00496 
00497             // if ((s>-tau) && (s<1.0+tau))
00498             // if ((s>=-eps) && (s<=1.0+eps))
00499             // if ((s2>=-eps) && (s2<=1.0+eps))
00500             if ( (s2>=-eps) && (s2<=sqrt(contour_segment_length_squared)+eps) )
00501               {
00502                 const double x = x2 + s*(x3-x2), y = y2 + s*(y3-y2);
00503                 const double dist_squared = (x-x0)*(x-x0) + (y-y0)*(y-y0);
00504                 if (dbg) printf("\t\t\t\t\t\t\t\t\t\tdist to segment = %e\n", sqrt(dist_squared));
00505 
00506                 // 100214: That the tolerance required in the next test is as large as 1e-4 really shows that
00507                 //         the trimming curve is crappy, so by using 1-e4 we are really just hiding a symptom...
00508 
00509                 if (dist_squared<eps*eps)
00510                   //if (dist_squared<1e-6*1e-6)
00511                   //if (dist_squared<1e-4*1e-4)
00512                   {
00513                     if (dbg) printf("TRUE\n");
00514                     return true;
00515                   }
00516               }
00517           }
00518         else
00519           {
00520             //
00521             // 090117: The contour segment is degenerate, and will be treated as a point.
00522             //
00523             // 100214: We should not get here, duplicate points should have been removed, but it's no harm in
00524             //         keeping the branch I guess...
00525             //
00526             const double mx = 0.5*(x2+x3), my = 0.5*(y2+y3);
00527             const double dist_squared = (x0-mx)*(x0-mx) + (y0-my)*(y0-my);
00528             if (dist_squared<eps*eps)
00529               {
00530                 if (dbg) printf("TRUE\n");
00531                 return true;
00532               }
00533           }
00534       }
00535 
00536     if (dbg) printf("FALSE\n");
00537     return false;
00538   }

bool Go::point_on_contour_corner ( const double  x0,
const double  y0,
const double *const   vertices,
const vector< int > &  contour 
)

Definition at line 405 of file 2dpoly_for_s2m.C.

Referenced by is_on_corner().

00407   {
00408     const double eps=1e-13; // 090115: Used for zero-tests for distances in the parameter domain.
00409     //         Hmm... these should *really*, *really* be taken from some global variable
00410     //         or something
00411     for (int ilim=contour.size(), i=0; i<ilim; i++)
00412       {
00413         const double &corner_u=vertices[contour[i]], &corner_v=vertices[contour[i]+1];
00414         const double dist_squared = (corner_u-x0)*(corner_u-x0) + (corner_v-y0)*(corner_v-y0);
00415 
00416         if (dist_squared<eps*eps)
00417           return true;
00418       }
00419     return false;
00420   }

bool Go::point_on_segment ( const double  x0,
const double  y0,
const double  x2,
const double  y2,
const double  x3,
const double  y3,
const double  zero_eps,
const double  snap_eps 
)

Definition at line 551 of file 2dpoly_for_s2m.C.

Referenced by segment_contour_intersection_for_s2m().

00560   {
00561 #ifndef DBG
00562     const bool dbg = false; // This way, all tests on 'dbg' is removed compile-time when DBG is not defined.
00563 #endif
00564 
00565     const double t = ( (x0-x2)*(x3-x2) + (y0-y2)*(y3-y2) ) / ( (x3-x2)*(x3-x2) + (y3-y2)*(y3-y2) );
00566     const double x = x2 + t*(x3-x2) - x0;
00567     const double y = y2 + t*(y3-y2) - y0;
00568     const double dist = sqrt( x*x+y*y );
00569     if ( (dist<snap_eps) && (t>=-zero_eps) && (t-zero_eps<=1.0) )
00570       {
00571         if (dbg)
00572           {
00573             printf("    END TESTS 2: t=%f, dist=%f\n", t, dist);
00574             // printf("\nline([%f; %f], [%f; %f], 'color', 'k', 'linewidth', 6);\n", x0, x1, y0, y1);
00575             printf("line([%f; %f], [%f; %f], 'color', 'y', 'linewidth', 6);\n", x2, x3, y2, y3);
00576           }
00577         return true;
00578       }
00579 
00580     return false;
00581   }

void Go::principalCurvatures ( const ParamSurface &  sf,
double  u,
double  v,
double &  k1,
Point &  d1,
double &  k2,
Point &  d2 
)

Definition at line 94 of file CurvatureAnalysis.C.

References computeSecondFundamentalForm(), Go::ParamSurface::point(), and Go::Point::setValue().

Referenced by evaluateMinCurvatureRadius().

00099 {
00100     double resolution = 1.0e-15;
00101 
00102     // Compute surface derivatives
00103     int derivs = 1;
00104     std::vector<Point> pts(3);
00105     sf.point(pts, u, v, derivs);
00106     Point Su = pts[1];
00107     Point Sv = pts[2];
00108 
00109     // Compute 1. and 2. fundamental form
00110     double I[3];
00111     double II[3];
00112     computeSecondFundamentalForm(sf, u, v, I, II);
00113     double denom = I[0]*I[2]-I[1]*I[1];
00114 
00115     // Calculate the transformation matrix
00116     double transform[4]; // The sequence is a11, a12, a21, a22.        
00117     transform[0] = (I[1]*II[1] - I[2]*II[0])/denom;
00118     transform[1] = (I[1]*II[2] - I[2]*II[1])/denom;
00119     transform[2] = (I[1]*II[0] - I[0]*II[1])/denom;
00120     transform[3] = (I[1]*II[1] - I[0]*II[2])/denom;
00121    
00122     // Initialize the principal directions to the parameter directions
00123     d1.setValue(1.0, 0.0);
00124     d2.setValue(0.0, 1.0);
00125 
00126     // Calculate the principal curvatures
00127     double a = 1.;
00128     double b = transform[0] + transform[3];
00129     double c = transform[0]*transform[3] - transform[1]*transform[2];
00130       
00131     double sqrt_arg = b*b - 4.*a*c;
00132     if (sqrt_arg < resolution)
00133       {
00134          k1 = - b/(2.*a);
00135          k2 = k1;
00136          return;
00137       }
00138 
00139     k1 = (- b + sqrt(sqrt_arg))/(2.*a);
00140     k2 = (- b - sqrt(sqrt_arg))/(2.*a);
00141       
00142     // Calculate the curvature directions.
00143     double ratio, length; 
00144 
00145     // Direction corresponding to the maximal curvature
00146     if (fabs(transform[0] + k1) < resolution &&
00147              fabs(transform[1]) < resolution)
00148     {
00149         // Parallel to u direction
00150         length = 1./sqrt(Su[0]*Su[0] + Su[1]*Su[1] + Su[2]*Su[2]);
00151         d1.setValue(length, 0.0);
00152     }
00153     else if (fabs(transform[3] + k1) < resolution &&
00154                   fabs(transform[2]) < resolution)
00155     {
00156         // Parallel to v direction
00157         length = 1./sqrt(Sv[0]*Sv[0] + Sv[1]*Sv[1] + Sv[2]*Sv[2]);
00158         d1.setValue(0.0, length);
00159     }
00160     else if (fabs(transform[0] + k1) < fabs(transform[1]))
00161     {
00162         ratio = (transform[0] + k1)/transform[1];
00163         length = 1./sqrt((Su[0] - ratio*Sv[0])*(Su[0] - ratio*Sv[0]) +
00164                          (Su[1] - ratio*Sv[1])*(Su[1] - ratio*Sv[1]) +
00165                          (Su[2] - ratio*Sv[2])*(Su[2] - ratio*Sv[2]));
00166         d1.setValue(length, -ratio*length);
00167     }
00168     else
00169     {
00170         ratio = transform[1]/(transform[0] + k1);
00171         length = 1./sqrt((Sv[0] - ratio*Su[0])*(Sv[0] - ratio*Su[0]) +
00172                          (Sv[1] - ratio*Su[1])*(Sv[1] - ratio*Su[1]) +
00173                          (Sv[2] - ratio*Su[2])*(Sv[2] - ratio*Su[2]));
00174         d1.setValue(-ratio*length, length);
00175     }
00176 
00177     // Minimal curvature direction
00178     if (fabs(transform[0] + k2) < resolution &&
00179              fabs(transform[1]) < resolution)
00180     {
00181         // Parallel to u direction
00182         length = 1./sqrt(Su[0]*Su[0] + Su[1]*Su[1] + Su[2]*Su[2]);
00183         d2.setValue(length, 0.0);
00184     }
00185     else if (fabs(transform[3] + k2) < resolution &&
00186                   fabs(transform[2]) < resolution)
00187     {
00188         // Parallel to v direction
00189         length = 1./sqrt(Sv[0]*Sv[0] + Sv[1]*Sv[1] + Sv[2]*Sv[2]);
00190         d2.setValue(0.0, length);
00191     }
00192     else if (fabs(transform[0] + k2) < fabs(transform[1]))
00193     {
00194         ratio = (transform[0] + k2)/transform[1];
00195         length = 1./sqrt((Su[0] - ratio*Sv[0])*(Su[0] - ratio*Sv[0]) +
00196                          (Su[1] - ratio*Sv[1])*(Su[1] - ratio*Sv[1]) +
00197                          (Su[2] - ratio*Sv[2])*(Su[2] - ratio*Sv[2]));
00198         d2.setValue(length, -ratio*length);
00199     }
00200     else
00201     {
00202         ratio = transform[1]/(transform[0] + k2);
00203         length = 1./sqrt((Sv[0] - ratio*Su[0])*(Sv[0] - ratio*Su[0]) +
00204                          (Sv[1] - ratio*Su[1])*(Sv[1] - ratio*Su[1]) +
00205                          (Sv[2] - ratio*Su[2])*(Sv[2] - ratio*Su[2]));
00206         d2.setValue(-ratio*length, length);
00207     }
00208 
00209          
00210 
00211 }

shared_ptr<ParamCurve> Go::projectCurve ( shared_ptr< ParamCurve >  incurve,
const Point &  normal,
bool  planar 
)

Definition at line 18 of file projectCurve.C.

References ALWAYS_ERROR_IF, Class_Line, Class_SplineCurve, Go::Point::dimension(), MESSAGE, MESSAGE_IF, and projectCurve().

00021 {
00022   int dim = incurve->dimension();
00023   ALWAYS_ERROR_IF(dim != 2 && dim != 3, "Dimension must be 2 or 3");
00024   ALWAYS_ERROR_IF(dim!=2 && dim!=normal.dimension(),
00025                   "Error in dimension.");
00026 
00027   if (incurve->instanceType() == Class_Line)
00028     {
00029       shared_ptr<Line> line = shared_dynamic_cast<Line, ParamCurve>(incurve);
00030       MESSAGE_IF(!line->isBounded(), "Line not bounded.");
00031 
00032       shared_ptr<SplineCurve> spline_cv(line->geometryCurve());
00033       shared_ptr<SplineCurve> proj_cv =
00034         projectCurve(*spline_cv, normal, planar);
00035 
00036       Point from_pt = proj_cv->ParamCurve::point(line->startparam());
00037       Point to_pt = proj_cv->ParamCurve::point(line->endparam());
00038       Point dir_vec = to_pt - from_pt;
00039       shared_ptr<ParamCurve> proj_line =
00040         shared_ptr<Line>(new Line(from_pt, dir_vec));
00041       proj_line->setParameterInterval(line->startparam(), line->endparam());
00042       return proj_line;
00043     }
00044   else if (incurve->instanceType() == Class_SplineCurve)
00045     {
00046       shared_ptr<SplineCurve> spline_cv =
00047         shared_dynamic_cast<SplineCurve, ParamCurve>(incurve);
00048       return projectCurve(*spline_cv, normal, planar);
00049     }
00050   else {
00051       shared_ptr<SplineCurve> spline_cv(incurve->geometryCurve());
00052       if (spline_cv.get() == NULL) {
00053           MESSAGE("Unexpected curve type!");
00054       } else {
00055           return projectCurve(*spline_cv, normal, planar);
00056       }
00057   }
00058 
00059   return shared_ptr<ParamCurve>();
00060 }

shared_ptr< SplineCurve > Go::projectCurve ( const SplineCurve &  incurve,
const Point &  normal,
bool  planar 
)

Project a 3D SplineCurve into a given plane.

The curve can be returned either as a 3D curve lying in the plane or as a 2D curve. In the latter case, the coordinate system is rotated such that the given plane normal coincides with the z-axis.

Parameters:
incurve the curve to project
normal the normal to the plane of projection
planar 'true' if we want the returned curve to be a 2D curve.
Returns:
a shared pointer to a newly constructed, planar SplineCurve expressing the projection of 'incurve' onto the given plane.

Definition at line 63 of file projectCurve.C.

References ALWAYS_ERROR_IF, Go::SplineCurve::basis(), Go::BsplineBasis::begin(), Go::SplineCurve::coefs_begin(), Go::Point::dimension(), Go::SplineCurve::dimension(), Go::Point::normalize(), Go::SplineCurve::numCoefs(), Go::SplineCurve::order(), Go::SplineCurve::rational(), and Go::SplineCurve::rcoefs_begin().

00075 {
00076   int dim = incurve.dimension();
00077   ALWAYS_ERROR_IF(dim != 2 && dim != 3, "Dimension must be 2 or 3");
00078   ALWAYS_ERROR_IF(dim!=2 && dim!=normal.dimension(),
00079                   "Error in dimension.");
00080 
00081   // Make sure that the given normal is normalized.
00082   Point norm = normal;
00083   norm.normalize();
00084 
00085   // Fetch the coefficients of the input curve
00086   int nmbcoef = incurve.numCoefs();
00087   bool rational = incurve.rational();
00088   std::vector<double>::const_iterator coefs;
00089   if (rational)
00090     coefs = incurve.rcoefs_begin();
00091   else
00092     coefs = incurve.coefs_begin();
00093   int dim1 = dim + (rational);
00094 
00095   // Find the position of the plane which approximates
00096   // the input curve best. First compute the mean distance
00097   // from the curve coefficients to the plane with the given 
00098   // normal passing through origo.
00099   double meandist = 0.0, dist;
00100   int ki, kj;
00101   std::vector<double>::const_iterator co;
00102   std::vector<double>::iterator co2, co3;
00103   for (ki=0, co=coefs; ki<nmbcoef; ki++, co+=dim1)
00104     {
00105       for (kj=0, dist=0.0; kj<dim; kj++)
00106         dist += co[kj]*norm[kj];
00107       meandist += dist;
00108     }
00109   meandist /= (double)nmbcoef;
00110 
00111   // The point in the plane
00112   Point point(meandist*norm);
00113 
00114   // Project the coefficients into the found plane
00115   std::vector<double> coef2(dim1*nmbcoef);
00116   for (ki=0, co=coefs, co2=coef2.begin(); ki<nmbcoef; ki++, co+=dim1, co2+=dim1)
00117     {
00118       Point pp(co[0],co[1],co[2]);
00119       double td = (point - pp)*norm;
00120       for (kj=0; kj<dim; kj++)
00121         co2[kj] = co[kj] - td*norm[kj];
00122       if (rational)
00123         co2[dim] = co[dim];   // Keep the weight
00124     }
00125 
00126   SplineCurve *planecrv;
00127   if (planar)
00128     {
00129       // Rotate coordinate system such that the z-axis coincides
00130       // with the given plane normal, and express the coefficients in 
00131       // this coordinate system. Remove z in each coefficient.
00132       std::vector<double> coef3((dim1-1)*nmbcoef);
00133       double tdum;
00134       for (co3=coef3.begin(), co2=coef2.begin(), ki=0; ki<nmbcoef; 
00135            ki++, co3+=(dim1-1), co2+=dim1)
00136         {
00137           co3[0] = norm[2]*co2[0] + norm[0]*co2[1] + norm[1]*co2[2];
00138           co3[1] = norm[1]*co2[0] + norm[2]*co2[1] + norm[0]*co2[2];
00139           tdum = norm[0]*co2[0]+norm[1]*co2[1]+norm[2]*co2[2];
00140           if (rational)
00141             co3[2] = co2[dim];
00142         }
00143       
00144       planecrv = new SplineCurve(nmbcoef, incurve.order(),
00145                                    incurve.basis().begin(),
00146                                    coef3.begin(), 2, rational);
00147     }
00148   else
00149     planecrv = new SplineCurve(nmbcoef, incurve.order(),
00150                                incurve.basis().begin(),
00151                                coef2.begin(), 3, rational);
00152 
00153   return shared_ptr<SplineCurve>(planecrv);
00154 }

boost::shared_ptr<ParamCurve> GO_API Go::projectCurve ( boost::shared_ptr< ParamCurve >  incurve,
const Point &  normal,
bool  planar 
)

Referenced by projectCurve().

double Go::pt_dist_from_line ( const Vector2D p,
const Vector2D A,
const Vector2D B 
) [inline]

Definition at line 998 of file spline2mesh.C.

Referenced by pt_dist_from_tri_edge().

00999   {
01000     const double t = ((p-A)*(B-A))/((B-A)*(B-A));
01001     const Vector2D proj = A+t*(B-A);
01002     return sqrt((proj-p)*(proj-p));
01003   }

double Go::pt_dist_from_tri_edge ( const Vector2D p,
const Vector2D c1,
const Vector2D c2,
const Vector2D c3 
) [inline]

Definition at line 1005 of file spline2mesh.C.

References pt_dist_from_line().

01006   {
01007     return std::min(pt_dist_from_line(p, c1, c2),
01008                     std::min(pt_dist_from_line(p, c2, c3), pt_dist_from_line(p, c3, c1)));
01009   }

bool Go::pt_inside_tri ( const Vector3D p,
const Vector3D c1,
const Vector3D c2,
const Vector3D c3 
) [inline]

Definition at line 971 of file spline2mesh.C.

Referenced by make_trimmed_mesh().

00972   {
00973     const Vector2D e=c2-c1, f=c3-c1, pc=p-c1;
00974     const double ee=e*e, ff=f*f, ef=e*f;
00975 #if 0
00976     // This is faster on x86 than allocating new variables for pc*e and pc*f, it seems...
00977     const double u = ff*(pc*e) - ef*(pc*f);
00978     const double v = ee*(pc*f) - ef*(pc*e);
00979 #else
00980     // Not on core2 is seems...
00981     const double pce=pc*e, pcf=pc*f;
00982     const double u = ff*pce - ef*pcf;
00983     const double v = ee*pcf - ef*pce;
00984 #endif
00985 
00986     return ((u>=0.0) && (v>=0.0) && (u+v<=ee*ff-ef*ef));
00987   }

void Go::push_an_intersection ( const boost::shared_ptr< SplineSurface srf,
const Vector3D c1,
const Vector3D c2,
const Vector2D c1_p,
const Vector2D c2_p,
const Vector3D n1,
const Vector3D n2,
const double &  s,
vector< Vector3D > &  vert,
vector< Vector2D > &  vert_p,
vector< Vector3D > &  norm,
vector< int > &  bd 
) [inline]

Definition at line 505 of file spline2mesh.C.

References Go::Array< T, Dim >::normalize().

Referenced by split_triangle().

00513   {
00514     vert_p.push_back(  (1.0-s)*c1_p + s*c2_p );
00515 
00516 #ifndef EVAL_SRF_NOT_INTERP
00517     vert  .push_back(  (1.0-s)*c1   + s*c2   );
00518     Vector3D tmp =     (1.0-s)*n1   + s*n2;
00519     tmp.normalize();
00520     norm.push_back(tmp);
00521     bd.push_back(1);
00522 #else
00523     vector<Point> res(3);
00524     srf->point(res, vert_p.back()[0], vert_p.back()[1], 1); // Could we have used 0 here? 
00525 
00526     // The point on the surface:
00527     vert.push_back( Vector3D(res[0].begin()) );
00528 
00529     // The normal in the same point:
00530     const Point nrm = res[1].cross(res[2]);
00531     Vector3D tmp = Vector3D(nrm);
00532     tmp.normalize();
00533     norm.push_back(tmp);
00534     
00535     // This is Vibeke's, don't know what it's for...
00536     bd.push_back(1);
00537 #endif
00538 
00539   }

double Go::quadrinomial ( int  n,
int  i,
int  j,
int  k 
) [inline]

computes the quadrinomial coefficient: n! / (i! j! k! (n-i-j-k)!)

Definition at line 77 of file binom.h.

References binom().

00078 {
00079     if (i < 0 || i > n || j < 0 || j > n || k < 0 || k > n)
00080         return 0;
00081 
00082     return binom(n, i) * binom(n-i, j) * binom(n-i-j, k);
00083 }

void Go::refmatrix ( double *  et,
int  im,
int  ik,
double *  etau,
int  in,
double *  ea,
int *  nfirst,
int *  nlast 
)

Corresponds to sh1922 in SISL Computes the B-spline refinement transformation matrix from the spline space generated by the knot vector etau to the refined spline space generated by the refined knot vector et.

Parameters:
et Real array of length (im+ik) containing the refined knot vector.
im The dimension of the spline space corresponding to et.
ik The order of the spline space.
etau Real array of length (in+ik) containing the original knot vector.
in The dimension of the spline space corresponding to etau.
ea Real array of dimension (im*ik) containing the B-spline refinement matrix from the knot vector etau to the knot vector et. This matrix has dimension im*in but since at most ik entries are nonzero in each row, it can be stored in a im*ik array together with two integer arrays indicating the position of the first and last nonzero elements in each row.
nfirst Integer array of dimension (im) containing pointers to the first nonzero element of each row of the B-spline refinement matrix from etau to et.
nlast Integer array of dimension (im) containing pointers to the last nonzero element of each row of the B-spline refinement matrix from etau to et.

Definition at line 20 of file refmatrix.C.

References osloalg().

00027              : To compute the B-spline refinement transformation matrix
00028 *              from the spline space generated by the knot vector etau
00029 *              to the refined spline space generated by the refined knot
00030 *              vector et.
00031 * 
00032 * INPUT      : et     - Real array of length (im+ik) containing the refined
00033 *                       knot vector.
00034 *              im     - The dimension of the spline space corresponding to et.
00035 *              ik     - The order of the spline space.
00036 *              etau   - Real array of length (in+ik) containing the original 
00037 *                       knot vector.
00038 *              in     - The dimension of the spline space corresponding
00039 *                       to etau.
00040 *
00041 * 
00042 * OUTPUT     : ea     - Real array of dimension (im*ik) containing 
00043 *                       the B-spline refinement matrix from the knot vector
00044 *                       etau to the knot vector et. This matrix has
00045 *                       dimension im*in but since at most
00046 *                       ik entries are nonzero in each row, it can
00047 *                       be stored in a im*ik array together
00048 *                       with two integer arrays indicating the position
00049 *                       of the first and last nonzero elements in each
00050 *                       row.
00051 *              nfirst - Integer array of dimension (im) containing 
00052 *                       pointers to the first nonzero element of each row 
00053 *                       of the B-spline refinement matrix from etau to et.
00054 *              nlast  - Integer array of dimension (im) containing 
00055 *                       pointers to the last nonzero element of each row 
00056 *                       of the B-spline refinement matrix from etau to et.
00057 *              jstat      - status messages  
00058 *                                         > 0      : warning
00059 *                                         = 0      : ok
00060 *                                         < 0      : error
00061 *             
00062 * 
00063 * METHOD     : 
00064 *
00065 *
00066 * REFERENCES : 
00067 *              
00068 *
00069 * USE        :
00070 *
00071 *-
00072 * CALLS      :   
00073 *
00074 * WRITTEN BY : Vibeke Skytt, SI, 05.92, on the basis of a routine
00075 *              written by Tom Lyche and Knut Moerken, 12.85.
00076 * REVISED BY : Vibeke Skytt, Sintef, 19/04/2002. Go-ified.
00077 *
00078 *********************************************************************
00079 */
00080 {
00081    int kj1,kj2;
00082    int kih1,kih2;
00083    int ki,kj,kjh,kkj;
00084    int kmu;
00085    int kpl, kfi, kla;
00086 
00087    std::vector<double> sahvec(2*ik, 0.0);
00088    double *sah = &sahvec[0];
00089    
00090    /* The first and last few rows of the refinement matrix ea may contain
00091       only zeroes. The first task is to find the first and the last
00092       nonzero rows (pointed at by kj1 and kj2).  First kj2 are determined. */
00093 
00094    for (kmu=in+ik-1; etau[kmu-1] == etau[kmu]; kmu--);
00095    
00096    for (kjh=im-1; et[kjh+ik]>etau[kmu]; kjh--);
00097    
00098    ki = kjh;
00099    if (et[kjh+ik] == etau[kmu])
00100       {
00101          for (; et[ki-1+ik] == et[kjh+ik]; ki--);
00102       }
00103       
00104    kj2 = std::min(im-1,ki+in+ik-kmu-1);
00105    
00106    /* Determine kj1.  */
00107        
00108    for (kmu=0; etau[kmu+1] == etau[kmu]; kmu++);
00109    
00110    for (kjh=0; et[kjh]<etau[kmu]; kjh++);
00111    
00112    ki = kjh;
00113    if (et[kjh] == etau[kmu])
00114       {
00115          for (; et[ki+1] == et[kjh]; ki++);
00116       }
00117    kj1 = std::max(0,ki-kmu);      
00118       
00119 //     /*  Set all elements of ea to zero. */
00120       
00121 //     memzero(ea,im*ik,DOUBLE);
00122    
00123    /* Determine the refinement transformation.  */
00124    /* Indicate that rows 1,2,..,kj1 of ea are zero by setting nfirst>nlast
00125       for these rows.  */
00126    
00127    for (kj=0; kj<kj1; kj++)
00128      {
00129         nfirst[kj] = ik;
00130         nlast[kj] = 0;
00131      }
00132    
00133    /* Similarily for rows kj2+1, ... im-1 of ea.  */
00134    
00135    for (kj=kj2+1; kj<im; kj++)
00136      {
00137         nfirst[kj] = ik;
00138         nlast[kj] = 0;
00139      }
00140    
00141    /* Compute rows kj1 to kj2 of ea. */
00142    
00143    for (kj=kj1; kj<=kj2; kj++)
00144      {
00145        for (; etau[kmu+1] <= et[kj]; kmu++);
00146        kkj = kj;
00147        Go::osloalg(kkj, kmu, ik, in, &kpl, &kfi, &kla,
00148                    et, etau, sah);
00149        //       sh1929(etau,in,ik,kmu,et,im,kkj,sah,&kmuprm,&knu,&kstat);
00150        //       if (kstat < 0) goto error;
00151                        
00152        /* Get the pointers right.  */
00153                        
00154        //         nfirst[kj] = MAX(kmuprm-knu,0);
00155        //         nlast[kj] = MIN(kmuprm,in-1);
00156        //         kih1 = nfirst[kj] + ik - kmuprm - 1;
00157        //         kih2 = nlast[kj] + ik - kmuprm - 1;
00158        nfirst[kj] = std::max(kfi, 0);
00159        nlast[kj] = std::min(kla, in-1);
00160        kih1 = kfi + kpl;
00161        kih2 = kpl + kla;
00162        for (ki=kih1; ki<=kih2; ki++)
00163          ea[kj*ik+ki] = sah[ki];
00164      }
00165 
00166    /* Refinement transformation matrix computed.  */
00167 
00168 
00169 }

template<class T >
void Go::Register (  )  [inline]

This function is used to register a class derived from GeomObject with the global Factory.

By using this function rather than Factory::registerClass(), the user does not have to worry about the details of the Creator class. To register a class

 DerivedClass 

, it should be sufficient to run:

 Register<DerivedClass>() 

.

Definition at line 128 of file Factory.h.

References f(), Go::Factory::globalFactory(), and Go::Factory::registerClass().

00129     {
00130         Factory* f = Factory::globalFactory();
00131         ConcreteCreator<T>* c = new ConcreteCreator<T>;
00132         f->registerClass(T::classType(), c);
00133         delete c;
00134     }

boost::shared_ptr< SplineSurface > Go::representCurveAsSurface ( const SplineCurve &  curve,
int  cv_dir,
const BsplineBasis &  other_bas,
bool  rational 
)

Describe a curve as surface in a given direction.

The surface output is rational if the argument rational is set to 'true'. In that case the curve is supposed to live in homogenous space. Describe a curve as a lower-dimensional surface in a given direction.

Parameters:
curve the curve that we want to express as a surface
cv_dir If this variable is set to '1', then the curve's parameter will become the first parameter in the generated surface. If it is set to '2', the curve's parameter will become the second parameter in the generated surface. Other values are illegal.
other_bas the BsplineBasis for the additional parameter direction.
rational define whether the generated surface shall be specified as rational or not.
Returns:
a shared pointer to a new SplineSurface, expressing the curve in a space of lower dimensionality.

Definition at line 625 of file GeometryTools.C.

References Go::SplineCurve::basis(), Go::SplineCurve::coefs_begin(), Go::SplineCurve::dimension(), Go::SplineCurve::numCoefs(), Go::BsplineBasis::numCoefs(), Go::SplineCurve::rational(), and THROW.

Referenced by Go::SplineSurface::appendSurface(), Go::SplineSurface::subSurface(), and unifySurfaceSplineSpaceOneDir().

00630 {
00631     if (curve.rational()) {
00632         THROW("It does not make sense to have a rational hypercurve.");
00633     }
00634   int kdim = curve.dimension()/other_bas.numCoefs();
00635   std::vector<double>::const_iterator co
00636       = curve.coefs_begin();
00637   std::vector<double> surf_coefs;
00638   std::vector<double>::const_iterator coefstart;
00639   const BsplineBasis& bas = curve.basis();
00640   if (cv_dir!=2) {
00641     // We must flip the curve coefficients
00642     int nu = curve.numCoefs();
00643     int nv = other_bas.numCoefs();
00644     surf_coefs.reserve(nu*nv*kdim);
00645     for (int i = 0; i < nv; ++i)
00646       for (int j = 0; j < nu; ++j)
00647         for (int k = 0; k < kdim; ++k)
00648           surf_coefs.push_back(co[(j*nv+i)*kdim + k]);
00649     coefstart = surf_coefs.begin();
00650   } else {
00651     coefstart = co;
00652   }
00653   int dim = rational ? kdim - 1 : kdim;
00654   boost::shared_ptr<SplineSurface> surface
00655     (new SplineSurface((cv_dir==1) ? bas : other_bas,
00656                          (cv_dir==1) ? other_bas : bas, 
00657                          coefstart, dim, rational));
00658   return surface;
00659 }

boost::shared_ptr< SplineCurve > Go::representSurfaceAsCurve ( const SplineSurface &  surface,
int  cv_dir 
)

Describe a surface as a high-dimensional curve in a given direction.

If the surface is rational, the curve will be non-rational and living in the homogenous space.

Parameters:
surface the surface to express as a curve
cv_dir the parameter direction that will be kept when defining the curve (the other one will disappear, as the control points in this direction will be lumped together and expressed as single control points in a higher-dimensional space. 'cv_dir' takes either the value '1' (keep the first parameter direction) or '2' (keep the second parameter direction).
Returns:
shared pointer to a new SplineCurve, expressing the surface as a curve in a high-dimensional space.

Definition at line 584 of file GeometryTools.C.

References Go::SplineSurface::basis(), Go::BsplineBasis::begin(), Go::SplineSurface::coefs_begin(), Go::SplineSurface::dimension(), Go::BsplineBasis::numCoefs(), Go::SplineSurface::numCoefs_u(), Go::SplineSurface::numCoefs_v(), Go::BsplineBasis::order(), Go::SplineSurface::rational(), and Go::SplineSurface::rcoefs_begin().

Referenced by analyzePeriodicity(), analyzePeriodicityDerivs(), Go::SplineSurface::appendSurface(), Go::SplineSurface::subSurface(), and unifySurfaceSplineSpaceOneDir().

00586 {
00587   int dim = surface.dimension();
00588   int kdim = dim + (surface.rational() ? 1 : 0);
00589   const std::vector<double>::const_iterator co = (surface.rational()) ?
00590     surface.rcoefs_begin() : surface.coefs_begin();
00591   std::vector<double> huge_curve_coefs;
00592   std::vector<double>::const_iterator coefstart; 
00593   if (cv_dir != 2) {
00594     // We must flip the surface coefficients
00595     int nu = surface.numCoefs_u();
00596     int nv = surface.numCoefs_v();
00597     huge_curve_coefs.reserve(nu*nv*kdim);
00598     for (int i = 0; i < nu; ++i)
00599       for (int j = 0; j < nv; ++j)
00600         for (int k = 0; k < kdim; ++k)
00601           huge_curve_coefs.push_back(co[(j*nu+i)*kdim + k]);
00602     coefstart = huge_curve_coefs.begin();
00603   } else {
00604     coefstart = co;
00605   }
00606   
00607     const BsplineBasis& bas = surface.basis(2-cv_dir);
00608     const BsplineBasis& other_bas = surface.basis(cv_dir-1);
00609 
00610     int num = other_bas.numCoefs();
00611     int order = other_bas.order();
00612     std::vector<double>::const_iterator knotstart = other_bas.begin();
00613 
00614     int dim2 = bas.numCoefs() * kdim;
00615     shared_ptr<SplineCurve> curve(new SplineCurve(num, order,
00616                                                   knotstart, coefstart,
00617                                                   dim2, 
00618                                                   false));
00619     return curve;
00620 }

void Go::rotateLineCloud ( Point  rot_axis,
double  alpha,
LineCloud &  lc 
)

Rotate the given LineCloud a certain angle around a given axis.

Parameters:
rot_axis the axis of rotation. It does not have to be normalized, but must of course be nonzero.
alpha the angle of rotation, given in radians
lc reference to the LineCloud that is to be rotated

Definition at line 1083 of file GeometryTools.C.

References ASSERT, Go::Point::begin(), Go::Array< T, Dim >::begin(), Go::Point::dimension(), Go::Array< T, Dim >::end(), Go::Point::normalize(), Go::LineCloud::numLines(), Go::LineCloud::point(), Go::LineCloud::rawData(), and rotatePoint().

01085 {
01086     rot_axis.normalize();
01087     ASSERT(rot_axis.dimension() == 3); // We're working in 3D space.
01088     int ki;
01089     int nmb_pts = lc.numLines()*2;
01090     int dim = 3;
01091     for (ki = 0; ki < nmb_pts; ++ki) {
01092         Vector3D vec = lc.point(ki);
01093         Point pt(vec.begin(), vec.end());
01094         rotatePoint(rot_axis, alpha, pt.begin());
01095         copy(pt.begin(), pt.end(), lc.rawData() + ki*dim);
01096     }
01097 }

void Go::rotatePoint ( Point  rot_axis,
double  alpha,
Point &  space_pt 
)

Rotate the given 3D point a certain angle around a certain axis.

Parameters:
rot_axis the axis of rotation. It does not have to be normalized, but must of course be nonzero.
alpha the angle of rotation, given in radians
space_pt reference to teh point to be rotated. This will be overwritten with the rotated coordinates.

Definition at line 1119 of file GeometryTools.C.

References Go::Point::begin(), and rotatePoint().

01121 {
01122     rotatePoint(rot_axis, alpha, space_pt.begin());
01123 }

void Go::rotatePoint ( Point  rot_axis,
double  alpha,
double *  space_pt 
)

Rotate the given 3D point a certain angle around a certain axis.

Parameters:
rot_axis the axis of rotation. It does not have to be normalized, but must of course be nonzero.
alpha the angle of rotation, given in radians
space_pt pointer to the memory location where the 3D coordinates of the point are stored. These will be overwritten with the rotated coordinates.

Definition at line 1101 of file GeometryTools.C.

References ASSERT, Go::Point::dimension(), getRotationMatrix(), and Go::Point::normalize().

Referenced by Go::CreatorsUtils::createCrossTangent(), Go::CreatorsUtils::projectCurvePoint(), Go::Parabola::reverseParameterDirection(), Go::Hyperbola::reverseParameterDirection(), Go::Ellipse::reverseParameterDirection(), Go::Circle::reverseParameterDirection(), rotateLineCloud(), rotatePoint(), rotateSplineCurve(), and rotateSplineSurf().

01103 {
01104     rot_axis.normalize();
01105     ASSERT(rot_axis.dimension() == 3); // We're working in 3D space.
01106     std::vector<double> rot_mat = getRotationMatrix(rot_axis, alpha);
01107     int ki, kj;
01108     Point rotated_pt(0.0, 0.0, 0.0);
01109     for (ki = 0; ki < 3; ++ki)
01110         for (kj = 0; kj < 3; ++kj)
01111             rotated_pt[ki] += rot_mat[ki*3+kj]*space_pt[kj];
01112 
01113     for (ki = 0; ki < 3; ++ki)
01114         space_pt[ki] = rotated_pt[ki];
01115 }

void Go::rotateSplineCurve ( Point  rot_axis,
double  alpha,
SplineCurve &  cv 
)

Rotate the given SplineCurve a certain angle around a given axis.

Parameters:
rot_axis the axis of rotation. It does not have to be normalized, but must of course be nonzero.
alpha the angle of rotation, given in radians
cv reference to the curve that is to be rotated

Definition at line 1061 of file GeometryTools.C.

References ASSERT, Go::SplineCurve::coefs_begin(), Go::SplineCurve::coefs_end(), Go::Point::dimension(), Go::Point::normalize(), Go::SplineCurve::rational(), Go::SplineCurve::rcoefs_begin(), Go::SplineCurve::rcoefs_end(), and rotatePoint().

Referenced by Go::Circle::geometryCurve(), and Go::BoundedUtils::rotateBoundedSurf().

01063 {
01064     rot_axis.normalize();
01065     ASSERT(rot_axis.dimension() == 3); // We're working in 3D space.
01066     int dim = 3 + cv.rational();
01067     std::vector<double>::iterator iter = cv.rational() ? cv.rcoefs_begin() : cv.coefs_begin();
01068     std::vector<double>::iterator end_iter = cv.rational() ? cv.rcoefs_end() : cv.coefs_end();
01069     std::vector<double>::iterator coef_iter = cv.coefs_begin();
01070     while (iter != end_iter) { // @@ A faster approach would be to use rotation matrix directly.
01071         rotatePoint(rot_axis, alpha, &*iter);
01072         if (cv.rational()) {
01073             for (int ki = 0; ki < 3; ++ki)
01074                 coef_iter[ki] = iter[ki]/iter[3];
01075             coef_iter += dim - 1;
01076         }
01077         iter += dim;
01078     }
01079 }

void Go::rotateSplineSurf ( Point  rot_axis,
double  alpha,
SplineSurface &  sf 
)

Rotate the given SplineSurface a certain angle around a given axis.

Parameters:
rot_axis the axis of rotation. It does not have to be normalized, but must of course be nonzero.
alpha the angle of rotation, given in radians
sf reference to the surface that is to be rotated.

Definition at line 1039 of file GeometryTools.C.

References ASSERT, Go::SplineSurface::coefs_begin(), Go::SplineSurface::coefs_end(), Go::Point::dimension(), Go::Point::normalize(), Go::SplineSurface::rational(), Go::SplineSurface::rcoefs_begin(), Go::SplineSurface::rcoefs_end(), and rotatePoint().

Referenced by Go::Sphere::geometrySurface(), Go::Cylinder::geometrySurface(), Go::Cone::geometrySurface(), and Go::BoundedUtils::rotateBoundedSurf().

01041 {
01042     rot_axis.normalize();
01043     ASSERT(rot_axis.dimension() == 3); // We're working in 3D space.
01044     int dim = 3 + sf.rational();
01045     std::vector<double>::iterator iter = sf.rational() ? sf.rcoefs_begin() : sf.coefs_begin();
01046     std::vector<double>::iterator end_iter = sf.rational() ? sf.rcoefs_end() : sf.coefs_end();
01047     std::vector<double>::iterator coef_iter = sf.coefs_begin();
01048     while (iter != end_iter) { // @@ A faster approach would be to use rotation matrix directly.
01049         rotatePoint(rot_axis, alpha, &*iter);
01050         if (sf.rational()) {
01051             for (int ki = 0; ki < 3; ++ki)
01052                 coef_iter[ki] = iter[ki]/iter[3];
01053             coef_iter += dim - 1;
01054         }
01055         iter += dim;
01056     }
01057 }

bool Go::segment_contour_intersection_for_s2m ( const double  x0,
const double  y0,
const double  x1,
const double  y1,
const double *const   vertices,
const std::vector< int > &  contour,
double &  x,
double &  y,
double &  s,
const bool  snap_ends = false 
)

Definition at line 654 of file 2dpoly_for_s2m.C.

References DBG_FLAG, and point_on_segment().

Referenced by split_quad(), and split_triangle().

00665   {
00666 #ifndef DBG
00667     const bool dbg=false; // This way, all tests on 'dbg' is removed compile-time when DBG is not defined.
00668 #endif
00669 
00670     if (dbg) puts("\n\n  # Entering segment_contour_intersection_for_s2m ########################################\n");
00671 
00672     //
00673     // Now we search for the (actually, just "a") piece of the contour which intersects the segment. Maybe it is
00674     // faster to just do this without the previous test, if we can use the 'sorted_segments' information.
00675     //
00676 
00677     int i;
00678     //const double tau=1e-14; // 090115: Used for zero-tests for degeneracy and parallellity tests.
00679     const double tau=1e-12; // 100218:
00680 
00681     const double parallellity_eps = 1e-10; // 100219
00682 
00683     const double eps=1e-13; // 090115: Used for zero-tests for distances in the parameter domain.
00684     //const double eps2=1e-8; // 090203: This is used to determine whether or not an intersection is at one of the ends
00685     const double eps2=1e-5; // 100218:
00686     //         of an edge. (In which case we continue to look for an "interior" intersection,
00687     //         which will be favoured. Is this always sensible? Or is it possible to make a
00688     //         case in which the opposite behaviour should be preferred?
00689     // 090204: We need this as large as 1e-8 for bin_p1_3.g2 to be meshed properly.
00690     bool intersection_found_at_the_end_of_the_segment = false;
00691     double x_saved=1e99, y_saved=1e99, s_saved=1e99; // Initial values to help spot unforeseen problems...
00692     const int n=contour.size();
00693     for (i=0; i<n; i++)
00694       {
00695         const int ii=i, jj=(ii+1)%n;
00696         const double &x2=vertices[contour[ii]], &y2=vertices[contour[ii]+1];
00697         const double &x3=vertices[contour[jj]], &y3=vertices[contour[jj]+1];
00698         double t;
00699 
00700 #if 0
00701         if (dbg)
00702           {
00703             const double d02 = sqrt( (x2-x0)*(x2-x0) + (y2-y0)*(y2-y0) );
00704             const double d03 = sqrt( (x3-x0)*(x3-x0) + (y3-y0)*(y3-y0) );
00705             const double d12 = sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) );
00706             const double d13 = sqrt( (x3-x1)*(x3-x1) + (y3-y1)*(y3-y1) );
00707             
00708             const double eps3 = 1e-3;
00709 
00710             if ( (d02<eps3) || (d03<eps3) || (d12<eps3) || (d13<eps3) || (i==111169) )
00711               {
00712                 printf("    i=%4d: END TESTS: d02=%f, d03=%f, d12=%f, d13=%f\n", i, d02, d03, d12, d13);
00713                 printf("\nline([%f; %f], [%f; %f], 'color', 'k', 'linewidth', 6);\n", x0, x1, y0, y1);
00714                 printf("line([%f; %f], [%f; %f], 'color', 'y', 'linewidth', 6);\n", x2, x3, y2, y3);
00715               }
00716 
00717             // testing if ends of first segment is in the other.
00718 
00719             const double t0 = ( (x0-x2)*(x3-x2) + (y0-y2)*(y3-y2) ) / ( (x3-x2)*(x3-x2) + (y3-y2)*(y3-y2) );
00720             double p = x2+t0*(x3-x2) - x0;
00721             double q = y2+t0*(y3-y2) - y0;
00722             const double dist0 = sqrt(p*p+q*q);
00723             //if ( (dist0<1e-5) && (t0>=-eps) && (t0<=1.0+eps) )
00724             if (i==69)
00725               {
00726                 printf("    i=%4d: END TESTS 2: t0=%f, dist=%f\n", i, t0, dist0);
00727                 printf("\nline([%f; %f], [%f; %f], 'color', 'k', 'linewidth', 6);\n", x0, x1, y0, y1);
00728                 printf("line([%f; %f], [%f; %f], 'color', 'y', 'linewidth', 6);\n", x2, x3, y2, y3);
00729               }
00730 
00731             p = x2+t0*(x3-x2) - x1;
00732             q = y2+t0*(y3-y2) - y1;
00733             const double dist1 = sqrt(p*p+q*q);
00734             if (i==69)
00735             //if ( (dist1<1e-5) && (t0>=-eps) && (t0<=1.0+eps) )
00736               {
00737                 printf("    i=%4d: END TESTS 3: t0=%f, dist=%f\n", i, t0, dist0);
00738                 printf("\nline([%f; %f], [%f; %f], 'color', 'k', 'linewidth', 6);\n", x0, x1, y0, y1);
00739                 printf("line([%f; %f], [%f; %f], 'color', 'y', 'linewidth', 6);\n", x2, x3, y2, y3);
00740               }
00741 
00742           }
00743 #endif
00744       
00745         // 081209: Adding this test...
00746         const double contour_segment_length_squared = (x2-x3)*(x2-x3)+(y2-y3)*(y2-y3);
00747         // if (dbg2)    printf("i=%3d cont segm len=%f ", i, sqrt(contour_segment_length_squared));
00748 
00749         if (contour_segment_length_squared>tau*tau)
00750           {
00751 
00752             if (snap_ends)
00753               {
00754                 //
00755                 // 100219: We check if the ends of the segment (the one given as input to the function) are
00756                 //         close to the contour piece in question. If 'snap_ends' is true, we could have that
00757                 //         situation even if the pieces are (close to) parallel. We do this testing now,
00758                 //         before the parallellity-test, since that test is too strict to determine if this
00759                 //         'snap_ends'-test should be performed. (It is too strict because it is meant to trap
00760                 //         division with zero before they happen, mainly.)
00761                 //
00762                 //         Note also that if one of the ends is on the contour, this is an "end intersection",
00763                 //         and this 'intersection_found_at_the_end_of_the_segment' is set and the search
00764                 //         continued, in case there is also some inner intersection.
00765                 //
00766 
00767                 if (point_on_segment(x0, y0, x2, y2, x3, y3, eps, eps2)) // , prøve med true her og nedenfor, se om det alltid blir bra da.))
00768                   {
00769                     intersection_found_at_the_end_of_the_segment = true;
00770                     x_saved = x0;
00771                     y_saved = y0;
00772                     s_saved = 0.0;
00773                   }
00774                 else
00775                   if (point_on_segment(x1, y1, x2, y2, x3, y3, eps, eps2 DBG_FLAG))
00776                     {
00777                       intersection_found_at_the_end_of_the_segment = true;
00778                       x_saved = x1;
00779                       y_saved = y1;
00780                       s_saved = 1.0;
00781                     }
00782               }
00783             
00784             // 090115: The next one should be zero for contour segment and segment parallel. If so, no intersection...
00785             const double parallellity = (x3-x2)*(y1-y0)-(y3-y2)*(x1-x0);
00786             if ( fabs(parallellity) > parallellity_eps ) // i.e., not parallel...
00787               {
00788                 //
00789                 // 100219: Let the (triangle) segment has ends A=(x0, y0) and B=(x1, y1), and the contour
00790                 //         piece has ends C=(x2, y2) and D=(x3, y3).  With intersection S = A+s(B-A) =
00791                 //         C+t(D-C), we get the following:
00792                 //
00793                 t = ((x0-x2)*(y1-y0)-(y0-y2)*(x1-x0)) / parallellity;
00794                 if ((t>=-eps) && (t<=1.0+eps))
00795                   {
00796                     if (fabs(x1-x0)>fabs(y1-y0))
00797                       s = ((x2-x0)+t*(x3-x2))/(x1-x0);
00798                     else
00799                       s = ((y2-y0)+t*(y3-y2))/(y1-y0);
00800                     // if (dbg2) printf("s=%f ", s);
00801                     if ((s>=-eps) && (s<=1.0+eps))
00802                       {
00803                         if (dbg)
00804                           {
00805                             const double ss = ((x0-x2)*(y3-y2)-(y0-y2)*(x3-x2)) / parallellity;
00806                             printf("    i=%4d: s=%f (%f), t=%f, parallellity=%f\n", i, s, ss, t, parallellity);
00807                             printf("\nline([%f; %f], [%f; %f], 'color', 'k', 'linewidth', 6);\n", x0, x1, y0, y1);
00808                             printf("line([%f; %f], [%f; %f], 'color', 'y', 'linewidth', 6);\n", x2, x3, y2, y3);
00809                             const double px = x0 + s*(x1-x0), py = y0 + s*(y1-y0);
00810                             const double qx = x2 + t*(x3-x2), qy = y2 + t*(y3-y2);
00811                             printf("hold on; plot(%f, %f, 'gs', 'markersize', 15, 'linewidth', 2);\n", px, py);
00812                             printf("plot(%f, %f, 'ks', 'markersize', 15, 'linewidth', 2); hold off;\n\n", qx, qy);
00813                           }
00814                         s = std::max(std::min(s, 1.0), 0.0);
00815                         x = x2+t*(x3-x2);
00816                         y = y2+t*(y3-y2);
00817                         //printf("***** s=%f t=%f x=%f y=%f\n", s, t, x, y);
00818                         //printf("returning true from %s:%d...\n", __FILE__, __LINE__);
00819                         if ((fabs(s)<eps2) || (fabs(s-1.0)<eps2))
00820                           {
00821                             intersection_found_at_the_end_of_the_segment=true;
00822                             if (dbg) printf("Intersection is at and end.\n");
00823                             x_saved=x;
00824                             y_saved=y;
00825                             s_saved=s;
00826                           }
00827                         else
00828                           {
00829                             if (dbg) puts("  # Returning true from segment_contour_intersection_for_s2m # (a) #####\n");
00830                             return true;
00831                           }
00832                       }
00833                     else
00834                       if (dbg) printf("    i=%4d: NO INTERS, s OUT OF RANGE s=%f, t=%f, p=%g\n", i, s, t, parallellity);
00835                   }
00836                 else
00837                   if (dbg) printf("    i=%4d: no inters, t out of range s=%f, t=%f, p=%g\n", i, s, t, parallellity);
00838               }
00839             else
00840               if (dbg)
00841                 {
00842                   printf("    i=%4d: PARALLEL parallellity=%e\n", i, parallellity);
00843                   // The egde of the triangle ("segment") and the piece of the contour:
00844                   printf("\nline([%f; %f], [%f; %f], 'color', 'k', 'linewidth', 6);\n", x0, x1, y0, y1);
00845                   printf("line([%f; %f], [%f; %f], 'color', 'y', 'linewidth', 6);\n\n", x2, x3, y2, y3);
00846                 }
00847           }
00848         else
00849           {
00850             if (dbg) printf("    Hmm... degen contour segment... should that still be possible?!\n");
00851             // 090117: The contour segment is degenerate, and will be treated as a point.
00852             const double mx = 0.5*(x2+x3), my = 0.5*(y2+y3);
00853 
00854             // The projection will be (x0, y0) + s*[(x1, y1)-(x0, y0)].
00855             s = ( (mx-x0)*(x1-x0)+(my-y0)*(y1-y0) ) / ( (x1-x0)*(x1-x0)+(y1-y0)*(y1-y0) );
00856             // if (dbg2) printf("s=%f ", s);
00857 
00858             if ((s>-eps) && (s<1.0+eps))
00859               {
00860                 x = x0 + s*(x1-x0);
00861                 y = y0 + s*(y1-y0);
00862               
00863                 const double dist_squared = (x-mx)*(x-mx) + (y-my)*(y-my);
00864                 if (dist_squared<eps*eps)
00865                   {
00866                     intersection_found_at_the_end_of_the_segment=true;
00867                     x_saved=x;
00868                     y_saved=y;
00869                     s_saved=s;
00870                   }
00871               }
00872           }
00873         // if (dbg2) printf("\n");
00874       }
00875 
00876     if (intersection_found_at_the_end_of_the_segment)
00877       {
00878         x=x_saved;
00879         y=y_saved;
00880         s=s_saved;
00881         if (dbg) puts("  # Returning true from segment_contour_intersection_for_s2m # (b) #######################\n");
00882         return true;
00883       }
00884   
00885     // 090205: This message is not longer as relevant (or correct!) Now (also before?) it is perfectly
00886     //         acceptable that this returns 'false' for the "second intersection, first try". The problem is
00887     //         that it should not happen in the "second try" done by 'split_triangle'... But the proper place to
00888     //         catch that problem is most likely in 'split_triangle' itself, so I'll disable this old message...
00889 //   MESSAGE("\nCouldn't find proper intersection between segment\n"
00890 //        "and contour, while the segment's ends\n"
00891 //        "are determined to be on opposite sides of the contour!!!\n"
00892 //        "If you see this, the results are very likely going to look like crap, unfortunately.\n"
00893 //        "It is currently unknown how this could happen.\n");
00894 //   printf("Segment length in the parameter domain: %g\n\n\n", sqrt((x0-x1)*(x0-x1) + (y0-y1)*(y0-y1)));
00895 
00896     if (dbg) puts("  # Returning false from segment_contour_intersection_for_s2m # (c) ##########################\n");
00897 
00898     return false;
00899   }

void Go::setSfBdCoefToConst ( SplineSurface &  srf,
int  bd_idx,
int  idx_d,
double  val,
double  deg_tol 
)

Modify surface along specified boundary to match a specific constant in one direction.

Currently only non-rational surfaces

Definition at line 330 of file GeometryTools.C.

References Go::SplineSurface::coefs_begin(), Go::SplineSurface::dimension(), Go::SplineSurface::numCoefs_u(), and Go::SplineSurface::numCoefs_v().

00336 {
00337     bool dir_u = (bd_idx == 2 || bd_idx == 3);
00338     int nmb1 = (dir_u) ? srf.numCoefs_u() : srf.numCoefs_v();
00339     int nmb2 = (dir_u) ? srf.numCoefs_v() : srf.numCoefs_u();
00340     int dim = srf.dimension();
00341     vector<double>::iterator coefs = srf.coefs_begin();
00342     int kr1 = (dir_u) ? dim : nmb1*dim;
00343     int kr2 = (dir_u) ? nmb2*dim : dim;
00344 
00345     if (idx_d >= dim)
00346         return;  // Does not make sense
00347 
00348     // Check degeneracy
00349     bool bd[] = { false, false, false, false }; // left, right, bottom, top
00350     // bool deg = srf.isDegenerate(bd[2], bd[1], bd[3], bd[0], deg_tol);
00351     bool start_deg = ((bd_idx <=1 && bd[2]) || (bd_idx > 1 && bd[0]));
00352     bool end_deg = ((bd_idx <=1 && bd[3]) || (bd_idx > 1 && bd[1]));
00353 
00354     // Modify coefficients
00355     vector<double>::iterator c1 = coefs;
00356     if (bd_idx == 3)
00357         c1 += (nmb2-1)*nmb1*dim;
00358     if (bd_idx == 1)
00359         c1 += (nmb2-1)*dim;
00360 
00361     for (int ki=0; ki<nmb1; ki++, c1+=kr1)
00362     {
00363         c1[idx_d] = val;
00364     }
00365 
00366     if (start_deg)
00367     {
00368         // Make sure that the degeneracy is maintained
00369         vector<double>::iterator d1 = coefs;
00370         for (int ki=0; ki<nmb2; ki++, d1+=kr2)
00371         {
00372             d1[idx_d] = val;
00373         }
00374     }
00375 
00376     if (end_deg)
00377     {
00378         // Make sure that the degeneracy is maintained
00379         vector<double>::iterator d1 = coefs;
00380         if (bd_idx <= 1)
00381             d1 += (nmb1-1)*nmb2*dim;
00382         else
00383             d1 += (nmb1-1)*dim;
00384         for (int ki=0; ki<nmb2; ki++, d1+=kr2)
00385         {
00386             d1[idx_d] = val;
00387         }
00388     }
00389 
00390 }

template<typename T >
T Go::signed_area ( const Array< T, 3 > *  c,
const Array< T, 3 > &  normal 
) [inline]

Computes the signed area of a triangle embedded in 3D space.

Input is an array of corner points and a normal to determine the sign.

Definition at line 92 of file Volumes.h.

References Go::Array< T, Dim >::cross(), and Go::Array< T, Dim >::length().

Referenced by Go::BaryCoordSystemTriangle3D::cartToBary().

00093 {
00094     // Using the one-half cross product rule
00095     Array<T, 3> d0 = c[1] - c[0];
00096     Array<T, 3> d1 = c[2] - c[0];
00097     Array<T, 3> crossprod = d0.cross(d1);
00098     if (crossprod*normal > 0) {
00099         return 0.5 * crossprod.length();
00100     } else {
00101         return -0.5 * crossprod.length();
00102     }
00103 }

template<typename T , int Dim>
T Go::simplex_volume ( const Array< T, Dim > *  a  )  [inline]

Computes the volume of a simplex consisting of (Dim+1) vertices embedded in Euclidean space of dimension (Dim).

Definition at line 52 of file Volumes.h.

References determinantOf(), and Go::InverseFactorial< T, N >::val().

Referenced by area(), Go::BaryCoordSystem< Dim >::BaryCoordSystem(), Go::BaryCoordSystem< Dim >::cartToBary(), Go::BaryCoordSystem< Dim >::read(), Go::BaryCoordSystem< Dim >::setCorners(), and volume().

00053 {
00054     Array<T, Dim> tmp[Dim];
00055     for (int i = 0; i < Dim; ++i) {
00056         tmp[i] = a[i] - a[i+1];
00057     }
00058     return determinantOf(tmp) * InverseFactorial<double, Dim>::val();
00059     // determinant / factorial
00060 }

template<typename Functor >
double Go::simpsons_rule ( Functor &  f,
double  a,
double  b,
const double  eps = 1.0e-6,
const int  max_iter = 20 
) [inline]

Routine to calculate the integral of the functor f from a to b using Simpson's rule.

Definition at line 59 of file Integration.h.

References MESSAGE, and trapezoidal().

Referenced by main(), and simpsons_rule2D().

00061 {
00062     const double one_third = double(1) / double(3);
00063     double result = 0;
00064     double tz = 0;
00065     double last_tz = std::numeric_limits<double>::min();
00066     double last_result =  std::numeric_limits<double>::min();
00067 
00068     for (int j = 1; j <= max_iter; ++j) {
00069         trapezoidal(f, a, b, tz, j);
00070         result = (4.0 * tz - last_tz) * one_third;
00071         if ((fabs(result - last_result) < eps * fabs(last_result)) ||
00072             (fabs(result) < eps && fabs(last_result) < eps && j > 6)) {
00073             return result;
00074         }
00075         last_result = result;
00076         last_tz = tz;
00077     }
00078     MESSAGE("Too many steps in simpsons_rule.");
00079     throw std::runtime_error("Too many steps in simpsons_rule.");
00080 } // 

template<typename Functor2D >
double Go::simpsons_rule2D ( Functor2D &  f,
double  ax,
double  bx,
double  ay,
double  by,
const double  eps = 1.0e-6,
const int  max_iter = 20 
) [inline]

Routine to integrate the two-dimensional functor f over the rectangle defined by ax, bx, ay and by.

Uses Simpson's rule.

Definition at line 136 of file Integration.h.

References simpsons_rule().

00139 {
00140     Integrate2ndFunctor<Functor2D> fu(f, ay, by);
00141     return simpsons_rule(fu, ax, bx, eps, max_iter);
00142 }

SplineCurve * Go::SISLCurve2Go ( const SISLCurve *const   cv  ) 

Convert a SISLCurve to a SplineCurve.

Parameters:
cv the SISLcurve to convert
Returns:
A newly generated SplineCurve that describes the same curve as 'cv'. The user assumes ownership and is responsible for cleaning up by calling the delete function.

Definition at line 74 of file SISLconversion.C.

References THROW.

Referenced by main().

00075 {
00076     double* coefsstart;
00077     bool rational;
00078     if (cv->ikind == 2) {
00079         coefsstart = cv->rcoef;
00080         rational = true;
00081     } else if (cv->ikind == 1) {
00082         coefsstart = cv->ecoef;
00083         rational = false;
00084     } else {
00085         THROW("ikind must be 1 or 2.");
00086     }
00087     return new SplineCurve(cv->in, cv->ik, cv->et,
00088                              coefsstart, cv->idim, rational);
00089 }

SplineSurface * Go::SISLSurf2Go ( SISLSurf *  sf  ) 

Convert a SISLSurface to a SplineSurface.

Parameters:
sf the SISLSurf to convert
Returns:
A newly generated SplineSurface that describes the same surface as 'sf'. The user assumes ownership and is responsible for cleaning up by calling the delete function.

Definition at line 110 of file SISLconversion.C.

References THROW.

Referenced by main().

00111 {
00112     double* coefsstart;
00113     bool rational;
00114     if (sf->ikind == 2) {
00115         coefsstart = sf->rcoef;
00116         rational = true;
00117     } else if (sf->ikind == 1) {
00118         coefsstart = sf->ecoef;
00119         rational = false;
00120     } else {
00121         THROW("ikind must be 1 or 2.");
00122     }
00123     return new SplineSurface(sf->in1, sf->in2, sf->ik1, sf->ik2,
00124                                sf->et1, sf->et2,
00125                                coefsstart, sf->idim, rational);
00126 }

vector< short_list_short_list > Go::sort_2dpoly_segments ( const double *const   vertices,
const std::vector< int > &  contour,
const bool  transposed = false 
)

Definition at line 910 of file 2dpoly_for_s2m.C.

References THROW.

00913   {
00914     vector< short_list_short_list > sorted_segments;
00915     const int n=contour.size();
00916 
00917     const int debug=0;
00918   
00919     // 020615: Introducing the 'transposed' for making a version in which x and y swap roles.
00920 
00921     //
00922     // We cannot choose, it must contain indices into the 'contour' vector, if we were to copy that vector's
00923     // indices directly into 'vertices', we would lose information about one of the ends of all segments, as
00924     // soon as we started reordering the segments.  Hence, initializing with 'contour[i]' was wrong. It must be
00925     // 'i'.
00926     sorted_segments.resize(n);
00927     for (int i=0; i<n; i++)
00928       sorted_segments[i].first=i;
00929 
00930     // Now we sort this "outer" list wrt. largest x-value of the segments.
00931     {
00932       less_largest_x compare_functor(contour, vertices, 0.0, transposed);
00933       std::sort(sorted_segments.begin(), sorted_segments.end(), compare_functor);
00934     }
00935   
00936     if ((debug) && (!transposed))
00937       {
00938         //short_list_short_list *first_cut;
00939         vector<short_list_short_list>::iterator first_cut;
00940       
00941         printf("\n");
00942         for (first_cut=sorted_segments.begin(); first_cut<sorted_segments.end(); first_cut++)
00943           {
00944             const int a=contour[first_cut->first], b=contour[(first_cut->first+1)%n];
00945             printf("%3d: %5d-%5d: (%10.3f, %10.3f, %10.3f)-"
00946                    "(%10.3f, %10.3f, %10.3f) maxx: %10.3f\n",
00947                    int(first_cut-sorted_segments.begin()),
00948                    a, b,
00949                    vertices[a+0], vertices[a+1], vertices[a+2],
00950                    vertices[b+0], vertices[b+1], vertices[b+2],
00951                    std::max(vertices[a+0], vertices[b+0]));
00952           }
00953       }
00954   
00955     // Next, we fill inn all the lists of each pair of this "outer" list, i.e., the "middle" lists.
00956     if (transposed)
00957       {
00958         THROW("Huh?! This should not be in use, I think... J.O. 090129");
00959         exit(0);
00960       }
00961     less_smallest_y lsy_comp(contour, vertices, 0.0); // , transposed);
00962     less_largest_y lly_comp(contour, vertices, 0.0); // , transposed);
00963   
00964     for (int i=0; i<n; i++)
00965       {
00966         sorted_segments[i].second=new vector<short_list>;
00967         sorted_segments[i].second->resize(n-i);
00968         for (int j=0; j<n-i; j++)
00969           (*sorted_segments[i].second)[j].first=sorted_segments[i+j].first;
00970       
00971         // Now we sort this "middle" list wrt. largest y-value of the segments.
00972         std::sort(sorted_segments[i].second->begin(), sorted_segments[i].second->end(), lly_comp);
00973       
00974         if ((debug) && (!transposed))
00975           {
00976             vector<short_list>::iterator second_cut;
00977           
00978             printf("\n");
00979             for (second_cut=sorted_segments[i].second->begin(); second_cut<sorted_segments[i].second->end(); second_cut++)
00980               {
00981                 const int a=contour[second_cut->first], b=contour[(second_cut->first+1)%n];
00982                 printf("     %3d: %5d-%5d: (%10.3f, %10.3f, %10.3f)-"
00983                        "(%10.3f, %10.3f, %10.3f) maxy: %10.3f\n",
00984                        int(second_cut-sorted_segments[i].second->begin()),
00985                        a, b,
00986                        vertices[a+0], vertices[a+1], vertices[a+2],
00987                        vertices[b+0], vertices[b+1], vertices[b+2],
00988                        std::max(vertices[a+1], vertices[b+1]));
00989               }
00990           }
00991       
00992         // Next, we fill inn all the lists of each pair of this "middle" list, i.e., the "inner" lists.
00993         for (int j=0; j<n-i; j++)
00994           {
00995             (*sorted_segments[i].second)[j].second=new vector<short>;
00996             (*sorted_segments[i].second)[j].second->resize(n-i-j);
00997             for (int k=0; k<n-i-j; k++)
00998               (*(*sorted_segments[i].second)[j].second)[k] = (*sorted_segments[i].second)[j+k].first;
00999           
01000             // Now we sort this "inner" list wrt. smallest y-value of the segments. Default 'compare' should be
01001             // 'less'.
01002             //
01003             // 020614: Don't know why such a default comparison functor is mentioned. How could it ever work
01004             //         with these compounded lists with the "strange" comparisons that are to be done?!
01005             // 020615: Probably I thought that as the inner list's entries consist of just an integer, there is
01006             //         no need for the complex compare_functor, but then I forgot that it's not the integers (or
01007             //         shorts) that are to be used as key in the sorting, but that which they point to!
01008             std::sort((*sorted_segments[i].second)[j].second->begin(),
01009                       (*sorted_segments[i].second)[j].second->end(),
01010                       lsy_comp);
01011           
01012             if ((debug) && (!transposed))
01013               {
01014                 vector<short>::iterator third_cut;
01015               
01016                 printf("\n");
01017                 for (third_cut=(*sorted_segments[i].second)[j].second->begin();
01018                      third_cut<(*sorted_segments[i].second)[j].second->end();
01019                      third_cut++)
01020                   {
01021                     const int a=contour[*third_cut], b=contour[(*third_cut+1)%n];
01022                     printf("          %3d: %5d-%5d: (%10.3f, %10.3f, %10.3f)-"
01023                            "(%10.3f, %10.3f, %10.3f) miny: %10.3f\n",
01024                            int(third_cut-
01025                                (*sorted_segments[i].second)[j].second->begin()),
01026                            a, b,
01027                            vertices[a+0], vertices[a+1], vertices[a+2],
01028                            vertices[b+0], vertices[b+1], vertices[b+2],
01029                            std::min(vertices[a+1], vertices[b+1]));
01030                   }
01031               }
01032           
01033           }
01034       }
01035   
01036 //    if (transposed)
01037 //      {
01038 //        printf("\n");
01039 //        print_sorted_segments2(sorted_segments, contour, vertices);
01040 //      }
01041   
01042     return sorted_segments;
01043   }

void Go::split_quad ( const int  i0,
const int  j0,
const int  i1,
const int  j1,
const int  i2,
const int  j2,
const vector< int > &  si0,
const vector< int > &  sj0,
const vector< int > &  si1,
const vector< int > &  sj1,
boost::shared_ptr< SplineSurface srf,
vector< Vector3D > &  vert,
vector< Vector2D > &  vert_p,
vector< int > &  bd,
vector< Vector3D > &  norm,
vector< int > &  mesh,
const int  dn,
const int  dm,
const vector< Vector3D > &  trim_curve_p,
const vector< int > &  contour,
const bool  with_boundary,
const bool  dbg = false 
)

Definition at line 186 of file spline2mesh.C.

References add_triangle(), ASSERT2, DBG_FLAG, is_on_contour(), MESSAGE, Go::Array< T, Dim >::normalize(), and segment_contour_intersection_for_s2m().

Referenced by make_trimmed_mesh().

00192                            : All the vectors above have two elements each, s?0[i] and s?1[i] are the two end
00193                   //         points of two of the sides of some quad, that the contour is assumed to intersect.
00194                   //         (The contour is given in 'contour', and 'vert', together. I think.)
00195                   //         (i?, j?) (actually, it makes more sense to say (j?, i?)...) specifies corners of
00196                   //         the quad. Which corners, is dependent on the configuration in question... (sigh.)
00197 
00198                   boost::shared_ptr<SplineSurface> srf,
00199                   vector< Vector3D > &vert, vector<Vector2D> &vert_p,
00200                   vector< int > &bd, vector< Vector3D > &norm,
00201                   //vector< Vector3D > &col,
00202                   vector<int> &mesh, const int dn, const int dm,
00203                   //vector< Vector3D > &extra_v,
00204                   const vector< Vector3D > &trim_curve_p,
00205                   const vector<int> &contour,
00206                   const bool with_boundary, const bool dbg=false)
00207   {
00208     //
00209     // This one always get two existing points and two segments between two pairs of points in, and intersect
00210     // the trimming curve twice against these segments for the two remaining points. The triangles are not
00211     // always oriented the same way, but that shouldn't matter too much. [Could easily be fixed by a switch
00212     // among the arguments...]
00213     //
00214 
00215     int i;
00216 
00217     //
00218     // Do the intersections.
00219     //
00220 
00221     const double u0=srf->startparam_u();
00222     const double u1=srf->endparam_u();
00223     const double v0=srf->startparam_v();
00224     const double v1=srf->endparam_v();
00225     for (i=0; i<2; i++)
00226       {
00227         double x, y, s;
00228         if (dbg)
00229           printf("%f %f     %f %f\n", u0*(1.0-sj0[i]/double(dn)) + u1*sj0[i]/double(dn),
00230                  v0*(1.0-si0[i]/double(dm)) + v1*si0[i]/double(dm),
00231                  u0*(1.0-sj1[i]/double(dn)) + u1*sj1[i]/double(dn),
00232                  v0*(1.0-si1[i]/double(dm)) + v1*si1[i]/double(dm));
00233         bool inters_found = segment_contour_intersection_for_s2m(u0*(1.0-sj0[i]/double(dn)) + u1*sj0[i]/double(dn),
00234                                                                  v0*(1.0-si0[i]/double(dm)) + v1*si0[i]/double(dm),
00235                                                                  u0*(1.0-sj1[i]/double(dn)) + u1*sj1[i]/double(dn),
00236                                                                  v0*(1.0-si1[i]/double(dm)) + v1*si1[i]/double(dm),
00237                                                                  &trim_curve_p[0][0], contour, 
00238                                                                  x, y, s,
00239                                                                  false // 100222: New 'snap_ends' flag.
00240                                                                  DBG_FLAG);
00241         if (dbg)
00242           printf("=1===> i=%d, inters=%d\n", i, inters_found?1:0);
00243 
00244         if ((!inters_found) && (with_boundary))
00245           {
00246             // 090117: Didn't find intersection, even though one should be here. Checking if the segment's ends
00247             //         are on the contour.
00248             if (is_on_contour(trim_curve_p, contour,
00249                               u0*(1.0-sj0[i]/double(dn)) + u1*sj0[i]/double(dn),
00250                               v0*(1.0-si0[i]/double(dm)) + v1*si0[i]/double(dm)))
00251               {
00252                 x=u0*(1.0-sj0[i]/double(dn)) + u1*sj0[i]/double(dn);
00253                 y=v0*(1.0-si0[i]/double(dm)) + v1*si0[i]/double(dm);
00254                 s=0.0;
00255                 inters_found=true;
00256                 if (dbg)
00257                   printf("=2===> i=%d, inters=%d\n", i, inters_found?1:0);
00258               }
00259             else
00260               if (is_on_contour(trim_curve_p, contour,
00261                                 u0*(1.0-sj1[i]/double(dn)) + u1*sj1[i]/double(dn),
00262                                 v0*(1.0-si1[i]/double(dm)) + v1*si1[i]/double(dm)))
00263                 {
00264                   x=u0*(1.0-sj1[i]/double(dn)) + u1*sj1[i]/double(dn);
00265                   y=v0*(1.0-si1[i]/double(dm)) + v1*si1[i]/double(dm);
00266                   s=1.0;
00267                   inters_found=true;
00268                   if (dbg)
00269                     printf("=3===> i=%d, inters=%d\n", i, inters_found?1:0);
00270                 }
00271           }
00272 
00273         if (!inters_found)
00274           {
00275             MESSAGE("Failed finding intersection. Expected one.");
00276             fflush(stderr);
00277           } 
00278         else 
00279           {
00280             const double eps=1e-13; // 090115: Used for zero-tests for distances in the parameter domain.
00281             //         Hmm... these should *really*, *really* be taken from some global
00282             //         variable or something
00283             // 090117: Anyway... s will never be out of range here...
00284             ASSERT2((s>=-eps) && (s<=1.0+eps), printf("Huh?! s=%f\n", s));
00285           }
00286         // eval surf i x og y for aa faa vert og norm, evt. returnere param
00287         // for skjaering mellom punktene s.a. vi igjen kan danne lin komb.
00288         if (inters_found)
00289           {
00290             vert.push_back((1.0-s)*vert[si0[i]*(dn+1)+sj0[i]] +
00291                            s*vert[si1[i]*(dn+1)+sj1[i]]   );
00292             vert_p.push_back((1.0-s)*vert_p[si0[i]*(dn+1)+sj0[i]] +
00293                              s*vert_p[si1[i]*(dn+1)+sj1[i]]   );
00294             if (dbg)
00295               printf("=4===> inters: %f %f\n", vert_p[vert_p.size()-1][0], vert_p[vert_p.size()-1][1]);
00296             bd.push_back(1);
00297             Vector3D new_norm = (1.0-s)*norm[si0[i]*(dn+1)+sj0[i]] +
00298               s*norm[si1[i]*(dn+1)+sj1[i]];
00299             new_norm.normalize();
00300             norm.push_back(new_norm);
00301           }
00302         //extra_v.push_back(vert[vert.size()-1]); // for debugging
00303       }
00304 
00305     //
00306     // Add triangles to the mesh.
00307     //
00308     // Adding three triangles: (A, B, 0), (B, 1, 0), (0, 2, A).
00309     //
00310     //   (i1, j1)  B
00311     //      o------x----o
00312     //      |        \  |
00313     //      |         \ x A
00314     //      |           |
00315     //      o-----------o
00316     //   (i0, j0)    (i2, j2)
00317     //
00318     //
00319     // Adding two triangles: 
00320     //
00321     //  "-1"       -----o "-2"          Note that we want the triangles
00322     //      o-----/     |                       oriented ccw., i.e.,
00323     //      |           |                       (-2, -1, 0), and (-2, 0, 1).
00324     //      |           |
00325     //      o-----------o
00326     //   (i0, j0)    (i1, j1)
00327     //
00328 
00329     // This triangle can be used in all three modes.
00330     add_triangle(vert_p, mesh, vert.size()-2, vert.size()-1, i0*(dn+1)+j0);
00331     //col.push_back(Vector3D(1.0, 0.6, 0.6));
00332 
00333     if ((i1==-1) || (j1==-1))
00334       // Only one triangle to add.
00335       return;
00336 
00337     if ((i2==-1) || (j2==-1))
00338       {
00339         // Two triangles to add, i.e., one more.
00340         add_triangle(vert_p, mesh, vert.size()-2, i0*(dn+1)+j0, i1*(dn+1)+j1);
00341         //col.push_back(Vector3D(0.0, 0.0, 1.0));
00342       }
00343     else
00344       {
00345         // Three triangles to add, i.e., two more.
00346         add_triangle(vert_p, mesh, i0*(dn+1)+j0, vert.size()-1, i1*(dn+1)+j1);
00347         //col.push_back(Vector3D(0.6, 1.0, 0.6));
00348       
00349         add_triangle(vert_p, mesh, vert.size()-2, i0*(dn+1)+j0, i2*(dn+1)+j2);
00350         //col.push_back(Vector3D(0.6, 0.6, 1.0));
00351       }
00352   }

bool Go::split_triangle ( const int  c1_indx,
const int  c2_indx,
const int  c3_indx,
boost::shared_ptr< SplineSurface srf,
vector< Vector3D > &  vert,
vector< Vector2D > &  vert_p,
vector< int > &  bd,
vector< Vector3D > &  norm,
vector< int > &  newmesh,
const vector< Vector3D > &  trim_curve_p,
const vector< int > &  contour,
const bool  dbg = false,
bool  forced_skipping_of_second_edge = false,
const bool  inner_trimming_curve = false 
)

Definition at line 544 of file spline2mesh.C.

References add_triangle(), DBG_FLAG, degenerate_triangle(), MESSAGE, push_an_intersection(), and segment_contour_intersection_for_s2m().

Referenced by trim_a_triangle().

00553                                                                         : See above.
00554   {
00555     const double abs_eps = 1e-12;       // 100218: Used for distance between two intersections in the param domain.
00556 
00557     // 100223: Testing a new approach. Want to get rid of 'forced_skipping_of_second_edge', but trying to do
00558     //         it one step at a time, through these temporary switches...
00559 
00560     const bool try_without_forced_stuff = true;
00561     
00562     if (try_without_forced_stuff)
00563       forced_skipping_of_second_edge = false;
00564 
00565     // 090129: Not using references in fear of what 'push_back' will do...
00566     const Vector2D c1_p=vert_p[c1_indx], c2_p=vert_p[c2_indx], c3_p=vert_p[c3_indx];
00567     const Vector3D c1=vert[c1_indx], c2=vert[c2_indx], c3=vert[c3_indx];
00568     const Vector3D n1=norm[c1_indx], n2=norm[c2_indx], n3=norm[c3_indx];
00569 
00570     if (dbg)
00571       {
00572         puts("\n\n  ----- split_triangle starting -----------------------------------------------------------------");
00573         printf("\n    The corners:\n\n");
00574         printf("hold on; plot(%f, %f, 'rd', 'markersize', %d, 'linewidth', 2); hold off\n", c1_p[0], c1_p[1], 14);
00575         printf("hold on; plot(%f, %f, 'gd', 'markersize', %d, 'linewidth', 2); hold off\n", c2_p[0], c2_p[1], 14);
00576         printf("hold on; plot(%f, %f, 'bd', 'markersize', %d, 'linewidth', 2); hold off\n\n", c3_p[0], c3_p[1], 14);
00577       }
00578 
00579     double x1, y1, s1, x2, y2, s2;
00580     
00581     if (dbg) printf("    Looking for intersection on edge 1-2...\n");
00582     const bool first_inters =
00583       segment_contour_intersection_for_s2m(c1_p[0], c1_p[1], c2_p[0], c2_p[1], 
00584                                            &trim_curve_p[0][0], // Pointer to vertices is enough, size not needed
00585                                            contour, x1, y1, s1, 
00586                                            true                 // 100222: New 'snap_ends' flag.
00587                                            DBG_FLAG);
00588     if (!first_inters)
00589       {
00590         if (!inner_trimming_curve)
00591           {
00592             // 100223: Disabling this warning, for with the new branch depending on "innerness" of contour,
00593             //         the situation will probably (hopefully) be correctly treated in all cases now.
00594             if ( (dbg) && (0) )
00595               puts("    Warning:\n  It is likely that the 'inside'-test gave a false positive for a corner of a\n"
00596                    "    triangle that is really fully outside a trimming curve. We continue with this\n"
00597                    "    assumption, and discard the triangle in question, without attempting to clip it.\n");
00598           }
00599         else
00600           // 100223: The new and alternate branch, which should be more likely to be correct for inner curves.
00601           add_triangle(vert_p, newmesh, c1_indx, c2_indx, c3_indx);
00602         if (dbg) puts("  ----- split_triangle done, no new triangles produced ---------------------------------\n\n");
00603         return false;
00604       }
00605   
00606     //
00607     // The first intersection is now between corner c1 and c2. The second may be between c2 and c3, or between
00608     // c3 and c1. Per assumption, c1 is *inside* the contour. (And c2 outside, c3 unknown.)
00609     //
00610     // 100223: But remember, now, that there may in fact be a lot more than the anticipated/assumed two
00611     //         intersections... trying to cope better with such situations from now on.
00612     //
00613     
00614     // Pushing inters1.
00615     push_an_intersection(srf, c1, c2, c1_p, c2_p, n1, n2, s1, vert, vert_p, norm, bd);
00616     if (dbg)
00617       printf("    First intersection found: s1=%f\n\n      hold on; plot(%f, %f, 'm*', 'markersize', "
00618              "7, 'linewidth', 2); hold off\n\n", s1, vert_p.back()[0], vert_p.back()[1]);
00619     
00620     // 100218: Note that we only have to *test* for a 2-3 intersection, since if there is none, we should have a 3-1.
00621     if (dbg) printf("    Looking for intersection on edge 2-3...\n");
00622     const bool second_inters =
00623       segment_contour_intersection_for_s2m(c2_p[0], c2_p[1], c3_p[0], c3_p[1], &trim_curve_p[0][0], contour, x2, y2, s2,
00624                                            true // 100222: New 'snap_ends'-flag
00625                                            DBG_FLAG);
00626 
00627     const double i1_i2_dist_squared = second_inters ? (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) : 0.0;
00628     if (dbg) printf("    second_inters (2-3) =%d, s2=%f, dist=%g\n", second_inters, s2, sqrt(i1_i2_dist_squared));
00629     const bool inters1_and_inters2_distinct = i1_i2_dist_squared > abs_eps*abs_eps;
00630 
00631 
00632     //--------------------------------------------------------------------------------------------------------------
00633     //
00634     // 100223: When three intersections between triangle edges and the contour are detected, the triangle is
00635     //         split in four, and flagged for further trimming in a new iteration. This should take care of a
00636     //         lot of previously unsolved cases with minimal new code!
00637     //
00638     //--------------------------------------------------------------------------------------------------------------
00639 
00640     bool third_inters;
00641     const bool look_for_a_third_inters = first_inters && second_inters && inters1_and_inters2_distinct;
00642     if (dbg) printf("    look_for_a_third_inters = %d\n", look_for_a_third_inters);
00643     double x3, y3, s3;
00644     if ( look_for_a_third_inters )
00645       {
00646         if (dbg) printf("    PRE_SPLITTING_3_INTERS: Looking for intersection on edge 3-1...\n");
00647         third_inters = segment_contour_intersection_for_s2m(c3_p[0], c3_p[1], c1_p[0], c1_p[1],
00648                                                             &trim_curve_p[0][0], contour, x3, y3, s3,
00649                                                             true // 100222: New 'snap_ends'-flag
00650                                                             DBG_FLAG);
00651         if (third_inters)
00652           {
00653             const double i1_i3_dist_squared = (x3-x1)*(x3-x1) + (y3-y1)*(y3-y1);
00654             const bool inters1_and_inters3_distinct = i1_i3_dist_squared > abs_eps*abs_eps;
00655             const double i2_i3_dist_squared = (x3-x2)*(x3-x2) + (y3-y2)*(y3-y2);
00656             const bool inters2_and_inters3_distinct = i2_i3_dist_squared > abs_eps*abs_eps;
00657             
00658             if (inters1_and_inters3_distinct && inters2_and_inters3_distinct)
00659               {
00660                 // puts("JEPP, FANT ET KJIPT LITE TRIANGEL...");
00661                 
00662                 // Pushing inters2.
00663                 push_an_intersection(srf, c2, c3, c2_p, c3_p, n2, n3, s2, vert, vert_p, norm, bd);
00664                 // Pushing inters3.
00665                 push_an_intersection(srf, c3, c1, c3_p, c1_p, n3, n1, s3, vert, vert_p, norm, bd);
00666                 
00667                 // Triangles...
00668                 add_triangle(vert_p, newmesh, c1_indx, vert.size()-3, vert.size()-1 DBG_FLAG);
00669                 add_triangle(vert_p, newmesh, c2_indx, vert.size()-2, vert.size()-3 DBG_FLAG);
00670                 add_triangle(vert_p, newmesh, c3_indx, vert.size()-1, vert.size()-2 DBG_FLAG);
00671                 add_triangle(vert_p, newmesh, vert.size()-3, vert.size()-2, vert.size()-1 DBG_FLAG);
00672                 
00673                 return true;
00674               }
00675           }
00676       }
00677 
00678     if ( second_inters && inters1_and_inters2_distinct && (!forced_skipping_of_second_edge) )
00679       {
00680         //----------------------------------------------------------------------------------------------------
00681         //
00682         // The second intersection is between corners c2 and c3, and it is distinct from the first
00683         // intersection. We can try to make the triangles as round as possible...
00684         //
00685         // 100223: What happens when 'forced_skipping_of_second_edge=true', is that this branch is not taken,
00686         //         although a perfectly fine intersection distinct from inters1 was found on 2-3. That will
00687         //         cause an intersection on 3-1 to be searched for, and used instead. (And who knows what will
00688         //         happen if that 3-1 intersection does not exist...) If we were to enter this branch, it
00689         //         seems a lot of triangles will be wrongly discarded, for some reasone. Cannot actually see
00690         //         how that will happen in this branch, right now, though... Could be that one of the four
00691         //         'add_triangle' calls below try to add a degenerate triangle. Hmm... seems not so unlikely.
00692         //
00693         //----------------------------------------------------------------------------------------------------
00694 
00695         // Pushing inters2.
00696         push_an_intersection(srf, c2, c3, c2_p, c3_p, n2, n3, s2, vert, vert_p, norm, bd);
00697         if (dbg)
00698           printf("    branch 1:\n\n    hold on; plot(%f, %f, 'g*', 'markersize', 7, 'linewidth', 2); hold off\n\n", 
00699                  vert_p.back()[0], vert_p.back()[1]);
00700       
00701         if ( (x2-c1_p[0])*(x2-c1_p[0])+(y2-c1_p[1])*(y2-c1_p[1]) < (x1-c3_p[0])*(x1-c3_p[0])+(y1-c3_p[1])*(y1-c3_p[1]) )
00702           // Splitting between c1 and inters2.
00703           {
00704             if (dbg) printf("    branch 2: Adding triangles (c1, i1, i2) and (c1, i2, c3).\n");
00705             if (dbg) printf("      adding the first:\n");
00706             add_triangle(vert_p, newmesh, c1_indx, vert.size()-2, vert.size()-1 DBG_FLAG);
00707             if (dbg) printf("      adding the second:\n");
00708             add_triangle(vert_p, newmesh, c1_indx, vert.size()-1, c3_indx DBG_FLAG);
00709           }
00710         else
00711           // Splitting between c3 and inters1.
00712           {
00713             if (dbg) printf("    branch 3: Adding triangles (c1, i1, c3) and (i1, i2, c3).\n");
00714             add_triangle(vert_p, newmesh, c1_indx, vert.size()-2, c3_indx DBG_FLAG);
00715             add_triangle(vert_p, newmesh, vert.size()-2, vert.size()-1, c3_indx DBG_FLAG);
00716           }
00717       }
00718     else
00719       {
00720         //----------------------------------------------------------------------------------------------------
00721         // 
00722         // Ok, no second intersection 2-3, then it should be on 3-1. If not, that's an error... (There should
00723         // always be exactly two intersections!) (100223: Yeah... well... not entirely true, really...)
00724         //
00725         //----------------------------------------------------------------------------------------------------
00726 
00727         if (dbg) printf("    branch 4:\n    Looking for intersection on edge 3-1...\n");
00728         bool tmp;
00729         if (look_for_a_third_inters) // If so, we have already called 'segment_contour_intersection_for_s2m'...
00730           tmp = third_inters, x2 = x3, y2 = y3, s2 = s3;
00731         else
00732           tmp = segment_contour_intersection_for_s2m(c3_p[0], c3_p[1], c1_p[0], c1_p[1], 
00733                                                      &trim_curve_p[0][0], contour, x2, y2, s2,
00734                                                      true); // 100222: New 'snap_ends'-flag
00735 
00736         // 100224: Hmm... tmp only used for debugging output? (Hence the name 'tmp'?!)
00737 
00738         if (dbg)
00739           printf("  2nd try: 3-1-inters=%d, dist=%g\n  forced_skipping_of_second_edge=%d\n\n"
00740                  "    hold on; plot(%f, %f, 'g*', 'markersize', 8, 'linewidth', 2); hold off\n\n",
00741                  tmp?1:0, sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)), forced_skipping_of_second_edge, x2, y2);
00742 
00743         //
00744         // 100224: Ok, before, we had 'if (!forced...) { ... }' here, because it would be detected as a
00745         //         problem if we got here, i.e., one 1-2-intersection and no 2-3-intersection *without* the
00746         //         caller expecting this and therefore using 'forced...'.
00747         //
00748         //         If we now want to get rid of the 'forced...' flag, we cannot trap this as a potential
00749         //         problem, since we have no way of knowing if the caller expected it. If we get here, we must
00750         //         simply assume that it is correct, and continue with the splitting... Therefore: We wrap the
00751         //         test in the new 'do_ignore_forced_skipping'-test:
00752         //
00753 
00754         if (!try_without_forced_stuff)
00755           if (!forced_skipping_of_second_edge)
00756             {
00757               MESSAGE("  Warning:\nShould not happen 2 ! Where did the second intersection go?!"
00758                       //"\nJust keeping the full triangle...\n");
00759                       "\n  Discarding the full triangle...\n");
00760               fflush(stdout);
00761               fflush(stderr);
00762               //add_triangle(vert_p, newmesh, c1_indx, c2_indx, c3_indx);
00763               
00764               if (dbg)
00765                 {
00766                   if (degenerate_triangle(vert_p[c1_indx], vert_p[c2_indx], vert_p[c3_indx] DBG_FLAG))
00767                     puts("Hmm... triangle is degenerate, so maybe appropriate to discard it then...");
00768                   int m=5*(c1_indx%4+1);
00769                   printf("\n\nwwwwwwwwwwww\n\n\n"
00770                          "hold on; plot(%f, %f, 'rs', 'markersize', %d, 'linewidth', 2); hold off\n"
00771                          "hold on; plot(%f, %f, 'gs', 'markersize', %d, 'linewidth', 2); hold off\n"
00772                          "hold on; plot(%f, %f, 'bs', 'markersize', %d, 'linewidth', 2); hold off\n\n",
00773                          c1_p[0], c1_p[1], m, c2_p[0], c2_p[1], m, c3_p[0], c3_p[1], m);
00774                   puts("  ----- split_triangle done ------------------------------------------------------------\n\n");
00775                 }
00776               return false;
00777             }
00778         
00779         //==============================================================================================================
00780         // 090217: Now, if the first intersection is through the first corner, and there is another "non-corner"
00781         //         intersection in the "middle" edge (and 'forced_skipping_of_second_edge' is true) we do some
00782         //         special treatment: We split the triangle in two new ones covering the old. Note that these
00783         //         must then be recursively re-processed by the caller! To make this simpler, we introduce a
00784         //         boolean return value, which will be true when further processing may be required.
00785       
00786         if ( ((fabs(s1)<1e-12) || (fabs(s2-1.0)<1e-12)) && forced_skipping_of_second_edge )
00787           {
00788             double x3, y3, s3;
00789             if (dbg) printf("    Looking for intersection on edge 2-3 again...\n");
00790             const bool tmp2=
00791               segment_contour_intersection_for_s2m(c2_p[0], c2_p[1], c3_p[0], c3_p[1], 
00792                                                    &trim_curve_p[0][0], contour, x3, y3, s3,
00793                                                    true); // 100222: New 'snap_ends' flag.
00794             if ( tmp2 && (fabs(s3)>1e-12) && (fabs(s3-1.0)<1-1e-12) )
00795               {
00796                 // Pushing inters3.
00797                 push_an_intersection(srf, c2, c3, c2_p, c3_p, n2, n3, s3, vert, vert_p, norm, bd);
00798                 // Hmm... now we have added a totally unneeded point, for intersection 1...
00799                 add_triangle(vert_p, newmesh, c1_indx, vert.size()-1, c3_indx);
00800                 add_triangle(vert_p, newmesh, c1_indx, c2_indx, vert.size()-1);
00801               
00802                 if (dbg) puts("  ----- split_triangle done -----------------------------------------------------\n\n");
00803                 return true;
00804               }
00805           }
00806       
00807         // Pushing inters2.
00808         push_an_intersection(srf, c3, c1, c3_p, c1_p, n3, n1, s2, vert, vert_p, norm, bd);
00809         if (dbg)
00810           printf("  s2=%g\n  hold on; plot(%f, %f, 'b*', 'markersize', 7, 'linewidth', 2); hold off\n",
00811                  s2, vert_p[vert_p.size()-1][0], vert_p[vert_p.size()-1][1]);
00812       
00813         // There is only one triangle to push on the list in this case.
00814         if (dbg) printf("    adding the only triangle...\n");
00815         add_triangle(vert_p, newmesh, c1_indx, vert.size()-2, vert.size()-1);
00816 
00817       } // end of the block for the second intersection being of 3-1 kind instead of 2-3...
00818 
00819     if (dbg) puts("  ----- split_triangle done ----------- xxx ------------------------------------------------\n\n");
00820     return false;
00821   }

void Go::splitCurveIntoSegments ( const SplineCurve &  cv,
std::vector< SplineCurve > &  seg 
)

Split a spline curve into Bezier segments.

Definition at line 28 of file GGUsplit.C.

References Go::SplineCurve::basis(), Go::BsplineBasis::begin(), Go::SplineCurve::makeBernsteinKnots(), Go::SplineCurve::numCoefs(), Go::SplineCurve::order(), and Go::SplineCurve::subCurve().

Referenced by main().

00031 {
00032     SplineCurve orig = cv;
00033     orig.makeBernsteinKnots();
00034 
00035     int n = orig.numCoefs();
00036     int order = orig.order();
00037     int numseg = n / order;
00038 
00039     seg.resize(numseg);
00040     vector<double>::const_iterator it = orig.basis().begin();
00041     for (int i = 0; i < numseg; ++i) {
00042         shared_ptr<ParamCurve> new_cv(orig.subCurve(*it, *(it+order)));
00043         seg[i] = dynamic_cast<SplineCurve&>(*new_cv);
00044         it += order;
00045     }
00046 
00047     return;
00048 }

std::vector< boost::shared_ptr< SplineSurface > > Go::splitInKinks ( const SplineSurface &  sf,
const std::vector< double > &  u_kinks,
const std::vector< double > &  v_kinks 
)

Extract sub patches from the surface given by input parameters.

Definition at line 871 of file GeometryTools.C.

References Go::SplineSurface::endparam_u(), Go::SplineSurface::endparam_v(), Go::SplineSurface::startparam_u(), Go::SplineSurface::startparam_v(), and Go::SplineSurface::subSurface().

00875 {
00876     std::vector<shared_ptr<SplineSurface> > return_sfs;
00877 
00878     std::vector<double> split_params_u;
00879     std::vector<double> split_params_v;
00880     split_params_u.push_back(sf.startparam_u());
00881     split_params_u.insert(split_params_u.end(), u_kinks.begin(), u_kinks.end());
00882     split_params_u.push_back(sf.endparam_u());
00883     split_params_v.push_back(sf.startparam_v());
00884     split_params_v.insert(split_params_v.end(), v_kinks.begin(), v_kinks.end());
00885     split_params_v.push_back(sf.endparam_v());
00886     int num_u = split_params_u.size();
00887     int num_v = split_params_v.size();
00888     for (int ki = 0; ki < num_u - 1; ++ki)
00889         for (int kj = 0; kj < num_v - 1; ++kj)
00890           {
00891 // #if _MSC_VER > 0 && _MSC_VER < 1300
00892 //          return_sfs.push_back(shared_ptr<SplineSurface>
00893 //                               (dynamic_cast<SplineSurface*>
00894 //                                (sf.subSurface(split_params_u[ki], split_params_v[kj],
00895 //                                                split_params_u[ki+1], split_params_v[kj+1]))));
00896 // #else            
00897             return_sfs.push_back(shared_ptr<SplineSurface>
00898                                  (sf.subSurface(split_params_u[ki], split_params_v[kj],
00899                                                  split_params_u[ki+1], split_params_v[kj+1])));
00900 // #endif
00901           }
00902     
00903     return return_sfs;
00904 }

void Go::splitSurfaceIntoPatches ( const SplineSurface &  sf,
std::vector< SplineSurface > &  pat 
)

Splits a spline surface into Bezier patches.

Definition at line 52 of file GGUsplit.C.

References Go::SplineSurface::basis_u(), Go::SplineSurface::basis_v(), Go::BsplineBasis::begin(), Go::SplineSurface::makeBernsteinKnotsU(), Go::SplineSurface::makeBernsteinKnotsV(), Go::SplineSurface::numCoefs_u(), Go::SplineSurface::numCoefs_v(), Go::SplineSurface::order_u(), Go::SplineSurface::order_v(), and Go::SplineSurface::subSurface().

Referenced by main(), Go::SurfaceCreators::mult1DSurfaces(), and Go::SplineSurface::normalSurface().

00055 {
00056     SplineSurface orig = sf;
00057     orig.makeBernsteinKnotsU();
00058     orig.makeBernsteinKnotsV();
00059 
00060     int num_u = orig.numCoefs_u();
00061     int num_v = orig.numCoefs_v();
00062     int order_u = orig.order_u();
00063     int order_v = orig.order_v();
00064     int numpat_u = num_u / order_u;
00065     int numpat_v = num_v / order_v;
00066 
00067     pat.resize(numpat_u * numpat_v);
00068     typedef vector<double>::const_iterator const_iter;
00069     const_iter itu = orig.basis_u().begin();
00070     const_iter itv;
00071     for (int i = 0; i < numpat_u; ++i) {
00072         itv = orig.basis_v().begin();
00073         for (int j = 0; j < numpat_v; ++j) {
00074             shared_ptr<SplineSurface>
00075                 new_sf(orig.subSurface(*itu, *itv,
00076                                        *(itu+order_u), *(itv+order_v)));
00077             pat[numpat_u*j + i] = *new_sf;
00078             itv += order_v;
00079         }
00080         itu += order_u;
00081     }
00082 
00083     return;
00084 }

double Go::stepLenFromRadius ( double  radius,
double  aepsge 
)

Computes the step length along a curve based on radius of curvature at a point on the curve, and an absolute tolerance.

Definition at line 89 of file CurvatureUtils.C.

References ltol, and M_PI.

00094 {
00095   double tstep;
00096 
00097   if (radius > ltol) {
00098     // Estimate the opening angle of the segments based on the error formula.
00099     double talpha = M_PI/0.4879*pow(aepsge/radius,1.0/6.0);
00100 
00101     // Estimate step length equal to curve length of this circular arc,
00102     // We limit the step length to half the radius of curvature.
00103     tstep = std::min(talpha,0.5)*radius;
00104   }
00105 
00106   else if (radius >= 0.0)  //  Radius of curvature is zero 
00107     tstep = 100.0*aepsge;
00108 
00109   else       //  Infinite radius of curvature
00110     tstep = 1.e4*aepsge;   // @@ ????  tstep = amax in s1311
00111 
00112   return tstep;
00113 }

template<typename ForwardIterator >
go_iterator_traits<ForwardIterator>::value_type Go::sum ( ForwardIterator  first,
ForwardIterator  last 
) [inline]

sum finds the sum of the elements

Definition at line 112 of file Utils.h.

Referenced by Go::SplineSurface::accumulateBasis(), Go::SplineCurve::appendCurve(), Go::CreatorsUtils::createCrossTangent(), curve_ratder(), LUDecomp(), Go::SmoothSurfSet::removeKnownCoefs(), Go::SmoothSurf::setSideConstraints(), Go::SmoothCurve::setSideConstraints(), and trapezoidal().

00114         {
00115             typename go_iterator_traits<ForwardIterator>::value_type sum = 0;
00116             for (; first != last; ++first)
00117                 sum += *first;
00118             return sum;
00119         }

template<typename ForwardIterator >
go_iterator_traits<ForwardIterator>::value_type Go::sum_squared ( ForwardIterator  first,
ForwardIterator  last 
) [inline]

sum_squared finds the squared sum of the elements

Definition at line 124 of file Utils.h.

Referenced by Go::CoonsPatchGen::blendcoef(), and normalize().

00126         {
00127             typename go_iterator_traits<ForwardIterator>::value_type sum = 0;
00128             for (; first != last; ++first)
00129                 sum += (*first)*(*first);
00130             return sum;
00131         }

void Go::surface_ratder ( double const   eder[],
int  idim,
int  ider,
double  gder[] 
)

This function takes as input the position and a certain number of derivatives in homogenous space of a point on a rational surface.

It outputs the positioin and derivatives of this point in non-homogenous ("ordinary") space. (Corresponds to s6strider in SISL)

Parameters:
eder pointer to double array of dimenson [(ider+1)*(ider+2)*(idim+1)/2] containing the position and the derivative vectors of the homogeneous surface at the point with parameter value (epar[0],epar[1]). (idim+1 is the number of components of each B-spline coefficient, i.e. the dimension of the homogemous space in which the surface lies.) These vectors are stored in the following order: First the idim+1 components of the position vector, then the idim+1 components of the D(1,0) vector, then the idim+1 components of the D(0,1) vector, then the idim+1 components of the D(2,0) vector, followed by D(1,1), D(0,2) and so on up to the idim+1 components of the D(0,ider).
idim The dimension of the non homogenous space
ider The number of input derivatives with respect to both parameter directions.
gder pointer to the array where the result will be written (in same order as 'eder').

Definition at line 166 of file ratder.C.

References ALWAYS_ERROR_IF, and binom().

Referenced by Go::SplineSurface::point(), Go::SplineSurface::pointsGrid(), and surfaceKinks().

00170              : To calculate the value and ider*ider derivatives of 
00171 *              a rational B-spline surface.
00172 *
00173 * INPUT      : eder    - Double array of dimenson [(ider+1)*(ider+2)*(idim+1)/2]
00174 *                        containing the position and the derivative vectors
00175 *                        of the homogeneous surface at the point with parameter value
00176 *                        (epar[0],epar[1]).
00177 *                        (idim+1 is the number of components of each B-spline
00178 *                        coefficient, i.e. the dimension of the homogemous
00179 *                        space in which the surface lies.)
00180 *                        These vectors are stored in the following order:
00181 *                        First the idim+1 components of the position vector,
00182 *                        then the idim+1 components of the D(1,0) vector,
00183 *                        then the idim+1 components of the D(0,1) vector,
00184 *                        then the idim+1 components of the D(2,0) vector,
00185 *                        followed by D(1,1), D(0,2)
00186 *                        and so on up to the idim+1 components of the D(0,ider).
00187 *              idim    - The dimension of the non homogenous space
00188 *              ider    - The number of input derivatives with respect
00189 *                        to both parameter directions.
00190 *
00191 *
00192 * OUTPUT     : jstat   - Status message
00193 *                                        >0      : Warning
00194 *                                        =0      : ok
00195 *                                        <0      : Error
00196 *              gder    - Double array of dimension [(ider+1)*(ider+2)*idim/2]
00197 *                        containing the position and the derivative vectors
00198 *                        of the surface at the point with parameter value
00199 *                        (epar[0],epar[1]).
00200 *                        (idim is the number of components of each B-spline
00201 *                        coefficient, i.e. the dimension of the Euclidean
00202 *                        space in which the surface lies.)
00203 *                        These vectors are stored in the following order:
00204 *                        First the idim components of the position vector,
00205 *                        then the idim components of the D(1,0) vector,
00206 *                        then the idim components of the D(0,1) vector,
00207 *                        then the idim components of the D(2,0) vector,
00208 *                        followed by D(1,1), D(0,2)
00209 *                        and so on up to the idim components of the D(0,ider).
00210 *
00211 *
00212 * METHOD     :  The surface P(u,v) can be written as the quotient
00213 *               P(u,v) = T(u,v) / w(u,v) where T and w are ordinary splines.
00214 *               The dimensions of T and w are idim and 1
00215 *               respectively. The array eder contains position
00216 *               and derivatives of the idim+1 dimensional surface
00217 *               (T(u,v),w(u,v)).
00218 *
00219 *               Now, since wP = T, we find, by the Leibnitz formula,
00220 *
00221 *      k   l
00222 *                  k!       l!     (k-i,l-j) (i,j)         (k,l)
00223 *     sum sum   -------- -------- w         P         =   T       .
00224 *               i!(k-i)! j!(l-j)!
00225 *     i=0 j=0
00226 *
00227 *               Therefore
00228 *               
00229 *
00230 *              --            k   l                                     --
00231 *      (k,l)   |   (k,l)                k!       l!     (k-i,l-j) (i,j) |    
00232 *     P      = |  T      -  sum sum  -------- -------- w         P      | / w .
00233 *              |                     i!(k-i)! j!(l-j)!                  |
00234 *              --           i=0 j=0                                    --
00235 *                               i+j<k+l
00236 *
00237 *               This formula is applied recursively to evaluate P's derivatives.
00238 *
00239 *                                                          MF.
00240 *
00241 *
00242 *
00243 * CALLS      :
00244 *
00245 * WRITTEN BY : Michael Floater, SI, 3.9.92.
00246 *                Essentially the same as s6sratder
00247 *                except that we work with triangular matrices
00248 *                ((0,0), (1,0), (0,1), (2,0), (1,1), ...)
00249 *                instead of rectangular ones.
00250 * Revised by : Christophe Rene Birkeland, SINTEF Oslo, May 1993.
00251 *              Error message corrected
00252 * Revised by : Atgeirr F Rasmussen, SINTEF, 06/04/2001. Go and C++-ified.
00253 *
00254 *********************************************************************
00255 */
00256 {
00257   double w0;           /* The denominator.                       */
00258   int ki;              /* Count through dimensions.              */
00259   int idu;             /* Count through derivatives in u.        */
00260   int idv;             /* Count through derivatives in v.        */
00261   int* binom;
00262   std::vector<int> binomvec;
00263   int *binomu=0;    /* Pointer to binomial coefficients in u. */
00264   int *binomv=0;    /* Pointer to binomial coefficients in v. */
00265   double *sum1=0;   /* Leibnitz expansion in u                */
00266   double *sum2=0;   /* Leibnitz expansion in u and v.         */
00267   std::vector<double> sum1v;
00268   std::vector<double> sum2v;
00269   double sumdum1[4];   /* Fixed space for sum1.                  */
00270   double sumdum2[4];   /* Fixed space for sum2.                  */
00271   int idimp1;          /* idim + 1.                              */
00272   int iw;              /* Pointer to a weight.                   */
00273   int igder;           /* Pointer to already calculated derivs.  */
00274   int i,iu,iv,j,k;     /* Counters.                              */
00275   int iderp1;          /* ider + 1.                              */
00276   int igrow;           /* (ider+1) * idim.                       */  
00277   int iwrow;           /* (ider+1) * idimp1.                     */  
00278   int iutemp,ivtemp;   /* Used to find next weight in the sum.   */
00279   int tot,temp1;       /* Temporary variables.                   */
00280   int bidum[10];       /* Array for storing binomial coeffs.     */
00281   double temp;         /* Temporary multiple.                    */
00282   
00283   ALWAYS_ERROR_IF(ider<0, "Less than zero derivatives ?!?");
00284   ALWAYS_ERROR_IF(idim<1, "Less than zero derivatives ?!?");
00285 
00286   /* Find denominator. */ 
00287   
00288   w0 = eder[idim];
00289   if (fabs(w0)<1e-13) w0 = (double)1.0; // Maybe we should throw instead?
00290 
00291   /* If we're only asked for position, we'll do it
00292      now and exit for the sake of speed. */
00293 
00294   if(ider == 0)
00295   {
00296     for(ki=0; ki<idim; ki++)
00297       gder[ki] = eder[ki] / w0;
00298 
00299     return;
00300   }
00301 
00302   /* Set up some constants. */
00303 
00304   idimp1  = idim + 1;
00305   iderp1 = ider + 1;
00306   igrow   = iderp1 * idim;
00307   iwrow   = igrow + iderp1;  /* = iderp1 * idimp1 */
00308 
00309   /* Set up  binomial coefficients.
00310      Use new array only when ider > 3. */
00311 
00312   if (ider > 3)
00313   { 
00314     binomvec.resize((iderp1*(iderp1+1))/2);
00315     binom = &binomvec[0];
00316   }
00317   else
00318   { 
00319     binom = bidum;
00320   }
00321 
00322   for(j=0,k=0; j<=ider; j++,k+=j)
00323   {
00324       /* Calculate the new row of binomial coefficients. */
00325   
00326       binom[k] = 1;
00327   
00328       for(i=k+1; i<k+j; i++)
00329       {
00330           binom[i] = binom[i-j-1] + binom[i-j];
00331       }
00332 
00333       binom[k+j] = 1;
00334   }
00335 
00336   /* Set up space for sum1 and sum2 if necessary.
00337      Use new arrays only when idim > 4. */
00338 
00339   if (idim > 4)
00340   { 
00341     sum1v.resize(idim);
00342     sum1 = &sum1v[0];
00343     sum2v.resize(idim);
00344     sum2 = &sum2v[0];
00345   }
00346   else
00347   { 
00348     sum1=sumdum1;
00349     sum2=sumdum2;
00350   }
00351   
00352   /* Loop through derivatives in u and v. */
00353 
00354   for(idv=0,binomv=binom; idv<=ider; idv++,binomv+=idv)
00355   {
00356     for(idu=0,binomu=binom; idu<=ider-idv; idu++,binomu+=idu)
00357     {
00358       if(idu == 0 && idv == 0)
00359       {
00360           /* Position is a special case. */
00361     
00362           for(ki=0; ki<idim; ki++)
00363             gder[ki] = eder[ki] / w0;
00364       }
00365       else
00366       {
00367           /* Calculate indices in eder and gder. */
00368     
00369           tot = idu + idv;
00370           temp1 = ((tot * (tot+1)) >> 1) + idv;
00371     
00372           j = temp1 * idim;
00373           k = j + temp1;
00374 
00375           /* Calculating each coefficient of the (idu,idv)'th
00376              derivative of the rational surface (in gder).
00377         
00378              This requires calculating the Liebnitz sum from
00379              the subarray of gder (0,..,idu, 0,...,idv) and
00380              the subarray of eder (0,..,idu, 0,...,idv). */
00381 
00382           /* Calculate the Leibnitz sum. */
00383 
00384           for(ki=0; ki<idim; ki++)
00385             sum2[ki] = (double)0.0;        
00386 
00387           for(iv=0; iv<=idv; iv++)
00388           {
00389             for(ki=0; ki<idim; ki++)
00390                sum1[ki] = (double)0.0;                 
00391             ivtemp = idv-iv;
00392 
00393             for(iu=0; iu<=idu; iu++)
00394             {
00395                 tot = iu + iv;
00396                 temp1 = ((tot * (tot+1)) >> 1) + iv;
00397 
00398                 igder = temp1 * idim;
00399                 iutemp = idu-iu;
00400 
00401                 tot = iutemp + ivtemp;
00402                 temp1 = ((tot * (tot+1)) >> 1) + ivtemp;
00403 
00404                 iw   = temp1 * idimp1 + idim;
00405 
00406               /* Add the next Leibnitz term unless we
00407                  have reached the last one (the unknown). */
00408   
00409                 if(iu<idu || iv<idv)
00410                 {
00411                   /* If iu=0 or iu=idu, the u binomial
00412                      coefficient is 1 so don't multiply. */
00413   
00414                     if(iu>0 && iu<idu)
00415                     {
00416                       temp = (double)binomu[iu] * eder[iw];
00417                       for(ki=0; ki<idim; ki++,igder++)
00418                          sum1[ki] += temp * gder[igder];
00419                      }
00420                      else
00421                        for(ki=0; ki<idim; ki++,igder++)
00422                          sum1[ki] += eder[iw] * gder[igder];
00423                 }
00424             }
00425   
00426             /* If iv=0 or iv=idv, the v binomial
00427                coefficient is 1 so don't multiply. */
00428   
00429             if(iv>0 && iv<idv)
00430               for(ki=0; ki<idim; ki++)
00431                   sum2[ki] += (double)binomv[iv] * sum1[ki];
00432             else
00433               for(ki=0; ki<idim; ki++)
00434                  sum2[ki] += sum1[ki];              
00435           }
00436           for(ki=0; ki<idim; ki++,j++,k++)
00437             gder[j] = (eder[k] - sum2[ki]) / w0;
00438       }
00439     }
00440   }  
00441 
00442   return;
00443 }

void Go::surfaceKinks ( const SplineSurface &  sf,
double  max_normal_angle,
std::vector< double > &  g1_disc_u,
std::vector< double > &  g1_disc_v,
bool  compute_g1_disc = true 
)

Surface assumed to be continuous.

Return parameter values failing to achieve G1-continuity.

Definition at line 720 of file GeometryTools.C.

References ALWAYS_ERROR_IF, Go::Point::angle(), Go::SplineSurface::basis(), Go::Point::begin(), Go::BsplineBasis::begin(), Go::SplineSurface::coefs_begin(), Go::SplineSurface::coefs_end(), Go::BsplineBasis::computeBasisValues(), Go::BsplineBasis::computeBasisValuesLeft(), Go::SplineSurface::dimension(), Go::Point::dist(), Go::Point::end(), Go::BsplineBasis::end(), Go::BsplineBasis::knotIntervalFuzzy(), Go::BsplineBasis::knotMultiplicity(), Go::BsplineBasis::numCoefs(), Go::BsplineBasis::order(), Go::SplineSurface::rational(), Go::SplineSurface::rcoefs_begin(), Go::SplineSurface::rcoefs_end(), Go::Point::resize(), Go::Point::setValue(), Go::BsplineBasis::startparam(), surface_ratder(), and transpose_array().

Referenced by Go::BoundedUtils::trimSurfaceKinks().

00724 {
00725     int dim = sf.dimension();
00726     bool rational = sf.rational();
00727     int kdim = dim + (rational);
00728     ALWAYS_ERROR_IF(dim != 3,
00729                 "Expecting surface to be of dimension 3.");
00730     g1_disc_u.clear();
00731     g1_disc_v.clear();
00732 
00733     bool dir_is_u = true; // We traverse dir given by dir_is_u, looking for kinks.
00734     for (int ki = 0; ki < 2; ++ki) { // We perform calculations in both parameter directions.
00735         const BsplineBasis& basis = sf.basis(!dir_is_u);
00736         const BsplineBasis& other_basis = sf.basis(dir_is_u);
00737         std::vector<double> disc_candidates;
00738         int order = basis.order();
00739         int other_order = other_basis.order();
00740         int num_coefs = basis.numCoefs();
00741         int other_num_coefs = other_basis.numCoefs();
00742         std::vector<double> coefs(rational ? sf.rcoefs_begin() : sf.coefs_begin(), 
00743                                   rational ? sf.rcoefs_end() : sf.coefs_end());
00744         if (!dir_is_u) // We may now assume that direction is u.
00745             transpose_array(kdim, num_coefs, other_num_coefs, &coefs[0]);
00746 
00747         int nmb_int_samples = (rational) ?
00748             9*other_order - 11 : 4*other_order - 5; // # of evaluations for each knot interval
00749 
00750         if (!compute_g1_disc)
00751         {
00752             // Check for parametric continuity. Fewer evaluations are required
00753             nmb_int_samples = (rational) ? 4*other_order - 1 : other_order-1;
00754         }
00755 
00756         int g1_mult = order - 2; // Multiplicity for which g1 is assured.
00757         std::vector<double>::const_iterator iter = basis.begin() + order;
00758         std::vector<double>::const_iterator end_iter = basis.end() - order;
00759         for (; iter != end_iter; ++iter)
00760             if (iter[0] == iter[g1_mult]) {
00761                 disc_candidates.push_back(*iter);
00762                 while (iter[0] == iter[1])
00763                     ++iter;
00764             }
00765 
00766         // For each possible discontinuity we calculate angles between normals.
00767         for (size_t kj = 0; kj < disc_candidates.size(); ++kj) {
00768             double tpar = disc_candidates[kj];
00769             int derivs = 1;
00770             std::vector<double> basis_vals_left = // Computing from the left.
00771                 basis.computeBasisValuesLeft(tpar, derivs);
00772             std::vector<double> basis_vals_right = // Computing from the right.
00773                 basis.computeBasisValues(tpar, derivs);
00774             int coef_li = basis.knotIntervalFuzzy(tpar) - order + 1;
00775             int mult = basis.knotMultiplicity(tpar);
00776             int coef_left_li = coef_li - mult;
00777 
00778             // To increase performance we avoid recalculating basis values when next
00779             // knots is in the same interval.
00780             std::vector<double>::const_iterator iter = other_basis.begin();
00781             while (iter != other_basis.end()) {
00782                 std::vector<double>::const_iterator next_iter = iter + 1;
00783                 while ((next_iter < other_basis.end()) && (*next_iter == *iter))
00784                     ++next_iter;
00785                 if (next_iter == other_basis.end()) {
00786                     break;
00787                 }
00788                 double tstep = (*next_iter - *iter)/(nmb_int_samples - 1);
00789                 double tmin = other_basis.startparam();
00790                 int kh;
00791                 for (kh = 0; kh < nmb_int_samples; ++kh) {
00792                     double other_tpar = tmin + kh*tstep;
00793                     // We must calculate normals from both sides of the iso-curve.
00794                     std::vector<double> other_basis_vals =
00795                         other_basis.computeBasisValues(other_tpar, derivs);
00796                     int other_coef_li = other_basis.knotIntervalFuzzy(other_tpar) - other_order + 1;
00797 
00798                     Point part_left(kdim);
00799                     part_left.setValue(0.0);
00800                     Point part_right = part_left;
00801                     Point other_part = part_left;
00802                     Point pt = part_left;
00803                     // We compute the partial derivatives in both dirs, assuming surface is cont.
00804                     for (int ii = 0; ii < order; ++ii)
00805                         for (int jj = 0; jj < other_order; ++jj)
00806                             for (int kk = 0; kk < kdim; ++kk) {
00807                                 double coef =
00808                                     coefs[kdim*((other_coef_li+jj)*num_coefs+coef_li+ii)+kk];
00809                                 double coef_l =
00810                                     coefs[kdim*((other_coef_li+jj)*num_coefs+coef_left_li+ii)+kk];
00811                                 pt[kk] +=
00812                                     coef*basis_vals_right[2*ii]*other_basis_vals[2*jj];
00813                                 part_left[kk] +=
00814                                     coef_l*basis_vals_left[2*ii+1]*other_basis_vals[2*jj];
00815                                 part_right[kk] +=
00816                                     coef*basis_vals_right[2*ii+1]*other_basis_vals[2*jj];
00817                                 other_part[kk] +=
00818                                     coef*basis_vals_left[2*ii]*other_basis_vals[2*jj+1];
00819                             }
00820                     if (rational) {
00821                         std::vector<double> restemp(3*kdim);
00822                         std::copy(pt.begin(), pt.end(), restemp.begin());
00823                         std::copy(part_left.begin(), part_left.end(), restemp.begin() + kdim);
00824                         std::copy(other_part.begin(), other_part.end(), restemp.begin() + 2*kdim);
00825                         std::vector<double> restemp2(3*dim);
00826                         surface_ratder(&restemp[0], dim, 1, &restemp2[0]);
00827                         part_left.resize(dim);
00828                         part_left.setValue(&restemp2[dim]);
00829                         std::copy(part_right.begin(), part_right.end(), restemp.begin() + kdim);
00830                         surface_ratder(&restemp[0], dim, 1, &restemp2[0]);
00831                         part_right.resize(dim);
00832                         part_right.setValue(&restemp2[dim]);
00833                         other_part.resize(dim);
00834                         other_part.setValue(&restemp2[2*dim]);
00835                     }
00836 
00837                     double angle;
00838                     if (compute_g1_disc)
00839                     {
00840                         // Compute angle between surface normals
00841                         Point left_normal = part_left%other_part;
00842                         Point right_normal = part_right%other_part;
00843                         angle = left_normal.angle(right_normal);
00844                     }
00845                     else
00846                     {
00847                         // Compute difference between partial derivatives 
00848                         angle = part_left.dist(part_right);
00849                     }
00850 
00851                     if (angle > max_normal_angle) {
00852                         if (dir_is_u)
00853                             g1_disc_u.push_back(tpar);
00854                         else
00855                             g1_disc_v.push_back(tpar);
00856                         break;
00857                     }
00858                 }
00859                 if (kh < nmb_int_samples)
00860                     break;
00861                 else
00862                     iter = next_iter;
00863             }
00864         }
00865         dir_is_u = false;
00866     }
00867 }

boost::shared_ptr< SplineSurface > Go::surfaceSum ( const SplineSurface &  sf1,
double  fac1,
const SplineSurface &  sf2,
double  fac2,
double  num_tol = 1e-05 
)

Definition at line 25 of file surfaceSum.C.

References ALWAYS_ERROR_IF, Go::SplineSurface::clone(), Go::SplineSurface::endparam_u(), Go::SplineSurface::endparam_v(), Go::SplineSurface::rational(), Go::SplineSurface::startparam_u(), Go::SplineSurface::startparam_v(), THROW, and unifySurfaceSplineSpace().

00033   {
00034     // Check input
00035     ALWAYS_ERROR_IF(fabs(sf1.startparam_u() - sf2.startparam_u()) > num_tol ||
00036                     fabs(sf1.endparam_u() - sf2.endparam_u()) > num_tol ||
00037                     fabs(sf1.startparam_v() - sf2.startparam_v()) > num_tol ||
00038                     fabs(sf1.endparam_v() - sf2.endparam_v()) > num_tol,
00039                     "Inconsistent parameter domain.");
00040 
00041     // For the time being
00042     if (sf1.rational() || sf2.rational()) {
00043         THROW("Sum of rational surfaces is not implemented");
00044     }
00045 
00046     // Make copy of surfaces
00047     vector<shared_ptr<SplineSurface> > surfaces;
00048     surfaces.reserve(2);
00049     shared_ptr<SplineSurface> sf;
00050 // #ifdef _MSC_VER
00051 //     sf = shared_ptr<SplineSurface>(dynamic_cast<SplineSurface*>(sf1.clone()));
00052 // #else
00053     sf = shared_ptr<SplineSurface>(sf1.clone());
00054 // #endif
00055     surfaces.push_back(sf);
00056 // #ifdef _MSC_VER
00057 //     sf = shared_ptr<SplineSurface>(dynamic_cast<SplineSurface*>(sf2.clone()));
00058 // #else
00059     sf = shared_ptr<SplineSurface>(sf2.clone());
00060 // #endif
00061     surfaces.push_back(sf);
00062 
00063     // Make sure that the surfaces live on the same knot vector
00064     unifySurfaceSplineSpace(surfaces, num_tol);
00065 
00066     // Add signed coefficients
00067     vector<double> coefs;
00068     int nmb_coefs_u = surfaces[0]->numCoefs_u();
00069     int nmb_coefs_v = surfaces[0]->numCoefs_v();
00070     int dim = surfaces[0]->dimension();
00071     coefs.resize(dim*nmb_coefs_u*nmb_coefs_v);
00072     int ki;
00073     std::vector<double>::iterator s1 = surfaces[0]->coefs_begin();
00074     std::vector<double>::iterator s2 = surfaces[1]->coefs_begin();
00075     for (ki=0; ki<dim*nmb_coefs_u*nmb_coefs_v; ki++)
00076       coefs[ki] = fac1*s1[ki] + fac2*s2[ki];
00077 
00078     // Create output curve
00079     boost::shared_ptr<SplineSurface>
00080         surfacesum(new SplineSurface(nmb_coefs_u, nmb_coefs_v,
00081                                      surfaces[0]->order_u(),
00082                                      surfaces[0]->order_v(),
00083                                      surfaces[0]->basis_u().begin(),
00084                                      surfaces[0]->basis_v().begin(),
00085                                      &coefs[0], dim, false));
00086 
00087     return surfacesum;
00088   }

void Go::systemSleep ( double  sleep_time  ) 

Sleep for sleep_time seconds.

Definition at line 127 of file timeutils.C.

00129     {
00130         // Sleep if sleep time is positive
00131         if( sleep_time > 0 )
00132         {
00133 #ifdef WIN32
00134 #ifndef _WIN32_WCE
00135             Sleep((unsigned long)(sleep_time*1000));
00136 #else
00137             // Do not sleep...
00138 #endif
00139 #else
00140 #ifdef __GNUC__
00141             usleep((long)(sleep_time*1e6));
00142 #else
00143             usleep(sleep_time*1e6);
00144 #endif
00145 #endif
00146         }
00147     }

double Go::tanLenFromRadius ( double  radius,
double  angle 
)

To create the tangent length for interpolating a circular arc with an almost equi-oscillating Hermit qubic.

Definition at line 116 of file CurvatureUtils.C.

Referenced by getHermiteData().

00121 {
00122   double tcos,tsin;          /* Dummy variables                     */
00123   double ta,tb,tc,tl;        /* Dummy variables                     */
00124   double tconst = (double)1.85530139760811990992528773586425;
00125                              /* Constant used in the calculation    */
00126   
00127   
00128   
00129   tcos = cos(angle);
00130   tsin = sin(angle);
00131   
00132   /*  Calculate length of tangents
00133    *   tconst = (3-2sqrt(2))**1/3 + (3+2sqrt(2))**1/3 - 0.5 */
00134   
00135   ta     = (double)0.6*tconst - (double)0.9*tcos;
00136   tb     = ((double)0.4*tconst+(double)1.8)*tsin;
00137   tc     = ((double)0.4*tconst+(double)1.0)
00138            * tcos - (double)0.4*tconst - (double)1.0;
00139   tl     = radius*(-tb+sqrt(tb*tb-4*ta*tc))/((double)2.0*ta);
00140   
00141   return(tl);
00142 }

void Go::translateLineCloud ( const Point &  trans_vec,
LineCloud &  lc 
)

Translate the given LineCloud by trans_vec.

Definition at line 1023 of file GeometryTools.C.

References Go::Array< T, Dim >::begin(), Go::Array< T, Dim >::end(), Go::LineCloud::numLines(), Go::LineCloud::point(), and Go::LineCloud::rawData().

01025 {
01026     int ki;
01027     int nmb_pts = lc.numLines()*2;
01028     int dim = 3;
01029     for (ki = 0; ki < nmb_pts; ++ki) {
01030         Vector3D vec = lc.point(ki);
01031         Point pt(vec.begin(), vec.end());
01032         pt += trans_vec;
01033         copy(pt.begin(), pt.end(), lc.rawData() + ki*dim);
01034     }
01035 }

void Go::translateSplineCurve ( const Point &  trans_vec,
SplineCurve &  cv 
)

Translate the given SplineCurve by trans_vec.

Definition at line 999 of file GeometryTools.C.

References ASSERT, Go::SplineCurve::coefs_begin(), Go::SplineCurve::coefs_end(), Go::Point::dimension(), Go::SplineCurve::rational(), Go::SplineCurve::rcoefs_begin(), and Go::SplineCurve::rcoefs_end().

Referenced by Go::Circle::geometryCurve(), and Go::BoundedUtils::translateBoundedSurf().

01001 {
01002     int ki;
01003     ASSERT(trans_vec.dimension() == 3); // We're working in 3D space.
01004     int dim = 3 + cv.rational();
01005     std::vector<double>::iterator iter = cv.rational() ? cv.rcoefs_begin() : cv.coefs_begin();
01006     std::vector<double>::iterator end_iter = cv.rational() ? cv.rcoefs_end() : cv.coefs_end();
01007     std::vector<double>::iterator coef_iter = cv.coefs_begin();
01008     while (iter != end_iter) { // @@ A faster approach would be to use rotation matrix directly.
01009         double weight = cv.rational() ? iter[3] : 1.0;
01010         for (ki = 0; ki < 3; ++ki)
01011             iter[ki] = (iter[ki]/weight + trans_vec[ki])*weight;
01012         if (cv.rational()) {
01013             for (ki = 0; ki < 3; ++ki)
01014                 coef_iter[ki] = iter[ki]/weight;
01015             coef_iter += dim - 1;
01016         }
01017         iter += dim;
01018     }
01019 }

void Go::translateSplineSurf ( const Point &  trans_vec,
SplineSurface &  sf 
)

Translate the given SplineSurface by trans_vec.

Definition at line 976 of file GeometryTools.C.

References ASSERT, Go::SplineSurface::coefs_begin(), Go::SplineSurface::coefs_end(), Go::Point::dimension(), Go::SplineSurface::rational(), Go::SplineSurface::rcoefs_begin(), and Go::SplineSurface::rcoefs_end().

Referenced by Go::Sphere::geometrySurface(), Go::Cylinder::geometrySurface(), Go::Cone::geometrySurface(), and Go::BoundedUtils::translateBoundedSurf().

00978 {
00979     int ki;
00980     ASSERT(trans_vec.dimension() == 3); // We're working in 3D space.
00981     int dim = 3 + sf.rational();
00982     std::vector<double>::iterator iter = sf.rational() ? sf.rcoefs_begin() : sf.coefs_begin();
00983     std::vector<double>::iterator end_iter = sf.rational() ? sf.rcoefs_end() : sf.coefs_end();
00984     std::vector<double>::iterator coef_iter = sf.coefs_begin();
00985     while (iter != end_iter) {
00986         double weight = sf.rational() ? iter[3] : 1.0;
00987         for (ki = 0; ki < 3; ++ki)
00988             iter[ki] = (iter[ki]/weight + trans_vec[ki])*weight;
00989         if (sf.rational()) {
00990             for (ki = 0; ki < 3; ++ki)
00991                 coef_iter[ki] = iter[ki]/weight;
00992             coef_iter += dim - 1;
00993         }
00994         iter += dim;
00995     }
00996 }

void Go::transpose_array ( int  dim,
int  m,
int  n,
double *  array_start 
)

Transpose an (m x n) matrix of dim-dimensional points stored as an array in row-major order (i.e.

all elements of a single row are stored together).

Parameters:
dim the dimension of each of the points in the array
m number of lines in the matrix
n number of columns in the matrix
array_start pointer to the start of array where matrix is stored

Definition at line 29 of file Utils.C.

Referenced by Go::SplineSurface::interpolate(), main(), surfaceKinks(), Go::RectGrid::swapDirections(), and Go::SplineSurface::swapParameterDirection().

00032 {
00033     std::vector<double> c(array_start,
00034                           array_start + dim*num_old_cols*num_old_rows);
00035     for (int new_row = 0; new_row < num_old_cols; ++new_row) {
00036         for (int new_col = 0; new_col < num_old_rows; ++new_col) {
00037             for (int dd = 0; dd < dim; ++dd) {
00038                 array_start[new_row*num_old_rows*dim + new_col*dim + dd]
00039                     = c[new_col*num_old_cols*dim + new_row*dim + dd];
00040             }
00041         }
00042     }
00043 }

template<typename Functor >
void Go::trapezoidal ( Functor &  f,
double  a,
double  b,
double &  s,
int  n 
) [inline]

This routine computes the n'th stage of refinement of an extended trapezoidal rule.

Used as a help routine for 'simpsons_rule', found further down in this file. NB: It only carries out the computation for ONE stage of the procedure, so if you want to use it to integrate a function, you must call it successively for n = 1, n = 2, ....

Definition at line 35 of file Integration.h.

References DEBUG_ERROR_IF, f(), and sum().

Referenced by simpsons_rule().

00036 {
00037     DEBUG_ERROR_IF(n < 1, "Bad function argument to trapezoidal().");
00038     if (n == 1) {
00039         s = 0.5 * (b - a) * (f(a) + f(b));
00040     } else {
00041         int num_int_pts = 1 << (n-2);
00042         //int num_int_pts = std::power(2, n-2);
00043         double spacing = (b - a) / num_int_pts;
00044         double x = a + 0.5 * spacing;
00045         double sum = 0.0;
00046         for (int i = 0; i < num_int_pts; ++i) {
00047             sum += f(x);
00048             x += spacing;
00049         }
00050         s += (b - a) * sum / num_int_pts;
00051         s *= 0.5;
00052     }
00053 }

bool Go::trim_a_triangle ( boost::shared_ptr< SplineSurface srf,
vector< Vector3D > &  vert,
vector< Vector2D > &  vert_p,
vector< int > &  bd,
vector< Vector3D > &  norm,
const vector< Vector3D > &  trim_curve_p,
const vector< int > &  contour,
const int  c1_indx,
const int  c2_indx,
const int  c3_indx,
vector< int > &  mesh,
const bool  inner_trimming_curve = false 
)

Definition at line 1022 of file spline2mesh.C.

References add_triangle(), DBG_FLAG, degenerate_triangle(), is_inside(), is_on_contour(), and split_triangle().

Referenced by trim_a_triangle_soup().

01035   {
01036 #ifndef DBG
01037     const bool dbg=false;
01038 #endif
01039     if (dbg)
01040       printf("\n\n= trim_a_triangle starting =====================================================================\n");
01041 
01042     vector<int> new_mesh;
01043 
01044     const Vector3D c1=vert[c1_indx], c2=vert[c2_indx], c3=vert[c3_indx];
01045     const Vector3D n1=norm[c1_indx], n2=norm[c2_indx], n3=norm[c3_indx];
01046     const Vector2D c1_p=vert_p[c1_indx], c2_p=vert_p[c2_indx], c3_p=vert_p[c3_indx];
01047     int s0, s, s3;
01048 
01049     if (dbg)
01050       {
01051         printf("\n  The corners:\n\n");
01052         printf("hold on; plot(%f, %f, 'rx', 'markersize', %d, 'linewidth', 2); hold off\n", c1_p[0], c1_p[1], 14);
01053         printf("hold on; plot(%f, %f, 'gx', 'markersize', %d, 'linewidth', 2); hold off\n", c2_p[0], c2_p[1], 14);
01054         printf("hold on; plot(%f, %f, 'bx', 'markersize', %d, 'linewidth', 2); hold off\n\n", c3_p[0], c3_p[1], 14);
01055       }
01056 
01057     if (dbg) printf("  = Calling is_inside (point_inside_contour) for corner c1... ============================\n");
01058     const int c1_inside = is_inside(trim_curve_p, contour, c1_p[0], c1_p[1] DBG_FLAG);
01059     if (dbg) printf("  = Calling is_inside (point_inside_contour) for corner c2... ============================\n");
01060     const int c2_inside = is_inside(trim_curve_p, contour, c2_p[0], c2_p[1] DBG_FLAG);
01061     if (dbg) printf("  = Calling is_inside (point_inside_contour) for corner c3... ============================\n");
01062     const int c3_inside = is_inside(trim_curve_p, contour, c3_p[0], c3_p[1] DBG_FLAG);
01063 
01064     if (dbg) printf("  = Calling is_on_contour (point_on_contour) for corner c1... ============================\n");
01065     const int c1_on     = is_on_contour(trim_curve_p, contour, c1_p[0], c1_p[1] DBG_FLAG);
01066     if (dbg) printf("  = Calling is_on_contour (point_on_contour) for corner c2... ============================\n");
01067     const int c2_on     = is_on_contour(trim_curve_p, contour, c2_p[0], c2_p[1] DBG_FLAG);
01068     if (dbg) printf("  = Calling is_on_contour (point_on_contour) for corner c3... ============================\n");
01069     const int c3_on     = is_on_contour(trim_curve_p, contour, c3_p[0], c3_p[1] DBG_FLAG);
01070 
01071     if (dbg)
01072       printf("----------------------------------------------------------------------------------------------------\n"
01073              "IN/ON-tests before considering whether curve is outer or inner:\n"
01074              "c1_inside=%d, c2_inside=%d, c3_inside=%d, c1_on=%d, c2_on=%d, c3_on=%d\n"
01075              "----------------------------------------------------------------------------------------------------\n",
01076              c1_inside, c2_inside, c3_inside, c1_on, c2_on, c3_on);
01077 
01078     // 100211: s2==0 <=> no corner on curve itself.
01079     const int s2 = (c1_on << 0)  +  (c2_on << 1)  +  (c3_on << 2);
01080 
01081     const Vector2D centroid = (1.0/3.0)*(c1_p+c2_p+c3_p);
01082     const int c_inside  = is_inside(trim_curve_p, contour, centroid[0], centroid[1]);
01083     
01084     if (inner_trimming_curve)
01085       {
01086         // 100211: s0==0 <=> all corners are not inside. (Is "on edge" included in "inside"?)
01087         s0 = ((!c1_inside) << 0) + ((!c2_inside) << 1) + ((!c3_inside) << 2);
01088 
01089         // 100211: 
01090         s = (((!c1_inside) | c1_on) << 0)  +  (((!c2_inside) | c2_on) << 1)  +  (((!c3_inside) | c3_on) << 2);
01091         
01092         // 100211: s3==true <=> "centroid is not inside".
01093         s3 = !c_inside;
01094 
01095         if (dbg)
01096 //        if ((s0!=7) || (s2!=0) || (s!=7))
01097           printf("  s0=%d, s2=%d, s=%d, s3=%d\n", s0, s2, s, s3);
01098         
01099         if ( (s0==0) && ((s2==1) || (s2==2) || (s2==4)) )
01100           {
01101             if (dbg)
01102               printf("No points on the inside, exactly one *on* the contour. Setting s=0 and skipping triangle. 1\n");
01103             s=0;
01104           }
01105         if ( ((s0==1) && (s2==1)) || ((s0==2) && (s2==2)) || ((s0==4) && (s2==4)) )
01106           {
01107             if (dbg)
01108               printf("Two points not on the inside, the remaining both inside and *on*. Skipping triangle. 2\n");
01109             s=0;
01110           }
01111 
01112         if (dbg)
01113           if ( (s==7) && (s3==0) )
01114             {
01115               printf("All corners on the inside, mean not, skipping triangle.\n");
01116               // 090220: This is not so straightforward... Not all these triangles are either fully inside or
01117               //         outside. They should really be split, but then we should split neighbours also, if we
01118               //         ever are to get a valid triangulation. (Which we are currently not getting, since we
01119               //         produce lots of duplicate nodes and so on...)
01120               //s=0;
01121             }
01122 
01123         if (dbg)
01124           if ( ((s2==3) && (s0==4)) ||
01125                ((s2==5) && (s0==2)) ||
01126                ((s2==6) && (s0==1))    )
01127             {
01128               printf("Two points on the curve, one inside. Skipping triangle.\n");
01129 //            s=0;
01130             }
01131         
01132         if (dbg)
01133           if (s2==7)
01134             {
01135               printf("All points on contour, guessing that the triangle should be excluded. \n");
01136               printf("  s0=%d, s2=%d, s=%d, s3=%d\n", s0, s2, s, s3);
01137 //            s=0;
01138             }
01139 
01140       }
01141     else
01142       {
01143         s0 = (c1_inside << 0) + (c2_inside << 1) + (c3_inside << 2);
01144         s = ((c1_inside | c1_on) << 0)  +  ((c2_inside | c2_on) << 1)  +  ((c3_inside | c3_on) << 2);
01145         s3 = c_inside;
01146 
01147         if (dbg)
01148           printf("---> s0=%d s2=%d s=%d s3=%d\n", s0, s2, s, s3), fflush(stdout);
01149 
01150         if ( (s0==0) && ((s2==1) || (s2==2) || (s2==4)) )
01151           {
01152             if (dbg)
01153               printf("No points on the inside, exactly one *on* the contour. Setting s=0 and skipping triangle. 4\n");
01154             // s=0;
01155           }
01156 
01157         if ( ((s0==1) && (s2==1)) || ((s0==2) && (s2==2)) || ((s0==4) && (s2==4)) )
01158           {
01159             if (dbg)
01160               printf("Two points not inside, the remaining both inside and *on*. Skipping triangle. s=%d 5\n", s);
01161             //s=0;
01162             //s=7;
01163           }
01164 
01165         if (dbg)
01166           if ((s==7) && (!s3))
01167             {
01168               printf("====================> HUH?! s0=%d s2=%d s=%d s3=%d\n", s0, s2, s, s3);
01169 //        s=0;
01170             }
01171         
01172         if (dbg)
01173           printf("---> s0=%d s2=%d s=%d s3=%d\n", s0, s2, s, s3), fflush(stdout);
01174         
01175       }
01176     
01177     if (degenerate_triangle(c1_p, c2_p, c3_p))
01178       {
01179         printf("Degenerate triangle! setting s=-1 and skipping triangle. 6\n");
01180         s=-1;
01181       }
01182 
01183           
01184     //
01185     // 100223: Hmm... What is really the pattern with respect to the usage of
01186     //         'forced_skipping_of_second_edge'-values used below? 
01187     //
01188     //         Note that if s==0, the triangle will silently be forgotten...
01189     //
01190     // 100225: No, adding a stage for this situation too.
01191     //
01192     //         Hmm... Maybe it's time to stop letting "on" imply "inside"...?!
01193     //
01194 
01195 #ifdef SPLIT_LARGE_TRIANGLES
01196     if (  (!(c1_inside || c2_inside || c3_inside))  &&  (!inner_trimming_curve)  &&  (c1_on || c2_on || c3_on)  )
01197       s=0;
01198 #endif
01199     
01200 
01201 
01202 
01203     bool redo=false;
01204     if (dbg)
01205       printf("  Going into the switch, s=%d\n", s);
01206     switch (s)
01207       {
01208 #ifdef SPLIT_LARGE_TRIANGLES
01209       case 0:
01210         if (dbg) printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
01211         if (!inner_trimming_curve)
01212           redo = split_triangle_with_all_corners_outside(c1_indx, c2_indx, c3_indx,
01213                                                          c1_inside, c2_inside, c3_inside,
01214                                                          c1_on, c2_on, c3_on,
01215                                                          srf, vert, vert_p, bd, norm, new_mesh, trim_curve_p, contour,
01216                                                          dbg, inner_trimming_curve);
01217         if (dbg) printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
01218         break;
01219 #endif
01220       case 5: // Corners 1 and 3 are inside, intersections must be on edges 1-2 and 2-3. Compatible with 1-case.
01221         // 090217: Not now, don't want the 'forced skip'.
01222         redo=split_triangle(c1_indx, c2_indx, c3_indx, srf, vert, vert_p, bd, norm, new_mesh,
01223                             trim_curve_p, contour, dbg, false, inner_trimming_curve);
01224         break;
01225       case 1: // Only corner 1 is inside, so intersections must be on edges 1-2 and 3-1.
01226         redo=split_triangle(c1_indx, c2_indx, c3_indx, srf, vert, vert_p, bd, norm, new_mesh,
01227                             trim_curve_p, contour, dbg, true, inner_trimming_curve);
01228         break;
01229       case 2: // Corner 2 is inside, intersections must be on edges 2-3 and 3-1. Can go straight into the 3-case.
01230 
01231         // 090217: Huh?! Should be 2-3 and 1-2, shouldn't it?!  Think maybe the comment was wrong, but
01232         //         conclusion and code correct.  Sadly, this will only work when the assumption about no
01233         //         "spurious" intersections is met. I.e., that there are no "superfluous"
01234         //         intersections. In many cases this does not hold. Trying to fix this by not combining
01235         //         cases here, and at the same time, not letting split_triangle choose to continue on the
01236         //         third edge if it does not find any intersection on the second edge. The problem seems
01237         //         to be that such a spurious intersection can be on edge 2, causing split_triangle not to
01238         //         look for the (correct and sought) intersection on edge 3...
01239 
01240         redo=split_triangle(c2_indx, c3_indx, c1_indx, srf, vert, vert_p, bd, norm, new_mesh, 
01241                             trim_curve_p, contour, dbg, true, inner_trimming_curve);
01242         break;
01243       case 3: // Corners 1 and 2 are inside, so intersections must be on edges 2-3 and 3-1.
01244         redo=split_triangle(c2_indx, c3_indx, c1_indx, srf, vert, vert_p, bd, norm, new_mesh,
01245                             trim_curve_p, contour, dbg, false, inner_trimming_curve);
01246         break;
01247       case 6: // Corners 2 and 3 are inside, intersections must be on edges 3-1 and 1-2. Compatible with 4-case.
01248         // 090217: Not now, don't want the 'forced skip'.
01249         redo=split_triangle(c3_indx, c1_indx, c2_indx, srf, vert, vert_p, bd, norm, new_mesh,
01250                             trim_curve_p, contour, dbg, false, inner_trimming_curve);
01251         break;
01252       case 4: // Corner 3 is inside, so intersections must be on edges 3-1 and 2-3.
01253         redo=split_triangle(c3_indx, c1_indx, c2_indx, srf, vert, vert_p, bd, norm, new_mesh,
01254                             trim_curve_p, contour, dbg, true, inner_trimming_curve);
01255         break;
01256       case 7: // All corners are inside, not splitting, just keeping it.
01257         add_triangle(vert_p, new_mesh, c1_indx, c2_indx, c3_indx);
01258         redo=false;
01259         break;
01260       }
01261     mesh=new_mesh;
01262 
01263     if (dbg)
01264       printf("  redo=%d\n= trim_a_triangle done ======================================================="
01265              "==================\n\n\n", redo);
01266 
01267     return redo;
01268   }

void Go::trim_a_triangle_soup ( boost::shared_ptr< SplineSurface srf,
vector< Vector3D > &  vert,
vector< Vector2D > &  vert_p,
vector< int > &  bd,
vector< Vector3D > &  norm,
const vector< Vector3D > &  trim_curve_p,
const vector< int > &  contour,
vector< int > &  mesh,
const bool  inner_trimming_curve = false 
)

Definition at line 1287 of file spline2mesh.C.

References trim_a_triangle().

Referenced by make_trimmed_mesh().

01298   {
01299     vector<int> new_mesh, mesh_to_reiterate, mesh_ok;
01300     const int maxiter=10;
01301     int iter=0;
01302 
01303 #ifdef DBG
01304     system("rm tats*.m");
01305 #endif
01306 
01307     do
01308       {
01309         
01310         for (int ilim=mesh.size()/3, i=0; i<ilim; i++)
01311         //for (int ilim=mesh.size()/3, i=0; i<1; i++)
01312           {
01313             const int c1_indx=mesh[3*i], c2_indx=mesh[3*i+1], c3_indx=mesh[3*i+2];
01314             bool redo=trim_a_triangle(srf, vert, vert_p, bd, norm, trim_curve_p, contour,
01315                                       c1_indx, c2_indx, c3_indx, new_mesh, inner_trimming_curve
01316 #ifdef DBG
01317                                       // 100223: Remember that when having more trimming curves, this may be
01318                                       //         triggered once for each of them...
01319                                       ,false // , i==423 // , false // , i==1069 // , false // , i==94
01320 #endif
01321               );
01322             if (redo)
01323               mesh_to_reiterate.insert(mesh_to_reiterate.end(), new_mesh.begin(), new_mesh.end());
01324             else
01325               mesh_ok.insert(mesh_ok.end(), new_mesh.begin(), new_mesh.end());
01326 #ifdef DBG
01327             // 100210: Showing both the triangle being processed (magenta) and the ones being produced (red.)
01328             if ( (iter==0) || (iter==1) )
01329 #if 0
01330               if ( 
01331                 
01332                 ( ((fabs(vert_p[mesh[3*i  ]][0]-(-22.56))<1e-5) && (fabs(vert_p[mesh[3*i  ]][1]-(30.888))<1e-5)) ||
01333                   ((fabs(vert_p[mesh[3*i+1]][0]-(-22.56))<1e-5) && (fabs(vert_p[mesh[3*i+1]][1]-(30.888))<1e-5)) ||
01334                   ((fabs(vert_p[mesh[3*i+2]][0]-(-22.56))<1e-5) && (fabs(vert_p[mesh[3*i+2]][1]-(30.888))<1e-5))    ) &&
01335                 
01336                 (vert_p[mesh[3*i]][0] > -26) &&
01337                 (vert_p[mesh[3*i]][0] < -17) &&
01338                 (vert_p[mesh[3*i]][1] >  28) &&
01339                 (vert_p[mesh[3*i]][1] <  36)    )
01340 #endif
01341               {
01342                 char fname[1000];
01343                 if (iter==0)
01344                   sprintf(fname, "tats%04d.m", i);
01345                 else
01346                   sprintf(fname, "xtats%04d.m", i);
01347                 FILE *f = fopen(fname, "w");
01348                 fprintf(f, "hold on\ngrid on\n");
01349                 const int u=0, v=1;
01350                 const char col1 = iter==0 ? 'm' : 'b';
01351                 const char col2 = iter==0 ? 'r' : 'g';
01352                 fprintf(f, "patch([%f; %f; %f], [%f; %f; %f], '%c');\n",
01353                         vert_p[mesh[3*i]][u], vert_p[mesh[3*i+1]][u], vert_p[mesh[3*i+2]][u], 
01354                         vert_p[mesh[3*i]][v], vert_p[mesh[3*i+1]][v], vert_p[mesh[3*i+2]][v], col1);
01355                 fprintf(f, "line([%f; %f; %f; %f], [%f; %f; %f; %f], 'color', 'k');\n",
01356                         vert_p[mesh[3*i]][u], vert_p[mesh[3*i+1]][u], vert_p[mesh[3*i+2]][u], vert_p[mesh[3*i]][u], 
01357                         vert_p[mesh[3*i]][v], vert_p[mesh[3*i+1]][v], vert_p[mesh[3*i+2]][v], vert_p[mesh[3*i]][v]);
01358                 for (int j=0; j<int(new_mesh.size())/3; j++)
01359                   {
01360                     fprintf(f, "patch([%f; %f; %f], [%f; %f; %f], '%c');\n",
01361                             vert_p[new_mesh[3*j]][u], vert_p[new_mesh[3*j+1]][u], vert_p[new_mesh[3*j+2]][u], 
01362                             vert_p[new_mesh[3*j]][v], vert_p[new_mesh[3*j+1]][v], vert_p[new_mesh[3*j+2]][v], col2);
01363                     fprintf(f, "line([%f; %f; %f; %f], [%f; %f; %f; %f], 'color', 'k');\n",
01364                             vert_p[new_mesh[3*j  ]][u], vert_p[new_mesh[3*j+1]][u],
01365                             vert_p[new_mesh[3*j+2]][u], vert_p[new_mesh[3*j  ]][u], 
01366                             vert_p[new_mesh[3*j  ]][v], vert_p[new_mesh[3*j+1]][v], 
01367                             vert_p[new_mesh[3*j+2]][v], vert_p[new_mesh[3*j  ]][v]);
01368                   }
01369                 fprintf(f, "xlabel('magenta/blue=old triangle, red/green=new ones');\n");
01370                 fprintf(f, "hold off\n");
01371                 fclose(f);
01372               }
01373 #endif
01374           }
01375         
01376 #ifdef DBG
01377         if (iter==0)
01378           if (inner_trimming_curve)
01379             col=vector<char>(mesh_ok.size()/3, 'm');
01380           else
01381             col=vector<char>(mesh_ok.size()/3, 'c');
01382 #endif
01383       
01384         mesh=mesh_to_reiterate;
01385         iter++;
01386 
01387       }
01388     while ( (mesh.size()>0) && (iter<maxiter) );
01389 
01390     mesh=mesh_ok;
01391 #ifdef DBG
01392     while (col.size()<mesh.size()/3)
01393       if (inner_trimming_curve)
01394         col.push_back('y');
01395       else
01396         col.push_back('b');
01397 #endif
01398   }

double Go::trinomial ( int  n,
int  i,
int  j 
) [inline]

computes the trinomial coefficient: n! / (i! j! (n-i-j)!)

Definition at line 67 of file binom.h.

References binom().

00068 {
00069     if (i < 0 || i > n || j < 0 || j > n)
00070         return 0;
00071 
00072     return binom(n, i) * binom(n-i, j);
00073 }

void Go::uniformNoise ( double *  res,
double  lval,
double  uval,
int  num_samples 
)

Gives a certain number of random samples drawn from the uniform distribution.

Parameters:
res a pointer to the array where the resulting samples should be written.
lval lower bound of the range from which the samples can take their values.
uval upper bound of the range from which the samples can take their values.
num_samples the desired number of samples (should also be the size of the array pointed to by res.

Definition at line 47 of file randomnoise.C.

00049 {
00050     if (uval <= lval) {
00051         throw runtime_error("uniformNoise(...) : erroneous range.");
00052     }
00053     double range = uval - lval;
00054     double scale_factor = range / double(RAND_MAX);
00055     for (int i = 0; i < num_samples; ++i) {
00056         res[i] = double(rand()) * scale_factor + lval;
00057     }
00058 }

void Go::unifyCurveSplineSpace ( vector< shared_ptr< SplineCurve > > &  curves,
double  tol 
)

Definition at line 20 of file unifyCurveSplineSpace.C.

References makeUnionKnots(), and THROW.

00026 {
00027   int ki;
00028   int num_curves = curves.size();
00029   // Do not allow input curves to have inner knots with pos difference less than tol.
00030   for (ki = 0; ki < num_curves; ++ki)
00031     if (curves[ki].get() != 0) {
00032       vector<double>::iterator iter = curves[ki]->basis().begin();
00033       vector<double>::iterator next_iter = iter + 1;
00034       while (next_iter != curves[ki]->basis().end()) {
00035         if ((*iter != *next_iter) && (*next_iter - *iter < tol))
00036           THROW("Inner knot difference too small!");
00037         iter = next_iter;
00038         next_iter = iter + 1;
00039       }
00040     }
00041 
00042   // We allow members of curves to be NULL pointers.
00043   vector<shared_ptr<SplineCurve> > copy_curves;
00044   vector<bool> curve_exists(num_curves);
00045   for (ki = 0; ki < num_curves; ++ki)
00046     if (curves[ki].get() != 0) {
00047       copy_curves.push_back(curves[ki]);
00048       curve_exists[ki] = true;
00049     } else
00050       curve_exists[ki] = false;
00051 
00052   if (copy_curves.size() <= 1)
00053     return;  // Nothing to do
00054 
00055   // Raise the order of each curve to the maximum order
00056   int nmb_crv = copy_curves.size();
00057   int order_max = copy_curves[0]->order();
00058   int order;
00059   for (ki=1; ki<nmb_crv; ki++)
00060     {
00061       order = copy_curves[ki]->order();
00062       order_max = std::max(order_max, order);
00063     }
00064 
00065   for (ki=0; ki<nmb_crv; ki++)
00066     {
00067       // Also make sure that the copy_curves have multiple knots in the ends
00068       copy_curves[ki]->makeKnotStartRegular();
00069       copy_curves[ki]->makeKnotEndRegular();
00070       order = copy_curves[ki]->order();
00071       if (order < order_max)
00072         copy_curves[ki]->raiseOrder(order_max - order);
00073     }
00074 
00075   // Unify knot vectors
00076   // First find the union of all knot vector
00077   vector<double> union_knots;
00078   vector<BsplineBasis> bbasis(nmb_crv);
00079   for (ki=0; ki<nmb_crv; ++ki)
00080     bbasis[ki] = copy_curves[ki]->basis();
00081 
00082   makeUnionKnots(bbasis, tol, union_knots);
00083 
00084   // Insert missing knots into the copy_curves
00085   int num_union = union_knots.size() - order_max;
00086   for (ki=0; ki<nmb_crv; ki++)
00087     {
00088       vector<double> new_knots;
00089       double knot;
00090       int kj, kh;
00091       for (kj=order_max, kh=order_max; 
00092            kj<copy_curves[ki]->numCoefs() || kh<num_union;)
00093         {
00094           knot = copy_curves[ki]->basis().begin()[kj];
00095           if (fabs(knot - union_knots[kh]) < tol)
00096             {
00097               kj++;
00098               kh++;
00099             }
00100           else if (union_knots[kh] < knot)
00101             {
00102               new_knots.push_back(union_knots[kh]);
00103               kh++;
00104             }
00105           else
00106             kj++;
00107         }
00108 
00109       // Insert new knots
00110       copy_curves[ki]->insertKnot(new_knots);
00111       // We test whether we must make a new spline curve in order to
00112       // alter tol-equal knots.
00113       vector<double> difference;
00114       std::set_difference(union_knots.begin(), union_knots.end(),
00115                           copy_curves[ki]->basis().begin(),
00116                           copy_curves[ki]->basis().end(),
00117                           std::back_inserter(difference));
00118       if (difference.size() != 0)
00119         {
00120           SplineCurve tmp(copy_curves[ki]->numCoefs(),
00121                           copy_curves[ki]->order(),
00122                           union_knots.begin(),
00123                           copy_curves[ki]->coefs_begin(),
00124                           copy_curves[ki]->dimension());
00125           copy_curves[ki]->swap(tmp);
00126         }
00127     }
00128 
00129   // We make sure the original curve is altered.
00130   int kj = 0;
00131   for (ki = 0; ki < num_curves; ++ki)
00132     if (curve_exists[ki]) {
00133       curves[ki] = copy_curves[kj];
00134       ++kj;
00135     }
00136 }

void GO_API Go::unifyCurveSplineSpace ( std::vector< boost::shared_ptr< SplineCurve > > &  curves,
double  tol 
)

Make sure that a set of curves live on the same knot vector tol-equal knots are set equal (i.e.

if they differ within tol).

Referenced by curveSum(), Go::CurveCreators::insertParamDomain(), and unifySurfaceSplineSpaceOneDir().

void Go::unifySurfaceSplineSpace ( vector< shared_ptr< SplineSurface > > &  surfaces,
double  tol,
int  dir 
)

Definition at line 30 of file unifySurfaceSplineSpace.C.

References MESSAGE.

00032     {
00033 
00034       if (surfaces.size() <= 1)
00035         return;
00036 
00037       int nmb_srfs = surfaces.size();
00038       double startparam_u = surfaces[0]->startparam_u();
00039       double endparam_u = surfaces[0]->endparam_u();
00040       double startparam_v = surfaces[0]->startparam_v();
00041       double endparam_v = surfaces[0]->endparam_v();
00042       int i, j, h, g;
00043       // We first locate a joint parameter domain.
00044       for (i = 1; i < nmb_srfs; ++i) {
00045         startparam_u = std::max(startparam_u, surfaces[i]->startparam_u());
00046         endparam_u = std::min(endparam_u, surfaces[i]->endparam_u());
00047         startparam_v = std::max(startparam_v, surfaces[i]->startparam_v());
00048         endparam_v = std::min(endparam_v, surfaces[i]->endparam_v());
00049       }
00050       // We make sure the surfaces are k-regular, over tol-equal param domain.
00051       for (i = 0; i < nmb_srfs; ++i) {
00052         if (((dir != 2) &&
00053            ((fabs(startparam_u - surfaces[i]->startparam_u()) > tol) ||
00054              (fabs(endparam_u - surfaces[i]->endparam_u()) > tol))) ||
00055             ((dir != 1) &&
00056              ((fabs(startparam_v - surfaces[i]->startparam_v()) > tol) ||
00057               (fabs(endparam_v - surfaces[i]->endparam_v()) > tol)))) {
00058             MESSAGE("Surfaces defined over different parameter domains, reparametrizing!");
00059             double umin = (dir != 2) ? startparam_u : surfaces[i]->startparam_u();
00060             double umax = (dir != 2) ? endparam_u : surfaces[i]->endparam_u();
00061             double vmin = (dir != 1) ? startparam_v : surfaces[i]->startparam_v();
00062             double vmax = (dir != 1) ? endparam_v : surfaces[i]->endparam_v();
00063             surfaces[i]->setParameterDomain(umin, umax, vmin, vmax);
00064         }
00065 
00066 // #ifdef _MSC_VER
00067 //      surfaces[i] = shared_ptr<SplineSurface>
00068 //          (dynamic_cast<SplineSurface*>(surfaces[i]->subSurface(surfaces[i]->startparam_u(),
00069 //                                                                  surfaces[i]->startparam_v(),
00070 //                                                                  surfaces[i]->endparam_u(),
00071 //                                                                  surfaces[i]->endparam_v())));
00072 // #else
00073         surfaces[i]->makeSurfaceKRegular();
00074 // #endif
00075       }
00076 
00077       int order_u_max = surfaces[0]->order_u();
00078       int order_v_max = surfaces[0]->order_v();
00079       // Raise the order of each surface to the maximum order
00080       for (i = 1; i < nmb_srfs; ++i) {
00081           order_u_max = std::max(order_u_max, surfaces[i]->order_u());
00082           order_v_max = std::max(order_v_max, surfaces[i]->order_v());
00083       }
00084       for (i = 0; i < nmb_srfs; ++i)
00085         if ((order_u_max > surfaces[i]->order_u()) ||
00086             (order_v_max > surfaces[i]->order_v()))
00087           surfaces[i]->raiseOrder(order_u_max - surfaces[i]->order_u(),
00088                                   order_v_max - surfaces[i]->order_v());
00089 
00090       // This last section is cut and paste from unifyCurveSplineSpace.C...
00091       // Unify knot vectors
00092       // First find the union of all knot vectors
00093       vector<double> union_knots_u, union_knots_v;
00094       for (g = 0; g < 2; ++g) {
00095           if (((g == 0) && (dir == 2)) || ((g == 1) && (dir == 1)))
00096           continue; // We will not unify in that direction.
00097 
00098         vector< std::vector<double>::const_iterator > c_ptr;
00099         vector< std::vector<double>::const_iterator > c_end;
00100         c_ptr.resize(nmb_srfs);
00101         c_end.resize(nmb_srfs);
00102         for (i = 0; i < nmb_srfs; ++i)
00103           {
00104             c_ptr[i] = (g == 0) ? surfaces[i]->basis_u().begin() :
00105               surfaces[i]->basis_v().begin();
00106             c_end[i] = (g == 0) ? surfaces[i]->basis_u().end() :
00107               surfaces[i]->basis_v().end();
00108           }
00109 
00110         vector<double> union_knots;
00111         double min_knot, knot;
00112         int max_mult, mult;
00113         while (true)
00114           {
00115             // More knots?
00116             for (i = 0; i < nmb_srfs; ++i)
00117               if (c_ptr[i] < c_end[i])
00118                 break;
00119 
00120             if (i == nmb_srfs)
00121               break;  // All knots collected
00122 
00123             min_knot = c_ptr[0][0];
00124             for (i = 1; i < nmb_srfs; ++i)
00125               {
00126                 knot = c_ptr[i][0];
00127                 min_knot = std::min(min_knot, knot);
00128               }
00129        
00130             mult = 1;
00131             max_mult = 1;
00132             for (i = 0; i < nmb_srfs; ++i)
00133               {
00134                 knot = c_ptr[i][0];
00135                 if (knot < min_knot + tol)
00136                   for (mult=0; c_ptr[i]<c_end[i] && c_ptr[i][0]==knot; 
00137                        mult++, c_ptr[i]++);
00138                 max_mult = std::max(max_mult, mult);
00139               }
00140 
00141             for (i = 0; i < max_mult; ++i)
00142               union_knots.push_back(min_knot);
00143           }
00144 
00145         // Extract the new knot vectors.
00146         if (g == 0)
00147           union_knots_u = union_knots;
00148         else union_knots_v = union_knots;
00149       }
00150 
00151       // Insert missing knots into the surfaces
00152       for (i = 0; i < nmb_srfs; ++i) {
00153           for (g = 0; g < 2; ++g) {
00154               if (((g == 0) && (dir == 2)) || ((g == 1) && (dir == 1)))
00155                   continue; // We will not unify in that direction.
00156 
00157               vector<double> union_knots = (g == 0) ? union_knots_u : union_knots_v;
00158               double knot;
00159               int order_max = (g == 0) ? order_u_max : order_v_max;
00160               int num_union = union_knots.size() - order_max;
00161               int num_coefs = (g == 0) ? surfaces[i]->numCoefs_u() :
00162                   surfaces[i]->numCoefs_v();
00163               vector<double> new_knots;
00164               for (j = order_max, h = order_max; 
00165                    j < num_coefs || h < num_union;)
00166                   {
00167                       knot = (g == 0) ? surfaces[i]->basis_u().begin()[j] :
00168                           surfaces[i]->basis_v().begin()[j];
00169                       if (fabs(knot - union_knots[h]) < tol)
00170                           {
00171                               ++j;
00172                               ++h;
00173                           }
00174                       else if (union_knots[h] < knot)
00175                           {
00176                               new_knots.push_back(union_knots[h]);
00177                               ++h;
00178                           }
00179                       else
00180                           ++j;
00181                   }
00182 
00183               if (g == 0)
00184                   surfaces[i]->insertKnot_u(new_knots);
00185               else surfaces[i]->insertKnot_v(new_knots);
00186           }
00187 
00188           // We test whether we must make a new spline surface in order to
00189           // alter tol-equal knots.
00190           vector<double> difference_u, difference_v;
00191           if (dir == 1)
00192               union_knots_v.assign(surfaces[i]->basis_v().begin(), surfaces[i]->basis_v().end());
00193           else if (dir == 2)
00194               union_knots_u.assign(surfaces[i]->basis_u().begin(), surfaces[i]->basis_u().end());
00195           std::set_difference(union_knots_u.begin(), union_knots_u.end(),
00196                               surfaces[i]->basis_u().begin(),
00197                               surfaces[i]->basis_u().end(),
00198                               std::back_inserter(difference_u));
00199           std::set_difference(union_knots_v.begin(), union_knots_v.end(),
00200                               surfaces[i]->basis_v().begin(),
00201                               surfaces[i]->basis_v().end(),
00202                               std::back_inserter(difference_v));
00203           if ((difference_u.size() != 0) || (difference_v.size() != 0))
00204             {
00205               SplineSurface tmp(surfaces[i]->numCoefs_u(),
00206                                 surfaces[i]->numCoefs_v(),
00207                                 surfaces[i]->order_u(),
00208                                 surfaces[i]->order_v(),
00209                                 union_knots_u.begin(),
00210                                 union_knots_v.begin(),
00211                                 surfaces[i]->coefs_begin(),
00212                                 surfaces[i]->dimension());
00213               surfaces[i]->swap(tmp);
00214             }
00215       }
00216     }

void GO_API Go::unifySurfaceSplineSpace ( std::vector< boost::shared_ptr< SplineSurface > > &  surfaces,
double  tol,
int  dir = 0 
)

Make sure that a set of surfaces live on the same knot vectors tol-equal knots are set equal (i.e.

if they differ within tol). dir 0 means both, 1 is u, 2 is v

Referenced by averageBoundaryCoefs(), Go::SurfaceCreators::mergeRationalParts(), and surfaceSum().

void Go::unifySurfaceSplineSpaceOneDir ( vector< shared_ptr< SplineSurface > > &  surfaces,
double  tol,
bool  unify_u_dir 
)

Definition at line 219 of file unifySurfaceSplineSpace.C.

References representCurveAsSurface(), representSurfaceAsCurve(), and unifyCurveSplineSpace().

00221   {
00222     int cv_dir = unify_u_dir ? 1 : 2;
00223     int nmb_sfs = surfaces.size();
00224 
00225     vector<shared_ptr<SplineCurve> > curves;
00226     for (int i = 0; i < nmb_sfs; ++i)
00227       {
00228         SplineSurface* sf = surfaces[i].get();
00229         curves.push_back(representSurfaceAsCurve(*sf, cv_dir));
00230       }
00231     unifyCurveSplineSpace(curves, tol);
00232 
00233     if (unify_u_dir)
00234       for (int i = 0; i < nmb_sfs; ++i)
00235         {
00236           SplineCurve* cv = curves[i].get();
00237           surfaces[i] = representCurveAsSurface(*cv, cv_dir, surfaces[i]->basis_v(), surfaces[i]->rational());
00238         }
00239     else
00240       for (int i = 0; i < nmb_sfs; ++i)
00241         {
00242           SplineCurve* cv = curves[i].get();
00243           surfaces[i] = representCurveAsSurface(*cv, cv_dir, surfaces[i]->basis_u(), surfaces[i]->rational());
00244         }
00245   }

void GO_API Go::unifySurfaceSplineSpaceOneDir ( std::vector< boost::shared_ptr< SplineSurface > > &  surfaces,
double  tol,
bool  unify_u_dir 
)

Make sure that a set of surfaces live on the same knot vectors in one parameter direction.

tol-equal knots are set equal (i.e. if they differ within tol). Nothing is changed in the other parameter direction (as opposed to unifySurfaceSplineSpace() where orders are raised to same value for all surfaces in both directions) Warning! Objects being pointed to may be recreated inside function. Remember to update other shared pointers if needed.

Parameters:
surfaces Surfaces to end up with common knot vectors
tol tolerance for identifying equal knot values
unify_u_dir if 'true', unify bases in first parameter direction if 'false', unify bases in second parameter direction
template<typename T >
T Go::volume ( const Array< T, 3 > *  c  )  [inline]

Computes the volume of a 3D simplex (embedded i 3D space).

Definition at line 85 of file Volumes.h.

References simplex_volume().

00086 { return simplex_volume(c); }

void Go::writeSISLFormat ( const SplineCurve &  spline_cv,
std::ostream &  os 
)

Write a SplineCurve to a stream using the SISL file format (not the Go format).

Parameters:
spline_cv the curve to write to a stream
os the stream to which the curve will be written (in SISL format)x

Definition at line 116 of file SplineDebugUtils.C.

References Go::SplineCurve::basis(), Go::BsplineBasis::begin(), Go::SplineCurve::coefs_begin(), Go::SplineCurve::dimension(), Go::SplineCurve::numCoefs(), Go::SplineCurve::order(), Go::SplineCurve::rational(), and Go::SplineCurve::rcoefs_begin().

00118 {
00119   int i,j;
00120   int linenum;
00121 
00122   int dim = spline_cv.dimension();
00123   int num_coefs = spline_cv.numCoefs();
00124   int order = spline_cv.order();
00125 
00126   os << setprecision(15);
00127 
00128   os << "$ This is a B-Spline curve" << std::endl;
00129   os << "$ type: 0 is usual, 5 point, 6 analytic\n" << std::endl;
00130   os << "0" << std::endl;
00131   /* order */
00132   os << "$ order ik" << std::endl;
00133   os << order << std::endl;
00134 
00135   /* number of control vertices */
00136   os << "$ number of control vertices in" << std::endl;
00137   os << num_coefs << std::endl;
00138 
00139   /* dimension of geometry space  */
00140   os << "$ dimension" << std::endl;
00141   os << dim << std::endl;
00142 
00143   /* curve open/closed */
00144   os << "$ curve open/closed" << std::endl;
00145   os << 1 << std::endl;
00146 
00147   /* nonrational, i.e. polynomial */
00148   os << "$ rational or not" << std::endl;
00149   os << spline_cv.rational() << std::endl;
00150 
00151   /* knot vector */
00152   linenum = (num_coefs + order)/4;
00153   os << "$ knot vector" << std::endl;
00154   for (j=0; j < linenum; j++){
00155       for (i=0; i < 4; i++)
00156           os << spline_cv.basis().begin()[j * 4 + i] << " ";
00157       os << "";
00158   }
00159   for (i = linenum * 4; i < (num_coefs + order); i++)
00160       os << spline_cv.basis().begin()[i] << " ";
00161   os << std::endl;
00162 
00163   /* control vertices */
00164   os << "$ control vertices" << std::endl;
00165 
00166   if (!spline_cv.rational())
00167   {
00168      for ( i = 0; i < num_coefs; i++ )
00169      {
00170          for ( j = 0; j < dim; j++ )
00171              os << spline_cv.coefs_begin()[i*dim+j] << " ";
00172          os << 1.0 << std::endl;
00173      }
00174   }
00175   else
00176   {
00177      for ( i = 0; i < num_coefs; i++ )
00178      {
00179         for ( j = 0; j < dim+1; j++ )
00180             os << spline_cv.rcoefs_begin()[i*(dim+1)+j] << " ";
00181         os << "" << std::endl;
00182      }
00183   }
00184 
00185   /* instance matrix */
00186   os << "$ instance matrix" << std::endl;
00187   if (dim == 3)
00188   {
00189      os << 1.0 << " " << 0.0 << " " << 0.0 << " " << 0.0 << std::endl;
00190      os << 0.0 << " " << 1.0 << " " << 0.0 << " " << 0.0 << std::endl;
00191      os << 0.0 << " " << 0.0 << " " << 1.0 << " " << 0.0 << std::endl;
00192      os << 0.0 << " " << 0.0 << " " << 0.0 << " " << 1.0 << std::endl;
00193   }
00194   else if (dim == 2)
00195   {
00196      os << 1.0 << " " << 0.0 << " " << 0.0 << " " << std::endl;
00197      os << 0.0 << " " << 1.0 << " " << 0.0 << " " << std::endl;
00198      os << 0.0 << " " << 0.0 << " " << 1.0 << " " << std::endl;
00199   }
00200   else
00201   {
00202       os << 1.0 << " " << 0.0 << std::endl;
00203       os << 0.0 << " " << 1.0 << std::endl;
00204   }
00205 
00206   os << "$ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" << std::endl;
00207 
00208   return;
00209 }

void Go::writeSpaceParamCurve ( const SplineCurve &  pcurve,
std::ostream &  os,
double  z = 0.0 
)

For debugging.

Writes a parameter curve in the xy-plane. Remove when GoViewer handles 2D curves. For debugging. Writes a parameter curve (2D) in the xy-plane, for a given z-value. It will be written (with header) to the specified stream as a 3D curve.

Parameters:
pcurve the parameter curve we want to write as a 3D curve
os the stream to which we want to write the 3D curve
z the constant z-value for the generated curve

Definition at line 31 of file SplineDebugUtils.C.

References ALWAYS_ERROR_IF, Go::SplineCurve::basis(), Go::BsplineBasis::begin(), Go::SplineCurve::coefs_begin(), Go::SplineCurve::dimension(), Go::SplineCurve::numCoefs(), Go::SplineCurve::order(), Go::SplineCurve::write(), and Go::GeomObject::writeStandardHeader().

Referenced by Go::BoundedSurface::orderBoundaryLoops(), and writeTrimmedInfo().

00033 {
00034     ALWAYS_ERROR_IF(pcurve.dimension() != 2,
00035                 "Expecting input of 2D-curve.");
00036 
00037     std::vector<double> space_coefs;
00038     for (int i = 0; i < pcurve.numCoefs(); ++i) {
00039         space_coefs.insert(space_coefs.end(),
00040                            pcurve.coefs_begin() + i*2,
00041                            pcurve.coefs_begin() + (i + 1)*2);
00042         space_coefs.push_back(z); // Make param_curve live in plane parallell to the xy-plane.
00043     }
00044 
00045     SplineCurve space_pcurve =
00046         SplineCurve(pcurve.numCoefs(), pcurve.order(),
00047                       pcurve.basis().begin(), space_coefs.begin(), 3);
00048     space_pcurve.writeStandardHeader(os);
00049     space_pcurve.write(os);
00050 }

void Go::writeTrimmedInfo ( BoundedSurface &  bd_sf,
std::ostream &  os,
double  z = 0.0 
)

Definition at line 54 of file SplineDebugUtils.C.

References Class_SplineCurve, Go::BoundedSurface::loop(), Go::BoundedSurface::numberOfLoops(), Go::BoundedSurface::underlyingSurface(), and writeSpaceParamCurve().

Referenced by Go::CreatorsUtils::fixTrimCurves().

00057 {
00058     shared_ptr<ParamSurface> under_sf = bd_sf.underlyingSurface();
00059     under_sf->writeStandardHeader(os);
00060     under_sf->write(os);
00061     int nmb_loops = bd_sf.numberOfLoops();
00062     for (int kj = 0; kj < nmb_loops; ++kj) {
00063         shared_ptr<CurveLoop> loop = bd_sf.loop(kj);
00064         for (int kk = 0; kk < loop->size(); ++kk) {
00065             shared_ptr<CurveOnSurface> cv_on_sf =
00066                 shared_dynamic_cast<CurveOnSurface, ParamCurve>
00067                 ((*loop)[kk]);
00068             shared_ptr<ParamCurve> par_cv =
00069                 cv_on_sf->parameterCurve();
00070             if (par_cv.get() != NULL) {
00071                 if (par_cv->instanceType() == Class_SplineCurve) {
00072                     shared_ptr<SplineCurve> spline_cv =
00073                         shared_dynamic_cast<SplineCurve, ParamCurve>
00074                         (par_cv);
00075                     writeSpaceParamCurve(*spline_cv,
00076                                          os);
00077                 }
00078             }
00079             shared_ptr<ParamCurve> space_cv =
00080                 cv_on_sf->spaceCurve();
00081             if (space_cv.get() != NULL) {
00082                 space_cv->writeStandardHeader(os);
00083                 space_cv->write(os);
00084             }
00085         }
00086     }
00087 }


Variable Documentation

double Go::ltol = 1.0e-11

Definition at line 25 of file CurvatureUtils.C.

Referenced by curvatureRadius(), getHermiteData(), and stepLenFromRadius().

const int Go::MAJOR_VERSION = 1

Definition at line 26 of file GeomObject.h.

Referenced by Go::GeomObject::writeStandardHeader().

const int Go::MINOR_VERSION = 0

Definition at line 27 of file GeomObject.h.

Referenced by Go::GeomObject::writeStandardHeader().

vector<vector<shared_ptr<CurveOnSurface> > > Go::new_loops

Definition at line 937 of file BoundedUtils.C.

const bool Go::s2m_with_boundary = false

Definition at line 77 of file spline2mesh.C.

Referenced by make_trimmed_mesh().

Generated on Tue Sep 21 15:44:25 2010 for GoTools Core by  doxygen 1.6.3