karbon

whirlpinchplugin.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002, The Karbon Developers
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <core/vselection.h>
00021 #include "whirlpinchplugin.h"
00022 #include <karbon_view.h>
00023 #include <karbon_part.h>
00024 #include <kgenericfactory.h>
00025 #include <core/vdocument.h>
00026 #include <core/vcomposite.h>
00027 #include <core/vpath.h>
00028 #include <core/vsegment.h>
00029 #include <core/vglobal.h>
00030 
00031 #include <kdebug.h>
00032 
00033 #include <qgroupbox.h>
00034 #include <qlabel.h>
00035 
00036 #include <knuminput.h>
00037 
00038 typedef KGenericFactory<WhirlPinchPlugin, KarbonView> WhirlPinchPluginFactory;
00039 K_EXPORT_COMPONENT_FACTORY( karbon_whirlpinchplugin, WhirlPinchPluginFactory( "karbonwhirlpinchplugin" ) )
00040 
00041 WhirlPinchPlugin::WhirlPinchPlugin( KarbonView *parent, const char* name, const QStringList & ) : Plugin( parent, name )
00042 {
00043     new KAction(
00044         i18n( "&Whirl/Pinch..." ), "14_whirl", 0, this,
00045         SLOT( slotWhirlPinch() ), actionCollection(), "path_whirlpinch" );
00046 
00047     m_whirlPinchDlg = new VWhirlPinchDlg();
00048     m_whirlPinchDlg->setAngle( 20.0 );
00049     m_whirlPinchDlg->setPinch( 0.0 );
00050     m_whirlPinchDlg->setRadius( 100.0 );
00051 }
00052 
00053 void
00054 WhirlPinchPlugin::slotWhirlPinch()
00055 {
00056     KarbonPart *part = ((KarbonView *)parent())->part();
00057     if( part && m_whirlPinchDlg->exec() )
00058         part->addCommand( new VWhirlPinchCmd( &part->document(), m_whirlPinchDlg->angle(), m_whirlPinchDlg->pinch(), m_whirlPinchDlg->radius() ), true );
00059 }
00060 
00061 VWhirlPinchDlg::VWhirlPinchDlg( QWidget* parent, const char* name )
00062     : KDialogBase( parent, name, true, i18n( "Whirl Pinch" ), Ok | Cancel )
00063 {
00064     // add input fields:
00065     QGroupBox* group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this );
00066 
00067     new QLabel( i18n( "Angle:" ), group );
00068     m_angle = new KDoubleNumInput( group );
00069     new QLabel( i18n( "Pinch:" ), group );
00070     m_pinch = new KDoubleNumInput( group );
00071     new QLabel( i18n( "Radius:" ), group );
00072     m_radius = new KDoubleNumInput( group );
00073     group->setMinimumWidth( 300 );
00074 
00075     // signals and slots:
00076     connect( this, SIGNAL( okClicked() ), this, SLOT( accept() ) );
00077     connect( this, SIGNAL( cancelClicked() ), this, SLOT( reject() ) );
00078 
00079     setMainWidget( group );
00080     setFixedSize( baseSize() );
00081 }
00082 
00083 double
00084 VWhirlPinchDlg::angle() const
00085 {
00086     return m_angle->value();
00087 }
00088 
00089 double
00090 VWhirlPinchDlg::pinch() const
00091 {
00092     return m_pinch->value();
00093 }
00094 
00095 double
00096 VWhirlPinchDlg::radius() const
00097 {
00098     return m_radius->value();
00099 }
00100 
00101 void
00102 VWhirlPinchDlg::setAngle( double value )
00103 {
00104     m_angle->setValue( value);
00105 }
00106 
00107 void
00108 VWhirlPinchDlg::setPinch( double value )
00109 {
00110     m_pinch->setValue(value);
00111 }
00112 
00113 void
00114 VWhirlPinchDlg::setRadius( double value )
00115 {
00116     m_radius->setValue( value);
00117 }
00118 
00119 VWhirlPinchCmd::VWhirlPinchCmd( VDocument* doc,
00120     double angle, double pinch, double radius )
00121         : VCommand( doc, i18n( "Whirl Pinch" ) )
00122 {
00123     m_selection = document()->selection()->clone();
00124 
00125     m_angle = angle;
00126     m_pinch = pinch;
00127     m_radius = radius;
00128     m_center = m_selection->boundingBox().center();
00129 }
00130 
00131 VWhirlPinchCmd::~VWhirlPinchCmd()
00132 {
00133     delete( m_selection );
00134 }
00135 
00136 void
00137 VWhirlPinchCmd::execute()
00138 {
00139     VObjectListIterator itr( m_selection->objects() );
00140     for ( ; itr.current() ; ++itr )
00141         visit( *itr.current() );
00142 }
00143 
00144 void
00145 VWhirlPinchCmd::unexecute()
00146 {
00147 }
00148 
00149 void
00150 VWhirlPinchCmd::visitVPath( VPath& composite )
00151 {
00152     // first subdivide:
00153 //  VInsertKnots insertKnots( 2 );
00154 //  insertKnots.visit( composite );
00155 
00156     VVisitor::visitVPath( composite );
00157 }
00158 
00159 void
00160 VWhirlPinchCmd::visitVSubpath( VSubpath& path )
00161 {
00162     QWMatrix m;
00163     KoPoint delta;
00164     double dist;
00165 
00166     path.first();
00167 
00168     while( path.current() )
00169     {
00170 // TODO: selfmade this function since it's gone:
00171 //      path.current()->convertToCurve();
00172 
00173 
00174         // Apply three times separately to each segment node.
00175 
00176         delta = path.current()->knot() - m_center;
00177         dist = sqrt( delta.x() * delta.x() + delta.y() * delta.y() );
00178 
00179         if( dist < m_radius )
00180         {
00181             m.reset();
00182 
00183             dist /= m_radius;
00184 
00185             // pinch:
00186             m.translate( m_center.x(), m_center.y() );
00187             m.scale(
00188                 pow( sin( VGlobal::pi_2 * dist ), -m_pinch ),
00189                 pow( sin( VGlobal::pi_2 * dist ), -m_pinch ) );
00190 
00191             // whirl:
00192             m.rotate( m_angle * ( 1.0 - dist ) * ( 1.0 - dist ) );
00193             m.translate( -m_center.x(), -m_center.y() );
00194 
00195             path.current()->setKnot( path.current()->knot().transform( m ) );
00196         }
00197 
00198         if( path.current()->isCurve() )
00199         {
00200             delta = path.current()->point( 0 ) - m_center;
00201             dist = sqrt( delta.x() * delta.x() + delta.y() * delta.y() );
00202 
00203             if( dist < m_radius )
00204             {
00205                 m.reset();
00206 
00207                 dist /= m_radius;
00208 
00209                 // Pinch.
00210                 m.translate( m_center.x(), m_center.y() );
00211                 m.scale(
00212                     pow( sin( VGlobal::pi_2 * dist ), -m_pinch ),
00213                     pow( sin( VGlobal::pi_2 * dist ), -m_pinch ) );
00214 
00215                 // Whirl.
00216                 m.rotate( m_angle * ( 1.0 - dist ) * ( 1.0 - dist ) );
00217                 m.translate( -m_center.x(), -m_center.y() );
00218 
00219                 path.current()->setPoint( 0, path.current()->point(0).transform( m ) );
00220             }
00221 
00222 
00223             delta = path.current()->point( 1 ) - m_center;
00224             dist = sqrt( delta.x() * delta.x() + delta.y() * delta.y() );
00225 
00226             if( dist < m_radius )
00227             {
00228                 m.reset();
00229 
00230                 dist /= m_radius;
00231 
00232                 // Pinch.
00233                 m.translate( m_center.x(), m_center.y() );
00234                 m.scale(
00235                     pow( sin( VGlobal::pi_2 * dist ), -m_pinch ),
00236                     pow( sin( VGlobal::pi_2 * dist ), -m_pinch ) );
00237 
00238                 // Whirl.
00239                 m.rotate( m_angle * ( 1.0 - dist ) * ( 1.0 - dist ) );
00240                 m.translate( -m_center.x(), -m_center.y() );
00241 
00242                 path.current()->setPoint( 1, path.current()->point(1).transform( m ) );
00243             }
00244         }
00245 
00246 
00247         if( !success() )
00248             setSuccess();
00249 
00250 
00251         path.next();
00252     }
00253 
00254     // Invalidate bounding box once.
00255     path.invalidateBoundingBox();
00256 }
00257 
00258 #include "whirlpinchplugin.moc"
00259 
KDE Home | KDE Accessibility Home | Description of Access Keys