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