You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/kpovmodeler/pmcamera.cpp

770 lines
22 KiB

/*
**************************************************************************
description
--------------------
copyright : (C) 2000-2001 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 "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( )
{
}
TQString PMCamera::description( ) const
{
return i18n( "camera" );
}
void PMCamera::serialize( TQDomElement& e, TQDomDocument& 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( TQWidget* 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;
}
TQString PMCamera::cameraTypeToString( PMCamera::CameraType t )
{
TQString 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 TQString& 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( );
}