|
|
|
/*
|
|
|
|
**************************************************************************
|
|
|
|
description
|
|
|
|
--------------------
|
|
|
|
copyright : (C) 2003 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 "pmspheresweep.h"
|
|
|
|
|
|
|
|
#include "pmxmlhelper.h"
|
|
|
|
#include "pmspheresweepedit.h"
|
|
|
|
#include "pmmemento.h"
|
|
|
|
#include "pmviewstructure.h"
|
|
|
|
#include "pm3dcontrolpoint.h"
|
|
|
|
#include "pmdistancecontrolpoint.h"
|
|
|
|
#include "pmsplinememento.h"
|
|
|
|
#include "pmdefaults.h"
|
|
|
|
#include "pmenumproperty.h"
|
|
|
|
#include "pmobjectaction.h"
|
|
|
|
#include "pmpoint.h"
|
|
|
|
#include "pmmatrix.h"
|
|
|
|
|
|
|
|
#include <klocale.h>
|
|
|
|
|
|
|
|
const int defaultNumberOfPoints = 2;
|
|
|
|
const PMVector defaultPoint[defaultNumberOfPoints] =
|
|
|
|
{
|
|
|
|
PMVector( 0.0, 1.0, 0.0 ),
|
|
|
|
PMVector( 0.0, 0.0, 0.0 )
|
|
|
|
};
|
|
|
|
const double defaultRadii[defaultNumberOfPoints] =
|
|
|
|
{
|
|
|
|
0.3, 0.5
|
|
|
|
};
|
|
|
|
|
|
|
|
const double defaultTolerance = 1e-6;
|
|
|
|
const PMSphereSweep::SplineType defaultSplineType = PMSphereSweep::LinearSpline;
|
|
|
|
|
|
|
|
PMDefinePropertyClass( PMSphereSweep, PMSphereSweepProperty );
|
|
|
|
PMDefineEnumPropertyClass( PMSphereSweep, PMSphereSweep::SplineType, PMSplineTypeProperty );
|
|
|
|
|
|
|
|
PMMetaObject* PMSphereSweep::s_pMetaObject = 0;
|
|
|
|
PMObject* createNewSphereSweep( PMPart* part )
|
|
|
|
{
|
|
|
|
return new PMSphereSweep( part );
|
|
|
|
}
|
|
|
|
|
|
|
|
int PMSphereSweep::s_rSteps = c_defaultSphereSweepRSteps;
|
|
|
|
int PMSphereSweep::s_sSteps = c_defaultSphereSweepSSteps;
|
|
|
|
int PMSphereSweep::s_parameterKey = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Memento for @ref PMLathe
|
|
|
|
*/
|
|
|
|
class PMSphereSweepMemento : public PMSplineMemento
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Creates a memento for the object originator
|
|
|
|
*/
|
|
|
|
PMSphereSweepMemento( PMObject* originator )
|
|
|
|
: PMSplineMemento( originator )
|
|
|
|
{
|
|
|
|
m_bRadiiSaved = false;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Deletes the memento
|
|
|
|
*/
|
|
|
|
virtual ~PMSphereSweepMemento( ) { };
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Saves the radii
|
|
|
|
*/
|
|
|
|
void setRadii( const TQValueList<double>& r )
|
|
|
|
{
|
|
|
|
if( !m_bRadiiSaved )
|
|
|
|
{
|
|
|
|
// Direct assignment does not work with TQt 2.3.x
|
|
|
|
// The list will be changed later in a graphical
|
|
|
|
// change because TQValueList::detach( ) is called
|
|
|
|
// too late!
|
|
|
|
// Copy the list by hand.
|
|
|
|
|
|
|
|
TQValueList<double>::ConstIterator it = r.begin( );
|
|
|
|
for( ; it != r.end( ); ++it )
|
|
|
|
m_radii.append( *it );
|
|
|
|
|
|
|
|
m_bRadiiSaved = true;
|
|
|
|
addChange( PMCData );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Returns the radii
|
|
|
|
*/
|
|
|
|
TQValueList<double> radii( ) const
|
|
|
|
{
|
|
|
|
if( !m_bRadiiSaved )
|
|
|
|
kdError( PMArea ) << "Radii points not saved in PMSphereSweepMemento::radii\n";
|
|
|
|
return m_radii;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Returns true if the spline points were saved
|
|
|
|
*/
|
|
|
|
bool radiiSaved( ) const { return m_bRadiiSaved; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
/**
|
|
|
|
* The stored radii
|
|
|
|
*/
|
|
|
|
TQValueList<double> m_radii;
|
|
|
|
bool m_bRadiiSaved;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
PMSphereSweep::PMSphereSweep( PMPart* part )
|
|
|
|
: Base( part )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for( i = 0; i < defaultNumberOfPoints; i++ )
|
|
|
|
{
|
|
|
|
m_points.append( defaultPoint[i] );
|
|
|
|
m_radii.append( defaultRadii[i] );
|
|
|
|
}
|
|
|
|
m_splineType = defaultSplineType;
|
|
|
|
m_tolerance = defaultTolerance;
|
|
|
|
}
|
|
|
|
|
|
|
|
PMSphereSweep::PMSphereSweep( const PMSphereSweep& l )
|
|
|
|
: Base( l )
|
|
|
|
{
|
|
|
|
m_points = l.m_points;
|
|
|
|
m_radii = l.m_radii;
|
|
|
|
m_splineType = l.m_splineType;
|
|
|
|
m_tolerance = l.m_tolerance;
|
|
|
|
}
|
|
|
|
|
|
|
|
PMSphereSweep::~PMSphereSweep( )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString PMSphereSweep::description( ) const
|
|
|
|
{
|
|
|
|
return i18n( "sphere sweep" );
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::serialize( TQDomElement& e, TQDomDocument& doc ) const
|
|
|
|
{
|
|
|
|
TQDomElement data = doc.createElement( "extra_data" );
|
|
|
|
TQDomElement p;
|
|
|
|
|
|
|
|
e.setAttribute( "spline_type", m_splineType );
|
|
|
|
e.setAttribute( "tolerance", m_tolerance );
|
|
|
|
|
|
|
|
TQValueList<PMVector>::ConstIterator it;
|
|
|
|
TQValueList<double>::ConstIterator it2;
|
|
|
|
for( it = m_points.begin( ), it2 = m_radii.begin( );
|
|
|
|
it != m_points.end( ) && it2 != m_radii.end( ); ++it, ++it2 )
|
|
|
|
{
|
|
|
|
p = doc.createElement( "point" );
|
|
|
|
p.setAttribute( "vector", ( *it ).serializeXML( ) );
|
|
|
|
p.setAttribute( "radius", *it2 );
|
|
|
|
data.appendChild( p );
|
|
|
|
}
|
|
|
|
|
|
|
|
e.appendChild( data );
|
|
|
|
Base::serialize( e, doc );
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::readAttributes( const PMXMLHelper& h )
|
|
|
|
{
|
|
|
|
m_splineType = ( SplineType ) h.intAttribute( "spline_type", defaultSplineType );
|
|
|
|
m_tolerance = h.doubleAttribute( "tolerance", defaultTolerance );
|
|
|
|
|
|
|
|
m_points.clear( );
|
|
|
|
m_radii.clear( );
|
|
|
|
PMVector v( 3 );
|
|
|
|
|
|
|
|
TQDomElement e = h.extraData( );
|
|
|
|
if( !e.isNull( ) )
|
|
|
|
{
|
|
|
|
TQDomNode c = e.firstChild( );
|
|
|
|
while( !c.isNull( ) )
|
|
|
|
{
|
|
|
|
if( c.isElement( ) )
|
|
|
|
{
|
|
|
|
TQDomElement ce = c.toElement( );
|
|
|
|
if( ce.tagName( ) == "point" )
|
|
|
|
{
|
|
|
|
TQString str = ce.attribute( "vector" );
|
|
|
|
if( !str.isNull( ) )
|
|
|
|
{
|
|
|
|
v.loadXML( str );
|
|
|
|
m_points.append( v );
|
|
|
|
TQString str = ce.attribute( "radius" );
|
|
|
|
m_radii.append( str.toDouble( ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c = c.nextSibling( );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Base::readAttributes( h );
|
|
|
|
}
|
|
|
|
|
|
|
|
PMMetaObject* PMSphereSweep::metaObject( ) const
|
|
|
|
{
|
|
|
|
if( !s_pMetaObject )
|
|
|
|
{
|
|
|
|
s_pMetaObject = new PMMetaObject( "SphereSweep", Base::metaObject( ),
|
|
|
|
createNewSphereSweep );
|
|
|
|
s_pMetaObject->addProperty(
|
|
|
|
new PMSphereSweepProperty( "tolerance", &PMSphereSweep::setTolerance, &PMSphereSweep::tolerance ) );
|
|
|
|
PMSplineTypeProperty* p = new PMSplineTypeProperty(
|
|
|
|
"splineType", &PMSphereSweep::setSplineType, &PMSphereSweep::splineType );
|
|
|
|
p->addEnumValue( "LinearSpline", LinearSpline );
|
|
|
|
p->addEnumValue( "BSpline", BSpline );
|
|
|
|
p->addEnumValue( "CubicSpline", CubicSpline );
|
|
|
|
s_pMetaObject->addProperty( p );
|
|
|
|
//s_pMetaObject->addProperty( new PMPointProperty( ) );
|
|
|
|
}
|
|
|
|
return s_pMetaObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::cleanUp( ) const
|
|
|
|
{
|
|
|
|
if( s_pMetaObject )
|
|
|
|
{
|
|
|
|
delete s_pMetaObject;
|
|
|
|
s_pMetaObject = 0;
|
|
|
|
}
|
|
|
|
Base::cleanUp( );
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::setSplineType( PMSphereSweep::SplineType t )
|
|
|
|
{
|
|
|
|
if( m_splineType != t )
|
|
|
|
{
|
|
|
|
if( m_pMemento )
|
|
|
|
m_pMemento->addData( s_pMetaObject, PMSplineTypeID, ( int ) m_splineType );
|
|
|
|
setViewStructureChanged( );
|
|
|
|
m_splineType = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::setTolerance( double t )
|
|
|
|
{
|
|
|
|
if( m_tolerance != t )
|
|
|
|
{
|
|
|
|
if( m_pMemento )
|
|
|
|
m_pMemento->addData( s_pMetaObject, PMToleranceID, m_tolerance );
|
|
|
|
m_tolerance = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::setPoints( const TQValueList<PMVector>& points )
|
|
|
|
{
|
|
|
|
if( m_points != points )
|
|
|
|
{
|
|
|
|
if( m_pMemento )
|
|
|
|
( ( PMSplineMemento* ) m_pMemento )->setSplinePoints( m_points );
|
|
|
|
|
|
|
|
setViewStructureChanged( );
|
|
|
|
m_points = points;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::setRadii( const TQValueList<double>& radii )
|
|
|
|
{
|
|
|
|
if( m_radii != radii )
|
|
|
|
{
|
|
|
|
if( m_pMemento )
|
|
|
|
( ( PMSphereSweepMemento* ) m_pMemento )->setRadii( m_radii );
|
|
|
|
|
|
|
|
setViewStructureChanged( );
|
|
|
|
m_radii = radii;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PMDialogEditBase* PMSphereSweep::editWidget( TQWidget* parent ) const
|
|
|
|
{
|
|
|
|
return new PMSphereSweepEdit( parent );
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::createMemento( )
|
|
|
|
{
|
|
|
|
if( m_pMemento )
|
|
|
|
delete m_pMemento;
|
|
|
|
m_pMemento = new PMSphereSweepMemento( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::restoreMemento( PMMemento* s )
|
|
|
|
{
|
|
|
|
PMSphereSweepMemento* m = ( PMSphereSweepMemento* ) s;
|
|
|
|
PMMementoDataIterator it( s );
|
|
|
|
PMMementoData* data;
|
|
|
|
|
|
|
|
for( ; it.current( ); ++it )
|
|
|
|
{
|
|
|
|
data = it.current( );
|
|
|
|
if( data->objectType( ) == s_pMetaObject )
|
|
|
|
{
|
|
|
|
switch( data->valueID( ) )
|
|
|
|
{
|
|
|
|
case PMSplineTypeID:
|
|
|
|
setSplineType( ( SplineType ) data->intData( ) );
|
|
|
|
break;
|
|
|
|
case PMToleranceID:
|
|
|
|
setTolerance( data->doubleData( ) );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
kdError( PMArea ) << "Wrong ID in PMSphereSweep::restoreMemento\n";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( m->splinePointsSaved( ) )
|
|
|
|
setPoints( m->splinePoints( ) );
|
|
|
|
if( m->radiiSaved( ) )
|
|
|
|
setRadii( m->radii( ) );
|
|
|
|
|
|
|
|
Base::restoreMemento( s );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PMSphereSweep::createViewStructure( )
|
|
|
|
{
|
|
|
|
int numSegments = 0;
|
|
|
|
int numSpheres = m_points.size( );
|
|
|
|
m_segments.clear( );
|
|
|
|
|
|
|
|
int rSteps = (int)( ( (float)s_rSteps / 2 ) * ( displayDetail( ) + 1 ) );
|
|
|
|
int sSteps = (int)( ( (float)s_sSteps / 2 ) * ( displayDetail( ) + 1 ) );
|
|
|
|
|
|
|
|
switch ( m_splineType )
|
|
|
|
{
|
|
|
|
case LinearSpline:
|
|
|
|
numSegments = numSpheres - 1;
|
|
|
|
setLinear( sSteps );
|
|
|
|
break;
|
|
|
|
case BSpline:
|
|
|
|
numSegments = numSpheres - 3;
|
|
|
|
setCurved( false, sSteps );
|
|
|
|
break;
|
|
|
|
case CubicSpline:
|
|
|
|
numSegments = numSpheres - 3;
|
|
|
|
setCurved( true, sSteps );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Calculates sphere points
|
|
|
|
int numPoints = ( ( rSteps * ( rSteps - 2 ) ) + 2 ) *
|
|
|
|
( numSegments + 1 );
|
|
|
|
//Calculates segments points
|
|
|
|
numPoints += ( rSteps * sSteps ) * numSegments;
|
|
|
|
|
|
|
|
//Calculates sphere lines
|
|
|
|
int numLines = ( rSteps * ( rSteps + rSteps - 3 ) ) *
|
|
|
|
( numSegments + 1 );
|
|
|
|
//Calculates segments lines
|
|
|
|
numLines += ( ( sSteps * rSteps ) +
|
|
|
|
( ( sSteps - 1 ) * rSteps ) ) * numSegments;
|
|
|
|
|
|
|
|
if ( !m_pViewStructure )
|
|
|
|
{
|
|
|
|
m_pViewStructure = new PMViewStructure( numPoints, numLines );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_pViewStructure->points( ).resize( numPoints );
|
|
|
|
m_pViewStructure->lines( ).resize( numLines );
|
|
|
|
}
|
|
|
|
|
|
|
|
PMPointArray& points = m_pViewStructure->points( );
|
|
|
|
PMLineArray& lines = m_pViewStructure->lines( );
|
|
|
|
m_nextPoint = m_nextLine = 0;
|
|
|
|
|
|
|
|
PMVector v1, v2;
|
|
|
|
double rotval = M_PI / ( rSteps / 2 );
|
|
|
|
|
|
|
|
createSphere( m_segments[0].points[0], m_segments[0].radii[0], rSteps );
|
|
|
|
for ( int i = 0; i < numSegments; ++i )
|
|
|
|
{
|
|
|
|
for ( int j = 0; j < sSteps; ++ j )
|
|
|
|
{
|
|
|
|
v1 = m_segments[i].points[sSteps] - m_segments[i].points[0];
|
|
|
|
v1 = PMVector::cross( m_segments[i].direction[j], v1.orthogonal( ) );
|
|
|
|
v1 = ( v1 * ( 1 / v1.abs( ) ) ) * m_segments[i].radii[j];
|
|
|
|
|
|
|
|
for ( int k = 0; k < rSteps; ++k )
|
|
|
|
{
|
|
|
|
v2 = PMMatrix::rotation( m_segments[i].direction[j],
|
|
|
|
( rotval * k ) ) * v1;
|
|
|
|
points[m_nextPoint++] = PMPoint( v2 + m_segments[i].points[j] );
|
|
|
|
if ( k < ( rSteps - 1 ) )
|
|
|
|
lines[m_nextLine++] = PMLine(
|
|
|
|
m_nextPoint - 1, m_nextPoint );
|
|
|
|
else
|
|
|
|
lines[m_nextLine++] = PMLine(
|
|
|
|
m_nextPoint - 1, m_nextPoint - rSteps );
|
|
|
|
|
|
|
|
if ( j < ( sSteps - 1 ) )
|
|
|
|
{
|
|
|
|
lines[m_nextLine++] = PMLine(
|
|
|
|
m_nextPoint - 1, m_nextPoint + ( rSteps - 1 ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
createSphere( m_segments[i].points[sSteps - 1],
|
|
|
|
m_segments[i].radii[sSteps - 1], rSteps );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::controlPoints( PMControlPointList& list )
|
|
|
|
{
|
|
|
|
TQValueList<PMVector>::Iterator it;
|
|
|
|
TQValueList<double>::Iterator it2;
|
|
|
|
int i, nr;
|
|
|
|
|
|
|
|
for( it = m_points.begin( ), it2 = m_radii.begin( ), nr = 1, i = 0;
|
|
|
|
it != m_points.end( ) && it2 != m_radii.end( ); ++it, ++it2, ++nr )
|
|
|
|
{
|
|
|
|
PM3DControlPoint* p = new PM3DControlPoint( *it, i++,
|
|
|
|
i18n( "Center %1" ).arg( nr ) );
|
|
|
|
list.append( p );
|
|
|
|
list.append( new PMDistanceControlPoint( p, PMVector( 1.0, 0.0, 0.0 ),
|
|
|
|
*it2, i++,
|
|
|
|
i18n( "Radius %1 (x)" ).arg( nr ),
|
|
|
|
true ) );
|
|
|
|
list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 1.0, 0.0 ),
|
|
|
|
*it2, i++,
|
|
|
|
i18n( "Radius %1 (y)" ).arg( nr ),
|
|
|
|
true ) );
|
|
|
|
list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 0.0, 1.0 ),
|
|
|
|
*it2, i++,
|
|
|
|
i18n( "Radius %1 (z)" ).arg( nr ),
|
|
|
|
true ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::controlPointsChanged( PMControlPointList& list )
|
|
|
|
{
|
|
|
|
PMControlPointListIterator it1( list );
|
|
|
|
TQValueList<PMVector>::Iterator pit = m_points.begin( );
|
|
|
|
TQValueList<double>::Iterator rit = m_radii.begin( );
|
|
|
|
int i;
|
|
|
|
PM3DControlPoint* p;
|
|
|
|
PMDistanceControlPoint* r;
|
|
|
|
bool firstChange = true;
|
|
|
|
|
|
|
|
for( ; it1.current( ) && pit != m_points.end( ) && rit != m_radii.end( );
|
|
|
|
++pit, ++rit )
|
|
|
|
{
|
|
|
|
p = ( PM3DControlPoint* ) it1.current( );
|
|
|
|
if( p->changed( ) )
|
|
|
|
{
|
|
|
|
if( firstChange )
|
|
|
|
{
|
|
|
|
firstChange = false;
|
|
|
|
setViewStructureChanged( );
|
|
|
|
}
|
|
|
|
if( m_pMemento )
|
|
|
|
{
|
|
|
|
PMSphereSweepMemento* m = ( PMSphereSweepMemento* ) m_pMemento;
|
|
|
|
if( !m->splinePointsSaved( ) )
|
|
|
|
m->setSplinePoints( m_points );
|
|
|
|
}
|
|
|
|
( *pit ) = p->point( );
|
|
|
|
}
|
|
|
|
++it1;
|
|
|
|
|
|
|
|
for( i = 0; i < 3 && it1.current( ); i++ )
|
|
|
|
{
|
|
|
|
r = ( PMDistanceControlPoint* ) it1.current( );
|
|
|
|
if( r->changed( ) )
|
|
|
|
{
|
|
|
|
if( firstChange )
|
|
|
|
{
|
|
|
|
firstChange = false;
|
|
|
|
setViewStructureChanged( );
|
|
|
|
}
|
|
|
|
if( m_pMemento )
|
|
|
|
{
|
|
|
|
PMSphereSweepMemento* m = ( PMSphereSweepMemento* ) m_pMemento;
|
|
|
|
if( !m->radiiSaved( ) )
|
|
|
|
m->setRadii( m_radii );
|
|
|
|
}
|
|
|
|
( *rit ) = r->distance( );
|
|
|
|
}
|
|
|
|
++it1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for( it1.toFirst( ), rit = m_radii.begin( ); rit != m_radii.end( ); ++rit )
|
|
|
|
{
|
|
|
|
++it1;
|
|
|
|
for( i = 0; i < 3; ++i, ++it1 )
|
|
|
|
( ( PMDistanceControlPoint* ) *it1 )->setDistance( *rit );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::addObjectActions( const PMControlPointList& /*cp*/,
|
|
|
|
TQPtrList<PMObjectAction>& actions )
|
|
|
|
{
|
|
|
|
PMObjectAction* a;
|
|
|
|
|
|
|
|
a = new PMObjectAction( s_pMetaObject, PMSplitSegmentID,
|
|
|
|
i18n( "Add Sphere" ) );
|
|
|
|
actions.append( a );
|
|
|
|
|
|
|
|
a = new PMObjectAction( s_pMetaObject, PMJoinSegmentsID,
|
|
|
|
i18n( "Remove Sphere" ) );
|
|
|
|
int np = m_points.count( );
|
|
|
|
int minp = 2;
|
|
|
|
switch( m_splineType )
|
|
|
|
{
|
|
|
|
case LinearSpline:
|
|
|
|
minp = 2;
|
|
|
|
break;
|
|
|
|
case BSpline:
|
|
|
|
minp = 4;
|
|
|
|
break;
|
|
|
|
case CubicSpline:
|
|
|
|
minp = 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( np < minp )
|
|
|
|
a->setEnabled( false );
|
|
|
|
actions.append( a );
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::objectActionCalled( const PMObjectAction* action,
|
|
|
|
const PMControlPointList& cp,
|
|
|
|
const TQPtrList<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 PMSphereSweep::objectActionCalled\n";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Base::objectActionCalled( action, cp, cpViewPosition, clickPosition );
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::splitSegment( const PMControlPointList& /*cp*/,
|
|
|
|
const TQPtrList<PMVector>& cpViewPosition,
|
|
|
|
const PMVector& clickPosition )
|
|
|
|
{
|
|
|
|
// find nearest segment
|
|
|
|
int nump = cpViewPosition.count( ) / 4 - 1;
|
|
|
|
double abs = 0.0, minabs = 1e10;
|
|
|
|
int ns = -1;
|
|
|
|
int i, j;
|
|
|
|
PMVector mid( 3 ), dist( 2 );
|
|
|
|
|
|
|
|
TQPtrListIterator<PMVector> it1( cpViewPosition );
|
|
|
|
TQPtrListIterator<PMVector> it2( cpViewPosition );
|
|
|
|
++it2;
|
|
|
|
|
|
|
|
for( i = 0; i < nump; i++ )
|
|
|
|
{
|
|
|
|
bool skip = false;
|
|
|
|
switch( m_splineType )
|
|
|
|
{
|
|
|
|
case LinearSpline:
|
|
|
|
break;
|
|
|
|
case BSpline:
|
|
|
|
case CubicSpline:
|
|
|
|
if( ( i == 0 ) || ( i == ( nump - 1 ) ) )
|
|
|
|
skip = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !skip )
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for( j = 0; j < 4; j++ )
|
|
|
|
{
|
|
|
|
++it1;
|
|
|
|
++it2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add a new segment
|
|
|
|
TQValueList<PMVector> newPoints = m_points;
|
|
|
|
TQValueList<double> newRadii = m_radii;
|
|
|
|
|
|
|
|
TQValueList<PMVector>::Iterator it = newPoints.at( ( unsigned ) ns );
|
|
|
|
TQValueList<PMVector>::Iterator hit = it;
|
|
|
|
++it;
|
|
|
|
mid = ( *it + *hit ) / 2;
|
|
|
|
newPoints.insert( it, mid );
|
|
|
|
|
|
|
|
TQValueList<double>::Iterator rit = newRadii.at( ( unsigned ) ns );
|
|
|
|
TQValueList<double>::Iterator rhit = rit;
|
|
|
|
++rit;
|
|
|
|
newRadii.insert( rit, ( *rit + *rhit ) / 2 );
|
|
|
|
|
|
|
|
setPoints( newPoints );
|
|
|
|
setRadii( newRadii );
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::joinSegments( const PMControlPointList& /*cp*/,
|
|
|
|
const TQPtrList<PMVector>& cpViewPosition,
|
|
|
|
const PMVector& clickPosition )
|
|
|
|
{
|
|
|
|
// find nearest point
|
|
|
|
int nump = cpViewPosition.count( ) / 4;
|
|
|
|
int minp = 0;
|
|
|
|
|
|
|
|
switch( m_splineType )
|
|
|
|
{
|
|
|
|
case LinearSpline:
|
|
|
|
minp = 3;
|
|
|
|
break;
|
|
|
|
case BSpline:
|
|
|
|
case CubicSpline:
|
|
|
|
minp = 5;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( nump < minp )
|
|
|
|
{
|
|
|
|
kdError( PMArea ) << "Not enough points in PMSphereSweep::joinSegments\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
double abs = 0.0, minabs = 1e10;
|
|
|
|
int ns = -1;
|
|
|
|
int i, j;
|
|
|
|
PMVector* p;
|
|
|
|
PMVector dist( 2 );
|
|
|
|
|
|
|
|
TQPtrListIterator<PMVector> it1( cpViewPosition );
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
for( j = 0; j < 4; j++ )
|
|
|
|
++it1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// join two segments
|
|
|
|
TQValueList<PMVector> newPoints = m_points;
|
|
|
|
TQValueList<PMVector>::Iterator it;
|
|
|
|
TQValueList<double> newRadii = m_radii;
|
|
|
|
TQValueList<double>::Iterator rit;
|
|
|
|
|
|
|
|
// never remove the first or last point
|
|
|
|
if( ns == 0 )
|
|
|
|
ns++;
|
|
|
|
if( ns == ( nump - 1 ) )
|
|
|
|
ns--;
|
|
|
|
it = newPoints.at( ns );
|
|
|
|
newPoints.remove( it );
|
|
|
|
rit = newRadii.at( ns );
|
|
|
|
newRadii.remove( rit );
|
|
|
|
|
|
|
|
setPoints( newPoints );
|
|
|
|
setRadii( newRadii );
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::setRSteps( int r )
|
|
|
|
{
|
|
|
|
if( r >= 4 )
|
|
|
|
s_rSteps = r;
|
|
|
|
else
|
|
|
|
kdDebug( PMArea ) << "PMSphereSweep::setRSteps: R must be greater than 3\n";
|
|
|
|
s_parameterKey++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::setSSteps( int s )
|
|
|
|
{
|
|
|
|
if( s >= 1 )
|
|
|
|
s_sSteps = s;
|
|
|
|
else
|
|
|
|
kdDebug( PMArea ) << "PMSphereSweep::setSSteps: S must be greater than 0\n";
|
|
|
|
s_parameterKey++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::setLinear( int sSteps )
|
|
|
|
{
|
|
|
|
int numsegments = ( m_points.size( ) - 1 );
|
|
|
|
|
|
|
|
double raddif;
|
|
|
|
PMVector diff, angle;
|
|
|
|
Segment seg;
|
|
|
|
|
|
|
|
for ( int i = 0; i < numsegments; ++i )
|
|
|
|
{
|
|
|
|
seg.points.clear( );
|
|
|
|
seg.radii.clear( );
|
|
|
|
seg.direction.clear( );
|
|
|
|
diff = ( m_points[i + 1] - m_points[i] ) / ( sSteps - 1.0 );
|
|
|
|
raddif = ( m_radii[i + 1] - m_radii[i] ) / ( sSteps - 1.0 );
|
|
|
|
angle = diff * ( 1 / diff.abs( ) );
|
|
|
|
|
|
|
|
for ( int j = 0; j < sSteps; ++j )
|
|
|
|
{
|
|
|
|
seg.points.append( m_points[i] + ( diff * j ) );
|
|
|
|
seg.radii.append( m_radii[i] + ( raddif * j ) );
|
|
|
|
seg.direction.append( angle );
|
|
|
|
}
|
|
|
|
m_segments.append( seg );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::setCurved( bool cubic, int sSteps )
|
|
|
|
{
|
|
|
|
int numsegments = ( m_points.size( ) - 3 );
|
|
|
|
PMVector centres[4];
|
|
|
|
PMVector vtr;
|
|
|
|
double divs = 1.0 / ( sSteps - 1.0 );
|
|
|
|
double raddif;
|
|
|
|
Segment seg;
|
|
|
|
|
|
|
|
for ( int i = 0; i < numsegments; ++i )
|
|
|
|
{
|
|
|
|
seg.points.clear( );
|
|
|
|
seg.radii.clear( );
|
|
|
|
seg.direction.clear( );
|
|
|
|
raddif = ( m_radii[i + 2] - m_radii[i + 1] ) / ( sSteps - 1.0 );
|
|
|
|
for ( int j = 0; j < 4; ++j )
|
|
|
|
centres[j] = m_points[ i + j ];
|
|
|
|
|
|
|
|
for ( int j = 0; j < sSteps; ++j )
|
|
|
|
{
|
|
|
|
if ( cubic )
|
|
|
|
seg.points.append( catmullRom( centres, ( divs * j ) ) );
|
|
|
|
else
|
|
|
|
seg.points.append( bSpline( centres, ( divs * j ) ) );
|
|
|
|
|
|
|
|
seg.radii.append( m_radii[i + 1] + ( raddif * j ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
seg.direction.append( seg.points[0] - seg.points[1] );
|
|
|
|
for ( int j = 1; j < ( sSteps - 1 ) ; ++ j )
|
|
|
|
{
|
|
|
|
vtr = seg.points[ j - 1 ] - seg.points[j];
|
|
|
|
vtr += seg.points[j] - seg.points[ j + 1 ];
|
|
|
|
seg.direction.append( vtr );
|
|
|
|
}
|
|
|
|
seg.direction.append( seg.points[ sSteps - 2 ] -
|
|
|
|
seg.points[ sSteps - 1 ] );
|
|
|
|
|
|
|
|
m_segments.append( seg );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PMVector PMSphereSweep::catmullRom( PMVector *v, double t )
|
|
|
|
{
|
|
|
|
PMVector rst;
|
|
|
|
double t2 = t * t;
|
|
|
|
double t3 = t * t * t;
|
|
|
|
|
|
|
|
rst.setX( (
|
|
|
|
( -t3 + 2 * t2 - t ) * v[0].x( ) +
|
|
|
|
( 3 * t3 -5 * t2 + 2 ) * v[1].x( ) +
|
|
|
|
( -3 * t3 + 4 * t2 + t ) * v[2].x( ) +
|
|
|
|
( t3 - t2 ) * v[3].x( )
|
|
|
|
) / 2
|
|
|
|
);
|
|
|
|
rst.setY( (
|
|
|
|
( -t3 + 2 * t2 -t ) * v[0].y( ) +
|
|
|
|
( 3 * t3 -5 * t2 + 2 ) * v[1].y( ) +
|
|
|
|
( -3 * t3 + 4 * t2 + t ) * v[2].y( ) +
|
|
|
|
( t3 - t2) * v[3].y( )
|
|
|
|
) / 2
|
|
|
|
);
|
|
|
|
rst.setZ( (
|
|
|
|
( -t3 + 2 * t2 - t ) * v[0].z( ) +
|
|
|
|
( 3 * t3 -5 * t2 + 2 ) * v[1].z( ) +
|
|
|
|
( -3 * t3 + 4 * t2 + t ) * v[2].z( ) +
|
|
|
|
( t3 - t2 ) * v[3].z( )
|
|
|
|
) / 2
|
|
|
|
);
|
|
|
|
|
|
|
|
return rst;
|
|
|
|
}
|
|
|
|
|
|
|
|
PMVector PMSphereSweep::bSpline( PMVector *v, double t )
|
|
|
|
{
|
|
|
|
PMVector rst;
|
|
|
|
double t2 = t * t;
|
|
|
|
double t3 = t * t * t;
|
|
|
|
|
|
|
|
rst.setX( (
|
|
|
|
( -t3 + 3 * t2 -3 * t + 1 ) * v[0].x( ) +
|
|
|
|
( 3 * t3 -6 * t2 + 4 ) * v[1].x( ) +
|
|
|
|
( -3 * t3 + 3 * t2 + 3 * t + 1 ) * v[2].x( ) +
|
|
|
|
( t3 ) * v[3].x( )
|
|
|
|
) / 6
|
|
|
|
);
|
|
|
|
rst.setY( (
|
|
|
|
( -t3 + 3 * t2 -3 * t + 1 ) * v[0].y( ) +
|
|
|
|
( 3 * t3 -6 * t2 + 4 ) * v[1].y( ) +
|
|
|
|
( -3 * t3 + 3 * t2 + 3 * t + 1 ) * v[2].y( ) +
|
|
|
|
( t3 ) * v[3].y( )
|
|
|
|
) / 6
|
|
|
|
);
|
|
|
|
rst.setZ( (
|
|
|
|
( -t3 + 3 * t2 -3 * t + 1 ) * v[0].z( ) +
|
|
|
|
( 3 * t3 -6 * t2 + 4 ) * v[1].z( ) +
|
|
|
|
( -3 * t3 + 3 * t2 + 3 * t + 1 ) * v[2].z( ) +
|
|
|
|
( t3 ) * v[3].z( )
|
|
|
|
) / 6
|
|
|
|
);
|
|
|
|
|
|
|
|
return rst;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PMSphereSweep::createSphere( PMVector v, double r, int rSteps )
|
|
|
|
{
|
|
|
|
PMPointArray& points = m_pViewStructure->points( );
|
|
|
|
PMLineArray& lines = m_pViewStructure->lines( );
|
|
|
|
|
|
|
|
PMVector point = PMVector( 0, 1, 0 ) * r;
|
|
|
|
int pointUp = m_nextPoint++;
|
|
|
|
int pointDown = m_nextPoint++;
|
|
|
|
double rotVal1 = M_PI / ( rSteps - 1 );
|
|
|
|
double rotVal2 = ( M_PI / rSteps ) * 2;
|
|
|
|
|
|
|
|
points[pointUp] = PMPoint ( point + v );
|
|
|
|
points[pointDown] = PMPoint ( ( PMMatrix::rotation( 0, 0, M_PI ) * point ) + v );
|
|
|
|
|
|
|
|
|
|
|
|
for ( int i = 0; i < rSteps; ++i )
|
|
|
|
{
|
|
|
|
lines[ m_nextLine++] = PMLine( pointUp, m_nextPoint );
|
|
|
|
for ( int j = 1; j < ( rSteps - 1 ); ++j )
|
|
|
|
{
|
|
|
|
points[m_nextPoint++] = PMPoint(
|
|
|
|
( PMMatrix::rotation( ( rotVal1 * j ), ( rotVal2 * i ), 0 ) * point ) + v );
|
|
|
|
|
|
|
|
if ( i < ( rSteps - 1 ) )
|
|
|
|
lines[m_nextLine++] = PMLine( m_nextPoint - 1, m_nextPoint +
|
|
|
|
rSteps - 3 );
|
|
|
|
else
|
|
|
|
lines[m_nextLine++] = PMLine( m_nextPoint - 1, m_nextPoint -
|
|
|
|
( ( rSteps - 1 ) * ( rSteps - 2 ) ) - 1 );
|
|
|
|
|
|
|
|
if ( j < ( rSteps - 2 ) )
|
|
|
|
lines[m_nextLine++] = PMLine( m_nextPoint - 1, m_nextPoint );
|
|
|
|
else
|
|
|
|
lines[m_nextLine++] = PMLine( m_nextPoint - 1, pointDown );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|