summaryrefslogtreecommitdiffstats
path: root/kpovmodeler/pmmesh.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kpovmodeler/pmmesh.cpp')
-rw-r--r--kpovmodeler/pmmesh.cpp557
1 files changed, 557 insertions, 0 deletions
diff --git a/kpovmodeler/pmmesh.cpp b/kpovmodeler/pmmesh.cpp
new file mode 100644
index 00000000..571170a9
--- /dev/null
+++ b/kpovmodeler/pmmesh.cpp
@@ -0,0 +1,557 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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 "pmmesh.h"
+
+#include <klocale.h>
+#include "pmxmlhelper.h"
+#include "pmmeshedit.h"
+#include "pmmemento.h"
+#include "pmtriangle.h"
+#include "pm3dcontrolpoint.h"
+#include "pmvectorcontrolpoint.h"
+
+const PMVector insideVectorDefault = PMVector( 0.0, 0.0, 0.0 );
+
+PMDefinePropertyClass( PMMesh, PMMeshProperty );
+
+class PMMeshMemento : public PMMemento
+{
+public:
+ /**
+ * Creates a memento for the object originator
+ */
+ PMMeshMemento( PMObject* originator ) : PMMemento( originator )
+ {
+ m_bTriangleMementosSaved = false;
+ m_triangleMementos.setAutoDelete( true );
+ }
+ /**
+ * Deletes the memento
+ */
+ virtual ~PMMeshMemento( )
+ {
+ m_triangleMementos.clear( );
+ }
+
+ /**
+ * Saves the triangles memento data
+ */
+ void setTriangleMementos( const QPtrList<PMMemento>& list )
+ {
+ if ( !m_bTriangleMementosSaved )
+ {
+ QPtrListIterator<PMMemento> Itr( list );
+ PMMemento* m;
+ while( ( m = Itr.current( ) ) != 0 )
+ {
+ m_triangleMementos.append( m );
+ ++Itr;
+ }
+
+ m_bTriangleMementosSaved = true;
+ addChange( PMCData );
+ }
+ }
+ /**
+ * Returns the triangles memento data
+ */
+ QPtrList<PMMemento> triangleMementos( ) const
+ {
+ if ( !m_bTriangleMementosSaved )
+ kdError( PMArea ) << "Triangles mementos not saved in PMMeshMemento::triangleMementos\n";
+ return m_triangleMementos;
+ }
+ /**
+ * Returns true if the triangle mementos have been saved
+ */
+ bool triangleMementosSaved( ) const { return m_bTriangleMementosSaved; }
+private:
+ QPtrList<PMMemento> m_triangleMementos;
+ bool m_bTriangleMementosSaved;
+};
+
+PMMetaObject* PMMesh::s_pMetaObject = 0;
+PMObject* createNewMesh( PMPart* part )
+{
+ return new PMMesh( part );
+}
+
+PMMesh::PMMesh( PMPart* part )
+ : Base( part )
+{
+ m_hierarchy = true;
+ m_enableInsideVector = false;
+ m_insideVector = insideVectorDefault;
+}
+
+PMMesh::PMMesh( const PMMesh& m )
+ : Base( m )
+{
+ m_hierarchy = m.m_hierarchy;
+ m_enableInsideVector = m.m_enableInsideVector;
+ m_insideVector = m.m_insideVector;
+}
+
+PMMesh::~PMMesh( )
+{
+}
+
+QString PMMesh::description( ) const
+{
+ return i18n( "mesh" );
+}
+
+void PMMesh::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "hierarchy", m_hierarchy );
+ e.setAttribute( "enable_inside_vector", m_enableInsideVector );
+ e.setAttribute( "inside_vector", m_insideVector.serializeXML( ) );
+ Base::serialize( e, doc );
+}
+
+void PMMesh::readAttributes( const PMXMLHelper& h )
+{
+ m_hierarchy = h.boolAttribute( "hierarchy", true );
+ m_enableInsideVector = h.boolAttribute( "enable_inside_vector", false );
+ m_insideVector = h.vectorAttribute( "inside_vector", insideVectorDefault );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMMesh::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Mesh", Base::metaObject( ), createNewMesh );
+
+ s_pMetaObject->addProperty(
+ new PMMeshProperty( "hierarchy", &PMMesh::setHierarchy, &PMMesh::hierarchy ) );
+ s_pMetaObject->addProperty(
+ new PMMeshProperty( "insideVectorEnabled", &PMMesh::enableInsideVector, &PMMesh::isInsideVectorEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMMeshProperty( "insideVector", &PMMesh::setInsideVector, &PMMesh::insideVector ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMMesh::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMMesh::setHierarchy( bool h )
+{
+ if( h != m_hierarchy )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMHierarchyID, m_hierarchy );
+ m_hierarchy = h;
+ }
+}
+
+void PMMesh::enableInsideVector( bool eiv )
+{
+ if( eiv != m_enableInsideVector )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableInsideVectorID, m_enableInsideVector );
+ m_enableInsideVector = eiv;
+ }
+}
+
+void PMMesh::setInsideVector( const PMVector& iv )
+{
+ if( iv != m_insideVector )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMInsideVectorID, m_insideVector );
+ m_insideVector = iv;
+ }
+}
+
+PMDialogEditBase* PMMesh::editWidget( QWidget* parent ) const
+{
+ return new PMMeshEdit( parent );
+}
+
+void PMMesh::createMemento( )
+{
+ delete m_pMemento;
+ m_pMemento = new PMMeshMemento( this );
+}
+
+void PMMesh::restoreMemento( PMMemento* s )
+{
+ PMMeshMemento* m = ( PMMeshMemento * ) s;
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMHierarchyID:
+ setHierarchy( data->boolData( ) );
+ break;
+ case PMEnableInsideVectorID:
+ enableInsideVector( data->boolData( ) );
+ break;
+ case PMInsideVectorID:
+ setInsideVector( data->vectorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMMesh::restoreMemento\n";
+ break;
+ }
+ }
+ }
+
+ if ( m->triangleMementosSaved( ) )
+ {
+ int numChildren = countChildren( );
+ PMMemento* tm;
+ QPtrList<PMMemento> list = m->triangleMementos( );
+ QPtrListIterator<PMMemento> Itr( list );
+ for ( int i = 0; i < numChildren && ( tm = Itr.current( ) ) != 0; ++i, ++Itr )
+ childAt( i )->restoreMemento( tm );
+ }
+
+ Base::restoreMemento( s );
+}
+
+void PMMesh::controlPoints( PMControlPointList& list )
+{
+ unsigned numChildren = countChildren();
+ PMTriangle *obj;
+ pointToPoint ptp;
+ bool found;
+ PMVector point, normal;
+ PMControlPoint* listP;
+ PM3DControlPoint* cp;
+ PMVectorControlPoint* vp;
+ int currentPoint = 0;
+ int firstNormal = numChildren * 3;
+ int currentNormal = firstNormal;
+
+ m_pointToPointList.clear( );
+ for ( unsigned i = 0; i < numChildren; ++i )
+ {
+ if ( childAt( i )->isA( "Triangle" ) )
+ {
+
+ obj = ( PMTriangle * ) childAt( i );
+ ptp.object = obj;
+ for ( unsigned j = 0; j < 3; ++j )
+ {
+ found = false;
+ ptp.pointID = j;
+ point = obj->point( j );
+
+ for( listP = list.first( ); listP; listP = list.next( ) )
+ {
+ if ( listP->id( ) < firstNormal && point == listP->position( ) )
+ {
+ found = true;
+ ptp.listID = listP->id( );
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ cp = new PM3DControlPoint( point, currentPoint,
+ i18n( "Mesh Point " + currentPoint ) );
+ list.append( cp );
+ ptp.listID = currentPoint++;
+ }
+
+ m_pointToPointList.append( ptp );
+
+ if ( obj->isSmoothTriangle( ) )
+ {
+ found = false;
+ ptp.pointID = j + 3;
+ normal = obj->normal( j );
+
+ for ( listP = list.first( ); listP; listP = list.next( ) )
+ {
+ if ( listP->id( ) >= firstNormal )
+ {
+ vp = ( PMVectorControlPoint* ) listP;
+ if ( vp->basePoint( ) == point &&
+ vp->vector( ) == normal )
+ {
+ found = true;
+ ptp.listID = listP->id( );
+ break;
+ }
+ }
+ }
+
+ if ( !found )
+ {
+ vp = new PMVectorControlPoint( point, normal, currentNormal,
+ i18n( "Mesh Normal " + currentNormal ) );
+ list.append( vp );
+ ptp.listID = currentNormal++;
+ }
+
+ m_pointToPointList.append( ptp );
+ }
+
+ }
+ }
+ }
+}
+
+void PMMesh::controlPointsChangedList( PMControlPointList& list, PMObjectList& objList )
+{
+ int numChildren = countChildren( );
+ PMControlPoint* p;
+ QValueList<pointToPoint>::ConstIterator ptpItr = m_pointToPointList.begin( );
+ QPtrList<PMMemento> mementoList;
+ PMTriangle *obj;
+ PMVector p0, p1, p2;
+ PM3DControlPoint* cp0, * cp1, * cp2;
+ bool bp0, bp1, bp2;
+ PMVector n0, n1, n2;
+ PMVectorControlPoint* cn0, * cn1, * cn2;
+ bool bn0, bn1, bn2;
+ PMVector triangleNormal;
+ double d, normalDirection = 1.0;
+ bool found, validNormal, validTriangles = true;
+ int listID, pointID, numCP;
+
+ // have to cache changed values because checking once changes them to false
+ QMemArray<bool> changed( list.count( ) );
+ p = list.first( );
+ for ( int i = 0; p; ++i, p = list.next( ) )
+ changed[i] = p->changed( );
+
+ for ( int i = 0; i < numChildren && validTriangles; ++i )
+ {
+ if ( childAt( i )->isA( "Triangle" ) )
+ {
+ obj = ( PMTriangle* )childAt( i );
+ obj->createMemento( );
+ objList.append( obj );
+ validNormal = false;
+
+ if ( obj->isSmoothTriangle( ) )
+ numCP = 6;
+ else
+ numCP = 3;
+
+ cp0 = cp1 = cp2 = 0;
+ cn0 = cn1 = cn2 = 0;
+
+ bp0 = bp1 = bp2 = bn0 = bn1 = bn2 = false;
+
+ for ( int j = 0; j < numCP; ++j, ++ptpItr )
+ {
+
+ listID = (*ptpItr).listID;
+ pointID = (*ptpItr).pointID;
+ found = false;
+ p = list.first( );
+ for ( int k = 0; p && !found; p = list.next( ), ++k )
+ {
+ if( listID == p->id( ) )
+ {
+ switch( pointID )
+ {
+ case 0:
+ cp0 = ( PM3DControlPoint* ) p;
+ p0 = cp0->point( );
+ bp0 = changed[ k ];
+ break;
+ case 1:
+ cp1 = ( PM3DControlPoint* ) p;
+ p1 = cp1->point( );
+ bp1 = changed[ k ];
+ break;
+ case 2:
+ cp2 = ( PM3DControlPoint* ) p;
+ p2 = cp2->point( );
+ bp2 = changed[ k ];
+ break;
+ case 3:
+ cn0 = ( PMVectorControlPoint* ) p;
+ n0 = cn0->vector( );
+ bn0 = changed[ k ];
+ break;
+ case 4:
+ cn1 = ( PMVectorControlPoint* ) p;
+ n1 = cn1->vector( );
+ bn1 = changed[ k ];
+ break;
+ case 5:
+ cn2 = ( PMVectorControlPoint* ) p;
+ n2 = cn2->vector( );
+ bn2 = changed[ k ];
+ break;
+ default:
+ break;
+ }
+ found = true;
+ }
+ }
+ }
+
+ if ( obj->isSmoothTriangle( ) )
+ {
+ triangleNormal = PMVector::cross( obj->point( 1 ) - obj->point( 0 ),
+ obj->point( 2 ) - obj->point( 0 ) );
+ normalDirection = PMVector::dot( triangleNormal, obj->normal( 0 ) );
+ if( approxZero( normalDirection ) )
+ normalDirection = PMVector::dot( triangleNormal, obj->normal( 1 ) );
+ if( approxZero( normalDirection ) )
+ normalDirection = PMVector::dot( triangleNormal, obj->normal( 2 ) );
+ if( normalDirection < 0 )
+ triangleNormal = -triangleNormal;
+ if( !approxZero( triangleNormal.abs( ) ) )
+ {
+ validNormal = true;
+ triangleNormal /= triangleNormal.abs( );
+ }
+ }
+
+ if ( bp0 )
+ {
+ if ( !( p0.approxEqual( p1 ) || p0.approxEqual( p2 ) ) )
+ obj->setPoint( 0, p0 );
+ else
+ {
+ validTriangles = false;
+ cp0->setPoint( obj->point( 0 ) );
+ break;
+ }
+ }
+
+ if ( bp1 )
+ {
+ if ( !( p1.approxEqual( p0 ) || p1.approxEqual( p2 ) ) )
+ obj->setPoint( 1, p1 );
+ else
+ {
+ validTriangles = false;
+ cp1->setPoint( obj->point( 1 ) );
+ break;
+ }
+ }
+
+ if ( bp2 )
+ {
+ if ( !( p2.approxEqual( p0 ) || p2.approxEqual( p1 ) ) )
+ obj->setPoint( 2, p2 );
+ else
+ {
+ validTriangles = false;
+ cp2->setPoint( obj->point( 2 ) );
+ break;
+ }
+ }
+
+ if ( obj->isSmoothTriangle( ) )
+ {
+ if ( bn0 )
+ {
+ if( validNormal )
+ {
+ d = PMVector::dot( triangleNormal, n0 );
+ if( d > 0 )
+ obj->setNormal( 0, n0 );
+ else
+ {
+ obj->setNormal( 0, n0 - ( d - 1e-5 ) * triangleNormal );
+ cn0->setVector( obj->normal( 0 ) );
+ }
+ }
+ else
+ cn0->setVector( obj->normal( 0 ) );
+ }
+
+ if ( bn1 )
+ {
+ if( validNormal )
+ {
+ d = PMVector::dot( triangleNormal, n1 );
+ if( d > 0 )
+ obj->setNormal( 1, n1 );
+ else
+ {
+ obj->setNormal( 1, n1 - ( d - 1e-5 ) * triangleNormal );
+ cn1->setVector( obj->normal( 1 ) );
+ }
+ }
+ else
+ cn1->setVector( obj->normal( 1 ) );
+ }
+
+ if ( bn2 )
+ {
+ if( validNormal )
+ {
+ d = PMVector::dot( triangleNormal, n2 );
+ if( d > 0 )
+ obj->setNormal( 2, n2 );
+ else
+ {
+ obj->setNormal( 2, n2 - ( d - 1e-5 ) * triangleNormal );
+ cn2->setVector( obj->normal( 2 ) );
+ }
+ }
+ else
+ cn2->setVector( obj->normal( 2 ) );
+ }
+ }
+
+ mementoList.append( obj->takeMemento( ) );
+
+ if ( !validTriangles )
+ {
+ PMMemento *tm;
+ for ( int j = i; j >= 0; --j )
+ {
+ if ( ( tm = mementoList.getLast( ) ) )
+ {
+ childAt( j )->restoreMemento( tm );
+ delete tm;
+ mementoList.removeLast( );
+ }
+ }
+ }
+ }
+ }
+
+ if ( validTriangles )
+ {
+ if ( m_pMemento )
+ ( ( PMMeshMemento * ) m_pMemento )->setTriangleMementos( mementoList );
+ objList.append( this );
+ setViewStructureChanged( );
+ }
+}