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/pmprism.cpp

1188 lines
32 KiB

/*
**************************************************************************
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 "pmprism.h"
#include "pmxmlhelper.h"
#include "pmprismedit.h"
#include "pmmemento.h"
#include "pmviewstructure.h"
#include "pm2dcontrolpoint.h"
#include "pmdistancecontrolpoint.h"
#include "pmprismmemento.h"
#include "pmsplinesegment.h"
#include "pmdefaults.h"
#include "pmenumproperty.h"
#include "pmobjectaction.h"
#include <klocale.h>
const int defaultNumberOfPoints = 6;
const PMVector defaultPoint[defaultNumberOfPoints] =
{
PMVector( 0.5, 1.0 ),
PMVector( 1.0, 0.0 ),
PMVector( 0.5, -1.0 ),
PMVector( -0.5, -1.0 ),
PMVector( -1.0, 0.0 ),
PMVector( -0.5, 1.0 ),
};
const bool defaultSturm = false;
const bool defaultOpen = false;
const PMPrism::SplineType defaultSplineType = PMPrism::LinearSpline;
const PMPrism::SweepType defaultSweepType = PMPrism::LinearSweep;
const double defaultHeight1 = 0.0;
const double defaultHeight2 = 1.0;
int PMPrism::s_sSteps = c_defaultPrismSSteps;
int PMPrism::s_parameterKey = 0;
PMMetaObject* PMPrism::s_pMetaObject = 0;
PMObject* createNewPrism( PMPart* part )
{
return new PMPrism( part );
}
PMDefinePropertyClass( PMPrism, PMPrismProperty );
PMDefineEnumPropertyClass( PMPrism, PMPrism::SplineType, PMSplineTypeProperty );
PMDefineEnumPropertyClass( PMPrism, PMPrism::SweepType, PMSweepTypeProperty );
class PMPointProperty : public PMPropertyBase
{
public:
PMPointProperty( )
: PMPropertyBase( "splinePoints", PMVariant::Vector )
{
m_index[0] = 0;
m_index[1] = 0;
}
virtual int dimensions( ) const { return 2; }
virtual void setIndex( int dimension, int index )
{
if( dimension == 0 || dimension == 1 )
m_index[dimension] = index;
}
virtual int size( PMObject* object, int dimension ) const
{
PMPrism* prism = ( PMPrism* ) object;
TQValueList< TQValueList<PMVector> > points = prism->points( );
if( dimension == 0 )
return points.size( );
else
{
TQValueList< TQValueList<PMVector> >::ConstIterator it
= points.at( m_index[0] );
if( it != points.end( ) )
return ( *it ).size( );
}
return 0;
}
protected:
virtual bool setProtected( PMObject* obj, const PMVariant& var )
{
PMPrism* p = ( PMPrism* ) obj;
TQValueList< TQValueList<PMVector> > list = p->points( );
TQValueList< TQValueList<PMVector> >::Iterator sit = list.begin( );
int i;
PMVector v = var.vectorData( );
v.resize( 2 );
for( i = 0; i < m_index[0] && sit != list.end( ); ++i )
++sit;
// expand the list if necessary
for( ; i < m_index[0]; ++i )
list.insert( sit, TQValueList< PMVector >( ) );
if( sit == list.end( ) )
sit = list.insert( sit, TQValueList< PMVector >( ) );
TQValueList<PMVector>::Iterator it = ( *sit ).begin( );
for( i = 0; i < m_index[1] && it != ( *sit ).end( ); ++i )
++it;
// expand the list if necessary
for( ; i < m_index[1]; ++i )
( *sit ).insert( it, v );
if( it == ( *sit ).end( ) )
it = ( *sit ).insert( it, v );
else
*it = v;
p->setPoints( list );
return true;
}
virtual PMVariant getProtected( const PMObject* obj )
{
PMPrism* p = ( PMPrism* ) obj;
TQValueList< TQValueList<PMVector> > list = p->points( );
TQValueList< TQValueList<PMVector> >::ConstIterator sit = list.at( m_index[0] );
if( sit == list.end( ) )
{
kdError( PMArea ) << "Range error in PMPrism::PointProperty::get" << endl;
return PMVariant( );
}
TQValueList<PMVector>::ConstIterator it = ( *sit ).at( m_index[1] );
if( it == ( *sit ).end( ) )
{
kdError( PMArea ) << "Range error in PMPrism::PointProperty::get" << endl;
return PMVariant( );
}
return PMVariant( *it );
}
private:
int m_index[2];
};
PMPrism::PMPrism( PMPart* part )
: Base( part )
{
int i;
TQValueList<PMVector> p;
for( i = 0; i < defaultNumberOfPoints; ++i )
p.append( defaultPoint[i] );
m_points.append( p );
m_splineType = defaultSplineType;
m_sweepType = defaultSweepType;
m_sturm = defaultSturm;
m_open = defaultOpen;
m_height1 = defaultHeight1;
m_height2 = defaultHeight2;
}
PMPrism::PMPrism( const PMPrism& p )
: Base( p )
{
m_splineType = p.m_splineType;
m_sweepType = p.m_sweepType;
m_points = p.m_points;
m_height1 = p.m_height1;
m_height2 = p.m_height2;
m_open = p.m_open;
m_sturm = p.m_sturm;
}
PMPrism::~PMPrism( )
{
}
TQString PMPrism::description( ) const
{
return i18n( "prism" );
}
void PMPrism::serialize( TQDomElement& e, TQDomDocument& doc ) const
{
TQDomElement data = doc.createElement( "extra_data" );
TQDomElement p, p2;
e.setAttribute( "spline_type", m_splineType );
e.setAttribute( "sweep_type", m_sweepType );
e.setAttribute( "sturm", m_sturm );
e.setAttribute( "open", m_open );
e.setAttribute( "height1", m_height1 );
e.setAttribute( "height2", m_height2 );
TQValueList< TQValueList<PMVector> >::ConstIterator it;
TQValueList<PMVector>::ConstIterator it2;
for( it = m_points.begin( ); it != m_points.end( ); ++it )
{
p = doc.createElement( "sub_prism" );
for( it2 = ( *it ).begin( ); it2 != ( *it ).end( ); ++it2 )
{
p2 = doc.createElement( "point" );
p2.setAttribute( "vector", ( *it2 ).serializeXML( ) );
p.appendChild( p2 );
}
data.appendChild( p );
}
e.appendChild( data );
Base::serialize( e, doc );
}
void PMPrism::readAttributes( const PMXMLHelper& h )
{
m_splineType = ( SplineType ) h.intAttribute( "spline_type", defaultSplineType );
m_sweepType = ( SweepType ) h.intAttribute( "sweep_type", defaultSweepType );
m_open = h.boolAttribute( "open", defaultOpen );
m_sturm = h.boolAttribute( "sturm", defaultSturm );
m_height1 = h.doubleAttribute( "height1", defaultHeight1 );
m_height2 = h.doubleAttribute( "height2", defaultHeight2 );
m_points.clear( );
TQValueList<PMVector> list;
PMVector v( 2 );
TQDomElement e = h.extraData( );
if( !e.isNull( ) )
{
TQDomNode sp = e.firstChild( );
while( !sp.isNull( ) )
{
if( sp.isElement( ) )
{
TQDomElement spe = sp.toElement( );
if( spe.tagName( ) == "sub_prism" )
{
list.clear( );
TQDomNode c = spe.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 );
list.append( v );
}
}
}
c = c.nextSibling( );
}
m_points.append( list );
}
}
sp = sp.nextSibling( );
}
}
Base::readAttributes( h );
}
PMMetaObject* PMPrism::tqmetaObject( ) const
{
if( !s_pMetaObject )
{
s_pMetaObject = new PMMetaObject( "Prism", Base::tqmetaObject( ),
createNewPrism );
s_pMetaObject->addProperty(
new PMPrismProperty( "sturm", &PMPrism::setSturm, &PMPrism::sturm ) );
s_pMetaObject->addProperty(
new PMPrismProperty( "open", &PMPrism::setOpen, &PMPrism::open ) );
s_pMetaObject->addProperty(
new PMPrismProperty( "height1", &PMPrism::setHeight1, &PMPrism::height1 ) );
s_pMetaObject->addProperty(
new PMPrismProperty( "height2", &PMPrism::setHeight2, &PMPrism::height2 ) );
PMSplineTypeProperty* p = new PMSplineTypeProperty(
"splineType", &PMPrism::setSplineType, &PMPrism::splineType );
p->addEnumValue( "LinearSpline", LinearSpline );
p->addEnumValue( "QuadraticSpline", QuadraticSpline );
p->addEnumValue( "CubicSpline", CubicSpline );
p->addEnumValue( "BezierSpline", BezierSpline );
s_pMetaObject->addProperty( p );
PMSweepTypeProperty* sp = new PMSweepTypeProperty(
"sweepType", &PMPrism::setSweepType, &PMPrism::sweepType );
sp->addEnumValue( "LinearSweep", LinearSweep );
sp->addEnumValue( "ConicSweep", ConicSweep );
s_pMetaObject->addProperty( sp );
s_pMetaObject->addProperty( new PMPointProperty( ) );
}
return s_pMetaObject;
}
void PMPrism::cleanUp( ) const
{
if( s_pMetaObject )
{
delete s_pMetaObject;
s_pMetaObject = 0;
}
Base::cleanUp( );
}
void PMPrism::setSplineType( PMPrism::SplineType t )
{
if( m_splineType != t )
{
if( m_pMemento )
m_pMemento->addData( s_pMetaObject, PMSplineTypeID, ( int ) m_splineType );
setViewStructureChanged( );
m_splineType = t;
}
}
void PMPrism::setSweepType( PMPrism::SweepType t )
{
if( m_sweepType != t )
{
if( m_pMemento )
m_pMemento->addData( s_pMetaObject, PMSweepTypeID, ( int ) m_sweepType );
setViewStructureChanged( );
m_sweepType = t;
}
}
void PMPrism::setSturm( bool s )
{
if( m_sturm != s )
{
if( m_pMemento )
m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm );
m_sturm = s;
}
}
void PMPrism::setOpen( bool o )
{
if( m_open != o )
{
if( m_pMemento )
m_pMemento->addData( s_pMetaObject, PMOpenID, m_open );
m_open = o;
}
}
void PMPrism::setHeight1( double h )
{
if( m_height1 != h )
{
if( m_pMemento )
m_pMemento->addData( s_pMetaObject, PMHeight1ID, m_height1 );
m_height1 = h;
setViewStructureChanged( );
}
}
void PMPrism::setHeight2( double h )
{
if( m_height2 != h )
{
if( m_pMemento )
m_pMemento->addData( s_pMetaObject, PMHeight2ID, m_height2 );
m_height2 = h;
setViewStructureChanged( );
}
}
void PMPrism::setPoints( const TQValueList< TQValueList<PMVector> >& points )
{
if( m_points != points )
{
if( m_pMemento )
( ( PMPrismMemento* ) m_pMemento )->setPrismPoints( m_points );
setViewStructureChanged( );
m_points = points;
}
}
PMDialogEditBase* PMPrism::editWidget( TQWidget* tqparent ) const
{
return new PMPrismEdit( tqparent );
}
void PMPrism::createMemento( )
{
if( m_pMemento )
delete m_pMemento;
m_pMemento = new PMPrismMemento( this );
}
void PMPrism::restoreMemento( PMMemento* s )
{
PMPrismMemento* m = ( PMPrismMemento* ) 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 PMSweepTypeID:
setSweepType( ( SweepType ) data->intData( ) );
break;
case PMOpenID:
setOpen( data->boolData( ) );
break;
case PMSturmID:
setSturm( data->boolData( ) );
break;
case PMHeight1ID:
setHeight1( data->doubleData( ) );
break;
case PMHeight2ID:
setHeight2( data->doubleData( ) );
break;
default:
kdError( PMArea ) << "Wrong ID in PMPrism::restoreMemento\n";
break;
}
}
}
if( m->prismPointsSaved( ) )
setPoints( m->prismPoints( ) );
Base::restoreMemento( s );
}
void PMPrism::createViewStructure( )
{
if( s_sSteps == 0 )
s_sSteps = c_defaultPrismSSteps;
int sSteps = (int)( ( (float)s_sSteps / 2 ) * ( displayDetail( ) + 1 ) );
// calculate number of points and lines of the view structure
TQValueList< TQValueList<PMVector> >::ConstIterator spit = m_points.begin( );
int np = 0;
for( ; spit != m_points.end( ); ++spit )
{
int snp = ( *spit ).count( );
switch( m_splineType )
{
case LinearSpline:
break;
case QuadraticSpline:
snp -= 1;
break;
case CubicSpline:
snp -= 2;
break;
case BezierSpline:
snp /= 3;
break;
}
np += snp;
}
int nl = 0;
nl = np * sSteps * 3;
np *= sSteps * 2;
if( m_pViewStructure )
{
if( m_pViewStructure->points( ).size( ) != ( unsigned ) np )
m_pViewStructure->points( ).resize( np );
if( m_pViewStructure->lines( ).size( ) != ( unsigned ) nl )
m_pViewStructure->lines( ).resize( nl );
}
else
m_pViewStructure = new PMViewStructure( np, nl );
PMLineArray& lines = m_pViewStructure->lines( );
PMPointArray& points = m_pViewStructure->points( );
int lb = 0;
int pb = 0;
for( spit = m_points.begin( ); spit != m_points.end( ); ++spit )
{
TQValueList<PMSplineSegment> segments;
TQValueList<PMVector> fullPoints = expandedPoints( *spit );
int ns = fullPoints.count( );
int i, j;
switch( m_splineType )
{
case LinearSpline:
ns -= 1;
break;
case QuadraticSpline:
ns -= 2;
break;
case CubicSpline:
ns -= 3;
break;
case BezierSpline:
ns = ns / 4;
break;
}
TQValueList<PMVector>::Iterator it1, it2, it3, it4;
// create the spline segments
it1 = fullPoints.begin( );
it2 = it1; ++it2;
it3 = it2; ++it3;
it4 = it3; ++it4;
PMSplineSegment s;
for( i = 0; i < ns; ++i )
{
switch( m_splineType )
{
case LinearSpline:
s.calculateLinear( *it1, *it2 );
++it1;
++it2;
break;
case QuadraticSpline:
s.calculateQuadratic( *it1, *it2, *it3 );
++it1;
++it2;
++it3;
break;
case CubicSpline:
s.calculateCubic( *it1, *it2, *it3, *it4 );
++it1;
++it2;
++it3;
++it4;
break;
case BezierSpline:
s.calculateBezier( *it1, *it2, *it3, *it4 );
for( j = 0; j < 4; ++j )
{
++it1;
++it2;
++it3;
++it4;
}
break;
}
segments.append( s );
}
// create the line array
int vp = ns * sSteps;
for( i = 0; i < vp - 1; ++i )
lines[lb+i] = PMLine( pb + i, pb + i + 1 );
lines[lb+vp-1] = PMLine( pb, pb + vp - 1 );
lb += vp;
for( i = 0; i < vp - 1; ++i )
lines[lb+i] = PMLine( pb + vp + i, pb + vp + i + 1 );
lines[lb+vp-1] = PMLine( pb + vp, pb + vp + vp - 1 );
lb += vp;
for( i = 0; i < vp; ++i )
lines[lb+i] = PMLine( pb + i, pb + vp + i );
lb += vp;
// calculate the points
PMVector point2( 2 ), point3;
TQValueList<PMSplineSegment>::Iterator sit = segments.begin( );
int pi = 0;
double poffset = 1.0 / sSteps;
for( i = 0; i < ns; ++i, ++sit )
{
for( j = 0; j < sSteps; ++j )
{
point2 = ( *sit ).point( poffset * j );
if( m_sweepType == LinearSweep )
{
point3[0] = point2[0];
point3[1] = m_height1;
point3[2] = point2[1];
points[pb+pi] = PMPoint( point3 );
point3[1] = m_height2;
points[pb+pi+vp] = PMPoint( point3 );
}
else
{
point3[0] = point2[0];
point3[1] = 1.0;
point3[2] = point2[1];
points[pb+pi] = PMPoint( point3 * m_height1 );
points[pb+pi+vp] = PMPoint( point3 * m_height2 );
}
++pi;
}
}
pb += vp * 2;
}
}
void PMPrism::controlPoints( PMControlPointList& list )
{
TQValueList< TQValueList<PMVector> >::Iterator it1;
TQValueList<PMVector>::Iterator it2;
int i1, i2;
list.append( new PMDistanceControlPoint( PMVector( 0.0, 0.0, 0.0 ),
PMVector( 0.0, 1.0, 0.0 ),
m_height1, PMHeight1ID,
i18n( "Height 1" ) ) );
list.append( new PMDistanceControlPoint( PMVector( 0.0, 0.0, 0.0 ),
PMVector( 0.0, 1.0, 0.0 ),
m_height2, PMHeight2ID,
i18n( "Height 2" ) ) );
PM2DControlPoint* cp;
for( it1 = m_points.begin( ), i1 = 0; it1 != m_points.end( ); ++it1, ++i1 )
{
if( m_splineType != BezierSpline )
{
int refb = ( *it1 ).count( ) - 1;
if( m_splineType == CubicSpline )
--refb;
it2 = ( *it1 ).begin( );
PM2DControlPoint* firstPoint = 0;
PM2DControlPoint* secondPoint = 0;
for( i2 = 0; it2 != ( *it1 ).end( ); ++it2, ++i2 )
{
cp = new PM2DControlPoint( *it2, PM2DControlPoint::PM2DXZ, i2,
i18n( "Point %1.%2" ).tqarg( i1 + 1 ).tqarg( i2 + 1 ) );
if( i2 == 0 )
firstPoint = cp;
else if( i2 == 1 )
secondPoint = cp;
cp->setThirdCoordinate( m_height2 );
if( m_sweepType == ConicSweep )
cp->setScale( m_height2 );
if( ( ( m_splineType == QuadraticSpline )
|| ( m_splineType == CubicSpline ) )
&& ( i2 == 1 ) )
firstPoint->setBasePoint( cp );
if( ( m_splineType == CubicSpline ) && ( i2 == ( refb + 2 ) ) )
cp->setBasePoint( secondPoint );
list.append( cp );
if( ( m_splineType != BezierSpline ) && ( i2 == refb ) )
++i2;
}
}
else
{
it2 = ( *it1 ).begin( );
PM2DControlPoint* firstPoint = 0;
PM2DControlPoint* lastPoint = 0;
PM2DControlPoint* startPoint = 0;
for( i2 = 0; it2 != ( *it1 ).end( ); ++it2, ++i2 )
{
int i2mod4 = i2 % 4;
cp = new PM2DControlPoint( *it2, PM2DControlPoint::PM2DXZ, i2,
i18n( "Point %1.%2" ).tqarg( i1 + 1 ).tqarg( i2 + 1 ) );
if( i2mod4 == 0 )
firstPoint = cp;
if( i2mod4 == 2 )
lastPoint = cp;
if( !startPoint )
startPoint = cp;
cp->setThirdCoordinate( m_height2 );
if( m_sweepType == ConicSweep )
cp->setScale( m_height2 );
if( i2mod4 == 1 )
cp->setBasePoint( firstPoint );
if( ( i2mod4 == 0 ) && lastPoint )
lastPoint->setBasePoint( cp );
list.append( cp );
if( i2mod4 == 2 )
++i2;
}
if( lastPoint )
lastPoint->setBasePoint( startPoint );
}
}
}
void PMPrism::controlPointsChanged( PMControlPointList& list )
{
PMControlPointListIterator it( list );
TQValueList< TQValueList<PMVector> >::Iterator spit = m_points.begin( );
TQValueList<PMVector>::Iterator pit = ( *spit ).begin( );
PM2DControlPoint* p1;
PMDistanceControlPoint* dcp;
bool firstChange = true;
bool h2changed = false;
// IDs are ignored, quick hack, but should work
if( it.current( )->changed( ) )
{
dcp = ( PMDistanceControlPoint* ) it.current( );
setHeight1( dcp->distance( ) );
}
++it;
if( it.current( )->changed( ) )
{
dcp = ( PMDistanceControlPoint* ) it.current( );
setHeight2( dcp->distance( ) );
h2changed = true;
}
++it;
for( ; it.current( ); ++it )
{
p1 = ( PM2DControlPoint* ) it.current( );
if( p1->changed( ) )
{
if( firstChange )
{
if( m_pMemento )
{
PMPrismMemento* m = ( PMPrismMemento* ) m_pMemento;
if( !m->prismPointsSaved( ) )
m->setPrismPoints( m_points );
}
firstChange = false;
setViewStructureChanged( );
}
( *pit ) = p1->point( );
}
if( h2changed )
{
p1->setThirdCoordinate( m_height2 );
if( m_sweepType == ConicSweep )
p1->setScale( m_height2 );
}
++pit;
if( pit == ( *spit ).end( ) )
{
++spit;
pit = ( *spit ).begin( );
}
}
}
void PMPrism::addObjectActions( const PMControlPointList& /*cp*/,
TQPtrList<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" ) );
bool enableJoin = false;
TQValueList< TQValueList<PMVector> >::ConstIterator spit = m_points.begin( );
int minp = 4;
switch( m_splineType )
{
case LinearSpline:
minp = 4;
break;
case QuadraticSpline:
minp = 5;
break;
case CubicSpline:
minp = 6;
break;
case BezierSpline:
minp = 6;
break;
}
for( ; ( spit != m_points.end( ) ) && !enableJoin; ++spit )
if( ( *spit ).count( ) >= ( unsigned ) minp )
enableJoin = true;
a->setEnabled( enableJoin );
actions.append( a );
}
void PMPrism::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 PMPrism::objectActionCalled\n";
break;
}
}
else
Base::objectActionCalled( action, cp, cpViewPosition, clickPosition );
}
void PMPrism::splitSegment( const PMControlPointList& /*cp*/,
const TQPtrList<PMVector>& cpViewPosition,
const PMVector& clickPosition )
{
// find nearest segment
double abs = 0.0, minabs = 1e10;
int ns = -1;
int nsp = 0;
int spnr = 0, pnr = 0;
int i;
PMVector mid( 3 ), dist( 2 );
PMVector firstPoint( 3 );
TQPtrListIterator<PMVector> it1( cpViewPosition );
TQPtrListIterator<PMVector> it2( cpViewPosition );
for( i = 0; i < 2; ++i ) ++it1;
for( i = 0; i < 3; ++i ) ++it2;
TQValueList< TQValueList<PMVector> >::Iterator spit = m_points.begin( );
for( spnr = 0; spit != m_points.end( ); ++spit, ++spnr )
{
int nump = ( *spit ).count( );
bool first = true;
for( pnr = 0; pnr < nump; ++pnr )
{
bool skip = false;
switch( m_splineType )
{
case LinearSpline:
case BezierSpline:
break;
case QuadraticSpline:
if( pnr == 0 )
skip = true;
break;
case CubicSpline:
if( ( pnr == 0 ) || ( pnr == ( nump - 1 ) ) )
skip = true;
break;
}
if( !skip )
{
if( first )
{
firstPoint = **it1;
first = false;
}
if( ( ( m_splineType == CubicSpline ) && ( pnr == ( nump - 2 ) ) )
|| ( ( m_splineType != CubicSpline ) && ( pnr == ( nump - 1 ) ) ) )
mid = ( **it1 + firstPoint ) / 2.0;
else
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 = pnr;
nsp = spnr;
}
}
++it1;
++it2;
}
}
// add a new segment
TQValueList< TQValueList<PMVector> > newPoints = m_points;
spit = newPoints.at( nsp );
TQValueList<PMVector> newSubPoints = *spit;
if( m_splineType == BezierSpline )
{
ns /= 3;
ns *= 3;
}
TQValueList<PMVector>::Iterator it = newSubPoints.at( ( unsigned ) ns );
PMVector p[4];
TQValueList<PMVector>::Iterator hit = it, eit = newSubPoints.end( );
--eit;
// calculate the spline segment
PMSplineSegment segment;
switch( m_splineType )
{
case LinearSpline:
for( i = 0; i < 2; ++i )
{
p[i] = *hit;
++hit;
if( hit == newSubPoints.end( ) )
hit = newSubPoints.begin( );
}
segment.calculateLinear( p[0], p[1] );
break;
case QuadraticSpline:
--hit;
for( i = 0; i < 3; ++i )
{
p[i] = *hit;
++hit;
if( hit == newSubPoints.end( ) )
{
hit = newSubPoints.begin( );
++hit;
}
}
segment.calculateQuadratic( p[0], p[1], p[2] );
break;
case CubicSpline:
--hit;
for( i = 0; i < 4; ++i )
{
if( hit == eit )
{
hit = newSubPoints.begin( );
++hit;
p[i] = *hit;
hit = eit;
++i;
if( i < 4 )
p[i] = *hit;
}
else
p[i] = *hit;
++hit;
}
segment.calculateCubic( p[0], p[1], p[2], p[3] );
break;
case BezierSpline:
for( i = 0; i < 4; ++i )
{
p[i] = *hit;
++hit;
if( hit == newSubPoints.end( ) )
hit = newSubPoints.begin( );
}
segment.calculateBezier( p[0], p[1], p[2], p[3] );
break;
}
mid = segment.point( 0.5 );
if( m_splineType != BezierSpline )
{
++it;
newSubPoints.insert( it, mid );
}
else
{
PMVector end = *it;
++it;
*it = end + ( *it - end ) / 2.0;
++it;
PMVector grad = segment.gradient( 0.5 ) / 4.0;
newSubPoints.insert( it, mid - grad );
newSubPoints.insert( it, mid );
newSubPoints.insert( it, mid + grad );
++it;
if( it == newSubPoints.end( ) )
end = *newSubPoints.begin( );
else
end = *it;
--it;
*it = end + ( *it - end ) / 2.0;
}
( *spit ) = newSubPoints;
setPoints( newPoints );
}
void PMPrism::joinSegments( const PMControlPointList& /*cp*/,
const TQPtrList<PMVector>& cpViewPosition,
const PMVector& clickPosition )
{
// find nearest point
double abs = 0.0, minabs = 1e10;
int ns = -1;
int nsp = 0;
int spnr = 0, pnr = 0;
int i;
PMVector dist( 2 );
TQPtrListIterator<PMVector> it1( cpViewPosition );
for( i = 0; i < 2; ++i ) ++it1;
int minp = 0;
switch( m_splineType )
{
case LinearSpline:
minp = 4;
break;
case QuadraticSpline:
minp = 5;
break;
case CubicSpline:
minp = 6;
break;
case BezierSpline:
minp = 6;
break;
}
TQValueList< TQValueList<PMVector> >::Iterator spit = m_points.begin( );
for( spnr = 0; spit != m_points.end( ); ++spit, ++spnr )
{
int nump = ( *spit ).count( );
for( pnr = 0; pnr < nump; ++pnr )
{
bool skip = false;
switch( m_splineType )
{
case LinearSpline:
case BezierSpline:
break;
case QuadraticSpline:
if( pnr == 0 )
skip = true;
break;
case CubicSpline:
if( ( pnr == 0 ) || ( pnr == ( nump - 1 ) ) )
skip = true;
break;
}
if( nump < minp )
skip = true;
if( !skip )
{
dist[0] = (**it1)[0];
dist[1] = (**it1)[1];
dist -= clickPosition;
abs = dist.abs( );
if( ( minabs > abs ) || ( ns < 0 ) )
{
minabs = abs;
ns = pnr;
nsp = spnr;
}
}
++it1;
}
}
if( ns < 0 )
{
kdError( PMArea ) << "Not enough points in PMPrism::joinSegments\n";
return;
}
// remove the segment
TQValueList< TQValueList<PMVector> > newPoints = m_points;
spit = newPoints.at( nsp );
TQValueList<PMVector> newSubPoints = *spit;
TQValueList<PMVector>::Iterator it;
if( m_splineType != BezierSpline )
{
it = newSubPoints.at( ( unsigned ) ns );
newSubPoints.remove( it );
}
else
{
int last = ( newSubPoints.count( ) - 3 ) / 3;
ns -= 2;
if( ns < 0 )
ns = last;
else
ns /= 3;
it = newSubPoints.at( ns * 3 + 2 );
if( ns != last )
{
it = newSubPoints.remove( it );
it = newSubPoints.remove( it );
it = newSubPoints.remove( it );
}
else
{
newSubPoints.remove( it );
it = newSubPoints.begin( );
it = newSubPoints.remove( it );
it = newSubPoints.remove( it );
PMVector h = *it;
it = newSubPoints.remove( it );
newSubPoints.insert( newSubPoints.end( ), h );
}
}
( *spit ) = newSubPoints;
setPoints( newPoints );
}
void PMPrism::setSSteps( int s )
{
if( s >= 1 )
s_sSteps = s;
else
kdDebug( PMArea ) << "PMPrism::setSSteps: S must be greater than 0\n";
++s_parameterKey;
}
TQValueList<PMVector> PMPrism::expandedPoints( const TQValueList<PMVector>& p ) const
{
// add the missing points
int refa = 0, refb = p.count( );
TQValueList<PMVector> result = p;
switch( m_splineType )
{
case LinearSpline:
break;
case QuadraticSpline:
++refa;
break;
case CubicSpline:
++refa;
--refb;
break;
case BezierSpline:
refb = refb / 3 * 4;
break;
}
TQValueList<PMVector>::Iterator it1, it2, it3;
if( m_splineType != BezierSpline )
{
it1 = result.at( refa );
it2 = result.at( refb );
result.insert( it2, *it1 );
}
else
{
int i;
it1 = result.begin( );
for( i = 1; it1 != result.end( ); ++it1, ++i )
{
if( ( i % 3 ) == 0 )
{
it2 = it1;
++it2;
it3 = it2;
if( it3 == result.end( ) )
it3 = result.begin( );
it1 = result.insert( it2, *it3 );
}
}
}
return result;
}