Point Cloud Library (PCL)
1.7.1
Main Page
Modules
Namespaces
Classes
surface
include
pcl
surface
3rdparty
opennurbs
opennurbs_fsp.h
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
#if !defined(OPENNURBS_FSP_INC_)
17
#define OPENNURBS_FSP_INC_
18
19
class
ON_CLASS
ON_FixedSizePool
20
{
21
public
:
22
ON_FixedSizePool
();
23
~
ON_FixedSizePool
();
24
25
/*
26
Description:
27
Create a fixed size memory pool.
28
Parameters:
29
sizeof_element - [in]
30
number of bytes in each element. This parameter must be greater than zero.
31
In general, use sizeof(element type). If you pass a "raw" number as
32
sizeof_element, then be certain that it is the right size to insure the
33
fields in your elements will be properly aligned.
34
element_count_estimate - [in] (0 = good default)
35
If you know how many elements you will need, pass that number here.
36
It is better to slightly overestimate than to slightly underestimate.
37
If you do not have a good estimate, then use zero.
38
block_element_capacity - [in] (0 = good default)
39
If block_element_capacity is zero, Create() will calculate a block
40
size that is efficent for most applications. If you are an expert
41
user and want to specify the number of elements per block,
42
then pass the number of elements per block here. When
43
block_element_capacity > 0 and element_count_estimate > 0, the first
44
block will have a capacity of at least element_count_estimate; in this
45
case do not ask for extraordinarly large amounts of contiguous heap.
46
Remarks:
47
You must call Create() on an unused ON_FixedSizePool or call Destroy()
48
before calling create.
49
Returns:
50
True if successful and the pool can be used.
51
*/
52
bool
Create(
53
size_t
sizeof_element,
54
size_t
element_count_estimate,
55
size_t
block_element_capacity
56
);
57
58
/*
59
Returns:
60
Size of the elements in this pool.
61
*/
62
size_t
SizeofElement()
const
;
63
64
/*
65
Returns:
66
A pointer to sizeof_element bytes. The memory is zeroed.
67
*/
68
void
* AllocateElement();
69
70
/*
71
Description:
72
Return an element to the pool.
73
Parameters:
74
p - [in]
75
A pointer returned by AllocateElement().
76
It is critical that p be from this pool and that
77
you return a pointer no more than one time.
78
Remarks:
79
If you find the following remarks confusing, but you really want to use
80
ReturnElement(), then here are some simple guidelines.
81
1) SizeofElement() must be >= 16
82
2) SizeofElement() must be a multiple of 8.
83
3) Do not use FirstElement() and NextElement() to iterate through
84
the pool.
85
86
If 1 to 3 don't work for you, then you need to understand the following
87
information before using ReturnElement().
88
89
ON_FixedMemoryPool uses the first sizeof(void*) bytes of the
90
returned element for bookkeeping purposes. Therefore, if you
91
are going to use ReturnElement(), then SizeofElement() must be
92
at least sizeof(void*). If you are using a platform that requires
93
pointers to be aligned on sizeof(void*) boundaries, then
94
SizeofElement() must be a multiple of sizeof(void*).
95
If you are going to use ReturnElement() and then use FirstElement()
96
and NextElement() to iterate through the list of elements, then you
97
need to set a value in the returned element to indicate that it
98
needs to be skipped during the iteration. This value cannot be
99
located in the fist sizeof(void*) bytes of the element. If the
100
element is a class with a vtable, you cannot call a virtual
101
function on a returned element because the vtable pointer is
102
trashed when ReturnElement() modifies the fist sizeof(void*) bytes.
103
*/
104
void
ReturnElement(
void
* p);
105
106
/*
107
Description:
108
Return all allocated elements to the pool. No heap is freed and
109
the pool remains initialized and ready for AllocateElement()
110
to be called.
111
*/
112
void
ReturnAll();
113
114
/*
115
Description:
116
Destroy the pool and free all the heap. The pool cannot be used again
117
until Create() is called.
118
*/
119
void
Destroy();
120
121
/*
122
Returns:
123
Number of active elements. (Elements that have been returned are not active.)
124
*/
125
size_t
ActiveElementCount()
const
;
126
127
/*
128
Returns:
129
Total number of elements = number of active elements + number of returned elements.
130
*/
131
size_t
TotalElementCount()
const
;
132
133
/*
134
Description:
135
Get the first element when iterating through the list of elements.
136
Parameters:
137
element_index - [in]
138
If you use the version of FirstElement() that has an
139
element_index parameter, then the iteration begins at
140
that element.
141
Example:
142
The loop will iteratate through all the elements returned from
143
AllocateElement(), including any that have be returned to the pool
144
using ReturnElement().
145
146
// iterate through all elements in the pool
147
// This iteration will go through TotalElements() items.
148
for ( void* p = FirstElement(); 0 != p; p = NextElement() )
149
{
150
// If you are not using ReturnElement(), then you may process
151
// "p" immediately. If you have used ReturnElement(), then you
152
// must check some value in p located after the first sizeof(void*)
153
// bytes to see if p is active.
154
if ( p is not active )
155
continue;
156
157
... process p
158
}
159
160
Returns:
161
The first element when iterating through the list of elements.
162
Remarks:
163
FirstElement() and NextElement() will return elements that have
164
been returned to the pool using ReturnElement(). If you use
165
ReturnElement(), then be sure to mark the element so it can be
166
identified and skipped.
167
168
Do not make any calls to FirstBlock() or NextBlock() when using
169
FirstElement() and NextElement() to iteratate through elements.
170
171
If you need iterate through a fixed size pool and another
172
function may also be in the middle of iterating the pool
173
as well, then use ON_FixedSizePoolIterator. In particular,
174
if you have multiple concurrent threads iterating the same
175
fixed size pool, then use ON_FixedSizePoolIterator.
176
*/
177
void
* FirstElement();
178
void
* FirstElement(
size_t
element_index );
179
180
/*
181
Description:
182
Get the next element when iterating through the list of elements.
183
Example:
184
See the FirstElement() documentation.
185
Returns:
186
The next element when iterating through the list of elements.
187
Remarks:
188
FirstElement() and NextElement() will return elements that have
189
been returned to the pool using ReturnElement(). If you use
190
ReturnElement(), then be sure to mark the element so it can be
191
identified and skipped.
192
193
Do not make any calls to FirstBlock() or NextBlock() when using
194
FirstElement() and NextElement() to iteratate through elements.
195
196
If you need iterate through a fixed size pool and another
197
function may also be in the middle of iterating the pool
198
as well, then use ON_FixedSizePoolIterator. In particular,
199
if you have multiple concurrent threads iterating the same
200
fixed size pool, then use ON_FixedSizePoolIterator.
201
*/
202
void
* NextElement();
203
204
/*
205
Description:
206
Get a pointer to the first element in the first block.
207
Parameters:
208
block_element_count - [out] (can be null)
209
If not null, the number of elements allocated from the
210
first block is returned in block_element_count.
211
Note that if you have used ReturnElement(), some
212
of these elemements may have been returned.
213
Example:
214
The loop will iteratate through all the blocks.
215
216
// iterate through all blocks in the pool
217
size_t block_element_count = 0;
218
for ( void* p = FirstBlock(&block_element_count);
219
0 != p;
220
p = NextBlock(&block_element_count)
221
)
222
{
223
ElementType* e = (ElementType*)p;
224
for ( size_t i = 0;
225
i < block_element_count;
226
i++, e = ((const char*)e) + SizeofElement()
227
)
228
{
229
...
230
}
231
}
232
233
Returns:
234
The first block when iterating the list of blocks.
235
Remarks:
236
The heap for a fixed size memory pool is simply a linked
237
list of blocks. FirstBlock() and NextBlock() can be used
238
to iterate through the list of blocks.
239
240
Do not make any calls to FirstElement() or NextElement() when using
241
FirstBlock() and NextBlock() to iteratate through blocks.
242
243
If you need iterate through a fixed size pool and another
244
function may also be in the middle of iterating the pool
245
as well, then use ON_FixedSizePoolIterator. In particular,
246
if you have multiple concurrent threads iterating the same
247
fixed size pool, then use ON_FixedSizePoolIterator.
248
*/
249
void
* FirstBlock(
size_t
* block_element_count );
250
251
/*
252
Description:
253
Get the next block when iterating through the blocks.
254
Parameters:
255
block_element_count - [out] (can be null)
256
If not null, the number of elements allocated from the
257
block is returned in block_element_count. Note that if
258
you have used ReturnElement(), some of these elemements
259
may have been returned.
260
Example:
261
See the FirstBlock() documentation.
262
Returns:
263
The next block when iterating through the blocks.
264
Remarks:
265
Do not make any calls to FirstElement() or NextElement() when using
266
FirstBlock() and NextBlock() to iteratate through blocks.
267
268
If you need iterate through a fixed size pool and another
269
function may also be in the middle of iterating the pool
270
as well, then use ON_FixedSizePoolIterator. In particular,
271
if you have multiple concurrent threads iterating the same
272
fixed size pool, then use ON_FixedSizePoolIterator.
273
*/
274
void
* NextBlock(
size_t
* block_element_count );
275
276
/*
277
Description:
278
Get the i-th elment in the pool.
279
Parameters:
280
element_index - [in]
281
Returns:
282
A pointer to the i-th element. The first element has index = 0
283
and is the element returned by the first call to AllocateElement().
284
The last element has index = ElementCount()-1.
285
If i is out of range, null is returned.
286
Remarks:
287
It is faster to use FirstElement() and NextElement() to iterate
288
through the entire list of elements. This function is relatively
289
efficient when there are a few large blocks in the pool
290
or element_index is small compared to the number of elements
291
in the first few blocks.
292
293
If ReturnElement() is not used or AllocateElement() calls to
294
are made after any use of ReturnElement(), then the i-th
295
element is the one returned by the (i+1)-th call to
296
AllocateElement().
297
*/
298
void
* Element(
size_t
element_index)
const
;
299
300
public
:
301
// Expert user functions below for situations where you
302
// need to specify the heap used for this pool.
303
304
/*
305
Description:
306
Expert user function to specify which heap is used.
307
*/
308
void
SetHeap( ON_MEMORY_POOL* heap );
309
310
/*
311
Description:
312
Expert user function.
313
Returns:
314
Heap used by this pool. A null pointer means the default
315
heap is being used.
316
*/
317
ON_MEMORY_POOL* Heap();
318
319
/*
320
Description:
321
Expert user function to call when the heap used by this pool
322
is no longer valid. This call zeros all fields and does not
323
call any heap functions. After calling EmergencyDestroy(),
324
the destructor will not attempt to free any heap.
325
*/
326
void
EmergencyDestroy();
327
328
private
:
329
friend
class
ON_FixedSizePoolIterator
;
330
331
void
* m_first_block;
332
333
// ReturnElement() adds to the m_al_element stack.
334
// AllocateElement() will use the stack before using m_al_element_array[]
335
void
* m_al_element_stack;
336
337
// used by the iterators
338
void
* m_qwerty_it_block;
339
void
* m_qwerty_it_element;
340
341
void
* m_al_block;
// current element allocation block.
342
// m_al_element_array[] is in m_al_block and has length m_al_count.
343
void
* m_al_element_array;
344
size_t
m_al_count;
345
size_t
m_sizeof_element;
346
size_t
m_block_element_count;
// block element count
347
size_t
m_active_element_count;
// number of active elements
348
size_t
m_total_element_count;
// total number of elements (active + returned)
349
ON_MEMORY_POOL* m_heap;
350
351
private
:
352
// returns capacity of elements in existing block
353
size_t
BlockElementCapacity(
const
void
* block )
const
;
354
355
// returns number of allocated of elements in existing block
356
size_t
BlockElementCount(
const
void
* block )
const
;
357
private
:
358
// prohibit copy construction and operator=.
359
ON_FixedSizePool
(
const
ON_FixedSizePool
&);
360
ON_FixedSizePool
& operator=(
const
ON_FixedSizePool
&);
361
};
362
363
class
ON_CLASS
ON_FixedSizePoolIterator
364
{
365
public
:
366
ON_FixedSizePoolIterator
(
const
class
ON_FixedSizePool
& fsp );
367
368
const
class
ON_FixedSizePool
&
m_fsp
;
369
370
/*
371
Description:
372
Get the first element when iterating through the list of elements.
373
Parameters:
374
element_index - [in]
375
If you use the version of FirstElement() that has an
376
element_index parameter, then the iteration begins at
377
that element.
378
Example:
379
The loop will iteratate through all the elements returned from
380
AllocateElement(), including any that have be returned to the pool
381
using ReturnElement().
382
383
// iterate through all elements in the pool
384
// This iteration will go through TotalElements() items.
385
for ( void* p = FirstElement(); 0 != p; p = NextElement() )
386
{
387
// If you are not using ReturnElement(), then you may process
388
// "p" immediately. If you have used ReturnElement(), then you
389
// must check some value in p located after the first sizeof(void*)
390
// bytes to see if p is active.
391
if ( p is not active )
392
continue;
393
394
... process p
395
}
396
397
Returns:
398
The first element when iterating through the list of elements.
399
Remarks:
400
FirstElement() and NextElement() will return elements that have
401
been returned to the pool using ReturnElement(). If you use
402
ReturnElement(), then be sure to mark the element so it can be
403
identified and skipped.
404
405
Do not make any calls to FirstBlock() or NextBlock() when using
406
FirstElement() and NextElement() to iteratate through elements.
407
*/
408
void
*
FirstElement
();
409
void
*
FirstElement
(
size_t
element_index );
410
411
/*
412
Description:
413
Get the next element when iterating through the list of elements.
414
Example:
415
See the FirstElement() documentation.
416
Returns:
417
The next element when iterating through the list of elements.
418
Remarks:
419
FirstElement() and NextElement() will return elements that have
420
been returned to the pool using ReturnElement(). If you use
421
ReturnElement(), then be sure to mark the element so it can be
422
identified and skipped.
423
424
Do not make any calls to FirstBlock() or NextBlock() when using
425
FirstElement() and NextElement() to iteratate through elements.
426
*/
427
void
*
NextElement
();
428
429
/*
430
Description:
431
Get a pointer to the first element in the first block.
432
Parameters:
433
block_element_count - [out] (can be null)
434
If not null, the number of elements allocated from the
435
first block is returned in block_element_count.
436
Note that if you have used ReturnElement(), some
437
of these elemements may have been returned.
438
Example:
439
The loop will iteratate through all the blocks.
440
441
// iterate through all blocks in the pool
442
size_t block_element_count = 0;
443
for ( void* p = FirstBlock(&block_element_count);
444
0 != p;
445
p = NextBlock(&block_element_count)
446
)
447
{
448
ElementType* e = (ElementType*)p;
449
for ( size_t i = 0;
450
i < block_element_count;
451
i++, e = ((const char*)e) + SizeofElement()
452
)
453
{
454
...
455
}
456
}
457
458
Returns:
459
The first block when iterating the list of blocks.
460
Remarks:
461
The heap for a fixed size memory pool is simply a linked
462
list of blocks. FirstBlock() and NextBlock() can be used
463
to iterate through the list of blocks.
464
465
Do not make any calls to FirstElement() or NextElement() when using
466
FirstBlock() and NextBlock() to iteratate through blocks.
467
*/
468
void
*
FirstBlock
(
size_t
* block_element_count );
469
470
/*
471
Description:
472
Get the next block when iterating through the blocks.
473
Parameters:
474
block_element_count - [out] (can be null)
475
If not null, the number of elements allocated from the
476
block is returned in block_element_count. Note that if
477
you have used ReturnElement(), some of these elemements
478
may have been returned.
479
Example:
480
See the FirstBlock() documentation.
481
Returns:
482
The next block when iterating through the blocks.
483
Remarks:
484
Do not make any calls to FirstElement() or NextElement() when using
485
FirstBlock() and NextBlock() to iteratate through blocks.
486
*/
487
void
*
NextBlock
(
size_t
* block_element_count );
488
489
private
:
490
void
* m_it_block;
491
void
* m_it_element;
492
493
// no implementation (you can use a copy construtor)
494
ON_FixedSizePoolIterator
& operator=(
const
ON_FixedSizePoolIterator
&);
495
};
496
497
498
template
<
class
T>
class
ON_SimpleFixedSizePool
:
private
ON_FixedSizePool
499
{
500
public
:
501
// construction ////////////////////////////////////////////////////////
502
503
ON_SimpleFixedSizePool
();
504
~ON_SimpleFixedSizePool
();
505
506
/*
507
Description:
508
Create a fixed size memory pool.
509
Parameters:
510
element_count_estimate - [in] (0 = good default)
511
If you know how many elements you will need, pass that number here.
512
It is better to slightly overestimate than to slightly underestimate.
513
If you do not have a good estimate, then use zero.
514
block_element_count - [in] (0 = good default)
515
If block_element_count is zero, Create() will calculate a block
516
size that is efficent for most applications. If you are an expert
517
user and want to specify the number of blocks, then pass the number
518
of elements per block here. When block_element_count > 0 and
519
element_count_estimate > 0, the first block will be large enough
520
element_count_estimate*sizeof(T) bytes; in this case do not
521
ask for extraordinarly large amounts of contiguous heap.
522
Remarks:
523
You must call Create() on an unused ON_FixedSizePool or call Destroy()
524
before calling create.
525
Returns:
526
True if successful and the pool can be used.
527
*/
528
bool
Create
(
529
size_t
element_count_estimate,
530
size_t
block_element_count
531
);
532
533
/*
534
Returns:
535
Size of the elements in this pool.
536
*/
537
size_t
SizeofElement
()
const
;
538
539
/*
540
Returns:
541
A pointer to sizeof_element bytes. The memory is zeroed.
542
*/
543
T*
AllocateElement
();
544
545
/*
546
Description:
547
Return an element to the pool.
548
Parameters:
549
p - [in]
550
A pointer returned by AllocateElement().
551
It is critical that p be from this pool and that
552
you return a pointer no more than one time.
553
Remarks:
554
If you find the following remarks confusing, but you really want to use
555
ReturnElement(), then here are some simple guidelines.
556
1) SizeofElement() must be >= 16
557
2) SizeofElement() must be a multiple of 8.
558
3) Do not use FirstElement() and NextElement() to iterate through
559
the pool.
560
561
If 1 to 3 don't work for you, then you need to understand the following
562
information before using ReturnElement().
563
564
ON_FixedMemoryPool uses the first sizeof(void*) bytes of the
565
returned element for bookkeeping purposes. Therefore, if you
566
are going to use ReturnElement(), then SizeofElement() must be
567
at least sizeof(void*). If you are using a platform that requires
568
pointers to be aligned on sizeof(void*) boundaries, then
569
SizeofElement() must be a multiple of sizeof(void*).
570
If you are going to use ReturnElement() and then use FirstElement()
571
and NextElement() to iterate through the list of elements, then you
572
need to set a value in the returned element to indicate that it
573
needs to be skipped during the iteration. This value cannot be
574
located in the fist sizeof(void*) bytes of the element. If the
575
element is a class with a vtable, you cannot call a virtual
576
function on a returned element because the vtable pointer is
577
trashed when ReturnElement() modifies the fist sizeof(void*) bytes.
578
*/
579
void
ReturnElement
(T* p);
580
581
/*
582
Description:
583
Return all allocated elements to the pool. No heap is freed and
584
the pool remains initialized and ready for AllocateElement()
585
to be called.
586
*/
587
void
ReturnAll
();
588
589
/*
590
Description:
591
Destroy the pool and free all the heap. The pool cannot be used again
592
until Create() is called.
593
*/
594
void
Destroy
();
595
596
/*
597
Returns:
598
Number of active elements. (Elements that have been returned are not active.)
599
*/
600
size_t
ActiveElementCount
()
const
;
601
602
/*
603
Returns:
604
Total number of elements = number of active elements + number of returned elements.
605
*/
606
size_t
TotalElementCount
()
const
;
607
608
/*
609
Description:
610
Get the next element when iterating through the active elements.
611
Example:
612
The loop will iteratate through all the elements returned from
613
AllocateElement(), including any that have be returned to the pool
614
using ReturnElement().
615
616
// iterate through all elements in the pool
617
for ( T* p = FirstElement(); 0 != p; p = NextElement() )
618
{
619
// If you are not using ReturnElement(), then you may process
620
// "p" immediately. If you have used ReturnElement(), then you
621
// must check some value in p located after the first sizeof(void*)
622
// bytes to see if p is active.
623
if ( p is not active )
624
continue;
625
626
... process p
627
}
628
629
Returns:
630
The next element when iterating through the active elements.
631
Remarks:
632
NextElement() will return elements that have been returned to
633
the pool using ReturnElement(). If you use ReturnElement(),
634
be sure to mark the element so it can be identified and skipped.
635
*/
636
T*
FirstElement
();
637
638
/*
639
Description:
640
Get the next element when iterating through the active elements.
641
Example:
642
See the FirstElement() documentation.
643
Returns:
644
The next element when iterating through the active elements.
645
Remarks:
646
NextElement() will return elements that have been returned to
647
the pool using ReturnElement(). If you use ReturnElement(),
648
be sure to mark the element so it can be identified and skipped.
649
*/
650
T*
NextElement
();
651
652
/*
653
Description:
654
Get a pointer to the first element in the first block.
655
Example:
656
The loop will iteratate through all the blocks.
657
658
// iterate through all blocks in the pool
659
size_t block_element_count = 0;
660
for ( T* p = FirstBlock(&block_element_count);
661
0 != p;
662
p = NextBlock(&block_element_count)
663
)
664
{
665
// a[] is an array of length block_element_count
666
}
667
668
Returns:
669
The next block when iterating the list of blocks.
670
Remarks:
671
Do not make any calls to FirstElement() or NextElement() when using
672
FirstBlock() and NextBlock() to iteratate through blocks.
673
*/
674
T*
FirstBlock
(
size_t
* block_element_count );
675
676
/*
677
Description:
678
Get the next block when iterating through the blocks.
679
Example:
680
See the FirstBlock() documentation.
681
Returns:
682
The next block when iterating through the blocks.
683
Remarks:
684
Do not make any calls to FirstElement() or NextElement() when using
685
FirstBlock() and NextBlock() to iteratate through blocks.
686
*/
687
T*
NextBlock
(
size_t
* block_element_count );
688
689
690
/*
691
Description:
692
Get the i-th elment in the pool.
693
Parameters:
694
element_index - [in]
695
Returns:
696
A pointer to the i-th element. The first element has index = 0
697
and is the element returned by the first call to AllocateElement().
698
The last element has index = ElementCount()-1.
699
If i is out of range, null is returned.
700
Remarks:
701
It is faster to use FirstElement() and NextElement() to iterate
702
through the entire list of elements. This function is relatively
703
efficient when there are a few large blocks in the pool
704
or element_index is small compared to the number of elements
705
in the first few blocks.
706
707
If ReturnElement() is not used or AllocateElement() calls to
708
are made after any use of ReturnElement(), then the i-th
709
element is the one returned by the (i+1)-th call to
710
AllocateElement().
711
*/
712
T*
Element
(
size_t
element_index)
const
;
713
714
public
:
715
// Expert user functions below for situations where you
716
// need to specify the heap used for this pool.
717
718
/*
719
Description:
720
Expert user function to specify which heap is used.
721
*/
722
void
SetHeap
( ON_MEMORY_POOL* heap );
723
724
/*
725
Description:
726
Expert user function.
727
Returns:
728
Heap used by this pool. A null pointer means the default
729
heap is being used.
730
*/
731
ON_MEMORY_POOL*
Heap
();
732
733
/*
734
Description:
735
Expert user function to call when the heap used by this pool
736
is no longer valid. This call zeros all fields and does not
737
call any heap functions. After calling EmergencyDestroy(),
738
the destructor will not attempt to free any heap.
739
*/
740
void
EmergencyDestroy
();
741
742
private
:
743
// prohibit copy construction and operator=.
744
ON_SimpleFixedSizePool
(
const
ON_SimpleFixedSizePool<T>
&);
745
ON_SimpleFixedSizePool<T>
& operator=(
const
ON_SimpleFixedSizePool<T>
&);
746
};
747
748
// definitions of the template functions are in a different file
749
// so that Microsoft's developer studio's autocomplete utility
750
// will work on the template functions.
751
#include "opennurbs_fsp_defs.h"
752
753
#endif
754