diff options
Diffstat (limited to 'kpovmodeler/pmsqe.cpp')
-rw-r--r-- | kpovmodeler/pmsqe.cpp | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/kpovmodeler/pmsqe.cpp b/kpovmodeler/pmsqe.cpp new file mode 100644 index 00000000..051aac72 --- /dev/null +++ b/kpovmodeler/pmsqe.cpp @@ -0,0 +1,413 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 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 "pmsqe.h" + +#include "pmxmlhelper.h" +#include "pmsqeedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pmdefaults.h" +#include "pmmath.h" + +#include <klocale.h> + +const double c_defaultEastWestExponent = 1.0; +const double c_defaultNorthSouthExponent = 1.0; + +PMViewStructure* PMSuperquadricEllipsoid::s_pDefaultViewStructure = 0; +int PMSuperquadricEllipsoid::s_vStep = c_defaultSuperquadricEllipsoidVSteps; +int PMSuperquadricEllipsoid::s_uStep = c_defaultSuperquadricEllipsoidUSteps; +int PMSuperquadricEllipsoid::s_parameterKey = 0; + +PMDefinePropertyClass( PMSuperquadricEllipsoid, PMSuperquadricEllipsoidProperty ); + +PMMetaObject* PMSuperquadricEllipsoid::s_pMetaObject = 0; +PMObject* createNewSuperquadricEllipsoid( PMPart* part ) +{ + return new PMSuperquadricEllipsoid( part ); +} + +PMSuperquadricEllipsoid::PMSuperquadricEllipsoid( PMPart* part ) + : Base( part ) +{ + m_eastWestExponent = c_defaultEastWestExponent; + m_northSouthExponent = c_defaultNorthSouthExponent; +} + +PMSuperquadricEllipsoid::PMSuperquadricEllipsoid( const PMSuperquadricEllipsoid& s ) + : Base( s ) +{ + m_eastWestExponent = s.m_eastWestExponent; + m_northSouthExponent = s.m_northSouthExponent; +} + +PMSuperquadricEllipsoid::~PMSuperquadricEllipsoid( ) +{ +} + +QString PMSuperquadricEllipsoid::description( ) const +{ + return i18n( "superquadric ellipsoid" ); +} + +void PMSuperquadricEllipsoid::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "value_e", m_eastWestExponent ); + e.setAttribute( "value_n", m_northSouthExponent ); + Base::serialize( e, doc ); +} + +void PMSuperquadricEllipsoid::readAttributes( const PMXMLHelper& h ) +{ + m_eastWestExponent = h.doubleAttribute( "value_e", c_defaultEastWestExponent ); + m_northSouthExponent = h.doubleAttribute( "value_n", c_defaultNorthSouthExponent ); + Base::readAttributes( h ); +} + +PMMetaObject* PMSuperquadricEllipsoid::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "SuperquadricEllipsoid", Base::metaObject( ), + createNewSuperquadricEllipsoid ); + s_pMetaObject->addProperty( + new PMSuperquadricEllipsoidProperty( "eastWestExponent", + &PMSuperquadricEllipsoid::setEastWestExponent, + &PMSuperquadricEllipsoid::eastWestExponent ) ); + s_pMetaObject->addProperty( + new PMSuperquadricEllipsoidProperty( "northSouthExponent", + &PMSuperquadricEllipsoid::setNorthSouthExponent, + &PMSuperquadricEllipsoid::northSouthExponent ) ); + } + return s_pMetaObject; +} + +void PMSuperquadricEllipsoid::setEastWestExponent( double e ) +{ + if( e != m_eastWestExponent ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEastWestExponentID, + m_eastWestExponent ); + if( e < 0.001 ) + { + kdError( PMArea ) << "EastWestExponent < 0.001 in PMSuperquadricEllipsoid::setEastWestExponent\n"; + e = 0.001; + } + m_eastWestExponent = e; + setViewStructureChanged( ); + } +} + +void PMSuperquadricEllipsoid::setNorthSouthExponent( double n ) +{ + if( n != m_northSouthExponent ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNorthSouthExponentID, + m_northSouthExponent ); + if( n < 0.001 ) + { + kdError( PMArea ) << "NorthSouthExponent < 0.001 in PMSuperquadricEllipsoid::setNorthSouthExponent\n"; + n = 0.001; + } + + m_northSouthExponent = n; + setViewStructureChanged( ); + } +} + +PMDialogEditBase* PMSuperquadricEllipsoid::editWidget( QWidget* parent ) const +{ + return new PMSuperquadricEllipsoidEdit( parent ); +} + +void PMSuperquadricEllipsoid::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMEastWestExponentID: + setEastWestExponent( data->doubleData( ) ); + break; + case PMNorthSouthExponentID: + setNorthSouthExponent( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMSuperquadricEllipsoid::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + + +bool PMSuperquadricEllipsoid::isDefault( ) +{ + if( ( m_eastWestExponent == c_defaultEastWestExponent ) && + ( m_northSouthExponent == c_defaultNorthSouthExponent ) + && globalDetail( ) ) + return true; + return false; +} + +void PMSuperquadricEllipsoid::createViewStructure( ) +{ + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + + int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) ); + int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) ); + int uStep2 = uStep * 4; + int vStep2 = vStep * 8; + unsigned ptsSize = vStep2 * ( uStep2 - 1 ) + 2; + unsigned lineSize = vStep2 * ( uStep2 - 1 ) * 2 + vStep2; + + if( ptsSize != m_pViewStructure->points( ).size( ) ) + m_pViewStructure->points( ).resize( ptsSize ); + + createPoints( m_pViewStructure->points( ), m_eastWestExponent, + m_northSouthExponent, uStep, vStep ); + + if( lineSize != m_pViewStructure->lines( ).size( ) ) + { + m_pViewStructure->lines( ).detach( ); + m_pViewStructure->lines( ).resize( lineSize ); + createLines( m_pViewStructure->lines( ), uStep2, vStep2 ); + } +} + +PMViewStructure* PMSuperquadricEllipsoid::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + int uStep = (int)( ( (float)s_uStep / 2 ) * ( globalDetailLevel( ) + 1 ) ); + int vStep = (int)( ( (float)s_vStep / 2 ) * ( globalDetailLevel( ) + 1 ) ); + + // transform u and v steps to sphere u/v steps + int uStep2 = uStep * 4; + int vStep2 = vStep * 8; + + s_pDefaultViewStructure = + new PMViewStructure( vStep2 * ( uStep2 - 1 ) + 2, + vStep2 * ( uStep2 - 1 ) * 2 + vStep2 ); + + // points + createPoints( s_pDefaultViewStructure->points( ), + c_defaultEastWestExponent, c_defaultNorthSouthExponent, uStep, vStep ); + + createLines( s_pDefaultViewStructure->lines( ), uStep2, vStep2 ); + } + return s_pDefaultViewStructure; +} + +void PMSuperquadricEllipsoid::createLines( PMLineArray& lines, int uStep, int vStep ) +{ + int u, v; + int offset = 0; + + // horizontal lines + for( u = 0; u < ( uStep - 1 ); u++ ) + { + for( v = 0; v < ( vStep - 1 ); v++ ) + lines[offset + v] = + PMLine( u * vStep + v + 1, u * vStep + v + 2 ); + lines[offset + vStep - 1] = + PMLine( u * vStep + 1, u * vStep + vStep ); + + offset += vStep; + } + + // vertical lines + // lines at the "north pole" + for( v = 0; v < vStep; v++ ) + lines[offset + v] = PMLine( 0, v + 1 ); + offset += vStep; + + for( v = 0; v < vStep; v++ ) + { + for( u = 0; u < ( uStep - 2 ); u++ ) + { + lines[offset + u] = + PMLine( u * vStep + v + 1, ( u + 1 ) * vStep + v + 1 ); + } + offset += ( uStep - 2 ); + } + // lines at the "south pole" + for( v = 0; v < vStep; v++ ) + lines[offset + v] = PMLine( ( uStep - 2 ) * vStep + v + 1, + ( uStep - 1 ) * vStep + 1 ); + // offset += vStep; +} + +void PMSuperquadricEllipsoid::createPoints( PMPointArray& points, + double e, double n, int uStep, int vStep ) +{ + int u, v; + int zi; + int pbase = 0, pref = 0; + + if( e <= 0.001 ) + e = 0.001; + if( n <= 0.001 ) + n = 0.001; + + double c2_e = 2.0 / e; + double c2_n = 2.0 / n; + double cn_2 = n / 2.0; + double ce_2 = e / 2.0; + double cn_e = n / e; +// double ce_n = e / n; + double z = 0.0, c = 0.0, a = 0.0, a2 = 0.0, x = 0.0, y = 0.0; + double k = 0.0, k2 = 0.0, du = 0.0, dv = 0.0; + PMPoint p; + + points[0] = PMPoint( 0, 0, 1 ); + pbase++; + + for( zi = 0; zi < 2; zi++ ) + { + for( u = 0; u < uStep; u++ ) + { + du = ( double ) ( u + 1 ) / ( double ) uStep; + if( zi == 1 ) + du = 1.0 - du; + k = tan( M_PI / 4.0 * pow( du, n < 1.0 ? n : sqrt( n ) ) ); + k2 = 1 / ( pow( k, c2_n ) + 1 ); + z = pow( k2, cn_2 ); + if( zi == 1 ) + z *= k; + c = pow( 1 - pow( z, c2_n ), cn_e ); + + for( v = 0; v < ( vStep + 1 ); v++ ) + { + dv = ( double ) v / ( double ) vStep; + a = tan( M_PI / 4.0 * pow( dv, e < 1.0 ? e : sqrt( e ) ) ); + a2 = 1 + pow( a, c2_e ); + x = pow( c / a2, ce_2 ); + y = x * a; + + points[pbase+v] = PMPoint( x, y, z ); + } + // 1/8 + + pref = pbase + 2 * vStep; + for( v = 0; v < vStep; v++, pref-- ) + { + p = points[pbase+v]; + x = p[0]; + p[0] = p[1]; + p[1] = x; + points[pref] = p; + } + // 1/4 + + pref = pbase + 4 * vStep; + for( v = 0; v < ( 2 * vStep ); v++, pref-- ) + { + p = points[pbase+v]; + p[0] = -p[0]; + points[pref] = p; + } + // 1/2 + + pref = pbase + 8 * vStep - 1; + for( v = 1; v < ( 4 * vStep ); v++, pref-- ) + { + p = points[pbase+v]; + p[1] = -p[1]; + points[pref] = p; + } + + pbase += 8 * vStep; + } + } + + for( u = 0; u < ( uStep * 2 - 1 ); u++ ) + { + pbase = 1 + u * vStep * 8; + pref = 1 + ( uStep * 4 - 2 - u ) * vStep * 8; + + for( v = 0; v < ( vStep * 8 ); v++, pref++ ) + { + p = points[pbase + v]; + p[2] = -p[2]; + points[pref] = p; + } + } + points[ vStep * 8 * ( uStep * 4 - 1 ) + 1 ] = PMPoint( 0, 0, -1 ); +} + +void PMSuperquadricEllipsoid::setUSteps( int u ) +{ + if( u >= 2 ) + { + s_uStep = u; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMSuperquadricEllipsoid::setUSteps: U must be greater than 1\n"; + s_parameterKey++; +} + +void PMSuperquadricEllipsoid::setVSteps( int v ) +{ + if( v >= 2 ) + { + s_vStep = v; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMSuperquadricEllipsoid::setVSteps: V must be greater than 1\n"; + s_parameterKey++; +} + +void PMSuperquadricEllipsoid::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} |