tobezier.cc revision f220fa62
1f220fa62Smrg/*
2f220fa62Smrg** License Applicability. Except to the extent portions of this file are
3f220fa62Smrg** made subject to an alternative license as permitted in the SGI Free
4f220fa62Smrg** Software License B, Version 1.1 (the "License"), the contents of this
5f220fa62Smrg** file are subject only to the provisions of the License. You may not use
6f220fa62Smrg** this file except in compliance with the License. You may obtain a copy
7f220fa62Smrg** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
8f220fa62Smrg** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
9f220fa62Smrg**
10f220fa62Smrg** http://oss.sgi.com/projects/FreeB
11f220fa62Smrg**
12f220fa62Smrg** Note that, as provided in the License, the Software is distributed on an
13f220fa62Smrg** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
14f220fa62Smrg** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
15f220fa62Smrg** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
16f220fa62Smrg** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
17f220fa62Smrg**
18f220fa62Smrg** Original Code. The Original Code is: OpenGL Sample Implementation,
19f220fa62Smrg** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
20f220fa62Smrg** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
21f220fa62Smrg** Copyright in any portions created by third parties is as indicated
22f220fa62Smrg** elsewhere herein. All Rights Reserved.
23f220fa62Smrg**
24f220fa62Smrg** Additional Notice Provisions: The application programming interfaces
25f220fa62Smrg** established by SGI in conjunction with the Original Code are The
26f220fa62Smrg** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
27f220fa62Smrg** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
28f220fa62Smrg** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
29f220fa62Smrg** Window System(R) (Version 1.3), released October 19, 1998. This software
30f220fa62Smrg** was created using the OpenGL(R) version 1.2.1 Sample Implementation
31f220fa62Smrg** published by SGI, but has not been independently verified as being
32f220fa62Smrg** compliant with the OpenGL(R) version 1.2.1 Specification.
33f220fa62Smrg*/
34f220fa62Smrg
35f220fa62Smrg/*
36f220fa62Smrg * tobezier.c++
37f220fa62Smrg *
38f220fa62Smrg */
39f220fa62Smrg
40f220fa62Smrg#include "glimports.h"
41f220fa62Smrg#include "myassert.h"
42f220fa62Smrg#include "mystdio.h"
43f220fa62Smrg#include "mystring.h"
44f220fa62Smrg#include "quilt.h"
45f220fa62Smrg#include "knotvector.h"
46f220fa62Smrg
47f220fa62Smrg/* local type definitions */
48f220fa62Smrgstruct Breakpt {		/* breakpoints	*/
49f220fa62Smrg    Knot		value;		/* value	*/
50f220fa62Smrg    int			multi;		/* multiplicity	*/
51f220fa62Smrg    int			def;		/* deficit */
52f220fa62Smrg};
53f220fa62Smrg
54f220fa62Smrgstruct Knotspec {		/* knotvector format */
55f220fa62Smrg    long		order;		/* order of spline  */
56f220fa62Smrg    Knot_ptr		inkbegin;	/* input knot sequence */
57f220fa62Smrg    Knot_ptr		inkend;		/* location after last knot */
58f220fa62Smrg    Knot_ptr		outkbegin;	/* in-process knot subsequence */
59f220fa62Smrg    Knot_ptr		outkend;	/* location after last knot */
60f220fa62Smrg    Knot_ptr		kleft;		/* */
61f220fa62Smrg    Knot_ptr		kright;		/* */
62f220fa62Smrg    Knot_ptr		kfirst;		/* */
63f220fa62Smrg    Knot_ptr		klast;		/* */
64f220fa62Smrg    Knot_ptr		sbegin;		/* conversion factor values */
65f220fa62Smrg    Breakpt *		bbegin;		/* in-process breakpoints */
66f220fa62Smrg    Breakpt *		bend;		/* last breakpoint */
67f220fa62Smrg    int			ncoords;	/* coordinates per control point */
68f220fa62Smrg    int			prestride;	/* stride between input points */
69f220fa62Smrg    int			poststride;	/* stride between output points	*/
70f220fa62Smrg    int 		preoffset;	/* scaled point offset	*/
71f220fa62Smrg    int 		postoffset;	/* scaled point offset	*/
72f220fa62Smrg    int 		prewidth;	/* width of dimension	*/
73f220fa62Smrg    int 		postwidth;	/* width of dimension	*/
74f220fa62Smrg    int 		istransformed;	/* was dimension transformed */
75f220fa62Smrg    Knotspec *		next;   	/* next knotspec */
76f220fa62Smrg    Knotspec *		kspectotrans;   /* knotspec in transformation direction */
77f220fa62Smrg
78f220fa62Smrg			Knotspec( void );
79f220fa62Smrg			~Knotspec( void );
80f220fa62Smrg    void		factors( void );
81f220fa62Smrg    void		insert( REAL * );
82f220fa62Smrg    void		preselect();
83f220fa62Smrg    void		select( void );
84f220fa62Smrg    void		copy( INREAL *, REAL * );
85f220fa62Smrg    void		breakpoints( void );
86f220fa62Smrg    void		knots( void );
87f220fa62Smrg    void		transform( REAL * );
88f220fa62Smrg    void		showpts( REAL * );
89f220fa62Smrg
90f220fa62Smrg    void		pt_io_copy( REAL *, INREAL * );
91f220fa62Smrg    void		pt_oo_copy( REAL *, REAL * );
92f220fa62Smrg    void		pt_oo_sum( REAL*, REAL*, REAL*, Knot, Knot );
93f220fa62Smrg};
94f220fa62Smrg
95f220fa62Smrgstruct Splinespec {		/* a non-uniform tensor element */
96f220fa62Smrg			Splinespec( int );
97f220fa62Smrg                        ~Splinespec(void);
98f220fa62Smrg    Knotspec		*kspec;	/* format of each param. dir. */
99f220fa62Smrg    int			dim;		/* domain dimension */
100f220fa62Smrg    REAL *		outcpts;	/* Bezier control points */
101f220fa62Smrg
102f220fa62Smrg    void		kspecinit( Knotvector & );
103f220fa62Smrg    void		kspecinit( Knotvector &, Knotvector & );
104f220fa62Smrg    void		select( void );
105f220fa62Smrg    void		layout( long );
106f220fa62Smrg    void		setupquilt( Quilt_ptr );
107f220fa62Smrg    void		copy( INREAL * );
108f220fa62Smrg    void		transform( void );
109f220fa62Smrg};
110f220fa62Smrg
111f220fa62Smrg/*-----------------------------------------------------------------------------
112f220fa62Smrg * Quilt::toBezier - convert from NURBS to rational Bezier
113f220fa62Smrg *-----------------------------------------------------------------------------
114f220fa62Smrg */
115f220fa62Smrg
116f220fa62Smrgvoid
117f220fa62SmrgQuilt::toBezier(
118f220fa62Smrg    Knotvector& knotvector,	/* a knot vector */
119f220fa62Smrg    INREAL *ctlpts,		/* input contol points */
120f220fa62Smrg    long ncoords )		/* number of coordinates per control point */
121f220fa62Smrg{
122f220fa62Smrg    Splinespec spline( 1 );
123f220fa62Smrg    spline.kspecinit( knotvector );
124f220fa62Smrg    spline.select();
125f220fa62Smrg    spline.layout( ncoords );
126f220fa62Smrg    spline.setupquilt( this );
127f220fa62Smrg    spline.copy( ctlpts );
128f220fa62Smrg    spline.transform();
129f220fa62Smrg}
130f220fa62Smrg
131f220fa62Smrgvoid
132f220fa62SmrgQuilt::toBezier(
133f220fa62Smrg    Knotvector& sknotvector,	/* a knot vector */
134f220fa62Smrg    Knotvector& tknotvector,	/* a knot vector */
135f220fa62Smrg    INREAL *ctlpts,		/* input contol points */
136f220fa62Smrg    long ncoords )		/* number of coordinates per control point */
137f220fa62Smrg{
138f220fa62Smrg    Splinespec spline( 2 );
139f220fa62Smrg    spline.kspecinit( sknotvector, tknotvector );
140f220fa62Smrg    spline.select();
141f220fa62Smrg    spline.layout( ncoords );
142f220fa62Smrg    spline.setupquilt( this );
143f220fa62Smrg    spline.copy( ctlpts );
144f220fa62Smrg    spline.transform();
145f220fa62Smrg}
146f220fa62SmrgSplinespec::Splinespec( int dimen )
147f220fa62Smrg{
148f220fa62Smrg    dim = dimen;
149f220fa62Smrg}
150f220fa62Smrg
151f220fa62SmrgSplinespec::~Splinespec( void )
152f220fa62Smrg{
153f220fa62Smrg    /* Note: do NOT delete 'outcpts' here since its address (not contents)
154f220fa62Smrg     * is copied in 'cpts' in this file in function Splinespec::setupquilt().
155f220fa62Smrg     * This block of memory will eventually be deleted in file quilt.c++ in
156f220fa62Smrg     * function Quilt::deleteMe() through 'cpts' so do NOT delete it here!
157f220fa62Smrg     */
158f220fa62Smrg    Knotspec *ktrav= kspec;         //start at beginning of list
159f220fa62Smrg    while (ktrav != 0) {            //any items to delete?
160f220fa62Smrg       Knotspec *deleteThis= ktrav; //remember to delete this
161f220fa62Smrg       ktrav= ktrav->next;          //go to next item if any
162f220fa62Smrg       delete deleteThis;           //delete it
163f220fa62Smrg    }
164f220fa62Smrg} /* ~Splinespec() */
165f220fa62Smrg
166f220fa62Smrg/*-----------------------------------------------------------------------------
167f220fa62Smrg * Splinespec::kspecinit - initialize Splinespec structure
168f220fa62Smrg *
169f220fa62Smrg * Client: Quilt::toBezier
170f220fa62Smrg *-----------------------------------------------------------------------------
171f220fa62Smrg */
172f220fa62Smrg
173f220fa62Smrgvoid
174f220fa62SmrgSplinespec::kspecinit( Knotvector& knotvector )
175f220fa62Smrg{
176f220fa62Smrg    kspec = new Knotspec;
177f220fa62Smrg    kspec->inkbegin = knotvector.knotlist;
178f220fa62Smrg    kspec->inkend = knotvector.knotlist + knotvector.knotcount;
179f220fa62Smrg    kspec->prestride = (int) knotvector.stride;
180f220fa62Smrg    kspec->order = knotvector.order;
181f220fa62Smrg    kspec->next = NULL;
182f220fa62Smrg}
183f220fa62Smrg
184f220fa62Smrgvoid
185f220fa62SmrgSplinespec::kspecinit( Knotvector& sknotvector, Knotvector& tknotvector )
186f220fa62Smrg{
187f220fa62Smrg    kspec = new Knotspec;
188f220fa62Smrg    Knotspec *tkspec = new Knotspec;
189f220fa62Smrg
190f220fa62Smrg    kspec->inkbegin = sknotvector.knotlist;
191f220fa62Smrg    kspec->inkend = sknotvector.knotlist + sknotvector.knotcount;
192f220fa62Smrg    kspec->prestride = (int) sknotvector.stride;
193f220fa62Smrg    kspec->order = sknotvector.order;
194f220fa62Smrg    kspec->next = tkspec;
195f220fa62Smrg
196f220fa62Smrg    tkspec->inkbegin = tknotvector.knotlist;
197f220fa62Smrg    tkspec->inkend = tknotvector.knotlist + tknotvector.knotcount;
198f220fa62Smrg    tkspec->prestride = (int) tknotvector.stride;
199f220fa62Smrg    tkspec->order = tknotvector.order;
200f220fa62Smrg    tkspec->next = NULL;
201f220fa62Smrg}
202f220fa62Smrg
203f220fa62Smrg
204f220fa62Smrg/*-----------------------------------------------------------------------------
205f220fa62Smrg * Splinespec::select - select the subsegments to copy
206f220fa62Smrg *
207f220fa62Smrg * Client: gl_quilt_to_bezier
208f220fa62Smrg *-----------------------------------------------------------------------------
209f220fa62Smrg */
210f220fa62Smrg
211f220fa62Smrgvoid
212f220fa62SmrgSplinespec::select( )
213f220fa62Smrg{
214f220fa62Smrg    for( Knotspec *knotspec = kspec; knotspec; knotspec = knotspec->next ) {
215f220fa62Smrg	knotspec->preselect();
216f220fa62Smrg	knotspec->select();
217f220fa62Smrg    }
218f220fa62Smrg}
219f220fa62Smrg
220f220fa62Smrg/*-----------------------------------------------------------------------------
221f220fa62Smrg * Splinespec::layout -
222f220fa62Smrg *
223f220fa62Smrg * Client: gl_quilt_to_bezier
224f220fa62Smrg *-----------------------------------------------------------------------------
225f220fa62Smrg */
226f220fa62Smrg
227f220fa62Smrgvoid
228f220fa62SmrgSplinespec::layout( long ncoords )
229f220fa62Smrg{
230f220fa62Smrg
231f220fa62Smrg    long stride = ncoords;
232f220fa62Smrg    for( Knotspec *knotspec = kspec; knotspec; knotspec=knotspec->next ) {
233f220fa62Smrg	knotspec->poststride = (int) stride;
234f220fa62Smrg	stride *= ((knotspec->bend-knotspec->bbegin)*knotspec->order + knotspec->postoffset);
235f220fa62Smrg        knotspec->preoffset  *= knotspec->prestride;
236f220fa62Smrg	knotspec->prewidth  *= knotspec->poststride;
237f220fa62Smrg	knotspec->postwidth *= knotspec->poststride;
238f220fa62Smrg	knotspec->postoffset *= knotspec->poststride;
239f220fa62Smrg        knotspec->ncoords = (int) ncoords;
240f220fa62Smrg    }
241f220fa62Smrg    outcpts = new REAL[stride];
242f220fa62Smrg    assert( outcpts != 0 );
243f220fa62Smrg}
244f220fa62Smrg
245f220fa62Smrg/*-----------------------------------------------------------------------------
246f220fa62Smrg * Splinespec::copy - copy the control points of current subobject
247f220fa62Smrg *
248f220fa62Smrg * Client: gl_quilt_to_bezier
249f220fa62Smrg *-----------------------------------------------------------------------------
250f220fa62Smrg */
251f220fa62Smrg
252f220fa62Smrgvoid
253f220fa62SmrgSplinespec::copy( INREAL *incpts )
254f220fa62Smrg{
255f220fa62Smrg    kspec->copy( incpts, outcpts );
256f220fa62Smrg}
257f220fa62Smrg
258f220fa62Smrg/*-----------------------------------------------------------------------------
259f220fa62Smrg * Splinespec::setupquilt - assign all quilt variables from knotspec
260f220fa62Smrg *
261f220fa62Smrg * Client: gl_quilt_to_bezier
262f220fa62Smrg *-----------------------------------------------------------------------------
263f220fa62Smrg */
264f220fa62Smrg
265f220fa62Smrgvoid
266f220fa62SmrgSplinespec::setupquilt( Quilt_ptr quilt )
267f220fa62Smrg{
268f220fa62Smrg    Quiltspec_ptr qspec = quilt->qspec;
269f220fa62Smrg    quilt->eqspec = qspec + dim;
270f220fa62Smrg    for( Knotspec *knotspec = kspec; knotspec; knotspec=knotspec->next, qspec++ ) {
271f220fa62Smrg	qspec->stride	= knotspec->poststride;
272f220fa62Smrg	qspec->width	= knotspec->bend - knotspec->bbegin;
273f220fa62Smrg	qspec->order	= (int) knotspec->order;
274f220fa62Smrg	qspec->offset	= knotspec->postoffset;
275f220fa62Smrg	qspec->index	= 0;
276f220fa62Smrg	qspec->bdry[0]	= (knotspec->kleft == knotspec->kfirst) ? 1 : 0;
277f220fa62Smrg	qspec->bdry[1]	= (knotspec->kright == knotspec->klast) ? 1 : 0;
278f220fa62Smrg	qspec->breakpoints = new Knot[qspec->width+1];
279f220fa62Smrg	Knot_ptr k =  qspec->breakpoints;
280f220fa62Smrg	for( Breakpt *bk = knotspec->bbegin; bk <= knotspec->bend; bk++ )
281f220fa62Smrg	    *(k++) = bk->value;
282f220fa62Smrg    }
283f220fa62Smrg    quilt->cpts = outcpts;
284f220fa62Smrg    quilt->next = 0;
285f220fa62Smrg}
286f220fa62Smrg
287f220fa62Smrg/*-----------------------------------------------------------------------------
288f220fa62Smrg * Splinespec::transform - convert a spline to Bezier format
289f220fa62Smrg *
290f220fa62Smrg * Client: gl_quilt_to_bezier
291f220fa62Smrg *-----------------------------------------------------------------------------
292f220fa62Smrg */
293f220fa62Smrg
294f220fa62Smrgvoid
295f220fa62SmrgSplinespec::transform( void )
296f220fa62Smrg{
297f220fa62Smrg    Knotspec *knotspec;
298f220fa62Smrg    for( knotspec = kspec; knotspec; knotspec=knotspec->next )
299f220fa62Smrg        knotspec->istransformed = 0;
300f220fa62Smrg
301f220fa62Smrg    for( knotspec = kspec; knotspec; knotspec=knotspec->next ) {
302f220fa62Smrg	for( Knotspec *kspec2 = kspec; kspec2; kspec2=kspec2->next )
303f220fa62Smrg	    kspec2->kspectotrans = knotspec;
304f220fa62Smrg	kspec->transform( outcpts );
305f220fa62Smrg	knotspec->istransformed = 1;
306f220fa62Smrg    }
307f220fa62Smrg}
308f220fa62Smrg
309f220fa62Smrg
310f220fa62Smrg/*-----------------------------------------------------------------------------
311f220fa62Smrg * Knotspec::Knotspec -  constuct a knot spec
312f220fa62Smrg *-----------------------------------------------------------------------------
313f220fa62Smrg */
314f220fa62Smrg
315f220fa62SmrgKnotspec::Knotspec( void )
316f220fa62Smrg{
317f220fa62Smrg    bbegin = 0;
318f220fa62Smrg    sbegin = 0;
319f220fa62Smrg    outkbegin = 0;
320f220fa62Smrg}
321f220fa62Smrg
322f220fa62Smrg/*-----------------------------------------------------------------------------
323f220fa62Smrg * Knotspec::copy -  copy the control points along minor direction
324f220fa62Smrg *
325f220fa62Smrg * Client: Splinespec::copy
326f220fa62Smrg *-----------------------------------------------------------------------------
327f220fa62Smrg */
328f220fa62Smrg
329f220fa62Smrgvoid
330f220fa62SmrgKnotspec::copy( INREAL *inpt, REAL *outpt )
331f220fa62Smrg{
332f220fa62Smrg    inpt = (INREAL *) (((char *) inpt) + preoffset);
333f220fa62Smrg
334f220fa62Smrg    if( next ) {
335f220fa62Smrg        for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride ) {
336f220fa62Smrg	    next->copy( inpt, outpt );
337f220fa62Smrg	    inpt = (INREAL *) (((char *) inpt) + prestride);
338f220fa62Smrg	}
339f220fa62Smrg   } else {
340f220fa62Smrg        for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride ) {
341f220fa62Smrg	    pt_io_copy( outpt, inpt );
342f220fa62Smrg	    inpt = (INREAL *) (((char *) inpt) + prestride);
343f220fa62Smrg	}
344f220fa62Smrg     }
345f220fa62Smrg}
346f220fa62Smrg
347f220fa62Smrg/*-----------------------------------------------------------------------------
348f220fa62Smrg * Knotspec::showpts - print out points before transformation
349f220fa62Smrg *
350f220fa62Smrg * Client: Knotspec::select
351f220fa62Smrg *-----------------------------------------------------------------------------
352f220fa62Smrg */
353f220fa62Smrgvoid
354f220fa62SmrgKnotspec::showpts( REAL *outpt )
355f220fa62Smrg{
356f220fa62Smrg    if( next ) {
357f220fa62Smrg        for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride )
358f220fa62Smrg	    next->showpts( outpt );
359f220fa62Smrg    } else {
360f220fa62Smrg        for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride )
361f220fa62Smrg	    _glu_dprintf(  "show %g %g %g\n", outpt[0], outpt[1], outpt[2] );
362f220fa62Smrg    }
363f220fa62Smrg}
364f220fa62Smrg
365f220fa62Smrg/*-----------------------------------------------------------------------------
366f220fa62Smrg * Knotspec::factors - precompute scale factors
367f220fa62Smrg *	   - overwrites knot vector, actual new knot vector is NOT produced
368f220fa62Smrg *
369f220fa62Smrg * Client: Knotspec::select
370f220fa62Smrg *-----------------------------------------------------------------------------
371f220fa62Smrg */
372f220fa62Smrg
373f220fa62Smrgvoid
374f220fa62SmrgKnotspec::factors( void )
375f220fa62Smrg{
376f220fa62Smrg    Knot *mid = (outkend - 1) - order + bend->multi;
377f220fa62Smrg    Knot_ptr fptr = sbegin;
378f220fa62Smrg
379f220fa62Smrg    for( Breakpt *bpt = bend; bpt >= bbegin; bpt-- ) {
380f220fa62Smrg    	mid -= bpt->multi;		// last knot less than knot to insert
381f220fa62Smrg	int def = bpt->def - 1;		// number of knots to insert
382f220fa62Smrg	if( def <= 0 ) continue;
383f220fa62Smrg	Knot kv = bpt->value;		// knot to insert
384f220fa62Smrg
385f220fa62Smrg	Knot *kf = (mid-def) + (order-1);
386f220fa62Smrg	for( Knot *kl = kf + def; kl != kf; kl-- ) {
387f220fa62Smrg	    Knot *kh, *kt;
388f220fa62Smrg	    for( kt=kl, kh=mid; kt != kf; kh--, kt-- )
389f220fa62Smrg		*(fptr++) = (kv - *kh) / (*kt - *kh);
390f220fa62Smrg	    *kl = kv;
391f220fa62Smrg	}
392f220fa62Smrg    }
393f220fa62Smrg}
394f220fa62Smrg
395f220fa62Smrg/*-----------------------------------------------------------------------------
396f220fa62Smrg * Knotspec::insert - convert subobject in direction of kspec into Bezier
397f220fa62Smrg *
398f220fa62Smrg * Client: Knotspec::transform
399f220fa62Smrg *-----------------------------------------------------------------------------
400f220fa62Smrg */
401f220fa62Smrg
402f220fa62Smrgvoid
403f220fa62SmrgKnotspec::insert( REAL *p )
404f220fa62Smrg{
405f220fa62Smrg    Knot_ptr fptr = sbegin;
406f220fa62Smrg    REAL *srcpt = p + prewidth - poststride;
407f220fa62Smrg    REAL *dstpt = p + postwidth + postoffset - poststride;
408f220fa62Smrg    Breakpt *bpt = bend;
409f220fa62Smrg
410f220fa62Smrg   for( REAL *pend = srcpt - poststride*bpt->def; srcpt != pend; pend +=poststride ) {
411f220fa62Smrg	REAL *p1 = srcpt;
412f220fa62Smrg	for( REAL *p2 = srcpt-poststride; p2 != pend; p1 = p2, p2 -= poststride ) {
413f220fa62Smrg	    pt_oo_sum( p1, p1, p2, *fptr, 1.0-*fptr );
414f220fa62Smrg	    fptr++;
415f220fa62Smrg	}
416f220fa62Smrg    }
417f220fa62Smrg
418f220fa62Smrg    for( --bpt; bpt >= bbegin; bpt-- ) {
419f220fa62Smrg
420f220fa62Smrg	for( int multi = bpt->multi; multi > 0; multi-- ) {
421f220fa62Smrg	    pt_oo_copy( dstpt, srcpt );
422f220fa62Smrg	    dstpt -= poststride;
423f220fa62Smrg	    srcpt -= poststride;
424f220fa62Smrg	}
425f220fa62Smrg
426f220fa62Smrg	for( REAL *pend = srcpt - poststride*bpt->def; srcpt != pend; pend +=poststride, dstpt-=poststride ) {
427f220fa62Smrg	    pt_oo_copy( dstpt, srcpt );
428f220fa62Smrg	    REAL *p1 = srcpt;
429f220fa62Smrg
430f220fa62Smrg	    for( REAL *p2 = srcpt-poststride; p2 != pend; p1=p2, p2 -= poststride ) {
431f220fa62Smrg		pt_oo_sum( p1, p1, p2, *fptr, 1.0-*fptr );
432f220fa62Smrg		fptr++;
433f220fa62Smrg	    }
434f220fa62Smrg	}
435f220fa62Smrg    }
436f220fa62Smrg}
437f220fa62Smrg
438f220fa62Smrg/*-----------------------------------------------------------------------------
439f220fa62Smrg * Knotspec::preselect - initialize kspec for processing
440f220fa62Smrg *
441f220fa62Smrg * Client: Splinespec::select
442f220fa62Smrg *-----------------------------------------------------------------------------
443f220fa62Smrg */
444f220fa62Smrg
445f220fa62Smrgvoid
446f220fa62SmrgKnotspec::preselect( void )
447f220fa62Smrg{
448f220fa62Smrg    Knot kval;
449f220fa62Smrg
450f220fa62Smrg    /* position klast after last knot of "last" breakpoint */
451f220fa62Smrg    for( klast = inkend - order, kval = *klast; klast != inkend; klast++ )
452f220fa62Smrg	if( ! identical( *klast, kval ) ) break;
453f220fa62Smrg
454f220fa62Smrg    /* position kfirst after last knot of "first" breakpoint */
455f220fa62Smrg    for( kfirst = inkbegin+order-1, kval= *kfirst;  kfirst != inkend; kfirst++ )
456f220fa62Smrg	if( ! identical( *kfirst, kval ) ) break;
457f220fa62Smrg
458f220fa62Smrg    /* compute multiplicity of first breakpoint */
459f220fa62Smrg    Knot_ptr k;
460f220fa62Smrg    for( k  = kfirst - 1; k >= inkbegin; k-- )
461f220fa62Smrg	if( ! identical( kval, *k ) ) break;
462f220fa62Smrg    k++;
463f220fa62Smrg
464f220fa62Smrg    /* allocate space for breakpoints -
465f220fa62Smrg       use worst case estimate on number of breakpoints */
466f220fa62Smrg
467f220fa62Smrg    bbegin = new Breakpt[(klast - kfirst)+1];
468f220fa62Smrg    /* record multiplicity and value of first breakpoint */
469f220fa62Smrg    bbegin->multi = kfirst - k;
470f220fa62Smrg    bbegin->value = kval;
471f220fa62Smrg    bend = bbegin;
472f220fa62Smrg
473f220fa62Smrg    kleft = kright = kfirst;
474f220fa62Smrg}
475f220fa62Smrg
476f220fa62Smrg
477f220fa62Smrg/*-----------------------------------------------------------------------------
478f220fa62Smrg * Knotspec::select - Knotspec::select segments and precompute scale factors
479f220fa62Smrg *
480f220fa62Smrg * Client: Splinespec::select
481f220fa62Smrg *-----------------------------------------------------------------------------
482f220fa62Smrg */
483f220fa62Smrg
484f220fa62Smrgvoid
485f220fa62SmrgKnotspec::select( void )
486f220fa62Smrg{
487f220fa62Smrg    breakpoints();
488f220fa62Smrg    knots();
489f220fa62Smrg    factors();
490f220fa62Smrg
491f220fa62Smrg    preoffset	= kleft - (inkbegin + order);
492f220fa62Smrg    postwidth	= (int)((bend - bbegin) * order);
493f220fa62Smrg    prewidth 	= (int)((outkend - outkbegin) - order);
494f220fa62Smrg    postoffset  = (bbegin->def > 1) ? (bbegin->def-1) : 0;
495f220fa62Smrg}
496f220fa62Smrg
497f220fa62Smrg/*-----------------------------------------------------------------------------
498f220fa62Smrg * Knotspec::breakpoints - compute breakpoints for knotspec
499f220fa62Smrg *
500f220fa62Smrg * Client: Knotspec::select
501f220fa62Smrg *-----------------------------------------------------------------------------
502f220fa62Smrg */
503f220fa62Smrg
504f220fa62Smrgvoid
505f220fa62SmrgKnotspec::breakpoints( void )
506f220fa62Smrg{
507f220fa62Smrg    Breakpt *ubpt	= bbegin;
508f220fa62Smrg    Breakpt *ubend	= bend;
509f220fa62Smrg    long    nfactors  	= 0;
510f220fa62Smrg
511f220fa62Smrg    ubpt->value	= ubend->value;
512f220fa62Smrg    ubpt->multi	= ubend->multi;
513f220fa62Smrg
514f220fa62Smrg    kleft = kright;
515f220fa62Smrg
516f220fa62Smrg    for( ; kright != klast; kright++ ) {
517f220fa62Smrg        if ( identical(*kright,ubpt->value) ) {
518f220fa62Smrg	    (ubpt->multi)++;
519f220fa62Smrg	} else {
520f220fa62Smrg    	    ubpt->def = (int) (order - ubpt->multi);
521f220fa62Smrg    	    nfactors += (ubpt->def * (ubpt->def - 1)) / 2;
522f220fa62Smrg	    (++ubpt)->value = *kright;
523f220fa62Smrg	    ubpt->multi = 1;
524f220fa62Smrg	}
525f220fa62Smrg    }
526f220fa62Smrg    ubpt->def = (int) (order - ubpt->multi);
527f220fa62Smrg    nfactors += (ubpt->def * (ubpt->def - 1)) / 2;
528f220fa62Smrg
529f220fa62Smrg    bend = ubpt;
530f220fa62Smrg
531f220fa62Smrg    if( nfactors ) {
532f220fa62Smrg        sbegin = new Knot[nfactors];
533f220fa62Smrg    } else {
534f220fa62Smrg	sbegin = NULL;
535f220fa62Smrg    }
536f220fa62Smrg}
537f220fa62Smrg
538f220fa62Smrg
539f220fa62Smrg/*-----------------------------------------------------------------------------
540f220fa62Smrg * Knotspec::knots - copy relevant subsequence of knots into temporary area
541f220fa62Smrg *
542f220fa62Smrg * Client: Knotspec::select
543f220fa62Smrg *-----------------------------------------------------------------------------
544f220fa62Smrg */
545f220fa62Smrg
546f220fa62Smrgvoid
547f220fa62SmrgKnotspec::knots( void )
548f220fa62Smrg{
549f220fa62Smrg    Knot_ptr inkpt = kleft - order;
550f220fa62Smrg    Knot_ptr inkend = kright  + bend->def;
551f220fa62Smrg
552f220fa62Smrg    /* allocate space for knots and factors */
553f220fa62Smrg    outkbegin = new Knot[inkend-inkpt];
554f220fa62Smrg    Knot_ptr outkpt;
555f220fa62Smrg    for( outkpt = outkbegin; inkpt != inkend; inkpt++, outkpt++ )
556f220fa62Smrg	*outkpt = *inkpt;
557f220fa62Smrg
558f220fa62Smrg    outkend = outkpt;
559f220fa62Smrg}
560f220fa62Smrg
561f220fa62Smrg
562f220fa62Smrg/*-----------------------------------------------------------------------------
563f220fa62Smrg * Knotspec::transform -	convert a spline along a given direction
564f220fa62Smrg *
565f220fa62Smrg * Client: Splienspec::transform
566f220fa62Smrg *-----------------------------------------------------------------------------
567f220fa62Smrg */
568f220fa62Smrg
569f220fa62Smrgvoid
570f220fa62SmrgKnotspec::transform( REAL *p )
571f220fa62Smrg{
572f220fa62Smrg   if( next ) {
573f220fa62Smrg	if( this == kspectotrans ) {
574f220fa62Smrg	    next->transform( p );
575f220fa62Smrg	} else {
576f220fa62Smrg	    if( istransformed ) {
577f220fa62Smrg		p += postoffset;
578f220fa62Smrg		for( REAL *pend = p + postwidth; p != pend; p += poststride )
579f220fa62Smrg		    next->transform( p );
580f220fa62Smrg	    } else {
581f220fa62Smrg		REAL *pend = p + prewidth;
582f220fa62Smrg		for( ; p != pend; p += poststride )
583f220fa62Smrg		    next->transform( p );
584f220fa62Smrg	    }
585f220fa62Smrg	}
586f220fa62Smrg   } else {
587f220fa62Smrg	if( this == kspectotrans ) {
588f220fa62Smrg	    insert( p );
589f220fa62Smrg	} else {
590f220fa62Smrg	    if( istransformed ) {
591f220fa62Smrg		p += postoffset;
592f220fa62Smrg		for( REAL *pend = p + postwidth; p != pend; p += poststride )
593f220fa62Smrg		    kspectotrans->insert( p );
594f220fa62Smrg	    } else {
595f220fa62Smrg		REAL *pend = p + prewidth;
596f220fa62Smrg		for( ; p != pend; p += poststride )
597f220fa62Smrg		    kspectotrans->insert( p );
598f220fa62Smrg	    }
599f220fa62Smrg	}
600f220fa62Smrg   }
601f220fa62Smrg}
602f220fa62Smrg
603f220fa62Smrg/*-----------------------------------------------------------------------------
604f220fa62Smrg * Knotspec::~Knotspec - free space alocated for knotspec
605f220fa62Smrg *-----------------------------------------------------------------------------
606f220fa62Smrg */
607f220fa62Smrg
608f220fa62SmrgKnotspec::~Knotspec( void )
609f220fa62Smrg{
610f220fa62Smrg    if( bbegin ) delete[] bbegin;
611f220fa62Smrg    if( sbegin ) delete[] sbegin;
612f220fa62Smrg    if( outkbegin ) delete[] outkbegin;
613f220fa62Smrg}
614f220fa62Smrg
615f220fa62Smrg
616f220fa62Smrg/*-----------------------------------------------------------------------------
617f220fa62Smrg * pt_io_copy - make internal copy of input cntrl pt. of x coords
618f220fa62Smrg *-----------------------------------------------------------------------------
619f220fa62Smrg */
620f220fa62Smrg
621f220fa62Smrgvoid
622f220fa62SmrgKnotspec::pt_io_copy( REAL *topt, INREAL *frompt )
623f220fa62Smrg{
624f220fa62Smrg    switch( ncoords ) {
625f220fa62Smrg    case 4:
626f220fa62Smrg        topt[3] = (REAL) frompt[3];
627f220fa62Smrg    case 3:
628f220fa62Smrg        topt[2] = (REAL) frompt[2];
629f220fa62Smrg    case 2:
630f220fa62Smrg        topt[1] = (REAL) frompt[1];
631f220fa62Smrg    case 1:
632f220fa62Smrg        topt[0] = (REAL) frompt[0];
633f220fa62Smrg	break;
634f220fa62Smrg    default: {
635f220fa62Smrg	    for( int i = 0; i < ncoords; i++ )
636f220fa62Smrg		*topt++ = (REAL) *frompt++;
637f220fa62Smrg	}
638f220fa62Smrg    }
639f220fa62Smrg}
640f220fa62Smrg
641f220fa62Smrg/*-----------------------------------------------------------------------------
642f220fa62Smrg * pt_oo_copy - make internal copy of internal cntrl pt. of x coords
643f220fa62Smrg *-----------------------------------------------------------------------------
644f220fa62Smrg */
645f220fa62Smrg
646f220fa62Smrgvoid
647f220fa62SmrgKnotspec::pt_oo_copy( REAL *topt, REAL *frompt )
648f220fa62Smrg{
649f220fa62Smrg    switch( ncoords ) {
650f220fa62Smrg    case 4:
651f220fa62Smrg        topt[3] = frompt[3];
652f220fa62Smrg    case 3:
653f220fa62Smrg        topt[2] = frompt[2];
654f220fa62Smrg    case 2:
655f220fa62Smrg        topt[1] = frompt[1];
656f220fa62Smrg    case 1:
657f220fa62Smrg        topt[0] = frompt[0];
658f220fa62Smrg	break;
659f220fa62Smrg    default:
660f220fa62Smrg	memcpy( topt, frompt, ncoords * sizeof( REAL ) );
661f220fa62Smrg    }
662f220fa62Smrg}
663f220fa62Smrg
664f220fa62Smrg/*-----------------------------------------------------------------------------
665f220fa62Smrg * pt_oo_sum - compute affine combination of internal cntrl pts
666f220fa62Smrg *-----------------------------------------------------------------------------
667f220fa62Smrg */
668f220fa62Smrg
669f220fa62Smrgvoid
670f220fa62SmrgKnotspec::pt_oo_sum( REAL *x, REAL *y, REAL *z, Knot a, Knot b )
671f220fa62Smrg{
672f220fa62Smrg    switch( ncoords ) {
673f220fa62Smrg    case 4:
674f220fa62Smrg        x[3] = a * y[3]  +  b * z[3];
675f220fa62Smrg    case 3:
676f220fa62Smrg        x[2] = a * y[2]  +  b * z[2];
677f220fa62Smrg    case 2:
678f220fa62Smrg        x[1] = a * y[1]  +  b * z[1];
679f220fa62Smrg    case 1:
680f220fa62Smrg        x[0] = a * y[0]  +  b * z[0];
681f220fa62Smrg	break;
682f220fa62Smrg    default: {
683f220fa62Smrg          for( int i = 0; i < ncoords; i++ )
684f220fa62Smrg              *x++ = a * *y++   +   b * *z++;
685f220fa62Smrg    }
686f220fa62Smrg    }
687f220fa62Smrg}
688