1 // libSNL - Simple Nurbs Library
2 // Copyright 2006 Scott A.E. Lanham, Australia.
3 // --------------------------------------------
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 
14 // snlSurface projection related functions.
15 
16 #include "snlSurface_projection.h"
17 
project_depr(snlPoint * toProject,int numPoints,double convergTol,double normTol,int maxPass)18 snlVertex* snlSurface::project_depr ( snlPoint* toProject, int numPoints, double convergTol,
19                                       double normTol, int maxPass )
20 {
21     //! Project an array of points to surface.
22     //  --------------------------------------
23     //! @param toProject Array of snlPoints to project to surface.
24     //! @param numPoints Number of points being projected. ie size of points array.
25     //! @param convergTol If the difference between successive newton iterations converges and is
26     //!                   below this value then the point is taken to be projected.
27     //! @param normTol If the cosine of the angle between the projection vector and the
28     //!                projected points normal is under this value then the projection is used.
29     //! @param maxPass Maximum number of mesh refinement passes allowed. Stops infinite loops
30     //!                if projections don't converge.
31     //!
32     //! Notes: This function is now deprecated but stays around as a cross reference for
33     //!        new projection work.
34 
35     sLocn* projections = new sLocn [ numPoints ];
36 
37     ptrList < sLocn >* ambig = projPtSurf ( *this, toProject, numPoints, projections,
38                                             convergTol, normTol, maxPass );
39 
40     // Create vertexes to return and populate with converted sLocn's.
41     // -------------------------------------------------------------
42 
43     snlVertex* retVertexes = new snlVertex [ numPoints ];
44 
45     for ( int index = 0; index < numPoints; index ++ )
46     {
47         retVertexes [ index ] = projections [ index ].pt;
48 
49         retVertexes [ index ].evalParamU ( projections [ index ].paramT );
50         retVertexes [ index ].evalParamV ( projections [ index ].paramU );
51 
52         retVertexes [ index ].flag = projections [ index ].flag;
53     }
54 
55     delete ambig;
56     delete[] projections;
57 
58     return retVertexes;
59 }
60 
invert(snlPoint * toInvert,int numPoints,int * retArraySize,double convergTol,double normTol,int maxPass)61 snlSurfLocn* snlSurface::invert ( snlPoint* toInvert, int numPoints, int* retArraySize,
62                                   double convergTol, double normTol, int maxPass )
63 {
64     //! Find parametric location of given points
65     //  ----------------------------------------
66     //! @param toInvert Array of snlPoints to find on surface.
67     //! @param numPoints Number of points being inverted. ie size of points array.
68     //! @param retArraySize Size of array of surface locations that is returned.
69     //! @param convergTol If the difference between successive newton iterations converges and is
70     //!                   below this value then the point is taken to be inverted.
71     //! @param normTol How close to perpendicular the projection of the given point to the point
72     //!                found gets to the surface tangents at the found point for convergence to be
73     //!                successful.
74     //! @param maxPass Maximum number of refinement passes allowed. Stops infinite loops if
75     //!                projections don't converge.
76 
77     // Generate point mask. If false, entry is not processed during pass.
78 
79     bool* pointMask = new bool [ numPoints ];
80 
81     for ( int index = 0; index < numPoints; index ++ )
82         pointMask [ index ] = true;
83 
84     // Calculate best guess for each point to be inverted.
85 
86     ptrList <snlSurfLocnGuess>* guesses = guessInvLocation ( toInvert, numPoints, pointMask,
87                                                              degU, degV );
88 
89     delete[] pointMask;
90 
91     return processGuesses ( toInvert, numPoints, retArraySize, guesses, convergTol,
92                             normTol, maxPass );
93 }
94 
project(snlPoint * toProject,int numPoints,int * retArraySize,double convergTol,double normTol,int maxPass)95 snlSurfLocn* snlSurface::project ( snlPoint* toProject, int numPoints, int* retArraySize,
96                                    double convergTol, double normTol, int maxPass )
97 {
98     //! Find parametric location of given points
99     //  ----------------------------------------
100     //! @param toProject Array of snlPoints to find projections of on surface.
101     //! @param numPoints Number of points being inverted. ie size of points array.
102     //! @param retArraySize Size of array of surface locations that is returned.
103     //! @param convergTol If the difference between successive newton iterations converges and is
104     //!                   below this value then the point is taken to be inverted.
105     //! @param normTol How close to perpendicular the projection of the given point to the point
106     //!                found gets to the surface tangents at the found point for convergence to be
107     //!                successful.
108     //! @param maxPass Maximum number of refinement passes allowed. Stops infinite loops if
109     //!                projections don't converge.
110 
111     // Generate point mask. If false, entry is not processed during pass.
112 
113     bool* pointMask = new bool [ numPoints ];
114 
115     for ( int index = 0; index < numPoints; index ++ )
116         pointMask [ index ] = true;
117 
118     // Only work on copy of surface.
119 
120     snlSurface* tmpSurf = new snlSurface ( *this );
121 
122     tmpSurf -> createConvexBezierSegments( 0, 0, 0.00009 );  // Sensitivity of 0.05 degrees.
123 
124     // Calculate best guess for each point to be inverted.
125 
126     ptrList <snlSurfLocnGuess>* guesses = tmpSurf -> guessProjLocation ( toProject, numPoints,
127                                                                          pointMask );
128 
129     snlSurfLocn* retArray = processGuesses ( toProject, numPoints, retArraySize, guesses,
130                                              convergTol, normTol, maxPass, true );
131 
132     // Clean up and return.
133 
134     delete[] pointMask;
135 
136     delete tmpSurf;
137 
138     return retArray;
139 }
140 
fastProject(snlPoint * toProject,int numPoints,int * retArraySize,double convergTol,double normTol,int maxPass,int sensitivity,int maxLocns)141 snlSurfLocn* snlSurface::fastProject ( snlPoint* toProject, int numPoints, int* retArraySize,
142                                        double convergTol, double normTol, int maxPass,
143                                        int sensitivity, int maxLocns )
144 {
145     //! Find parametric location of given points
146     //  ----------------------------------------
147     //! @param toProject Array of snlPoints to find projections of on surface.
148     //! @param numPoints Number of points being inverted. ie size of points array.
149     //! @param retArraySize Size of array of surface locations that is returned.
150     //! @param convergTol If the difference between successive newton iterations converges and is
151     //!                   below this value then the point is taken to be inverted.
152     //! @param normTol How close to perpendicular the projection of the given point to the point
153     //!                found gets to the surface tangents at the found point for convergence to be
154     //!                successful.
155     //! @param maxPass Maximum number of refinement passes allowed. Stops infinite loops if
156     //!                projections don't converge.
157     //! @param sensitivity The higher this number the more accurate the initial guess phase is but
158     //!                    the function becomes slower. Increases the number of subdivisions per
159     //!                    knot span by this amount. Must be a positive integer
160     //! @param maxLocns Maximum number of surface locations to return. If a surface is known to
161     //!                 have ambiguous areas then this number should be greater than one. Value is
162     //!                 clamped to be greater than zero.
163     //!
164     //! Notes: Fast project is not nearly as accurate as other project or invert functions.
165 
166     ptrList <snlSurfLocnGuess>* guesses = guessFastProjLocation ( toProject, numPoints, maxLocns,
167                                                                   degU + sensitivity,
168                                                                   degV + sensitivity );
169 
170     snlSurfLocn* retArray = processGuesses ( toProject, numPoints, retArraySize, guesses,
171                                              convergTol, normTol, maxPass, true, true );
172 
173     return retArray;
174 }
175 
processGuesses(snlPoint * points,int numPoints,int * retArraySize,ptrList<snlSurfLocnGuess> * guesses,double convergTol,double normTol,int maxPass,bool retNonConverged,bool noCull,int numVelocity,int numNewton)176 snlSurfLocn* snlSurface::processGuesses ( snlPoint* points, int numPoints, int* retArraySize,
177                                           ptrList <snlSurfLocnGuess>* guesses, double convergTol,
178                                           double normTol, int maxPass, bool retNonConverged,
179                                           bool noCull, int numVelocity, int numNewton )
180 {
181     //! Refine parametric location of given points
182     //  ------------------------------------------
183     //! @param points Array of snlPoints to find on surface.
184     //! @param numPoints Number of points being inverted. ie size of points array.
185     //! @param retArraySize Size of array of surface locations that is returned.
186     //! @param guesses Parametric location guesses for given points.
187     //! @param convergTol If the difference between successive newton iterations converges and is
188     //!                   below this value then the point is taken to be inverted.
189     //! @param normTol How close to perpendicular the projection of the given point to the point
190     //!                found gets to the surface tangents at the found point for convergence to be
191     //!                successful.
192     //! @param maxPass Maximum number of refinement passes allowed. Stops infinite loops if
193     //!                projections don't converge.
194     //! @param retNonConverged Return non converged points. Used for projection.
195     //! @param noCull Do not cull guesses that converge to the same point.
196     //! @param numVelocity Number of velocity iterations to perform per pass.
197     //! @param numNewton Number of newton iterations to perform per pass.
198 
199     // Converge to points using multiple passes if necessary.
200 
201     for ( int pass = 0; pass < maxPass; pass ++ )
202     {
203         bool converged = convergeVelocity ( points, guesses, numVelocity, convergTol, normTol );
204 
205         if ( ! converged )
206             converged = convergeNewton ( points, guesses, numNewton, convergTol, normTol );
207 
208         // If all guesses have been culled for a given point then reprocess one of them.
209 
210         snlSurfLocnGuess* guess = guesses -> first();
211 
212         for ( int index = 0; index < numPoints; index ++ )
213         {
214             bool allCulled = true;
215 
216             snlSurfLocnGuess* bestGuess = guess;
217 
218             if ( guess )
219             {
220                 while ( guess )
221                 {
222 
223                     if ( guess -> origPtIndex != index ) break;
224 
225                     if ( ! guess -> culled )
226                         allCulled = false;
227                     else if ( guess -> dist < bestGuess -> dist )
228                         bestGuess = guess;
229 
230                     guess = guesses -> next();
231                 }
232 
233                 if ( allCulled )
234                 {
235                     // Force another pass to be performed.
236 
237                     bestGuess -> ignoreParamBounds = true;
238                     bestGuess -> culled = false;
239                     converged = false;
240                 }
241             }
242         }
243     }
244 
245     // Cull duplicate guesses that have converged to the same point. Keep best one.
246 
247     snlSurfLocnGuess* guess = guesses -> first();
248 
249     int pointIndex = -1;
250 
251     ptrList <snlSurfLocnGuess> pointGuesses;
252 
253     while ( guess && ! noCull )
254     {
255         if ( ! guess -> culled && ( guess -> converged || retNonConverged ) )
256         {
257             if ( guess -> origPtIndex != pointIndex )
258             {
259                 // Move onto next point indexes guesses.
260 
261                 pointIndex = guess -> origPtIndex;
262 
263                 pointGuesses.clear();
264 
265                 pointGuesses.append ( guess, false );
266             }
267             else
268             {
269                 // Compare point with others found. Take best one.
270 
271                 snlSurfLocnGuess* ptGuess = pointGuesses.first();
272 
273                 while ( ptGuess )
274                 {
275                     if ( ! ptGuess -> culled )
276                     {
277                         // If other guesses param bounds overlap current guess
278                         // then assume they have converged to the same point.
279 
280                         if ( guess -> paramU >= ptGuess -> minU
281                              && guess -> paramU <= ptGuess -> maxU )
282                         {
283                             if ( guess -> paramV >= ptGuess -> minV
284                                  && guess -> paramV <= ptGuess -> maxV )
285                             {
286                                 // Both guesses are in same param zone. Cull guess with largest
287                                 // distance.
288 
289                                 if ( guess -> dist > ptGuess -> dist )
290                                     guess -> culled = true;
291                                 else
292                                     ptGuess -> culled = true;
293                             }
294                         }
295                     }
296 
297                     ptGuess = pointGuesses.next();
298                 }
299 
300                 pointGuesses.append ( guess, false );
301             }
302         }
303 
304         guess = guesses -> next();
305     }
306 
307     // Assemble best found points.
308 
309     // Get total number of points found.
310 
311     int totalCount = 0;
312 
313     guess = guesses -> first();
314 
315     while ( guess )
316     {
317         if ( ! guess -> culled && ( guess -> converged || retNonConverged ) )
318             totalCount ++;
319 
320         guess = guesses -> next();
321     }
322 
323     snlSurfLocn* retLocns = new snlSurfLocn [ totalCount ];
324 
325     int index = 0;
326 
327     guess = guesses -> first();
328 
329     while ( guess )
330     {
331         if ( ( retNonConverged || guess -> converged ) && ! guess -> culled )
332         {
333             retLocns [ index ].paramU = guess -> paramU;
334             retLocns [ index ].paramV = guess -> paramV;
335             retLocns [ index ].pt = guess -> pt;
336             retLocns [ index ].dist = sqrt ( guess -> dist );
337             retLocns [ index ].origPtIndex = guess -> origPtIndex;
338             retLocns [ index ].cos = guess -> cos;
339 
340             index ++;
341         }
342 
343         guess = guesses -> next();
344     }
345 
346     // Clean up and return.
347 
348     delete guesses;
349 
350     if ( retArraySize )
351         *retArraySize = totalCount;
352 
353     return retLocns;
354 }
355 
convergeVelocity(snlPoint * convergToPts,ptrList<snlSurfLocnGuess> * guesses,int numIterations,double convergTol,double normTol)356 bool snlSurface::convergeVelocity ( snlPoint* convergToPts, ptrList <snlSurfLocnGuess>* guesses,
357                                     int numIterations, double convergTol, double normTol )
358 {
359     //! Converge guesses to given points using velocity technique.
360     //  ----------------------------------------------------------
361     //! @param convergToPts Array of points that are to be converged to. ie Points to be found.
362     //! @param guesses List of current guesses to be converged.
363     //! @param numIterations Maximum number of convergence iterations to perform.
364     //! @param convergTol Maximum distance between point and guess allowed for convergence to be
365     //!                   successful.
366     //! @param normTol How close to perpendicular the projection of the given point to the guessed
367     //!                point gets to the surface tangents at the guessed point for convergence to be
368     //!                successful.
369 
370     cout.precision ( 16 );
371 
372     double convTolSqrd = convergTol * convergTol;
373 
374     knot minU = knotVectU -> min();
375     knot maxU = knotVectU -> max();
376 
377     knot minV = knotVectV -> min();
378     knot maxV = knotVectV -> max();
379 
380     snlSurfLocnGuess* guess = guesses -> first();
381 
382     snlVector velocityU, velocityV;
383     snlPoint evalPoint;
384 
385     bool converged = true;
386 
387     while ( guess )
388     {
389         if ( ! guess -> converged && ! guess -> culled )
390         {
391             if ( guess -> dist >= convTolSqrd )
392             {
393                 // Generate new guess.
394 
395                 snlSurfLocnGuess newGuess = *guess;
396 
397                 for ( int iteration = 0; iteration < numIterations; iteration ++ )
398                 {
399                     // Get Initial velocities at guessed point
400 
401                     if ( ! iteration )
402                         velocities ( newGuess.paramU, newGuess.paramV, evalPoint, velocityU,
403                                      velocityV );
404 
405                     // Calculate new parameters based on velocities.
406 
407                     snlVector guessToPt ( newGuess.pt, convergToPts [ newGuess.origPtIndex ] );
408 
409                     double lengthU = velocityU.length();
410 
411                     if ( lengthU == 0.0 ) break;
412 
413                     double distU = guessToPt.dot ( velocityU ) / lengthU;
414                     knot deltaU = distU / lengthU;
415 
416                     double lengthV = velocityV.length();
417 
418                     if ( lengthV == 0.0 ) break;
419 
420                     double distV = guessToPt.dot ( velocityV ) / lengthV;
421                     knot deltaV =  distV / lengthV;
422 
423                     knot newU = newGuess.paramU + deltaU;
424                     knot newV = newGuess.paramV + deltaV;
425 
426                     if ( newU < minU ) newU = minU;
427                     if ( newU > maxU ) newU = maxU;
428 
429                     if ( newV < minV ) newV = minV;
430                     if ( newV > maxV ) newV = maxV;
431 
432                     // If the distance travelled exceeds the required distance by more than 10% then
433                     // recalculate the param deltas.
434 
435                     evalPoint = eval ( newU, newV );
436 
437                     double newDist = evalPoint.distSqrd ( convergToPts [ newGuess.origPtIndex ] );
438 
439 
440                     int loopCount = -1;
441 
442                     while ( newDist > newGuess.dist * 1.1 )
443                     {
444                         // Calculate new parameters based on actual distance travelled.
445 
446                         loopCount ++;
447 
448                         snlVector newGuessToPt ( newGuess.pt, evalPoint );
449 
450                         double newDistU = newGuessToPt.dot ( velocityU ) / lengthU;
451                         double newDistV = newGuessToPt.dot ( velocityV ) / lengthV;
452 
453                         if ( newDistU == 0.0 && newDistV == 0.0 )
454                             break;
455 
456                         double loopAdj = 1.0 / (double) ( loopCount + 1 );
457 
458                         knot newAdjustU;
459                         knot newAdjustV;
460 
461                         if ( newDistU != 0.0 )
462                             newAdjustU = newGuess.paramU + ( ( distU * loopAdj / newDistU )
463                                          * ( newU - newGuess.paramU ) );
464                         else
465                             newAdjustU = newU;
466 
467                         if ( newDistV != 0.0 )
468                             newAdjustV = newGuess.paramV + ( ( distV * loopAdj / newDistV )
469                                          * ( newV - newGuess.paramV ) );
470                         else
471                             newAdjustV = newV;
472 
473                         // Do out of bounds check.
474 
475                         if ( newAdjustU < minU ) newAdjustU = minU;
476                         if ( newAdjustU > maxU ) newAdjustU = maxU;
477 
478                         if ( newAdjustV < minV ) newAdjustV = minV;
479                         if ( newAdjustV > maxV ) newAdjustV = maxV;
480 
481                         // Test for infinite loop.
482 
483                         if ( newU == newAdjustU && newV == newAdjustV )
484                             break;
485 
486                         newU = newAdjustU;
487                         newV = newAdjustV;
488 
489                         // Re-evaluate parameters.
490 
491                         evalPoint = eval ( newU, newV );
492 
493                         newDist = evalPoint.distSqrd ( convergToPts [ newGuess.origPtIndex ] );
494                     }
495 
496                     // Store point and velocities that match new params.
497 
498                     velocities ( newU, newV, evalPoint, velocityU, velocityV );
499 
500                     newGuess.paramU = newU;
501                     newGuess.paramV = newV;
502 
503                     newGuess.pt = evalPoint;
504 
505                     newGuess.dist = evalPoint.distSqrd ( convergToPts [ newGuess.origPtIndex ] );
506 
507                     // Test for guess going out of parametric bounds.
508 
509                     if ( ! newGuess.ignoreParamBounds )
510                     {
511                         if ( newGuess.paramU < newGuess.minU || newGuess.paramU > newGuess.maxU )
512                         {
513                             guess -> culled = true;
514                             break;
515                         }
516 
517                         if ( newGuess.paramV < newGuess.minV || newGuess.paramV > newGuess.maxV )
518                         {
519                             guess -> culled = true;
520                             break;
521                         }
522                     }
523 
524                     // Test for convergence.
525 
526                     if ( newGuess.dist < convTolSqrd )
527                     {
528                         newGuess.converged = true;
529                         break;
530                     }
531 
532                     snlVector projToSurf ( convergToPts [ newGuess.origPtIndex ], evalPoint );
533 
534                     basis cosU = projToSurf.calcAbsCos ( velocityU );
535 
536                     basis cosV = projToSurf.calcAbsCos ( velocityV );
537 
538                     newGuess.cos = cosU > cosV ? cosU : cosV;
539 
540                     if ( cosU <= normTol && cosV <= normTol )
541                     {
542                         newGuess.converged = true;
543                         break;
544                     }
545                 }
546 
547                 // If new guess is better than old and hasn't been culled then replace old guess.
548 
549                 if ( ! guess -> culled )
550                 {
551                     // If parameters haven't changed over all iterations then set as converged.
552 
553                     if ( guess -> paramU == newGuess.paramU && guess -> paramV == newGuess.paramV )
554                         newGuess.converged = true;
555 
556                     *guess = newGuess;
557                 }
558             }
559             else
560                 guess -> converged = true;
561 
562             // Test for guess going out of parametric bounds.
563             if ( ! guess -> ignoreParamBounds && guess -> culled )
564             {
565                 if ( guess -> paramU < guess -> minU || guess -> paramU > guess -> maxU )
566                     guess -> culled = true;
567 
568                 if ( guess -> paramV < guess -> minV || guess -> paramV > guess -> maxV )
569                     guess -> culled = true;
570             }
571         }
572 
573         if ( ! guess -> converged && ! guess -> culled ) converged = false;
574 
575         guess = guesses -> next();
576     }
577 
578     return converged;
579 }
580 
convergeNewton(snlPoint * convergToPts,ptrList<snlSurfLocnGuess> * guesses,int numIterations,double convergTol,double normTol)581 bool snlSurface::convergeNewton ( snlPoint* convergToPts, ptrList <snlSurfLocnGuess>* guesses,
582                                   int numIterations, double convergTol, double normTol )
583 {
584     //! Converge guesses to given points using Newton iteration
585     //  -------------------------------------------------------
586     //! @param convergToPts Array of points that are to be converged to. ie Points to be found.
587     //! @param guesses List of current guesses to be converged.
588     //! @param numIterations Maximum number of convergence iterations to perform.
589     //! @param convergTol Maximum distance between point and guess allowed for convergence to be
590     //!                   successful.
591     //! @param normTol Cosine of angle between normal to surface at guess and projection from
592     //!                guess to given point. If cosine is below this angle then iterations stop.
593 
594     double convTolSqrd = convergTol * convergTol;
595 
596     knot minU = knotVectU -> min();
597     knot maxU = knotVectU -> max();
598 
599     knot minV = knotVectV -> min();
600     knot maxV = knotVectV -> max();
601 
602     snlSurfLocnGuess* guess = guesses -> first();
603 
604     snlPoint* derivs;
605 
606     bool converged = true;
607 
608     while ( guess )
609     {
610         derivs = 0;
611 
612         if ( ! guess -> converged && ! guess -> culled )
613         {
614             snlSurfLocnGuess newGuess = *guess;
615 
616             if ( guess -> dist >= convTolSqrd )
617             {
618                 for ( int iteration = 0; iteration < numIterations; iteration ++ )
619                 {
620                     // Get 1st and 2nd derivatives.
621 
622                     if ( ! derivs )
623                         derivs = evalDerivs ( newGuess.paramU, newGuess.paramV, 2, 2 );
624 
625                     // Generate next Newton approximation.
626 
627                     knot deltaU, deltaV;
628 
629                     if ( degU > 1 && degV > 1 )
630                     {
631                         if ( ! newtonIterStepSurf ( derivs, convergToPts + newGuess.origPtIndex,
632                                                     &deltaU, &deltaV ) )
633                             break;  // Param deltas would have gone to infinity.
634                     }
635                     else
636                     {
637                         // At least one of the degrees is 1.
638 
639                         snlPoint uDerivs [ 3 ];
640 
641                         uDerivs [ 0 ] = derivs [ 0 ];
642                         uDerivs [ 1 ] = derivs [ 3 ];
643                         uDerivs [ 2 ] = derivs [ 6 ];
644 
645                         if ( degU == 1 )
646                         {
647                             if ( ! lineIterStepCurve ( uDerivs, convergToPts + newGuess.origPtIndex,
648                                                        &deltaU ) )
649                                 break;
650                         }
651                         else
652                         {
653                             if ( ! newtonIterStepCurve ( uDerivs,
654                                                          convergToPts + newGuess.origPtIndex,
655                                                          &deltaU ) )
656                                 break;
657                         }
658 
659                         if ( degV == 1 )
660                         {
661                             if ( ! lineIterStepCurve ( derivs, convergToPts + newGuess.origPtIndex,
662                                                        &deltaV ) )
663                                 break;
664                         }
665                         else
666                         {
667                             if ( ! newtonIterStepCurve ( derivs, convergToPts +
668                                                          newGuess.origPtIndex, &deltaV ) )
669                                 break;
670                         }
671                     }
672 
673                     // Calcualte and clamp new parameters.
674 
675                     knot newU = newGuess.paramU + deltaU;
676                     knot newV = newGuess.paramV + deltaV;
677 
678                     if ( newU < minU ) newU = minU;
679                     if ( newU > maxU ) newU = maxU;
680 
681                     if ( newV < minV ) newV = minV;
682                     if ( newV > maxV ) newV = maxV;
683 
684                     // If parameters haven't changed between iterations then guess has converged.
685 
686                     if ( newU == newGuess.paramU && newV == newGuess.paramV )
687                     {
688                         newGuess.converged = true;
689                         break;
690                     }
691 
692                     newGuess.paramU = newU;
693                     newGuess.paramV = newV;
694 
695                     // Evaluate new parameters.
696 
697                     delete[] derivs;
698                     derivs = evalDerivs ( newGuess.paramU, newGuess.paramV, 2, 2 );
699 
700                     newGuess.pt = derivs [ 0 ];
701 
702                     newGuess.dist = derivs [ 0 ].distSqrd ( convergToPts [ newGuess.origPtIndex ] );
703 
704                     // Check for distance and cosine tolerances.
705 
706                     if ( newGuess.dist < convTolSqrd )
707                     {
708                         newGuess.converged = true;
709                         break;
710                     }
711 
712                     snlVector velocityU ( derivs [ 3 ] );
713                     snlVector velocityV ( derivs [ 1 ] );
714 
715                     snlVector projToSurf ( convergToPts [ newGuess.origPtIndex ], newGuess.pt );
716 
717                     basis cosU = projToSurf.calcAbsCos ( velocityU );
718 
719                     basis cosV = projToSurf.calcAbsCos ( velocityV );
720 
721                     newGuess.cos = cosU > cosV ? cosU : cosV;
722 
723                     if ( cosU <= normTol && cosV <= normTol )
724                     {
725                         newGuess.converged = true;
726                         break;
727                     }
728                 }
729             }
730             else
731                 guess -> converged = true;
732 
733             if ( ! guess -> culled && newGuess.dist < guess -> dist )
734                 *guess = newGuess;
735         }
736 
737         // Test for guess going out of parametric bounds.
738 
739         if ( ! guess -> ignoreParamBounds && ! guess -> culled )
740         {
741             if ( guess -> paramU < guess -> minU || guess -> paramU > guess -> maxU )
742                 guess -> culled = true;
743 
744             if ( guess -> paramV < guess -> minV || guess -> paramV > guess -> maxV )
745                 guess -> culled = true;
746         }
747 
748         if ( ! guess -> converged && ! guess -> culled ) converged = false;
749 
750         guess = guesses -> next();
751 
752         // Clean up.
753 
754         if ( derivs ) delete[] derivs;
755     }
756 
757     return converged;
758 }
759 
guessInvLocation(snlPoint * points,int numPoints,bool * pointMask,int granU,int granV)760 ptrList <snlSurfLocnGuess>* snlSurface::guessInvLocation ( snlPoint* points, int numPoints,
761                                                            bool* pointMask, int granU,
762                                                            int granV )
763 {
764     //! Guess parametric location of given points.
765     //  ------------------------------------------
766     //! @param points Array of points to find matches with.
767     //! @param numPoints Number of points in array.
768     //! @param pointMask Array specifying which points to process. Corresponding index to points
769     //!                  array. Must be true to process.
770     //! @param granU Granularity of each span in U direction.
771     //! @param granV Granularity of each span in V direction.
772     //!
773     //! @return Array of surface location guess structs. Caller owns this array.
774     //!
775     //! Notes:       This function will return one guess per parametric span.
776 
777     int     index;
778 
779     int numSpansU = knotVectU -> getNumSpans();
780     int numSpansV = knotVectV -> getNumSpans();
781 
782     int numEvalU = granU * numSpansU + 1;
783     int numEvalV = granV * numSpansV + 1;
784 
785     // Pre-calculate parametric positions.
786 
787     knot* paramU = new knot [ numEvalU ];
788     int* spanU = new int [ numEvalU ];
789 
790     knot* paramV = new knot [ numEvalV ];
791     int* spanV = new int [ numEvalV ];
792 
793     // U direction.
794 
795     int cSpan = knotVectU -> getFirstSpan();
796 
797     knot paramStart = knotVectU -> val ( cSpan );
798 
799     cSpan = knotVectU -> getNextSpan ( cSpan );
800 
801     knot paramEnd;
802 
803     if ( cSpan )
804         paramEnd = knotVectU -> val ( cSpan );
805     else
806         paramEnd = knotVectU -> max();
807 
808 
809     int numSteps;
810 
811     int paramIndex = 0;
812 
813     basis param;
814 
815     for ( int span = 0; span < numSpansU; span ++ )
816     {
817         basis paramStep = ( paramEnd - paramStart ) / (double) granU;
818 
819         param = paramStart;
820 
821         if ( span )
822         {
823             numSteps = granU;
824             param += paramStep;
825         }
826         else
827         {
828             numSteps = granU + 1;
829         }
830 
831         // Generate params for span.
832 
833         for ( index = 0; index < numSteps; index ++ )
834         {
835             paramU [ paramIndex ] = param;
836 
837             spanU [ paramIndex ++ ] = span;
838 
839             param += paramStep;
840 
841             if ( param > paramEnd ) param = paramEnd;  // Round off error trap.
842         }
843 
844         paramStart = paramEnd;
845 
846         cSpan = knotVectU -> getNextSpan ( cSpan );
847 
848         if ( cSpan )
849             paramEnd = knotVectU -> val ( cSpan );
850         else
851             paramEnd = knotVectU -> max();
852     }
853 
854     // V direction.
855 
856     cSpan = knotVectV -> getFirstSpan();
857 
858     paramStart = knotVectV -> val ( cSpan );
859 
860     cSpan = knotVectV -> getNextSpan ( cSpan );
861 
862     if ( cSpan )
863         paramEnd = knotVectV -> val ( cSpan );
864     else
865         paramEnd = knotVectV -> max();
866 
867     paramIndex = 0;
868 
869     for ( int span = 0; span < numSpansV; span ++ )
870     {
871         basis paramStep = ( paramEnd - paramStart ) / (double) granV;
872 
873         param = paramStart;
874 
875         if ( span )
876         {
877             numSteps = granV;
878             param += paramStep;
879         }
880         else
881         {
882             numSteps = granV + 1;
883         }
884 
885         for ( index = 0; index < numSteps; index ++ )
886         {
887             paramV [ paramIndex ] = param;
888 
889             spanV [ paramIndex ++ ] = span;
890 
891             param += paramStep;
892 
893             if ( param > paramEnd ) param = paramEnd;  // Round off error trap.
894         }
895 
896         paramStart = paramEnd;
897 
898         cSpan = knotVectV -> getNextSpan ( cSpan );
899 
900         if ( cSpan )
901             paramEnd = knotVectV -> val ( cSpan );
902         else
903             paramEnd = knotVectV -> max();
904     }
905 
906     // Pre-evaluate basis functions.
907 
908     basis** basisU = new basis* [ numEvalU ];
909     basis** basisV = new basis* [ numEvalV ];
910 
911     for ( index = 0; index < numEvalU; index ++ )
912         basisU [ index ] = knotVectU -> evalBasis ( paramU [ index ] );
913 
914     for ( index = 0; index < numEvalV; index ++ )
915         basisV [ index ] = knotVectV -> evalBasis ( paramV [ index ] );
916 
917     // Evaluate surface points and vectors.
918 
919     int numEvalPts = numEvalU * numEvalV;
920 
921     snlPoint* evalPts = new snlPoint [ numEvalPts ];
922 
923     index = 0;
924 
925     for ( int indexU = 0; indexU < numEvalU; indexU ++ )
926     {
927         for ( int indexV = 0; indexV < numEvalV; indexV ++ )
928         {
929             evalPts [ index ] = eval ( paramU [ indexU ], paramV [ indexV ], basisU [ indexU ],
930                                        basisV [ indexV ] );
931 
932             index ++;
933         }
934     }
935 
936     // Calculate bounding distances. They are used for culling improbable guesses.
937 
938     double* boundDist = new double [ numEvalPts ];
939 
940     index = 0;
941 
942     for ( int indexU = 0; indexU < numEvalU; indexU ++ )
943     {
944         for ( int indexV = 0; indexV < numEvalV; indexV ++ )
945         {
946             double maxDist = 0;
947             double dist;
948 
949             if ( indexU > 0 )
950             {
951                 // U before current index.
952 
953                 if ( indexV > 0 )
954                 {
955                     dist = evalPts [ index - numEvalV - 1 ].distSqrd ( evalPts [ index ] );
956                     if ( dist > maxDist ) maxDist = dist;
957                 }
958 
959                 if ( indexV < numEvalV - 1 )
960                 {
961                     dist = evalPts [ index - numEvalV + 1 ].distSqrd ( evalPts [ index ] );
962                     if ( dist > maxDist ) maxDist = dist;
963                 }
964             }
965 
966             if ( indexU < numEvalU - 1 )
967             {
968                 // U after current index.
969 
970                 if ( indexV > 0 )
971                 {
972                     dist = evalPts [ index + numEvalV - 1 ].distSqrd ( evalPts [ index ] );
973                     if ( dist > maxDist ) maxDist = dist;
974                 }
975 
976                 if ( indexV < numEvalV - 1 )
977                 {
978                     dist = evalPts [ index + numEvalV + 1 ].distSqrd ( evalPts [ index ] );
979                     if ( dist > maxDist ) maxDist = dist;
980                 }
981             }
982 
983             boundDist [ index ] = maxDist;
984 
985             index ++;
986         }
987     }
988 
989     // Compare given points to evaluated points. One entry per span.
990 
991     int numSpans = numSpansU * numSpansV;
992 
993     int numSpanPoints = numPoints * numSpans;
994 
995     // Two dimensional arrays [ given point index ] [ span index ].
996 
997     int* uIndexes = new int [ numSpanPoints ];  // NOT control point indexes.
998     int* vIndexes = new int [ numSpanPoints ];
999     double* distances = new double [ numSpanPoints ];
1000     bool* populated = new bool [ numSpanPoints ];  // If false distances have not been populated.
1001 
1002     for ( index = 0; index < numSpanPoints; index ++ )
1003         populated [ index ] = false;
1004 
1005     double distSqrd;
1006 
1007     int numToReturn = 0;
1008 
1009     index = 0;
1010 
1011     for ( int indexU = 0; indexU < numEvalU; indexU ++ )
1012     {
1013         for ( int indexV = 0; indexV < numEvalV; indexV ++ )
1014         {
1015             int spanIndex = spanU [ indexU ] * numSpansV + spanV [ indexV ];
1016 
1017             for ( int ptIndex = 0; ptIndex < numPoints; ptIndex ++ )
1018             {
1019                 if ( pointMask [ ptIndex ] )
1020                 {
1021                     int ptIndexOffset = ptIndex * numSpans;
1022 
1023                     distSqrd = evalPts [ index ].distSqrd ( points [ ptIndex ] );
1024 
1025                     // Only process span point if distance is within probable bounds.
1026 
1027                     if ( distSqrd < boundDist [ index ] )
1028                     {
1029                         if ( distances [ ptIndexOffset + spanIndex ] > distSqrd
1030                              || ! populated [ ptIndexOffset + spanIndex ])
1031                         {
1032                             if ( ! populated [ ptIndexOffset + spanIndex ] )
1033                             {
1034                                 numToReturn ++;
1035                                 populated [ ptIndexOffset + spanIndex ] = true;
1036                             }
1037 
1038                             distances [ ptIndexOffset + spanIndex ] = distSqrd;
1039                             uIndexes [ ptIndexOffset + spanIndex ] = indexU;
1040                             vIndexes [ ptIndexOffset + spanIndex ] = indexV;
1041                         }
1042                     }
1043                 }
1044             }
1045 
1046             index ++;
1047         }
1048     }
1049 
1050     // Build array of surface locations to return.
1051 
1052     ptrList <snlSurfLocnGuess>* retList = new ptrList <snlSurfLocnGuess>;
1053 
1054     int indexU, indexV;
1055 
1056     index = 0;
1057 
1058     for ( int ptIndex = 0; ptIndex < numPoints; ptIndex ++ )
1059     {
1060         for ( int spanIndex = 0; spanIndex < numSpans; spanIndex ++ )
1061         {
1062             if ( populated [ index ] )
1063             {
1064                 snlSurfLocnGuess* guessLocn = new snlSurfLocnGuess;
1065 
1066                 indexU = uIndexes [ index ];
1067                 indexV = vIndexes [ index ];
1068 
1069                 guessLocn -> paramU = paramU [ indexU ];
1070                 guessLocn -> paramV = paramV [ indexV ];
1071 
1072                 guessLocn -> pt = evalPts [ indexU * numEvalV + indexV ];
1073 
1074                 guessLocn -> dist = distances [ index ];
1075 
1076                 guessLocn -> origPtIndex = ptIndex;
1077 
1078                 guessLocn -> spanNumber = spanIndex;
1079 
1080                 if ( indexU > 0 )
1081                     guessLocn -> minU = paramU [ indexU - 1 ];
1082                 else
1083                     guessLocn -> minU = paramU [ indexU ];
1084 
1085                 if ( indexU < numEvalU - 1 )
1086                     guessLocn -> maxU = paramU [ indexU + 1 ];
1087                 else
1088                     guessLocn -> maxU = paramU [ indexU ];
1089 
1090                 if ( indexV > 0 )
1091                     guessLocn -> minV = paramV [ indexV - 1 ];
1092                 else
1093                     guessLocn -> minV = paramV [ indexV ];
1094 
1095                 if ( indexV < numEvalV -1 )
1096                     guessLocn -> maxV = paramV [ indexV + 1 ];
1097                 else
1098                     guessLocn -> maxV = paramV [ indexV ];
1099 
1100                 guessLocn -> culled = false;
1101                 guessLocn -> ignoreParamBounds = false;
1102                 guessLocn -> converged = false;
1103 
1104                 retList -> append ( guessLocn, true );
1105             }
1106 
1107             index ++;
1108         }
1109     }
1110 
1111     // Clean up
1112 
1113     delete[] uIndexes;
1114     delete[] vIndexes;
1115     delete[] distances;
1116     delete[] populated;
1117 
1118     delete[] evalPts;
1119     delete[] boundDist;
1120 
1121     delete[] paramU;
1122     delete[] paramV;
1123 
1124     delete[] spanU;
1125     delete[] spanV;
1126 
1127     for ( int index = 0; index < numEvalU; index ++ )
1128         delete[] basisU [ index ];
1129 
1130     for ( int index = 0; index < numEvalV; index ++ )
1131         delete[] basisV [ index ];
1132 
1133     delete[] basisU;
1134     delete[] basisV;
1135 
1136     return retList;
1137 }
1138 
guessProjLocation(snlPoint * points,int numPoints,bool * pointMask)1139 ptrList <snlSurfLocnGuess>* snlSurface::guessProjLocation ( snlPoint* points, int numPoints,
1140                                                             bool* pointMask )
1141 {
1142     //! Guess parametric location of given points.
1143     //  ------------------------------------------
1144     //! @param points Array of points to find matches with.
1145     //! @param numPoints Number of points in array.
1146     //! @param pointMask Array specifying which points to process. Corresponding index to points
1147     //!                  array. Must be true to process.
1148     //!
1149     //! @return List of surface location guess structs. Caller owns this list.
1150     //!
1151     //! @par Notes: Function expects all spans to be convex Bezier segments. It will _not_ work
1152     //!      if this is not so.
1153 
1154     int     index;
1155 
1156     int numSpansU = knotVectU -> getNumSpans();
1157     int numSpansV = knotVectV -> getNumSpans();
1158 
1159     int numEvalU = numSpansU + 1;
1160     int numEvalV = numSpansV + 1;
1161 
1162     // Pre-calculate parametric positions.
1163 
1164     knot* paramU = new knot [ numEvalU ];
1165 
1166     knot* paramV = new knot [ numEvalV ];
1167 
1168     // U Direction.
1169 
1170     int cSpan = knotVectU -> getFirstSpan();
1171 
1172     for ( int evalIndex = 0; evalIndex < numEvalU - 1; evalIndex ++ )
1173     {
1174         paramU [ evalIndex ] = knotVectU -> val ( cSpan );
1175 
1176         cSpan = knotVectU -> getNextSpan ( cSpan );
1177     }
1178 
1179     paramU [ numEvalU - 1 ] = knotVectU -> max();
1180 
1181     // V Direction.
1182 
1183     cSpan = knotVectV -> getFirstSpan();
1184 
1185     for ( int evalIndex = 0; evalIndex < numEvalV - 1; evalIndex ++ )
1186     {
1187         paramV [ evalIndex ] = knotVectV -> val ( cSpan );
1188 
1189         cSpan = knotVectV -> getNextSpan ( cSpan );
1190     }
1191 
1192     paramV [ numEvalV - 1 ] = knotVectV -> max();
1193 
1194     // Evaluate surface points and velocities.
1195     // Because the surface is segmented into Bezier segements the segment
1196     // corners are the control points and the velocities are calculated
1197     // directly from the control points without the need for basis functions.
1198 
1199     int numEvalPts = numEvalU * numEvalV;
1200 
1201     snlPoint* evalPts = new snlPoint [ numEvalPts ];
1202 
1203     snlVector* edgeNormalU = new snlVector [ 4 ];
1204     snlVector* edgeNormalV = new snlVector [ 4 ];
1205 
1206     bool* hasGuess = new bool [ numPoints ];
1207     snlSurfLocnGuess** lastGuess = new snlSurfLocnGuess* [ numPoints ];
1208 
1209     for ( int ptIndex = 0; ptIndex < numPoints; ptIndex ++ )
1210         hasGuess [ ptIndex ] = false;
1211 
1212     index = 0;
1213 
1214     int ctrlPtIndex;
1215 
1216     const snlCtrlPoint* ctrlPts = ctrlPtNet -> getCtrlPts();
1217 
1218     int vSize = sizeV();
1219 
1220     for ( int indexU = 0; indexU < numEvalU; indexU ++ )
1221     {
1222         ctrlPtIndex = degU * indexU * vSize;
1223 
1224         for ( int indexV = 0; indexV < numEvalV; indexV ++ )
1225         {
1226             evalPts [ index ] = ctrlPts [ ctrlPtIndex ];
1227 
1228             index ++;
1229 
1230             ctrlPtIndex += degV;
1231         }
1232     }
1233 
1234     ptrList <snlSurfLocnGuess>* tmpList = new ptrList <snlSurfLocnGuess>;  // List of out of order
1235                                                                            // guesses.
1236 
1237     int spanEvalIndex = 0;
1238 
1239     int spanNum = 0;
1240 
1241     for ( int spanU = 0; spanU < numSpansU; spanU ++ )
1242     {
1243         for ( int spanV = 0; spanV < numSpansV; spanV ++ )
1244         {
1245             // Calculate eight edge normals per segment. 4 per parametric direction.
1246             //
1247             // Edge normal orientation per segment:
1248             //
1249             // 1 ---- 2 --- V
1250             // |      |
1251             // 3 ---- 4
1252             // |
1253             // U
1254 
1255             snlVector velocityU;
1256             snlVector velocityV;
1257             snlVector normal;
1258             snlVector edge;
1259 
1260             int baseIndex = spanU * degU * vSize + spanV * degV;
1261 
1262             // Calculate and orient first set of edge normals
1263 
1264             velocityU.calc ( ctrlPts [ baseIndex ], ctrlPts [ baseIndex + vSize ] );
1265             velocityV.calc ( ctrlPts [ baseIndex ], ctrlPts [ baseIndex + 1 ] );
1266 
1267             normal.crossProduct ( velocityU, velocityV );
1268 
1269             edge.calc ( evalPts [ spanEvalIndex ], evalPts [ spanEvalIndex + 1 ] );
1270             edgeNormalU [ 0 ].crossProduct ( normal, edge );
1271 
1272             snlVector orient ( evalPts [ spanEvalIndex ], evalPts [ spanEvalIndex + numEvalV ] );
1273             if ( edgeNormalU [ 0 ].dot ( orient ) < 0.0 ) edgeNormalU [ 0 ] *= - 1.0;
1274 
1275             if ( edgeNormalU [ 0 ].dot ( velocityV ) < 0.0 )
1276             {
1277                 // If velocity vectors are outside of edge then use them for edge normal calculation
1278                 // instead.
1279 
1280                 edgeNormalU [ 0 ].crossProduct ( normal, velocityV );
1281                 if ( edgeNormalU [ 0 ].dot ( orient ) < 0.0 ) edgeNormalU [ 0 ] *= - 1.0;
1282             }
1283 
1284             edge.calc ( evalPts [ spanEvalIndex ], evalPts [ spanEvalIndex + numEvalV ] );
1285             edgeNormalV [ 0 ].crossProduct ( normal, edge );
1286 
1287             orient.calc ( evalPts [ spanEvalIndex ], evalPts [ spanEvalIndex + 1 ] );
1288             if ( edgeNormalV [ 0 ].dot ( orient ) < 0.0 ) edgeNormalV [ 0 ] *= - 1.0;
1289 
1290             if ( edgeNormalV [ 0 ].dot ( velocityU ) < 0.0 )
1291             {
1292                 edgeNormalV [ 0 ].crossProduct ( normal, velocityU );
1293                 if ( edgeNormalV [ 0 ].dot ( orient ) < 0.0 ) edgeNormalV [ 0 ] *= - 1.0;
1294             }
1295 
1296             // Calculate and orient second set of edge normals
1297 
1298             velocityU.calc ( ctrlPts [ baseIndex + degV ], ctrlPts [ baseIndex + degV + vSize ] );
1299             velocityV.calc ( ctrlPts [ baseIndex + degV ], ctrlPts [ baseIndex + degV - 1 ] );
1300 
1301             normal.crossProduct ( velocityU, velocityV );
1302 
1303             edge.calc ( evalPts [ spanEvalIndex + 1 ], evalPts [ spanEvalIndex ] );
1304             edgeNormalU [ 1 ].crossProduct ( normal, edge );
1305 
1306             orient.calc ( evalPts [ spanEvalIndex + 1 ], evalPts [ spanEvalIndex + numEvalV + 1 ] );
1307             if ( edgeNormalU [ 1 ].dot ( orient ) < 0.0 ) edgeNormalU [ 1 ] *= - 1.0;
1308 
1309             if ( edgeNormalU [ 1 ].dot ( velocityV ) < 0.0 )
1310             {
1311                 edgeNormalU [ 1 ].crossProduct ( normal, velocityV );
1312                 if ( edgeNormalU [ 1 ].dot ( orient ) < 0.0 ) edgeNormalU [ 1 ] *= - 1.0;
1313             }
1314 
1315             edge.calc ( evalPts [ spanEvalIndex + 1 ], evalPts [ spanEvalIndex + numEvalV + 1] );
1316             edgeNormalV [ 1 ].crossProduct ( normal, edge );
1317 
1318             orient.calc ( evalPts [ spanEvalIndex + 1 ], evalPts [ spanEvalIndex ] );
1319             if ( edgeNormalV [ 1 ].dot ( orient ) < 0.0 ) edgeNormalV [ 1 ] *= - 1.0;
1320 
1321             if ( edgeNormalV [ 1 ].dot ( velocityU ) < 0.0 )
1322             {
1323                 edgeNormalV [ 1 ].crossProduct ( normal, velocityU );
1324                 if ( edgeNormalV [ 1 ].dot ( orient ) < 0.0 ) edgeNormalV [ 1 ] *= - 1.0;
1325             }
1326 
1327             baseIndex += degU * vSize;
1328 
1329             // Calculate and orient third set of edge normals
1330 
1331             velocityU.calc ( ctrlPts [ baseIndex ], ctrlPts [ baseIndex - vSize ] );
1332             velocityV.calc ( ctrlPts [ baseIndex ], ctrlPts [ baseIndex + 1 ] );
1333 
1334             normal.crossProduct ( velocityU, velocityV );
1335 
1336             edge.calc ( evalPts [ spanEvalIndex + numEvalV ],
1337                         evalPts [ spanEvalIndex + numEvalV + 1 ] );
1338 
1339             edgeNormalU [ 2 ].crossProduct ( normal, edge );
1340 
1341             orient.calc ( evalPts [ spanEvalIndex + numEvalV ], evalPts [ spanEvalIndex ] );
1342 
1343             if ( edgeNormalU [ 2 ].dot ( orient ) < 0.0 ) edgeNormalU [ 2 ] *= - 1.0;
1344 
1345             if ( edgeNormalU [ 2 ].dot ( velocityV ) < 0.0 )
1346             {
1347                 edgeNormalU [ 2 ].crossProduct ( normal, velocityV );
1348                 if ( edgeNormalU [ 2 ].dot ( orient ) < 0.0 ) edgeNormalU [ 2 ] *= - 1.0;
1349             }
1350 
1351             edge.calc ( evalPts [ spanEvalIndex + numEvalV ], evalPts [ spanEvalIndex ] );
1352             edgeNormalV [ 2 ].crossProduct ( normal, edge );
1353 
1354             orient.calc ( evalPts [ spanEvalIndex + numEvalV ],
1355                           evalPts [ spanEvalIndex + numEvalV + 1 ] );
1356 
1357             if ( edgeNormalV [ 2 ].dot ( orient ) < 0.0 ) edgeNormalV [ 2 ] *= - 1.0;
1358 
1359             if ( edgeNormalV [ 2 ].dot ( velocityU ) < 0.0 )
1360             {
1361                 edgeNormalV [ 2 ].crossProduct ( normal, velocityU );
1362                 if ( edgeNormalV [ 2 ].dot ( orient ) < 0.0 ) edgeNormalV [ 2 ] *= - 1.0;
1363             }
1364 
1365             // Calculate and orient fourth set of edge normals
1366 
1367             velocityU.calc ( ctrlPts [ baseIndex + degV ], ctrlPts [ baseIndex + degV - vSize ] );
1368             velocityV.calc ( ctrlPts [ baseIndex + degV ], ctrlPts [ baseIndex + degV - 1 ] );
1369 
1370             normal.crossProduct ( velocityU, velocityV );
1371 
1372             edge.calc ( evalPts [ spanEvalIndex + numEvalV + 1 ],
1373                         evalPts [ spanEvalIndex + numEvalV ] );
1374 
1375             edgeNormalU [ 3 ].crossProduct ( normal, edge );
1376 
1377             orient.calc ( evalPts [ spanEvalIndex + numEvalV + 1 ], evalPts [ spanEvalIndex + 1 ] );
1378 
1379             if ( edgeNormalU [ 3 ].dot ( orient ) < 0.0 ) edgeNormalU [ 3 ] *= - 1.0;
1380 
1381             if ( edgeNormalU [ 3 ].dot ( velocityV ) < 0.0 )
1382             {
1383                 edgeNormalU [ 3 ].crossProduct ( normal, velocityV );
1384                 if ( edgeNormalU [ 3 ].dot ( orient ) < 0.0 ) edgeNormalU [ 3 ] *= - 1.0;
1385             }
1386 
1387             edge.calc ( evalPts [ spanEvalIndex + numEvalV + 1 ], evalPts [ spanEvalIndex + 1 ] );
1388             edgeNormalV [ 3 ].crossProduct ( normal, edge );
1389 
1390             orient.calc ( evalPts [ spanEvalIndex + numEvalV + 1 ],
1391                           evalPts [ spanEvalIndex + numEvalV ] );
1392 
1393             if ( edgeNormalV [ 3 ].dot ( orient ) < 0.0 ) edgeNormalV [ 3 ] *= - 1.0;
1394 
1395             if ( edgeNormalV [ 3 ].dot ( velocityU ) < 0.0 )
1396             {
1397                 edgeNormalV [ 3 ].crossProduct ( normal, velocityU );
1398                 if ( edgeNormalV [ 3 ].dot ( orient ) < 0.0 ) edgeNormalV [ 3 ] *= - 1.0;
1399             }
1400 
1401             // Step through each given point and check to see if it is probable that it belongs
1402             // to this patch. If it is, create a guess for it.
1403 
1404             knot minU = paramU [ spanU ];
1405             knot maxU = paramU [ spanU + 1 ];
1406             knot minV = paramV [ spanV ];
1407             knot maxV = paramV [ spanV + 1 ];
1408 
1409             for ( int ptIndex = 0; ptIndex < numPoints; ptIndex ++ )
1410             {
1411                 bool withinEdge1_2 = false;
1412                 bool withinEdge2_4 = false;
1413                 bool withinEdge4_3 = false;
1414                 bool withinEdge3_1 = false;
1415 
1416                 // Corner 1.
1417 
1418                 orient.calc ( evalPts [ spanEvalIndex ], points [ ptIndex ] );
1419 
1420                 if ( orient.dot ( edgeNormalU [ 0 ] ) >= 0.0 )
1421                     withinEdge1_2 = true;
1422 
1423                 if ( orient.dot ( edgeNormalV [ 0 ] ) >= 0.0 )
1424                     withinEdge3_1 = true;
1425 
1426                 // Corner 2.
1427 
1428                 orient.calc ( evalPts [ spanEvalIndex + 1 ], points [ ptIndex ] );
1429 
1430                 if ( orient.dot ( edgeNormalU [ 1 ] ) >= 0.0 )
1431                     withinEdge1_2 = true;
1432 
1433                 if ( orient.dot ( edgeNormalV [ 1 ] ) >= 0.0 )
1434                     withinEdge2_4 = true;
1435 
1436                 // Corner 3.
1437 
1438                 orient.calc ( evalPts [ spanEvalIndex + numEvalV ], points [ ptIndex ] );
1439 
1440                 if ( orient.dot ( edgeNormalU [ 2 ] ) >= 0.0 )
1441                     withinEdge4_3 = true;
1442 
1443                 if ( orient.dot ( edgeNormalV [ 2 ] ) >= 0.0 )
1444                     withinEdge3_1 = true;
1445 
1446                 // Corner 4.
1447 
1448                 orient.calc ( evalPts [ spanEvalIndex + numEvalV + 1 ], points [ ptIndex ] );
1449 
1450                 if ( orient.dot ( edgeNormalU [ 3 ] ) >= 0.0 )
1451                     withinEdge4_3 = true;
1452 
1453                 if ( orient.dot ( edgeNormalV [ 3 ] ) >= 0.0 )
1454                     withinEdge2_4 = true;
1455 
1456                 // If point is within all edges then a guess needs to be created.
1457 
1458                 if ( withinEdge1_2 && withinEdge2_4 && withinEdge4_3 && withinEdge3_1 )
1459                 {
1460                     snlSurfLocnGuess* newGuess = new snlSurfLocnGuess;
1461 
1462                     newGuess -> paramU = ( ( maxU - minU ) / 2 ) + minU;
1463                     newGuess -> paramV = ( ( maxV - minV ) / 2 ) + minV;
1464                     newGuess -> pt = eval ( newGuess -> paramU, newGuess -> paramV );
1465                     newGuess -> dist = ( newGuess -> pt ).distSqrd ( points [ ptIndex ] );
1466                     newGuess -> origPtIndex = ptIndex;
1467                     newGuess -> spanNumber = spanNum;
1468                     newGuess -> minU = minU;
1469                     newGuess -> maxU= maxU;
1470                     newGuess -> minV = minV;
1471                     newGuess -> maxV = maxV;
1472                     newGuess -> culled = false;
1473                     newGuess -> ignoreParamBounds = false;
1474                     newGuess -> converged = false;
1475 
1476                     tmpList -> append ( newGuess, false );
1477 
1478                     hasGuess [ ptIndex ] = true;
1479                     lastGuess [ ptIndex ] = newGuess;
1480                 }
1481             }
1482 
1483             spanNum ++;
1484 
1485             spanEvalIndex ++;
1486         }
1487 
1488         spanEvalIndex ++;
1489     }
1490 
1491     // If a candidate span is not found for a given point then find closest evaluated point
1492     // but don't impose parametric bounds to the guess.
1493 
1494     for ( int ptIndex = 0; ptIndex < numPoints; ptIndex ++ )
1495     {
1496         if ( ! hasGuess [ ptIndex ] )
1497         {
1498             snlSurfLocnGuess* newGuess = new snlSurfLocnGuess;
1499 
1500             index = 0;
1501 
1502             for ( int indexU = 0; indexU < numEvalU; indexU ++ )
1503             {
1504                 for ( int indexV = 0; indexV < numEvalV; indexV ++ )
1505                 {
1506                     double distSqrd = points [ ptIndex ].distSqrd ( evalPts [ index ] );
1507 
1508                     if ( ( ! indexU && ! indexV ) || ( newGuess -> dist > distSqrd ) )
1509                     {
1510                         newGuess -> dist = distSqrd;
1511                         newGuess -> paramU = paramU [ indexU ];
1512                         newGuess -> paramV = paramV [ indexV ];
1513                         newGuess -> pt = evalPts [ index ];
1514                     }
1515 
1516                     index ++;
1517                 }
1518             }
1519 
1520             // Fill in rest of guess data.
1521 
1522             newGuess -> origPtIndex = ptIndex;
1523             newGuess -> culled = false;
1524             newGuess -> ignoreParamBounds = true;
1525             newGuess -> converged = false;
1526 
1527             tmpList -> append ( newGuess, false );
1528 
1529             lastGuess [ ptIndex ] = newGuess;
1530         }
1531     }
1532 
1533     // Build properly ordered return list.
1534 
1535     ptrList <snlSurfLocnGuess>* retList = new ptrList <snlSurfLocnGuess>; // List of guesses to
1536                                                                           // return.
1537 
1538     for ( int ptIndex = 0; ptIndex < numPoints; ptIndex ++ )
1539     {
1540         snlSurfLocnGuess* guess = tmpList -> first();
1541 
1542         while ( guess )
1543         {
1544             if ( guess -> origPtIndex == ptIndex )
1545                 retList -> append ( guess, true );
1546 
1547             guess = tmpList -> next();
1548         }
1549     }
1550 
1551     // Clean up and return.
1552 
1553     delete[] paramU;
1554     delete[] paramV;
1555 
1556     delete[] evalPts;
1557 
1558     delete[] edgeNormalU;
1559     delete[] edgeNormalV;
1560 
1561     delete[] hasGuess;
1562     delete[] lastGuess;
1563 
1564     delete tmpList;
1565 
1566     return retList;
1567 }
1568 
guessFastProjLocation(snlPoint * points,int numPoints,int numGuessesPerPt,int granU,int granV)1569 ptrList <snlSurfLocnGuess>* snlSurface::guessFastProjLocation ( snlPoint* points, int numPoints, int numGuessesPerPt,
1570                                                                 int granU, int granV )
1571 {
1572     //! Guess parametric location of given points.
1573     //  ------------------------------------------
1574     //! @param points Array of points to find matches with.
1575     //! @param numPoints Number of points in array.
1576     //! @param numGuessesPerPt Number of guesses to return per point.
1577     //! @param granU Number of guesses per span.
1578     //! @param granV Number of guesses per span.
1579     //!
1580     //! @return List of surface location guess structs. Caller owns this lists.
1581 
1582     int index;
1583 
1584     int numSpansU = knotVectU -> getNumSpans();
1585     int numSpansV = knotVectV -> getNumSpans();
1586 
1587     int numEvalU = granU * numSpansU + 1;
1588     int numEvalV = granV * numSpansV + 1;
1589 
1590     // Pre-calculate parametric positions.
1591 
1592     knot* paramU = new knot [ numEvalU ];
1593     int* spanU = new int [ numEvalU ];
1594 
1595     knot* paramV = new knot [ numEvalV ];
1596     int* spanV = new int [ numEvalV ];
1597 
1598     // U direction.
1599 
1600     int cSpan = knotVectU -> getFirstSpan();
1601 
1602     knot paramStart = knotVectU -> val ( cSpan );
1603 
1604     cSpan = knotVectU -> getNextSpan ( cSpan );
1605 
1606     knot paramEnd;
1607 
1608     if ( cSpan )
1609         paramEnd = knotVectU -> val ( cSpan );
1610     else
1611         paramEnd = knotVectU -> max();
1612 
1613 
1614     int numSteps;
1615 
1616     int paramIndex = 0;
1617 
1618     basis param;
1619 
1620     for ( int span = 0; span < numSpansU; span ++ )
1621     {
1622         basis paramStep = ( paramEnd - paramStart ) / (double) granU;
1623 
1624         param = paramStart;
1625 
1626         if ( span )
1627         {
1628             numSteps = granU;
1629             param += paramStep;
1630         }
1631         else
1632         {
1633             numSteps = granU + 1;
1634         }
1635 
1636         // Generate params for span.
1637 
1638         for ( index = 0; index < numSteps; index ++ )
1639         {
1640             paramU [ paramIndex ] = param;
1641 
1642             spanU [ paramIndex ++ ] = span;
1643 
1644             param += paramStep;
1645 
1646             if ( param > paramEnd ) param = paramEnd;  // Round off error trap.
1647         }
1648 
1649         paramStart = paramEnd;
1650 
1651         cSpan = knotVectU -> getNextSpan ( cSpan );
1652 
1653         if ( cSpan )
1654             paramEnd = knotVectU -> val ( cSpan );
1655         else
1656             paramEnd = knotVectU -> max();
1657     }
1658 
1659     // V direction.
1660 
1661     cSpan = knotVectV -> getFirstSpan();
1662 
1663     paramStart = knotVectV -> val ( cSpan );
1664 
1665     cSpan = knotVectV -> getNextSpan ( cSpan );
1666 
1667     if ( cSpan )
1668         paramEnd = knotVectV -> val ( cSpan );
1669     else
1670         paramEnd = knotVectV -> max();
1671 
1672     paramIndex = 0;
1673 
1674     for ( int span = 0; span < numSpansV; span ++ )
1675     {
1676         basis paramStep = ( paramEnd - paramStart ) / (double) granV;
1677 
1678         param = paramStart;
1679 
1680         if ( span )
1681         {
1682             numSteps = granV;
1683             param += paramStep;
1684         }
1685         else
1686         {
1687             numSteps = granV + 1;
1688         }
1689 
1690         for ( index = 0; index < numSteps; index ++ )
1691         {
1692             paramV [ paramIndex ] = param;
1693 
1694             spanV [ paramIndex ++ ] = span;
1695 
1696             param += paramStep;
1697 
1698             if ( param > paramEnd ) param = paramEnd;  // Round off error trap.
1699         }
1700 
1701         paramStart = paramEnd;
1702 
1703         cSpan = knotVectV -> getNextSpan ( cSpan );
1704 
1705         if ( cSpan )
1706             paramEnd = knotVectV -> val ( cSpan );
1707         else
1708             paramEnd = knotVectV -> max();
1709     }
1710 
1711     // Pre-evaluate basis functions.
1712 
1713     basis** basisU = new basis* [ numEvalU ];
1714     basis** basisV = new basis* [ numEvalV ];
1715 
1716     for ( index = 0; index < numEvalU; index ++ )
1717         basisU [ index ] = knotVectU -> evalBasis ( paramU [ index ] );
1718 
1719     for ( index = 0; index < numEvalV; index ++ )
1720         basisV [ index ] = knotVectV -> evalBasis ( paramV [ index ] );
1721 
1722     // Evaluate surface points and vectors.
1723 
1724     int numEvalPts = numEvalU * numEvalV;
1725 
1726     snlPoint* evalPts = new snlPoint [ numEvalPts ];
1727 
1728     index = 0;
1729 
1730     for ( int indexU = 0; indexU < numEvalU; indexU ++ )
1731     {
1732         for ( int indexV = 0; indexV < numEvalV; indexV ++ )
1733         {
1734             evalPts [ index ] = eval ( paramU [ indexU ], paramV [ indexV ], basisU [ indexU ],
1735                                        basisV [ indexV ] );
1736 
1737             index ++;
1738         }
1739     }
1740 
1741     // Compare given points to evaluated points.
1742 
1743     int totalNumGuesses = numGuessesPerPt * numPoints;
1744 
1745     snlSurfLocnGuess** guesses = new snlSurfLocnGuess* [ totalNumGuesses ];
1746 
1747     for ( int guessIndex = 0; guessIndex < totalNumGuesses; guessIndex ++ )
1748         guesses [ guessIndex ] = 0;
1749 
1750     index = 0;
1751 
1752     for ( int indexU = 0; indexU < numEvalU; indexU ++ )
1753     {
1754         for ( int indexV = 0; indexV < numEvalV; indexV ++ )
1755         {
1756             for ( int ptIndex = 0; ptIndex < numPoints; ptIndex ++ )
1757             {
1758                 double distSqrd = evalPts [ index ].distSqrd ( points [ ptIndex ] );
1759 
1760                 // If no guesses in available guess position then add a new one.
1761 
1762                 int guessOffset = ptIndex * numGuessesPerPt;
1763 
1764                 bool guessInserted = false;
1765 
1766                 for ( int guessIndex = 0; guessIndex < numGuessesPerPt; guessIndex ++ )
1767                 {
1768                     if ( ! guesses [ guessIndex + guessOffset ] )
1769                     {
1770                         // Create new guess.
1771 
1772                         snlSurfLocnGuess* newGuess = new snlSurfLocnGuess;
1773 
1774                         newGuess -> paramU = paramU [ indexU ];
1775                         newGuess -> paramV = paramV [ indexV ];
1776                         newGuess -> pt = evalPts [ index ];
1777                         newGuess -> dist = distSqrd;
1778                         newGuess -> origPtIndex = ptIndex;
1779                         newGuess -> spanNumber = - 1;
1780                         newGuess -> culled = false;
1781                         newGuess -> ignoreParamBounds = true;
1782                         newGuess -> converged = false;
1783 
1784                         guesses [ guessIndex + guessOffset ] = newGuess;
1785 
1786                         guessInserted = true;
1787 
1788                         break;
1789                     }
1790                 }
1791 
1792                 if ( ! guessInserted )
1793                 {
1794                     // Find guess with largest distance.
1795 
1796                     int replaceIndex = guessOffset;
1797                     double dist = guesses [ guessOffset ] -> dist;
1798 
1799                     for ( int guessIndex = 1; guessIndex < numGuessesPerPt; guessIndex ++ )
1800                     {
1801                         if ( guesses [ guessIndex + guessOffset ] -> dist > dist )
1802                         {
1803                             replaceIndex = guessIndex + guessOffset;
1804                             dist = guesses [ guessIndex + guessOffset ] -> dist;
1805                         }
1806                     }
1807 
1808                     if ( dist > distSqrd )
1809                     {
1810                         // Replace guess.
1811 
1812                         guesses [ replaceIndex ] -> paramU = paramU [ indexU ];
1813                         guesses [ replaceIndex ] -> paramV = paramV [ indexV ];
1814                         guesses [ replaceIndex ] -> pt = evalPts [ index ];
1815                         guesses [ replaceIndex ] -> dist = distSqrd;
1816                         guesses [ replaceIndex ] -> origPtIndex = ptIndex;
1817                     }
1818                 }
1819             }
1820 
1821             index ++;
1822         }
1823     }
1824 
1825     // Assemble return list.
1826 
1827     ptrList <snlSurfLocnGuess>* retList = new ptrList <snlSurfLocnGuess>;  // List of guesses to return.
1828 
1829     for ( int guessIndex = 0; guessIndex < totalNumGuesses; guessIndex ++ )
1830     {
1831         if ( guesses [ guessIndex ] )
1832             retList -> append ( guesses [ guessIndex ], true );
1833     }
1834 
1835     // Clean up and return.
1836 
1837     delete[] evalPts;
1838 
1839     delete[] guesses;
1840 
1841     delete[] paramU;
1842     delete[] paramV;
1843 
1844     delete[] spanU;
1845     delete[] spanV;
1846 
1847     for ( int index = 0; index < numEvalU; index ++ )
1848         delete[] basisU [ index ];
1849 
1850     for ( int index = 0; index < numEvalV; index ++ )
1851         delete[] basisV [ index ];
1852 
1853     delete[] basisU;
1854     delete[] basisV;
1855 
1856     return retList;
1857 }
1858 
1859 //ptrList <snlSurfLocnGuess>* snlSurface::guessProjLocation_triMethod ( snlPoint* points, int numPoints, bool* pointMask )
1860 //{
1861 //    //! Guess parametric location of given points using triangular decomposition.
1862 //    //  -------------------------------------------------------------------------
1863 //    //! @param points Array of points to find matches with.
1864 //    //! @param numPoints Number of points in array.
1865 //    //! @param pointMask Array specifying which points to process. Corresponding index to points
1866 //    //!                  array. Must be true to process.
1867 //    //!
1868 //    //! @return List of surface location guess structs. Caller owns this list.
1869 //
1870 //
1871 //
1872 //}
1873 
hasAmbigEdges(sEdge * results,double tolerance)1874 int snlSurface::hasAmbigEdges ( sEdge* results, double tolerance )
1875 {
1876     //! See if the surface has ambiguous edges
1877     //  --------------------------------------
1878     //! @param results Array of sEdge. Should be size 4.
1879     //! @param tolerance Tolerance of edge detection.
1880     //!
1881     //! @return Number of ambiguous edges.
1882 
1883     snlPoint    evalPt [ 4 ];  // Current evaled non-homogeneous point.
1884 
1885     knot        min_u, max_u, min_v, max_v;
1886 
1887     min_u = knotVectU -> min();
1888     max_u = knotVectU -> max();
1889     min_v = knotVectV -> min();
1890     max_v = knotVectV -> max();
1891 
1892     // Generate points to process.
1893 
1894     knot mid_u = ( max_u - min_u ) / 2.0 + min_u;
1895     knot mid_v = ( max_v - min_v ) / 2.0 + min_v;
1896 
1897     // Min / Max U
1898 
1899     evalPt [ 0 ] = eval ( min_u, mid_v );
1900 
1901     evalPt [ 1 ] = eval ( max_u, mid_v );
1902 
1903     // Min / Max V
1904 
1905     evalPt  [ 2 ] = eval ( mid_u, min_v );
1906 
1907     evalPt [ 3 ] = eval ( mid_u, max_v );
1908 
1909     // Generate initial guesses. 3 Per edge.
1910 
1911     ptrList <snlSurfLocnGuess>* guessList = new ptrList <snlSurfLocnGuess>;
1912 
1913     snlSurfLocnGuess guessTemplate;
1914     guessTemplate.culled = false;
1915     guessTemplate.ignoreParamBounds = true;
1916     guessTemplate.converged = false;
1917 
1918     // Edge: Min U. Eval index 0.
1919 
1920     snlSurfLocnGuess* guess;
1921 
1922     // Max U.
1923     guess = new snlSurfLocnGuess;
1924     *guess = guessTemplate;
1925     guess -> paramU = max_u;
1926     guess -> paramV = mid_v;
1927     guess -> pt = evalPt [ 1 ];
1928     guess -> dist = evalPt [ 1 ].distSqrd ( evalPt [ 0 ] );
1929     guess -> origPtIndex = 0;
1930     guessList -> append ( guess, true );
1931 
1932     // Min V.
1933 
1934     guess = new snlSurfLocnGuess;
1935     *guess = guessTemplate;
1936     guess -> paramU = mid_u;
1937     guess -> paramV = min_v;
1938     guess -> pt = evalPt [ 2 ];
1939     guess -> dist = evalPt [ 2 ].distSqrd ( evalPt [ 0 ] );
1940     guess -> origPtIndex = 0;
1941     guessList -> append ( guess, true );
1942 
1943     // Max V.
1944 
1945     guess = new snlSurfLocnGuess;
1946     *guess = guessTemplate;
1947     guess -> paramU = mid_u;
1948     guess -> paramV = max_v;
1949     guess -> pt = evalPt [ 3 ];
1950     guess -> dist = evalPt [ 3 ].distSqrd ( evalPt [ 0 ] );
1951     guess -> origPtIndex = 0;
1952     guessList -> append ( guess, true );
1953 
1954     // Edge: Max U. Eval index 1.
1955 
1956     // Min U.
1957 
1958     guess = new snlSurfLocnGuess;
1959     *guess = guessTemplate;
1960     guess -> paramU = min_u;
1961     guess -> paramV = mid_v;
1962     guess -> pt = evalPt [ 0 ];
1963     guess -> dist = evalPt [ 0 ].distSqrd ( evalPt [ 1 ] );
1964     guess -> origPtIndex = 1;
1965     guessList -> append ( guess, true );
1966 
1967     // Min V.
1968 
1969     guess = new snlSurfLocnGuess;
1970     *guess = guessTemplate;
1971     guess -> paramU = mid_u;
1972     guess -> paramV = min_v;
1973     guess -> pt = evalPt [ 2 ];
1974     guess -> dist = evalPt [ 2 ].distSqrd ( evalPt [ 1 ] );
1975     guess -> origPtIndex = 1;
1976     guessList -> append ( guess, true );
1977 
1978     // Max V.
1979 
1980     guess = new snlSurfLocnGuess;
1981     *guess = guessTemplate;
1982     guess -> paramU = mid_u;
1983     guess -> paramV = max_v;
1984     guess -> pt = evalPt [ 3 ];
1985     guess -> dist = evalPt [ 3 ].distSqrd ( evalPt [ 1 ] );
1986     guess -> origPtIndex = 1;
1987     guessList -> append ( guess, true );
1988 
1989     // Edge: Min V. Eval index 2.
1990 
1991     // Max V.
1992 
1993     guess = new snlSurfLocnGuess;
1994     *guess = guessTemplate;
1995     guess -> paramU = mid_u;
1996     guess -> paramV = max_v;
1997     guess -> pt = evalPt [ 3 ];
1998     guess -> dist = evalPt [ 3 ].distSqrd ( evalPt [ 2 ] );
1999     guess -> origPtIndex = 2;
2000     guessList -> append ( guess, true );
2001 
2002     // Min U.
2003 
2004     guess = new snlSurfLocnGuess;
2005     *guess = guessTemplate;
2006     guess -> paramU = min_u;
2007     guess -> paramV = mid_v;
2008     guess -> pt = evalPt [ 0 ];
2009     guess -> dist = evalPt [ 0 ].distSqrd ( evalPt [ 2 ] );
2010     guess -> origPtIndex = 2;
2011     guessList -> append ( guess, true );
2012 
2013     // Max U.
2014 
2015     guess = new snlSurfLocnGuess;
2016     *guess = guessTemplate;
2017     guess -> paramU = max_u;
2018     guess -> paramV = mid_v;
2019     guess -> pt = evalPt [ 1 ];
2020     guess -> dist = evalPt [ 1 ].distSqrd ( evalPt [ 2 ] );
2021     guess -> origPtIndex = 2;
2022     guessList -> append ( guess, true );
2023 
2024     // Edge: Max V. Eval index 3.
2025 
2026     // Min V.
2027 
2028     guess = new snlSurfLocnGuess;
2029     *guess = guessTemplate;
2030     guess -> paramU = mid_u;
2031     guess -> paramV = min_v;
2032     guess -> pt = evalPt [ 2 ];
2033     guess -> dist = evalPt [ 2 ].distSqrd ( evalPt [ 3 ] );
2034     guess -> origPtIndex = 3;
2035     guessList -> append ( guess, true );
2036 
2037     // Min U.
2038 
2039     guess = new snlSurfLocnGuess;
2040     *guess = guessTemplate;
2041     guess -> paramU = min_u;
2042     guess -> paramV = mid_v;
2043     guess -> pt = evalPt [ 0 ];
2044     guess -> dist = evalPt [ 0 ].distSqrd ( evalPt [ 3 ] );
2045     guess -> origPtIndex = 3;
2046     guessList -> append ( guess, true );
2047 
2048     // Max U.
2049 
2050     guess = new snlSurfLocnGuess;
2051     *guess = guessTemplate;
2052     guess -> paramU = max_u;
2053     guess -> paramV = mid_v;
2054     guess -> pt = evalPt [ 1 ];
2055     guess -> dist = evalPt [ 1 ].distSqrd ( evalPt [ 3 ] );
2056     guess -> origPtIndex = 3;
2057     guessList -> append ( guess, true );
2058 
2059     // Process guesses.
2060 
2061     int arraySize;
2062 
2063     snlSurfLocn* locns = processGuesses ( evalPt, 4, &arraySize, guessList, tolerance, tolerance,
2064                                           10, true, true );
2065 
2066     // Check for projected points remaining, within tolerance, on their original edge.
2067 
2068     bool edgeIsAmbig [ 4 ] = { false, false, false, false };
2069 
2070     for ( int index = 0; index < arraySize; index ++ )
2071     {
2072         if ( locns [ index ].dist > tolerance ) continue;
2073 
2074         switch ( locns [ index ].origPtIndex )
2075         {
2076             case 0:
2077 
2078                 // Min U.
2079 
2080                 if ( locns [ index ].paramU < min_u + tolerance )
2081                     edgeIsAmbig [ 0 ] = true;
2082 
2083                 break;
2084 
2085             case 1:
2086 
2087                 // Max U.
2088 
2089                 if ( locns [ index ].paramU > max_u - tolerance )
2090                     edgeIsAmbig [ 1 ] = true;
2091 
2092                 break;
2093 
2094             case 2:
2095 
2096                 // Min V.
2097 
2098                 if ( locns [ index ].paramV < min_v + tolerance )
2099                     edgeIsAmbig [ 2 ] = true;
2100 
2101                 break;
2102 
2103             case 3:
2104 
2105                 // Max V.
2106 
2107                 if ( locns [ index ].paramV > max_v - tolerance )
2108                     edgeIsAmbig [ 3 ] = true;
2109 
2110                 break;
2111         }
2112     }
2113 
2114     int cIndex = 0;
2115     int numAmbig = 0;
2116 
2117     // Process ambiguous points to find edges.
2118 
2119     if ( edgeIsAmbig [ 0 ] )
2120     {
2121         results [ cIndex ].direction = 0;
2122         results [ cIndex ].pVal = min_u;
2123 
2124         numAmbig++;
2125         cIndex++;
2126     }
2127 
2128     if ( edgeIsAmbig [ 1 ] )
2129     {
2130         results [ cIndex ].direction = 0;
2131         results [ cIndex ].pVal = max_u;
2132 
2133         numAmbig++;
2134         cIndex++;
2135     }
2136 
2137     if ( edgeIsAmbig [ 2 ] )
2138     {
2139         results [ cIndex ].direction = 1;
2140         results [ cIndex ].pVal = min_v;
2141 
2142         numAmbig++;
2143         cIndex++;
2144     }
2145 
2146     if ( edgeIsAmbig [ 3 ] )
2147     {
2148         results [ cIndex ].direction = 1;
2149         results [ cIndex ].pVal = max_v;
2150 
2151         numAmbig++;
2152     }
2153 
2154     delete[] locns;
2155 
2156     return numAmbig;
2157 }
2158 
hasAmbigEdges_depr(sEdge * results)2159 int snlSurface::hasAmbigEdges_depr ( sEdge* results )
2160 {
2161     //! See if the surface has ambiguous edges
2162     //! --------------------------------------
2163     //! @param results Array of sEdge. Should be size 4.
2164     //!
2165     //! @return Number of ambiguous edges.
2166     //!
2167     //! Notes: Function is now deprecated.
2168 
2169     snlPoint    evalPt [ 4 ];  // Current evaled non-homogeneous point.
2170 
2171     knot        minT, maxT, minU, maxU;
2172 
2173     minT = knotVectU -> min();
2174     maxT = knotVectU -> max();
2175     minU = knotVectV -> min();
2176     maxU = knotVectV -> max();
2177 
2178     // Min / Max T
2179 
2180     evalPt [ 0 ] = eval ( minT, ( ( maxU - minU ) / 2 ) + minU );
2181 
2182     evalPt [ 1 ] = eval ( maxT, ( ( maxU - minU ) / 2 ) + minU );
2183 
2184     // Min / Max U
2185 
2186     evalPt  [ 2 ] = eval (( ( maxT - minT ) / 2 ) + minT, minU );
2187 
2188     evalPt [ 3 ] = eval (( ( maxT - minT ) / 2 ) + minT, maxU );
2189 
2190     // Get projection function to do the work.
2191 
2192     ptrList < sLocn >* ambig;
2193 
2194     sLocn projns [ 4 ];
2195 
2196     ambig = projPtSurf ( *this, evalPt, 4, projns,
2197                          0.000001, 0.00001, 3 );
2198 
2199     int cIndex = 0;
2200     int numAmbig = 0;
2201 
2202     // Process ambiguous points to find edges.
2203 
2204     if ( projns [ 0 ].flag > 1 )
2205     {
2206         results [ cIndex ].direction = 0;
2207         results [ cIndex ].pVal = minT;
2208 
2209         numAmbig++;
2210         cIndex++;
2211     }
2212 
2213     if ( projns [ 1 ].flag > 1 )
2214     {
2215         results [ cIndex ].direction = 0;
2216         results [ cIndex ].pVal = maxT;
2217 
2218         numAmbig++;
2219         cIndex++;
2220     }
2221 
2222     if ( projns [ 2 ].flag > 1 )
2223     {
2224         results [ cIndex ].direction = 1;
2225         results [ cIndex ].pVal = minU;
2226 
2227         numAmbig++;
2228         cIndex++;
2229     }
2230 
2231     if ( projns [ 3 ].flag > 1 )
2232     {
2233         results [ cIndex ].direction = 1;
2234         results [ cIndex ].pVal = maxU;
2235 
2236         numAmbig++;
2237     }
2238 
2239     delete ambig;
2240 
2241     return numAmbig;
2242 }
2243 
2244