/* ************************************************************************** description -------------------- copyright : (C) 2001 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 "pmtriangle.h" #include "pmtriangleedit.h" #include "pmxmlhelper.h" #include "pmmemento.h" #include "pmviewstructure.h" #include "pm3dcontrolpoint.h" #include "pmvectorcontrolpoint.h" #include const PMVector point0Default = PMVector( -1.0, 0.0, 0.0 ); const PMVector point1Default = PMVector( 1.0, 0.0, 0.0 ); const PMVector point2Default = PMVector( 0.0, 0.0, 1.0 ); const PMVector normal0Default = PMVector( 0.0, 1.0, 0.0 ); const PMVector normal1Default = PMVector( 0.0, 1.0, 0.0 ); const PMVector normal2Default = PMVector( 0.0, 1.0, 0.0 ); const PMVector uvVector0Default = PMVector( 0.0, 0.0 ); const PMVector uvVector1Default = PMVector( 1.0, 0.0 ); const PMVector uvVector2Default = PMVector( 0.5, 1.0 ); PMDefinePropertyClass( PMTriangle, PMTriangleProperty ); class PMPointProperty : public PMPropertyBase { public: PMPointProperty( ) : PMPropertyBase( "points", PMVariant::Vector ) { m_index = 0; } virtual int dimensions( ) const { return 1; } virtual void setIndex( int /*dimension*/, int index ) { if( index < 0 || index > 2 ) kdError( PMArea ) << "Illegal index in PMTriangle::PointProperty::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 ) { PMTriangle* p = ( PMTriangle* ) obj; p->setPoint( m_index, v.vectorData( ) ); return true; } virtual PMVariant getProtected( const PMObject* obj ) { const PMTriangle* p = ( const PMTriangle* ) obj; return PMVariant( p->point( m_index ) ); } private: int m_index; }; class PMNormalProperty : public PMPropertyBase { public: PMNormalProperty( ) : PMPropertyBase( "normals", PMVariant::Vector ) { m_index = 0; } virtual int dimensions( ) const { return 1; } virtual void setIndex( int /*dimension*/, int index ) { if( index < 0 || index > 2 ) kdError( PMArea ) << "Illegal index in PMTriangle::NormalProperty::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 ) { PMTriangle* p = ( PMTriangle* ) obj; p->setNormal( m_index, v.vectorData( ) ); return true; } virtual PMVariant getProtected( const PMObject* obj ) { const PMTriangle* p = ( const PMTriangle* ) obj; return PMVariant( p->normal( 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 > 2 ) kdError( PMArea ) << "Illegal index in PMTriangle::UVVectorProperty::setIndex" << endl; else m_index = index; } virtual int size( PMObject* /*object*/, int /*dimension*/ ) const { return 2; } protected: virtual bool setProtected( PMObject* obj, const PMVariant& v ) { PMTriangle* p = ( PMTriangle* ) obj; p->setUVVector( m_index, v.vectorData( ) ); return true; } virtual PMVariant getProtected( const PMObject* obj ) { const PMTriangle* p = ( const PMTriangle* ) obj; return PMVariant( p->uvVector( m_index ) ); } private: int m_index; }; PMMetaObject* PMTriangle::s_pMetaObject = 0; PMObject* createNewTriangle( PMPart* part ) { return new PMTriangle( part ); } PMViewStructure* PMTriangle::s_pDefaultViewStructure = 0; PMTriangle::PMTriangle( PMPart* part ) : Base( part ) { m_point[0] = point0Default; m_point[1] = point1Default; m_point[2] = point2Default; m_normal[0] = normal0Default; m_normal[1] = normal1Default; m_normal[2] = normal2Default; m_smooth = false; m_uvVector[0] = uvVector0Default; m_uvVector[1] = uvVector1Default; m_uvVector[2] = uvVector2Default; m_uvEnabled = false; } PMTriangle::PMTriangle( const PMTriangle& t ) : Base( t ) { int i; for( i = 0; i < 3; i++ ) { m_point[i] = t.m_point[i]; m_normal[i] = t.m_normal[i]; m_uvVector[i] = t.m_uvVector[i]; } m_smooth = t.m_smooth; m_uvEnabled = t.m_uvEnabled; } PMTriangle::~PMTriangle( ) { } TQString PMTriangle::description( ) const { if( m_smooth ) return i18n( "smooth triangle" ); return i18n( "triangle" ); } void PMTriangle::serialize( TQDomElement& e, TQDomDocument& doc ) const { e.setAttribute( "point0", m_point[0].serializeXML( ) ); e.setAttribute( "point1", m_point[1].serializeXML( ) ); e.setAttribute( "point2", m_point[2].serializeXML( ) ); e.setAttribute( "normal0", m_normal[0].serializeXML( ) ); e.setAttribute( "normal1", m_normal[1].serializeXML( ) ); e.setAttribute( "normal2", m_normal[2].serializeXML( ) ); e.setAttribute( "smooth", m_smooth ); e.setAttribute( "uvVector0", m_uvVector[0].serializeXML( ) ); e.setAttribute( "uvVector1", m_uvVector[1].serializeXML( ) ); e.setAttribute( "uvVector2", m_uvVector[2].serializeXML( ) ); e.setAttribute( "uvEnabled", m_uvEnabled ); Base::serialize( e, doc ); } void PMTriangle::readAttributes( const PMXMLHelper& h ) { m_point[0] = h.vectorAttribute( "point0", point0Default ); m_point[1] = h.vectorAttribute( "point1", point1Default ); m_point[2] = h.vectorAttribute( "point2", point2Default ); m_normal[0] = h.vectorAttribute( "normal0", normal0Default ); m_normal[1] = h.vectorAttribute( "normal1", normal1Default ); m_normal[2] = h.vectorAttribute( "normal2", normal2Default ); m_smooth = h.boolAttribute( "smooth", false ); m_uvVector[0] = h.vectorAttribute( "uvVector0", uvVector0Default ); m_uvVector[1] = h.vectorAttribute( "uvVector1", uvVector1Default ); m_uvVector[2] = h.vectorAttribute( "uvVector2", uvVector2Default ); m_uvEnabled = h.boolAttribute( "uvEnabled", m_uvEnabled ); Base::readAttributes( h ); } PMMetaObject* PMTriangle::metaObject( ) const { if( !s_pMetaObject ) { s_pMetaObject = new PMMetaObject( "Triangle", Base::metaObject( ), createNewTriangle ); s_pMetaObject->addProperty( new PMTriangleProperty( "smooth", &PMTriangle::setSmoothTriangle, &PMTriangle::isSmoothTriangle ) ); s_pMetaObject->addProperty( new PMPointProperty( ) ); s_pMetaObject->addProperty( new PMNormalProperty( ) ); s_pMetaObject->addProperty( new PMUVVectorProperty( ) ); } return s_pMetaObject; } void PMTriangle::setPoint( int i, const PMVector& p ) { if( ( i >= 0 ) && ( i <= 2 ) ) { if( p != m_point[i] ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMPoint0ID + i, m_point[i] ); m_point[i] = p; m_point[i].resize( 3 ); setViewStructureChanged( ); } } else kdError( PMArea ) << "Wrong index in PMTriangle::setPoint\n"; } PMVector PMTriangle::point( int i ) const { if( ( i >= 0 ) && ( i <= 2 ) ) return m_point[i]; else kdError( PMArea ) << "Wrong index in PMTriangle::point\n"; return PMVector( 0.0, 0.0, 0.0 ); } void PMTriangle::setNormal( int i, const PMVector& p ) { if( ( i >= 0 ) && ( i <= 2 ) ) { if( p != m_normal[i] ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMNormal0ID + i, m_normal[i] ); m_normal[i] = p; m_normal[i].resize( 3 ); setViewStructureChanged( ); } } else kdError( PMArea ) << "Wrong index in PMTriangle::setNormal\n"; } PMVector PMTriangle::normal( int i ) const { if( ( i >= 0 ) && ( i <= 2 ) ) return m_normal[i]; else kdError( PMArea ) << "Wrong index in PMTriangle::normal\n"; return PMVector( 0.0, 0.0, 0.0 ); } void PMTriangle::setSmoothTriangle( bool on ) { if( on != m_smooth ) { if( m_pMemento ) { m_pMemento->addData( s_pMetaObject, PMSmoothID, m_smooth ); m_pMemento->setDescriptionChanged( ); } m_smooth = on; setViewStructureChanged( ); } } PMVector PMTriangle::uvVector( int i ) const { if( i >= 0 && i < 3 ) return m_uvVector[i]; else kdError( PMArea ) << "Wrong index in PMTriangle::uvVector\n"; return PMVector( 0.0, 0.0 ); } void PMTriangle::setUVVector( int i, const PMVector& v ) { if( i >= 0 && i < 3 ) { if( v != m_uvVector[i] ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMUVVector0ID + i, m_uvVector[i] ); m_uvVector[i] = v; m_uvVector[i].resize( 2 ); } } else kdError( PMArea ) << "Wrong index in PMTriangle::setNormal\n"; } void PMTriangle::enableUV( bool yes ) { if( yes != m_uvEnabled ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMUVEnabledID, m_uvEnabled ); m_uvEnabled = yes; } } PMDialogEditBase* PMTriangle::editWidget( TQWidget* parent ) const { return new PMTriangleEdit( parent ); } void PMTriangle::restoreMemento( PMMemento* s ) { PMMementoDataIterator it( s ); PMMementoData* data; for( ; it.current( ); ++it ) { data = it.current( ); if( data->objectType( ) == s_pMetaObject ) { switch( data->valueID( ) ) { case PMPoint0ID: setPoint( 0, data->vectorData( ) ); break; case PMPoint1ID: setPoint( 1, data->vectorData( ) ); break; case PMPoint2ID: setPoint( 2, data->vectorData( ) ); break; case PMNormal0ID: setNormal( 0, data->vectorData( ) ); break; case PMNormal1ID: setNormal( 1, data->vectorData( ) ); break; case PMNormal2ID: setNormal( 2, data->vectorData( ) ); break; case PMSmoothID: setSmoothTriangle( data->boolData( ) ); break; case PMUVVector0ID: setUVVector( 0, data->vectorData( ) ); break; case PMUVVector1ID: setUVVector( 1, data->vectorData( ) ); break; case PMUVVector2ID: setUVVector( 2, data->vectorData( ) ); break; case PMUVEnabledID: enableUV( data->boolData( ) ); break; default: kdError( PMArea ) << "Wrong ID in PMTriangle::restoreMemento\n"; break; } } } Base::restoreMemento( s ); } bool PMTriangle::isDefault( ) { if( ( m_point[0] == point0Default ) && ( m_point[1] == point1Default ) && ( m_point[2] == point2Default ) ) return true; return false; } void PMTriangle::createViewStructure( ) { if( !m_pViewStructure ) { m_pViewStructure = new PMViewStructure( defaultViewStructure( ) ); m_pViewStructure->points( ).detach( ); } PMPointArray& points = m_pViewStructure->points( ); points[0] = m_point[0]; points[1] = m_point[1]; points[2] = m_point[2]; } PMViewStructure* PMTriangle::defaultViewStructure( ) const { if( !s_pDefaultViewStructure ) { s_pDefaultViewStructure = new PMViewStructure( 3, 3 ); PMPointArray& points = s_pDefaultViewStructure->points( ); PMLineArray& lines = s_pDefaultViewStructure->lines( ); points[0] = point0Default; points[1] = point1Default; points[2] = point2Default; lines[0] = PMLine( 0, 1 ); lines[1] = PMLine( 1, 2 ); lines[2] = PMLine( 0, 2 ); } return s_pDefaultViewStructure; } void PMTriangle::controlPoints( PMControlPointList& list ) { PM3DControlPoint* cp; cp = new PM3DControlPoint( m_point[0], PMPoint0ID, i18n( "Point 1" ) ); list.append( cp ); if( m_smooth ) list.append( new PMVectorControlPoint( cp, m_normal[0], PMNormal0ID, i18n( "Normal 1" ) ) ); cp = new PM3DControlPoint( m_point[1], PMPoint1ID, i18n( "Point 2" ) ); list.append( cp ); if( m_smooth ) list.append( new PMVectorControlPoint( cp, m_normal[1], PMNormal1ID, i18n( "Normal 2" ) ) ); cp = new PM3DControlPoint( m_point[2], PMPoint2ID, i18n( "Point 3" ) ); list.append( cp ); if( m_smooth ) list.append( new PMVectorControlPoint( cp, m_normal[2], PMNormal2ID, i18n( "Normal 3" ) ) ); } void PMTriangle::controlPointsChanged( PMControlPointList& list ) { PMControlPoint* p; PMVector p0, p1, p2; PMVector n0, n1, n2; double normalDirection = 1.0; PMVector triangleNormal; bool validNormal = false; double d; for( p = list.first( ); p; p = list.next( ) ) { switch( p->id( ) ) { case PMPoint0ID: p0 = ( ( PM3DControlPoint* ) p )->point( ); break; case PMPoint1ID: p1 = ( ( PM3DControlPoint* ) p )->point( ); break; case PMPoint2ID: p2 = ( ( PM3DControlPoint* ) p )->point( ); break; case PMNormal0ID: n0 = ( ( PMVectorControlPoint* ) p )->vector( ); break; case PMNormal1ID: n1 = ( ( PMVectorControlPoint* ) p )->vector( ); break; case PMNormal2ID: n2 = ( ( PMVectorControlPoint* ) p )->vector( ); break; default: break; } } if( m_smooth ) { triangleNormal = PMVector::cross( m_point[1] - m_point[0], m_point[2] - m_point[0] ); normalDirection = PMVector::dot( triangleNormal, m_normal[0] ); if( approxZero( normalDirection ) ) normalDirection = PMVector::dot( triangleNormal, m_normal[1] ); if( approxZero( normalDirection ) ) normalDirection = PMVector::dot( triangleNormal, m_normal[2] ); if( normalDirection < 0 ) triangleNormal = -triangleNormal; if( !approxZero( triangleNormal.abs( ) ) ) { validNormal = true; triangleNormal /= triangleNormal.abs( ); } } for( p = list.first( ); p; p = list.next( ) ) { if( p->changed( ) ) { switch( p->id( ) ) { case PMPoint0ID: if( !( p0.approxEqual( p1 ) || p0.approxEqual( p2 ) ) ) setPoint( 0, p0 ); else ( ( PM3DControlPoint* ) p )->setPoint( m_point[0] ); break; case PMPoint1ID: if( !( p1.approxEqual( p0 ) || p1.approxEqual( p2 ) ) ) setPoint( 1, p1 ); else ( ( PM3DControlPoint* ) p )->setPoint( m_point[1] ); break; case PMPoint2ID: if( !( p2.approxEqual( p0 ) || p2.approxEqual( p1 ) ) ) setPoint( 2, p2 ); else ( ( PM3DControlPoint* ) p )->setPoint( m_point[2] ); break; case PMNormal0ID: if( validNormal ) { d = PMVector::dot( triangleNormal, n0 ); if( d > 0 ) setNormal( 0, n0 ); else { setNormal( 0, n0 - ( d - 1e-5 ) * triangleNormal ); ( ( PMVectorControlPoint* ) p )->setVector( m_normal[0] ); } } else ( ( PMVectorControlPoint* ) p )->setVector( m_normal[0] ); break; case PMNormal1ID: if( validNormal ) { d = PMVector::dot( triangleNormal, n1 ); if( d > 0 ) setNormal( 1, n1 ); else { setNormal( 1, n1 - ( d - 1e-5 ) * triangleNormal ); ( ( PMVectorControlPoint* ) p )->setVector( m_normal[1] ); } } else ( ( PMVectorControlPoint* ) p )->setVector( m_normal[1] ); break; case PMNormal2ID: if( validNormal ) { d = PMVector::dot( triangleNormal, n2 ); if( d > 0 ) setNormal( 2, n2 ); else { setNormal( 2, n2 - ( d - 1e-5 ) * triangleNormal ); ( ( PMVectorControlPoint* ) p )->setVector( m_normal[2] ); } } else ( ( PMVectorControlPoint* ) p )->setVector( m_normal[2] ); break; default: kdError( PMArea ) << "Wrong ID in PMTriangle::controlPointsChanged\n"; break; } } } } void PMTriangle::cleanUp( ) const { if( s_pDefaultViewStructure ) delete s_pDefaultViewStructure; s_pDefaultViewStructure = 0; if( s_pMetaObject ) { delete s_pMetaObject; s_pMetaObject = 0; } Base::cleanUp( ); }