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.
tdeedu/kig/misc/special_constructors.cpp

1629 lines
48 KiB

// Copyright (C) 2003 Dominique Devriese <devriese@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.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301, USA.
#include "special_constructors.h"
#include "calcpaths.h"
#include "common.h"
#include "conic-common.h"
#include "guiaction.h"
#include "kigpainter.h"
#include "../kig/kig_part.h"
#include "../modes/construct_mode.h"
#include "../objects/bogus_imp.h"
#include "../objects/centerofcurvature_type.h"
#include "../objects/circle_imp.h"
#include "../objects/conic_imp.h"
#include "../objects/conic_types.h"
#include "../objects/cubic_imp.h"
#include "../objects/intersection_types.h"
#include "../objects/inversion_type.h"
#include "../objects/line_imp.h"
#include "../objects/line_type.h"
#include "../objects/locus_imp.h"
#include "../objects/object_calcer.h"
#include "../objects/object_drawer.h"
#include "../objects/object_factory.h"
#include "../objects/object_holder.h"
#include "../objects/object_imp.h"
#include "../objects/object_type.h"
#include "../objects/other_imp.h"
#include "../objects/other_type.h"
#include "../objects/point_imp.h"
#include "../objects/point_type.h"
#include "../objects/polygon_imp.h"
#include "../objects/polygon_type.h"
#include "../objects/tangent_type.h"
#include "../objects/text_imp.h"
#include "../objects/transform_types.h"
#include <tqpen.h>
#include <tdelocale.h>
#include <algorithm>
#include <functional>
class ConicConicIntersectionConstructor
: public StandardConstructorBase
{
protected:
ArgsParser mparser;
public:
ConicConicIntersectionConstructor();
~ConicConicIntersectionConstructor();
void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
const KigDocument& ) const;
std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& w ) const;
void plug( KigPart* doc, KigGUIAction* kact );
bool isTransform() const;
};
class ConicLineIntersectionConstructor
: public MultiObjectTypeConstructor
{
public:
ConicLineIntersectionConstructor();
~ConicLineIntersectionConstructor();
};
class ArcLineIntersectionConstructor
: public MultiObjectTypeConstructor
{
public:
ArcLineIntersectionConstructor();
~ArcLineIntersectionConstructor();
};
ConicRadicalConstructor::ConicRadicalConstructor()
: StandardConstructorBase(
I18N_NOOP( "Radical Lines for Conics" ),
I18N_NOOP( "The lines constructed through the intersections "
"of two conics. This is also defined for "
"non-intersecting conics." ),
"conicsradicalline", mparser ),
mtype( ConicRadicalType::instance() ),
mparser( mtype->argsParser().without( IntImp::stype() ) )
{
}
ConicRadicalConstructor::~ConicRadicalConstructor()
{
}
void ConicRadicalConstructor::drawprelim(
const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents, const KigDocument& doc ) const
{
if ( parents.size() == 2 && parents[0]->imp()->inherits( ConicImp::stype() ) &&
parents[1]->imp()->inherits( ConicImp::stype() ) )
{
Args args;
std::transform( parents.begin(), parents.end(),
std::back_inserter( args ), std::mem_fun( &ObjectCalcer::imp ) );
for ( int i = -1; i < 2; i += 2 )
{
IntImp root( i );
IntImp zeroindex( 1 );
args.push_back( &root );
args.push_back( &zeroindex );
ObjectImp* data = mtype->calc( args, doc );
drawer.draw( *data, p, true );
delete data; data = 0;
args.pop_back();
args.pop_back();
};
};
}
std::vector<ObjectHolder*> ConicRadicalConstructor::build( const std::vector<ObjectCalcer*>& os, KigDocument&, KigWidget& ) const
{
using namespace std;
std::vector<ObjectHolder*> ret;
ObjectCalcer* zeroindexcalcer = new ObjectConstCalcer( new IntImp( 1 ) );
for ( int i = -1; i < 2; i += 2 )
{
std::vector<ObjectCalcer*> args;
std::copy( os.begin(), os.end(), back_inserter( args ) );
args.push_back( new ObjectConstCalcer( new IntImp( i ) ) );
// we use only one zeroindex dataobject, so that if you switch one
// radical line around, then the other switches along..
args.push_back( zeroindexcalcer );
ret.push_back(
new ObjectHolder( new ObjectTypeCalcer( mtype, args ) ) );
};
return ret;
}
static const struct ArgsParser::spec argsspecpp[] =
{
{ PointImp::stype(), I18N_NOOP( "Moving Point" ),
I18N_NOOP( "Select the moving point, which will be moved around while drawing the locus..." ), false },
{ PointImp::stype(), I18N_NOOP( "Following Point" ),
I18N_NOOP( "Select the following point, whose locations the locus will be drawn through..." ), true }
};
LocusConstructor::LocusConstructor()
: StandardConstructorBase( I18N_NOOP( "Locus" ), I18N_NOOP( "A locus" ),
"locus", margsparser ),
margsparser( argsspecpp, 2 )
{
}
LocusConstructor::~LocusConstructor()
{
}
void LocusConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
const KigDocument& ) const
{
// this function is rather ugly, but it is necessary to do it this
// way in order to play nice with Kig's design..
if ( parents.size() != 2 ) return;
const ObjectTypeCalcer* constrained = dynamic_cast<ObjectTypeCalcer*>( parents.front() );
const ObjectCalcer* moving = parents.back();
if ( ! constrained || ! constrained->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
{
// moving is in fact the constrained point.. swap them..
moving = parents.front();
constrained = dynamic_cast<const ObjectTypeCalcer*>( parents.back() );
assert( constrained );
};
assert( constrained->type()->inherits( ObjectType::ID_ConstrainedPointType ) );
const ObjectImp* oimp = constrained->parents().back()->imp();
if( !oimp->inherits( CurveImp::stype() ) )
oimp = constrained->parents().front()->imp();
assert( oimp->inherits( CurveImp::stype() ) );
const CurveImp* cimp = static_cast<const CurveImp*>( oimp );
ObjectHierarchy hier( constrained, moving );
LocusImp limp( cimp->copy(), hier );
drawer.draw( limp, p, true );
}
const int LocusConstructor::wantArgs(
const std::vector<ObjectCalcer*>& os, const KigDocument&, const KigWidget&
) const
{
int ret = margsparser.check( os );
if ( ret == ArgsParser::Invalid ) return ret;
else if ( os.size() != 2 ) return ret;
if ( dynamic_cast<ObjectTypeCalcer*>( os.front() ) &&
static_cast<ObjectTypeCalcer*>( os.front() )->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
{
std::set<ObjectCalcer*> children = getAllChildren( os.front() );
return children.find( os.back() ) != children.end() ? ret : ArgsParser::Invalid;
}
if ( dynamic_cast<ObjectTypeCalcer*>( os.back() ) &&
static_cast<ObjectTypeCalcer*>( os.back() )->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
{
std::set<ObjectCalcer*> children = getAllChildren( os.back() );
return children.find( os.front() ) != children.end() ? ret : ArgsParser::Invalid;
}
return ArgsParser::Invalid;
}
std::vector<ObjectHolder*> LocusConstructor::build( const std::vector<ObjectCalcer*>& parents, KigDocument&, KigWidget& ) const
{
std::vector<ObjectHolder*> ret;
assert( parents.size() == 2 );
ObjectTypeCalcer* constrained = dynamic_cast<ObjectTypeCalcer*>( parents.front() );
ObjectCalcer* moving = parents.back();
if ( ! constrained || ! constrained->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
{
// moving is in fact the constrained point.. swap them..
moving = parents.front();
constrained = dynamic_cast<ObjectTypeCalcer*>( parents.back() );
assert( constrained );
};
assert( constrained->type()->inherits( ObjectType::ID_ConstrainedPointType ) );
ret.push_back( ObjectFactory::instance()->locus( constrained, moving ) );
return ret;
}
TQString LocusConstructor::useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& os,
const KigDocument&, const KigWidget& ) const
{
if ( dynamic_cast<const ObjectTypeCalcer*>( &o ) &&
static_cast<const ObjectTypeCalcer&>( o ).type()->inherits( ObjectType::ID_ConstrainedPointType ) &&
( os.empty() || !dynamic_cast<ObjectTypeCalcer*>( os[0] ) ||
!static_cast<const ObjectTypeCalcer*>( os[0] )->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
) return i18n( "Moving Point" );
else return i18n( "Dependent Point" );
}
void ConicRadicalConstructor::plug( KigPart*, KigGUIAction* )
{
}
void LocusConstructor::plug( KigPart*, KigGUIAction* )
{
}
bool ConicRadicalConstructor::isTransform() const
{
return mtype->isTransform();
}
bool LocusConstructor::isTransform() const
{
return false;
}
/*
* generic polygon constructor
*/
PolygonBNPTypeConstructor::PolygonBNPTypeConstructor()
: mtype( PolygonBNPType::instance() )
{
}
PolygonBNPTypeConstructor::~PolygonBNPTypeConstructor()
{
}
const TQString PolygonBNPTypeConstructor::descriptiveName() const
{
return i18n("Polygon by Its Vertices");
}
const TQString PolygonBNPTypeConstructor::description() const
{
return i18n("Construct a polygon by giving its vertices");
}
const TQCString PolygonBNPTypeConstructor::iconFileName( const bool ) const
{
return "kig_polygon";
}
const bool PolygonBNPTypeConstructor::isAlreadySelectedOK(
const std::vector<ObjectCalcer*>& os, const int& pos ) const
{
if ( pos == 0 && os.size() >= 3 ) return true;
return false;
}
const int PolygonBNPTypeConstructor::wantArgs( const std::vector<ObjectCalcer*>& os,
const KigDocument&,
const KigWidget& ) const
{
int count=os.size() - 1;
for ( int i = 0; i <= count; i++ )
{
if ( ! ( os[i]->imp()->inherits( PointImp::stype() ) ) ) return ArgsParser::Invalid;
}
if ( count < 3 ) return ArgsParser::Valid;
if ( os[0] == os[count] ) return ArgsParser::Complete;
return ArgsParser::Valid;
}
void PolygonBNPTypeConstructor::handleArgs(
const std::vector<ObjectCalcer*>& os, KigPart& d,
KigWidget& v ) const
{
std::vector<ObjectHolder*> bos = build( os, d.document(), v );
for ( std::vector<ObjectHolder*>::iterator i = bos.begin();
i != bos.end(); ++i )
{
(*i)->calc( d.document() );
}
d.addObjects( bos );
}
void PolygonBNPTypeConstructor::handlePrelim(
KigPainter& p, const std::vector<ObjectCalcer*>& os,
const KigDocument& d, const KigWidget&
) const
{
uint count = os.size();
if ( count < 2 ) return;
for ( uint i = 0; i < count; i++ )
{
assert ( os[i]->imp()->inherits( PointImp::stype() ) );
}
std::vector<ObjectCalcer*> args = os;
p.setBrushStyle( Qt::NoBrush );
p.setBrushColor( TQt::red );
p.setPen( TQPen ( TQt::red, 1) );
p.setWidth( -1 ); // -1 means the default width for the object being
// drawn..
ObjectDrawer drawer( TQt::red );
drawprelim( drawer, p, args, d );
}
TQString PolygonBNPTypeConstructor::useText( const ObjectCalcer&, const std::vector<ObjectCalcer*>& os,
const KigDocument&, const KigWidget& ) const
{
if ( os.size() > 3 )
return i18n("... with this vertex (click on the first vertex to terminate construction)");
else return i18n("Construct a polygon with this vertex");
}
TQString PolygonBNPTypeConstructor::selectStatement(
const std::vector<ObjectCalcer*>&, const KigDocument&,
const KigWidget& ) const
{
return i18n("Select a point to be a vertex of the new polygon...");
}
void PolygonBNPTypeConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
const KigDocument& ) const
{
if ( parents.size() < 2 ) return;
std::vector<Coordinate> points;
for ( uint i = 0; i < parents.size(); ++i )
{
const Coordinate vertex =
static_cast<const PointImp*>( parents[i]->imp() )->coordinate();
points.push_back( vertex );
}
if ( parents.size() == 2 )
{
SegmentImp segment = SegmentImp( points[0], points[1] );
drawer.draw( segment, p, true );
} else {
PolygonImp polygon = PolygonImp( points );
drawer.draw( polygon, p, true );
}
}
std::vector<ObjectHolder*> PolygonBNPTypeConstructor::build( const std::vector<ObjectCalcer*>& parents, KigDocument&, KigWidget& ) const
{
uint count = parents.size() - 1;
assert ( count >= 3 );
std::vector<ObjectCalcer*> args;
for ( uint i = 0; i < count; ++i ) args.push_back( parents[i] );
ObjectTypeCalcer* calcer = new ObjectTypeCalcer( mtype, args );
ObjectHolder* h = new ObjectHolder( calcer );
std::vector<ObjectHolder*> ret;
ret.push_back( h );
return ret;
}
void PolygonBNPTypeConstructor::plug( KigPart*, KigGUIAction* )
{
}
bool PolygonBNPTypeConstructor::isTransform() const
{
return false;
}
/*
* construction of polygon vertices
*/
static const struct ArgsParser::spec argsspecpv[] =
{
{ PolygonImp::stype(), I18N_NOOP( "Polygon" ),
I18N_NOOP( "Construct the vertices of this polygon..." ), true }
};
PolygonVertexTypeConstructor::PolygonVertexTypeConstructor()
: StandardConstructorBase( I18N_NOOP( "Vertices of a Polygon" ),
I18N_NOOP( "The vertices of a polygon." ),
"polygonvertices", margsparser ),
mtype( PolygonVertexType::instance() ),
margsparser( argsspecpv, 1 )
{
}
PolygonVertexTypeConstructor::~PolygonVertexTypeConstructor()
{
}
void PolygonVertexTypeConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
const KigDocument& ) const
{
if ( parents.size() != 1 ) return;
const PolygonImp* polygon = dynamic_cast<const PolygonImp*>( parents.front()->imp() );
const std::vector<Coordinate> points = polygon->points();
int sides = points.size();
for ( int i = 0; i < sides; ++i )
{
PointImp point = PointImp( points[i] );
drawer.draw( point, p, true );
}
}
std::vector<ObjectHolder*> PolygonVertexTypeConstructor::build( const std::vector<ObjectCalcer*>& parents, KigDocument&, KigWidget& ) const
{
std::vector<ObjectHolder*> ret;
assert( parents.size() == 1 );
const PolygonImp* polygon = dynamic_cast<const PolygonImp*>( parents.front()->imp() );
const std::vector<Coordinate> points = polygon->points();
int sides = points.size();
for ( int i = 0; i < sides; ++i )
{
ObjectConstCalcer* d = new ObjectConstCalcer( new IntImp( i ) );
std::vector<ObjectCalcer*> args( parents );
args.push_back( d );
ret.push_back( new ObjectHolder( new ObjectTypeCalcer( mtype, args ) ) );
}
return ret;
}
void PolygonVertexTypeConstructor::plug( KigPart*, KigGUIAction* )
{
}
bool PolygonVertexTypeConstructor::isTransform() const
{
return false;
}
/*
* construction of polygon sides
*/
static const struct ArgsParser::spec argsspecps[] =
{
{ PolygonImp::stype(), I18N_NOOP( "Polygon" ),
I18N_NOOP( "Construct the sides of this polygon..." ), false }
};
PolygonSideTypeConstructor::PolygonSideTypeConstructor()
: StandardConstructorBase( I18N_NOOP( "Sides of a Polygon" ),
I18N_NOOP( "The sides of a polygon." ),
"polygonsides", margsparser ),
mtype( PolygonSideType::instance() ),
margsparser( argsspecps, 1 )
{
}
PolygonSideTypeConstructor::~PolygonSideTypeConstructor()
{
}
void PolygonSideTypeConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
const KigDocument& ) const
{
if ( parents.size() != 1 ) return;
const PolygonImp* polygon = dynamic_cast<const PolygonImp*>( parents.front()->imp() );
const std::vector<Coordinate> points = polygon->points();
uint sides = points.size();
for ( uint i = 0; i < sides; ++i )
{
uint nexti = ( i + 1 < sides )?(i + 1):0;
SegmentImp segment = SegmentImp( points[i], points[nexti] );
drawer.draw( segment, p, true );
}
}
std::vector<ObjectHolder*> PolygonSideTypeConstructor::build( const std::vector<ObjectCalcer*>& parents, KigDocument&, KigWidget& ) const
{
std::vector<ObjectHolder*> ret;
assert( parents.size() == 1 );
const PolygonImp* polygon = dynamic_cast<const PolygonImp*>( parents.front()->imp() );
const std::vector<Coordinate> points = polygon->points();
uint sides = points.size();
for ( uint i = 0; i < sides; ++i )
{
ObjectConstCalcer* d = new ObjectConstCalcer( new IntImp( i ) );
std::vector<ObjectCalcer*> args( parents );
args.push_back( d );
ret.push_back( new ObjectHolder( new ObjectTypeCalcer( mtype, args ) ) );
}
return ret;
}
void PolygonSideTypeConstructor::plug( KigPart*, KigGUIAction* )
{
}
bool PolygonSideTypeConstructor::isTransform() const
{
return false;
}
/*
* polygon by center and vertex
*/
PolygonBCVConstructor::PolygonBCVConstructor()
: mtype( PolygonBCVType::instance() )
{
}
PolygonBCVConstructor::~PolygonBCVConstructor()
{
}
const TQString PolygonBCVConstructor::descriptiveName() const
{
return i18n("Regular Polygon with Given Center");
}
const TQString PolygonBCVConstructor::description() const
{
return i18n("Construct a regular polygon with a given center and vertex");
}
const TQCString PolygonBCVConstructor::iconFileName( const bool ) const
{
return "hexagonbcv";
}
const bool PolygonBCVConstructor::isAlreadySelectedOK(
const std::vector<ObjectCalcer*>&, const int& ) const
{
return false;
}
const int PolygonBCVConstructor::wantArgs( const std::vector<ObjectCalcer*>& os,
const KigDocument&,
const KigWidget& ) const
{
if ( os.size() > 3 ) return ArgsParser::Invalid;
uint imax = ( os.size() <= 2) ? os.size() : 2;
for ( uint i = 0; i < imax; ++i )
if ( ! ( os[i]->imp()->inherits( PointImp::stype() ) ) ) return ArgsParser::Invalid;
if ( os.size() < 3 ) return ArgsParser::Valid;
if ( ! ( os[2]->imp()->inherits( BogusPointImp::stype() ) ) )
return ArgsParser::Invalid;
return ArgsParser::Complete;
}
void PolygonBCVConstructor::handleArgs(
const std::vector<ObjectCalcer*>& os, KigPart& d,
KigWidget& v ) const
{
std::vector<ObjectHolder*> bos = build( os, d.document(), v );
for ( std::vector<ObjectHolder*>::iterator i = bos.begin();
i != bos.end(); ++i )
{
(*i)->calc( d.document() );
}
d.addObjects( bos );
}
void PolygonBCVConstructor::handlePrelim(
KigPainter& p, const std::vector<ObjectCalcer*>& os,
const KigDocument& d, const KigWidget&
) const
{
if ( os.size() < 2 ) return;
for ( uint i = 0; i < 2; i++ )
{
assert ( os[i]->imp()->inherits( PointImp::stype() ) );
}
Coordinate c = static_cast<const PointImp*>( os[0]->imp() )->coordinate();
Coordinate v = static_cast<const PointImp*>( os[1]->imp() )->coordinate();
int nsides = 6;
bool moreinfo = false;
int winding = 0; // 0 means allow winding > 1
if ( os.size() == 3 )
{
assert ( os[2]->imp()->inherits( BogusPointImp::stype() ) );
Coordinate cntrl = static_cast<const PointImp*>( os[2]->imp() )->coordinate();
nsides = computeNsides( c, v, cntrl, winding );
moreinfo = true;
}
std::vector<ObjectCalcer*> args;
args.push_back( os[0] );
args.push_back( os[1] );
ObjectConstCalcer* ns = new ObjectConstCalcer( new IntImp( nsides ) );
args.push_back( ns );
if ( winding > 1 )
{
ns = new ObjectConstCalcer( new IntImp( winding ) );
args.push_back( ns );
}
p.setBrushStyle( Qt::NoBrush );
p.setBrushColor( TQt::red );
p.setPen( TQPen ( TQt::red, 1) );
p.setWidth( -1 ); // -1 means the default width for the object being
// drawn..
ObjectDrawer drawer( TQt::red );
drawprelim( drawer, p, args, d );
if ( moreinfo )
{
p.setPointStyle( 1 );
p.setWidth( 6 );
double ro = 1.0/(2.5);
Coordinate where = getRotatedCoord( c, (1-ro)*c+ro*v, 4*M_PI/5.0 );
PointImp ptn = PointImp( where );
TextImp text = TextImp( "(5,2)", where, false );
ptn.draw( p );
text.draw( p );
for ( int i = 3; i < 9; ++i )
{
where = getRotatedCoord( c, v, 2.0*M_PI/i );
ptn = PointImp( where );
ptn.draw( p );
if ( i > 5 ) continue;
text = TextImp( TQString( "(%1)" ).arg(i), where, false );
text.draw( p );
}
p.setStyle( Qt::DotLine );
p.setWidth( 1 );
double radius = ( v - c ).length();
CircleImp circle = CircleImp( c, radius );
circle.draw( p );
for ( int i = 2; i < 5; i++ )
{
ro = 1.0/(i+0.5);
CircleImp circle = CircleImp( c, ro*radius );
circle.draw( p );
}
}
delete_all( args.begin() + 2, args.end() );
}
std::vector<ObjectHolder*> PolygonBCVConstructor::build( const std::vector<ObjectCalcer*>& parents, KigDocument&, KigWidget& ) const
{
assert ( parents.size() == 3 );
std::vector<ObjectCalcer*> args;
Coordinate c = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
Coordinate v = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
Coordinate cntrl = static_cast<const PointImp*>( parents[2]->imp() )->coordinate();
args.push_back( parents[0] );
args.push_back( parents[1] );
int winding = 0;
int nsides = computeNsides( c, v, cntrl, winding );
ObjectConstCalcer* d = new ObjectConstCalcer( new IntImp( nsides ) );
args.push_back( d );
if ( winding > 1 )
{
d = new ObjectConstCalcer( new IntImp( winding ) );
args.push_back( d );
}
ObjectTypeCalcer* calcer = new ObjectTypeCalcer( mtype, args );
ObjectHolder* h = new ObjectHolder( calcer );
std::vector<ObjectHolder*> ret;
ret.push_back( h );
return ret;
}
TQString PolygonBCVConstructor::useText( const ObjectCalcer&, const std::vector<ObjectCalcer*>& os,
const KigDocument&, const KigWidget& ) const
{
switch ( os.size() )
{
case 1:
return i18n( "Construct a regular polygon with this center" );
break;
case 2:
return i18n( "Construct a regular polygon with this vertex" );
break;
case 3:
Coordinate c = static_cast<const PointImp*>( os[0]->imp() )->coordinate();
Coordinate v = static_cast<const PointImp*>( os[1]->imp() )->coordinate();
Coordinate cntrl = static_cast<const PointImp*>( os[2]->imp() )->coordinate();
int winding = 0;
int nsides = computeNsides( c, v, cntrl, winding );
if ( winding > 1 )
{
TQString result = TQString(
i18n( "Adjust the number of sides (%1/%2)" )
).arg( nsides ).arg( winding );
return result;
} else
{
TQString result = TQString(
i18n( "Adjust the number of sides (%1)" )
).arg( nsides );
return result;
}
break;
}
return "";
}
TQString PolygonBCVConstructor::selectStatement(
const std::vector<ObjectCalcer*>& os, const KigDocument&,
const KigWidget& ) const
{
switch ( os.size() )
{
case 1:
return i18n( "Select the center of the new polygon..." );
break;
case 2:
return i18n( "Select a vertex for the new polygon..." );
break;
case 3:
return i18n( "Move the cursor to get the desired number of sides..." );
break;
}
return "";
}
void PolygonBCVConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
const KigDocument& doc ) const
{
if ( parents.size() < 3 || parents.size() > 4 ) return;
assert ( parents[0]->imp()->inherits( PointImp::stype() ) &&
parents[1]->imp()->inherits( PointImp::stype() ) &&
parents[2]->imp()->inherits( IntImp::stype() ) );
if ( parents.size() == 4 )
assert ( parents[3]->imp()->inherits( IntImp::stype() ) );
Args args;
std::transform( parents.begin(), parents.end(),
std::back_inserter( args ), std::mem_fun( &ObjectCalcer::imp ) );
ObjectImp* data = mtype->calc( args, doc );
drawer.draw( *data, p, true );
delete data;
data = 0;
}
void PolygonBCVConstructor::plug( KigPart*, KigGUIAction* )
{
}
bool PolygonBCVConstructor::isTransform() const
{
return false;
}
Coordinate PolygonBCVConstructor::getRotatedCoord( const Coordinate& c,
const Coordinate& v, double alpha ) const
{
double cosalpha = cos(alpha);
double sinalpha = sin(alpha);
double dx = v.x - c.x;
double dy = v.y - c.y;
return c + Coordinate( cosalpha*dx - sinalpha*dy, sinalpha*dx + cosalpha*dy );
}
int PolygonBCVConstructor::computeNsides ( const Coordinate& c,
const Coordinate& v, const Coordinate& cntrl, int& winding ) const
{
Coordinate lvect = v - c;
Coordinate rvect = cntrl - c;
double angle = atan2( rvect.y, rvect.x ) - atan2( lvect.y, lvect.x );
angle = fabs( angle/(2*M_PI) );
while ( angle > 1 ) angle -= 1;
if ( angle > 0.5 ) angle = 1 - angle;
double realsides = 1.0/angle; // this is bigger that 2
if ( angle == 0. ) realsides = 3;
if ( winding <= 0 ) // free to compute winding
{
winding = 1;
double ratio = lvect.length()/rvect.length();
winding = int ( ratio );
if ( winding < 1 ) winding = 1;
if ( winding > 50 ) winding = 50;
}
int nsides = int( winding*realsides + 0.5 ); // nsides/winding should be reduced!
if ( nsides > 100 ) nsides = 100; // well, 100 seems large enough!
if ( nsides < 3 ) nsides = 3;
while ( !relativePrimes ( nsides, winding ) ) ++nsides;
return nsides;
}
/*
* ConicConic intersection...
*/
static const ArgsParser::spec argsspectc[] = {
{ ConicImp::stype(), "SHOULD NOT BE SEEN", "SHOULD NOT BE SEEN", true },
{ ConicImp::stype(), "SHOULD NOT BE SEEN", "SHOULD NOT BE SEEN", true }
};
ConicConicIntersectionConstructor::ConicConicIntersectionConstructor()
: StandardConstructorBase( "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"curvelineintersection", mparser ),
mparser( argsspectc, 2 )
{
}
ConicConicIntersectionConstructor::~ConicConicIntersectionConstructor()
{
}
void ConicConicIntersectionConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
const KigDocument& ) const
{
if ( parents.size() != 2 ) return;
assert ( parents[0]->imp()->inherits( ConicImp::stype() ) &&
parents[1]->imp()->inherits( ConicImp::stype() ) );
const ConicCartesianData conica =
static_cast<const ConicImp*>( parents[0]->imp() )->cartesianData();
const ConicCartesianData conicb =
static_cast<const ConicImp*>( parents[1]->imp() )->cartesianData();
bool ok = true;
for ( int wr = -1; wr < 2; wr += 2 )
{
LineData radical = calcConicRadical( conica, conicb, wr, 1, ok );
if ( ok )
{
for ( int wi = -1; wi < 2; wi += 2 )
{
Coordinate c = calcConicLineIntersect( conica, radical, 0.0, wi );
if ( c.valid() ) {
PointImp pi( c );
drawer.draw( pi, p, true );
}
};
};
};
}
std::vector<ObjectHolder*> ConicConicIntersectionConstructor::build(
const std::vector<ObjectCalcer*>& os, KigDocument& doc, KigWidget& ) const
{
assert( os.size() == 2 );
std::vector<ObjectHolder*> ret;
ObjectCalcer* conica = os[0];
ObjectConstCalcer* zeroindexdo = new ObjectConstCalcer( new IntImp( 1 ) );
for ( int wr = -1; wr < 2; wr += 2 )
{
std::vector<ObjectCalcer*> args = os;
args.push_back( new ObjectConstCalcer( new IntImp( wr ) ) );
args.push_back( zeroindexdo );
ObjectTypeCalcer* radical =
new ObjectTypeCalcer( ConicRadicalType::instance(), args );
radical->calc( doc );
for ( int wi = -1; wi < 2; wi += 2 )
{
args.clear();
args.push_back( conica );
args.push_back( radical );
args.push_back( new ObjectConstCalcer( new IntImp( wi ) ) );
ret.push_back(
new ObjectHolder(
new ObjectTypeCalcer(
ConicLineIntersectionType::instance(), args ) ) );
};
};
return ret;
}
void ConicConicIntersectionConstructor::plug( KigPart*, KigGUIAction* )
{
}
bool ConicConicIntersectionConstructor::isTransform() const
{
return false;
}
ConicLineIntersectionConstructor::ConicLineIntersectionConstructor()
: MultiObjectTypeConstructor(
ConicLineIntersectionType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"curvelineintersection", -1, 1 )
{
}
ConicLineIntersectionConstructor::~ConicLineIntersectionConstructor()
{
}
ArcLineIntersectionConstructor::ArcLineIntersectionConstructor()
: MultiObjectTypeConstructor(
ArcLineIntersectionType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"curvelineintersection", -1, 1 )
{
}
ArcLineIntersectionConstructor::~ArcLineIntersectionConstructor()
{
}
TQString ConicRadicalConstructor::useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>&,
const KigDocument&, const KigWidget& ) const
{
if ( o.imp()->inherits( CircleImp::stype() ) )
return i18n( "Construct the Radical Lines of This Circle" );
else
return i18n( "Construct the Radical Lines of This Conic" );
}
/*
* generic affinity and generic projectivity. A unique affinity can be
* obtained by specifying the image of three points (four for projectivity)
* in the end we need, besides the object to be transformed, a total of
* six point or (alternatively) two triangles; our affinity will map the
* first triangle onto the second with corresponding ordering of their
* vertices. Since we allow for two different ways of specifying the six
* points we shall use a Generic constructor, like that for intersections.
*/
GenericAffinityConstructor::GenericAffinityConstructor()
: MergeObjectConstructor(
I18N_NOOP( "Generic Affinity" ),
I18N_NOOP( "The unique affinity that maps three points (or a triangle) onto three other points (or a triangle)" ),
"genericaffinity" )
{
SimpleObjectTypeConstructor* b2tr =
new SimpleObjectTypeConstructor(
AffinityB2TrType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"genericaffinity" );
SimpleObjectTypeConstructor* gi3p =
new SimpleObjectTypeConstructor(
AffinityGI3PType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"genericaffinity" );
merge( b2tr );
merge( gi3p );
}
GenericAffinityConstructor::~GenericAffinityConstructor() {}
GenericProjectivityConstructor::GenericProjectivityConstructor()
: MergeObjectConstructor(
I18N_NOOP( "Generic Projective Transformation" ),
I18N_NOOP( "The unique projective transformation that maps four points (or a quadrilateral) onto four other points (or a quadrilateral)" ),
"genericprojectivity" )
{
SimpleObjectTypeConstructor* b2qu =
new SimpleObjectTypeConstructor(
ProjectivityB2QuType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"genericprojectivity" );
SimpleObjectTypeConstructor* gi4p =
new SimpleObjectTypeConstructor(
ProjectivityGI4PType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"genericprojectivity" );
merge( b2qu );
merge( gi4p );
}
GenericProjectivityConstructor::~GenericProjectivityConstructor() {}
/*
* inversion of points, lines with respect to a circle
*/
InversionConstructor::InversionConstructor()
: MergeObjectConstructor(
I18N_NOOP( "Inversion of Point, Line or Circle" ),
I18N_NOOP( "The inversion of a point, line or circle with respect to a circle" ),
"inversion" )
{
SimpleObjectTypeConstructor* pointobj =
new SimpleObjectTypeConstructor(
InvertPointType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"inversion" );
SimpleObjectTypeConstructor* lineobj =
new SimpleObjectTypeConstructor(
InvertLineType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"inversion" );
SimpleObjectTypeConstructor* segmentobj =
new SimpleObjectTypeConstructor(
InvertSegmentType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"inversion" );
SimpleObjectTypeConstructor* circleobj =
new SimpleObjectTypeConstructor(
InvertCircleType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"inversion" );
SimpleObjectTypeConstructor* arcobj =
new SimpleObjectTypeConstructor(
InvertArcType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"inversion" );
merge( arcobj );
merge( circleobj );
merge( pointobj );
merge( segmentobj );
merge( lineobj );
}
InversionConstructor::~InversionConstructor() {}
/*
* Transport of Measure
*/
MeasureTransportConstructor::MeasureTransportConstructor()
: mtype( MeasureTransportType::instance() )
{
}
MeasureTransportConstructor::~MeasureTransportConstructor()
{
}
const TQString MeasureTransportConstructor::descriptiveName() const
{
return i18n("Measure Transport");
}
const TQString MeasureTransportConstructor::description() const
{
return i18n("Transport the measure of a segment or arc over a line or circle.");
}
const TQCString MeasureTransportConstructor::iconFileName( const bool ) const
{
return "measuretransport";
}
const bool MeasureTransportConstructor::isAlreadySelectedOK(
const std::vector<ObjectCalcer*>&, const int& ) const
{
return false;
}
/*
* we want the arguments in the exact order, this makes
* the code simpler, but I guess it is also less confusing
* to the user
*/
const int MeasureTransportConstructor::wantArgs(
const std::vector<ObjectCalcer*>& os,
const KigDocument&,
const KigWidget& ) const
{
if ( os.size() == 0 ) return ArgsParser::Valid;
if ( ! os[0]->imp()->inherits( SegmentImp::stype() ) &&
! os[0]->imp()->inherits( ArcImp::stype() ) )
return ArgsParser::Invalid;
if ( os.size() == 1 ) return ArgsParser::Valid;
if ( ! os[1]->imp()->inherits( LineImp::stype() ) &&
! os[1]->imp()->inherits( CircleImp::stype() ) )
return ArgsParser::Invalid;
if ( os.size() == 2 ) return ArgsParser::Valid;
if ( ! os[2]->imp()->inherits( PointImp::stype() ) )
return ArgsParser::Invalid;
// we here use the "isPointOnCurve", which relies on
// "by construction" incidence, instead of a numerical
// check
if ( ! isPointOnCurve( os[2], os[1] ) )
return ArgsParser::Invalid;
if ( os.size() == 3 ) return ArgsParser::Complete;
return ArgsParser::Invalid;
}
void MeasureTransportConstructor::handleArgs(
const std::vector<ObjectCalcer*>& os, KigPart& d,
KigWidget& v ) const
{
std::vector<ObjectHolder*> bos = build( os, d.document(), v );
for ( std::vector<ObjectHolder*>::iterator i = bos.begin();
i != bos.end(); ++i )
{
(*i)->calc( d.document() );
}
d.addObjects( bos );
}
void MeasureTransportConstructor::handlePrelim(
KigPainter& p, const std::vector<ObjectCalcer*>& os,
const KigDocument& d, const KigWidget&
) const
{
p.setBrushStyle( Qt::NoBrush );
p.setBrushColor( TQt::red );
p.setPen( TQPen ( TQt::red, 1) );
p.setWidth( -1 ); // -1 means the default width for the object being
// drawn..
ObjectDrawer drawer( TQt::red );
drawprelim( drawer, p, os, d );
}
void MeasureTransportConstructor::drawprelim( const ObjectDrawer& drawer,
KigPainter& p,
const std::vector<ObjectCalcer*>& parents,
const KigDocument& doc ) const
{
Args args;
using namespace std;
transform( parents.begin(), parents.end(),
back_inserter( args ), mem_fun( &ObjectCalcer::imp ) );
ObjectImp* data = mtype->calc( args, doc );
drawer.draw( *data, p, true );
delete data;
}
TQString MeasureTransportConstructor::useText( const ObjectCalcer& o,
const std::vector<ObjectCalcer*>& os,
const KigDocument&, const KigWidget& ) const
{
if ( o.imp()->inherits( SegmentImp::stype() ) )
return i18n("Segment to transport");
if ( o.imp()->inherits( ArcImp::stype() ) )
return i18n("Arc to transport");
if ( o.imp()->inherits( LineImp::stype() ) )
return i18n("Transport a measure on this line");
if ( o.imp()->inherits( CircleImp::stype() ) )
return i18n("Transport a measure on this circle");
if ( o.imp()->inherits( PointImp::stype() ) )
{
if ( os[1]->imp()->inherits( CircleImp::stype() ) )
return i18n("Start transport from this point of the circle");
if ( os[1]->imp()->inherits( LineImp::stype() ) )
return i18n("Start transport from this point of the line");
else
return i18n("Start transport from this point of the curve");
// well, this isn't impemented yet, should never get here
}
return "";
}
TQString MeasureTransportConstructor::selectStatement(
const std::vector<ObjectCalcer*>&, const KigDocument&,
const KigWidget& ) const
{
//TODO
return i18n("Select a point to be a vertex of the new polygon...");
}
std::vector<ObjectHolder*> MeasureTransportConstructor::build(
const std::vector<ObjectCalcer*>& parents,
KigDocument&, KigWidget& ) const
{
assert ( parents.size() == 3 );
// std::vector<ObjectCalcer*> args;
// for ( uint i = 0; i < count; ++i ) args.push_back( parents[i] );
ObjectTypeCalcer* calcer = new ObjectTypeCalcer( mtype, parents );
ObjectHolder* h = new ObjectHolder( calcer );
std::vector<ObjectHolder*> ret;
ret.push_back( h );
return ret;
}
void MeasureTransportConstructor::plug( KigPart*, KigGUIAction* )
{
}
bool MeasureTransportConstructor::isTransform() const
{
return false;
}
/*
* Generic intersection
*/
GenericIntersectionConstructor::GenericIntersectionConstructor()
: MergeObjectConstructor(
I18N_NOOP( "Intersect" ),
I18N_NOOP( "The intersection of two objects" ),
"curvelineintersection" )
{
// intersection type..
// There is one "toplevel" object_constructor, that is composed
// of multiple subconstructors.. First we build the
// subconstructors:
SimpleObjectTypeConstructor* lineline =
new SimpleObjectTypeConstructor(
LineLineIntersectionType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"curvelineintersection" );
ObjectConstructor* lineconic =
new ConicLineIntersectionConstructor();
ObjectConstructor* arcline =
new ArcLineIntersectionConstructor();
MultiObjectTypeConstructor* linecubic =
new MultiObjectTypeConstructor(
LineCubicIntersectionType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"curvelineintersection", 1, 2, 3 );
ObjectConstructor* conicconic =
new ConicConicIntersectionConstructor();
MultiObjectTypeConstructor* circlecircle =
new MultiObjectTypeConstructor(
CircleCircleIntersectionType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"circlecircleintersection", -1, 1 );
SimpleObjectTypeConstructor* polygonline =
new SimpleObjectTypeConstructor(
PolygonLineIntersectionType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"curvelineintersection" );
merge( lineline );
merge( circlecircle );
merge( lineconic );
merge( linecubic );
merge( conicconic );
merge( arcline );
merge( polygonline );
}
GenericIntersectionConstructor::~GenericIntersectionConstructor()
{
}
bool GenericIntersectionConstructor::isIntersection() const
{
return true;
}
TQString GenericIntersectionConstructor::useText(
const ObjectCalcer& o, const std::vector<ObjectCalcer*>& os,
const KigDocument&, const KigWidget& ) const
{
TQString preamble;
switch (os.size())
{
case 1:
if ( o.imp()->inherits( CircleImp::stype() ) )
return i18n( "Intersect this Circle" );
else if ( o.imp()->inherits( ConicImp::stype() ) )
return i18n( "Intersect this Conic" );
else if ( o.imp()->inherits( AbstractLineImp::stype() ) )
return i18n( "Intersect this Line" );
else if ( o.imp()->inherits( CubicImp::stype() ) )
return i18n( "Intersect this Cubic Curve" );
else if ( o.imp()->inherits( ArcImp::stype() ) )
return i18n( "Intersect this Arc" );
else if ( o.imp()->inherits( PolygonImp::stype() ) )
return i18n( "Intersect this Polygon" );
else assert( false );
break;
case 2:
if ( o.imp()->inherits( CircleImp::stype() ) )
return i18n( "with this Circle" );
else if ( o.imp()->inherits( ConicImp::stype() ) )
return i18n( "with this Conic" );
else if ( o.imp()->inherits( AbstractLineImp::stype() ) )
return i18n( "with this Line" );
else if ( o.imp()->inherits( CubicImp::stype() ) )
return i18n( "with this Cubic Curve" );
else if ( o.imp()->inherits( ArcImp::stype() ) )
return i18n( "with this Arc" );
else if ( o.imp()->inherits( PolygonImp::stype() ) )
return i18n( "with this Polygon" );
else assert( false );
break;
}
return TQString();
}
static const ArgsParser::spec argsspecMidPointOfTwoPoints[] =
{
{ PointImp::stype(), I18N_NOOP( "Construct Midpoint of This Point and Another One" ),
I18N_NOOP( "Select the first of the points of which you want to construct the midpoint..." ), false },
{ PointImp::stype(), I18N_NOOP( "Construct the midpoint of this point and another one" ),
I18N_NOOP( "Select the other of the points of which to construct the midpoint..." ), false }
};
MidPointOfTwoPointsConstructor::MidPointOfTwoPointsConstructor()
: StandardConstructorBase( "Mid Point",
"Construct the midpoint of two points",
"bisection", mparser ),
mparser( argsspecMidPointOfTwoPoints, 2 )
{
}
MidPointOfTwoPointsConstructor::~MidPointOfTwoPointsConstructor()
{
}
void MidPointOfTwoPointsConstructor::drawprelim(
const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
const KigDocument& ) const
{
if ( parents.size() != 2 ) return;
assert( parents[0]->imp()->inherits( PointImp::stype() ) );
assert( parents[1]->imp()->inherits( PointImp::stype() ) );
const Coordinate m =
( static_cast<const PointImp*>( parents[0]->imp() )->coordinate() +
static_cast<const PointImp*>( parents[1]->imp() )->coordinate() ) / 2;
drawer.draw( PointImp( m ), p, true );
}
std::vector<ObjectHolder*> MidPointOfTwoPointsConstructor::build(
const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& ) const
{
ObjectTypeCalcer* seg = new ObjectTypeCalcer( SegmentABType::instance(), os );
seg->calc( d );
int index = seg->imp()->propertiesInternalNames().findIndex( "mid-point" );
assert( index != -1 );
ObjectPropertyCalcer* prop = new ObjectPropertyCalcer( seg, index );
prop->calc( d );
std::vector<ObjectHolder*> ret;
ret.push_back( new ObjectHolder( prop ) );
return ret;
}
void MidPointOfTwoPointsConstructor::plug( KigPart*, KigGUIAction* )
{
}
bool MidPointOfTwoPointsConstructor::isTransform() const
{
return false;
}
TestConstructor::TestConstructor( const ArgsParserObjectType* type, const char* descname,
const char* desc, const char* iconfile )
: StandardConstructorBase( descname, desc, iconfile, type->argsParser() ),
mtype( type )
{
}
TestConstructor::~TestConstructor()
{
}
void TestConstructor::drawprelim( const ObjectDrawer&, KigPainter&, const std::vector<ObjectCalcer*>&,
const KigDocument& ) const
{
// not used, only here because of the wrong
// ObjectConstructor-GUIAction design. See the TODO
}
std::vector<ObjectHolder*> TestConstructor::build( const std::vector<ObjectCalcer*>&, KigDocument&,
KigWidget& ) const
{
// not used, only here because of the wrong
// ObjectConstructor-GUIAction design. See the TODO
std::vector<ObjectHolder*> ret;
return ret;
}
void TestConstructor::plug( KigPart*, KigGUIAction* )
{
}
bool TestConstructor::isTransform() const
{
return false;
}
bool TestConstructor::isTest() const
{
return true;
}
BaseConstructMode* TestConstructor::constructMode( KigPart& doc )
{
return new TestConstructMode( doc, mtype );
}
const int TestConstructor::wantArgs( const std::vector<ObjectCalcer*>& os,
const KigDocument& d, const KigWidget& v ) const
{
int ret = StandardConstructorBase::wantArgs( os, d, v );
if ( ret == ArgsParser::Complete ) ret = ArgsParser::Valid;
return ret;
}
TQString GenericIntersectionConstructor::selectStatement(
const std::vector<ObjectCalcer*>& sel, const KigDocument&,
const KigWidget& ) const
{
if ( sel.size() == 0 )
return i18n( "Select the first object to intersect..." );
else
return i18n( "Select the second object to intersect..." );
}
TangentConstructor::TangentConstructor()
: MergeObjectConstructor(
I18N_NOOP( "Tangent" ),
I18N_NOOP( "The line tangent to a curve" ),
"tangent" )
{
SimpleObjectTypeConstructor* conic =
new SimpleObjectTypeConstructor(
TangentConicType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"tangentconic" );
SimpleObjectTypeConstructor* arc =
new SimpleObjectTypeConstructor(
TangentArcType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"tangentarc" );
SimpleObjectTypeConstructor* cubic =
new SimpleObjectTypeConstructor(
TangentCubicType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"tangentcubic" );
SimpleObjectTypeConstructor* curve =
new SimpleObjectTypeConstructor(
TangentCurveType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"tangentcurve" );
merge( conic );
merge( arc );
merge( cubic );
merge( curve );
}
TangentConstructor::~TangentConstructor()
{
}
TQString TangentConstructor::useText(
const ObjectCalcer& o, const std::vector<ObjectCalcer*>&,
const KigDocument&, const KigWidget& ) const
{
if ( o.imp()->inherits( CircleImp::stype() ) )
return i18n( "Tangent to This Circle" );
else if ( o.imp()->inherits( ConicImp::stype() ) )
return i18n( "Tangent to This Conic" );
else if ( o.imp()->inherits( ArcImp::stype() ) )
return i18n( "Tangent to This Arc" );
else if ( o.imp()->inherits( CubicImp::stype() ) )
return i18n( "Tangent to This Cubic Curve" );
else if ( o.imp()->inherits( CurveImp::stype() ) )
return i18n( "Tangent to This Curve" );
else if ( o.imp()->inherits( PointImp::stype() ) )
return i18n( "Tangent at This Point" );
// else assert( false );
return TQString();
}
//TQString TangentConstructor::selectStatement(
// const std::vector<ObjectCalcer*>& sel, const KigDocument&,
// const KigWidget& ) const
//{
// if ( sel.size() == 0 )
// return i18n( "Select the object..." );
// else
// return i18n( "Select the point for the tangent to go through..." );
//}
/*
* center of curvature of a curve
*/
CocConstructor::CocConstructor()
: MergeObjectConstructor(
I18N_NOOP( "Center Of Curvature" ),
I18N_NOOP( "The center of the osculating circle to a curve" ),
"centerofcurvature" )
{
SimpleObjectTypeConstructor* conic =
new SimpleObjectTypeConstructor(
CocConicType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"cocconic" );
SimpleObjectTypeConstructor* cubic =
new SimpleObjectTypeConstructor(
CocCubicType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"coccubic" );
SimpleObjectTypeConstructor* curve =
new SimpleObjectTypeConstructor(
CocCurveType::instance(),
"SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
"coccurve" );
merge( conic );
merge( cubic );
merge( curve );
}
CocConstructor::~CocConstructor()
{
}
TQString CocConstructor::useText(
const ObjectCalcer& o, const std::vector<ObjectCalcer*>&,
const KigDocument&, const KigWidget& ) const
{
if ( o.imp()->inherits( ConicImp::stype() ) )
return i18n( "Center of Curvature of This Conic" );
else if ( o.imp()->inherits( CubicImp::stype() ) )
return i18n( "Center of Curvature of This Cubic Curve" );
else if ( o.imp()->inherits( CurveImp::stype() ) )
return i18n( "Center of Curvature of This Curve" );
else if ( o.imp()->inherits( PointImp::stype() ) )
return i18n( "Center of Curvature at This Point" );
return TQString();
}
bool relativePrimes( int n, int p )
{
if ( p > n ) return relativePrimes( p, n );
assert ( p >= 0 );
if ( p == 0 ) return false;
if ( p == 1 ) return true;
int d = int( n/p );
return relativePrimes( p, n-d*p );
}
//TQString CocConstructor::selectStatement(
// const std::vector<ObjectCalcer*>& sel, const KigDocument&,
// const KigWidget& ) const
//{
// if ( sel.size() == 0 )
// return i18n( "Select the object..." );
// else
// return i18n( "Select the point where to compute the center of curvature..." );
//}