#include "glimports.h"
#include "myassert.h"
#include "mystdio.h"
#include "mystring.h"
#include "quilt.h"
#include "knotvector.h"
struct Breakpt {
Knot value;
int multi;
int def;
};
struct Knotspec {
long order;
Knot_ptr inkbegin;
Knot_ptr inkend;
Knot_ptr outkbegin;
Knot_ptr outkend;
Knot_ptr kleft;
Knot_ptr kright;
Knot_ptr kfirst;
Knot_ptr klast;
Knot_ptr sbegin;
Breakpt * bbegin;
Breakpt * bend;
int ncoords;
int prestride;
int poststride;
int preoffset;
int postoffset;
int prewidth;
int postwidth;
int istransformed;
Knotspec * next;
Knotspec * kspectotrans;
Knotspec( void );
~Knotspec( void );
void factors( void );
void insert( REAL * );
void preselect();
void select( void );
void copy( INREAL *, REAL * );
void breakpoints( void );
void knots( void );
void transform( REAL * );
void showpts( REAL * );
void pt_io_copy( REAL *, INREAL * );
void pt_oo_copy( REAL *, REAL * );
void pt_oo_sum( REAL*, REAL*, REAL*, Knot, Knot );
};
struct Splinespec {
Splinespec( int );
~Splinespec(void);
Knotspec *kspec;
int dim;
REAL * outcpts;
void kspecinit( Knotvector & );
void kspecinit( Knotvector &, Knotvector & );
void select( void );
void layout( long );
void setupquilt( Quilt_ptr );
void copy( INREAL * );
void transform( void );
};
void
Quilt::toBezier(
Knotvector& knotvector,
INREAL *ctlpts,
long ncoords )
{
Splinespec spline( 1 );
spline.kspecinit( knotvector );
spline.select();
spline.layout( ncoords );
spline.setupquilt( this );
spline.copy( ctlpts );
spline.transform();
}
void
Quilt::toBezier(
Knotvector& sknotvector,
Knotvector& tknotvector,
INREAL *ctlpts,
long ncoords )
{
Splinespec spline( 2 );
spline.kspecinit( sknotvector, tknotvector );
spline.select();
spline.layout( ncoords );
spline.setupquilt( this );
spline.copy( ctlpts );
spline.transform();
}
Splinespec::Splinespec( int dimen )
{
dim = dimen;
}
Splinespec::~Splinespec( void )
{
Knotspec *ktrav= kspec; while (ktrav != 0) { Knotspec *deleteThis= ktrav; ktrav= ktrav->next; delete deleteThis; }
}
void
Splinespec::kspecinit( Knotvector& knotvector )
{
kspec = new Knotspec;
kspec->inkbegin = knotvector.knotlist;
kspec->inkend = knotvector.knotlist + knotvector.knotcount;
kspec->prestride = (int) knotvector.stride;
kspec->order = knotvector.order;
kspec->next = NULL;
}
void
Splinespec::kspecinit( Knotvector& sknotvector, Knotvector& tknotvector )
{
kspec = new Knotspec;
Knotspec *tkspec = new Knotspec;
kspec->inkbegin = sknotvector.knotlist;
kspec->inkend = sknotvector.knotlist + sknotvector.knotcount;
kspec->prestride = (int) sknotvector.stride;
kspec->order = sknotvector.order;
kspec->next = tkspec;
tkspec->inkbegin = tknotvector.knotlist;
tkspec->inkend = tknotvector.knotlist + tknotvector.knotcount;
tkspec->prestride = (int) tknotvector.stride;
tkspec->order = tknotvector.order;
tkspec->next = NULL;
}
void
Splinespec::select( )
{
for( Knotspec *knotspec = kspec; knotspec; knotspec = knotspec->next ) {
knotspec->preselect();
knotspec->select();
}
}
void
Splinespec::layout( long ncoords )
{
long stride = ncoords;
for( Knotspec *knotspec = kspec; knotspec; knotspec=knotspec->next ) {
knotspec->poststride = (int) stride;
stride *= ((knotspec->bend-knotspec->bbegin)*knotspec->order + knotspec->postoffset);
knotspec->preoffset *= knotspec->prestride;
knotspec->prewidth *= knotspec->poststride;
knotspec->postwidth *= knotspec->poststride;
knotspec->postoffset *= knotspec->poststride;
knotspec->ncoords = (int) ncoords;
}
outcpts = new REAL[stride];
assert( outcpts != 0 );
}
void
Splinespec::copy( INREAL *incpts )
{
kspec->copy( incpts, outcpts );
}
void
Splinespec::setupquilt( Quilt_ptr quilt )
{
Quiltspec_ptr qspec = quilt->qspec;
quilt->eqspec = qspec + dim;
for( Knotspec *knotspec = kspec; knotspec; knotspec=knotspec->next, qspec++ ) {
qspec->stride = knotspec->poststride;
qspec->width = knotspec->bend - knotspec->bbegin;
qspec->order = (int) knotspec->order;
qspec->offset = knotspec->postoffset;
qspec->index = 0;
qspec->bdry[0] = (knotspec->kleft == knotspec->kfirst) ? 1 : 0;
qspec->bdry[1] = (knotspec->kright == knotspec->klast) ? 1 : 0;
qspec->breakpoints = new Knot[qspec->width+1];
Knot_ptr k = qspec->breakpoints;
for( Breakpt *bk = knotspec->bbegin; bk <= knotspec->bend; bk++ )
*(k++) = bk->value;
}
quilt->cpts = outcpts;
quilt->next = 0;
}
void
Splinespec::transform( void )
{
Knotspec *knotspec;
for( knotspec = kspec; knotspec; knotspec=knotspec->next )
knotspec->istransformed = 0;
for( knotspec = kspec; knotspec; knotspec=knotspec->next ) {
for( Knotspec *kspec2 = kspec; kspec2; kspec2=kspec2->next )
kspec2->kspectotrans = knotspec;
kspec->transform( outcpts );
knotspec->istransformed = 1;
}
}
Knotspec::Knotspec( void )
{
bbegin = 0;
sbegin = 0;
outkbegin = 0;
}
void
Knotspec::copy( INREAL *inpt, REAL *outpt )
{
inpt = (INREAL *) (((char *) inpt) + preoffset);
if( next ) {
for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride ) {
next->copy( inpt, outpt );
inpt = (INREAL *) (((char *) inpt) + prestride);
}
} else {
for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride ) {
pt_io_copy( outpt, inpt );
inpt = (INREAL *) (((char *) inpt) + prestride);
}
}
}
void
Knotspec::showpts( REAL *outpt )
{
if( next ) {
for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride )
next->showpts( outpt );
} else {
for( REAL *lpt=outpt+prewidth; outpt != lpt; outpt += poststride )
_glu_dprintf( "show %g %g %g\n", outpt[0], outpt[1], outpt[2] );
}
}
void
Knotspec::factors( void )
{
Knot *mid = (outkend - 1) - order + bend->multi;
Knot_ptr fptr = sbegin;
for( Breakpt *bpt = bend; bpt >= bbegin; bpt-- ) {
mid -= bpt->multi; int def = bpt->def - 1; if( def <= 0 ) continue;
Knot kv = bpt->value;
Knot *kf = (mid-def) + (order-1);
for( Knot *kl = kf + def; kl != kf; kl-- ) {
Knot *kh, *kt;
for( kt=kl, kh=mid; kt != kf; kh--, kt-- )
*(fptr++) = (kv - *kh) / (*kt - *kh);
*kl = kv;
}
}
}
void
Knotspec::insert( REAL *p )
{
Knot_ptr fptr = sbegin;
REAL *srcpt = p + prewidth - poststride;
REAL *dstpt = p + postwidth + postoffset - poststride;
Breakpt *bpt = bend;
for( REAL *pend = srcpt - poststride*bpt->def; srcpt != pend; pend +=poststride ) {
REAL *p1 = srcpt;
for( REAL *p2 = srcpt-poststride; p2 != pend; p1 = p2, p2 -= poststride ) {
pt_oo_sum( p1, p1, p2, *fptr, 1.0-*fptr );
fptr++;
}
}
for( --bpt; bpt >= bbegin; bpt-- ) {
for( int multi = bpt->multi; multi > 0; multi-- ) {
pt_oo_copy( dstpt, srcpt );
dstpt -= poststride;
srcpt -= poststride;
}
for( REAL *pend = srcpt - poststride*bpt->def; srcpt != pend; pend +=poststride, dstpt-=poststride ) {
pt_oo_copy( dstpt, srcpt );
REAL *p1 = srcpt;
for( REAL *p2 = srcpt-poststride; p2 != pend; p1=p2, p2 -= poststride ) {
pt_oo_sum( p1, p1, p2, *fptr, 1.0-*fptr );
fptr++;
}
}
}
}
void
Knotspec::preselect( void )
{
Knot kval;
for( klast = inkend - order, kval = *klast; klast != inkend; klast++ )
if( ! identical( *klast, kval ) ) break;
for( kfirst = inkbegin+order-1, kval= *kfirst; kfirst != inkend; kfirst++ )
if( ! identical( *kfirst, kval ) ) break;
Knot_ptr k;
for( k = kfirst - 1; k >= inkbegin; k-- )
if( ! identical( kval, *k ) ) break;
k++;
bbegin = new Breakpt[(klast - kfirst)+1];
bbegin->multi = kfirst - k;
bbegin->value = kval;
bend = bbegin;
kleft = kright = kfirst;
}
void
Knotspec::select( void )
{
breakpoints();
knots();
factors();
preoffset = kleft - (inkbegin + order);
postwidth = (int)((bend - bbegin) * order);
prewidth = (int)((outkend - outkbegin) - order);
postoffset = (bbegin->def > 1) ? (bbegin->def-1) : 0;
}
void
Knotspec::breakpoints( void )
{
Breakpt *ubpt = bbegin;
Breakpt *ubend = bend;
long nfactors = 0;
ubpt->value = ubend->value;
ubpt->multi = ubend->multi;
kleft = kright;
for( ; kright != klast; kright++ ) {
if ( identical(*kright,ubpt->value) ) {
(ubpt->multi)++;
} else {
ubpt->def = (int) (order - ubpt->multi);
nfactors += (ubpt->def * (ubpt->def - 1)) / 2;
(++ubpt)->value = *kright;
ubpt->multi = 1;
}
}
ubpt->def = (int) (order - ubpt->multi);
nfactors += (ubpt->def * (ubpt->def - 1)) / 2;
bend = ubpt;
if( nfactors ) {
sbegin = new Knot[nfactors];
} else {
sbegin = NULL;
}
}
void
Knotspec::knots( void )
{
Knot_ptr inkpt = kleft - order;
Knot_ptr inkend = kright + bend->def;
outkbegin = new Knot[inkend-inkpt];
Knot_ptr outkpt;
for( outkpt = outkbegin; inkpt != inkend; inkpt++, outkpt++ )
*outkpt = *inkpt;
outkend = outkpt;
}
void
Knotspec::transform( REAL *p )
{
if( next ) {
if( this == kspectotrans ) {
next->transform( p );
} else {
if( istransformed ) {
p += postoffset;
for( REAL *pend = p + postwidth; p != pend; p += poststride )
next->transform( p );
} else {
REAL *pend = p + prewidth;
for( ; p != pend; p += poststride )
next->transform( p );
}
}
} else {
if( this == kspectotrans ) {
insert( p );
} else {
if( istransformed ) {
p += postoffset;
for( REAL *pend = p + postwidth; p != pend; p += poststride )
kspectotrans->insert( p );
} else {
REAL *pend = p + prewidth;
for( ; p != pend; p += poststride )
kspectotrans->insert( p );
}
}
}
}
Knotspec::~Knotspec( void )
{
if( bbegin ) delete[] bbegin;
if( sbegin ) delete[] sbegin;
if( outkbegin ) delete[] outkbegin;
}
void
Knotspec::pt_io_copy( REAL *topt, INREAL *frompt )
{
switch( ncoords ) {
case 4:
topt[3] = (REAL) frompt[3];
case 3:
topt[2] = (REAL) frompt[2];
case 2:
topt[1] = (REAL) frompt[1];
case 1:
topt[0] = (REAL) frompt[0];
break;
default: {
for( int i = 0; i < ncoords; i++ )
*topt++ = (REAL) *frompt++;
}
}
}
void
Knotspec::pt_oo_copy( REAL *topt, REAL *frompt )
{
switch( ncoords ) {
case 4:
topt[3] = frompt[3];
case 3:
topt[2] = frompt[2];
case 2:
topt[1] = frompt[1];
case 1:
topt[0] = frompt[0];
break;
default:
memcpy( topt, frompt, ncoords * sizeof( REAL ) );
}
}
void
Knotspec::pt_oo_sum( REAL *x, REAL *y, REAL *z, Knot a, Knot b )
{
switch( ncoords ) {
case 4:
x[3] = a * y[3] + b * z[3];
case 3:
x[2] = a * y[2] + b * z[2];
case 2:
x[1] = a * y[1] + b * z[1];
case 1:
x[0] = a * y[0] + b * z[0];
break;
default: {
for( int i = 0; i < ncoords; i++ )
*x++ = a * *y++ + b * *z++;
}
}
}