summaryrefslogtreecommitdiffstats
path: root/kpovmodeler/pmsor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kpovmodeler/pmsor.cpp')
-rw-r--r--kpovmodeler/pmsor.cpp708
1 files changed, 708 insertions, 0 deletions
diff --git a/kpovmodeler/pmsor.cpp b/kpovmodeler/pmsor.cpp
new file mode 100644
index 00000000..b7a9f0ef
--- /dev/null
+++ b/kpovmodeler/pmsor.cpp
@@ -0,0 +1,708 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+**************************************************************************
+
+**************************************************************************
+* *
+* 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 "pmsor.h"
+
+#include "pmxmlhelper.h"
+#include "pmsoredit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pmsorcontrolpoint.h"
+#include "pmsplinememento.h"
+#include "pmsorsegment.h"
+#include "pmdefaults.h"
+#include "pmobjectaction.h"
+
+#include <klocale.h>
+
+const int defaultNumberOfPoints = 4;
+const PMVector defaultPoint[defaultNumberOfPoints] =
+{
+ PMVector( 0.0, 0.0 ),
+ PMVector( 0.5, 0.3 ),
+ PMVector( 0.5, 0.7 ),
+ PMVector( 0.0, 1.0 )
+};
+
+const bool defaultSturm = false;
+const bool defaultOpen = false;
+
+int PMSurfaceOfRevolution::s_rSteps = c_defaultSurfaceOfRevolutionRSteps;
+int PMSurfaceOfRevolution::s_sSteps = c_defaultSurfaceOfRevolutionSSteps;
+int PMSurfaceOfRevolution::s_parameterKey = 0;
+PMMetaObject* PMSurfaceOfRevolution::s_pMetaObject = 0;
+PMObject* createNewSurfaceOfRevolution( PMPart* part )
+{
+ return new PMSurfaceOfRevolution( part );
+}
+
+PMDefinePropertyClass( PMSurfaceOfRevolution, PMSurfaceOfRevolutionProperty );
+
+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 )
+ {
+ m_index = index;
+ }
+ virtual int size( PMObject* object, int /*dimension*/ ) const
+ {
+ return ( ( PMSurfaceOfRevolution* ) object )->numberOfPoints( );
+ }
+protected:
+ virtual bool setProtected( PMObject* obj, const PMVariant& var )
+ {
+ PMSurfaceOfRevolution* p = ( PMSurfaceOfRevolution* ) obj;
+ QValueList<PMVector> list = p->points( );
+ QValueList<PMVector>::Iterator it = list.begin( );
+ int i;
+ PMVector v = var.vectorData( );
+ v.resize( 2 );
+
+ for( i = 0; i < m_index && it != list.end( ); ++i )
+ ++it;
+ // expand the list if necessary
+ for( ; i < m_index; ++i )
+ list.insert( it, v );
+ if( it == list.end( ) )
+ it = list.insert( it, v );
+ else
+ *it = v;
+
+ p->setPoints( list );
+ return true;
+ }
+ virtual PMVariant getProtected( const PMObject* obj )
+ {
+ PMSurfaceOfRevolution* p = ( PMSurfaceOfRevolution* ) obj;
+ QValueList<PMVector> list = p->points( );
+ QValueList<PMVector>::ConstIterator it = list.at( m_index );
+
+ if( it == list.end( ) )
+ {
+ kdError( PMArea ) << "Range error in PMSurfaceOfRevolution::PointProperty::get" << endl;
+ return PMVariant( );
+ }
+
+ return PMVariant( *it );
+ }
+
+private:
+ int m_index;
+};
+
+PMSurfaceOfRevolution::PMSurfaceOfRevolution( PMPart* part )
+ : Base( part )
+{
+ int i;
+
+ for( i = 0; i < defaultNumberOfPoints; ++i )
+ m_points.append( defaultPoint[i] );
+ m_sturm = defaultSturm;
+ m_open = defaultOpen;
+}
+
+PMSurfaceOfRevolution::PMSurfaceOfRevolution( const PMSurfaceOfRevolution& s )
+ : Base( s )
+{
+ m_points = s.m_points;
+ m_sturm = s.m_sturm;
+ m_open = s.m_open;
+}
+
+PMSurfaceOfRevolution::~PMSurfaceOfRevolution( )
+{
+}
+
+QString PMSurfaceOfRevolution::description( ) const
+{
+ return i18n( "surface of revolution" );
+}
+
+void PMSurfaceOfRevolution::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ QDomElement data = doc.createElement( "extra_data" );
+ QDomElement p;
+
+ e.setAttribute( "sturm", m_sturm );
+ e.setAttribute( "open", m_open );
+
+ QValueList<PMVector>::ConstIterator it;
+ for( it = m_points.begin( ); it != m_points.end( ); ++it )
+ {
+ p = doc.createElement( "point" );
+ p.setAttribute( "vector", ( *it ).serializeXML( ) );
+ data.appendChild( p );
+ }
+
+ e.appendChild( data );
+ Base::serialize( e, doc );
+}
+
+void PMSurfaceOfRevolution::readAttributes( const PMXMLHelper& h )
+{
+ m_sturm = h.boolAttribute( "sturm", defaultSturm );
+ m_open = h.boolAttribute( "open", defaultOpen );
+
+ m_points.clear( );
+ PMVector v( 2 );
+
+ QDomElement e = h.extraData( );
+ if( !e.isNull( ) )
+ {
+ QDomNode c = e.firstChild( );
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ if( ce.tagName( ) == "point" )
+ {
+ QString str = ce.attribute( "vector" );
+ if( !str.isNull( ) )
+ {
+ v.loadXML( str );
+ m_points.append( v );
+ }
+ }
+ }
+ c = c.nextSibling( );
+ }
+ }
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMSurfaceOfRevolution::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "SurfaceOfRevolution", Base::metaObject( ),
+ createNewSurfaceOfRevolution );
+ s_pMetaObject->addProperty(
+ new PMSurfaceOfRevolutionProperty( "sturm", &PMSurfaceOfRevolution::setSturm,
+ &PMSurfaceOfRevolution::sturm ) );
+ s_pMetaObject->addProperty(
+ new PMSurfaceOfRevolutionProperty( "open", &PMSurfaceOfRevolution::setOpen,
+ &PMSurfaceOfRevolution::open ) );
+ s_pMetaObject->addProperty( new PMPointProperty( ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMSurfaceOfRevolution::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMSurfaceOfRevolution::setSturm( bool s )
+{
+ if( m_sturm != s )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm );
+ m_sturm = s;
+ }
+}
+
+void PMSurfaceOfRevolution::setOpen( bool o )
+{
+ if( m_open != o )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOpenID, m_open );
+ m_open = o;
+ }
+}
+
+void PMSurfaceOfRevolution::setPoints( const QValueList<PMVector>& points )
+{
+ if( m_points != points )
+ {
+ if( m_pMemento )
+ ( ( PMSplineMemento* ) m_pMemento )->setSplinePoints( m_points );
+
+ setViewStructureChanged( );
+ m_points = points;
+ }
+}
+
+PMDialogEditBase* PMSurfaceOfRevolution::editWidget( QWidget* parent ) const
+{
+ return new PMSurfaceOfRevolutionEdit( parent );
+}
+
+void PMSurfaceOfRevolution::createMemento( )
+{
+ if( m_pMemento )
+ delete m_pMemento;
+ m_pMemento = new PMSplineMemento( this );
+}
+
+void PMSurfaceOfRevolution::restoreMemento( PMMemento* s )
+{
+ PMSplineMemento* m = ( PMSplineMemento* ) s;
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMSturmID:
+ setSturm( data->boolData( ) );
+ break;
+ case PMOpenID:
+ setOpen( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMSurfaceOfRevolution::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ if( m->splinePointsSaved( ) )
+ setPoints( m->splinePoints( ) );
+
+ Base::restoreMemento( s );
+}
+
+
+void PMSurfaceOfRevolution::createViewStructure( )
+{
+ if( s_sSteps == 0 )
+ s_sSteps = c_defaultSurfaceOfRevolutionSSteps;
+ if( s_rSteps == 0 )
+ s_rSteps = c_defaultSurfaceOfRevolutionRSteps;
+
+ int rSteps = (int)( ( (float)s_rSteps / 2 ) * ( displayDetail( ) + 1 ) );
+ int sSteps = (int)( ( (float)s_sSteps / 2 ) * ( displayDetail( ) + 1 ) );
+
+ int np = m_points.count( );
+ int i, j, r;
+
+ // calculate number of segments
+ int ns = np - 3;
+
+ // calculate number of points and lines of the view structure
+ int vsp = ns * sSteps + 1;
+ int vsl = ( 2 * vsp - 1 ) * rSteps;
+ vsp *= rSteps;
+
+ if( m_pViewStructure )
+ {
+ if( m_pViewStructure->points( ).size( ) != ( unsigned ) vsp )
+ m_pViewStructure->points( ).resize( vsp );
+ if( m_pViewStructure->lines( ).size( ) != ( unsigned ) vsl )
+ m_pViewStructure->lines( ).resize( vsl );
+ }
+ else
+ m_pViewStructure = new PMViewStructure( vsp, vsl );
+
+
+ // calculate the spline segments
+ QValueList<PMSorSegment> segments;
+ QValueList<PMVector>::Iterator it1, it2, it3, it4;
+ it1 = m_points.begin( );
+ it2 = it1; ++it2;
+ it3 = it2; ++it3;
+ it4 = it3; ++it4;
+
+ for( i = 0; i < ns; ++i, ++it1, ++it2, ++it3, ++it4 )
+ segments.append( PMSorSegment( *it1, *it2, *it3, *it4 ) );
+
+ // create the line array
+ PMLineArray& lines = m_pViewStructure->lines( );
+ int vl = ns * sSteps;
+ int lb = 0;
+ for( i = 0; i < vl + 1; ++i )
+ {
+ for( j = 0; j < rSteps - 1; ++j )
+ lines[lb+j] = PMLine( lb + j, lb + j + 1 );
+ lines[lb+rSteps-1] = PMLine( lb, lb + rSteps - 1 );
+ lb += rSteps;
+ }
+ int pi = 0;
+ for( i = 0; i < vl; ++i )
+ {
+ for( j = 0; j < rSteps; ++j )
+ {
+ lines[lb] = PMLine( pi, pi + rSteps );
+ ++pi;
+ ++lb;
+ }
+ }
+
+ // calculate the points
+ PMVector point2, point3;
+ QValueList<PMSorSegment>::Iterator sit = segments.begin( );
+
+ double poffset = 1.0 / sSteps;
+ PMMatrix rot = PMMatrix::rotation( 0.0, M_PI * 2.0 / rSteps, 0.0 );
+ PMPointArray& points = m_pViewStructure->points( );
+ pi = 0;
+
+ for( i = 0; i < ns; ++i, ++sit )
+ {
+ for( j = 0; j < sSteps; ++j )
+ {
+ point2 = ( *sit ).point( poffset * j );
+ point3[0] = point2[0];
+ point3[1] = point2[1];
+ point3[2] = 0.0;
+
+ for( r = 0; r < rSteps; ++r )
+ {
+ points[pi] = PMPoint( point3 );
+ if( r != rSteps - 1 )
+ point3.transform( rot );
+ ++pi;
+ }
+ }
+ if( i == ns - 1 )
+ {
+ point2 = ( *sit ).point( 1.0 );
+ point3[0] = point2[0];
+ point3[1] = point2[1];
+ point3[2] = 0.0;
+
+ for( r = 0; r < rSteps; ++r )
+ {
+ points[pi] = PMPoint( point3 );
+ if( r != rSteps - 1 )
+ point3.transform( rot );
+ ++pi;
+ }
+ }
+ }
+}
+
+void PMSurfaceOfRevolution::controlPoints( PMControlPointList& list )
+{
+ QValueList<PMVector>::Iterator it;
+ QPtrList<PMSorControlPoint> tmp1, tmp2;
+ int i;
+
+ PMSorControlPoint* cp = 0;
+
+ PMSorControlPoint* lastPoint = 0;
+ cp = 0;
+
+ for( it = m_points.begin( ), i = 0; it != m_points.end( ); ++it, ++i )
+ {
+ lastPoint = cp;
+ cp = new PMSorControlPoint( lastPoint, *it, PMSorControlPoint::PM2DXY, i,
+ i18n( "Point %1 (xy)" ).arg( i + 1 ) );
+ tmp1.append( cp );
+ }
+
+ lastPoint = 0;
+ cp = 0;
+
+ for( it = m_points.begin( ), i = 0; it != m_points.end( ); ++it, ++i )
+ {
+ lastPoint = cp;
+ cp = new PMSorControlPoint( lastPoint, *it, PMSorControlPoint::PM2DZY, i,
+ i18n( "Point %1 (yz)" ).arg( i + 1 ) );
+ tmp2.append( cp );
+ }
+
+ QPtrListIterator<PMSorControlPoint> cit1( tmp1 ), cit2( tmp2 );
+
+ for( ; cit1.current( ) && cit2.current( ); ++cit1, ++cit2 )
+ {
+ ( *cit1 )->setSorLink( *cit2 );
+ ( *cit2 )->setSorLink( *cit1 );
+ }
+ for( cit1.toFirst( ); cit1.current( ); ++cit1 )
+ list.append( *cit1 );
+ for( cit2.toFirst( ); cit2.current( ); ++cit2 )
+ list.append( *cit2 );
+}
+
+void PMSurfaceOfRevolution::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPointListIterator it1( list ), it2( list );
+ QValueList<PMVector>::Iterator pit = m_points.begin( );
+ PMSorControlPoint* p1;
+ PMSorControlPoint* p2;
+ bool firstChange = true;
+ PMVector lastPoint( 2 );
+ int num = list.count( ) / 2;
+ int pnr = 0;
+
+ for( it2 += num; it2.current( ); ++it1, ++it2, ++pit, ++pnr )
+ {
+ p1 = ( PMSorControlPoint* ) it1.current( );
+ p2 = ( PMSorControlPoint* ) it2.current( );
+
+ if( p1->changed( ) )
+ {
+ if( firstChange )
+ {
+ if( m_pMemento )
+ {
+ PMSplineMemento* m = ( PMSplineMemento* ) m_pMemento;
+ if( !m->splinePointsSaved( ) )
+ m->setSplinePoints( m_points );
+ }
+ firstChange = false;
+ setViewStructureChanged( );
+ }
+ p2->setPoint( p1->point( ) );
+ ( *pit ) = p1->point( );
+ }
+ else if( p2->changed( ) )
+ {
+ if( firstChange )
+ {
+ if( m_pMemento )
+ {
+ PMSplineMemento* m = ( PMSplineMemento* ) m_pMemento;
+ if( !m->splinePointsSaved( ) )
+ m->setSplinePoints( m_points );
+ }
+ firstChange = false;
+ setViewStructureChanged( );
+ }
+ p1->setPoint( p2->point( ) );
+ ( *pit ) = p2->point( );
+ }
+
+ if( ( pnr > 1 ) && ( pnr < ( num - 1 ) ) )
+ {
+ if( ( ( *pit )[1] - lastPoint[1] ) < c_sorTolerance )
+ {
+ ( *pit )[1] = lastPoint[1] + c_sorTolerance;
+ p1->setPoint( *pit );
+ p2->setPoint( *pit );
+ }
+ }
+ if( ( pnr == ( num - 1 ) ) || ( pnr == 2 ) )
+ {
+ QValueList<PMVector>::Iterator hit = pit;
+ --hit; --hit;
+
+ if( approxZero( ( *hit )[1] - ( *pit )[1], c_sorTolerance ) )
+ {
+ ( *pit )[1] = ( *hit )[1] + c_sorTolerance;
+ p1->setPoint( *pit );
+ p2->setPoint( *pit );
+ }
+ }
+
+ lastPoint = *pit;
+ }
+}
+
+void PMSurfaceOfRevolution::addObjectActions( const PMControlPointList& /*cp*/,
+ QPtrList<PMObjectAction>& actions )
+{
+ PMObjectAction* a;
+
+ a = new PMObjectAction( s_pMetaObject, PMSplitSegmentID,
+ i18n( "Add Point" ) );
+ actions.append( a );
+
+ a = new PMObjectAction( s_pMetaObject, PMJoinSegmentsID,
+ i18n( "Remove Point" ) );
+ int np = m_points.count( );
+
+ if( np < 5 )
+ a->setEnabled( false );
+ actions.append( a );
+}
+
+void PMSurfaceOfRevolution::objectActionCalled( const PMObjectAction* action,
+ const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ if( action->objectType( ) == s_pMetaObject )
+ {
+ switch( action->actionID( ) )
+ {
+ case PMSplitSegmentID:
+ splitSegment( cp, cpViewPosition, clickPosition );
+ break;
+ case PMJoinSegmentsID:
+ joinSegments( cp, cpViewPosition, clickPosition );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMSurfaceOfRevolution::objectActionCalled\n";
+ break;
+ }
+ }
+ else
+ Base::objectActionCalled( action, cp, cpViewPosition, clickPosition );
+}
+
+void PMSurfaceOfRevolution::splitSegment( const PMControlPointList& /*cp*/,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ // find nearest segment
+ int nump = cpViewPosition.count( ) / 2 - 1;
+ double abs = 0.0, minabs = 1e10;
+ int ns = -1;
+ int i, j;
+ PMVector mid( 3 ), dist( 2 );
+
+ QPtrListIterator<PMVector> it1( cpViewPosition );
+ QPtrListIterator<PMVector> it2( cpViewPosition );
+ ++it2;
+
+ for( j = 0; j < 2; ++j )
+ {
+ ++it1;
+ ++it2;
+ for( i = 1; i < ( nump - 1 ); ++i )
+ {
+ mid = ( **it1 + **it2 ) / 2.0;
+ dist[0] = mid[0];
+ dist[1] = mid[1];
+ dist -= clickPosition;
+ abs = dist.abs( );
+
+ if( ( minabs > abs ) || ( ns < 0 ) )
+ {
+ minabs = abs;
+ ns = i;
+ }
+ ++it1;
+ ++it2;
+ }
+ ++it1;
+ ++it2;
+ ++it1;
+ ++it2;
+ }
+
+ // add a new segment
+ QValueList<PMVector> newPoints = m_points;
+ QValueList<PMVector>::Iterator it = newPoints.at( ( unsigned ) ns );
+ PMVector p[4];
+ QValueList<PMVector>::Iterator hit = it;
+
+ // calculate the spline segment
+ --hit;
+ for( i = 0; i < 4; ++i, ++hit )
+ p[i] = *hit;
+ PMSorSegment segment( p[0], p[1], p[2], p[3] );
+
+ mid = segment.point( 0.5 );
+ if( mid[0] < 0 )
+ mid[0] = 0;
+ ++it;
+ it = newPoints.insert( it, mid );
+ hit = it;
+ --it;
+
+ for( ; hit != newPoints.end( ); ++it, ++hit )
+ if( ( ( *hit )[1] - ( *it )[1] ) < c_sorTolerance )
+ ( *hit )[1] = ( *it )[1] + c_sorTolerance;
+
+ setPoints( newPoints );
+}
+
+void PMSurfaceOfRevolution::joinSegments( const PMControlPointList& /*cp*/,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ // find nearest point
+ int nump = cpViewPosition.count( ) / 2;
+
+ if( nump < 5 )
+ {
+ kdError( PMArea ) << "Not enough points in PMSurfaceOfRevolution::joinSegments\n";
+ return;
+ }
+
+ double abs = 0.0, minabs = 1e10;
+ int ns = -1;
+ int i, j;
+ PMVector* p;
+ PMVector dist( 2 );
+
+ QPtrListIterator<PMVector> it1( cpViewPosition );
+
+ for( j = 0; j < 2; ++j )
+ {
+ for( i = 0; i < nump; ++i )
+ {
+ p = *it1;
+ dist[0] = (*p)[0];
+ dist[1] = (*p)[1];
+ dist -= clickPosition;
+ abs = dist.abs( );
+
+ if( ( minabs > abs ) || ( ns < 0 ) )
+ {
+ minabs = abs;
+ ns = i;
+ }
+ ++it1;
+ }
+ }
+
+ // join two segments
+ QValueList<PMVector> newPoints = m_points;
+ QValueList<PMVector>::Iterator it;
+
+ // never remove the first or last point
+ if( ns == 0 )
+ ++ns;
+ if( ns == ( nump - 1 ) )
+ --ns;
+ it = newPoints.at( ns );
+ newPoints.remove( it );
+
+ setPoints( newPoints );
+}
+
+void PMSurfaceOfRevolution::setRSteps( int r )
+{
+ if( r >= 4 )
+ s_rSteps = r;
+ else
+ kdDebug( PMArea ) << "PMSurfaceOfRevolution::setRSteps: R must be greater than 3\n";
+ ++s_parameterKey;
+}
+
+void PMSurfaceOfRevolution::setSSteps( int s )
+{
+ if( s >= 1 )
+ s_sSteps = s;
+ else
+ kdDebug( PMArea ) << "PMSurfaceOfRevolution::setSSteps: S must be greater than 0\n";
+ ++s_parameterKey;
+}