1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16 
17 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
18 #include <pcl/pcl_macros.h>
19 
20 
21 ON_OBJECT_IMPLEMENT(ON_NurbsCage,ON_Geometry,"06936AFB-3D3C-41ac-BF70-C9319FA480A1");
22 
23 ON_OBJECT_IMPLEMENT(ON_MorphControl,ON_Geometry,"D379E6D8-7C31-4407-A913-E3B7040D034A");
24 
25 
Read(ON_BinaryArchive & archive)26 ON_BOOL32 ON_NurbsCage::Read(ON_BinaryArchive& archive)
27 {
28   Destroy();
29 
30   int major_version = 0;
31   int minor_version = 0;
32   bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
33   if ( rc )
34   {
35     while(rc)
36     {
37       if ( major_version != 1 )
38       {
39         ON_ERROR("ON_NurbsCage::Read - old code unable to read new version of chunk");
40         rc = false;
41         break;
42       }
43 
44       int dim=0;
45       int order0=0,order1=0,order2=0;
46       int cv_count0=0,cv_count1=0,cv_count2=0;
47       int is_rat=0;
48 
49       rc = archive.ReadInt(&dim);
50       if (!rc)
51         break;
52       if (dim < 1 || dim > 10000)
53       {
54         ON_ERROR("ON_NurbsCage::Read - invalid dim");
55         rc=false;
56         break;
57       }
58 
59       rc = archive.ReadInt(&is_rat);
60       if (!rc)
61         break;
62       if (is_rat != 0 && is_rat != 1)
63       {
64         ON_ERROR("ON_NurbsCage::Read - invalid is_rat");
65         rc=false;
66         break;
67       }
68 
69       rc = archive.ReadInt(&order0);
70       if (!rc)
71         break;
72       if ( order0 < 2 || order0 > 10000 )
73       {
74         ON_ERROR("ON_NurbsCage::Read - invalid order0");
75         rc=false;
76         break;
77       }
78 
79       rc = archive.ReadInt(&order1);
80       if (!rc)
81         break;
82       if ( order1 < 2 || order1 > 10000 )
83       {
84         ON_ERROR("ON_NurbsCage::Read - invalid order1");
85         rc=false;
86         break;
87       }
88 
89       rc = archive.ReadInt(&order2);
90       if (!rc)
91         break;
92       if ( order2 < 2 || order2 > 10000 )
93       {
94         ON_ERROR("ON_NurbsCage::Read - invalid order2");
95         rc=false;
96         break;
97       }
98 
99       rc = archive.ReadInt(&cv_count0);
100       if (!rc)
101         break;
102       if ( cv_count0 < order0 || cv_count0 > 100000 )
103       {
104         ON_ERROR("ON_NurbsCage::Read - invalid cv_count0");
105         rc=false;
106         break;
107       }
108 
109       rc = archive.ReadInt(&cv_count1);
110       if (!rc)
111         break;
112       if ( cv_count1 < order1 || cv_count1 > 100000 )
113       {
114         ON_ERROR("ON_NurbsCage::Read - invalid cv_count1");
115         rc=false;
116         break;
117       }
118 
119       rc = archive.ReadInt(&cv_count2);
120       if (!rc)
121         break;
122       if ( cv_count2 < order2 || cv_count2 > 100000 )
123       {
124         ON_ERROR("ON_NurbsCage::Read - invalid cv_count2");
125         rc=false;
126         break;
127       }
128 
129       rc = Create(dim,is_rat==1,order0,order1,order2,cv_count0,cv_count1,cv_count2);
130       if (!rc)
131         break;
132 
133       if (rc)
134         rc = archive.ReadDouble(KnotCount(0),m_knot[0]);
135       if (rc)
136         rc = archive.ReadDouble(KnotCount(1),m_knot[1]);
137       if (rc)
138         rc = archive.ReadDouble(KnotCount(2),m_knot[2]);
139 
140       int i,j,k;
141       const int cv_dim = m_is_rat?(m_dim+1):m_dim;
142       for(i = 0; i < cv_count0 && rc; i++)
143       {
144         for(j = 0; j < cv_count1 && rc; j++)
145         {
146           for ( k = 0; k < cv_count2 && rc; k++)
147           {
148             rc = archive.ReadDouble(cv_dim,CV(i,j,k));
149           }
150         }
151       }
152 
153 
154 
155       break;
156     }
157 
158     if ( !archive.EndRead3dmChunk() )
159     {
160       rc = false;
161     }
162   }
163   return rc;
164 }
165 
Write(ON_BinaryArchive & archive) const166 ON_BOOL32 ON_NurbsCage::Write(ON_BinaryArchive& archive) const
167 {
168   bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
169 
170   if (rc)
171   {
172     rc = archive.WriteInt(m_dim);
173     if(rc)
174       rc = archive.WriteInt(m_is_rat);
175 
176     if (rc)
177       rc = archive.WriteInt(m_order[0]);
178     if (rc)
179       rc = archive.WriteInt(m_order[1]);
180     if (rc)
181       rc = archive.WriteInt(m_order[2]);
182 
183     if (rc)
184       rc = archive.WriteInt(m_cv_count[0]);
185     if (rc)
186       rc = archive.WriteInt(m_cv_count[1]);
187     if (rc)
188       rc = archive.WriteInt(m_cv_count[2]);
189 
190     if (rc)
191       rc = archive.WriteDouble(KnotCount(0),m_knot[0]);
192     if (rc)
193       rc = archive.WriteDouble(KnotCount(1),m_knot[1]);
194     if (rc)
195       rc = archive.WriteDouble(KnotCount(2),m_knot[2]);
196 
197     int i,j,k;
198     const int cv_dim = m_is_rat?(m_dim+1):m_dim;
199     double* bogus_cv = (double*)alloca(cv_dim*sizeof(*bogus_cv));
200     for ( i = 0; i < cv_dim; i++ )
201       bogus_cv[i] = ON_UNSET_VALUE;
202     for(i = 0; i < m_cv_count[0] && rc; i++)
203     {
204       for(j = 0; j < m_cv_count[1] && rc; j++)
205       {
206         for ( k = 0; k < m_cv_count[2] && rc; k++)
207         {
208           const double* cv = CV(i,j,k);
209           if ( !cv )
210             cv = bogus_cv;
211           rc = archive.WriteDouble(cv_dim,cv);
212         }
213       }
214     }
215 
216     if ( !archive.EndWrite3dmChunk() )
217     {
218       rc = false;
219     }
220   }
221 
222   return rc;
223 }
224 
225 
226 
ON_NurbsCage()227 ON_NurbsCage::ON_NurbsCage()
228 : m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
229 {
230   m_order[0] = 0;
231   m_order[1] = 0;
232   m_order[2] = 0;
233   m_cv_count[0] = 0;
234   m_cv_count[1] = 0;
235   m_cv_count[2] = 0;
236   m_knot_capacity[0] = 0;
237   m_knot_capacity[1] = 0;
238   m_knot_capacity[2] = 0;
239   m_knot[0] = 0;
240   m_knot[1] = 0;
241   m_knot[2] = 0;
242   m_cv_stride[0] = 0;
243   m_cv_stride[1] = 0;
244   m_cv_stride[2] = 0;
245 }
246 
ON_NurbsCage(int dim,bool is_rat,int order0,int order1,int order2,int cv_count0,int cv_count1,int cv_count2)247 ON_NurbsCage::ON_NurbsCage( int dim, bool is_rat,
248                                 int order0,
249                                 int order1,
250                                 int order2,
251                                 int cv_count0,
252                                 int cv_count1,
253                                 int cv_count2
254                                 )
255                  : m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
256 {
257   m_order[0] = 0;
258   m_order[1] = 0;
259   m_order[2] = 0;
260   m_cv_count[0] = 0;
261   m_cv_count[1] = 0;
262   m_cv_count[2] = 0;
263   m_knot_capacity[0] = 0;
264   m_knot_capacity[1] = 0;
265   m_knot_capacity[2] = 0;
266   m_knot[0] = 0;
267   m_knot[1] = 0;
268   m_knot[2] = 0;
269   m_cv_stride[0] = 0;
270   m_cv_stride[1] = 0;
271   m_cv_stride[2] = 0;
272   Create( dim, is_rat, order0, order1, order2, cv_count0, cv_count1, cv_count2 );
273 }
274 
ON_NurbsCage(const ON_BoundingBox & bbox,int order0,int order1,int order2,int cv_count0,int cv_count1,int cv_count2)275 ON_NurbsCage::ON_NurbsCage( const ON_BoundingBox& bbox,
276                                int order0, int order1, int order2,
277                                int cv_count0, int cv_count1, int cv_count2
278                                )
279 : m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
280 {
281   m_order[0] = 0;
282   m_order[1] = 0;
283   m_order[2] = 0;
284   m_cv_count[0] = 0;
285   m_cv_count[1] = 0;
286   m_cv_count[2] = 0;
287   m_knot_capacity[0] = 0;
288   m_knot_capacity[1] = 0;
289   m_knot_capacity[2] = 0;
290   m_knot[0] = 0;
291   m_knot[1] = 0;
292   m_knot[2] = 0;
293   m_cv_stride[0] = 0;
294   m_cv_stride[1] = 0;
295   m_cv_stride[2] = 0;
296   Create(bbox,order0,order1,order2, cv_count0, cv_count1, cv_count2);
297 }
298 
IsParallelogram(double tolerance) const299 bool ON_NurbsCage::IsParallelogram(double tolerance) const
300 {
301   int i,j,k;
302   double r,s,t;
303   double x,y,z,dist;
304   ON_Interval d[3];
305   ON_3dPoint P, X, Y, Z, Q, B;
306 
307   bool rc = IsValid()?true:false;
308 
309   for ( i = 0; i < 3 && rc; i++ )
310   {
311     d[i] = Domain(i);
312     rc = (    d[i][0] == m_knot[i][0]
313            && d[i][1] == m_knot[i][m_cv_count[i]+m_order[i]-3]
314            );
315   }
316 
317   if (rc)
318   {
319     GetCV(0,0,0,P);
320     GetCV(m_cv_count[0]-1,0,0,X);
321     GetCV(0,m_cv_count[1]-1,0,Y);
322     GetCV(0,0,m_cv_count[2]-1,Z);
323 
324     if ( tolerance < ON_ZERO_TOLERANCE )
325       tolerance = ON_ZERO_TOLERANCE;
326 
327     for ( i = 0; i < m_cv_count[0]; i++ )
328     {
329       r = ON_GrevilleAbcissa(m_order[0],m_knot[0]+i);
330       x = d[0].NormalizedParameterAt(r);
331       for ( j = 0; j < m_cv_count[1]; j++ )
332       {
333         s = ON_GrevilleAbcissa(m_order[1],m_knot[1]+j);
334         y = d[1].NormalizedParameterAt(s);
335         for ( k = 0; k < m_cv_count[2]; k++ )
336         {
337           t = ON_GrevilleAbcissa(m_order[2],m_knot[2]+k);
338           z = d[2].NormalizedParameterAt(t);
339           Evaluate(r,s,t,0,3,&Q.x);
340           B = (1.0-x-y-z)*P + x*X + y*Y + z*Z;
341           dist = B.DistanceTo(Q);
342           if ( dist > tolerance )
343             return false;
344         }
345       }
346     }
347   }
348 
349   return rc;
350 }
351 
352 
ON_NurbsCage(const ON_3dPoint * box_corners,int order0,int order1,int order2,int cv_count0,int cv_count1,int cv_count2)353 ON_NurbsCage::ON_NurbsCage( const ON_3dPoint* box_corners,
354                                int order0, int order1, int order2,
355                                int cv_count0, int cv_count1, int cv_count2
356                                )
357 : m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
358 {
359   m_order[0] = 0;
360   m_order[1] = 0;
361   m_order[2] = 0;
362   m_cv_count[0] = 0;
363   m_cv_count[1] = 0;
364   m_cv_count[2] = 0;
365   m_knot_capacity[0] = 0;
366   m_knot_capacity[1] = 0;
367   m_knot_capacity[2] = 0;
368   m_knot[0] = 0;
369   m_knot[1] = 0;
370   m_knot[2] = 0;
371   m_cv_stride[0] = 0;
372   m_cv_stride[1] = 0;
373   m_cv_stride[2] = 0;
374   Create(box_corners,order0,order1,order2, cv_count0, cv_count1, cv_count2);
375 }
376 
ON_NurbsCage(const ON_BezierCage & src)377 ON_NurbsCage::ON_NurbsCage( const ON_BezierCage& src )
378 : m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
379 {
380   m_order[0] = 0;
381   m_order[1] = 0;
382   m_order[2] = 0;
383   m_cv_count[0] = 0;
384   m_cv_count[1] = 0;
385   m_cv_count[2] = 0;
386   m_knot_capacity[0] = 0;
387   m_knot_capacity[1] = 0;
388   m_knot_capacity[2] = 0;
389   m_knot[0] = 0;
390   m_knot[1] = 0;
391   m_knot[2] = 0;
392   m_cv_stride[0] = 0;
393   m_cv_stride[1] = 0;
394   m_cv_stride[2] = 0;
395   *this = src;
396 }
397 
~ON_NurbsCage()398 ON_NurbsCage::~ON_NurbsCage()
399 {
400   Destroy();
401 }
402 
KnotCount(int dir) const403 int ON_NurbsCage::KnotCount(int dir) const
404 {
405   return (dir>=0 && dir<=2) ? ON_KnotCount(m_order[dir],m_cv_count[dir]) : 0;
406 }
407 
GrevilleAbcissa(int dir,int gindex) const408 double ON_NurbsCage::GrevilleAbcissa(
409          int dir,    // dir
410          int gindex  // index (0 <= index < CVCount(dir)
411          ) const
412 {
413   return (dir >= 0 && dir <= 2)
414          ? ON_GrevilleAbcissa( m_order[dir], m_knot[dir] + gindex )
415          : ON_UNSET_VALUE;
416 }
417 
MakeDeformable()418 bool ON_NurbsCage::MakeDeformable()
419 {
420   return true;
421 }
422 
IsDeformable() const423 bool ON_NurbsCage::IsDeformable() const
424 {
425   return true;
426 }
427 
GetTightBoundingBox(ON_BoundingBox & tight_bbox,int bGrowBox,const ON_Xform * xform) const428 bool ON_NurbsCage::GetTightBoundingBox( ON_BoundingBox& tight_bbox,int bGrowBox,const ON_Xform* xform) const
429 {
430   if ( bGrowBox && !tight_bbox.IsValid() )
431   {
432     bGrowBox = false;
433   }
434 
435   if ( !bGrowBox )
436   {
437     tight_bbox.Destroy();
438   }
439 
440   if( xform && !xform->IsIdentity() )
441   {
442     ON_3dPoint P;
443     int i,j,k;
444     for ( i = 0; i < m_cv_count[0]; i++ )
445     {
446       for ( j = 0; j < m_cv_count[1]; j++ )
447       {
448         for ( k = 0; k < m_cv_count[2]; k++ )
449         {
450           GetCV(i,j,k,P);
451           P = (*xform)*P;
452           if ( tight_bbox.Set(P,bGrowBox) )
453           {
454             bGrowBox = true;
455           }
456         }
457       }
458     }
459   }
460   else
461   {
462     if ( GetBoundingBox(tight_bbox,bGrowBox) )
463       bGrowBox = true;
464   }
465 
466   return bGrowBox?true:false;
467 }
468 
CVCount() const469 int ON_NurbsCage::CVCount() const
470 {
471   return CVCount(0)*CVCount(1)*CVCount(2);
472 }
473 
CVCount(int dir) const474 int ON_NurbsCage::CVCount(int dir) const
475 {
476   return (dir>=0&&dir<=2) ? m_cv_count[dir] : 0;
477 }
478 
DestroyRuntimeCache(bool bDelete)479 void ON_NurbsCage::DestroyRuntimeCache(bool bDelete)
480 {
481   ON_Geometry::DestroyRuntimeCache(bDelete);
482 }
483 
ObjectType() const484 ON::object_type ON_NurbsCage::ObjectType() const
485 {
486   return ON::cage_object;
487 }
488 
operator =(const ON_BezierCage & src)489 ON_NurbsCage& ON_NurbsCage::operator=( const ON_BezierCage& src )
490 {
491   if ( Create(src.m_dim,src.m_is_rat,
492               src.m_order[0],src.m_order[1],src.m_order[2],
493               src.m_order[0],src.m_order[1],src.m_order[2]) )
494   {
495     int i,j,k;
496     for ( i = 0; i < m_cv_count[0]; i++ )
497     {
498       for ( j = 0; j < m_cv_count[1]; j++ )
499       {
500         for ( k = 0; k < m_cv_count[2]; k++ )
501         {
502           SetCV(i,j,k,ON::intrinsic_point_style,src.CV(i,j,k));
503         }
504       }
505     }
506   }
507   return *this;
508 }
509 
SizeOf() const510 unsigned int ON_NurbsCage::SizeOf() const
511 {
512   unsigned int sz = ON_Geometry::SizeOf();
513   sz += (sizeof(*this) - sizeof(ON_Geometry));
514   sz += (KnotCount(0) + KnotCount(1) + KnotCount(2) + CVSize()*CVCount())*sizeof(double);
515   return sz;
516 }
517 
DataCRC(ON__UINT32 current_remainder) const518 ON__UINT32 ON_NurbsCage::DataCRC(ON__UINT32 current_remainder) const
519 {
520   current_remainder = ON_CRC32(current_remainder,sizeof(m_dim),&m_dim);
521   current_remainder = ON_CRC32(current_remainder,sizeof(m_is_rat),&m_is_rat);
522   current_remainder = ON_CRC32(current_remainder,3*sizeof(m_order[0]),&m_order[0]);
523   current_remainder = ON_CRC32(current_remainder,3*sizeof(m_cv_count[0]),&m_cv_count[0]);
524   if (   m_cv_count[0] > 0 && m_cv_count[1] > 0 && m_cv_count[2] > 0
525       && m_cv_stride[0] > 0 && m_cv_stride[1] > 0 && m_cv_stride[2] > 0
526       && m_cv )
527   {
528     std::size_t sizeof_cv = CVSize()*sizeof(m_cv[0]);
529     const double* cv = m_cv;
530     int i, j, k;
531     for ( i = 0; i < m_cv_count[0]; i++ )
532     {
533       for ( j = 0; j < m_cv_count[1]; j++ )
534       {
535         cv = CV(i,j,0);
536         for (k = 0; i < m_cv_count[2]; k++ )
537         {
538           current_remainder = ON_CRC32(current_remainder,sizeof_cv,cv);
539           cv += m_cv_stride[2];
540         }
541       }
542     }
543   }
544   current_remainder = ON_CRC32(current_remainder,KnotCount(0)*sizeof(m_knot[0][0]),m_knot[0]);
545   current_remainder = ON_CRC32(current_remainder,KnotCount(1)*sizeof(m_knot[1][0]),m_knot[1]);
546   current_remainder = ON_CRC32(current_remainder,KnotCount(2)*sizeof(m_knot[2][0]),m_knot[2]);
547 
548   return current_remainder;
549 }
550 
ON_NurbsCage(const ON_NurbsCage & src)551 ON_NurbsCage::ON_NurbsCage(const ON_NurbsCage& src)
552                  : ON_Geometry(src),
553                    m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
554 {
555   m_order[0] = 0;
556   m_order[1] = 0;
557   m_order[2] = 0;
558   m_cv_count[0] = 0;
559   m_cv_count[1] = 0;
560   m_cv_count[2] = 0;
561   m_knot_capacity[0] = 0;
562   m_knot_capacity[1] = 0;
563   m_knot_capacity[2] = 0;
564   m_knot[0] = 0;
565   m_knot[1] = 0;
566   m_knot[2] = 0;
567   m_cv_stride[0] = 0;
568   m_cv_stride[1] = 0;
569   m_cv_stride[2] = 0;
570 
571   *this = src;
572 }
573 
574 
operator =(const ON_NurbsCage & src)575 ON_NurbsCage& ON_NurbsCage::operator=(const ON_NurbsCage& src)
576 {
577   if ( this != &src )
578   {
579     ON_Geometry::operator=(src);
580     if ( Create( src.m_dim, src.m_is_rat,
581          src.m_order[0], src.m_order[1], src.m_order[2],
582          src.m_cv_count[0], src.m_cv_count[1], src.m_cv_count[2]
583          ) )
584     {
585       if ( m_order[0] >= 2 && m_cv_count[0] >= m_order[0] && m_knot[0] && src.m_knot[0] )
586         memcpy( m_knot[0], src.m_knot[0], KnotCount(0)*sizeof(m_knot[0][0]));
587       if ( m_order[1] >= 2 && m_cv_count[1] >= m_order[1] && m_knot[1] && src.m_knot[1]  )
588         memcpy( m_knot[1], src.m_knot[1], KnotCount(1)*sizeof(m_knot[1][0]));
589       if ( m_order[2] >= 2 && m_cv_count[2] >= m_order[2] && m_knot[2] && src.m_knot[2]  )
590         memcpy( m_knot[2], src.m_knot[2], KnotCount(2)*sizeof(m_knot[2][0]));
591 
592       if ( m_cv && src.m_cv && m_cv_stride[0] > 0 && m_cv_stride[1] > 0 && m_cv_stride[2] > 0 )
593       {
594         const int cv_dim = CVSize();
595         const int sizeofcv = cv_dim*sizeof(m_cv[0]);
596         if (    m_cv_stride[0] == src.m_cv_stride[0]
597             && m_cv_stride[1] == src.m_cv_stride[1]
598             && m_cv_stride[2] == src.m_cv_stride[2] )
599         {
600           memcpy(m_cv,src.m_cv,m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*sizeofcv);
601         }
602         else
603         {
604           int i, j, k;
605           double* cv = m_cv;
606           for ( i = 0; i < m_cv_count[0]; i++ )
607           for ( j = 0; j < m_cv_count[1]; j++ )
608           for ( k = 0; k < m_cv_count[2]; k++ )
609           {
610             memcpy( cv, src.CV(i,j,k), sizeofcv );
611             cv += cv_dim;
612           }
613         }
614       }
615     }
616     else
617     {
618       Destroy();
619     }
620   }
621   return *this;
622 }
623 
IsValid(ON_TextLog *) const624 ON_BOOL32 ON_NurbsCage::IsValid(
625           ON_TextLog* //text_log
626           ) const
627 {
628   if ( 0 == m_cv )
629     return false;
630 
631   if ( 0 == m_knot[0] )
632     return false;
633 
634   if ( 0 == m_knot[1] )
635     return false;
636 
637   if ( 0 == m_knot[2] )
638     return false;
639 
640   if ( m_order[0] < 2 )
641     return false;
642   if ( m_order[1] < 2 )
643     return false;
644   if ( m_order[2] < 2 )
645     return false;
646 
647   if ( m_cv_count[0] < m_order[0] )
648     return false;
649   if ( m_cv_count[1] < m_order[1] )
650     return false;
651   if ( m_cv_count[2] < m_order[2] )
652     return false;
653 
654   if ( m_dim <= 0 )
655     return false;
656   if ( m_is_rat != 0 && m_is_rat != 1 )
657     return false;
658 
659   const int cvdim = m_is_rat ? (m_dim+1) : m_dim;
660 
661   if ( m_cv_capacity > 0 && m_cv_capacity < cvdim*m_cv_count[0]*m_cv_count[1]*m_cv_count[2] )
662     return false;
663 
664   int i[3];
665   i[0] = (m_cv_stride[0] <= m_cv_stride[1]) ? 0 : 1;
666   i[1] = 1-i[0];
667   if ( m_cv_stride[2] < m_cv_stride[i[0]] )
668   {
669     i[2] = i[1];
670     i[1] = i[0];
671     i[0] = 2;
672   }
673   else if ( m_cv_stride[2] < m_cv_stride[i[1]] )
674   {
675     i[2] = i[1];
676     i[1] = 2;
677   }
678   else
679   {
680     i[2] = 2;
681   }
682 
683   if ( m_cv_stride[i[0]] < cvdim )
684     return false;
685   if ( m_cv_stride[i[1]] < m_cv_stride[i[0]]*m_cv_count[i[0]] )
686     return false;
687   if ( m_cv_stride[i[2]] < m_cv_stride[i[1]]*m_cv_count[i[1]] )
688     return false;
689 
690   return true;
691 }
692 
Dump(ON_TextLog & dump) const693 void ON_NurbsCage::Dump( ON_TextLog& dump ) const
694 {
695   dump.Print( "ON_NurbsCage dim = %d is_rat = %d\n"
696                "        order = (%d, %d, %d) \n",
697                "        cv_count = (%d, %d, %d) \n",
698                m_dim, m_is_rat,
699                m_order[0], m_order[1], m_order[2],
700                m_cv_count[0], m_cv_count[1], m_cv_count[2] );
701 
702   int dir;
703   for ( dir = 0; dir < 3; dir++ )
704   {
705     dump.Print( "Knot Vector %d ( %d knots )\n", dir, KnotCount(dir) );
706     dump.PrintKnotVector( m_order[dir], m_cv_count[dir], m_knot[dir] );
707   }
708 
709   dump.Print( "Control Points  %d %s points\n"
710                "  index               value\n",
711                m_cv_count[0]*m_cv_count[1]*m_cv_count[2],
712                (m_is_rat) ? "rational" : "non-rational" );
713   if ( !m_cv )
714   {
715     dump.Print("  NULL cv array\n");
716   }
717   else
718   {
719     int i,j;
720     char sPreamble[128];
721     memset(sPreamble,0,sizeof(sPreamble));
722     for ( i = 0; i < m_order[0]; i++ )
723     {
724       for ( j = 0; j < m_order[1]; j++ )
725       {
726         if ( i > 0 || j > 0)
727           dump.Print("\n");
728         sPreamble[0] = 0;
729         sprintf(sPreamble,"  CV[%2d][%2d]",i,j);
730         dump.PrintPointList( m_dim, m_is_rat,
731                           m_cv_count[2], m_cv_stride[2],
732                           CV(i,j,0),
733                           sPreamble );
734       }
735       if ( i < m_order[0]-1)
736         dump.Print("\n");
737     }
738   }
739 }
740 
Dimension() const741 int ON_NurbsCage::Dimension() const
742 {
743   return m_dim;
744 }
745 
Create(const ON_BoundingBox & bbox,int order0,int order1,int order2,int cv_count0,int cv_count1,int cv_count2)746 bool ON_NurbsCage::Create( const ON_BoundingBox& bbox,
747                             int order0, int order1, int order2,
748                             int cv_count0, int cv_count1, int cv_count2
749                             )
750 {
751   /*
752             7______________6
753             |\             |\
754             | \            | \
755             |  \ _____________\
756             |   4          |   5
757             |   |          |   |
758             |   |          |   |
759             3---|----------2   |
760             \   |          \   |
761              \  |z          \  |
762             y \ |            \ |
763                \0_____________\1
764                        x
765   */
766   ON_3dPoint box_corners[8];
767   box_corners[0] = bbox.Corner(0,0,0);
768   box_corners[1] = bbox.Corner(1,0,0);
769   box_corners[2] = bbox.Corner(1,1,0);
770   box_corners[3] = bbox.Corner(0,1,0);
771   box_corners[4] = bbox.Corner(0,0,1);
772   box_corners[5] = bbox.Corner(1,0,1);
773   box_corners[6] = bbox.Corner(1,1,1);
774   box_corners[7] = bbox.Corner(0,1,1);
775   return Create(box_corners,order0,order1,order2,cv_count0,cv_count1,cv_count2);
776 }
777 
778 
Create(int dim,bool is_rat,int order0,int order1,int order2,int cv_count0,int cv_count1,int cv_count2)779 bool ON_NurbsCage::Create( int dim, bool is_rat,
780                             int order0, int order1, int order2,
781                             int cv_count0, int cv_count1, int cv_count2
782                             )
783 {
784   Destroy();
785   if ( order0 < 2 || order1 < 2 || order2 < 2 )
786   {
787     if (   0 == dim && 0 == is_rat
788          && 0 == order0 && 0 == order1 && 0 == order2
789          && 0 == cv_count0 && 0 == cv_count1 && 0 == cv_count2 )
790     {
791       return true;
792     }
793     ON_ERROR("ON_NurbsCage::Create - invalid orders");
794     return false;
795   }
796 
797   if ( cv_count0 < order0 || cv_count1 < order1 || cv_count2 < order2 )
798   {
799     ON_ERROR("ON_NurbsCage::Create - invalid cv counts");
800     return false;
801   }
802 
803   if ( dim < 1 )
804   {
805     ON_ERROR("ON_NurbsCage::Create - invalid dim");
806     return false;
807   }
808 
809   if ( is_rat != true && is_rat != false )
810   {
811     ON_ERROR("ON_NurbsCage::Create - invalid is_rat");
812     return false;
813   }
814 
815   m_dim = dim;
816   m_is_rat = is_rat ? 1 : 0;
817 
818   m_order[0] = order0;
819   m_order[1] = order1;
820   m_order[2] = order2;
821 
822   m_cv_count[0] = cv_count0;
823   m_cv_count[1] = cv_count1;
824   m_cv_count[2] = cv_count2;
825 
826   // Other ON_NurbsCage member functions, like operator=,
827   // depend on the strides being set this way.  If you anything
828   // in the next three lines, then you need to read all the
829   // code in the ON_NurbsCage member functions and adjust
830   // it accordingly.
831   m_cv_stride[2] = m_dim+m_is_rat;
832   m_cv_stride[1] = m_cv_stride[2]*m_cv_count[2];
833   m_cv_stride[0] = m_cv_stride[1]*m_cv_count[1];
834 
835   ReserveCVCapacity(m_cv_stride[0]*m_cv_count[0]);
836 
837   ReserveKnotCapacity(0,ON_KnotCount(m_order[0],m_cv_count[0]));
838   ReserveKnotCapacity(1,ON_KnotCount(m_order[1],m_cv_count[1]));
839   ReserveKnotCapacity(2,ON_KnotCount(m_order[2],m_cv_count[2]));
840 
841   ON_MakeClampedUniformKnotVector(m_order[0],m_cv_count[0],m_knot[0],1.0);
842   ON_MakeClampedUniformKnotVector(m_order[1],m_cv_count[1],m_knot[1],1.0);
843   ON_MakeClampedUniformKnotVector(m_order[2],m_cv_count[2],m_knot[2],1.0);
844 
845   ON_SetKnotVectorDomain( m_order[0], m_cv_count[0], m_knot[0], 0.0, 1.0);
846   ON_SetKnotVectorDomain( m_order[1], m_cv_count[1], m_knot[1], 0.0, 1.0);
847   ON_SetKnotVectorDomain( m_order[2], m_cv_count[2], m_knot[2], 0.0, 1.0);
848 
849   return IsValid() ? true : false;
850 }
851 
Create(const ON_3dPoint * box_corners,int order0,int order1,int order2,int cv_count0,int cv_count1,int cv_count2)852 bool ON_NurbsCage::Create(
853   const ON_3dPoint* box_corners,
854   int order0, int order1, int order2,
855   int cv_count0, int cv_count1, int cv_count2
856   )
857 {
858   int i, j, k;
859   double r,s,t;
860   //bool rc = false;
861   if ( 0 == box_corners )
862     return false;
863   for( i = 0; i < 8; i++ )
864   {
865     if ( !box_corners[i].IsValid() )
866       return false;
867   }
868 
869   // create trilinear "cube" to make it easy
870   // to calculate CV locations.
871   ON_BezierCage cube(3,0,2,2,2);
872   cube.SetCV(0,0,0,box_corners[0]);
873   cube.SetCV(1,0,0,box_corners[1]);
874   cube.SetCV(1,1,0,box_corners[2]);
875   cube.SetCV(0,1,0,box_corners[3]);
876   cube.SetCV(0,0,1,box_corners[4]);
877   cube.SetCV(1,0,1,box_corners[5]);
878   cube.SetCV(1,1,1,box_corners[6]);
879   cube.SetCV(0,1,1,box_corners[7]);
880 
881   if ( 2 == cv_count0 && 2 == cv_count1 && 2 == cv_count2 )
882   {
883     operator=(cube);
884   }
885   else
886   {
887     if (!Create(3,0,order0,order1,order2,cv_count0,cv_count1,cv_count2))
888       return false;
889 
890     double* g0 = (double*)onmalloc(m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*sizeof(*g0));
891     double* g1 = g0 + m_cv_count[0];
892     double* g2 = g1 + m_cv_count[1];
893 
894     ON_GetGrevilleAbcissae(m_order[0],m_cv_count[0],m_knot[0],false,g0);
895     ON_GetGrevilleAbcissae(m_order[1],m_cv_count[1],m_knot[1],false,g1);
896     ON_GetGrevilleAbcissae(m_order[2],m_cv_count[2],m_knot[2],false,g2);
897 
898     for (i = 0; i < m_cv_count[0]; i++)
899     {
900       r = g0[i];
901       for (j = 0; j < m_cv_count[1]; j++)
902       {
903         s = g1[j];
904         for (k = 0; k < m_cv_count[2]; k++)
905         {
906           t = g2[k];
907           SetCV(i,j,k,cube.PointAt(r,s,t));
908         }
909       }
910     }
911 
912     onfree(g0);
913   }
914   return IsValid()?true:false;
915 }
916 
917 
Destroy()918 void ON_NurbsCage::Destroy()
919 {
920   DestroyRuntimeCache();
921 
922   if ( m_cv && m_cv_capacity > 0 )
923   {
924     onfree(m_cv);
925     m_cv = 0;
926   }
927 
928   if ( m_knot[0] && m_knot_capacity[0] > 0 )
929   {
930     onfree(m_knot[0]);
931     m_knot[0] = 0;
932   }
933 
934   if ( m_knot[1] && m_knot_capacity[1] > 0 )
935   {
936     onfree(m_knot[1]);
937     m_knot[1] = 0;
938   }
939 
940   if ( m_knot[2] && m_knot_capacity[2] > 0 )
941   {
942     onfree(m_knot[2]);
943     m_knot[2] = 0;
944   }
945 
946   m_cv_capacity = 0;
947   m_knot_capacity[0] = 0;
948   m_knot_capacity[1] = 0;
949   m_knot_capacity[2] = 0;
950 
951   m_cv_stride[0] = 0;
952   m_cv_stride[1] = 0;
953   m_cv_stride[2] = 0;
954 
955   m_dim = 0;
956   m_is_rat = 0;
957 
958   m_order[0] = 0;
959   m_order[1] = 0;
960   m_order[2] = 0;
961 }
962 
EmergencyDestroy()963 void ON_NurbsCage::EmergencyDestroy()
964 {
965   DestroyRuntimeCache(false);
966   m_cv = 0;
967   m_knot[0] = 0;
968   m_knot[1] = 0;
969   m_knot[2] = 0;
970   m_cv_capacity = 0;
971   m_knot_capacity[0] = 0;
972   m_knot_capacity[1] = 0;
973   m_knot_capacity[2] = 0;
974   m_cv_stride[0] = 0;
975   m_cv_stride[1] = 0;
976   m_cv_stride[2] = 0;
977   m_dim = 0;
978   m_is_rat = 0;
979   m_order[0] = 0;
980   m_order[1] = 0;
981   m_order[2] = 0;
982 }
983 
984 
GetBBox(double * boxmin,double * boxmax,ON_BOOL32 bGrowBox) const985 ON_BOOL32 ON_NurbsCage::GetBBox( // returns true if successful
986        double* boxmin,    // minimum
987        double* boxmax,    // maximum
988        ON_BOOL32 bGrowBox  // true means grow box
989        ) const
990 {
991   int i, j;
992   bool rc = ( 0 != m_cv
993               && m_cv_count[0] >= 2 && m_cv_count[1] >= 2 && m_cv_count[2] >= 2
994               && m_cv_stride[0] > 0 && m_cv_stride[1] > 0 && m_cv_stride[2] > 0 ) ? true : false;
995   if ( !rc )
996   {
997     ON_ERROR("ON_NurbsCage::GetBBox - invalid input");
998   }
999   else
1000   {
1001     for ( i = 0; rc && i < m_cv_count[0]; i++ )
1002     for ( j = 0; rc && j < m_cv_count[1]; j++ )
1003     {
1004       rc = ON_GetPointListBoundingBox( m_dim, m_is_rat, m_cv_count[2], m_cv_stride[2],
1005                                       CV(i,j,0),
1006                                       boxmin, boxmax, bGrowBox?true:false );
1007       bGrowBox = true;
1008     }
1009   }
1010   return rc;
1011 }
1012 
Transform(const ON_Xform & xform)1013 ON_BOOL32 ON_NurbsCage::Transform( const ON_Xform& xform )
1014 {
1015   int i,j;
1016   bool rc = (m_cv_count[0] > 0 && m_cv_count[1] > 0 && m_cv_count[2]) ? true : false;
1017   if ( rc || !xform.IsIdentity() )
1018   {
1019     if ( 0 == m_is_rat )
1020     {
1021       if ( xform.m_xform[3][0] != 0.0 || xform.m_xform[3][1] != 0.0 || xform.m_xform[3][2] != 0.0 )
1022       {
1023         MakeRational();
1024       }
1025     }
1026 
1027     for ( i = 0; rc && i < m_cv_count[0]; i++ )
1028     {
1029       for ( j = 0; rc && j < m_cv_count[1]; j++ )
1030       {
1031         rc = ON_TransformPointList( m_dim, m_is_rat,
1032                                     m_cv_count[2], m_cv_stride[2],
1033                                     CV(i,j,0), xform );
1034       }
1035     }
1036   }
1037   return rc;
1038 }
1039 
Domain(int dir) const1040 ON_Interval ON_NurbsCage::Domain(
1041       int dir
1042       ) const
1043 {
1044   ON_Interval d;
1045   if ( dir < 0 || dir > 2 || !ON_GetKnotVectorDomain( m_order[dir], m_cv_count[dir], m_knot[dir], &d.m_t[0], &d.m_t[1] ) )
1046     d.Destroy();
1047   return d;
1048 }
1049 
1050 
1051 
1052 
1053 
ON_EvaluateNurbsCageSpan(int dim,int is_rat,int order0,int order1,int order2,const double * knot0,const double * knot1,const double * knot2,int cv_stride0,int cv_stride1,int cv_stride2,const double * cv0,int der_count,double t0,double t1,double t2,int v_stride,double * v)1054 bool ON_EvaluateNurbsCageSpan(
1055         int dim,
1056         int is_rat,
1057         int order0, int order1, int order2,
1058         const double* knot0,
1059         const double* knot1,
1060         const double* knot2,
1061         int cv_stride0, int cv_stride1, int cv_stride2,
1062         const double* cv0,
1063         int der_count,
1064         double t0, double t1, double t2,
1065         int v_stride,
1066         double* v
1067         )
1068 {
1069   double c;
1070   double* N_0, *N_1, *N_2, *P, *P0, *P00;
1071 	const double *cv;
1072   int j0, j1, j2, d0, d1, d2, d;
1073   const int cvdim = is_rat ? (dim+1) : dim;
1074   const int dcv2 = cv_stride2 - cvdim;
1075 	const int der_count0 = (der_count >= order0) ? order0-1 : der_count;
1076 	const int der_count1 = (der_count >= order1) ? order1-1 : der_count;
1077 	const int der_count2 = (der_count >= order1) ? order2-2 : der_count;
1078   int Pcount = der_count*(der_count*(der_count*2 + 9)+13)/6 + 1;
1079   int Psize = cvdim<<3;
1080   int i = order0*order0;
1081   int j = order1*order1;
1082   int k = order2*order2;
1083 
1084   // don't declare any variable below here to avoid problems caused
1085   // by compiler/optimizer/alloca() bugs that can't keep the SP
1086   // properly set.
1087 
1088   N_0 = (double*)alloca( ((i+j+k)*sizeof(*N_0)) + Pcount*Psize);
1089   N_1 = N_0 + i;
1090   N_2 = N_1 + j;
1091   P0  = N_2 + k;
1092   memset( P0, 0, Pcount*Psize );
1093 
1094   ON_EvaluateNurbsBasis( order0, knot0, t0, N_0 );
1095   ON_EvaluateNurbsBasis( order1, knot1, t1, N_1 );
1096   ON_EvaluateNurbsBasis( order2, knot2, t2, N_2 );
1097   if ( der_count0 > 0 )
1098   {
1099 		ON_EvaluateNurbsBasisDerivatives( order0, knot0, der_count0, N_0 );
1100 		ON_EvaluateNurbsBasisDerivatives( order1, knot1, der_count1, N_1 );
1101 		ON_EvaluateNurbsBasisDerivatives( order2, knot2, der_count2, N_2 );
1102   }
1103 
1104   // compute point
1105 	P = P0;
1106 	for ( j0 = 0; j0 < order0; j0++)
1107   {
1108 		for ( j1 = 0; j1 < order1; j1++ )
1109     {
1110       cv = cv0 + j0*cv_stride0 + j1*cv_stride1;
1111       for ( j2 = 0; j2 < order2; j2++ )
1112       {
1113 			  c = N_0[j0]*N_1[j1]*N_2[j2];
1114 			  j = cvdim;
1115 			  while (j--)
1116         {
1117 				  *P++ += c* *cv++;
1118         }
1119 			  P -= cvdim;
1120         cv += dcv2;
1121 		  }
1122 	  }
1123   }
1124 
1125   if ( der_count > 0 )
1126   {
1127     // quickly compute first derivatives
1128   	P += cvdim; // step over point
1129 		for ( j0 = 0; j0 < order0; j0++)
1130     {
1131 			for ( j1 = 0; j1 < order1; j1++ )
1132       {
1133         cv = cv0 + j0*cv_stride0 + j1*cv_stride1;
1134         for ( j2 = 0; j2 < order2; j2++ )
1135         {
1136           // "Dr"
1137 				  c = N_0[j0+order0]*N_1[j1]*N_2[j2];
1138 				  j = cvdim;
1139 				  while (j--)
1140 					  *P++ += c* *cv++;
1141           cv -= cvdim;
1142 
1143           // "Ds"
1144 				  c = N_0[j0]*N_1[j1+order1]*N_2[j2];
1145 				  j = cvdim;
1146 				  while (j--)
1147 					  *P++ += c* *cv++;
1148           cv -= cvdim;
1149 
1150           // "Dt"
1151 				  c = N_0[j0]*N_1[j1]*N_2[j2+order2];
1152 				  j = cvdim;
1153 				  while (j--)
1154 					  *P++ += c* *cv++;
1155 
1156 				  P -= 3*cvdim;
1157           cv += dcv2;
1158 			  }
1159 		  }
1160     }
1161 
1162     // compute higher order derivatives in generic loop
1163     for ( d = 2; d <= der_count; d++ )
1164     {
1165       // compute second derivatives
1166       P += (cvdim*d*(d+1))>>1; // step over (d-1) derivatives
1167       // P points to first coordinate of Dr^d
1168       if ( der_count0+der_count1+der_count2 > 1 )
1169       {
1170 		    for ( j0 = 0; j0 < order0; j0++)
1171         {
1172 		      for ( j1 = 0; j1 < order1; j1++)
1173           {
1174             cv = cv0 + j0*cv_stride0 + j1*cv_stride1;
1175 			      for ( j2 = 0; j2 < order2; j2++ )
1176             {
1177               P00 = P;
1178               for ( d0 = d; d0 >= 0; d0-- )
1179               {
1180                 for ( d1 = d-d0; d1 >= 0; d1-- )
1181                 {
1182                   d2 = d-d0-d1;
1183                   if ( d0 > der_count0 || d1 > der_count1 || d2 > der_count2 )
1184                   {
1185                     // this partial is zero
1186                     P += cvdim;
1187                   }
1188                   else
1189                   {
1190                     c = N_0[j0 + d0*order0]*N_1[j1 + d1*order1]*N_2[j2 + d2*order2];
1191                     j = cvdim;
1192                     while(j--)
1193                       *P++ += c* *cv++;
1194                     cv -= cvdim;
1195                   }
1196                 }
1197               }
1198               P = P00;
1199               cv += cv_stride2;
1200 			      }
1201 		      }
1202         }
1203       }
1204     }
1205 
1206   }
1207 
1208 	if ( is_rat )
1209   {
1210 		ON_EvaluateQuotientRule3( dim, der_count, cvdim, P0 );
1211 		Psize -= 8;
1212 	}
1213 
1214   Pcount = (der_count+1)*(der_count+2)*(der_count+3)/6;
1215 	for ( i = 0; i < Pcount; i++)
1216   {
1217 		memcpy( v, P0, Psize );
1218     v += v_stride;
1219 		P0 += cvdim;
1220 	}
1221 
1222   return true;
1223 }
1224 
Evaluate(double r,double s,double t,int der_count,int v_stride,double * v,int side,int * hint) const1225 bool ON_NurbsCage::Evaluate( // returns false if unable to evaluate
1226        double r, double s, double t,       // evaluation parameter
1227        int der_count,            // number of derivatives (>=0)
1228        int v_stride,             // array stride (>=Dimension())
1229        double* v,                // array of length stride*(ndir+1)*(ndir+2)/2
1230        int side,       // optional - determines which side to evaluate from
1231                        //         0 = default
1232                        //         1 = from upper NE quadrant
1233                        //         2 = from upper NW quadrant
1234                        //         3 = from upper SW quadrant
1235                        //         4 = from upper SE quadrant
1236                        //         5 = from lower NE quadrant
1237                        //         6 = from lower NW quadrant
1238                        //         7 = from lower SW quadrant
1239                        //         8 = from lower SE quadrant
1240        int* hint
1241        ) const
1242 {
1243   int side0 = (side&&(side==2||side==3||side==6||side==7))?-1:1;
1244   int side1 = (side&&(side==3||side==4||side==7||side==8))?-1:1;
1245   int side2 = (side>=5&&side<=8)?-1:1;
1246 
1247   int hint0 = (hint) ? hint[0] : 0;
1248   int hint1 = (hint) ? hint[1] : 0;
1249   int hint2 = (hint) ? hint[2] : 0;
1250   const int span_index0 = ON_NurbsSpanIndex(m_order[0],m_cv_count[0],m_knot[0],r,side0,hint0);
1251   const int span_index1 = ON_NurbsSpanIndex(m_order[1],m_cv_count[1],m_knot[1],s,side1,hint1);
1252   const int span_index2 = ON_NurbsSpanIndex(m_order[2],m_cv_count[2],m_knot[2],t,side2,hint2);
1253 
1254   bool rc = ON_EvaluateNurbsCageSpan(m_dim,m_is_rat,
1255     m_order[0],m_order[1],m_order[2],
1256     m_knot[0]+span_index0,
1257     m_knot[1]+span_index1,
1258     m_knot[2]+span_index2,
1259     m_cv_stride[0],m_cv_stride[1],m_cv_stride[2],
1260     m_cv + (m_cv_stride[0]*span_index0+m_cv_stride[1]*span_index1+m_cv_stride[2]*span_index2),
1261     der_count,
1262     r,s,t,
1263     v_stride,v);
1264 
1265   if( hint )
1266   {
1267     hint[0] = span_index0;
1268     hint[1] = span_index1;
1269     hint[2] = span_index2;
1270   }
1271 
1272   return rc;
1273 }
1274 
PointAt(double r,double s,double t) const1275 ON_3dPoint ON_NurbsCage::PointAt(
1276         double r,
1277         double s,
1278         double t
1279         ) const
1280 {
1281   ON_3dPoint pt;
1282   if ( m_dim <= 3 )
1283   {
1284     pt.x  = 0.0;
1285     pt.y  = 0.0;
1286     pt.z  = 0.0;
1287     Evaluate(r,s,t,0,3,&pt.x);
1288   }
1289   else
1290   {
1291     double* v = (double*)alloca(m_dim*sizeof(*v));
1292     v[0] = 0.0;
1293     v[1] = 0.0;
1294     v[2] = 0.0;
1295     Evaluate(r,s,t,0,m_dim,v);
1296     pt.x = v[0];
1297     pt.y = v[1];
1298     pt.z = v[2];
1299   }
1300   return pt;
1301 }
1302 
PointAt(ON_3dPoint rst) const1303 ON_3dPoint ON_NurbsCage::PointAt( ON_3dPoint rst ) const
1304 {
1305   ON_3dPoint pt;
1306   if ( m_dim <= 3 )
1307   {
1308     pt.x  = 0.0;
1309     pt.y  = 0.0;
1310     pt.z  = 0.0;
1311     Evaluate(rst.x,rst.y,rst.z,0,3,&pt.x);
1312   }
1313   else
1314   {
1315     double* v = (double*)alloca(m_dim*sizeof(*v));
1316     v[0] = 0.0;
1317     v[1] = 0.0;
1318     v[2] = 0.0;
1319     Evaluate(rst.x,rst.y,rst.z,0,m_dim,v);
1320     pt.x = v[0];
1321     pt.y = v[1];
1322     pt.z = v[2];
1323   }
1324   return pt;
1325 }
1326 
IsoSurface(int dir,double c,ON_NurbsSurface * srf) const1327 ON_NurbsSurface* ON_NurbsCage::IsoSurface(
1328         int dir,
1329         double c,
1330         ON_NurbsSurface* srf
1331         ) const
1332 {
1333   // c = 0; cage(c,s,t) = srf(s,t)
1334   // c = 1; cage(r,c,t) = srf(r,t)
1335   // c = 2; cage(r,s,c) = srf(r,s)
1336   if ( dir < 0 || dir > 2 )
1337   {
1338     ON_ERROR("ON_NurbsCage::IsoSurface - invalid dir parameter");
1339     return 0;
1340   }
1341   if ( m_order[dir] < 2 || m_cv_count[dir] < m_order[dir] || 0 == m_knot[dir] )
1342   {
1343     ON_ERROR("ON_NurbsCage::IsoSurface - invalid NURBS cage");
1344     return 0;
1345   }
1346 
1347   const int cage_cvdim = CVSize();
1348 
1349   int span_index = ON_NurbsSpanIndex(m_order[dir],m_cv_count[dir],m_knot[dir],c,0,0);
1350   ON_NurbsCurve nurbs_curve;
1351   nurbs_curve.m_dim = cage_cvdim*m_cv_count[0]*m_cv_count[1]*m_cv_count[2]/m_cv_count[dir];
1352   nurbs_curve.m_is_rat = 0;
1353   nurbs_curve.m_order = m_order[dir];
1354   nurbs_curve.m_cv_count = nurbs_curve.m_order;
1355   nurbs_curve.ReserveCVCapacity(nurbs_curve.m_dim*nurbs_curve.m_cv_count);
1356   nurbs_curve.m_cv_stride = nurbs_curve.m_dim;
1357   nurbs_curve.m_knot = m_knot[dir] + span_index;
1358   nurbs_curve.m_knot_capacity = 0;
1359 
1360   int ii,jj,kk;
1361   /*
1362   int i0 = 0;
1363   int i1 = m_cv_count[0];
1364   int j0 = 0;
1365   int j1 = m_cv_count[1];
1366   int k0 = 0;
1367   int k1 = m_cv_count[2];
1368   */
1369 
1370   //int i0 = span_index;
1371   //int i1 = span_index+m_order[dir];
1372   ii = dir;
1373   switch(dir)
1374   {
1375   case 0:
1376     jj = 1;
1377     kk = 2;
1378     break;
1379   case 1:
1380     jj = 0;
1381     kk = 2;
1382     break;
1383   case 2:
1384     jj = 0;
1385     kk = 1;
1386     break;
1387   default: // to keep lint happy
1388     ii = 0;
1389     jj = 1;
1390     kk = 2;
1391     break;
1392   };
1393 
1394 
1395   double* cv;
1396   const int cage_sizeofcv = cage_cvdim*sizeof(*cv);
1397   //int i0 = span_index;
1398   int i1 = span_index+m_order[ii];
1399   int j1 = m_cv_count[jj];
1400   int k1 = m_cv_count[kk];
1401 
1402   int i,j,k;
1403   int cage_ijk[3];
1404   for ( i = span_index; i < i1; i++)
1405   {
1406     cv = nurbs_curve.CV(i-span_index);
1407     cage_ijk[ii] = i;
1408     for ( j = 0; j < j1; j++ )
1409     {
1410       cage_ijk[jj] = j;
1411       for ( k = 0; k < k1; k++ )
1412       {
1413         cage_ijk[kk] = k;
1414         memcpy(cv,CV(cage_ijk[0],cage_ijk[1],cage_ijk[2]),cage_sizeofcv);
1415         cv += cage_cvdim;
1416       }
1417     }
1418   }
1419 
1420   ON_NurbsSurface* iso_srf = srf ? srf : ON_NurbsSurface::New();
1421   iso_srf->Create(m_dim,m_is_rat,m_order[jj],m_order[kk],m_cv_count[jj],m_cv_count[kk]);
1422   nurbs_curve.Evaluate(c,0,nurbs_curve.m_dim,iso_srf->m_cv,0,0);
1423   nurbs_curve.m_knot = 0;
1424   memcpy(iso_srf->m_knot[0],m_knot[jj],iso_srf->KnotCount(0)*sizeof(*iso_srf->m_knot[0]));
1425   memcpy(iso_srf->m_knot[1],m_knot[kk],iso_srf->KnotCount(1)*sizeof(*iso_srf->m_knot[1]));
1426 
1427   return iso_srf;
1428 }
1429 
IsRational() const1430 bool ON_NurbsCage::IsRational() const
1431 {
1432   return m_is_rat ? true : false;
1433 }
1434 
CVSize() const1435 int ON_NurbsCage::CVSize() const
1436 {
1437   return ( m_is_rat && m_dim>0 ) ? m_dim+1 : m_dim;
1438 }
1439 
Order(int dir) const1440 int ON_NurbsCage::Order( int dir ) const
1441 {
1442   return (dir>=0&&dir<=2) ? m_order[dir] : 0;
1443 }
1444 
Degree(int dir) const1445 int ON_NurbsCage::Degree(int dir) const
1446 {
1447   int order = Order(dir);
1448   return (order>=2) ? order-1 : 0;
1449 }
1450 
IsClosed(int dir) const1451 bool ON_NurbsCage::IsClosed(int dir) const
1452 {
1453   bool bIsClosed = false;
1454   if ( dir >= 0 && dir <= 2 && m_dim > 0)
1455   {
1456     if ( ON_IsKnotVectorClamped( m_order[dir], m_cv_count[dir], m_knot[dir] ) )
1457     {
1458       const double *cv0, *cv1;
1459       int i,j,k,d[3] = {0,0,0};
1460       d[dir] = m_cv_count[dir] - 1;
1461       for ( i = 0; i+d[0] < m_cv_count[0]; i++ )
1462       {
1463         for ( j = 0; j+d[1] < m_cv_count[1]; j++ )
1464         {
1465           for ( k = 0; k+d[2] < m_cv_count[2]; k++ )
1466           {
1467             cv0 = CV(i,j,k);
1468             cv1 = CV(i+d[0],j+d[1],k+d[2]);
1469             if ( false == ON_PointsAreCoincident( m_dim, m_is_rat, cv0, cv1 ) )
1470               return false;
1471           }
1472         }
1473       }
1474       bIsClosed = true;
1475     }
1476     else
1477     {
1478       bIsClosed =  IsPeriodic(dir);
1479     }
1480   }
1481   return bIsClosed;
1482 }
1483 
IsPeriodic(int dir) const1484 bool ON_NurbsCage::IsPeriodic(int dir) const
1485 {
1486   bool bIsPeriodic = false;
1487   if ( dir >= 0 && dir <= 2 && m_dim > 0 )
1488   {
1489     bIsPeriodic = ON_IsKnotVectorPeriodic( m_order[dir], m_cv_count[dir], m_knot[dir] );
1490     if ( bIsPeriodic )
1491     {
1492       const double *cv0, *cv1;
1493       int i,j,k,d[3] = {0,0,0};
1494       d[dir] = m_cv_count[dir] - (m_order[dir]-1);
1495       for ( i = 0; i+d[0] < m_cv_count[0]; i++ )
1496       {
1497         for ( j = 0; j+d[1] < m_cv_count[1]; j++ )
1498         {
1499           for ( k = 0; k+d[2] < m_cv_count[2]; k++ )
1500           {
1501             cv0 = CV(i,j,k);
1502             cv1 = CV(i+d[0],j+d[1],k+d[2]);
1503             if ( false == ON_PointsAreCoincident(m_dim, m_is_rat, cv0, cv1 ) )
1504               return false;
1505           }
1506         }
1507       }
1508     }
1509   }
1510   return bIsPeriodic;
1511 }
1512 
CV(int i,int j,int k) const1513 double* ON_NurbsCage::CV( int i, int j, int k ) const
1514 {
1515 
1516 #if defined(ON_DEBUG)
1517   if ( 0 == m_cv )
1518   {
1519     ON_ERROR("ON_NurbsCage::CV - NULL m_cv");
1520     return 0;
1521   }
1522   if ( i < 0 || i >= m_cv_count[0] || j< 0 || j >= m_cv_count[1] || k < 0 || k >= m_cv_count[2])
1523   {
1524     ON_ERROR("ON_NurbsCage::CV - (i,j,k) out of range");
1525     return 0;
1526   }
1527 #endif
1528 
1529   return (m_cv) ? (m_cv + i*m_cv_stride[0] + j*m_cv_stride[1] + k*m_cv_stride[2]) : 0;
1530 }
1531 
CVStyle() const1532 ON::point_style ON_NurbsCage::CVStyle() const
1533 {
1534   return m_is_rat ? ON::homogeneous_rational : ON::not_rational;
1535 }
1536 
Weight(int i,int j,int k) const1537 double ON_NurbsCage::Weight( int i, int j, int k ) const
1538 {
1539   return (m_cv && m_is_rat) ? m_cv[i*m_cv_stride[0] + j*m_cv_stride[1] + k*m_cv_stride[2] + + m_dim] : 1.0;
1540 }
1541 
1542 
SetWeight(int i,int j,int k,double w)1543 bool ON_NurbsCage::SetWeight( int i, int j, int k, double w )
1544 {
1545   bool rc = false;
1546   if ( m_is_rat )
1547   {
1548     double* cv = CV(i,j,k);
1549     if (cv)
1550     {
1551       cv[m_dim] = w;
1552       rc = true;
1553     }
1554   }
1555   else if ( w == 1.0 )
1556   {
1557     rc = true;
1558   }
1559   return rc;
1560 }
1561 
SetCV(int i,int j,int k,ON::point_style style,const double * Point)1562 bool ON_NurbsCage::SetCV( int i, int j, int k, ON::point_style style, const double* Point )
1563 {
1564   bool rc = true;
1565   int n;
1566   double w;
1567 
1568   double* cv = CV(i,j,k);
1569   if ( !cv )
1570     return false;
1571 
1572   switch ( style ) {
1573 
1574   case ON::not_rational:  // input Point is not rational
1575     memcpy( cv, Point, m_dim*sizeof(*cv) );
1576     if ( IsRational() ) {
1577       // NURBS surface is rational - set weight to one
1578       cv[m_dim] = 1.0;
1579     }
1580     break;
1581 
1582   case ON::homogeneous_rational:  // input Point is homogeneous rational
1583     if ( IsRational() ) {
1584       // NURBS surface is rational
1585       memcpy( cv, Point, (m_dim+1)*sizeof(*cv) );
1586     }
1587     else {
1588       // NURBS surface is not rational
1589       w = (Point[m_dim] != 0.0) ? 1.0/Point[m_dim] : 1.0;
1590       for ( n = 0; n < m_dim; n++ ) {
1591         cv[n] = w*Point[n];
1592       }
1593     }
1594     break;
1595 
1596   case ON::euclidean_rational:  // input Point is euclidean rational
1597     if ( IsRational() ) {
1598       // NURBS surface is rational - convert euclean point to homogeneous form
1599       w = Point[m_dim];
1600       for ( n = 0; n < m_dim; n++ )
1601         cv[i] = w*Point[i];
1602       cv[m_dim] = w;
1603     }
1604     else {
1605       // NURBS surface is not rational
1606       memcpy( cv, Point, m_dim*sizeof(*cv) );
1607     }
1608     break;
1609 
1610   case ON::intrinsic_point_style:
1611     n = m_is_rat?m_dim+1:m_dim;
1612     memcpy(cv,Point,n*sizeof(*cv));
1613     break;
1614 
1615   default:
1616     rc = false;
1617     break;
1618   }
1619   return rc;
1620 }
1621 
SetCV(int i,int j,int k,const ON_3dPoint & point)1622 bool ON_NurbsCage::SetCV( int i, int j, int k, const ON_3dPoint& point )
1623 {
1624   bool rc = false;
1625   double* cv = CV(i,j,k);
1626   if ( cv ) {
1627     cv[0] = point.x;
1628     if ( m_dim > 1 ) {
1629       cv[1] = point.y;
1630       if ( m_dim > 2 )
1631         cv[2] = point.z;
1632     }
1633     if ( m_is_rat ) {
1634       cv[m_dim] = 1.0;
1635     }
1636     rc = true;
1637   }
1638   return rc;
1639 }
1640 
SetCV(int i,int j,int k,const ON_4dPoint & point)1641 bool ON_NurbsCage::SetCV( int i, int j, int k, const ON_4dPoint& point )
1642 {
1643   bool rc = false;
1644   double* cv = CV(i,j,k);
1645   if ( cv ) {
1646     if ( m_is_rat ) {
1647       cv[0] = point.x;
1648       if ( m_dim > 1 ) {
1649         cv[1] = point.y;
1650         if ( m_dim > 2 )
1651           cv[2] = point.z;
1652       }
1653       cv[m_dim] = point.w;
1654       rc = true;
1655     }
1656     else {
1657       double w;
1658       if ( point.w != 0.0 ) {
1659         w = 1.0/point.w;
1660         rc = true;
1661       }
1662       else {
1663         w = 1.0;
1664       }
1665       cv[0] = w*point.x;
1666       if ( m_dim > 1 ) {
1667         cv[1] = w*point.y;
1668         if ( m_dim > 2 ) {
1669           cv[2] = w*point.z;
1670         }
1671       }
1672     }
1673   }
1674   return rc;
1675 }
1676 
GetCV(int i,int j,int k,ON::point_style style,double * Point) const1677 bool ON_NurbsCage::GetCV( int i, int j, int k, ON::point_style style, double* Point ) const
1678 {
1679   const double* cv = CV(i,j,k);
1680   if ( !cv )
1681     return false;
1682   int dim = Dimension();
1683   double w = ( IsRational() ) ? cv[dim] : 1.0;
1684   switch(style) {
1685   case ON::euclidean_rational:
1686     Point[dim] = w;
1687     PCL_FALLTHROUGH
1688   case ON::not_rational:
1689     if ( w == 0.0 )
1690       return false;
1691     w = 1.0/w;
1692     while(dim--) *Point++ = *cv++ * w;
1693     break;
1694   case ON::homogeneous_rational:
1695     Point[dim] = w;
1696     memcpy( Point, cv, dim*sizeof(*Point) );
1697     break;
1698   default:
1699     return false;
1700   }
1701   return true;
1702 }
1703 
GetCV(int i,int j,int k,ON_3dPoint & point) const1704 bool ON_NurbsCage::GetCV( int i, int j, int k, ON_3dPoint& point ) const
1705 {
1706   bool rc = false;
1707   const double* cv = CV(i,j,k);
1708   if ( cv ) {
1709     if ( m_is_rat ) {
1710       if (cv[m_dim] != 0.0) {
1711         const double w = 1.0/cv[m_dim];
1712         point.x = cv[0]*w;
1713         point.y = (m_dim>1)? cv[1]*w : 0.0;
1714         point.z = (m_dim>2)? cv[2]*w : 0.0;
1715         rc = true;
1716       }
1717     }
1718     else {
1719       point.x = cv[0];
1720       point.y = (m_dim>1)? cv[1] : 0.0;
1721       point.z = (m_dim>2)? cv[2] : 0.0;
1722       rc = true;
1723     }
1724   }
1725   return rc;
1726 }
1727 
GetCV(int i,int j,int k,ON_4dPoint & point) const1728 bool ON_NurbsCage::GetCV( int i, int j, int k, ON_4dPoint& point ) const
1729 {
1730   bool rc = false;
1731   const double* cv = CV(i,j,k);
1732   if ( cv ) {
1733     point.x = cv[0];
1734     point.y = (m_dim>1)? cv[1] : 0.0;
1735     point.z = (m_dim>2)? cv[2] : 0.0;
1736     point.w = (m_is_rat) ? cv[m_dim] : 1.0;
1737     rc = true;
1738   }
1739   return rc;
1740 }
1741 
1742 
1743 
SetKnot(int dir,int knot_index,double knot_value)1744 bool ON_NurbsCage::SetKnot(
1745       int dir,
1746       int knot_index,
1747       double knot_value
1748       )
1749 {
1750   bool rc;
1751 
1752   // Validate input so invalid input does not crash Rhino.
1753   // Expert programmers who want to write fast code can directly
1754   // access the m_knot[] arrays.
1755   if (    dir >= 0 && dir < 3
1756        && 0 != m_knot[dir]
1757        && knot_index >= 0
1758        && knot_index < m_order[dir]+m_cv_count[dir]-2
1759      )
1760   {
1761     m_knot[dir][knot_index] = knot_value;
1762     rc = true;
1763   }
1764   else
1765   {
1766     ON_ERROR("ON_NurbsCage::SetKnot - invalid input parameters");
1767     rc = false;
1768   }
1769   return rc;
1770 }
1771 
Knot(int dir,int knot_index) const1772 double ON_NurbsCage::Knot(
1773       int dir,
1774       int knot_index
1775       ) const
1776 {
1777   double knot_value;
1778 
1779   // Validate input so invalid input does not crash Rhino.
1780   // Expert programmers who want to write fast code can directly
1781   // access the m_knot[] arrays.
1782   if (    dir >= 0 && dir < 3
1783        && 0 != m_knot[dir]
1784        && knot_index >= 0
1785        && knot_index < m_order[dir]+m_cv_count[dir]-2
1786      )
1787   {
1788     knot_value = m_knot[dir][knot_index];
1789   }
1790   else
1791   {
1792     ON_ERROR("ON_NurbsCage::Knot - invalid input parameters");
1793     knot_value = ON_UNSET_VALUE;
1794   }
1795   return knot_value;
1796 }
1797 
ZeroCVs()1798 bool ON_NurbsCage::ZeroCVs()
1799 {
1800   // zeros control vertices and, if rational, sets weights to 1
1801   bool rc = false;
1802   int i,j,k;
1803   if ( m_cv ) {
1804     if ( m_cv_capacity > 0 ) {
1805       memset( m_cv, 0, m_cv_capacity*sizeof(*m_cv) );
1806       if ( m_is_rat ) {
1807         for ( i = 0; i < m_order[0]; i++ ) {
1808           for ( j = 0; j < m_order[1]; j++ ) {
1809             for ( k = 0; k < m_order[2]; k++ ) {
1810               SetWeight( i,j,k, 1.0 );
1811             }
1812           }
1813         }
1814       }
1815       rc = true;
1816     }
1817     else {
1818       double* cv;
1819       int s = CVSize()*sizeof(*cv);
1820       for ( i = 0; i < m_order[0]; i++ ) {
1821         for ( j = 0; j < m_order[1]; j++ ) {
1822           for ( k = 0; k < m_order[2]; k++ ) {
1823             cv = CV(i,j,k);
1824             memset(cv,0,s);
1825             if ( m_is_rat )
1826               cv[m_dim] = 1.0;
1827           }
1828         }
1829       }
1830       rc = (i>0) ? true : false;
1831     }
1832   }
1833   return rc;
1834 }
1835 
MakeRational()1836 bool ON_NurbsCage::MakeRational()
1837 {
1838   if ( !IsRational() )
1839   {
1840     const int dim = Dimension();
1841     if ( m_cv_count[0] > 0 && m_cv_count[1] > 0 && m_cv_count[2] > 0 && dim > 0 )
1842     {
1843       int i,j,k;
1844       if ( m_cv_stride[0] <= dim || m_cv_stride[1] <= dim || m_cv_stride[2] <= dim )
1845       {
1846         // there's not room for the weight in the existing m_cv array - adjust the strides
1847         double* new_cv = (double*)onmalloc(m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*(dim+1)*sizeof(*new_cv));
1848         double* cv1 = new_cv;
1849         const int sizeofoldcv = dim*sizeof(*cv1);
1850         for (i = 0; i < m_cv_count[0]; i++)
1851         {
1852           for(j = 0; j < m_cv_count[1]; j++)
1853           {
1854             for(k = 0; k < m_cv_count[2]; k++)
1855             {
1856               memcpy(cv1,CV(i,j,k),sizeofoldcv);
1857               cv1 += dim;
1858               *cv1++ = 1.0;
1859             }
1860           }
1861         }
1862         m_is_rat = 1;
1863         ReserveCVCapacity(m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*(dim+1));
1864         memcpy(m_cv,new_cv,m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*(dim+1)*sizeof(*m_cv));
1865         onfree(new_cv);
1866         m_cv_stride[2] = dim+1;
1867         m_cv_stride[1] = m_cv_stride[2]*m_cv_count[2];
1868         m_cv_stride[0] = m_cv_stride[1]*m_cv_count[1];
1869       }
1870       else
1871       {
1872         // there's room for the weight in the existing m_cv array
1873         for (i = 0; i < m_cv_count[0]; i++)
1874         {
1875           for(j = 0; j < m_cv_count[1]; j++)
1876           {
1877             for(k = 0; k < m_cv_count[2]; k++)
1878             {
1879               CV(i,j,k)[dim] = 1.0;
1880             }
1881           }
1882         }
1883         m_is_rat = 1;
1884       }
1885     }
1886   }
1887   return IsRational();
1888 }
1889 
MakeNonRational()1890 bool ON_NurbsCage::MakeNonRational()
1891 {
1892   if ( IsRational() && m_dim > 0 )
1893   {
1894     int i,j,k,n;
1895     double* cv;
1896     double w;
1897 
1898     for (i = 0; i < m_cv_count[0]; i++)
1899     for (j = 0; j < m_cv_count[1]; j++)
1900     for (k = 0; k < m_cv_count[2]; k++)
1901     {
1902       cv = CV(i,j,k);
1903       w = cv[m_dim];
1904       if ( w != 1.0 && w != 0.0 )
1905       {
1906         w = 1.0/w;
1907         n = m_dim;
1908         while(n--)
1909         {
1910           *cv++ *= w;
1911         }
1912         *cv = 1.0;
1913       }
1914     }
1915 
1916     m_is_rat = 0;
1917   }
1918   return ( IsRational() ) ? false : true;
1919 }
1920 
1921 /////////////////////////////////////////////////////////////////
1922 // Tools for managing CV and knot memory
ReserveCVCapacity(int capacity)1923 bool ON_NurbsCage::ReserveCVCapacity(
1924   int capacity// number of doubles to reserve
1925   )
1926 {
1927   if ( capacity > 0 && m_cv_capacity < capacity )
1928   {
1929     if ( m_cv )
1930     {
1931       if ( m_cv_capacity )
1932       {
1933         m_cv = (double*)onrealloc( m_cv, capacity*sizeof(*m_cv) );
1934         m_cv_capacity = (m_cv) ? capacity : 0;
1935       }
1936       // else user supplied m_cv[] array
1937     }
1938     else
1939     {
1940       m_cv = (double*)onmalloc( capacity*sizeof(*m_cv) );
1941       m_cv_capacity = (m_cv) ? capacity : 0;
1942     }
1943   }
1944   return ( m_cv ) ? true : false;
1945 }
1946 
ReserveKnotCapacity(int dir,int knot_capacity)1947 bool ON_NurbsCage::ReserveKnotCapacity(
1948   int dir,
1949   int knot_capacity
1950   )
1951 {
1952   bool rc = false;
1953   if ( dir >= 0 && dir <= 2 && knot_capacity > 0 )
1954   {
1955     if ( m_knot_capacity[dir] < knot_capacity )
1956     {
1957       if ( m_knot[dir] )
1958       {
1959         if( m_knot_capacity[dir] )
1960         {
1961           m_knot[dir] = (double*)onrealloc(m_knot[dir],knot_capacity*sizeof(m_knot[dir][0]));
1962           m_knot_capacity[dir] = m_knot[dir] ? knot_capacity : 0;
1963         }
1964         // else user supplied m_knot[dir] array.
1965       }
1966       else
1967       {
1968         m_knot[dir] = (double*)onmalloc(knot_capacity*sizeof(m_knot[dir][0]));
1969         m_knot_capacity[dir] = m_knot[dir] ? knot_capacity : 0;
1970       }
1971     }
1972     rc = m_knot[dir] != 0;
1973   }
1974   return rc;
1975 }
1976 
1977 
1978 
IsSingular(int) const1979 bool ON_NurbsCage::IsSingular(		 // true if surface side is collapsed to a point
1980        int //side														 // side of parameter space to test
1981 																			// 0 = south, 1 = east, 2 = north, 3 = west, 4 = bottom, 5 =top
1982 				) const
1983 {
1984   ON_ERROR("TODO: fill in ON_NurbsCage::IsSingular\n");
1985   return false;
1986 }
1987 
ON_GetCageXform(const ON_NurbsCage & cage,ON_Xform & cage_xform)1988 bool ON_GetCageXform( const ON_NurbsCage& cage, ON_Xform& cage_xform )
1989 {
1990   bool rc = false;
1991   cage_xform.Identity();
1992   if ( cage.IsValid() )
1993   {
1994     ON_3dPoint P000, P100, P010, P001;
1995     if ( !cage.GetCV(0,0,0,P000) )
1996       return false;
1997     if ( !cage.GetCV(cage.CVCount(0)-1,0,0,P100))
1998       return false;
1999     if (!cage.GetCV(0,cage.CVCount(1)-1,0,P010))
2000       return false;
2001     if (!cage.GetCV(0,0,cage.CVCount(2)-1,P001))
2002       return false;
2003 
2004     ON_3dVector X0 = P100 - P000;
2005     ON_3dVector Y0 = P010 - P000;
2006     ON_3dVector Z0 = P001 - P000;
2007 
2008     double dx0 = X0.Length();
2009     double dy0 = Y0.Length();
2010     double dz0 = Z0.Length();
2011 
2012     ON_Interval d0 = cage.Domain(0);
2013     ON_Interval d1 = cage.Domain(1);
2014     ON_Interval d2 = cage.Domain(2);
2015 
2016     X0.Unitize();
2017     Y0.Unitize();
2018     Z0.Unitize();
2019 
2020     ON_Xform x1;
2021     x1.Rotation(
2022       P000, X0, Y0, Z0,
2023       ON_origin, ON_xaxis, ON_yaxis, ON_zaxis
2024       );
2025 
2026     ON_Xform x2;
2027     x2.Scale( d0.Length()/dx0, d1.Length()/dy0, d2.Length()/dz0 );
2028 
2029     ON_Xform x3;
2030     x3.Translation( d0[0],d1[0],d2[0]);
2031 
2032 
2033     cage_xform = x3*(x2*x1);
2034     rc = true;
2035   }
2036   return rc;
2037 }
2038 
ON_CageMorph()2039 ON_CageMorph::ON_CageMorph()
2040 {
2041   m_control = 0;
2042 }
2043 
~ON_CageMorph()2044 ON_CageMorph::~ON_CageMorph()
2045 {
2046   m_control = 0;
2047 }
2048 
IsIdentity(const ON_BoundingBox & bbox) const2049 bool ON_MorphControl::IsIdentity( const ON_BoundingBox& bbox ) const
2050 {
2051   int i, count = m_localizers.Count();
2052   bool rc = (count > 0);
2053   for (i = 0; i < count && rc; i++ )
2054   {
2055     rc = m_localizers[i].IsZero(bbox);
2056   }
2057   return rc;
2058 }
2059 
IsIdentity(const ON_BoundingBox & bbox) const2060 bool ON_CageMorph::IsIdentity( const ON_BoundingBox& bbox ) const
2061 {
2062   return m_control ? m_control->IsIdentity(bbox) : true;
2063 }
2064 
ON_MorphControl()2065 ON_MorphControl::ON_MorphControl()
2066                 : m_varient(0),
2067                   m_nurbs_cage0(1.0)
2068 {
2069   m_sporh_tolerance          = 0.0;
2070   m_sporh_bQuickPreview      = false;
2071   m_sporh_bPreserveStructure = false;
2072 }
2073 
2074 
~ON_MorphControl()2075 ON_MorphControl::~ON_MorphControl()
2076 {
2077 }
2078 
Destroy()2079 void ON_MorphControl::Destroy()
2080 {
2081   m_varient = 0;
2082   m_nurbs_cage0.Identity();
2083   m_nurbs_curve0.Destroy();
2084   m_nurbs_curve.Destroy();
2085   m_nurbs_curve_domain.Destroy();
2086   m_nurbs_surface0.Destroy();
2087   m_nurbs_surface.Destroy();
2088   m_nurbs_surface_domain[0].Destroy();
2089   m_nurbs_surface_domain[1].Destroy();
2090   m_nurbs_cage.Destroy();
2091   m_captive_id.Empty();
2092   m_localizers.Destroy();
2093   m_sporh_tolerance = 0.0;
2094   m_sporh_bQuickPreview = false;
2095   m_sporh_bPreserveStructure = false;
2096 }
2097 
2098 
MemoryRelocate()2099 void ON_MorphControl::MemoryRelocate()
2100 {
2101   m_nurbs_curve0.MemoryRelocate();
2102   m_nurbs_curve.MemoryRelocate();
2103   m_nurbs_surface0.MemoryRelocate();
2104   m_nurbs_surface.MemoryRelocate();
2105   m_nurbs_cage.MemoryRelocate();
2106   ON_Geometry::MemoryRelocate();
2107 }
2108 
IsValid(ON_TextLog * text_log) const2109 ON_BOOL32 ON_MorphControl::IsValid( ON_TextLog* text_log ) const
2110 {
2111   ON_BOOL32 rc = false;
2112   switch(m_varient)
2113   {
2114   case 1:
2115     rc = m_nurbs_curve0.IsValid(text_log);
2116     if (rc)
2117       rc = m_nurbs_curve.IsValid(text_log);
2118     break;
2119 
2120   case 2:
2121     rc = m_nurbs_surface0.IsValid(text_log);
2122     if (rc)
2123       rc = m_nurbs_surface.IsValid(text_log);
2124     break;
2125 
2126   case 3:
2127     rc = m_nurbs_cage.IsValid(text_log);
2128     break;
2129 
2130   default:
2131     rc = false;
2132     if ( text_log )
2133     {
2134       text_log->Print("m_varient = %d - should be 1, 2, or 3\n",m_varient);
2135     }
2136     break;
2137   }
2138   return rc;
2139 }
2140 
Dump(ON_TextLog & text_log) const2141 void ON_MorphControl::Dump( ON_TextLog& text_log ) const
2142 {
2143   text_log.Print("Varient: %d\n",m_varient);
2144   text_log.Print("Control object:\n");
2145   text_log.PushIndent();
2146   switch(m_varient)
2147   {
2148   case 1:
2149     m_nurbs_curve0.Dump(text_log);
2150     m_nurbs_curve.Dump(text_log);
2151     break;
2152   case 2:
2153     m_nurbs_surface0.Dump(text_log);
2154     m_nurbs_surface.Dump(text_log);
2155     break;
2156   case 3:
2157     text_log.Print(m_nurbs_cage0);
2158     m_nurbs_cage.Dump(text_log);
2159     break;
2160   }
2161   text_log.PopIndent();
2162 }
2163 
SizeOf() const2164 unsigned int ON_MorphControl::SizeOf() const
2165 {
2166   unsigned int sz = sizeof(*this)
2167                   - 2*sizeof(ON_NurbsCurve)
2168                   - 2*sizeof(ON_NurbsSurface)
2169                   - sizeof(m_nurbs_cage);
2170   sz += m_nurbs_curve0.SizeOf();
2171   sz += m_nurbs_curve.SizeOf();
2172   sz += m_nurbs_surface0.SizeOf();
2173   sz += m_nurbs_surface.SizeOf();
2174   sz += m_nurbs_cage.SizeOf();
2175   sz += m_localizers.SizeOfArray();
2176 
2177   return sz;
2178 }
2179 
2180 
ObjectType() const2181 ON::object_type ON_MorphControl::ObjectType() const
2182 {
2183   return ON::morph_control_object;
2184 }
2185 
DestroyRuntimeCache(bool bDelete)2186 void ON_MorphControl::DestroyRuntimeCache( bool bDelete )
2187 {
2188   m_nurbs_curve.DestroyRuntimeCache(bDelete);
2189   m_nurbs_surface.DestroyRuntimeCache(bDelete);
2190   m_nurbs_cage.DestroyRuntimeCache(bDelete);
2191 }
2192 
Dimension() const2193 int ON_MorphControl::Dimension() const
2194 {
2195   int dim = 0;
2196   switch(m_varient)
2197   {
2198   case 1:
2199     dim = m_nurbs_curve.Dimension();
2200     break;
2201   case 2:
2202     dim = m_nurbs_surface.Dimension();
2203     break;
2204   case 3:
2205     dim = m_nurbs_cage.Dimension();
2206     break;
2207   }
2208   return dim;
2209 }
2210 
GetBBox(double * boxmin,double * boxmax,int bGrowBox) const2211 ON_BOOL32 ON_MorphControl::GetBBox(
2212         double* boxmin,
2213         double* boxmax,
2214         int bGrowBox
2215         ) const
2216 {
2217   ON_BOOL32 rc = false;
2218   switch(m_varient)
2219   {
2220   case 1:
2221     rc = m_nurbs_curve.GetBBox(boxmin,boxmax,bGrowBox);
2222     break;
2223   case 2:
2224     rc = m_nurbs_surface.GetBBox(boxmin,boxmax,bGrowBox);
2225     break;
2226   case 3:
2227     rc = m_nurbs_cage.GetBBox(boxmin,boxmax,bGrowBox);
2228     break;
2229   }
2230   return rc;
2231 }
2232 
GetTightBoundingBox(ON_BoundingBox & tight_bbox,int bGrowBox,const ON_Xform *) const2233 bool ON_MorphControl::GetTightBoundingBox(
2234 		ON_BoundingBox& tight_bbox,
2235     int bGrowBox,
2236 		const ON_Xform*
2237     ) const
2238 {
2239   bool rc = false;
2240   switch(m_varient)
2241   {
2242   case 1:
2243     rc = m_nurbs_curve.GetTightBoundingBox(tight_bbox,bGrowBox);
2244     break;
2245   case 2:
2246     rc = m_nurbs_surface.GetTightBoundingBox(tight_bbox,bGrowBox);
2247     break;
2248   case 3:
2249     rc = m_nurbs_cage.GetTightBoundingBox(tight_bbox,bGrowBox);
2250     break;
2251   }
2252   return rc;
2253 }
2254 
ClearBoundingBox()2255 void ON_MorphControl::ClearBoundingBox()
2256 {
2257 }
2258 
Transform(const ON_Xform & xform)2259 ON_BOOL32 ON_MorphControl::Transform(
2260         const ON_Xform& xform
2261         )
2262 {
2263   ON_BOOL32 rc = false;
2264 
2265   switch(m_varient)
2266   {
2267   case 1:
2268     rc = m_nurbs_curve.Transform(xform);
2269     break;
2270 
2271   case 2:
2272     rc = m_nurbs_surface.Transform(xform);
2273     break;
2274 
2275   case 3:
2276     rc = m_nurbs_cage.Transform(xform);
2277     break;
2278   }
2279 
2280   return rc;
2281 }
2282 
HasBrepForm() const2283 ON_BOOL32 ON_MorphControl::HasBrepForm() const
2284 {
2285   ON_BOOL32 rc = false;
2286 
2287   switch(m_varient)
2288   {
2289   case 1:
2290     rc = m_nurbs_curve.HasBrepForm();
2291     break;
2292 
2293   case 2:
2294     rc = m_nurbs_surface.HasBrepForm();
2295     break;
2296 
2297   case 3:
2298     rc = m_nurbs_cage.HasBrepForm();
2299     break;
2300   }
2301 
2302   return rc;
2303 }
2304 
BrepForm(ON_Brep * brep) const2305 ON_Brep* ON_MorphControl::BrepForm( ON_Brep* brep ) const
2306 {
2307   switch(m_varient)
2308   {
2309   case 1:
2310     brep = m_nurbs_curve.BrepForm(brep);
2311     break;
2312 
2313   case 2:
2314     brep = m_nurbs_surface.BrepForm(brep);
2315     break;
2316 
2317   case 3:
2318     brep = m_nurbs_cage.BrepForm(brep);
2319     break;
2320 
2321   default:
2322     brep = 0;
2323     break;
2324   }
2325 
2326   return brep;
2327 }
2328 
2329 
IsRational() const2330 bool ON_MorphControl::IsRational() const
2331 {
2332   bool rc = false;
2333   switch(m_varient)
2334   {
2335   case 1:
2336     rc = m_nurbs_curve.IsRational();
2337     break;
2338   case 2:
2339     rc = m_nurbs_surface.IsRational();
2340     break;
2341   case 3:
2342     rc = m_nurbs_cage.IsRational();
2343     break;
2344   }
2345   return rc;
2346 }
2347 
MakeRational()2348 bool ON_MorphControl::MakeRational()
2349 {
2350   bool rc = false;
2351   switch(m_varient)
2352   {
2353   case 1:
2354     rc = m_nurbs_curve.MakeRational();
2355     break;
2356   case 2:
2357     rc = m_nurbs_surface.MakeRational();
2358     break;
2359   case 3:
2360     rc = m_nurbs_cage.MakeRational();
2361     break;
2362   }
2363   return rc;
2364 }
2365 
MakeNonRational()2366 bool ON_MorphControl::MakeNonRational()
2367 {
2368   bool rc = false;
2369   switch(m_varient)
2370   {
2371   case 1:
2372     rc = m_nurbs_curve.MakeNonRational();
2373     break;
2374   case 2:
2375     rc = m_nurbs_surface.MakeNonRational();
2376     break;
2377   case 3:
2378     rc = m_nurbs_cage.MakeNonRational();
2379     break;
2380   }
2381   return rc;
2382 }
2383 
CVCount() const2384 int ON_MorphControl::CVCount() const
2385 {
2386   int rc = 0;
2387   switch(m_varient)
2388   {
2389   case 1:
2390     rc = m_nurbs_curve.CVCount();
2391     break;
2392   case 2:
2393     rc = m_nurbs_surface.CVCount();
2394     break;
2395   case 3:
2396     rc = m_nurbs_cage.CVCount();
2397     break;
2398   }
2399   return rc;
2400 }
2401 
CVCount(int dir) const2402 int ON_MorphControl::CVCount(int dir) const
2403 {
2404   int rc = 0;
2405   switch(m_varient)
2406   {
2407   case 1:
2408     rc = (0==dir) ? m_nurbs_curve.CVCount() : 0;
2409     break;
2410   case 2:
2411     rc = m_nurbs_surface.CVCount(dir);
2412     break;
2413   case 3:
2414     rc = m_nurbs_cage.CVCount(dir);
2415     break;
2416   }
2417   return rc;
2418 }
2419 
Order(int dir) const2420 int ON_MorphControl::Order(int dir) const
2421 {
2422   int rc = 0;
2423   switch(m_varient)
2424   {
2425   case 1:
2426     rc = (0==dir) ? m_nurbs_curve.Order() : 0;
2427     break;
2428   case 2:
2429     rc = m_nurbs_surface.Order(dir);
2430     break;
2431   case 3:
2432     rc = m_nurbs_cage.Order(dir);
2433     break;
2434   }
2435   return rc;
2436 }
2437 
MaxCVIndex() const2438 ON_3dex ON_MorphControl::MaxCVIndex() const
2439 {
2440   ON_3dex maxdex;
2441   maxdex.i = maxdex.j = maxdex.k = 0;
2442   switch(m_varient)
2443   {
2444   case 1:
2445     maxdex.i = m_nurbs_curve.CVCount();
2446     maxdex.j = maxdex.k = 1;
2447     break;
2448   case 2:
2449     maxdex.i = m_nurbs_surface.CVCount(0);
2450     maxdex.j = m_nurbs_surface.CVCount(1);
2451     maxdex.k = 1;
2452     break;
2453   case 3:
2454     maxdex.i = m_nurbs_cage.CVCount(0);
2455     maxdex.j = m_nurbs_cage.CVCount(1);
2456     maxdex.k = m_nurbs_cage.CVCount(2);
2457     break;
2458   }
2459   return maxdex;
2460 }
2461 
Knot(int dir) const2462 const double* ON_MorphControl::Knot(int dir) const
2463 {
2464   const double* knot = 0;
2465 
2466   switch(m_varient)
2467   {
2468   case 1:
2469     knot = (0 == dir) ? m_nurbs_curve.m_knot : 0;
2470     break;
2471   case 2:
2472     knot = (0 == dir || 1 == dir) ? m_nurbs_surface.m_knot[dir] : 0;
2473     break;
2474   case 3:
2475     knot = (0 <= dir && dir <= 2) ? m_nurbs_cage.m_knot[dir] : 0;
2476     break;
2477   }
2478 
2479   return knot;
2480 }
2481 
CV(ON_3dex ijk) const2482 const double* ON_MorphControl::CV(ON_3dex ijk) const
2483 {
2484   const double* cv = 0;
2485   switch(m_varient)
2486   {
2487   case 1:
2488     cv = (0 == ijk.j && 0 == ijk.k) ? m_nurbs_curve.CV(ijk.i) : 0;
2489     break;
2490   case 2:
2491     cv = (0 == ijk.k) ? m_nurbs_surface.CV(ijk.i,ijk.j) : 0;
2492     break;
2493   case 3:
2494     cv = m_nurbs_cage.CV(ijk.i,ijk.j,ijk.k);
2495     break;
2496   }
2497   return cv;
2498 }
2499 
Weight(ON_3dex ijk) const2500 double ON_MorphControl::Weight(ON_3dex ijk) const
2501 {
2502   double w = 1.0;
2503 
2504   switch(m_varient)
2505   {
2506   case 1:
2507     w = (0 == ijk.j && 0 == ijk.k) ? m_nurbs_curve.Weight(ijk.i) : 1.0;
2508     break;
2509   case 2:
2510     w = (0 == ijk.k) ? m_nurbs_surface.Weight(ijk.i,ijk.j) : 1.0;
2511     break;
2512   case 3:
2513     w = m_nurbs_cage.Weight(ijk.i,ijk.j,ijk.k);
2514     break;
2515   }
2516 
2517   return w;
2518 }
2519 
GetCageMorph(ON_CageMorph & cage_morph) const2520 bool ON_MorphControl::GetCageMorph(ON_CageMorph& cage_morph) const
2521 {
2522   cage_morph.m_control = this;
2523   cage_morph.SetPreserveStructure(m_sporh_bPreserveStructure);
2524   cage_morph.SetQuickPreview(m_sporh_bQuickPreview);
2525   cage_morph.SetTolerance(m_sporh_tolerance);
2526   return true;
2527 }
2528 
Read(ON_BinaryArchive & archive)2529 ON_BOOL32 ON_MorphControl::Read( ON_BinaryArchive& archive )
2530 {
2531   Destroy();
2532   int major_version = 0;
2533   int minor_version = 0;
2534   bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,
2535                                       &major_version,
2536                                       &minor_version);
2537   while(rc)
2538   {
2539     if ( 1 == major_version )
2540     {
2541       m_varient = 3;
2542       if (rc)
2543         rc = m_nurbs_cage.Read(archive)?true:false;
2544       if (rc)
2545         rc = m_captive_id.Read(archive);
2546       if (rc)
2547         rc = archive.ReadXform(m_nurbs_cage0);
2548     }
2549     else if ( 2 == major_version )
2550     {
2551       rc = archive.ReadInt(&m_varient);
2552       if (!rc) break;
2553 
2554       int mjv = 0;
2555       int mnv = 0;
2556       rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&mjv,&mnv);
2557       if (!rc) break;
2558       rc = (1 == mjv);
2559       if (rc)
2560       {
2561         switch(m_varient)
2562         {
2563         case 1:
2564           rc = m_nurbs_curve0.Read(archive)?true:false;
2565           if (rc)
2566             m_nurbs_curve_domain = m_nurbs_curve0.Domain();
2567           break;
2568         case 2:
2569           rc = m_nurbs_surface0.Read(archive)?true:false;
2570           if (rc)
2571           {
2572             m_nurbs_surface_domain[0] = m_nurbs_surface0.Domain(0);
2573             m_nurbs_surface_domain[1] = m_nurbs_surface0.Domain(1);
2574           }
2575           break;
2576         case 3:
2577           rc = archive.ReadXform(m_nurbs_cage0);
2578           break;
2579         }
2580       }
2581       if ( !archive.EndRead3dmChunk() )
2582         rc = false;
2583 
2584       if(!rc)
2585         break;
2586 
2587       mjv = 0;
2588       mnv = 0;
2589       rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&mjv,&mnv);
2590       if (!rc) break;
2591       rc = (1 == mjv);
2592       if (rc)
2593       {
2594         switch(m_varient)
2595         {
2596         case 1:
2597           rc = m_nurbs_curve.Read(archive)?true:false;
2598           break;
2599         case 2:
2600           rc = m_nurbs_surface.Read(archive)?true:false;
2601           break;
2602         case 3:
2603           rc = m_nurbs_cage.Read(archive)?true:false;
2604           break;
2605         }
2606       }
2607       if ( !archive.EndRead3dmChunk() )
2608         rc = false;
2609 
2610       // captive ids
2611       rc = m_captive_id.Read(archive);
2612       if (!rc)
2613         break;
2614 
2615       // localizers
2616       mjv = 0;
2617       mnv = 0;
2618       rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&mjv,&mnv);
2619       if (!rc)
2620         break;
2621       int i, count = 0;
2622       rc = (1 == mjv);
2623       if (rc)
2624         rc = archive.ReadInt(&count);
2625       if (rc)
2626         m_localizers.Reserve(count);
2627       for ( i = 0; i < count && rc; i++ )
2628       {
2629         m_localizers.AppendNew();
2630         rc = m_localizers[i].Read(archive);
2631       }
2632       if ( !archive.EndRead3dmChunk() )
2633         rc = false;
2634       if ( !rc)
2635         break;
2636 
2637       if ( minor_version >= 1 )
2638       {
2639         rc = archive.ReadDouble(&m_sporh_tolerance);
2640         if (!rc)
2641           break;
2642         rc = archive.ReadBool(&m_sporh_bQuickPreview);
2643         if (!rc)
2644           break;
2645         rc = archive.ReadBool(&m_sporh_bPreserveStructure);
2646         if (!rc)
2647           break;
2648       }
2649     }
2650     else
2651     {
2652       rc = false;
2653     }
2654 
2655     if ( !archive.EndRead3dmChunk() )
2656       rc = false;
2657     break;
2658   }
2659 
2660   return rc;
2661 }
2662 
Write(ON_BinaryArchive & archive) const2663 ON_BOOL32 ON_MorphControl::Write( ON_BinaryArchive& archive ) const
2664 {
2665   bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,2,1);
2666   if (!rc)
2667     return false;
2668 
2669   while(rc)
2670   {
2671     rc = archive.WriteInt(m_varient);
2672     if (!rc) break;
2673 
2674     // control start location
2675     rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
2676     if (!rc) break;
2677     switch(m_varient)
2678     {
2679     case 1:
2680       rc = m_nurbs_curve0.Write(archive)?true:false;
2681       break;
2682     case 2:
2683       rc = m_nurbs_surface0.Write(archive)?true:false;
2684       break;
2685     case 3:
2686       rc = archive.WriteXform(m_nurbs_cage0);
2687       break;
2688     }
2689     if ( !archive.EndWrite3dmChunk() )
2690       rc = false;
2691 
2692     if(!rc)
2693       break;
2694 
2695     // control end location
2696     rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
2697     if (!rc) break;
2698     switch(m_varient)
2699     {
2700     case 1:
2701       rc = m_nurbs_curve.Write(archive)?true:false;
2702       break;
2703     case 2:
2704       rc = m_nurbs_surface.Write(archive)?true:false;
2705       break;
2706     case 3:
2707       rc = m_nurbs_cage.Write(archive)?true:false;
2708       break;
2709     }
2710     if ( !archive.EndWrite3dmChunk() )
2711       rc = false;
2712 
2713     if ( !rc)
2714       break;
2715 
2716     // captive ids
2717     rc = m_captive_id.Write(archive);
2718     if (!rc)
2719       break;
2720 
2721     // localizers
2722     rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
2723     if (!rc)
2724       break;
2725     int i, count = m_localizers.Count();
2726     rc = archive.WriteInt(count);
2727     for ( i = 0; i < count && rc; i++ )
2728     {
2729       rc = m_localizers[i].Write(archive);
2730     }
2731     if ( !archive.EndWrite3dmChunk() )
2732       rc = false;
2733     if ( !rc)
2734       break;
2735 
2736     // 2.1 fields
2737     rc = archive.WriteDouble(m_sporh_tolerance);
2738     if (!rc)
2739       break;
2740     rc = archive.WriteBool(m_sporh_bQuickPreview);
2741     if (!rc)
2742       break;
2743     rc = archive.WriteBool(m_sporh_bPreserveStructure);
2744     if (!rc)
2745       break;
2746 
2747     break;
2748   }
2749 
2750   if ( !archive.EndWrite3dmChunk() )
2751     rc = false;
2752 
2753   return rc;
2754 }
2755 
AddControlLocalizer(double support_distance,double falloff_distance)2756 bool ON_MorphControl::AddControlLocalizer(
2757   double support_distance,
2758   double falloff_distance
2759   )
2760 {
2761   bool rc = (support_distance >= 0.0 && falloff_distance > 0.0 );
2762   if (rc)
2763   {
2764     switch(m_varient)
2765     {
2766     case 1:
2767     case 2:
2768       {
2769         ON_Localizer& localizer = m_localizers.AppendNew();
2770         localizer.m_type = ON_Localizer::distance_type;
2771         localizer.m_d.Set(support_distance+falloff_distance,support_distance);
2772         rc = true;
2773       }
2774       break;
2775 
2776     case 3:
2777       {
2778         ON_Xform xform = m_nurbs_cage0;
2779         xform.Invert();
2780         ON_Interval d[3];
2781         d[0] = m_nurbs_cage.Domain(0);
2782         d[1] = m_nurbs_cage.Domain(1);
2783         d[2] = m_nurbs_cage.Domain(2);
2784 
2785         ON_SimpleArray<ON_Plane> planes(6);
2786 
2787         ON_3dPoint C(d[0].ParameterAt(0.5),d[1].ParameterAt(0.5),d[2].ParameterAt(0.5));
2788         ON_3dPoint P;
2789         ON_3dVector N;
2790         int i;
2791         double det = (xform.Determinant() < 0.0) ? -1.0 : 1.0;
2792         for ( i = 0; i < 3; i++ )
2793         {
2794           P = C;
2795           N.Zero();
2796 
2797           N[i] = -det;
2798           P[i] = d[i][0];
2799           ON_Plane& plane0 = planes.AppendNew();
2800           plane0.CreateFromNormal(P,N);
2801           plane0.Transform(xform);
2802 
2803           P[i] = d[i][1];
2804           N[i] = det;
2805           ON_Plane& plane1 = planes.AppendNew();
2806           plane1.CreateFromNormal(P,N);
2807           plane1.Transform(xform);
2808         }
2809 
2810         rc = AddConvexPolygonLocalizer(planes,support_distance,falloff_distance);
2811       }
2812       break;
2813 
2814     default:
2815       rc = false;
2816       break;
2817     }
2818   }
2819   return rc;
2820 }
2821 
AddSphereLocalizer(ON_3dPoint center,double support_distance,double falloff_distance)2822 bool ON_MorphControl::AddSphereLocalizer(
2823   ON_3dPoint center,
2824   double support_distance,
2825   double falloff_distance
2826   )
2827 {
2828   bool rc = (center.IsValid() && support_distance >= 0.0 && falloff_distance > 0.0 );
2829   if (rc)
2830   {
2831     ON_Localizer& localizer = m_localizers.AppendNew();
2832     rc = localizer.CreateSphereLocalizer(
2833                   center,
2834                   support_distance+falloff_distance,
2835                   support_distance);
2836   }
2837   return rc;
2838 }
2839 
AddCylinderLocalizer(ON_Line axis,double support_distance,double falloff_distance)2840 bool ON_MorphControl::AddCylinderLocalizer(
2841   ON_Line axis,
2842   double support_distance,
2843   double falloff_distance
2844   )
2845 {
2846   bool rc = (axis.IsValid() && support_distance >= 0.0 && falloff_distance > 0.0 );
2847   if (rc)
2848   {
2849     ON_Localizer& localizer = m_localizers.AppendNew();
2850     rc = localizer.CreateCylinderLocalizer(
2851                   axis.from,axis.Tangent(),
2852                   support_distance+falloff_distance,
2853                   support_distance);
2854   }
2855   return rc;
2856 }
2857 
AddBoxLocalizer(ON_BoundingBox bbox,double support_distance,double falloff_distance)2858 bool ON_MorphControl::AddBoxLocalizer(
2859   ON_BoundingBox bbox,
2860   double support_distance,
2861   double falloff_distance
2862   )
2863 {
2864   ON_SimpleArray<ON_Plane> planes(6);
2865   bool rc = (bbox.IsValid() && support_distance >= 0.0 && falloff_distance > 0.0 );
2866   if (rc)
2867   {
2868     ON_3dPoint C = bbox.Center();
2869     ON_3dVector N;
2870     ON_3dPoint P;
2871     int i;
2872     for ( i = 0; i < 3; i++ )
2873     {
2874       P = C;
2875       N.Zero();
2876       ON_Plane& plane0 = planes.AppendNew();
2877       P[i] = bbox.m_min[i];
2878       N[i] = -1.0;
2879       plane0.CreateFromNormal(P,N);
2880 
2881       ON_Plane& plane1 = planes.AppendNew();
2882       P[i] = bbox.m_max[i];
2883       N[i] = 1.0;
2884       plane1.CreateFromNormal(P,N);
2885     }
2886     rc = AddConvexPolygonLocalizer(planes,support_distance,falloff_distance);
2887   }
2888   return rc;
2889 }
2890 
AddPlaneLocalizer(const ON_Plane & plane,double support_distance,double falloff_distance)2891 bool ON_MorphControl::AddPlaneLocalizer(
2892             const ON_Plane& plane,
2893             double support_distance,
2894             double falloff_distance
2895             )
2896 {
2897   ON_SimpleArray<ON_Plane> planes(1);
2898   planes.Append(plane);
2899   return AddConvexPolygonLocalizer(planes,support_distance,falloff_distance);
2900 }
2901 
AddConvexPolygonLocalizer(const ON_SimpleArray<ON_Plane> & planes,double support_distance,double falloff_distance)2902 bool ON_MorphControl::AddConvexPolygonLocalizer(
2903   const ON_SimpleArray<ON_Plane>& planes,
2904   double support_distance,
2905   double falloff_distance
2906   )
2907 {
2908   int i, count = planes.Count();
2909   bool rc = (support_distance >= 0.0 && falloff_distance > 0.0 );
2910   if (rc)
2911   {
2912     m_localizers.Reserve(m_localizers.Count() + count);
2913     for( i = 0; i < count && rc; i++)
2914     {
2915       const ON_Plane& plane = planes[i];
2916       ON_Localizer& localizer = m_localizers.AppendNew();
2917       rc = localizer.CreatePlaneLocalizer(
2918                     plane.origin,plane.zaxis,
2919                     support_distance+falloff_distance,
2920                     support_distance);
2921     }
2922   }
2923   return rc;
2924 }
2925 
2926