/* ************************************************************************** description -------------------- copyright : (C) 2001-2002 by Andreas Zehender email : zehender@kde.org ************************************************************************** ************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * **************************************************************************/ #include "pmbicubicpatch.h" #include "pmxmlhelper.h" #include "pmbicubicpatchedit.h" #include "pmmemento.h" #include "pmviewstructure.h" #include "pm3dcontrolpoint.h" #include "pmmath.h" #include const double c_defaultPatchSize = 6.0; const int c_defaultPatchType = 0; const int c_defaultPatchUSteps = 3; const int c_defaultPatchVSteps = 3; const double c_defaultPatchFlatness = 0; const PMVector c_defaultUVVector0 = PMVector( 0.0, 0.0 ); const PMVector c_defaultUVVector1 = PMVector( 1.0, 0.0 ); const PMVector c_defaultUVVector2 = PMVector( 1.0, 1.0 ); const PMVector c_defaultUVVector3 = PMVector( 0.0, 1.0 ); PMDefinePropertyClass( PMBicubicPatch, PMBicubicPatchProperty ); class PMPointProperty : public PMPropertyBase { public: PMPointProperty( ) : PMPropertyBase( "controlPoints", PMVariant::Vector ) { m_index = 0; } virtual int dimensions( ) const { return 1; } virtual void setIndex( int /*dimension*/, int index ) { if( index < 0 || index > 15 ) kdError( PMArea ) << "Illegal index in PMBicubicPatch::PointProperty::setIndex" << endl; else m_index = index; } virtual int size( PMObject* /*object*/, int /*dimension*/ ) const { return 16; } protected: virtual bool setProtected( PMObject* obj, const PMVariant& v ) { PMBicubicPatch* p = ( PMBicubicPatch* ) obj; p->setControlPoint( m_index, v.vectorData( ) ); return true; } virtual PMVariant getProtected( const PMObject* obj ) { const PMBicubicPatch* p = ( const PMBicubicPatch* ) obj; return PMVariant( p->controlPoint( m_index ) ); } private: int m_index; }; class PMUVVectorProperty : public PMPropertyBase { public: PMUVVectorProperty( ) : PMPropertyBase( "uvVectors", PMVariant::Vector ) { m_index = 0; } virtual int dimensions( ) const { return 1; } virtual void setIndex( int /*dimension*/, int index ) { if( index < 0 || index > 3 ) kdError( PMArea ) << "Illegal index in PMBicubicPatch::UVVectorProperty::setIndex" << endl; else m_index = index; } virtual int size( PMObject* /*object*/, int /*dimension*/ ) const { return 3; } protected: virtual bool setProtected( PMObject* obj, const PMVariant& v ) { PMBicubicPatch* p = ( PMBicubicPatch* ) obj; p->setUVVector( m_index, v.vectorData( ) ); return true; } virtual PMVariant getProtected( const PMObject* obj ) { const PMBicubicPatch* p = ( const PMBicubicPatch* ) obj; return PMVariant( p->uvVector( m_index ) ); } private: int m_index; }; PMMetaObject* PMBicubicPatch::s_pMetaObject = 0; PMObject* createNewBicubicPatch( PMPart* part ) { return new PMBicubicPatch( part ); } PMBicubicPatch::PMBicubicPatch( PMPart* part ) : Base( part ) { int x, z; double o = -c_defaultPatchSize / 2.0, s = c_defaultPatchSize / 3.0; m_patchType = c_defaultPatchType; m_numUSteps = c_defaultPatchUSteps; m_numVSteps = c_defaultPatchVSteps; m_flatness = c_defaultPatchFlatness; for( x = 0; x < 4; x++ ) for( z = 0; z < 4; z++ ) m_point[x+z*4] = PMVector( o + s * x, 0, o + s * z ); m_vsUSteps = 0; m_vsVSteps = 0; m_uvEnabled = false; m_uvVectors[0] = c_defaultUVVector0; m_uvVectors[1] = c_defaultUVVector1; m_uvVectors[2] = c_defaultUVVector2; m_uvVectors[3] = c_defaultUVVector3; } PMBicubicPatch::PMBicubicPatch( const PMBicubicPatch& p ) : Base( p ) { int i; m_patchType = p.m_patchType; m_numUSteps = p.m_numUSteps; m_numVSteps = p.m_numVSteps; m_flatness = p.m_flatness; for( i = 0; i < 16; i++ ) m_point[i] = p.m_point[i]; m_vsUSteps = 0; m_vsVSteps = 0; m_uvEnabled = p.m_uvEnabled; for( i = 0; i < 4; ++i ) m_uvVectors[i] = p.m_uvVectors[i]; } PMBicubicPatch::~PMBicubicPatch( ) { } TQString PMBicubicPatch::description( ) const { return i18n( "bicubic patch" ); } void PMBicubicPatch::serialize( TQDomElement& e, TQDomDocument& doc ) const { int i; e.setAttribute( "type", m_patchType ); e.setAttribute( "flatness", m_flatness ); e.setAttribute( "uSteps", m_numUSteps ); e.setAttribute( "vSteps", m_numVSteps ); e.setAttribute( "uvEnabled", m_uvEnabled ); for( i = 0; i < 16; i++ ) e.setAttribute( TQString( "cp%1" ).arg( i ), m_point[i].serializeXML( ) ); for( i = 0; i < 4; ++i ) e.setAttribute( TQString( "uv%1" ).arg( i ), m_uvVectors[i].serializeXML( ) ); Base::serialize( e, doc ); } void PMBicubicPatch::readAttributes( const PMXMLHelper& h ) { int u, v; double o = -c_defaultPatchSize / 2.0, s = c_defaultPatchSize / 3.0; m_patchType = h.intAttribute( "type", c_defaultPatchType ); m_flatness = h.doubleAttribute( "flatness", c_defaultPatchFlatness ); m_numUSteps = h.intAttribute( "uSteps", c_defaultPatchUSteps ); m_numVSteps = h.intAttribute( "vSteps", c_defaultPatchVSteps ); m_uvEnabled = h.boolAttribute( "uvEnabled", m_uvEnabled ); for( v = 0; v < 4; v++ ) for( u = 0; u < 4; u++ ) m_point[u+v*4] = h.vectorAttribute( TQString( "cp%1" ).arg( u+v*4 ), PMVector( o + s * u, 0, o + s * v ) ); m_uvVectors[0] = h.vectorAttribute( "uv0", c_defaultUVVector0 ); m_uvVectors[1] = h.vectorAttribute( "uv1", c_defaultUVVector1 ); m_uvVectors[2] = h.vectorAttribute( "uv2", c_defaultUVVector2 ); m_uvVectors[3] = h.vectorAttribute( "uv3", c_defaultUVVector3 ); Base::readAttributes( h ); } PMMetaObject* PMBicubicPatch::metaObject( ) const { if( !s_pMetaObject ) { s_pMetaObject = new PMMetaObject( "BicubicPatch", Base::metaObject( ), createNewBicubicPatch ); s_pMetaObject->addProperty( new PMBicubicPatchProperty( "patchType", &PMBicubicPatch::setPatchType, &PMBicubicPatch::patchType ) ); s_pMetaObject->addProperty( new PMBicubicPatchProperty( "uSteps", &PMBicubicPatch::setUSteps, &PMBicubicPatch::uSteps ) ); s_pMetaObject->addProperty( new PMBicubicPatchProperty( "vSteps", &PMBicubicPatch::setVSteps, &PMBicubicPatch::vSteps ) ); s_pMetaObject->addProperty( new PMBicubicPatchProperty( "flatness", &PMBicubicPatch::setFlatness, &PMBicubicPatch::flatness ) ); s_pMetaObject->addProperty( new PMBicubicPatchProperty( "uvEnabled", &PMBicubicPatch::enableUV, &PMBicubicPatch::isUVEnabled ) ); s_pMetaObject->addProperty( new PMPointProperty( ) ); s_pMetaObject->addProperty( new PMUVVectorProperty( ) ); } return s_pMetaObject; } void PMBicubicPatch::cleanUp( ) const { if( s_pMetaObject ) { delete s_pMetaObject; s_pMetaObject = 0; } Base::cleanUp( ); } void PMBicubicPatch::setPatchType( int patchType ) { if( ( patchType == 0 ) || ( patchType == 1 ) ) { if( patchType != m_patchType ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMTypeID, m_patchType ); m_patchType = patchType; } } else kdError( PMArea ) << "Wrong type in PMBicubicPatch::setPatchType( )\n"; } void PMBicubicPatch::setFlatness( double flatness ) { if( flatness >= 0.0 ) { if( flatness != m_flatness ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMFlatnessID, m_flatness ); m_flatness = flatness; } } else kdError( PMArea ) << "Flatness has to be >= 0 in PMBicubicPatch::setFlatness( )\n"; } void PMBicubicPatch::setUSteps( int steps ) { if( steps >= 0 ) { if( steps != m_numUSteps ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMUStepsID, m_numUSteps ); m_numUSteps = steps; setViewStructureChanged( ); } } else kdError( PMArea ) << "uSteps has to be >= 0 in PMBicubicPatch::setUSteps( )\n"; } void PMBicubicPatch::setVSteps( int steps ) { if( steps >= 0 ) { if( steps != m_numVSteps ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMVStepsID, m_numVSteps ); m_numVSteps = steps; setViewStructureChanged( ); } } else kdError( PMArea ) << "vSteps has to be >= 0 in PMBicubicPatch::setVSteps( )\n"; } void PMBicubicPatch::setControlPoint( int i, const PMVector& p ) { if( ( i >= 0 ) && ( i <= 15 ) ) { if( p != m_point[i] ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMCP0ID + i, m_point[i] ); m_point[i] = p; setViewStructureChanged( ); } } else kdError( PMArea ) << "Wrong index in PMBicubicPatch::setControlPoint( )\n"; } PMVector PMBicubicPatch::controlPoint( int i ) const { if( ( i >= 0 ) && ( i <= 15 ) ) return m_point[i]; else kdError( PMArea ) << "Wrong index in PMBicubicPatch::controlPoint( )\n"; return PMVector( 0, 0, 0 ); } void PMBicubicPatch::enableUV( bool yes ) { if( yes != m_uvEnabled ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMUVEnabledID, m_uvEnabled ); m_uvEnabled = yes; } } void PMBicubicPatch::setUVVector( int i, const PMVector& v ) { if ( i >= 0 && i < 4 ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMUV0ID + i, m_uvVectors[i] ); m_uvVectors[i] = v; m_uvVectors[i].resize( 2 ); } else kdError( PMArea ) << "Wrong index in PMBicubicPatch::setUVVector\n"; } PMVector PMBicubicPatch::uvVector( int i ) const { if( i >= 0 && i < 4 ) return m_uvVectors[i]; else kdError( PMArea ) << "Wrong index in PMBicubicPatch::uvVector\n"; return PMVector( 0.0, 0.0 ); } PMDialogEditBase* PMBicubicPatch::editWidget( TQWidget* parent ) const { return new PMBicubicPatchEdit( parent ); } void PMBicubicPatch::restoreMemento( PMMemento* s ) { PMMementoDataIterator it( s ); PMMementoData* data; for( ; it.current( ); ++it ) { data = it.current( ); if( data->objectType( ) == s_pMetaObject ) { switch( data->valueID( ) ) { case PMTypeID: setPatchType( data->intData( ) ); break; case PMFlatnessID: setFlatness( data->doubleData( ) ); break; case PMUStepsID: setUSteps( data->intData( ) ); break; case PMVStepsID: setVSteps( data->intData( ) ); break; case PMUVEnabledID: enableUV( data->boolData( ) ); break; default: if( ( data->valueID( ) >= PMCP0ID ) && ( data->valueID( ) <= PMCP15ID ) ) setControlPoint( data->valueID( ) - PMCP0ID, data->vectorData( ) ); else if ( data->valueID( ) >= PMUV0ID && data->valueID( ) <= PMUV3ID ) setUVVector( data->valueID( ) - PMUV0ID, data->vectorData( ) ); else kdError( PMArea ) << "Wrong ID in PMBicubicPatch::restoreMemento\n"; break; } } } Base::restoreMemento( s ); } void PMBicubicPatch::createViewStructure( ) { int u, v, i, j; int uSteps = m_numUSteps, vSteps = m_numVSteps; if( uSteps > 5 ) uSteps = 5; if( vSteps > 5 ) vSteps = 5; if( uSteps < 0 ) uSteps = 0; if( vSteps < 0 ) vSteps = 0; // bugfix: Swap u and v int segmentsU = pmpot( 2, vSteps ); int segmentsV = pmpot( 2, uSteps ); int np = ( segmentsU + 1 ) * ( segmentsV + 1 ); int nl = segmentsU * ( segmentsV + 1 ) + ( segmentsU + 1 ) * segmentsV; int offset = 0; if( !m_pViewStructure ) { m_pViewStructure = new PMViewStructure( np, nl ); m_vsUSteps = uSteps + 1; } else { if( m_pViewStructure->points( ).size( ) != ( unsigned ) np ) m_pViewStructure->points( ).resize( np ); if( m_pViewStructure->lines( ).size( ) != ( unsigned ) nl ) m_pViewStructure->lines( ).resize( nl ); } if( ( m_vsUSteps != uSteps ) || ( m_vsVSteps != vSteps ) ) { PMLineArray& lines = m_pViewStructure->lines( ); int poffset = 0; for( v = 0; v < ( segmentsV + 1 ); v++ ) { for( u = 0; u < segmentsU; u++ ) { lines[offset + u] = PMLine( poffset, poffset + 1 ); poffset++; } poffset++; offset += segmentsU; } poffset = 0; for( v = 0; v < segmentsV; v++ ) { for( u = 0; u < ( segmentsU + 1 ); u++ ) { lines[offset + u] = PMLine( poffset, poffset + segmentsU + 1 ); poffset++; } offset += segmentsU + 1; } m_vsUSteps = uSteps; m_vsVSteps = vSteps; } PMPointArray& points = m_pViewStructure->points( ); offset = 0; double incU = 1.0 / segmentsU; double incV = 1.0 / segmentsV; PMVector* hp[4]; for( v = 0; v < 4; v++ ) hp[v] = new PMVector[segmentsU+1]; PMVector tp[4]; double cu, cv; // points in u direction for( v = 0; v < 4; v++ ) { for( u = 1; u < segmentsU; u++ ) { cu = u * incU; for( i = 0; i < 4; i++ ) tp[i] = m_point[v*4+i]; for( i = 3; i > 0; i-- ) for( j = 0; j < i; j++ ) tp[j] = tp[j] * ( 1 - cu ) + tp[j+1] * cu; hp[v][u] = tp[0]; } hp[v][0] = m_point[v*4]; hp[v][segmentsU] = m_point[v*4+3]; } for( v = 0; v <= segmentsV; v++ ) { cv = v * incV; for( u = 0; u <= segmentsU; u++ ) { for( i = 0; i < 4; i++ ) tp[i] = hp[i][u]; for( i = 3; i > 0; i-- ) for( j = 0; j < i; j++ ) tp[j] = tp[j] * ( 1 - cv ) + tp[j+1] * cv; points[offset] = tp[0]; offset++; } } for( v = 0; v < 4; v++ ) delete[] hp[v]; } void PMBicubicPatch::controlPoints( PMControlPointList& list ) { int u, v; for( v = 0; v < 4; v++ ) for( u = 0; u < 4; u++ ) list.append( new PM3DControlPoint( m_point[u+v*4], u+v*4, i18n( "Point (%1, %2)" ).arg( u ).arg( v ) ) ); } void PMBicubicPatch::controlPointsChanged( PMControlPointList& list ) { PMControlPoint* p; for( p = list.first( ); p; p = list.next( ) ) { if( p->changed( ) ) { setControlPoint( p->id( ), p->position( ) ); } } }