/*
**************************************************************************
                                 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 "pmlathe.h"

#include "pmxmlhelper.h"
#include "pmlatheedit.h"
#include "pmmemento.h"
#include "pmviewstructure.h"
#include "pm2dcontrolpoint.h"
#include "pmsplinememento.h"
#include "pmsplinesegment.h"
#include "pmdefaults.h"
#include "pmenumproperty.h"
#include "pmobjectaction.h"

#include <klocale.h>

const int defaultNumberOfPoints = 4;
const PMVector defaultPoint[defaultNumberOfPoints] =
{
   PMVector( 0.0, 1.0 ),
   PMVector( 0.5, 0.7 ),
   PMVector( 0.5, 0.3 ),
   PMVector( 0.0, 0.0 )
};

const bool defaultSturm = false;
const PMLathe::SplineType defaultSplineType = PMLathe::LinearSpline;

PMDefinePropertyClass( PMLathe, PMLatheProperty );
PMDefineEnumPropertyClass( PMLathe, PMLathe::SplineType, PMSplineTypeProperty );

PMMetaObject* PMLathe::s_pMetaObject = 0;
PMObject* createNewLathe( PMPart* part )
{
   return new PMLathe( part );
}

class PMPointProperty : public PMPropertyBase
{
public:
   PMPointProperty( )
         : PMPropertyBase( "splinePoints", PMVariant::Vector )
   {
      m_index = 0;
   }
   virtual int dimensions( ) const { return 1; }
   virtual void setIndex( int /*dimension*/, int index )
   {
      m_index = index;
   }
   virtual int size( PMObject* object, int /*dimension*/ ) const
   {
      return ( ( PMLathe* ) object )->numberOfPoints( );
   }
protected:
   virtual bool setProtected( PMObject* obj, const PMVariant& var )
   {
      PMLathe* p = ( PMLathe* ) obj;
      TQValueList<PMVector> list = p->points( );
      TQValueList<PMVector>::Iterator it = list.begin( );
      int i;
      PMVector v = var.vectorData( );
      v.resize( 2 );

      for( i = 0; i < m_index && it != list.end( ); ++i )
         ++it;
      // expand the list if necessary
      for( ; i < m_index; ++i )
         list.insert( it, v );
      if( it == list.end( ) )
         it = list.insert( it, v );
      else
         *it = v;

      p->setPoints( list );
      return true;
   }
   virtual PMVariant getProtected( const PMObject* obj )
   {
      PMLathe* p = ( PMLathe* ) obj;
      TQValueList<PMVector> list = p->points( );
      TQValueList<PMVector>::ConstIterator it = list.at( m_index );

      if( it == list.end( ) )
      {
         kdError( PMArea ) << "Range error in PMLathe::PointProperty::get" << endl;
         return PMVariant( );
      }

      return PMVariant( *it );
   }

private:
   int m_index;
};


int PMLathe::s_rSteps = c_defaultLatheRSteps;
int PMLathe::s_sSteps = c_defaultLatheSSteps;
int PMLathe::s_parameterKey = 0;

PMLathe::PMLathe( PMPart* part )
      : Base( part )
{
   int i;

   for( i = 0; i < defaultNumberOfPoints; ++i )
      m_points.append( defaultPoint[i] );
   m_splineType = defaultSplineType;
   m_sturm = defaultSturm;
}

PMLathe::PMLathe( const PMLathe& l )
      : Base( l )
{
   m_points = l.m_points;
   m_splineType = l.m_splineType;
   m_sturm = l.m_sturm;
}

PMLathe::~PMLathe( )
{
}

TQString PMLathe::description( ) const
{
   return i18n( "lathe" );
}

void PMLathe::serialize( TQDomElement& e, TQDomDocument& doc ) const
{
   TQDomElement data = doc.createElement( "extra_data" );
   TQDomElement p;

   e.setAttribute( "spline_type", m_splineType );
   e.setAttribute( "sturm", m_sturm );

   TQValueList<PMVector>::ConstIterator it;
   for( it = m_points.begin( ); it != m_points.end( ); ++it )
   {
      p = doc.createElement( "point" );
      p.setAttribute( "vector", ( *it ).serializeXML( ) );
      data.appendChild( p );
   }

   e.appendChild( data );
   Base::serialize( e, doc );
}

void PMLathe::readAttributes( const PMXMLHelper& h )
{
   m_splineType = ( SplineType ) h.intAttribute( "spline_type", defaultSplineType );
   m_sturm = h.boolAttribute( "sturm", defaultSturm );

   m_points.clear( );
   PMVector v( 2 );

   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 );
               }
            }
         }
         c = c.nextSibling( );
      }
   }

   Base::readAttributes( h );
}

PMMetaObject* PMLathe::metaObject( ) const
{
   if( !s_pMetaObject )
   {
      s_pMetaObject = new PMMetaObject( "Lathe", Base::metaObject( ),
                                        createNewLathe );
      s_pMetaObject->addProperty(
         new PMLatheProperty( "sturm", &PMLathe::setSturm, &PMLathe::sturm ) );
      PMSplineTypeProperty* p = new PMSplineTypeProperty(
         "splineType", &PMLathe::setSplineType, &PMLathe::splineType );
      p->addEnumValue( "LinearSpline", LinearSpline );
      p->addEnumValue( "QuadraticSpline", QuadraticSpline );
      p->addEnumValue( "CubicSpline", CubicSpline );
      p->addEnumValue( "BezierSpline", BezierSpline );
      s_pMetaObject->addProperty( p );
      s_pMetaObject->addProperty( new PMPointProperty( ) );
   }
   return s_pMetaObject;
}

void PMLathe::cleanUp( ) const
{
   if( s_pMetaObject )
   {
      delete s_pMetaObject;
      s_pMetaObject = 0;
   }
   Base::cleanUp( );
}

void PMLathe::setSplineType( PMLathe::SplineType t )
{
   if( m_splineType != t )
   {
      if( m_pMemento )
         m_pMemento->addData( s_pMetaObject, PMSplineTypeID, ( int ) m_splineType );
      setViewStructureChanged( );
      m_splineType = t;
   }
}

void PMLathe::setSturm( bool s )
{
   if( m_sturm != s )
   {
      if( m_pMemento )
         m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm );
      m_sturm = s;
   }
}

void PMLathe::setPoints( const TQValueList<PMVector>& points )
{
   if( m_points != points )
   {
      if( m_pMemento )
         ( ( PMSplineMemento* ) m_pMemento )->setSplinePoints( m_points );

      setViewStructureChanged( );
      m_points = points;
   }
}

PMDialogEditBase* PMLathe::editWidget( TQWidget* parent ) const
{
   return new PMLatheEdit( parent );
}

void PMLathe::createMemento( )
{
   if( m_pMemento )
      delete m_pMemento;
   m_pMemento = new PMSplineMemento( this );
}

void PMLathe::restoreMemento( PMMemento* s )
{
   PMSplineMemento* m = ( PMSplineMemento* ) 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 PMSturmID:
               setSturm( data->boolData( ) );
               break;
            default:
               kdError( PMArea ) << "Wrong ID in PMLathe::restoreMemento\n";
               break;
         }
      }
   }
   if( m->splinePointsSaved( ) )
      setPoints( m->splinePoints( ) );

   Base::restoreMemento( s );
}


void PMLathe::createViewStructure( )
{
   if( s_sSteps == 0 )
      s_sSteps = c_defaultLatheSSteps;
   if( s_rSteps == 0 )
      s_rSteps = c_defaultLatheRSteps;

   int rSteps = (int)( ( (float)s_rSteps / 2 ) * ( displayDetail( ) + 1 ) );
   int sSteps = (int)( ( (float)s_sSteps / 2 ) * ( displayDetail( ) + 1 ) );

   int np = m_points.count( );
   int ns = 0;
   int i, j, r, si;

   // calculate number of segments
   switch( m_splineType )
   {
      case LinearSpline:
         ns = np - 1;
         break;
      case QuadraticSpline:
         ns = np - 2;
         break;
      case CubicSpline:
         ns = np - 3;
         break;
      case BezierSpline:
         ns = np / 4;
         break;
   }

   // calculate number of points and lines of the view structure
   int vsp = 0;
   if( m_splineType != BezierSpline )
      vsp = ns * sSteps + 1;
   else
      vsp = ns * ( sSteps + 1 );

   int vsl = 0;
   if( m_splineType != BezierSpline )
      vsl = ( 2 * vsp - 1 ) * rSteps;
   else
      vsl = ns * ( ( 2 * sSteps + 1 ) * rSteps );

   vsp *= rSteps;

   if( m_pViewStructure )
   {
      if( m_pViewStructure->points( ).size( ) != ( unsigned ) vsp )
         m_pViewStructure->points( ).resize( vsp );
      if( m_pViewStructure->lines( ).size( ) != ( unsigned ) vsl )
         m_pViewStructure->lines( ).resize( vsl );
   }
   else
      m_pViewStructure = new PMViewStructure( vsp, vsl );


   // calculate the spline segments
   TQValueList<PMSplineSegment> segments;
   TQValueList<PMVector>::Iterator it1, it2, it3, it4;
   it1 = m_points.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
   if( m_splineType != BezierSpline )
   {
      PMLineArray& lines = m_pViewStructure->lines( );
      int vl = ns * sSteps;
      int lb = 0;
      for( i = 0; i < vl + 1; ++i )
      {
         for( j = 0; j < rSteps - 1; ++j )
            lines[lb+j] = PMLine( lb + j, lb + j + 1 );
         lines[lb+rSteps-1] = PMLine( lb, lb + rSteps - 1 );
         lb += rSteps;
      }
      int pi = 0;
      for( i = 0; i < vl; ++i )
      {
         for( j = 0; j < rSteps; ++j )
         {
            lines[lb] = PMLine( pi, pi + rSteps );
            ++pi;
            ++lb;
         }
      }
   }
   else
   {
      PMLineArray& lines = m_pViewStructure->lines( );
      int lb = 0;
      int pi = 0;

      for( si = 0; si < ns; ++si )
      {
         for( i = 0; i < sSteps + 1; ++i )
         {
            for( j = 0; j < rSteps - 1; ++j )
               lines[lb+j] = PMLine( lb + j, lb + j + 1 );
            lines[lb+rSteps-1] = PMLine( lb, lb + rSteps - 1 );
            lb += rSteps;
         }
      }
      for( si = 0; si < ns; ++si )
      {
         for( i = 0; i < sSteps; ++i )
         {
            for( j = 0; j < rSteps; ++j )
            {
               lines[lb] = PMLine( pi, pi + rSteps );
               ++pi;
               ++lb;
            }
         }
         pi += rSteps;
      }
   }
   // calculate the points
   PMVector point2, point3;
   TQValueList<PMSplineSegment>::Iterator sit = segments.begin( );
   int pi = 0;

   double poffset = 1.0 / sSteps;
   PMMatrix rot = PMMatrix::rotation( 0.0, M_PI * 2.0 / rSteps, 0.0 );
   PMPointArray& points = m_pViewStructure->points( );

   if( m_splineType != BezierSpline )
   {
      for( i = 0; i < ns; ++i, ++sit )
      {
         for( j = 0; j < sSteps; ++j )
         {
            point2 = ( *sit ).point( poffset * j );
            point3[0] = point2[0];
            point3[1] = point2[1];
            point3[2] = 0.0;

            for( r = 0; r < rSteps; ++r )
            {
               points[pi] = PMPoint( point3 );
               if( r != rSteps - 1 )
                  point3.transform( rot );
               ++pi;
            }
         }
         if( i == ns - 1 )
         {
            point2 = ( *sit ).point( 1.0 );
            point3[0] = point2[0];
            point3[1] = point2[1];
            point3[2] = 0.0;

            for( r = 0; r < rSteps; ++r )
            {
               points[pi] = PMPoint( point3 );
               if( r != rSteps - 1 )
                  point3.transform( rot );
               ++pi;
            }
         }
      }
   }
   else
   {
      for( i = 0; i < ns; ++i, ++sit )
      {
         for( j = 0; j < sSteps + 1; ++j )
         {
            point2 = ( *sit ).point( poffset * j );
            point3[0] = point2[0];
            point3[1] = point2[1];
            point3[2] = 0.0;

            for( r = 0; r < rSteps; ++r )
            {
               points[pi] = PMPoint( point3 );
               if( r != rSteps - 1 )
                  point3.transform( rot );
               ++pi;
            }
         }
      }
   }
}

void PMLathe::controlPoints( PMControlPointList& list )
{
   TQValueList<PMVector>::Iterator it;
   int i, d;

   PM2DControlPoint* cp = 0;
   TQPtrList<PM2DControlPoint> tmp[2];

   for( d = 0; d < 2; ++d )
   {
      if( m_splineType != BezierSpline )
      {
         PM2DControlPoint* firstPoint = 0;
         PM2DControlPoint* lastPoint = 0;

         for( it = m_points.begin( ), i = 0; it != m_points.end( ); ++it, ++i )
         {
            lastPoint = cp;
            if( d == 0 )
               cp = new PM2DControlPoint( *it, PM2DControlPoint::PM2DXY, i,
                                          i18n( "Point %1 (xy)" ).arg( i + 1 ) );
            else
               cp = new PM2DControlPoint( *it, PM2DControlPoint::PM2DZY, i,
                                          i18n( "Point %1 (xy)" ).arg( i + 1 ) );

            if( i == 0 )
               firstPoint = cp;
            if( ( i == 1 ) && ( m_splineType != LinearSpline ) )
               firstPoint->setBasePoint( cp );

            tmp[d].append( cp );
         }
         if( m_splineType == CubicSpline )
            cp->setBasePoint( lastPoint );
      }
      else
      {
         PM2DControlPoint* helpPoint = 0;

         for( it = m_points.begin( ), i = 0; it != m_points.end( ); ++it, ++i )
         {
            int imod4 = i % 4;
            if( d == 0 )
               cp = new PM2DControlPoint( *it, PM2DControlPoint::PM2DXY, i,
                                          i18n( "Point %1 (xy)" ).arg( i + 1 ) );
            else
               cp = new PM2DControlPoint( *it, PM2DControlPoint::PM2DZY, i,
                                          i18n( "Point %1 (xy)" ).arg( i + 1 ) );
            switch( imod4 )
            {
               case 0:
                  helpPoint = cp;
                  break;
               case 1:
                  cp->setBasePoint( helpPoint );
                  break;
               case 2:
                  helpPoint = cp;
                  break;
               case 3:
                  helpPoint->setBasePoint( cp );
                  break;
               default:
                  break;
            }

            tmp[d].append( cp );
         }
      }
   }

   TQPtrListIterator<PM2DControlPoint> cit1( tmp[0] ), cit2( tmp[1] );

   for( ; cit1.current( ) && cit2.current( ); ++cit1, ++cit2 )
   {
      ( *cit1 )->setLatheLink( *cit2 );
      ( *cit2 )->setLatheLink( *cit1 );
   }
   for( cit1.toFirst( ); cit1.current( ); ++cit1 )
      list.append( *cit1 );
   for( cit2.toFirst( ); cit2.current( ); ++cit2 )
      list.append( *cit2 );
}

void PMLathe::controlPointsChanged( PMControlPointList& list )
{
   PMControlPointListIterator it1( list ), it2( list );
   TQValueList<PMVector>::Iterator pit = m_points.begin( );
   PM2DControlPoint* p1;
   PM2DControlPoint* p2;
   bool firstChange = true;

   for( it2 += list.count( ) / 2; it2.current( ); ++it1, ++it2, ++pit )
   {
      p1 = ( PM2DControlPoint* ) it1.current( );
      p2 = ( PM2DControlPoint* ) it2.current( );

      if( p1->changed( ) )
      {
         if( firstChange )
         {
            if( m_pMemento )
            {
               PMSplineMemento* m = ( PMSplineMemento* ) m_pMemento;
               if( !m->splinePointsSaved( ) )
                  m->setSplinePoints( m_points );
            }
            firstChange = false;
            setViewStructureChanged( );
         }
         p2->setPoint( p1->point( ) );
         ( *pit ) = p1->point( );
      }
      else if( p2->changed( ) )
      {
         if( firstChange )
         {
            if( m_pMemento )
            {
               PMSplineMemento* m = ( PMSplineMemento* ) m_pMemento;
               if( !m->splinePointsSaved( ) )
                  m->setSplinePoints( m_points );
            }
            firstChange = false;
            setViewStructureChanged( );
         }
         p1->setPoint( p2->point( ) );
         ( *pit ) = p2->point( );
      }
   }
}

void PMLathe::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" ) );
   int np = m_points.count( );
   int minp =  3;
   switch( m_splineType )
   {
      case LinearSpline:
         minp = 3;
         break;
      case QuadraticSpline:
         minp = 4;
         break;
      case CubicSpline:
         minp = 5;
         break;
      case BezierSpline:
         minp = 8;
         break;
   }

   if( np < minp )
      a->setEnabled( false );
   actions.append( a );
}

void PMLathe::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 PMLathe::objectActionCalled\n";
            break;
      }
   }
   else
      Base::objectActionCalled( action, cp, cpViewPosition, clickPosition );
}

void PMLathe::splitSegment( const PMControlPointList& /*cp*/,
                            const TQPtrList<PMVector>& cpViewPosition,
                            const PMVector& clickPosition )
{
   // find nearest segment
   int nump = cpViewPosition.count( ) / 2 - 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( j = 0; j < 2; ++j )
   {
      for( i = 0; i < nump; ++i )
      {
         bool skip = false;
         switch( m_splineType )
         {
            case LinearSpline:
            case BezierSpline:
               break;
            case QuadraticSpline:
               if( i == 0 )
                  skip = true;
               break;
            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;
            }
         }
         ++it1;
         ++it2;
      }
      ++it1;
      ++it2;
   }

   // add a new segment
   TQValueList<PMVector> newPoints = m_points;

   if( m_splineType == BezierSpline )
   {
      ns /= 4;
      ns *= 4;
   }
   TQValueList<PMVector>::Iterator it = newPoints.at( ( unsigned ) ns );
   PMVector p[4];
   TQValueList<PMVector>::Iterator hit = it;

   // calculate the spline segment
   PMSplineSegment segment;
   switch( m_splineType )
   {
      case LinearSpline:
         for( i = 0; i < 2; ++i, ++hit )
            p[i] = *hit;
         segment.calculateLinear( p[0], p[1] );
         break;
      case QuadraticSpline:
         --hit;
         for( i = 0; i < 3; ++i, ++hit )
            p[i] = *hit;
         segment.calculateQuadratic( p[0], p[1], p[2] );
         break;
      case CubicSpline:
         --hit;
         for( i = 0; i < 4; ++i, ++hit )
            p[i] = *hit;
         segment.calculateCubic( p[0], p[1], p[2], p[3] );
         break;
      case BezierSpline:
         for( i = 0; i < 4; ++i, ++hit )
            p[i] = *hit;
         segment.calculateBezier( p[0], p[1], p[2], p[3] );
         break;
   }

   mid = segment.point( 0.5 );
   if( m_splineType != BezierSpline )
   {
      ++it;
      newPoints.insert( it, mid );
   }
   else
   {
      PMVector end = *it;
      ++it;
      *it = end + ( *it - end ) / 2.0;
      ++it;

      PMVector grad = segment.gradient( 0.5 ) / 4.0;

      newPoints.insert( it, mid - grad );
      newPoints.insert( it, mid );
      newPoints.insert( it, mid );
      newPoints.insert( it, mid + grad );

      ++it;
      end = *it;
      --it;
      *it = end + ( *it - end ) / 2.0;
   }
   setPoints( newPoints );
}

void PMLathe::joinSegments( const PMControlPointList& /*cp*/,
                            const TQPtrList<PMVector>& cpViewPosition,
                            const PMVector& clickPosition )
{
   // find nearest point
   int nump = cpViewPosition.count( ) / 2;
   int minp = 0;

   switch( m_splineType )
   {
      case LinearSpline:
         minp = 3;
         break;
      case QuadraticSpline:
         minp = 4;
         break;
      case CubicSpline:
         minp = 5;
         break;
      case BezierSpline:
         minp = 8;
         break;
   }

   if( nump < minp )
   {
      kdError( PMArea ) << "Not enough points in PMLathe::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( j = 0; j < 2; ++j )
   {
      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;
         }
         ++it1;
      }
   }

   // join two segments
   TQValueList<PMVector> newPoints = m_points;
   TQValueList<PMVector>::Iterator it;

   if( m_splineType != BezierSpline )
   {
      // never remove the first or last point
      if( ns == 0 )
         ++ns;
      if( ns == ( nump - 1 ) )
         --ns;
      it = newPoints.at( ns );
      newPoints.remove( it );
   }
   else
   {
      ns = ( ns - 2 ) / 4;
      if( ns < 0 )
         ns = 0;
      if( ns >= ( nump / 4 - 1 ) )
         ns = nump / 4 - 2;

      it = newPoints.at( ns * 4 + 2 );
      for( i = 0; i < 4; ++i )
         it = newPoints.remove( it );
   }
   setPoints( newPoints );
}

void PMLathe::setRSteps( int r )
{
   if( r >= 4 )
      s_rSteps = r;
   else
      kdDebug( PMArea ) << "PMLathe::setRSteps: R must be greater than 3\n";
   ++s_parameterKey;
}

void PMLathe::setSSteps( int s )
{
   if( s >= 1 )
      s_sSteps = s;
   else
      kdDebug( PMArea ) << "PMLathe::setSSteps: S must be greater than 0\n";
   ++s_parameterKey;
}