/* ************************************************************************** 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 <tdelocale.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::metaObject( ) const { if( !s_pMetaObject ) { s_pMetaObject = new PMMetaObject( "Prism", Base::metaObject( ), 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* parent ) const { return new PMPrismEdit( parent ); } 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" ).arg( i1 + 1 ).arg( 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" ).arg( i1 + 1 ).arg( 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; }