diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 47d455dd55be855e4cc691c32f687f723d9247ee (patch) | |
tree | 52e236aaa2576bdb3840ebede26619692fed6d7d /kpovmodeler/pmsor.cpp | |
download | tdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.tar.gz tdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kpovmodeler/pmsor.cpp')
-rw-r--r-- | kpovmodeler/pmsor.cpp | 708 |
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 + email : [email protected] +************************************************************************** + +************************************************************************** +* * +* 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; +} |