2 ** License Applicability. Except to the extent portions of this file are
3 ** made subject to an alternative license as permitted in the SGI Free
4 ** Software License B, Version 1.1 (the "License"), the contents of this
5 ** file are subject only to the provisions of the License. You may not use
6 ** this file except in compliance with the License. You may obtain a copy
7 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
8 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
10 ** http://oss.sgi.com/projects/FreeB
12 ** Note that, as provided in the License, the Software is distributed on an
13 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
14 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
15 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
16 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
18 ** Original Code. The Original Code is: OpenGL Sample Implementation,
19 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
20 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
21 ** Copyright in any portions created by third parties is as indicated
22 ** elsewhere herein. All Rights Reserved.
24 ** Additional Notice Provisions: The application programming interfaces
25 ** established by SGI in conjunction with the Original Code are The
26 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
27 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
28 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
29 ** Window System(R) (Version 1.3), released October 19, 1998. This software
30 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
31 ** published by SGI, but has not been independently verified as being
32 ** compliant with the OpenGL(R) version 1.2.1 Specification.
38 * $Date$ $Revision: 1.1 $
39 * $Header: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/glu32/libnurbs/internals/tobezier.cc,v 1.1 2004/02/02 16:39:13 navaraf Exp $
42 #include "glimports.h"
47 #include "knotvector.h"
49 /* local type definitions */
50 struct Breakpt
{ /* breakpoints */
51 Knot value
; /* value */
52 int multi
; /* multiplicity */
53 int def
; /* deficit */
56 struct Knotspec
{ /* knotvector format */
57 long order
; /* order of spline */
58 Knot_ptr inkbegin
; /* input knot sequence */
59 Knot_ptr inkend
; /* location after last knot */
60 Knot_ptr outkbegin
; /* in-process knot subsequence */
61 Knot_ptr outkend
; /* location after last knot */
63 Knot_ptr kright
; /* */
64 Knot_ptr kfirst
; /* */
66 Knot_ptr sbegin
; /* conversion factor values */
67 Breakpt
* bbegin
; /* in-process breakpoints */
68 Breakpt
* bend
; /* last breakpoint */
69 int ncoords
; /* coordinates per control point */
70 int prestride
; /* stride between input points */
71 int poststride
; /* stride between output points */
72 int preoffset
; /* scaled point offset */
73 int postoffset
; /* scaled point offset */
74 int prewidth
; /* width of dimension */
75 int postwidth
; /* width of dimension */
76 int istransformed
; /* was dimension transformed */
77 Knotspec
* next
; /* next knotspec */
78 Knotspec
* kspectotrans
; /* knotspec in transformation direction */
83 void insert( REAL
* );
86 void copy( INREAL
*, REAL
* );
87 void breakpoints( void );
89 void transform( REAL
* );
90 void showpts( REAL
* );
92 void pt_io_copy( REAL
*, INREAL
* );
93 void pt_oo_copy( REAL
*, REAL
* );
94 void pt_oo_sum( REAL
*, REAL
*, REAL
*, Knot
, Knot
);
97 struct Splinespec
{ /* a non-uniform tensor element */
100 Knotspec
*kspec
; /* format of each param. dir. */
101 int dim
; /* domain dimension */
102 REAL
* outcpts
; /* Bezier control points */
104 void kspecinit( Knotvector
& );
105 void kspecinit( Knotvector
&, Knotvector
& );
108 void setupquilt( Quilt_ptr
);
109 void copy( INREAL
* );
110 void transform( void );
113 /*-----------------------------------------------------------------------------
114 * Quilt::toBezier - convert from NURBS to rational Bezier
115 *-----------------------------------------------------------------------------
120 Knotvector
& knotvector
, /* a knot vector */
121 INREAL
*ctlpts
, /* input contol points */
122 long ncoords
) /* number of coordinates per control point */
124 Splinespec
spline( 1 );
125 spline
.kspecinit( knotvector
);
127 spline
.layout( ncoords
);
128 spline
.setupquilt( this );
129 spline
.copy( ctlpts
);
135 Knotvector
& sknotvector
, /* a knot vector */
136 Knotvector
& tknotvector
, /* a knot vector */
137 INREAL
*ctlpts
, /* input contol points */
138 long ncoords
) /* number of coordinates per control point */
140 Splinespec
spline( 2 );
141 spline
.kspecinit( sknotvector
, tknotvector
);
143 spline
.layout( ncoords
);
144 spline
.setupquilt( this );
145 spline
.copy( ctlpts
);
148 Splinespec::Splinespec( int dimen
)
153 Splinespec::~Splinespec( void )
155 /* Note: do NOT delete 'outcpts' here since its address (not contents)
156 * is copied in 'cpts' in this file in function Splinespec::setupquilt().
157 * This block of memory will eventually be deleted in file quilt.c++ in
158 * function Quilt::deleteMe() through 'cpts' so do NOT delete it here!
160 Knotspec
*ktrav
= kspec
; //start at beginning of list
161 while (ktrav
!= 0) { //any items to delete?
162 Knotspec
*deleteThis
= ktrav
; //remember to delete this
163 ktrav
= ktrav
->next
; //go to next item if any
164 delete deleteThis
; //delete it
166 } /* ~Splinespec() */
168 /*-----------------------------------------------------------------------------
169 * Splinespec::kspecinit - initialize Splinespec structure
171 * Client: Quilt::toBezier
172 *-----------------------------------------------------------------------------
176 Splinespec::kspecinit( Knotvector
& knotvector
)
178 kspec
= new Knotspec
;
179 kspec
->inkbegin
= knotvector
.knotlist
;
180 kspec
->inkend
= knotvector
.knotlist
+ knotvector
.knotcount
;
181 kspec
->prestride
= (int) knotvector
.stride
;
182 kspec
->order
= knotvector
.order
;
187 Splinespec::kspecinit( Knotvector
& sknotvector
, Knotvector
& tknotvector
)
189 kspec
= new Knotspec
;
190 Knotspec
*tkspec
= new Knotspec
;
192 kspec
->inkbegin
= sknotvector
.knotlist
;
193 kspec
->inkend
= sknotvector
.knotlist
+ sknotvector
.knotcount
;
194 kspec
->prestride
= (int) sknotvector
.stride
;
195 kspec
->order
= sknotvector
.order
;
196 kspec
->next
= tkspec
;
198 tkspec
->inkbegin
= tknotvector
.knotlist
;
199 tkspec
->inkend
= tknotvector
.knotlist
+ tknotvector
.knotcount
;
200 tkspec
->prestride
= (int) tknotvector
.stride
;
201 tkspec
->order
= tknotvector
.order
;
206 /*-----------------------------------------------------------------------------
207 * Splinespec::select - select the subsegments to copy
209 * Client: gl_quilt_to_bezier
210 *-----------------------------------------------------------------------------
214 Splinespec::select( )
216 for( Knotspec
*knotspec
= kspec
; knotspec
; knotspec
= knotspec
->next
) {
217 knotspec
->preselect();
222 /*-----------------------------------------------------------------------------
223 * Splinespec::layout -
225 * Client: gl_quilt_to_bezier
226 *-----------------------------------------------------------------------------
230 Splinespec::layout( long ncoords
)
233 long stride
= ncoords
;
234 for( Knotspec
*knotspec
= kspec
; knotspec
; knotspec
=knotspec
->next
) {
235 knotspec
->poststride
= (int) stride
;
236 stride
*= ((knotspec
->bend
-knotspec
->bbegin
)*knotspec
->order
+ knotspec
->postoffset
);
237 knotspec
->preoffset
*= knotspec
->prestride
;
238 knotspec
->prewidth
*= knotspec
->poststride
;
239 knotspec
->postwidth
*= knotspec
->poststride
;
240 knotspec
->postoffset
*= knotspec
->poststride
;
241 knotspec
->ncoords
= (int) ncoords
;
243 outcpts
= new REAL
[stride
];
244 assert( outcpts
!= 0 );
247 /*-----------------------------------------------------------------------------
248 * Splinespec::copy - copy the control points of current subobject
250 * Client: gl_quilt_to_bezier
251 *-----------------------------------------------------------------------------
255 Splinespec::copy( INREAL
*incpts
)
257 kspec
->copy( incpts
, outcpts
);
260 /*-----------------------------------------------------------------------------
261 * Splinespec::setupquilt - assign all quilt variables from knotspec
263 * Client: gl_quilt_to_bezier
264 *-----------------------------------------------------------------------------
268 Splinespec::setupquilt( Quilt_ptr quilt
)
270 Quiltspec_ptr qspec
= quilt
->qspec
;
271 quilt
->eqspec
= qspec
+ dim
;
272 for( Knotspec
*knotspec
= kspec
; knotspec
; knotspec
=knotspec
->next
, qspec
++ ) {
273 qspec
->stride
= knotspec
->poststride
;
274 qspec
->width
= knotspec
->bend
- knotspec
->bbegin
;
275 qspec
->order
= (int) knotspec
->order
;
276 qspec
->offset
= knotspec
->postoffset
;
278 qspec
->bdry
[0] = (knotspec
->kleft
== knotspec
->kfirst
) ? 1 : 0;
279 qspec
->bdry
[1] = (knotspec
->kright
== knotspec
->klast
) ? 1 : 0;
280 qspec
->breakpoints
= new Knot
[qspec
->width
+1];
281 Knot_ptr k
= qspec
->breakpoints
;
282 for( Breakpt
*bk
= knotspec
->bbegin
; bk
<= knotspec
->bend
; bk
++ )
285 quilt
->cpts
= outcpts
;
289 /*-----------------------------------------------------------------------------
290 * Splinespec::transform - convert a spline to Bezier format
292 * Client: gl_quilt_to_bezier
293 *-----------------------------------------------------------------------------
297 Splinespec::transform( void )
300 for( knotspec
= kspec
; knotspec
; knotspec
=knotspec
->next
)
301 knotspec
->istransformed
= 0;
303 for( knotspec
= kspec
; knotspec
; knotspec
=knotspec
->next
) {
304 for( Knotspec
*kspec2
= kspec
; kspec2
; kspec2
=kspec2
->next
)
305 kspec2
->kspectotrans
= knotspec
;
306 kspec
->transform( outcpts
);
307 knotspec
->istransformed
= 1;
312 /*-----------------------------------------------------------------------------
313 * Knotspec::Knotspec - constuct a knot spec
314 *-----------------------------------------------------------------------------
317 Knotspec::Knotspec( void )
324 /*-----------------------------------------------------------------------------
325 * Knotspec::copy - copy the control points along minor direction
327 * Client: Splinespec::copy
328 *-----------------------------------------------------------------------------
332 Knotspec::copy( INREAL
*inpt
, REAL
*outpt
)
334 inpt
= (INREAL
*) (((char *) inpt
) + preoffset
);
337 for( REAL
*lpt
=outpt
+prewidth
; outpt
!= lpt
; outpt
+= poststride
) {
338 next
->copy( inpt
, outpt
);
339 inpt
= (INREAL
*) (((char *) inpt
) + prestride
);
342 for( REAL
*lpt
=outpt
+prewidth
; outpt
!= lpt
; outpt
+= poststride
) {
343 pt_io_copy( outpt
, inpt
);
344 inpt
= (INREAL
*) (((char *) inpt
) + prestride
);
349 /*-----------------------------------------------------------------------------
350 * Knotspec::showpts - print out points before transformation
352 * Client: Knotspec::select
353 *-----------------------------------------------------------------------------
356 Knotspec::showpts( REAL
*outpt
)
359 for( REAL
*lpt
=outpt
+prewidth
; outpt
!= lpt
; outpt
+= poststride
)
360 next
->showpts( outpt
);
362 for( REAL
*lpt
=outpt
+prewidth
; outpt
!= lpt
; outpt
+= poststride
)
363 dprintf( "show %g %g %g\n", outpt
[0], outpt
[1], outpt
[2] );
367 /*-----------------------------------------------------------------------------
368 * Knotspec::factors - precompute scale factors
369 * - overwrites knot vector, actual new knot vector is NOT produced
371 * Client: Knotspec::select
372 *-----------------------------------------------------------------------------
376 Knotspec::factors( void )
378 Knot
*mid
= (outkend
- 1) - order
+ bend
->multi
;
379 Knot_ptr fptr
= sbegin
;
381 for( Breakpt
*bpt
= bend
; bpt
>= bbegin
; bpt
-- ) {
382 mid
-= bpt
->multi
; // last knot less than knot to insert
383 int def
= bpt
->def
- 1; // number of knots to insert
384 if( def
<= 0 ) continue;
385 Knot kv
= bpt
->value
; // knot to insert
387 Knot
*kf
= (mid
-def
) + (order
-1);
388 for( Knot
*kl
= kf
+ def
; kl
!= kf
; kl
-- ) {
390 for( kt
=kl
, kh
=mid
; kt
!= kf
; kh
--, kt
-- )
391 *(fptr
++) = (kv
- *kh
) / (*kt
- *kh
);
397 /*-----------------------------------------------------------------------------
398 * Knotspec::insert - convert subobject in direction of kspec into Bezier
400 * Client: Knotspec::transform
401 *-----------------------------------------------------------------------------
405 Knotspec::insert( REAL
*p
)
407 Knot_ptr fptr
= sbegin
;
408 REAL
*srcpt
= p
+ prewidth
- poststride
;
409 REAL
*dstpt
= p
+ postwidth
+ postoffset
- poststride
;
412 for( REAL
*pend
= srcpt
- poststride
*bpt
->def
; srcpt
!= pend
; pend
+=poststride
) {
414 for( REAL
*p2
= srcpt
-poststride
; p2
!= pend
; p1
= p2
, p2
-= poststride
) {
415 pt_oo_sum( p1
, p1
, p2
, *fptr
, 1.0-*fptr
);
420 for( --bpt
; bpt
>= bbegin
; bpt
-- ) {
422 for( int multi
= bpt
->multi
; multi
> 0; multi
-- ) {
423 pt_oo_copy( dstpt
, srcpt
);
428 for( REAL
*pend
= srcpt
- poststride
*bpt
->def
; srcpt
!= pend
; pend
+=poststride
, dstpt
-=poststride
) {
429 pt_oo_copy( dstpt
, srcpt
);
432 for( REAL
*p2
= srcpt
-poststride
; p2
!= pend
; p1
=p2
, p2
-= poststride
) {
433 pt_oo_sum( p1
, p1
, p2
, *fptr
, 1.0-*fptr
);
440 /*-----------------------------------------------------------------------------
441 * Knotspec::preselect - initialize kspec for processing
443 * Client: Splinespec::select
444 *-----------------------------------------------------------------------------
448 Knotspec::preselect( void )
452 /* position klast after last knot of "last" breakpoint */
453 for( klast
= inkend
- order
, kval
= *klast
; klast
!= inkend
; klast
++ )
454 if( ! identical( *klast
, kval
) ) break;
456 /* position kfirst after last knot of "first" breakpoint */
457 for( kfirst
= inkbegin
+order
-1, kval
= *kfirst
; kfirst
!= inkend
; kfirst
++ )
458 if( ! identical( *kfirst
, kval
) ) break;
460 /* compute multiplicity of first breakpoint */
462 for( k
= kfirst
- 1; k
>= inkbegin
; k
-- )
463 if( ! identical( kval
, *k
) ) break;
466 /* allocate space for breakpoints -
467 use worst case estimate on number of breakpoints */
469 bbegin
= new Breakpt
[(klast
- kfirst
)+1];
470 /* record multiplicity and value of first breakpoint */
471 bbegin
->multi
= kfirst
- k
;
472 bbegin
->value
= kval
;
475 kleft
= kright
= kfirst
;
479 /*-----------------------------------------------------------------------------
480 * Knotspec::select - Knotspec::select segments and precompute scale factors
482 * Client: Splinespec::select
483 *-----------------------------------------------------------------------------
487 Knotspec::select( void )
493 preoffset
= kleft
- (inkbegin
+ order
);
494 postwidth
= (int)((bend
- bbegin
) * order
);
495 prewidth
= (int)((outkend
- outkbegin
) - order
);
496 postoffset
= (bbegin
->def
> 1) ? (bbegin
->def
-1) : 0;
499 /*-----------------------------------------------------------------------------
500 * Knotspec::breakpoints - compute breakpoints for knotspec
502 * Client: Knotspec::select
503 *-----------------------------------------------------------------------------
507 Knotspec::breakpoints( void )
509 Breakpt
*ubpt
= bbegin
;
510 Breakpt
*ubend
= bend
;
513 ubpt
->value
= ubend
->value
;
514 ubpt
->multi
= ubend
->multi
;
518 for( ; kright
!= klast
; kright
++ ) {
519 if ( identical(*kright
,ubpt
->value
) ) {
522 ubpt
->def
= (int) (order
- ubpt
->multi
);
523 nfactors
+= (ubpt
->def
* (ubpt
->def
- 1)) / 2;
524 (++ubpt
)->value
= *kright
;
528 ubpt
->def
= (int) (order
- ubpt
->multi
);
529 nfactors
+= (ubpt
->def
* (ubpt
->def
- 1)) / 2;
534 sbegin
= new Knot
[nfactors
];
541 /*-----------------------------------------------------------------------------
542 * Knotspec::knots - copy relevant subsequence of knots into temporary area
544 * Client: Knotspec::select
545 *-----------------------------------------------------------------------------
549 Knotspec::knots( void )
551 Knot_ptr inkpt
= kleft
- order
;
552 Knot_ptr inkend
= kright
+ bend
->def
;
554 /* allocate space for knots and factors */
555 outkbegin
= new Knot
[inkend
-inkpt
];
557 for( outkpt
= outkbegin
; inkpt
!= inkend
; inkpt
++, outkpt
++ )
564 /*-----------------------------------------------------------------------------
565 * Knotspec::transform - convert a spline along a given direction
567 * Client: Splienspec::transform
568 *-----------------------------------------------------------------------------
572 Knotspec::transform( REAL
*p
)
575 if( this == kspectotrans
) {
576 next
->transform( p
);
578 if( istransformed
) {
580 for( REAL
*pend
= p
+ postwidth
; p
!= pend
; p
+= poststride
)
581 next
->transform( p
);
583 REAL
*pend
= p
+ prewidth
;
584 for( ; p
!= pend
; p
+= poststride
)
585 next
->transform( p
);
589 if( this == kspectotrans
) {
592 if( istransformed
) {
594 for( REAL
*pend
= p
+ postwidth
; p
!= pend
; p
+= poststride
)
595 kspectotrans
->insert( p
);
597 REAL
*pend
= p
+ prewidth
;
598 for( ; p
!= pend
; p
+= poststride
)
599 kspectotrans
->insert( p
);
605 /*-----------------------------------------------------------------------------
606 * Knotspec::~Knotspec - free space alocated for knotspec
607 *-----------------------------------------------------------------------------
610 Knotspec::~Knotspec( void )
612 if( bbegin
) delete[] bbegin
;
613 if( sbegin
) delete[] sbegin
;
614 if( outkbegin
) delete[] outkbegin
;
618 /*-----------------------------------------------------------------------------
619 * pt_io_copy - make internal copy of input cntrl pt. of x coords
620 *-----------------------------------------------------------------------------
624 Knotspec::pt_io_copy( REAL
*topt
, INREAL
*frompt
)
628 topt
[3] = (REAL
) frompt
[3];
630 topt
[2] = (REAL
) frompt
[2];
632 topt
[1] = (REAL
) frompt
[1];
634 topt
[0] = (REAL
) frompt
[0];
637 for( int i
= 0; i
< ncoords
; i
++ )
638 *topt
++ = (REAL
) *frompt
++;
643 /*-----------------------------------------------------------------------------
644 * pt_oo_copy - make internal copy of internal cntrl pt. of x coords
645 *-----------------------------------------------------------------------------
649 Knotspec::pt_oo_copy( REAL
*topt
, REAL
*frompt
)
662 memcpy( topt
, frompt
, ncoords
* sizeof( REAL
) );
666 /*-----------------------------------------------------------------------------
667 * pt_oo_sum - compute affine combination of internal cntrl pts
668 *-----------------------------------------------------------------------------
672 Knotspec::pt_oo_sum( REAL
*x
, REAL
*y
, REAL
*z
, Knot a
, Knot b
)
676 x
[3] = a
* y
[3] + b
* z
[3];
678 x
[2] = a
* y
[2] + b
* z
[2];
680 x
[1] = a
* y
[1] + b
* z
[1];
682 x
[0] = a
* y
[0] + b
* z
[0];
685 for( int i
= 0; i
< ncoords
; i
++ )
686 *x
++ = a
* *y
++ + b
* *z
++;