diff options
Diffstat (limited to 'kpovmodeler/pmcamera.cpp')
-rw-r--r-- | kpovmodeler/pmcamera.cpp | 769 |
1 files changed, 769 insertions, 0 deletions
diff --git a/kpovmodeler/pmcamera.cpp b/kpovmodeler/pmcamera.cpp new file mode 100644 index 00000000..b224f340 --- /dev/null +++ b/kpovmodeler/pmcamera.cpp @@ -0,0 +1,769 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 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 "pmcamera.h" + +#include "pmxmlhelper.h" +#include "pmcameraedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pm3dcontrolpoint.h" +#include "pmvectorcontrolpoint.h" +#include "pmenumproperty.h" + +#include <klocale.h> + +PMDefinePropertyClass( PMCamera, PMCameraProperty ); +PMDefineEnumPropertyClass( PMCamera, PMCamera::CameraType, + PMCameraTypeProperty ); + +PMViewStructure* PMCamera::s_pDefaultViewStructure = 0; +PMMetaObject* PMCamera::s_pMetaObject = 0; +PMObject* createNewCamera( PMPart* part ) +{ + return new PMCamera( part ); +} + +const PMVector locationDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector lookAtDefault = PMVector( 0.0, 0.0, 1.0 ); +const PMVector directionDefault = PMVector( 0.0, 0.0, 1.0 ); +const PMVector upDefault = PMVector( 0.0, 1.0, 0.0 ); +const PMVector rightDefault = PMVector( 4.0/3.0, 0.0, 0.0 ); +const PMVector skyDefault = PMVector( 0.0, 1.0, 0.0 ); +//const double aspectDefault = 1.0; +const bool angleEnabledDefault = false; +const double angleDefault = 90.0; +const PMCamera::CameraType cameraTypeDefault = PMCamera::Perspective; +const int cylinderTypeDefault = 1; +const bool focalBlurDefault = false; +const double apertureDefault = 0.4; +const int blurSamplesDefault = 10; +const PMVector focalPointDefault = PMVector( 0.0, 0.0, 0.0 ); +const double confidenceDefault = 0.9; +const double varianceDefault = 0.008; +const bool c_defaultExport = true; + +PMCamera::PMCamera( PMPart* part ) + : Base( part ) +{ + m_location = locationDefault; + m_lookAt = lookAtDefault; + m_direction = directionDefault; + + m_up = upDefault; + m_right = rightDefault; + + m_sky = skyDefault; + m_angle = angleDefault; + m_angleEnabled = angleEnabledDefault; + + m_cameraType = cameraTypeDefault; + m_cylinderType = cylinderTypeDefault; + + m_focalBlurEnabled = focalBlurDefault; + m_aperture = apertureDefault; + m_blurSamples = blurSamplesDefault; + m_focalPoint = focalPointDefault; + m_confidence = confidenceDefault; + m_variance = varianceDefault; + m_export = c_defaultExport; +} + +PMCamera::PMCamera( const PMCamera& c ) + : Base( c ) +{ + m_location = c.m_location; + m_lookAt = c.m_lookAt; + m_direction = c.m_direction; + + m_up = c.m_up; + m_right = c.m_right; + + m_sky = c.m_sky; + m_angle = c.m_angle; + m_angleEnabled = c.m_angleEnabled; + + m_cameraType = c.m_cameraType; + m_cylinderType = c.m_cylinderType; + + m_focalBlurEnabled = c.m_focalBlurEnabled; + m_aperture = c.m_aperture; + m_blurSamples = c.m_blurSamples; + m_focalPoint = c.m_focalPoint; + m_confidence = c.m_confidence; + m_variance = c.m_variance; + m_export = c.m_export; +} + +PMCamera::~PMCamera( ) +{ +} + +QString PMCamera::description( ) const +{ + return i18n( "camera" ); +} + +void PMCamera::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "camera_type", cameraTypeToString( m_cameraType ) ); + e.setAttribute( "cylinder_type", m_cylinderType ); + e.setAttribute( "location", m_location.serializeXML( ) ); + e.setAttribute( "sky", m_sky.serializeXML( ) ); + e.setAttribute( "direction", m_direction.serializeXML( ) ); + e.setAttribute( "right", m_right.serializeXML( ) ); + e.setAttribute( "up", m_up.serializeXML( ) ); + e.setAttribute( "look_at", m_lookAt.serializeXML( ) ); + e.setAttribute( "angle_enabled", m_angleEnabled ); + e.setAttribute( "angle", m_angle ); + e.setAttribute( "focal_blur", m_focalBlurEnabled ); + e.setAttribute( "aperture", m_aperture ); + e.setAttribute( "blur_samples", m_blurSamples ); + e.setAttribute( "focal_point", m_focalPoint.serializeXML( ) ); + e.setAttribute( "confidence", m_confidence ); + e.setAttribute( "variance", m_variance ); + e.setAttribute( "export", m_export ); + + Base::serialize( e, doc ); +} + +void PMCamera::readAttributes( const PMXMLHelper& h ) +{ + m_cameraType = stringToCameraType( h.stringAttribute( "camera_type", + "perspective" ) ); + m_cylinderType = h.intAttribute( "cylinder_type", cylinderTypeDefault ); + m_location = h.vectorAttribute( "location", locationDefault ); + m_sky = h.vectorAttribute( "sky", skyDefault ); + m_direction = h.vectorAttribute( "direction", directionDefault ); + m_right = h.vectorAttribute( "right", rightDefault ); + m_up = h.vectorAttribute( "up", upDefault ); + m_lookAt = h.vectorAttribute( "look_at", lookAtDefault ); + m_angleEnabled = h.boolAttribute( "angle_enabled", angleEnabledDefault ); + m_angle = h.doubleAttribute( "angle", angleDefault ); + m_focalBlurEnabled = h.boolAttribute( "focal_blur", focalBlurDefault ); + m_aperture = h.doubleAttribute( "aperture", apertureDefault ); + m_blurSamples = h.intAttribute( "blur_samples", blurSamplesDefault ); + m_focalPoint = h.vectorAttribute( "focal_point", focalPointDefault ); + m_confidence = h.doubleAttribute( "confidence", confidenceDefault ); + m_variance = h.doubleAttribute( "variance", varianceDefault ); + m_export = h.boolAttribute( "export", c_defaultExport ); + Base::readAttributes( h ); +} + +PMMetaObject* PMCamera::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Camera", Base::metaObject( ), + createNewCamera ); + s_pMetaObject->addProperty( + new PMCameraProperty( "location", &PMCamera::setLocation, + &PMCamera::location ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "lookAt", &PMCamera::setLookAt, + &PMCamera::lookAt ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "up", &PMCamera::setUp, + &PMCamera::up ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "right", &PMCamera::setRight, + &PMCamera::right ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "direction", &PMCamera::setDirection, + &PMCamera::direction ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "sky", &PMCamera::setSky, + &PMCamera::sky ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "aspect", 0, &PMCamera::aspect ) ); + + s_pMetaObject->addProperty( + new PMCameraProperty( "angleEnabled", &PMCamera::enableAngle, + &PMCamera::isAngleEnabled ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "angle", &PMCamera::setAngle, + &PMCamera::angle ) ); + + PMCameraTypeProperty* p = new PMCameraTypeProperty( + "cameraType", &PMCamera::setCameraType, + &PMCamera::cameraType ); + p->addEnumValue( "Perspective", Perspective ); + p->addEnumValue( "Orthographic", Orthographic ); + p->addEnumValue( "FishEye", FishEye ); + p->addEnumValue( "UltraWideAngle", UltraWideAngle ); + p->addEnumValue( "Omnimax", Omnimax ); + p->addEnumValue( "Panoramic", Panoramic ); + p->addEnumValue( "Cylinder", Cylinder ); + s_pMetaObject->addProperty( p ); + + s_pMetaObject->addProperty( + new PMCameraProperty( "cylinderType", &PMCamera::setCylinderType, + &PMCamera::cylinderType ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "focalBlurEnabled", &PMCamera::enableFocalBlur, + &PMCamera::isFocalBlurEnabled ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "aperture", &PMCamera::setAperture, + &PMCamera::aperture ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "blurSamples", &PMCamera::setBlurSamples, + &PMCamera::blurSamples ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "focalPoint", &PMCamera::setFocalPoint, + &PMCamera::focalPoint ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "confidence", &PMCamera::setConfidence, + &PMCamera::confidence ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "variance", &PMCamera::setVariance, + &PMCamera::variance ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "export", &PMCamera::setExportPovray, + &PMCamera::exportPovray ) ); + } + return s_pMetaObject; +} + +void PMCamera::setLocation( const PMVector& p ) +{ + if( p != m_location ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLocationID, m_location ); + m_location = p; + m_location.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCamera::setLookAt( const PMVector& p ) +{ + if( p != m_lookAt ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLookAtID, m_lookAt ); + m_lookAt = p; + m_lookAt.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCamera::setUp( const PMVector& v ) +{ + if( v != m_up ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUpID, m_up ); + m_up = v; + m_up.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCamera::setRight( const PMVector& v ) +{ + if( v != m_right ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRightID, m_right ); + m_right = v; + m_right.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCamera::setDirection( const PMVector& v ) +{ + if( v != m_direction ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDirectionID, m_direction ); + m_direction = v; + m_direction.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCamera::setSky( const PMVector& v ) +{ + if( v != m_sky ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSkyID, m_sky ); + m_sky = v; + m_sky.resize( 3 ); + setViewStructureChanged( ); + } +} + +double PMCamera::aspect( ) const +{ + double d = m_up.abs( ); + if( approxZero( d ) ) + return 1.0; + return m_right.abs( ) / d; +} + +void PMCamera::enableAngle( bool yes ) +{ + if( yes != m_angleEnabled ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAngleEnabledID, m_angleEnabled ); + m_angleEnabled = yes; + setViewStructureChanged( ); + } +} + +void PMCamera::setAngle( double a ) +{ + if( a != m_angle ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAngleID, m_angle ); + m_angle = a; + setViewStructureChanged( ); + } +} + +void PMCamera::setCameraType( PMCamera::CameraType t ) +{ + if( t != m_cameraType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCameraTypeID, m_cameraType ); + m_cameraType = t; + setViewStructureChanged( ); + } +} + +void PMCamera::setCylinderType( int t ) +{ + if( ( t < 1 ) || ( t > 4 ) ) + kdError( PMArea ) << "Invalid type in PMCylinder::setCylinderType\n"; + else if( t != m_cylinderType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCylinderTypeID, m_cylinderType ); + m_cylinderType = t; + setViewStructureChanged( ); + } +} + +void PMCamera::enableFocalBlur( bool yes ) +{ + if( yes != m_focalBlurEnabled ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFocalBlurID, m_focalBlurEnabled ); + m_focalBlurEnabled = yes; + } +} + +void PMCamera::setAperture( double a ) +{ + if( a < 0 ) + kdError( PMArea ) << "Aperture < 0 in PMCylinder::setAperture\n"; + else if( a != m_aperture ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMApertureID, m_aperture ); + m_aperture = a; + } +} + +void PMCamera::setBlurSamples( int s ) +{ + if( s < 0 ) + kdError( PMArea ) << "Samples < 0 in PMCylinder::setBlutSamples\n"; + else if( s != m_blurSamples ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBlurSamplesID, m_blurSamples ); + m_blurSamples = s; + } +} + +void PMCamera::setFocalPoint( const PMVector& v ) +{ + if( v != m_focalPoint ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFocalPointID, m_focalPoint ); + m_focalPoint = v; + } +} + +void PMCamera::setConfidence( double c ) +{ + if( ( c < 0.0 ) || ( c > 1.0 ) ) + kdError( PMArea ) << "Confidence not in [0.0 1.0] in PMCylinder::setConfidence\n"; + else if( c != m_confidence ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMConfidenceID, m_confidence ); + m_confidence = c; + } +} + +void PMCamera::setVariance( double v ) +{ + if( v < 0 ) + kdError( PMArea ) << "Variance < 0 in PMCylinder::setVariance\n"; + else if( v != m_variance ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMVarianceID, m_variance ); + m_variance = v; + } +} + +void PMCamera::setExportPovray( bool ex ) +{ + if( m_export != ex ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMExportID, m_export ); + m_export = ex; + } +} + +PMDialogEditBase* PMCamera::editWidget( QWidget* parent ) const +{ + return new PMCameraEdit( parent ); +} + +void PMCamera::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMLocationID: + setLocation( data->vectorData( ) ); + break; + case PMLookAtID: + setLookAt( data->vectorData( ) ); + break; + case PMUpID: + setUp( data->vectorData( ) ); + break; + case PMRightID: + setRight( data->vectorData( ) ); + break; + case PMDirectionID: + setDirection( data->vectorData( ) ); + break; + case PMSkyID: + setSky( data->vectorData( ) ); + break; + case PMAngleEnabledID: + enableAngle( data->boolData( ) ); + break; + case PMAngleID: + setAngle( data->doubleData( ) ); + break; + case PMCameraTypeID: + setCameraType( ( CameraType ) data->intData( ) ); + break; + case PMCylinderTypeID: + setCylinderType( data->intData( ) ); + break; + case PMFocalBlurID: + enableFocalBlur( data->boolData( ) ); + break; + case PMBlurSamplesID: + setBlurSamples( data->intData( ) ); + break; + case PMFocalPointID: + setFocalPoint( data->vectorData( ) ); + break; + case PMConfidenceID: + setConfidence( data->doubleData( ) ); + break; + case PMVarianceID: + setVariance( data->doubleData( ) ); + break; + case PMApertureID: + setAperture( data->doubleData( ) ); + break; + case PMExportID: + setExportPovray( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMCamera::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +void PMCamera::createViewStructure( ) +{ + PMVector newUp, newRight, newDirection, tmp; + double upLen, rightLen; + + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + + PMPointArray& points = m_pViewStructure->points( ); + calculateLookAtAngle( newRight, newUp, newDirection ); + + points[0] = m_lookAt; + points[1] = m_location; + + upLen = newUp.abs( ); + rightLen = newRight.abs( ); + if( rightLen > upLen ) + { + newUp /= rightLen; + newRight /= rightLen; + newDirection /= rightLen; + } + else + { + newUp /= upLen; + newRight /= upLen; + newDirection /= upLen; + } + + newRight /= 2.0; + newUp /= 2.0; + tmp = m_location + newDirection; + points[2] = tmp - newRight + newUp; + points[3] = tmp - newRight - newUp; + points[4] = tmp + newRight - newUp; + points[5] = tmp + newRight + newUp; +// points[6] = m_location + m_sky; +} + +PMViewStructure* PMCamera::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure ) + { + s_pDefaultViewStructure = new PMViewStructure( 6, 9 ); + PMLineArray& lines = s_pDefaultViewStructure->lines( ); + + lines[0] = PMLine( 0, 1 ); + lines[1] = PMLine( 1, 2 ); + lines[2] = PMLine( 1, 3 ); + lines[3] = PMLine( 1, 4 ); + lines[4] = PMLine( 1, 5 ); + lines[5] = PMLine( 2, 3 ); + lines[6] = PMLine( 2, 5 ); + lines[7] = PMLine( 3, 4 ); + lines[8] = PMLine( 4, 5 ); +// lines[9] = PMLine( 1, 6 ); + } + return s_pDefaultViewStructure; +} + +void PMCamera::controlPoints( PMControlPointList& list ) +{ + PMControlPoint* p; + p = new PM3DControlPoint( m_location, PMLocationID, i18n( "Location" ) ); + list.append( p ); + list.append( new PM3DControlPoint( m_lookAt, PMLookAtID, i18n( "Look at" ) ) ); +} + +void PMCamera::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPoint* p; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMLocationID: + setLocation( ( ( PM3DControlPoint* ) p )->point( ) ); + break; + case PMLookAtID: + setLookAt( ( ( PM3DControlPoint* ) p )->point( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMCamera::controlPointsChanged\n"; + break; + } + } + } +} + +void PMCamera::calculateLookAtAngle( PMVector& right, PMVector& up, PMVector& direction ) +{ + PMVector tmpVector; + double directionLen, upLen, rightLen, handedness, angle; + + angle = m_angle; + if( m_cameraType == Perspective ) + { + if( angle < 0.0 ) + angle = angleDefault; + if( angle >= 180.0 ) + angle = angleDefault; + } + else + angle = 90.0; + + directionLen = m_direction.abs( ); + upLen = m_up.abs( ); + rightLen = m_right.abs( ); + + // for safety: if vector is null vector, use the default one + if( approxZero( directionLen ) ) + { + direction = directionDefault; + directionLen = direction.abs( ); + } + else + direction = m_direction; + + if( approxZero( upLen ) ) + { + up = upDefault; + upLen = up.abs( ); + } + else + up = m_up; + + if( approxZero( rightLen ) ) + { + right = rightDefault; + rightLen = right.abs( ); + } + else + right = m_right; + + if( m_angleEnabled ) + { + // calculate angle + direction /= directionLen; + directionLen = 0.5 * rightLen / tan( angle * M_PI / 360.0 ); + direction *= directionLen; + } + + // calculate handedness + tmpVector = PMVector::cross( up, direction ); + handedness = PMVector::dot( tmpVector, right ); + + direction = m_lookAt - m_location; + if( approxZero( direction.abs( ) ) ) + { + // Camera location and look_at point are the same + direction = directionDefault; + } + + // normalize new direction + direction /= direction.abs( ); + + tmpVector = right; + right = PMVector::cross( m_sky, direction ); + + if( approxZero( right.abs( ) ) ) + right = tmpVector; + + right /= right.abs( ); + up = PMVector::cross( direction, right ); + direction *= directionLen; + + if( handedness > 0.0 ) + right *= rightLen; + else + right *= -rightLen; + up *= upLen; +} + +QString PMCamera::cameraTypeToString( PMCamera::CameraType t ) +{ + QString str( "perspective" ); + switch( t ) + { + case Perspective: + break; + case Orthographic: + str = "orthographic"; + break; + case FishEye: + str = "fisheye"; + break; + case UltraWideAngle: + str = "ultra_wide_angle"; + break; + case Omnimax: + str = "omnimax"; + break; + case Panoramic: + str = "panoramic"; + break; + case Cylinder: + str = "cylinder"; + break; + } + return str; +} + +PMCamera::CameraType PMCamera::stringToCameraType( const QString& str ) +{ + CameraType t = Perspective; + + if( str == "perspective" ) + t = Perspective; + else if( str == "orthographic" ) + t = Orthographic; + else if( str == "fisheye" ) + t = FishEye; + else if( str == "ultra_wide_angle" ) + t = UltraWideAngle; + else if( str == "omnimax" ) + t = Omnimax; + else if( str == "panoramic" ) + t = Panoramic; + else if( str == "cylinder" ) + t = Cylinder; + else + kdDebug( PMArea ) << "Unknown camera type\n"; + + return t; +} + +void PMCamera::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + + Base::cleanUp( ); +} |