summaryrefslogtreecommitdiffstats
path: root/kig/objects
diff options
context:
space:
mode:
Diffstat (limited to 'kig/objects')
-rw-r--r--kig/objects/Makefile.am81
-rw-r--r--kig/objects/angle_type.cc208
-rw-r--r--kig/objects/angle_type.h50
-rw-r--r--kig/objects/arc_type.cc199
-rw-r--r--kig/objects/arc_type.h64
-rw-r--r--kig/objects/base_type.cc112
-rw-r--r--kig/objects/base_type.h57
-rw-r--r--kig/objects/bogus_imp.cc388
-rw-r--r--kig/objects/bogus_imp.h281
-rw-r--r--kig/objects/centerofcurvature_type.cc304
-rw-r--r--kig/objects/centerofcurvature_type.h68
-rw-r--r--kig/objects/circle_imp.cc356
-rw-r--r--kig/objects/circle_imp.h125
-rw-r--r--kig/objects/circle_type.cc181
-rw-r--r--kig/objects/circle_type.h69
-rw-r--r--kig/objects/common.cc43
-rw-r--r--kig/objects/common.h107
-rw-r--r--kig/objects/conic_imp.cc385
-rw-r--r--kig/objects/conic_imp.h157
-rw-r--r--kig/objects/conic_types.cc689
-rw-r--r--kig/objects/conic_types.h184
-rw-r--r--kig/objects/cubic_imp.cc437
-rw-r--r--kig/objects/cubic_imp.h81
-rw-r--r--kig/objects/cubic_type.cc185
-rw-r--r--kig/objects/cubic_type.h56
-rw-r--r--kig/objects/curve_imp.cc41
-rw-r--r--kig/objects/curve_imp.h62
-rw-r--r--kig/objects/intersection_types.cc338
-rw-r--r--kig/objects/intersection_types.h105
-rw-r--r--kig/objects/inversion_type.cc412
-rw-r--r--kig/objects/inversion_type.h86
-rw-r--r--kig/objects/line_imp.cc571
-rw-r--r--kig/objects/line_imp.h215
-rw-r--r--kig/objects/line_type.cc334
-rw-r--r--kig/objects/line_type.h110
-rw-r--r--kig/objects/locus_imp.cc397
-rw-r--r--kig/objects/locus_imp.h96
-rw-r--r--kig/objects/object_calcer.cc323
-rw-r--r--kig/objects/object_calcer.h301
-rw-r--r--kig/objects/object_drawer.cc204
-rw-r--r--kig/objects/object_drawer.h146
-rw-r--r--kig/objects/object_factory.cc369
-rw-r--r--kig/objects/object_factory.h145
-rw-r--r--kig/objects/object_holder.cc164
-rw-r--r--kig/objects/object_holder.h145
-rw-r--r--kig/objects/object_imp.cc308
-rw-r--r--kig/objects/object_imp.h360
-rw-r--r--kig/objects/object_imp_factory.cc510
-rw-r--r--kig/objects/object_imp_factory.h40
-rw-r--r--kig/objects/object_type.cc125
-rw-r--r--kig/objects/object_type.h130
-rw-r--r--kig/objects/object_type_factory.cc148
-rw-r--r--kig/objects/object_type_factory.h40
-rw-r--r--kig/objects/other_imp.cc710
-rw-r--r--kig/objects/other_imp.h243
-rw-r--r--kig/objects/other_type.cc189
-rw-r--r--kig/objects/other_type.h61
-rw-r--r--kig/objects/point_imp.cc223
-rw-r--r--kig/objects/point_imp.h91
-rw-r--r--kig/objects/point_type.cc665
-rw-r--r--kig/objects/point_type.h159
-rw-r--r--kig/objects/polygon_imp.cc550
-rw-r--r--kig/objects/polygon_imp.h94
-rw-r--r--kig/objects/polygon_type.cc669
-rw-r--r--kig/objects/polygon_type.h139
-rw-r--r--kig/objects/special_calcers.cc84
-rw-r--r--kig/objects/special_calcers.h38
-rw-r--r--kig/objects/tangent_type.cc285
-rw-r--r--kig/objects/tangent_type.h83
-rw-r--r--kig/objects/tests_type.cc382
-rw-r--r--kig/objects/tests_type.h111
-rw-r--r--kig/objects/text_imp.cc173
-rw-r--r--kig/objects/text_imp.h70
-rw-r--r--kig/objects/text_type.cc215
-rw-r--r--kig/objects/text_type.h55
-rw-r--r--kig/objects/transform_types.cc874
-rw-r--r--kig/objects/transform_types.h243
-rw-r--r--kig/objects/vector_type.cc100
-rw-r--r--kig/objects/vector_type.h45
79 files changed, 17643 insertions, 0 deletions
diff --git a/kig/objects/Makefile.am b/kig/objects/Makefile.am
new file mode 100644
index 00000000..21a02c6f
--- /dev/null
+++ b/kig/objects/Makefile.am
@@ -0,0 +1,81 @@
+INCLUDES=$(all_includes)
+noinst_LTLIBRARIES=libobjects.la
+noinst_HEADERS=\
+ angle_type.h \
+ arc_type.h \
+ base_type.h \
+ bogus_imp.h \
+ circle_imp.h \
+ circle_type.h \
+ polygon_type.h \
+ common.h \
+ conic_imp.h \
+ conic_types.h \
+ cubic_imp.h \
+ cubic_type.h \
+ curve_imp.h \
+ intersection_types.h \
+ inversion_type.h \
+ line_imp.h \
+ line_type.h \
+ locus_imp.h \
+ object_calcer.h \
+ object_drawer.h \
+ object_factory.h \
+ object_holder.h \
+ object_imp.h \
+ object_imp_factory.h \
+ object_type.h \
+ object_type_factory.h \
+ other_imp.h \
+ other_type.h \
+ point_imp.h \
+ polygon_imp.h \
+ tangent_type.h \
+ centerofcurvature_type.h \
+ tests_type.h \
+ text_imp.h \
+ text_type.h \
+ transform_types.h \
+ vector_type.h
+libobjects_la_SOURCES=\
+ angle_type.cc \
+ arc_type.cc \
+ base_type.cc \
+ bogus_imp.cc \
+ circle_imp.cc \
+ circle_type.cc \
+ polygon_type.cc \
+ common.cc \
+ conic_imp.cc \
+ conic_types.cc \
+ cubic_imp.cc \
+ cubic_type.cc \
+ curve_imp.cc \
+ intersection_types.cc \
+ inversion_type.cc \
+ line_imp.cc \
+ line_type.cc \
+ locus_imp.cc \
+ object_calcer.cc \
+ object_drawer.cc \
+ object_factory.cc \
+ object_holder.cc \
+ object_imp.cc \
+ object_imp_factory.cc \
+ object_type.cc \
+ object_type_factory.cc \
+ other_imp.cc \
+ other_type.cc \
+ point_imp.cc \
+ point_type.cc \
+ polygon_imp.cc \
+ tangent_type.cc \
+ centerofcurvature_type.cc \
+ tests_type.cc \
+ text_imp.cc \
+ text_type.cc \
+ transform_types.cc \
+ vector_type.cc
+libobjects_la_LIBADD=-lm
+METASOURCES=AUTO
diff --git a/kig/objects/angle_type.cc b/kig/objects/angle_type.cc
new file mode 100644
index 00000000..89a17131
--- /dev/null
+++ b/kig/objects/angle_type.cc
@@ -0,0 +1,208 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// 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 "angle_type.h"
+
+#include "bogus_imp.h"
+#include "other_imp.h"
+#include "point_imp.h"
+#include "../misc/calcpaths.h"
+#include "../misc/common.h"
+#include "../misc/goniometry.h"
+#include "../misc/kiginputdialog.h"
+#include "../kig/kig_commands.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+
+#include <functional>
+#include <algorithm>
+#include <cmath>
+
+#include <qstringlist.h>
+
+static const char* constructanglethroughpoint =
+ I18N_NOOP( "Construct an angle through this point" );
+
+static const ArgsParser::spec argsspecAngle[] =
+{
+ { PointImp::stype(), constructanglethroughpoint,
+ I18N_NOOP( "Select a point that the first half-line of the angle should go through..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct an angle at this point" ),
+ I18N_NOOP( "Select the point to construct the angle in..." ), true },
+ { PointImp::stype(), constructanglethroughpoint,
+ I18N_NOOP( "Select a point that the second half-line of the angle should go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( AngleType )
+
+AngleType::AngleType()
+ : ArgsParserObjectType( "Angle", argsspecAngle, 3 )
+{
+}
+
+AngleType::~AngleType()
+{
+}
+
+const AngleType* AngleType::instance()
+{
+ static const AngleType t;
+ return &t;
+}
+
+ObjectImp* AngleType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> points;
+ for ( uint i = 0; i < parents.size(); ++i )
+ points.push_back(
+ static_cast<const PointImp*>( parents[i] )->coordinate() );
+
+ Coordinate lvect = points[0] - points[1];
+ Coordinate rvect;
+ if ( points.size() == 3 )
+ rvect = points[2] - points[1];
+ else
+ {
+ rvect = lvect.orthogonal();
+ }
+
+ double startangle = atan2( lvect.y, lvect.x );
+ double endangle = atan2( rvect.y, rvect.x );
+ double anglelength = endangle - startangle;
+ if ( anglelength < 0 ) anglelength += 2* M_PI;
+ if ( startangle < 0 ) startangle += 2*M_PI;
+
+ return new AngleImp( points[1], startangle, anglelength );
+}
+
+const ObjectImpType* AngleType::resultId() const
+{
+ return AngleImp::stype();
+}
+
+QStringList AngleType::specialActions() const
+{
+ QStringList ret;
+ ret << i18n( "Set Si&ze" );
+ return ret;
+}
+
+void AngleType::executeAction(
+ int i, ObjectHolder&, ObjectTypeCalcer& t,
+ KigPart& d, KigWidget& w, NormalMode& ) const
+{
+ assert( i == 0 );
+ // pretend to use this var..
+ (void) i;
+
+ std::vector<ObjectCalcer*> parents = t.parents();
+
+ assert( margsparser.checkArgs( parents ) );
+
+ Coordinate a = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ Coordinate b = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
+ Coordinate c = static_cast<const PointImp*>( parents[2]->imp() )->coordinate();
+
+ Coordinate lvect = a - b;
+ Coordinate rvect = c - b;
+
+ double startangle = atan2( lvect.y, lvect.x );
+ double endangle = atan2( rvect.y, rvect.x );
+ double anglelength = endangle - startangle;
+ if ( anglelength < 0 ) anglelength += 2* M_PI;
+ if ( startangle < 0 ) startangle += 2*M_PI;
+
+ Goniometry go( anglelength, Goniometry::Rad );
+ go.convertTo( Goniometry::Deg );
+
+ bool ok;
+ Goniometry newsize = KigInputDialog::getAngle( &w, &ok, go );
+ if ( !ok )
+ return;
+ newsize.convertTo( Goniometry::Rad );
+
+ double newcangle = startangle + newsize.value();
+ Coordinate cdir( cos( newcangle ), sin( newcangle ) );
+ Coordinate nc = b + cdir.normalize( rvect.length() );
+
+ MonitorDataObjects mon( getAllParents( parents ) );
+ parents[2]->move( nc, d.document() );
+ KigCommand* kc = new KigCommand( d, i18n( "Resize Angle" ) );
+ mon.finish( kc );
+ d.history()->addCommand( kc );
+}
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( HalfAngleType )
+
+HalfAngleType::HalfAngleType()
+ : ArgsParserObjectType( "HalfAngle", argsspecAngle, 3 )
+{
+}
+
+HalfAngleType::~HalfAngleType()
+{
+}
+
+const HalfAngleType* HalfAngleType::instance()
+{
+ static const HalfAngleType t;
+ return &t;
+}
+
+ObjectImp* HalfAngleType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> points;
+ for ( uint i = 0; i < parents.size(); ++i )
+ points.push_back(
+ static_cast<const PointImp*>( parents[i] )->coordinate() );
+
+ Coordinate lvect = points[0] - points[1];
+ Coordinate rvect;
+ if ( points.size() == 3 )
+ rvect = points[2] - points[1];
+ else
+ {
+ rvect = lvect.orthogonal();
+ }
+
+ double startangle = atan2( lvect.y, lvect.x );
+ double endangle = atan2( rvect.y, rvect.x );
+ double anglelength = endangle - startangle;
+ if ( anglelength < 0 ) anglelength += 2 * M_PI;
+ if ( startangle < 0 ) startangle += 2 * M_PI;
+
+ if ( anglelength > M_PI )
+ {
+ startangle += anglelength;
+ anglelength = 2 * M_PI - anglelength;
+ if ( startangle > 2 * M_PI ) startangle -= 2 * M_PI;
+ if ( anglelength < 0 ) anglelength += 2 * M_PI;
+ }
+
+ return new AngleImp( points[1], startangle, anglelength );
+}
+
+const ObjectImpType* HalfAngleType::resultId() const
+{
+ return AngleImp::stype();
+}
+
diff --git a/kig/objects/angle_type.h b/kig/objects/angle_type.h
new file mode 100644
index 00000000..796143b4
--- /dev/null
+++ b/kig/objects/angle_type.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2003-2004 Dominique Devriese <devriese@kde.org>
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// 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.
+
+#ifndef KIG_MISC_ANGLE_TYPE_H
+#define KIG_MISC_ANGLE_TYPE_H
+
+#include "base_type.h"
+
+class AngleType
+ : public ArgsParserObjectType
+{
+ AngleType();
+ ~AngleType();
+public:
+ static const AngleType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ QStringList specialActions() const;
+ void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& c,
+ KigPart& d, KigWidget& w, NormalMode& m ) const;
+};
+
+class HalfAngleType
+ : public ArgsParserObjectType
+{
+ HalfAngleType();
+ ~HalfAngleType();
+public:
+ static const HalfAngleType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/arc_type.cc b/kig/objects/arc_type.cc
new file mode 100644
index 00000000..f6c660f2
--- /dev/null
+++ b/kig/objects/arc_type.cc
@@ -0,0 +1,199 @@
+// Copyright (C) 2003-2004 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 "arc_type.h"
+
+#include "bogus_imp.h"
+#include "other_imp.h"
+#include "point_imp.h"
+#include "line_imp.h"
+#include "locus_imp.h"
+
+#include "../misc/common.h"
+#include "../misc/calcpaths.h"
+#include "../misc/goniometry.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../kig/kig_commands.h"
+
+#include <functional>
+#include <algorithm>
+#include <cmath>
+
+using std::find;
+
+#include <qstringlist.h>
+
+static const char constructarcstartingstat[] = I18N_NOOP( "Construct an arc starting at this point" );
+
+static const ArgsParser::spec argsspecArcBTP[] =
+{
+ { PointImp::stype(), constructarcstartingstat,
+ I18N_NOOP( "Select the start point of the new arc..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct an arc through this point" ),
+ I18N_NOOP( "Select a point for the new arc to go through..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct an arc ending at this point" ),
+ I18N_NOOP( "Select the end point of the new arc..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ArcBTPType )
+
+ArcBTPType::ArcBTPType()
+ : ArgsParserObjectType( "ArcBTP", argsspecArcBTP, 3 )
+{
+}
+
+ArcBTPType::~ArcBTPType()
+{
+}
+
+const ArcBTPType* ArcBTPType::instance()
+{
+ static const ArcBTPType t;
+ return &t;
+}
+
+ObjectImp* ArcBTPType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args, 2 ) )
+ return new InvalidImp;
+
+ const Coordinate a =
+ static_cast<const PointImp*>( args[0] )->coordinate();
+ const Coordinate b =
+ static_cast<const PointImp*>( args[1] )->coordinate();
+ Coordinate center;
+ double angle = 0.;
+ double startangle = 0.;
+ if ( args.size() == 3 )
+ {
+ Coordinate c = static_cast<const PointImp*>( args[2] )->coordinate();
+ center = calcCenter( a, b, c );
+ if ( ! center.valid() ) return new InvalidImp;
+ Coordinate ad = a - center;
+ Coordinate bd = b - center;
+ Coordinate cd = c - center;
+ double anglea = atan2( ad.y, ad.x );
+ double angleb = atan2( bd.y, bd.x );
+ double anglec = atan2( cd.y, cd.x );
+
+ // anglea should be smaller than anglec
+ if ( anglea > anglec )
+ {
+ double t = anglea;
+ anglea = anglec;
+ anglec = t;
+ };
+ if ( angleb > anglec || angleb < anglea )
+ {
+ startangle = anglec;
+ angle = 2 * M_PI + anglea - startangle;
+ }
+ else
+ {
+ startangle = anglea;
+ angle = anglec - anglea;
+ };
+ }
+ else
+ {
+ // find a center and angles that look natural..
+ center = (b+a)/2 + .6*(b-a).orthogonal();
+ Coordinate bd = b - center;
+ Coordinate ad = a - center;
+ startangle = atan2( ad.y, ad.x );
+ double halfangle = atan2( bd.y, bd.x ) - startangle;
+ if ( halfangle < - M_PI ) halfangle += 2*M_PI;
+ angle = 2 * halfangle;
+ };
+
+ double radius = ( a - center ).length();
+ return new ArcImp( center, radius, startangle, angle );
+}
+
+const ObjectImpType* ArcBTPType::impRequirement( const ObjectImp*, const Args& ) const
+{
+ return PointImp::stype();
+}
+
+bool ArcBTPType::inherits( int type ) const
+{
+ return Parent::inherits( type );
+}
+
+const ObjectImpType* ArcBTPType::resultId() const
+{
+ return ArcImp::stype();
+}
+
+static const ArgsParser::spec argsspecArcBCPA[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Construct an arc with this center" ),
+ I18N_NOOP( "Select the center of the new arc..." ), true },
+ { PointImp::stype(), constructarcstartingstat,
+ I18N_NOOP( "Select the start point of the new arc..." ), true },
+ { AngleImp::stype(), I18N_NOOP( "Construct an arc with this angle" ),
+ I18N_NOOP( "Select the angle of the new arc..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ArcBCPAType )
+
+ArcBCPAType::ArcBCPAType()
+ : ArgsParserObjectType( "ArcBCPA", argsspecArcBCPA, 3 )
+{
+}
+
+ArcBCPAType::~ArcBCPAType()
+{
+}
+
+const ArcBCPAType* ArcBCPAType::instance()
+{
+ static const ArcBCPAType t;
+ return &t;
+}
+
+ObjectImp* ArcBCPAType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const Coordinate center = static_cast<const PointImp*>( args[0] )->coordinate();
+ const Coordinate p = static_cast<const PointImp*>( args[1] )->coordinate();
+ const AngleImp* a = static_cast<const AngleImp*>( args[2] );
+ const double angle = a->angle();
+ const Coordinate dir = p - center;
+ const double startangle = atan2( dir.y, dir.x );
+ const double radius = center.distance( p );
+
+ return new ArcImp( center, radius, startangle, angle );
+}
+
+const ObjectImpType* ArcBCPAType::impRequirement( const ObjectImp*, const Args& ) const
+{
+ return PointImp::stype();
+}
+
+bool ArcBCPAType::inherits( int type ) const
+{
+ return Parent::inherits( type );
+}
+
+const ObjectImpType* ArcBCPAType::resultId() const
+{
+ return ArcImp::stype();
+}
diff --git a/kig/objects/arc_type.h b/kig/objects/arc_type.h
new file mode 100644
index 00000000..cdfe0294
--- /dev/null
+++ b/kig/objects/arc_type.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2003-2004 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.
+
+#ifndef KIG_OBJECTS_ARC_TYPE_H
+#define KIG_OBJECTS_ARC_TYPE_H
+
+#include "base_type.h"
+#include "../misc/object_hierarchy.h"
+
+/**
+ * an arc by a start point, an intermediate point and an end point
+ */
+class ArcBTPType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ ArcBTPType();
+ ~ArcBTPType();
+public:
+ static const ArcBTPType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+
+ bool inherits( int type ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * an arc by a point (center), a starting point and an angle
+ */
+class ArcBCPAType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ ArcBCPAType();
+ ~ArcBCPAType();
+public:
+ static const ArcBCPAType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+
+ bool inherits( int type ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/base_type.cc b/kig/objects/base_type.cc
new file mode 100644
index 00000000..0f8eecec
--- /dev/null
+++ b/kig/objects/base_type.cc
@@ -0,0 +1,112 @@
+// 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 "base_type.h"
+
+#include "point_imp.h"
+#include "line_imp.h"
+#include "bogus_imp.h"
+#include "object_calcer.h"
+
+#include "../misc/common.h"
+
+ObjectABType::ObjectABType( const char* fulltypename, const ArgsParser::spec* spec, int n )
+ : ArgsParserObjectType( fulltypename, spec, n )
+{
+}
+
+ObjectABType::~ObjectABType()
+{
+}
+
+ObjectImp* ObjectABType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) )
+ return new InvalidImp;
+
+ Coordinate a = static_cast<const PointImp*>( parents[0] )->coordinate();
+ Coordinate b = static_cast<const PointImp*>( parents[1] )->coordinate();
+
+ return calc( a, b );
+}
+
+bool ObjectABType::canMove( const ObjectTypeCalcer& o ) const
+{
+ return isFreelyTranslatable( o );
+/*
+ * as observed by domi: this object is actually movable also
+ * if one point is FreelyTranslatable and the other is
+ * only movable, but then the "move" itself requires some
+ * trickery.
+ */
+}
+
+bool ObjectABType::isFreelyTranslatable( const ObjectTypeCalcer& o ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ return parents[0]->isFreelyTranslatable() && parents[1]->isFreelyTranslatable();
+}
+
+void ObjectABType::move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ assert( margsparser.checkArgs( parents ) );
+ const Coordinate a = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ const Coordinate b = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
+ const Coordinate dist = b - a;
+ if ( parents[0]->canMove() )
+ parents[0]->move( to, d );
+ if ( parents[1]->canMove() )
+ parents[1]->move( to + dist, d );
+}
+
+ObjectLPType::ObjectLPType( const char* fullname, const ArgsParser::spec* spec, int n )
+ : ArgsParserObjectType( fullname, spec, n )
+{
+}
+
+ObjectLPType::~ObjectLPType()
+{
+}
+
+ObjectImp* ObjectLPType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+ LineData l = static_cast<const AbstractLineImp*>( args[0] )->data();
+ Coordinate c = static_cast<const PointImp*>( args[1] )->coordinate();
+ return calc( l, c );
+}
+
+const Coordinate ObjectABType::moveReferencePoint( const ObjectTypeCalcer& o ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ assert( margsparser.checkArgs( parents ) );
+ return static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+}
+
+std::vector<ObjectCalcer*> ObjectABType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ std::vector<ObjectCalcer*> parents = ourobj.parents();
+ std::set<ObjectCalcer*> ret;
+ std::vector<ObjectCalcer*> tmp = parents[0]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ tmp = parents[1]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ ret.insert( parents.begin(), parents.end() );
+ return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
+}
diff --git a/kig/objects/base_type.h b/kig/objects/base_type.h
new file mode 100644
index 00000000..ff9c1983
--- /dev/null
+++ b/kig/objects/base_type.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef KIG_OBJECTS_BASE_TYPE_H
+#define KIG_OBJECTS_BASE_TYPE_H
+
+#include "object_type.h"
+
+#include "../misc/argsparser.h"
+
+class LineData;
+
+class ObjectABType
+ : public ArgsParserObjectType
+{
+protected:
+ ObjectABType( const char* fulltypename, const ArgsParser::spec* argsspec, int n );
+ ~ObjectABType();
+public:
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ bool canMove( const ObjectTypeCalcer& o ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& o ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& o ) const;
+
+ virtual ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const = 0;
+};
+
+class ObjectLPType
+ : public ArgsParserObjectType
+{
+protected:
+ ObjectLPType( const char* fullname, const ArgsParser::spec* spec, int n );
+ ~ObjectLPType();
+public:
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+
+ virtual ObjectImp* calc( const LineData& a, const Coordinate& b ) const = 0;
+};
+
+#endif
diff --git a/kig/objects/bogus_imp.cc b/kig/objects/bogus_imp.cc
new file mode 100644
index 00000000..c1ed6526
--- /dev/null
+++ b/kig/objects/bogus_imp.cc
@@ -0,0 +1,388 @@
+// Copyright (C) 2002 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 "bogus_imp.h"
+
+#include <qcstring.h>
+#include <qstringlist.h>
+#include <klocale.h>
+
+#include "../misc/rect.h"
+
+Coordinate BogusImp::attachPoint( ) const
+{
+ return Coordinate::invalidCoord();
+}
+
+void BogusImp::draw( KigPainter& ) const
+{
+}
+
+bool BogusImp::contains( const Coordinate&, int, const KigWidget& ) const
+{
+ return false;
+}
+
+bool BogusImp::inRect( const Rect&, int, const KigWidget& ) const
+{
+ return false;
+}
+
+DoubleImp::DoubleImp( const double d )
+ : mdata( d )
+{
+}
+
+IntImp::IntImp( const int d )
+ : mdata( d )
+{
+}
+
+StringImp::StringImp( const QString& d )
+ : mdata( d )
+{
+}
+
+DoubleImp* DoubleImp::copy() const
+{
+ return new DoubleImp( mdata );
+}
+
+IntImp* IntImp::copy() const
+{
+ return new IntImp( mdata );
+}
+
+StringImp* StringImp::copy() const
+{
+ return new StringImp( mdata );
+}
+
+ObjectImp* BogusImp::transform( const Transformation& ) const
+{
+ return copy();
+}
+
+InvalidImp* InvalidImp::copy() const
+{
+ return new InvalidImp();
+}
+
+InvalidImp::InvalidImp()
+{
+}
+
+void InvalidImp::fillInNextEscape( QString& s, const KigDocument& ) const
+{
+ s = s.arg( "[invalid]" );
+}
+
+void DoubleImp::fillInNextEscape( QString& s, const KigDocument& ) const
+{
+ s = s.arg( mdata );
+}
+
+void IntImp::fillInNextEscape( QString& s, const KigDocument& ) const
+{
+ s = s.arg( mdata );
+}
+
+void StringImp::fillInNextEscape( QString& s, const KigDocument& ) const
+{
+ s = s.arg( mdata );
+}
+
+HierarchyImp::HierarchyImp( const ObjectHierarchy& h )
+ : BogusImp(), mdata( h )
+{
+}
+
+HierarchyImp* HierarchyImp::copy() const
+{
+ return new HierarchyImp( mdata );
+}
+
+void InvalidImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void DoubleImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void IntImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void StringImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void HierarchyImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+TransformationImp::TransformationImp( const Transformation& h )
+ : mdata( h )
+{
+}
+
+TransformationImp* TransformationImp::copy() const
+{
+ return new TransformationImp( mdata );
+}
+
+void TransformationImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool InvalidImp::equals( const ObjectImp& rhs ) const
+{
+ return !rhs.valid();
+}
+
+bool DoubleImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( DoubleImp::stype() ) &&
+ static_cast<const DoubleImp&>( rhs ).data() == mdata;
+}
+
+bool IntImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( IntImp::stype() ) &&
+ static_cast<const IntImp&>( rhs ).data() == mdata;
+}
+
+bool StringImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( StringImp::stype() ) &&
+ static_cast<const StringImp&>( rhs ).data() == mdata;
+}
+
+bool HierarchyImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( HierarchyImp::stype() ) &&
+ static_cast<const HierarchyImp&>( rhs ).data() == mdata;
+}
+
+bool TransformationImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( TransformationImp::stype() ) &&
+ static_cast<const TransformationImp&>( rhs ).data() == mdata;
+}
+
+bool InvalidImp::canFillInNextEscape() const
+{
+ return true;
+}
+
+bool DoubleImp::canFillInNextEscape() const
+{
+ return true;
+}
+
+bool IntImp::canFillInNextEscape() const
+{
+ return true;
+}
+
+bool StringImp::canFillInNextEscape() const
+{
+ return true;
+}
+
+const ObjectImpType* InvalidImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "invalid", "", "", "", "", "", "", "", "", "" );
+ return &t;
+}
+
+const ObjectImpType* StringImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "string",
+ "string", "", "", "", "", "", "", "", "" );
+ return &t;
+}
+const ObjectImpType* HierarchyImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "hierarchy", "", "", "", "", "", "", "", "", "" );
+ return &t;
+}
+const ObjectImpType* TransformationImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "transformation", "", "", "", "", "", "", "", "", "");
+ return &t;
+}
+
+const ObjectImpType* InvalidImp::type() const
+{
+ return InvalidImp::stype();
+}
+
+const ObjectImpType* DoubleImp::type() const
+{
+ return DoubleImp::stype();
+}
+
+const ObjectImpType* IntImp::type() const
+{
+ return IntImp::stype();
+}
+
+const ObjectImpType* StringImp::type() const
+{
+ return StringImp::stype();
+}
+
+const ObjectImpType* HierarchyImp::type() const
+{
+ return HierarchyImp::stype();
+}
+
+const ObjectImpType* TransformationImp::type() const
+{
+ return TransformationImp::stype();
+}
+
+const ObjectImpType* DoubleImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "double",
+ "double", "", "", "", "", "", "", "", "" );
+ return &t;
+}
+
+const ObjectImpType* IntImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "int",
+ "int", "", "", "", "", "", "", "", "" );
+ return &t;
+}
+
+const ObjectImpType* BogusImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "bogus",
+ "", "", "", "", "", "", "", "", "" );
+ return &t;
+}
+
+const ObjectImpType* TestResultImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "testresult", "", "", "", "", "", "", "", "", "" );
+ return &t;
+
+}
+
+TestResultImp::TestResultImp( const QString& s )
+ : mdata( s )
+{
+}
+
+TestResultImp* TestResultImp::copy() const
+{
+ return new TestResultImp( mdata );
+}
+
+const ObjectImpType* TestResultImp::type() const
+{
+ return stype();
+}
+
+void TestResultImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool TestResultImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( TestResultImp::stype() ) &&
+ static_cast<const TestResultImp&>( rhs ).mdata == mdata;
+
+}
+
+const uint TestResultImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 1;
+}
+
+const QCStringList TestResultImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Test Result" );
+ assert( l.size() == TestResultImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList TestResultImp::propertiesInternalNames() const
+{
+ QCStringList s = Parent::propertiesInternalNames();
+ s << "test-result";
+ assert( s.size() == TestResultImp::numberOfProperties() );
+ return s;
+}
+
+ObjectImp* TestResultImp::property( uint which, const KigDocument& d ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, d );
+ if ( which == Parent::numberOfProperties() )
+ return new StringImp( data() );
+ else assert( false );
+ return new InvalidImp;
+}
+
+const char* TestResultImp::iconForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() )
+ return ""; // test-result
+ else assert( false );
+ return "";
+}
+
+const ObjectImpType* TestResultImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return TestResultImp::stype();
+}
+
+bool TestResultImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return false;
+}
+
+Rect BogusImp::surroundingRect() const
+{
+ return Rect::invalidRect();
+}
diff --git a/kig/objects/bogus_imp.h b/kig/objects/bogus_imp.h
new file mode 100644
index 00000000..8e9386a8
--- /dev/null
+++ b/kig/objects/bogus_imp.h
@@ -0,0 +1,281 @@
+// Copyright (C) 2002 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.
+
+#ifndef BOGUS_IMP_H
+#define BOGUS_IMP_H
+
+#include "object_imp.h"
+#include "../misc/object_hierarchy.h"
+#include "../misc/kigtransform.h"
+
+#include <qstring.h>
+
+/**
+ * This is the base class for the so-called BogusImp's. These
+ * ObjectImp's are not really ObjectImp's, in that they don't
+ * represent objects. They exist because ObjectImp's also serve
+ * another purpose, namely containing data. They can all be loaded
+ * and saved, and the only difference between these objects and normal
+ * objects are that these serve *only* to be loaded and saved. This
+ * approach adds a lot of flexibility to the Kig system, and has
+ * certainly proven itself very valuable.
+ */
+class BogusImp
+ : public ObjectImp
+{
+ typedef ObjectImp Parent;
+public:
+ /**
+ * Returns the ObjectImpType representing the BogusImp type.
+ */
+ static const ObjectImpType* stype();
+
+ Coordinate attachPoint( ) const;
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& w ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& w ) const;
+ Rect surroundingRect() const;
+
+ ObjectImp* transform( const Transformation& ) const;
+};
+
+/**
+ * This ObjectImp represents an invalid object. If a calculation
+ * fails, then often an InvalidImp is returned, indicating that the
+ * generated object is invalid.
+ */
+class InvalidImp
+ : public BogusImp
+{
+public:
+ /**
+ * Returns the ObjectImpType representing the InvalidImp type.
+ */
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ /**
+ * Construct a new InvalidImp.
+ */
+ InvalidImp();
+ InvalidImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool canFillInNextEscape() const;
+ void fillInNextEscape( QString& s, const KigDocument& ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+/**
+ * This ObjectImp is a BogusImp containing only a double value.
+ */
+class DoubleImp
+ : public BogusImp
+{
+ double mdata;
+public:
+ /**
+ * Returns the ObjectImpType representing the DoubleImp type.
+ */
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ /**
+ * Construct a new DoubleImp containing the value d.
+ */
+ DoubleImp( const double d );
+
+ /**
+ * Get hold of the contained data.
+ */
+ double data() const { return mdata; }
+ /**
+ * Set the contained data to d.
+ */
+ void setData( double d ) { mdata = d; }
+
+ DoubleImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool canFillInNextEscape() const;
+ void fillInNextEscape( QString& s, const KigDocument& ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+/**
+ * This ObjectImp is a BogusImp containing only an int value.
+ */
+class IntImp
+ : public BogusImp
+{
+ int mdata;
+public:
+ /**
+ * Returns the ObjectImpType representing the IntImp type..
+ */
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ /**
+ * Construct a new IntImp containing the value d.
+ */
+ IntImp( const int d );
+
+ /**
+ * Get hold of the contained data.
+ */
+ int data() const { return mdata; }
+ /**
+ * Set the contained data to d.
+ */
+ void setData( int d ) { mdata = d; }
+
+ IntImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool canFillInNextEscape() const;
+ void fillInNextEscape( QString& s, const KigDocument& ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+/**
+ * This ObjectImp is a BogusImp containing only a string value.
+ */
+class StringImp
+ : public BogusImp
+{
+ QString mdata;
+public:
+ /**
+ * Returns the ObjectImpType representing the StringImp type..
+ */
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ /**
+ * Construct a new StringImp containing the string d.
+ */
+ StringImp( const QString& d );
+
+ /**
+ * Get hold of the contained data.
+ */
+ const QString& data() const { return mdata; }
+ /**
+ * Set the contained data.
+ */
+ void setData( const QString& s ) { mdata = s; }
+
+ StringImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool canFillInNextEscape() const;
+ void fillInNextEscape( QString& s, const KigDocument& ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+class HierarchyImp
+ : public BogusImp
+{
+ ObjectHierarchy mdata;
+public:
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ HierarchyImp( const ObjectHierarchy& h );
+
+ const ObjectHierarchy& data() const { return mdata; }
+ void setData( const ObjectHierarchy& h ) { mdata = h; }
+
+ HierarchyImp* copy() const;
+ const char* baseName() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+/**
+ * \internal Don't mistake this imp for something that draws a
+ * transformed object. It does something completely different. It's
+ * a pure data Imp, like DoubleImp and friends that serves only to
+ * store the data of a transformation ( see the Transformation class
+ * in ../misc/kigtransform.h
+ */
+class TransformationImp
+ : public BogusImp
+{
+ Transformation mdata;
+public:
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ TransformationImp( const Transformation& h );
+
+ const Transformation& data() const { return mdata; }
+ void setData( const Transformation& h ) { mdata = h; }
+
+ TransformationImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+class TestResultImp
+ : public BogusImp
+{
+ const QString mdata;
+public:
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ TestResultImp( const QString& s );
+
+ TestResultImp* copy() const;
+
+ const QString& data() const { return mdata; }
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& d ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+#endif
diff --git a/kig/objects/centerofcurvature_type.cc b/kig/objects/centerofcurvature_type.cc
new file mode 100644
index 00000000..8111410f
--- /dev/null
+++ b/kig/objects/centerofcurvature_type.cc
@@ -0,0 +1,304 @@
+// Copyright (C) 2004 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+// 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 "centerofcurvature_type.h"
+
+#include "bogus_imp.h"
+#include "conic_imp.h"
+#include "cubic_imp.h"
+//#include "other_imp.h"
+#include "point_imp.h"
+//#include "line_imp.h"
+
+#include "../misc/common.h"
+#include "../misc/conic-common.h"
+//#include "../misc/calcpaths.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+
+static const char constructcenterofcurvaturepoint[] = "SHOULDNOTBESEEN";
+// I18N_NOOP( "Construct the center of curvature corresponding to this point" );
+static const char selectcoc1[] = I18N_NOOP( "Select the curve..." );
+static const char selectcoc2[] = I18N_NOOP( "Select a point on the curve..." );
+
+static const ArgsParser::spec argsspecCocConic[] =
+{
+ { ConicImp::stype(), "SHOULDNOTBESEEN", selectcoc1, false },
+ { PointImp::stype(), constructcenterofcurvaturepoint, selectcoc2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CocConicType )
+
+CocConicType::CocConicType()
+ : ArgsParserObjectType( "CocConic", argsspecCocConic, 2 )
+{
+}
+
+CocConicType::~CocConicType()
+{
+}
+
+const CocConicType* CocConicType::instance()
+{
+ static const CocConicType t;
+ return &t;
+}
+
+ObjectImp* CocConicType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const ConicImp* conic = static_cast<const ConicImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+
+ if ( !conic->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ double x = p.x;
+ double y = p.y;
+ ConicCartesianData data = conic->cartesianData();
+// double aconst = data.coeffs[5];
+ double ax = data.coeffs[3];
+ double ay = data.coeffs[4];
+ double axx = data.coeffs[0];
+ double axy = data.coeffs[2];
+ double ayy = data.coeffs[1];
+
+/*
+ * mp: we need to compute the normal vector and the curvature
+ * of the curve. The curve (conic) is given in implicit form
+ * f(x,y) = 0; the gradient of f gives the direction of the
+ * normal; for the curvature we can use the following formula:
+ * k = div(grad f/|grad f|)
+ *
+ * the hessian matrix has elements [hfxx, hfxy]
+ * [hfxy, hfyy]
+ *
+ * kgf is the curvature multiplied by the norm of grad f
+ */
+
+ double gradfx = 2*axx*x + axy*y + ax;
+ double gradfy = axy*x + 2*ayy*y + ay;
+ Coordinate gradf = Coordinate ( gradfx, gradfy );
+
+ double hfxx = 2*axx;
+ double hfyy = 2*ayy;
+ double hfxy = axy;
+
+ double kgf = hfxx + hfyy
+ - (hfxx*gradfx*gradfx + hfyy*gradfy*gradfy + 2*hfxy*gradfx*gradfy)
+ /(gradfx*gradfx + gradfy*gradfy);
+
+ bool ok = true;
+
+ const Coordinate coc = p - 1/kgf*gradf;
+
+ if ( !ok )
+ return new InvalidImp;
+
+ return new PointImp( coc );
+}
+
+const ObjectImpType* CocConicType::resultId() const
+{
+ return PointImp::stype();
+}
+
+/**** Cubic starts here ****/
+
+static const ArgsParser::spec argsspecCocCubic[] =
+{
+ { CubicImp::stype(), "SHOULDNOTBESEEN", selectcoc1, false },
+ { PointImp::stype(), constructcenterofcurvaturepoint, selectcoc2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CocCubicType )
+
+CocCubicType::CocCubicType()
+ : ArgsParserObjectType( "CocCubic", argsspecCocCubic, 2 )
+{
+}
+
+CocCubicType::~CocCubicType()
+{
+}
+
+const CocCubicType* CocCubicType::instance()
+{
+ static const CocCubicType t;
+ return &t;
+}
+
+ObjectImp* CocCubicType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const CubicImp* cubic = static_cast<const CubicImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+
+ if ( !cubic->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ double x = p.x;
+ double y = p.y;
+ CubicCartesianData data = cubic->data();
+// double aconst = data.coeffs[0];
+ double ax = data.coeffs[1];
+ double ay = data.coeffs[2];
+ double axx = data.coeffs[3];
+ double axy = data.coeffs[4];
+ double ayy = data.coeffs[5];
+ double axxx = data.coeffs[6];
+ double axxy = data.coeffs[7];
+ double axyy = data.coeffs[8];
+ double ayyy = data.coeffs[9];
+
+ /*
+ * we use here the same mechanism as for the
+ * conics, see above
+ */
+
+ double gradfx = 3*axxx*x*x + 2*axxy*x*y + axyy*y*y + 2*axx*x + axy*y + ax;
+ double gradfy = axxy*x*x + 2*axyy*x*y + 3*ayyy*y*y + axy*x + 2*ayy*y + ay;
+ Coordinate gradf = Coordinate ( gradfx, gradfy );
+
+ double hfxx = 6*axxx*x + 2*axxy*y + 2*axx;
+ double hfyy = 6*ayyy*y + 2*axyy*x + 2*ayy;
+ double hfxy = 2*axxy*x + 2*axyy*y + axy;
+
+ double kgf = hfxx + hfyy
+ - (hfxx*gradfx*gradfx + hfyy*gradfy*gradfy + 2*hfxy*gradfx*gradfy)
+ /(gradfx*gradfx + gradfy*gradfy);
+
+ bool ok = true;
+
+ const Coordinate coc = p - 1/kgf*gradf;
+
+ if ( !ok )
+ return new InvalidImp;
+
+ return new PointImp( coc );
+}
+
+const ObjectImpType* CocCubicType::resultId() const
+{
+ return PointImp::stype();
+}
+
+/**** Curve starts here ****/
+
+static const ArgsParser::spec argsspecCocCurve[] =
+{
+ { CurveImp::stype(), "SHOULDNOTBESEEN", selectcoc1, false },
+ { PointImp::stype(), constructcenterofcurvaturepoint, selectcoc2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CocCurveType )
+
+CocCurveType::CocCurveType()
+ : ArgsParserObjectType( "CocCurve", argsspecCocCurve, 2 )
+{
+}
+
+CocCurveType::~CocCurveType()
+{
+}
+
+const CocCurveType* CocCurveType::instance()
+{
+ static const CocCurveType t;
+ return &t;
+}
+
+ObjectImp* CocCurveType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const CurveImp* curve = static_cast<const CurveImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+
+ if ( !curve->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+
+ const double t = curve->getParam( p, doc );
+ const double tau0 = 5e-4;
+ const double sigmasq = 1e-12;
+ const int maxiter = 20;
+
+ double tau = tau0;
+ Coordinate gminus, g, gplus, tang, acc, curv, err;
+ double velsq, curvsq;
+ double tplus = t + tau;
+ double tminus = t - tau;
+ double t0 = t;
+ if ( tplus > 1 ) {tplus = 1; t0 = 1 - tau; tminus = 1 - 2*tau;}
+ if ( tminus < 0 ) {tminus = 0; t0 = tau; tplus = 2*tau;}
+ gminus = curve->getPoint( tminus, doc );
+ g = curve->getPoint( t0, doc );
+ gplus = curve->getPoint( tplus, doc );
+ tang = (gplus - gminus)/(2*tau);
+ acc = (gminus + gplus - 2*g)/(tau*tau);
+ velsq = tang.x*tang.x + tang.y*tang.y;
+ tang = tang/velsq;
+ Coordinate curvold = acc/velsq - (acc.x*tang.x + acc.y*tang.y)*tang;
+ curvsq = curvold.x*curvold.x + curvold.y*curvold.y;
+ curvold = curvold/curvsq;
+
+ for (int i = 0; i < maxiter; i++)
+ {
+ tau = tau/2;
+ tplus = t + tau;
+ tminus = t - tau;
+ t0 = t;
+ if ( tplus > 1 ) {tplus = 1; t0 = 1 - tau; tminus = 1 - 2*tau;}
+ if ( tminus < 0 ) {tminus = 0; t0 = tau; tplus = 2*tau;}
+
+ gminus = curve->getPoint( tminus, doc );
+ g = curve->getPoint( t0, doc );
+ gplus = curve->getPoint( tplus, doc );
+ tang = (gplus - gminus)/(2*tau);
+ acc = (gminus + gplus - 2*g)/(tau*tau);
+ velsq = tang.x*tang.x + tang.y*tang.y;
+ tang = tang/velsq;
+ curv = acc/velsq - (acc.x*tang.x + acc.y*tang.y)*tang;
+ curvsq = curv.x*curv.x + curv.y*curv.y;
+ curv = curv/curvsq;
+
+ err = (curvold - curv)/3;
+ /*
+ * curvsq is the inverse squared of the norm of curvsq
+ * so this is actually a relative test
+ * in the end we return an extrapolated value
+ */
+ if (err.squareLength() < sigmasq/curvsq)
+ {
+ curv = (4*curv - curvold)/3;
+ return new PointImp( p + curv );
+ }
+ curvold = curv;
+ }
+ return new InvalidImp;
+}
+
+const ObjectImpType* CocCurveType::resultId() const
+{
+ return PointImp::stype();
+}
diff --git a/kig/objects/centerofcurvature_type.h b/kig/objects/centerofcurvature_type.h
new file mode 100644
index 00000000..18dfc42a
--- /dev/null
+++ b/kig/objects/centerofcurvature_type.h
@@ -0,0 +1,68 @@
+// Copyright (C) 2004 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+// 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.
+
+#ifndef KIG_OBJECTS_CENTEROFCURVATURE_TYPE_H
+#define KIG_OBJECTS_CENTEROFCURVATURE_TYPE_H
+
+#include "base_type.h"
+
+/**
+ * the center of curvature of a conic at a point
+ */
+class CocConicType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ CocConicType();
+ ~CocConicType();
+public:
+ static const CocConicType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * the center of curvature of a cubic at a point
+ */
+class CocCubicType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ CocCubicType();
+ ~CocCubicType();
+public:
+ static const CocCubicType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * the center of curvature of a curve at a point
+ */
+class CocCurveType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ CocCurveType();
+ ~CocCurveType();
+public:
+ static const CocCurveType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/circle_imp.cc b/kig/objects/circle_imp.cc
new file mode 100644
index 00000000..13ceef93
--- /dev/null
+++ b/kig/objects/circle_imp.cc
@@ -0,0 +1,356 @@
+// 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 "circle_imp.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+
+#include "../misc/kigtransform.h"
+#include "../misc/kigpainter.h"
+#include "../misc/coordinate_system.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+#include <math.h>
+
+CircleImp::CircleImp( const Coordinate& center, double radius )
+ : mcenter( center ), mradius( radius )
+{
+}
+
+CircleImp::~CircleImp()
+{
+}
+
+ObjectImp* CircleImp::transform( const Transformation& t ) const
+{
+ if ( t.isHomothetic() )
+ {
+ Coordinate nc = t.apply( mcenter );
+ double nr = t.apply( mradius );
+ if ( nc.valid() )
+ return new CircleImp( nc, nr );
+ else return new InvalidImp;
+ }
+ else
+ {
+ // domi: i should return a ConicImp here, but i don't know how to
+ // calculate it..
+ return Parent::transform( t );
+ };
+}
+
+void CircleImp::draw( KigPainter& p ) const
+{
+ p.drawCircle( mcenter, mradius );
+}
+
+bool CircleImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return fabs((mcenter - p).length() - mradius) <= w.screenInfo().normalMiss( width );
+}
+
+bool CircleImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ // first we check if the rect contains at least one of the
+ // north/south/east/west points of the circle
+ if ( r.contains( mcenter + Coordinate( 0, -mradius ) ) ) return true;
+ if ( r.contains( mcenter + Coordinate( mradius, 0 ) ) ) return true;
+ if ( r.contains( mcenter + Coordinate( 0, mradius ) ) ) return true;
+ if ( r.contains( mcenter + Coordinate( -mradius, 0 ) ) ) return true;
+
+ // we allow a miss of some pixels ..
+ double miss = w.screenInfo().normalMiss( width );
+ double bigradius = mradius + miss;
+ bigradius *= bigradius;
+ double smallradius = mradius - miss;
+ smallradius *= smallradius;
+
+ const int in = -1;
+ const int undecided = 0;
+ const int out = 1;
+
+ int inorout = undecided;
+
+ Coordinate coords[4];
+ coords[0] = r.topLeft();
+ coords[1] = r.topRight();
+ coords[2] = r.bottomRight();
+ coords[3] = r.bottomLeft();
+
+ // we check if the corners of the rect are either
+ for ( Coordinate* i = coords; i < coords + 4; ++i )
+ {
+ double t = ( *i - mcenter ).squareLength();
+ if ( t >= bigradius )
+ {
+ if ( inorout == in ) return true;
+ inorout = out;
+ }
+ else if ( t <= smallradius )
+ {
+ if ( inorout == out ) return true;
+ inorout = in;
+ }
+ }
+ return inorout == undecided;
+}
+
+bool CircleImp::valid() const
+{
+ return true;
+}
+
+const uint CircleImp::numberOfProperties() const
+{
+ // We _intentionally_ do not use the Conic properties..
+ return CurveImp::numberOfProperties() + 7;
+}
+
+const QCStringList CircleImp::propertiesInternalNames() const
+{
+ QCStringList l = CurveImp::propertiesInternalNames();
+ l << "surface";
+ l << "circumference";
+ l << "radius";
+ l << "center";
+ l << "cartesian-equation";
+ l << "simply-cartesian-equation";
+ l << "polar-equation";
+ assert( l.size() == CircleImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList CircleImp::properties() const
+{
+ QCStringList l = CurveImp::properties();
+ l << I18N_NOOP( "Surface" );
+ l << I18N_NOOP( "Circumference" );
+ l << I18N_NOOP( "Radius" );
+ l << I18N_NOOP( "Center" );
+ l << I18N_NOOP( "Expanded Cartesian Equation" );
+ l << I18N_NOOP( "Cartesian Equation" );
+ l << I18N_NOOP( "Polar Equation" );
+ assert( l.size() == CircleImp::numberOfProperties() );
+ return l;
+}
+
+const ObjectImpType* CircleImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < CurveImp::numberOfProperties() )
+ return CurveImp::impRequirementForProperty( which );
+ else return CircleImp::stype();
+}
+
+const char* CircleImp::iconForProperty( uint which ) const
+{
+ assert( which < CircleImp::numberOfProperties() );
+ if ( which < CurveImp::numberOfProperties() )
+ return CurveImp::iconForProperty( which );
+ else if ( which == CurveImp::numberOfProperties() )
+ return "areaCircle"; // surface
+ else if ( which == CurveImp::numberOfProperties() + 1 )
+ return "circumference"; // circumference
+ else if ( which == CurveImp::numberOfProperties() + 2 )
+ return ""; //radius
+ else if ( which == CurveImp::numberOfProperties() + 3 )
+ return "baseCircle"; // circle center
+ else if ( which == CurveImp::numberOfProperties() + 4 )
+ return "kig_text"; // cartesian equation
+ else if ( which == CurveImp::numberOfProperties() + 5 )
+ return "kig_text"; // simply cartesian equation
+ else if ( which == CurveImp::numberOfProperties() + 6 )
+ return "kig_text"; // polar equation
+ else assert( false );
+ return "";
+}
+
+ObjectImp* CircleImp::property( uint which, const KigDocument& w ) const
+{
+ assert( which < CircleImp::numberOfProperties() );
+ if ( which < CurveImp::numberOfProperties() )
+ return CurveImp::property( which, w );
+ if ( which == CurveImp::numberOfProperties() )
+ return new DoubleImp( surface() );
+ else if ( which == CurveImp::numberOfProperties() + 1 )
+ return new DoubleImp( circumference() );
+ else if ( which == CurveImp::numberOfProperties() + 2 )
+ return new DoubleImp( radius() );
+ else if ( which == CurveImp::numberOfProperties() + 3 )
+ return new PointImp( center() );
+ else if ( which == CurveImp::numberOfProperties() + 4 )
+ return new StringImp( cartesianEquationString( w ) );
+ else if ( which == CurveImp::numberOfProperties() + 5 )
+ return new StringImp( simplyCartesianEquationString( w ) );
+ else if ( which == CurveImp::numberOfProperties() + 6 )
+ return new StringImp( polarEquationString( w ) );
+ else assert( false );
+ return new InvalidImp;
+}
+
+const Coordinate CircleImp::center() const
+{
+ return mcenter;
+}
+
+double CircleImp::radius() const
+{
+ return mradius;
+}
+
+double CircleImp::surface() const
+{
+ return M_PI * squareRadius();
+}
+
+double CircleImp::squareRadius() const
+{
+ return mradius * mradius;
+}
+
+double CircleImp::circumference() const
+{
+ return 2 * M_PI * radius();
+}
+
+QString CircleImp::polarEquationString( const KigDocument& w ) const
+{
+ QString ret = i18n( "rho = %1 [centered at %2]" );
+ ConicPolarData data = polarData();
+ ret = ret.arg( data.pdimen, 0, 'g', 3 );
+ ret = ret.arg( w.coordinateSystem().fromScreen( data.focus1, w ) );
+ return ret;
+}
+
+QString CircleImp::cartesianEquationString( const KigDocument& ) const
+{
+ QString ret = i18n( "x² + y² + %1 x + %2 y + %3 = 0" );
+ ConicCartesianData data = cartesianData();
+ ret = ret.arg( data.coeffs[3], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[4], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[5], 0, 'g', 3 );
+ return ret;
+}
+
+QString CircleImp::simplyCartesianEquationString( const KigDocument& ) const
+{
+ QString ret = i18n( "( x - %1 )² + ( y - %2 )² = %3" );
+ ret = ret.arg( mcenter.x, 0, 'g', 3 );
+ ret = ret.arg( mcenter.y, 0, 'g', 3 );
+ ret = ret.arg( mradius * mradius, 0, 'g', 3 );
+ return ret;
+}
+
+Coordinate CircleImp::focus1() const
+{
+ return center();
+}
+
+Coordinate CircleImp::focus2() const
+{
+ return center();
+}
+
+int CircleImp::conicType() const
+{
+ return 1;
+}
+
+const ConicCartesianData CircleImp::cartesianData() const
+{
+ Coordinate c = center();
+ double sqr = squareRadius();
+ ConicCartesianData data(
+ 1.0, 1.0, 0.0, -2*c.x, -2*c.y,
+ c.x*c.x + c.y*c.y - sqr );
+ return data;
+}
+
+const ConicPolarData CircleImp::polarData() const
+{
+ return ConicPolarData( center(), radius(), 0, 0 );
+}
+
+CircleImp* CircleImp::copy() const
+{
+ return new CircleImp( mcenter, mradius );
+}
+
+double CircleImp::getParam( const Coordinate& point, const KigDocument& ) const
+{
+ Coordinate tmp = point - mcenter;
+ double ret = atan2(tmp.y, tmp.x) / ( 2 * M_PI );
+ if ( ret > 0 ) return ret;
+ else return ret + 1;
+}
+
+const Coordinate CircleImp::getPoint( double p, const KigDocument& ) const
+{
+ return mcenter + Coordinate (cos(p * 2 * M_PI), sin(p * 2 * M_PI)) * mradius;
+}
+
+void CircleImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool CircleImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( CircleImp::stype() ) &&
+ static_cast<const CircleImp&>( rhs ).center() == center() &&
+ static_cast<const CircleImp&>( rhs ).radius() == radius();
+}
+
+const ObjectImpType* CircleImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "circle",
+ I18N_NOOP( "circle" ),
+ I18N_NOOP( "Select this circle" ),
+ I18N_NOOP( "Select circle %1" ),
+ I18N_NOOP( "Remove a Circle" ),
+ I18N_NOOP( "Add a Circle" ),
+ I18N_NOOP( "Move a Circle" ),
+ I18N_NOOP( "Attach to this circle" ),
+ I18N_NOOP( "Show a Circle" ),
+ I18N_NOOP( "Hide a Circle" )
+ );
+ return &t;
+}
+
+const ObjectImpType* CircleImp::type() const
+{
+ return CircleImp::stype();
+}
+
+bool CircleImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ assert( which < CircleImp::numberOfProperties() );
+ if ( which < CurveImp::numberOfProperties() )
+ return CurveImp::isPropertyDefinedOnOrThroughThisImp( which );
+ return false;
+}
+
+Rect CircleImp::surroundingRect() const
+{
+ Coordinate d( mradius, mradius );
+ return Rect( mcenter - d, mcenter + d );
+}
diff --git a/kig/objects/circle_imp.h b/kig/objects/circle_imp.h
new file mode 100644
index 00000000..d38716a6
--- /dev/null
+++ b/kig/objects/circle_imp.h
@@ -0,0 +1,125 @@
+// 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.
+
+#ifndef KIG_OBJECTS_CIRCLE_IMP_H
+#define KIG_OBJECTS_CIRCLE_IMP_H
+
+#include "conic_imp.h"
+
+/**
+ * An ObjectImp representing a circle. This class is a subclass of
+ * ConicImp, ensuring that a circle can be used as a conic.
+ */
+class CircleImp
+ : public ConicImp
+{
+ Coordinate mcenter;
+ double mradius;
+public:
+ typedef ConicImp Parent;
+ /**
+ * Returns the ObjectImpType representing the CircleImp type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct a Circle with a given center and radius.
+ */
+ CircleImp( const Coordinate& center, double radius );
+ ~CircleImp();
+ CircleImp* copy() const;
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ bool valid() const;
+ Rect surroundingRect() const;
+
+ double getParam( const Coordinate& point, const KigDocument& ) const;
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ /**
+ * Return the center of this circle.
+ */
+ const Coordinate center() const;
+ /**
+ * Return the radius of this circle.
+ */
+ double radius() const;
+ /**
+ * Return the square radius of this circle. Use this in preference
+ * to sqr( radius() ).
+ */
+ double squareRadius() const;
+ /**
+ * Return the surface of this circle.
+ */
+ double surface() const;
+ /**
+ * Return the circumference of this circle.
+ */
+ double circumference() const;
+
+ // trivial versions of the conic information functions..
+ /**
+ * Always returns 1, since a circle always is an ellipse.
+ */
+ int conicType() const;
+ const ConicCartesianData cartesianData() const;
+ const ConicPolarData polarData() const;
+ /**
+ * The first focus of a circle is simply its center.
+ */
+ Coordinate focus1() const;
+ /**
+ * The second focus of a circle is simply its center.
+ */
+ Coordinate focus2() const;
+
+ /**
+ * Return a string containing the cartesian equation of this circle.
+ * This will be of the form "x^2 + y^2 + a x + b y + c = 0"
+ */
+ QString cartesianEquationString( const KigDocument& w ) const;
+ /**
+ * Return a string containing the cartesian equation of this circle.
+ * This will be of the form "( x - x0 )^2 + ( y - y0 )^2 = r^2"
+ */
+ QString simplyCartesianEquationString( const KigDocument& w ) const;
+ /**
+ * Return a string containing the polar equation of this circle.
+ * This will be of the form "rho = r [centered at p]"
+ */
+ QString polarEquationString( const KigDocument& w ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+#endif
diff --git a/kig/objects/circle_type.cc b/kig/objects/circle_type.cc
new file mode 100644
index 00000000..97d2f615
--- /dev/null
+++ b/kig/objects/circle_type.cc
@@ -0,0 +1,181 @@
+// 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 "circle_type.h"
+
+#include "circle_imp.h"
+#include "bogus_imp.h"
+#include "line_imp.h"
+#include "point_imp.h"
+
+#include "../misc/common.h"
+
+#include <klocale.h>
+
+static const char constructcirclethroughpointstat[] = I18N_NOOP( "Construct a circle through this point" );
+
+static const char constructcirclewithcenterstat[] = I18N_NOOP( "Construct a circle with this center" );
+
+static const ArgsParser::spec argsspecCircleBCP[] =
+{
+ { PointImp::stype(), constructcirclewithcenterstat,
+ I18N_NOOP( "Select the center of the new circle..." ), false },
+ { PointImp::stype(), constructcirclethroughpointstat,
+ I18N_NOOP( "Select a point for the new circle to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CircleBCPType )
+
+CircleBCPType::CircleBCPType()
+ : ObjectABType( "CircleBCP", argsspecCircleBCP, 2 )
+{
+}
+
+CircleBCPType::~CircleBCPType()
+{
+}
+
+const CircleBCPType* CircleBCPType::instance()
+{
+ static const CircleBCPType s;
+ return &s;
+}
+
+ObjectImp* CircleBCPType::calc( const Coordinate& a, const Coordinate& b ) const
+{
+ return new CircleImp( a, ( b - a ).length() );
+}
+
+const CircleBTPType* CircleBTPType::instance()
+{
+ static const CircleBTPType t;
+ return &t;
+}
+
+static const ArgsParser::spec argsspecCircleBTP[] =
+{
+ { PointImp::stype(), constructcirclethroughpointstat,
+ I18N_NOOP( "Select a point for the new circle to go through..." ), true },
+ { PointImp::stype(), constructcirclethroughpointstat,
+ I18N_NOOP( "Select a point for the new circle to go through..." ), true },
+ { PointImp::stype(), constructcirclethroughpointstat,
+ I18N_NOOP( "Select a point for the new circle to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CircleBTPType )
+
+CircleBTPType::CircleBTPType()
+ : ArgsParserObjectType( "CircleBTP", argsspecCircleBTP, 3 )
+{
+}
+
+CircleBTPType::~CircleBTPType()
+{
+}
+
+ObjectImp* CircleBTPType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args, 2 ) ) return new InvalidImp;
+
+ const Coordinate a = static_cast<const PointImp*>( args[0] )->coordinate();
+ const Coordinate b = static_cast<const PointImp*>( args[1] )->coordinate();
+ Coordinate c;
+ if ( args.size() == 3 )
+ c = static_cast<const PointImp*>( args[2] )->coordinate();
+ else
+ {
+ // we pick the third point so that the three points form a
+ // triangle with equal sides...
+
+ // midpoint:
+ Coordinate m = ( b + a ) / 2;
+ if ( b.y != a.y )
+ {
+ // direction of the perpend:
+ double d = -(b.x-a.x)/(b.y-a.y);
+
+ // length:
+ // sqrt( 3 ) == tan( 60° ) == sqrt( 2^2 - 1^2 )
+ double l = 1.73205080756 * (a-b).length() / 2;
+
+ double d2 = d*d;
+ double l2 = l*l;
+ double dx = sqrt( l2 / ( d2 + 1 ) );
+ double dy = sqrt( l2 * d2 / ( d2 + 1 ) );
+ if( d < 0 ) dy = -dy;
+
+ c.x = m.x + dx;
+ c.y = m.y + dy;
+ }
+ else
+ {
+ c.x = m.x;
+ c.y = m.y + ( a.x - b.x );
+ };
+ };
+
+ const Coordinate center = calcCenter( a, b, c );
+ if ( center.valid() )
+ return new CircleImp( center, (center - a ).length() );
+ else return new InvalidImp;
+}
+
+const ObjectImpType* CircleBCPType::resultId() const
+{
+ return CircleImp::stype();
+}
+
+const ObjectImpType* CircleBTPType::resultId() const
+{
+ return CircleImp::stype();
+}
+
+static const ArgsParser::spec argsspecCircleBPR[] =
+{
+ { PointImp::stype(), "SHOULD NOT BE SEEN", "SHOULD NOT BE SEEN", false },
+ { DoubleImp::stype(), "SHOULD NOT BE SEEN", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CircleBPRType )
+
+CircleBPRType::CircleBPRType()
+ : ArgsParserObjectType( "CircleBPR", argsspecCircleBPR, 2 )
+{
+}
+
+CircleBPRType::~CircleBPRType()
+{
+}
+
+const CircleBPRType* CircleBPRType::instance()
+{
+ static const CircleBPRType t;
+ return &t;
+}
+
+ObjectImp* CircleBPRType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+ const Coordinate c = static_cast<const PointImp*>( args[0] )->coordinate();
+ double r = static_cast<const DoubleImp*>( args[1] )->data();
+ return new CircleImp( c, r );
+}
+
+const ObjectImpType* CircleBPRType::resultId() const
+{
+ return CircleImp::stype();
+}
diff --git a/kig/objects/circle_type.h b/kig/objects/circle_type.h
new file mode 100644
index 00000000..874d0b69
--- /dev/null
+++ b/kig/objects/circle_type.h
@@ -0,0 +1,69 @@
+// 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.
+
+#ifndef KIG_OBJECTS_CIRCLE_TYPE_H
+#define KIG_OBJECTS_CIRCLE_TYPE_H
+
+#include "base_type.h"
+
+/**
+ * Circle by center and point
+ */
+class CircleBCPType
+ : public ObjectABType
+{
+ CircleBCPType();
+ ~CircleBCPType();
+public:
+ static const CircleBCPType* instance();
+
+ ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * Circle by point and radius.
+ */
+class CircleBPRType
+ : public ArgsParserObjectType
+{
+ CircleBPRType();
+ ~CircleBPRType();
+public:
+ static const CircleBPRType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * Circle by three points
+ */
+class CircleBTPType
+ : public ArgsParserObjectType
+{
+ CircleBTPType();
+ ~CircleBTPType();
+
+public:
+ static const CircleBTPType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/common.cc b/kig/objects/common.cc
new file mode 100644
index 00000000..9932734c
--- /dev/null
+++ b/kig/objects/common.cc
@@ -0,0 +1,43 @@
+// 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 "common.h"
+#include "object_holder.h"
+
+std::vector<ObjectCalcer*> getAllCalcers( const std::vector<ObjectHolder*>& os )
+{
+ std::set<ObjectCalcer*> ret;
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ {
+ if ( ( *i )->nameCalcer() )
+ ret.insert( ( *i )->nameCalcer() );
+ ret.insert( ( *i )->calcer() );
+ }
+ return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
+}
+
+std::vector<ObjectCalcer*> getCalcers( const std::vector<ObjectHolder*>& os )
+{
+ std::vector<ObjectCalcer*> ret;
+ ret.reserve( os.size() );
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ ret.push_back( ( *i )->calcer() );
+ return ret;
+}
+
diff --git a/kig/objects/common.h b/kig/objects/common.h
new file mode 100644
index 00000000..a26a92cd
--- /dev/null
+++ b/kig/objects/common.h
@@ -0,0 +1,107 @@
+// Copyright (C) 2002 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.
+
+#ifndef KIG_OBJECTS_COMMON_H
+#define KIG_OBJECTS_COMMON_H
+
+#include <set>
+#include <vector>
+#include <qcstring.h>
+#include <qvaluelist.h>
+#include <qstringlist.h>
+#include <cassert>
+#include <klocale.h>
+
+class Coordinate;
+class KigDocument;
+class KigPainter;
+class KigPart;
+class KigWidget;
+class NormalMode;
+class ObjectCalcer;
+class ObjectDrawer;
+class ObjectHolder;
+class ObjectImp;
+class ObjectImpType;
+class ObjectPropertyCalcer;
+class ObjectType;
+class ObjectTypeCalcer;
+class QDomDocument;
+class QDomElement;
+class Rect;
+class ScreenInfo;
+class Transformation;
+
+typedef std::vector<const ObjectImp*> Args;
+typedef QValueList<QCString> QCStringList;
+
+template<typename T>
+void delete_all( T begin, T end )
+{
+ for( ; begin != end; ++begin )
+ {
+ delete *begin;
+ }
+}
+
+/**
+ * get the calcers that the holders represent and their namecalcers
+ */
+std::vector<ObjectCalcer*> getAllCalcers( const std::vector<ObjectHolder*>& os );
+
+/**
+ * get the calcers that the holders represent ( not their namecalcers )
+ */
+std::vector<ObjectCalcer*> getCalcers( const std::vector<ObjectHolder*>& os );
+
+/**
+ * The below is a trick. ObjectType's implement the singleton
+ * pattern. There can be only one of them at each time. This one
+ * instance of them needs to be constructed at some time, within the
+ * following restrictions:
+ *
+ * 1. They need to be constructed in the right order: if one ObjectType
+ * uses another in its constructor, the other needs to be constructed
+ * first. To achieve this, we use a scheme with ::instance()
+ * functions, that have a static variable in the body of the function
+ * ( if we would define them static outside of the function body, C++
+ * would provide no guarantee on the order they would be called in ).
+ *
+ * 2. They need to be constructed before Kig tries to use them. They
+ * need to be added to the ObjectTypeFactory before anyone tries to
+ * use that class to fetch a type. The below is a trick to achieve
+ * that in combination with the previous. Basically, we add a fake
+ * static instance of an empty class that receives the instance of the
+ * ObjectType as an argument to its constructor. C++ then guarantees
+ * that these things will be constructed before main() is entered.
+ *
+ * Thus, for your own ObjectType classes: use the scheme with the
+ * static ::instance methods, and add
+ * \code
+ * KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( MyObjectType)
+ * \endcode
+ * to the .cpp file of your class.
+ */
+class FakeClass {
+public:
+ FakeClass( const ObjectType* ) {
+ }
+};
+
+#define KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( type ) static class FakeClass _fake_class_instance_##type( type::instance() );
+
+#endif
diff --git a/kig/objects/conic_imp.cc b/kig/objects/conic_imp.cc
new file mode 100644
index 00000000..a65d8511
--- /dev/null
+++ b/kig/objects/conic_imp.cc
@@ -0,0 +1,385 @@
+// 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 "conic_imp.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+
+#include "../misc/kigpainter.h"
+#include "../misc/common.h"
+#include "../misc/coordinate_system.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+ObjectImp* ConicImp::transform( const Transformation& t ) const
+{
+ bool valid = true;
+ ConicCartesianData d = calcConicTransformation( cartesianData(), t, valid );
+ if ( ! valid ) return new InvalidImp;
+ else return new ConicImpCart( d );
+}
+
+void ConicImp::draw( KigPainter& p ) const
+{
+ p.drawCurve( this );
+}
+
+bool ConicImp::valid() const
+{
+ return true;
+}
+
+bool ConicImp::contains( const Coordinate& o, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( o, w.screenInfo().normalMiss( width ) );
+}
+
+bool ConicImp::inRect( const Rect&, int, const KigWidget& ) const
+{
+ // TODO
+ return false;
+}
+
+const uint ConicImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 5;
+}
+
+const QCStringList ConicImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l << "type";
+ l << "first-focus";
+ l << "second-focus";
+ l << "cartesian-equation";
+ l << "polar-equation";
+ assert( l.size() == ConicImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList ConicImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Conic Type" );
+ l << I18N_NOOP( "First Focus" );
+ l << I18N_NOOP( "Second Focus" );
+ l << I18N_NOOP( "Cartesian Equation" );
+ l << I18N_NOOP( "Polar Equation" );
+ assert( l.size() == ConicImp::numberOfProperties() );
+ return l;
+}
+
+const ObjectImpType* ConicImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return ConicImp::stype();
+}
+
+const char* ConicImp::iconForProperty( uint which ) const
+{
+ int pnum = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() + pnum++ )
+ return "kig_text"; // conic type string
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return ""; // focus1
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return ""; // focus2
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return "kig_text"; // cartesian equation string
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return "kig_text"; // polar equation string
+ else assert( false );
+ return "";
+}
+
+ObjectImp* ConicImp::property( uint which, const KigDocument& w ) const
+{
+ int pnum = 0;
+
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ if ( which == Parent::numberOfProperties() + pnum++ )
+ return new StringImp( conicTypeString() );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new PointImp( focus1() );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new PointImp( focus2() );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new StringImp( cartesianEquationString( w ) );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new StringImp( polarEquationString( w ) );
+ else assert( false );
+ return new InvalidImp;
+}
+
+double ConicImp::getParam( const Coordinate& p, const KigDocument& ) const
+{
+ const ConicPolarData d = polarData();
+ Coordinate tmp = p - d.focus1;
+ double l = tmp.length();
+ double theta = atan2(tmp.y, tmp.x);
+ double costheta = cos(theta);
+ double sintheta = sin(theta);
+ double ecosthetamtheta0 = costheta*d.ecostheta0 + sintheta*d.esintheta0;
+ double esinthetamtheta0 = sintheta*d.ecostheta0 - costheta*d.esintheta0;
+ double oneplus = 1.0 + d.ecostheta0*d.ecostheta0 + d.esintheta0*d.esintheta0;
+ double fact = esinthetamtheta0*(1.0 - ecosthetamtheta0)/(oneplus - 2*ecosthetamtheta0);
+// fact is sin(a)*cos(a) where a is the angle between the ray from the first
+// focus and the normal to the conic. We need it in order to adjust the
+// angle according to the projection onto the conic of our point
+ double rho1 = d.pdimen / (1 - ecosthetamtheta0);
+ double rho2 = - d.pdimen / (1 + ecosthetamtheta0);
+ if (fabs(rho1 - l) < fabs(rho2 - l))
+ {
+ theta += (rho1 - l)*fact/rho1;
+ return fmod(theta / ( 2 * M_PI ) + 1, 1);
+ } else {
+ theta += (rho2 - l)*fact/rho2;
+ return fmod(theta / ( 2 * M_PI ) + 0.5, 1);
+ }
+}
+
+const Coordinate ConicImp::getPoint( double p, const KigDocument& ) const
+{
+ const ConicPolarData d = polarData();
+
+ double costheta = cos(p * 2 * M_PI);
+ double sintheta = sin(p * 2 * M_PI);
+ double rho = d.pdimen / (1 - costheta* d.ecostheta0 - sintheta* d.esintheta0);
+ return d.focus1 + Coordinate (costheta, sintheta) * rho;
+}
+
+int ConicImp::conicType() const
+{
+ const ConicPolarData d = polarData();
+ double ec = d.ecostheta0;
+ double es = d.esintheta0;
+ double esquare = ec*ec + es*es;
+ const double parabolamiss = 1e-3; // don't know what a good value could be
+
+ if (esquare < 1.0 - parabolamiss) return 1;
+ if (esquare > 1.0 + parabolamiss) return -1;
+
+ return 0;
+}
+
+QString ConicImp::conicTypeString() const
+{
+ switch (conicType())
+ {
+ case 1:
+ return i18n("Ellipse");
+ case -1:
+ return i18n("Hyperbola");
+ case 0:
+ return i18n("Parabola");
+ default:
+ assert( false );
+ return "";
+ }
+}
+
+QString ConicImp::cartesianEquationString( const KigDocument& ) const
+{
+ QString ret = i18n( "%1 x² + %2 y² + %3 xy + %4 x + %5 y + %6 = 0" );
+ ConicCartesianData data = cartesianData();
+ ret = ret.arg( data.coeffs[0], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[1], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[2], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[3], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[4], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[5], 0, 'g', 3 );
+ return ret;
+}
+
+QString ConicImp::polarEquationString( const KigDocument& w ) const
+{
+ QString ret = i18n( "rho = %1/(1 + %2 cos theta + %3 sin theta)\n [centered at %4]" );
+ const ConicPolarData data = polarData();
+
+ ret = ret.arg( data.pdimen, 0, 'g', 3 );
+ ret = ret.arg( -data.ecostheta0, 0, 'g', 3 );
+ ret = ret.arg( -data.esintheta0, 0, 'g', 3 );
+
+ ret = ret.arg( w.coordinateSystem().fromScreen( data.focus1, w ) );
+ return ret;
+}
+
+const ConicCartesianData ConicImp::cartesianData() const
+{
+ return ConicCartesianData( polarData() );
+}
+
+Coordinate ConicImp::focus1() const
+{
+ return polarData().focus1;
+}
+
+Coordinate ConicImp::focus2() const
+{
+ const ConicPolarData d = polarData();
+ double ec = d.ecostheta0;
+ double es = d.esintheta0;
+
+ double fact = 2*d.pdimen/(1 - ec*ec - es*es);
+
+ return d.focus1 + fact*Coordinate(ec, es);
+}
+
+const ConicPolarData ConicImpCart::polarData() const
+{
+ return mpolardata;
+}
+
+const ConicCartesianData ConicImpCart::cartesianData() const
+{
+ return mcartdata;
+}
+
+ConicImpCart::ConicImpCart( const ConicCartesianData& data )
+ : ConicImp(), mcartdata( data ), mpolardata( data )
+{
+ assert( data.valid() );
+}
+
+ConicImpPolar::ConicImpPolar( const ConicPolarData& data )
+ : ConicImp(), mdata( data )
+{
+}
+
+ConicImpPolar::~ConicImpPolar()
+{
+}
+
+const ConicPolarData ConicImpPolar::polarData() const
+{
+ return mdata;
+}
+
+ConicImpCart* ConicImpCart::copy() const
+{
+ return new ConicImpCart( mcartdata );
+}
+
+ConicImpPolar* ConicImpPolar::copy() const
+{
+ return new ConicImpPolar( mdata );
+}
+
+ConicImp::ConicImp()
+{
+}
+
+ConicImp::~ConicImp()
+{
+}
+
+ConicImpCart::~ConicImpCart()
+{
+}
+
+void ConicImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool ConicImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( ConicImp::stype() ) &&
+ static_cast<const ConicImp&>( rhs ).polarData() == polarData();
+}
+
+const ObjectImpType* ConicImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "conic",
+ I18N_NOOP( "conic" ),
+ I18N_NOOP( "Select this conic" ),
+ I18N_NOOP( "Select conic %1" ),
+ I18N_NOOP( "Remove a Conic" ),
+ I18N_NOOP( "Add a Conic" ),
+ I18N_NOOP( "Move a Conic" ),
+ I18N_NOOP( "Attach to this conic" ),
+ I18N_NOOP( "Show a Conic" ),
+ I18N_NOOP( "Hide a Conic" )
+ );
+ return &t;
+}
+
+const ObjectImpType* ConicImp::type() const
+{
+ return ConicImp::stype();
+}
+
+bool ConicImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ const ConicPolarData d = polarData();
+
+// the threshold is relative to the size of the conic (mp)
+ return internalContainsPoint( p, test_threshold*d.pdimen );
+}
+
+bool ConicImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ const ConicPolarData d = polarData();
+
+ Coordinate focus1 = d.focus1;
+ double ecostheta0 = d.ecostheta0;
+ double esintheta0 = d.esintheta0;
+ double pdimen = d.pdimen;
+
+ Coordinate pos = p - focus1;
+ double len = pos.length();
+ double costheta = pos.x / len;
+ double sintheta = pos.y / len;
+
+ double ecosthetamtheta0 = costheta*ecostheta0 + sintheta*esintheta0;
+ double rho = pdimen / (1.0 - ecosthetamtheta0);
+
+ double oneplus = 1.0 + ecostheta0*ecostheta0 + esintheta0*esintheta0;
+
+// fact is the cosine of the angle between the ray from the first focus
+// and the normal to the conic, so that we compute the real distance
+
+ double fact = (1.0 - ecosthetamtheta0)/sqrt(oneplus - 2*ecosthetamtheta0);
+ if ( fabs((len - rho)*fact) <= threshold ) return true;
+ rho = - pdimen / ( 1.0 + ecosthetamtheta0 );
+ fact = (1.0 + ecosthetamtheta0)/sqrt(oneplus + 2*ecosthetamtheta0);
+ return fabs(( len - rho )*fact) <= threshold;
+}
+
+bool ConicImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+ return false;
+}
+
+Rect ConicImp::surroundingRect() const
+{
+ // it's prolly possible to calculate this ( in the case that the
+ // conic is limited in size ), but for now we don't.
+
+ return Rect::invalidRect();
+}
diff --git a/kig/objects/conic_imp.h b/kig/objects/conic_imp.h
new file mode 100644
index 00000000..55ba65ca
--- /dev/null
+++ b/kig/objects/conic_imp.h
@@ -0,0 +1,157 @@
+// 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.
+
+#ifndef KIG_OBJECTS_CONIC_IMP_H
+#define KIG_OBJECTS_CONIC_IMP_H
+
+#include "curve_imp.h"
+
+#include "../misc/conic-common.h"
+
+/**
+ * An ObjectImp representing a conic.
+ *
+ * A conic is a general second degree curve, and some beautiful theory
+ * has been developed about it.. See a math book for more
+ * information. This class is in fact an abstract base class hiding
+ * the fact that a ConicImp can be constructed in two ways. If only
+ * its Cartesian equation is known, then you should use ConicImpCart,
+ * otherwise, you should use ConicImpPolar. If the other
+ * representation is needed, it will be calculated, but a cartesian
+ * representation is rarely needed, and not calculating saves some CPU
+ * cycles.
+ */
+class ConicImp
+ : public CurveImp
+{
+protected:
+ ConicImp();
+ ~ConicImp();
+public:
+ typedef CurveImp Parent;
+ /**
+ * Returns the ObjectImpType representing the ConicImp type.
+ */
+ static const ObjectImpType* stype();
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ bool valid() const;
+ Rect surroundingRect() const;
+
+ const uint numberOfProperties() const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ const char* iconForProperty( uint which ) const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+
+ double getParam( const Coordinate& point, const KigDocument& ) const;
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+
+ // information about ourselves.. These are all virtual, because a
+ // trivial subclass like CircleImp can override these with trivial
+ // versions..
+
+ /**
+ * Type of conic.
+ * Return what type of conic this is:
+ * -1 for a hyperbola
+ * 0 for a parabola
+ * 1 for an ellipse
+ */
+ virtual int conicType() const;
+ /**
+ * A string containing "Hyperbola", "Parabola" or "Ellipse".
+ */
+ virtual QString conicTypeString() const;
+ /**
+ * A string containing the cartesian equation of the conic. This
+ * will be of the form "a x^2 + b y^2 + c xy + d x + e y + f = 0".
+ */
+ virtual QString cartesianEquationString( const KigDocument& w ) const;
+ /**
+ * A string containing the polar equation of the conic. This will
+ * be of the form "rho = pdimen/(1 + ect cos( theta ) + est sin(
+ * theta ) )\n [centered at p]"
+ */
+ virtual QString polarEquationString( const KigDocument& w ) const;
+ /**
+ * Return the cartesian representation of this conic.
+ */
+ virtual const ConicCartesianData cartesianData() const;
+ /**
+ * Return the polar representation of this conic.
+ */
+ virtual const ConicPolarData polarData() const = 0;
+ /**
+ * Return the first focus of this conic.
+ */
+ virtual Coordinate focus1() const;
+ /**
+ * Return the second focus of this conic.
+ */
+ virtual Coordinate focus2() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+/**
+ * An implementation of ConicImp to be used when only the cartesian
+ * equation of the conic is known.
+ */
+class ConicImpCart
+ : public ConicImp
+{
+ ConicCartesianData mcartdata;
+ ConicPolarData mpolardata;
+public:
+ ConicImpCart( const ConicCartesianData& data );
+ ~ConicImpCart();
+ ConicImpCart* copy() const;
+
+ const ConicCartesianData cartesianData() const;
+ const ConicPolarData polarData() const;
+};
+
+/**
+ * An implementation of ConicImp to be used when only the cartesian
+ * equation of the conic is known.
+ */
+class ConicImpPolar
+ : public ConicImp
+{
+ ConicPolarData mdata;
+public:
+ ConicImpPolar( const ConicPolarData& data );
+ ~ConicImpPolar();
+ ConicImpPolar* copy() const;
+
+ const ConicPolarData polarData() const;
+};
+
+#endif
diff --git a/kig/objects/conic_types.cc b/kig/objects/conic_types.cc
new file mode 100644
index 00000000..6e32f844
--- /dev/null
+++ b/kig/objects/conic_types.cc
@@ -0,0 +1,689 @@
+// 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 "conic_types.h"
+
+#include "bogus_imp.h"
+#include "conic_imp.h"
+#include "point_imp.h"
+#include "circle_imp.h"
+#include "line_imp.h"
+#include "object_calcer.h"
+#include "../misc/conic-common.h"
+#include "../misc/common.h"
+#include "../kig/kig_commands.h"
+#include "../kig/kig_part.h"
+
+#include <klocale.h>
+
+static const char conic_constructstatement[] = I18N_NOOP( "Construct a conic through this point" );
+
+static const struct ArgsParser::spec argsspecConicB5P[] =
+{
+ { PointImp::stype(), conic_constructstatement,
+ I18N_NOOP( "Select a point for the new conic to go through..." ), true },
+ { PointImp::stype(), conic_constructstatement,
+ I18N_NOOP( "Select a point for the new conic to go through..." ), true },
+ { PointImp::stype(), conic_constructstatement,
+ I18N_NOOP( "Select a point for the new conic to go through..." ), true },
+ { PointImp::stype(), conic_constructstatement,
+ I18N_NOOP( "Select a point for the new conic to go through..." ), true },
+ { PointImp::stype(), conic_constructstatement,
+ I18N_NOOP( "Select a point for the new conic to go through..." ),true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicB5PType )
+
+ConicB5PType::ConicB5PType()
+ : ArgsParserObjectType( "ConicB5P", argsspecConicB5P, 5 )
+{
+}
+
+ConicB5PType::~ConicB5PType()
+{
+}
+
+ObjectImp* ConicB5PType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 1 ) ) return new InvalidImp;
+ std::vector<Coordinate> points;
+
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ points.push_back( static_cast<const PointImp*>( *i )->coordinate() );
+
+ ConicCartesianData d =
+ calcConicThroughPoints( points, zerotilt, parabolaifzt, ysymmetry );
+ if ( d.valid() )
+ return new ConicImpCart( d );
+ else return new InvalidImp;
+}
+
+const ConicB5PType* ConicB5PType::instance()
+{
+ static const ConicB5PType t;
+ return &t;
+}
+
+static const ArgsParser::spec argsspecConicBAAP[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct a conic with this asymptote" ),
+ I18N_NOOP( "Select the first asymptote of the new conic..." ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct a conic with this asymptote" ),
+ I18N_NOOP( "Select the second asymptote of the new conic..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct a conic through this point" ),
+ I18N_NOOP( "Select a point for the new conic to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicBAAPType )
+
+ConicBAAPType::ConicBAAPType()
+ : ArgsParserObjectType( "ConicBAAP", argsspecConicBAAP, 3 )
+{
+}
+
+ConicBAAPType::~ConicBAAPType()
+{
+}
+
+const ConicBAAPType* ConicBAAPType::instance()
+{
+ static const ConicBAAPType t;
+ return &t;
+}
+
+ObjectImp* ConicBAAPType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) )
+ return new InvalidImp;
+ const LineData la = static_cast<const AbstractLineImp*>( parents[0] )->data();
+ const LineData lb = static_cast<const AbstractLineImp*>( parents[1] )->data();
+ const Coordinate c = static_cast<const PointImp*>( parents[2] )->coordinate();
+
+ return new ConicImpCart( calcConicByAsymptotes( la, lb, c ) );
+}
+
+ObjectImp* ConicBFFPType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+ std::vector<Coordinate> cs;
+
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ cs.push_back( static_cast<const PointImp*>( *i )->coordinate() );
+
+ return new ConicImpPolar( calcConicBFFP( cs, type() ) );
+}
+
+ConicBFFPType::ConicBFFPType( const char* fullname, const ArgsParser::spec* spec, int n )
+ : ArgsParserObjectType( fullname, spec, n )
+{
+}
+
+ConicBFFPType::~ConicBFFPType()
+{
+}
+
+static const char constructellipsewithfocusstat[] =
+ I18N_NOOP( "Construct an ellipse with this focus" );
+
+static const ArgsParser::spec argsspecEllipseBFFP[] =
+{
+ { PointImp::stype(), constructellipsewithfocusstat,
+ I18N_NOOP( "Select the first focus of the new ellipse..." ), false },
+ { PointImp::stype(), constructellipsewithfocusstat,
+ I18N_NOOP( "Select the second focus of the new ellipse..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct an ellipse through this point" ),
+ I18N_NOOP( "Select a point for the new ellipse to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( EllipseBFFPType )
+
+EllipseBFFPType::EllipseBFFPType()
+ : ConicBFFPType( "EllipseBFFP", argsspecEllipseBFFP, 3 )
+{
+}
+
+EllipseBFFPType::~EllipseBFFPType()
+{
+}
+
+int EllipseBFFPType::type() const
+{
+ return 1;
+}
+
+const EllipseBFFPType* EllipseBFFPType::instance()
+{
+ static const EllipseBFFPType t;
+ return &t;
+}
+
+static const char constructhyperbolawithfocusstat[] =
+ I18N_NOOP( "Construct a hyperbola with this focus" );
+
+static const ArgsParser::spec argsspecHyperbolaBFFP[] =
+{
+ { PointImp::stype(), constructhyperbolawithfocusstat,
+ I18N_NOOP( "Select the first focus of the new hyperbola..." ), false },
+ { PointImp::stype(), constructhyperbolawithfocusstat,
+ I18N_NOOP( "Select the second focus of the new hyperbola..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct a hyperbola through this point" ),
+ I18N_NOOP( "Select a point for the new hyperbola to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( HyperbolaBFFPType )
+
+HyperbolaBFFPType::HyperbolaBFFPType()
+ : ConicBFFPType( "HyperbolaBFFP", argsspecHyperbolaBFFP, 3 )
+{
+}
+
+HyperbolaBFFPType::~HyperbolaBFFPType()
+{
+}
+
+const HyperbolaBFFPType* HyperbolaBFFPType::instance()
+{
+ static const HyperbolaBFFPType t;
+ return &t;
+}
+
+int HyperbolaBFFPType::type() const
+{
+ return -1;
+}
+
+const ConicBDFPType* ConicBDFPType::instance()
+{
+ static const ConicBDFPType t;
+ return &t;
+}
+
+static const struct ArgsParser::spec argsspecConicBDFP[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct a conic with this line as directrix" ),
+ I18N_NOOP( "Select the directrix of the new conic..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct a conic with this point as focus" ),
+ I18N_NOOP( "Select the focus of the new conic..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct a conic through this point" ),
+ I18N_NOOP( "Select a point for the new conic to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicBDFPType )
+
+ConicBDFPType::ConicBDFPType()
+ : ArgsParserObjectType( "ConicBDFP", argsspecConicBDFP, 3 )
+{
+}
+
+ConicBDFPType::~ConicBDFPType()
+{
+}
+
+ObjectImp* ConicBDFPType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+
+ const LineData line = static_cast<const AbstractLineImp*>( parents[0] )->data();
+ const Coordinate focus =
+ static_cast<const PointImp*>( parents[1] )->coordinate();
+
+ Coordinate point;
+ if ( parents.size() == 3 )
+ point = static_cast<const PointImp*>( parents[2] )->coordinate();
+ else
+ {
+ /* !!!! costruisci point come punto medio dell'altezza tra fuoco e d. */
+ Coordinate ba = line.dir();
+ Coordinate fa = focus - line.b;
+ double balsq = ba.x*ba.x + ba.y*ba.y;
+ double scal = (fa.x*ba.x + fa.y*ba.y)/balsq;
+ point = 0.5*(line.a + focus + scal*ba);
+ };
+ return new ConicImpPolar( calcConicBDFP( line, focus, point ) );
+}
+
+static const char constructparabolathroughpointstat[] =
+ I18N_NOOP( "Construct a parabola through this point" );
+
+static const ArgsParser::spec argsspecParabolaBTP[] =
+{
+ { PointImp::stype(), constructparabolathroughpointstat,
+ I18N_NOOP( "Select a point for the new parabola to go through..." ), true },
+ { PointImp::stype(), constructparabolathroughpointstat,
+ I18N_NOOP( "Select a point for the new parabola to go through..." ), true },
+ { PointImp::stype(), constructparabolathroughpointstat,
+ I18N_NOOP( "Select a point for the new parabola to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ParabolaBTPType )
+
+ParabolaBTPType::ParabolaBTPType()
+ : ArgsParserObjectType( "ParabolaBTP", argsspecParabolaBTP, 3 )
+{
+}
+
+ParabolaBTPType::~ParabolaBTPType()
+{
+}
+
+const ParabolaBTPType* ParabolaBTPType::instance()
+{
+ static const ParabolaBTPType t;
+ return &t;
+}
+
+ObjectImp* ParabolaBTPType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> points;
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ points.push_back( static_cast<const PointImp*>( *i )->coordinate() );
+
+ ConicCartesianData d =
+ calcConicThroughPoints( points, zerotilt, parabolaifzt, ysymmetry );
+ if ( d.valid() )
+ return new ConicImpCart( d );
+ else
+ return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecConicPolarPoint[] =
+{
+ { ConicImp::stype(), I18N_NOOP( "Construct a polar point wrt. this conic" ),
+ I18N_NOOP( "Select the conic wrt. which you want to construct a polar point..." ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct the polar point of this line" ),
+ I18N_NOOP( "Select the line of which you want to construct the polar point..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicPolarPointType )
+
+ConicPolarPointType::ConicPolarPointType()
+ : ArgsParserObjectType( "ConicPolarPoint", argsspecConicPolarPoint, 2 )
+{
+}
+
+ConicPolarPointType::~ConicPolarPointType()
+{
+}
+
+const ConicPolarPointType* ConicPolarPointType::instance()
+{
+ static const ConicPolarPointType t;
+ return &t;
+}
+
+ObjectImp* ConicPolarPointType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const ConicCartesianData c = static_cast<const ConicImp*>( parents[0] )->cartesianData();
+ const LineData l = static_cast<const AbstractLineImp*>( parents[1] )->data();
+ const Coordinate p = calcConicPolarPoint( c, l );
+ if ( p.valid() ) return new PointImp( p );
+ else return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecConicPolarLine[] =
+{
+ { ConicImp::stype(), I18N_NOOP( "Construct a polar line wrt. this conic" ),
+ I18N_NOOP( "Select the conic wrt. which you want to construct a polar point..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct the polar line of this point" ),
+ I18N_NOOP( "Select the line of which you want to construct the polar point..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicPolarLineType )
+
+ConicPolarLineType::ConicPolarLineType()
+ : ArgsParserObjectType( "ConicPolarLine", argsspecConicPolarLine, 2 )
+{
+}
+
+ConicPolarLineType::~ConicPolarLineType()
+{
+}
+
+const ConicPolarLineType* ConicPolarLineType::instance()
+{
+ static const ConicPolarLineType t;
+ return &t;
+}
+
+ObjectImp* ConicPolarLineType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const ConicCartesianData c = static_cast<const ConicImp*>( parents[0] )->cartesianData();
+ const Coordinate p = static_cast<const PointImp*>( parents[1] )->coordinate();
+ bool valid = true;
+ const LineData l = calcConicPolarLine( c, p, valid );
+ if ( valid ) return new LineImp( l );
+ else return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecConicDirectrix[] =
+{
+ { ConicImp::stype(), I18N_NOOP( "Construct the directrix of this conic" ),
+ I18N_NOOP( "Select the conic of which you want to construct the directrix..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicDirectrixType )
+
+ConicDirectrixType::ConicDirectrixType()
+ : ArgsParserObjectType( "ConicDirectrix", argsspecConicDirectrix, 1 )
+{
+}
+
+ConicDirectrixType::~ConicDirectrixType()
+{
+}
+
+const ConicDirectrixType* ConicDirectrixType::instance()
+{
+ static const ConicDirectrixType t;
+ return &t;
+}
+
+ObjectImp* ConicDirectrixType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const ConicPolarData data =
+ static_cast<const ConicImp*>( parents[0] )->polarData();
+
+ double ec = data.ecostheta0;
+ double es = data.esintheta0;
+ double eccsq = ec*ec + es*es;
+
+ Coordinate a = data.focus1 - data.pdimen/eccsq*Coordinate(ec,es);
+ Coordinate b = a + Coordinate(-es,ec);
+ return new LineImp( a, b );
+}
+
+static const char hyperbolatpstatement[] = I18N_NOOP( "Construct a hyperbola through this point" );
+
+static const ArgsParser::spec argsspecHyperbolaB4P[] =
+{
+ { PointImp::stype(), hyperbolatpstatement,
+ I18N_NOOP( "Select a point for the new hyperbola to go through..." ), true },
+ { PointImp::stype(), hyperbolatpstatement,
+ I18N_NOOP( "Select a point for the new hyperbola to go through..." ), true },
+ { PointImp::stype(), hyperbolatpstatement,
+ I18N_NOOP( "Select a point for the new hyperbola to go through..." ), true },
+ { PointImp::stype(), hyperbolatpstatement,
+ I18N_NOOP( "Select a point for the new hyperbola to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( EquilateralHyperbolaB4PType )
+
+EquilateralHyperbolaB4PType::EquilateralHyperbolaB4PType()
+ : ArgsParserObjectType( "EquilateralHyperbolaB4P", argsspecHyperbolaB4P, 4 )
+{
+}
+
+EquilateralHyperbolaB4PType::~EquilateralHyperbolaB4PType()
+{
+}
+
+const EquilateralHyperbolaB4PType* EquilateralHyperbolaB4PType::instance()
+{
+ static const EquilateralHyperbolaB4PType t;
+ return &t;
+}
+
+ObjectImp* EquilateralHyperbolaB4PType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 1 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> pts;
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ pts.push_back( static_cast<const PointImp*>( *i )->coordinate() );
+
+ ConicCartesianData d = calcConicThroughPoints( pts, equilateral );
+ if ( d.valid() )
+ return new ConicImpCart( d );
+ else
+ return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecParabolaBDP[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct a parabola with this directrix" ),
+ I18N_NOOP( "Select the directrix of the new parabola..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct a parabola with this focus" ),
+ I18N_NOOP( "Select the focus of the new parabola..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ParabolaBDPType )
+
+ParabolaBDPType::ParabolaBDPType()
+ : ObjectLPType( "ParabolaBDP", argsspecParabolaBDP, 2 )
+{
+}
+
+ParabolaBDPType::~ParabolaBDPType()
+{
+}
+
+const ParabolaBDPType* ParabolaBDPType::instance()
+{
+ static const ParabolaBDPType t;
+ return &t;
+}
+
+ObjectImp* ParabolaBDPType::calc( const LineData& l, const Coordinate& c ) const
+{
+ ConicPolarData ret;
+ Coordinate ldir = l.dir();
+ ldir = ldir.normalize();
+ ret.focus1 = c;
+ ret.ecostheta0 = - ldir.y;
+ ret.esintheta0 = ldir.x;
+ Coordinate fa = c - l.a;
+ ret.pdimen = fa.y*ldir.x - fa.x*ldir.y;
+ ConicImpPolar* r = new ConicImpPolar( ret );
+ kdDebug() << k_funcinfo << r->conicTypeString() << endl;
+ return r;
+}
+
+static const ArgsParser::spec argsspecConicAsymptote[] =
+{
+ { ConicImp::stype(), I18N_NOOP( "Construct the asymptotes of this conic" ),
+ I18N_NOOP( "Select the conic of which you want to construct the asymptotes..." ), false },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicAsymptoteType )
+
+ConicAsymptoteType::ConicAsymptoteType()
+ : ArgsParserObjectType( "ConicAsymptote", argsspecConicAsymptote, 2 )
+{
+}
+
+ConicAsymptoteType::~ConicAsymptoteType()
+{
+}
+
+const ConicAsymptoteType* ConicAsymptoteType::instance()
+{
+ static const ConicAsymptoteType t;
+ return &t;
+}
+
+ObjectImp* ConicAsymptoteType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ bool valid = true;
+ const LineData ret = calcConicAsymptote(
+ static_cast<const ConicImp*>( parents[0] )->cartesianData(),
+ static_cast<const IntImp*>( parents[1] )->data(),
+ valid );
+
+ if ( valid )
+ return new LineImp( ret );
+ else
+ return new InvalidImp;
+}
+
+static const char radicallinesstatement[] = I18N_NOOP( "Construct the radical lines of this conic" );
+
+static const ArgsParser::spec argsspecConicRadical[] =
+{
+ { ConicImp::stype(), radicallinesstatement,
+ I18N_NOOP( "Select the first of the two conics of which you want to construct the radical line..." ), false },
+ { ConicImp::stype(), radicallinesstatement,
+ I18N_NOOP( "Select the other of the two conic of which you want to construct the radical line..." ), false },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicRadicalType )
+
+ConicRadicalType::ConicRadicalType()
+ : ArgsParserObjectType( "ConicRadical", argsspecConicRadical, 4 )
+{
+}
+
+const ConicRadicalType* ConicRadicalType::instance()
+{
+ static const ConicRadicalType t;
+ return &t;
+}
+
+ObjectImp* ConicRadicalType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ if ( parents[0]->inherits( CircleImp::stype() ) &&
+ parents[1]->inherits( CircleImp::stype() ) )
+ {
+ if( static_cast<const IntImp*>( parents[2] )->data() != 1 )
+ return new InvalidImp;
+ else
+ {
+ const CircleImp* c1 = static_cast<const CircleImp*>( parents[0] );
+ const CircleImp* c2 = static_cast<const CircleImp*>( parents[1] );
+ const Coordinate a = calcCircleRadicalStartPoint(
+ c1->center(), c2->center(), c1->squareRadius(), c2->squareRadius()
+ );
+ return new LineImp( a, calcPointOnPerpend(
+ LineData( c1->center(), c2->center() ), a ) );
+ };
+ }
+ else
+ {
+ bool valid = true;
+ const LineData l = calcConicRadical(
+ static_cast<const ConicImp*>( parents[0] )->cartesianData(),
+ static_cast<const ConicImp*>( parents[1] )->cartesianData(),
+ static_cast<const IntImp*>( parents[2] )->data(),
+ static_cast<const IntImp*>( parents[3] )->data(), valid );
+ if ( valid )
+ return new LineImp( l );
+ else
+ return new InvalidImp;
+ };
+}
+
+ConicRadicalType::~ConicRadicalType()
+{
+}
+
+const ObjectImpType* ConicB5PType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* ConicBAAPType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* ConicBFFPType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* ConicBDFPType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* ParabolaBTPType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* EquilateralHyperbolaB4PType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* ConicPolarPointType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* ConicPolarLineType::resultId() const
+{
+ return LineImp::stype();
+}
+
+const ObjectImpType* ConicDirectrixType::resultId() const
+{
+ return LineImp::stype();
+}
+
+const ObjectImpType* ParabolaBDPType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* ConicAsymptoteType::resultId() const
+{
+ return LineImp::stype();
+}
+
+const ObjectImpType* ConicRadicalType::resultId() const
+{
+ return LineImp::stype();
+}
+
+QStringList ConicRadicalType::specialActions() const
+{
+ QStringList ret;
+ ret << i18n( "Switch Radical Lines" );
+ return ret;
+}
+
+void ConicRadicalType::executeAction( int i, ObjectHolder&, ObjectTypeCalcer& t,
+ KigPart& d, KigWidget&, NormalMode& ) const
+{
+ assert( i == 0 );
+ std::vector<ObjectCalcer*> parents = t.parents();
+ assert( dynamic_cast<ObjectConstCalcer*>( parents[3] ) );
+ ObjectConstCalcer* zeroindexo = static_cast<ObjectConstCalcer*>( parents[3] );
+ MonitorDataObjects mon( zeroindexo );
+ assert( zeroindexo->imp()->inherits( IntImp::stype() ) );
+ int oldzeroindex = static_cast<const IntImp*>( zeroindexo->imp() )->data();
+ int newzeroindex = oldzeroindex % 3 + 1;
+ zeroindexo->setImp( new IntImp( newzeroindex ) );
+ KigCommand* kc = new KigCommand( d, "Switch Conic Radical Lines" );
+ mon.finish( kc );
+ d.history()->addCommand( kc );
+}
+
diff --git a/kig/objects/conic_types.h b/kig/objects/conic_types.h
new file mode 100644
index 00000000..e2a1881d
--- /dev/null
+++ b/kig/objects/conic_types.h
@@ -0,0 +1,184 @@
+// 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.
+
+#ifndef KIG_OBJECTS_CONIC_TYPES_H
+#define KIG_OBJECTS_CONIC_TYPES_H
+
+#include "base_type.h"
+
+class ConicB5PType
+ : public ArgsParserObjectType
+{
+ ConicB5PType();
+ ~ConicB5PType();
+public:
+ static const ConicB5PType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicBAAPType
+ : public ArgsParserObjectType
+{
+ ConicBAAPType();
+ ~ConicBAAPType();
+public:
+ static const ConicBAAPType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicBFFPType
+ : public ArgsParserObjectType
+{
+protected:
+ ConicBFFPType( const char* fullname, const ArgsParser::spec*, int n );
+ ~ConicBFFPType();
+public:
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+
+ /**
+ * -1 for hyperbola, 1 for ellipse..
+ */
+ virtual int type() const = 0;
+ const ObjectImpType* resultId() const;
+};
+
+class EllipseBFFPType
+ : public ConicBFFPType
+{
+ EllipseBFFPType();
+ ~EllipseBFFPType();
+public:
+ static const EllipseBFFPType* instance();
+ int type() const;
+};
+
+class HyperbolaBFFPType
+ : public ConicBFFPType
+{
+ HyperbolaBFFPType();
+ ~HyperbolaBFFPType();
+public:
+ static const HyperbolaBFFPType* instance();
+ int type() const;
+};
+
+class ConicBDFPType
+ : public ArgsParserObjectType
+{
+ ConicBDFPType();
+ ~ConicBDFPType();
+public:
+ static const ConicBDFPType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ParabolaBTPType
+ : public ArgsParserObjectType
+{
+ ParabolaBTPType();
+ ~ParabolaBTPType();
+public:
+ static const ParabolaBTPType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class EquilateralHyperbolaB4PType
+ : public ArgsParserObjectType
+{
+ EquilateralHyperbolaB4PType();
+ ~EquilateralHyperbolaB4PType();
+public:
+ static const EquilateralHyperbolaB4PType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicPolarPointType
+ : public ArgsParserObjectType
+{
+ ConicPolarPointType();
+ ~ConicPolarPointType();
+public:
+ static const ConicPolarPointType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicPolarLineType
+ : public ArgsParserObjectType
+{
+ ConicPolarLineType();
+ ~ConicPolarLineType();
+public:
+ static const ConicPolarLineType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicDirectrixType
+ : public ArgsParserObjectType
+{
+ ConicDirectrixType();
+ ~ConicDirectrixType();
+public:
+ static const ConicDirectrixType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ParabolaBDPType
+ : public ObjectLPType
+{
+ ParabolaBDPType();
+ ~ParabolaBDPType();
+public:
+ static const ParabolaBDPType* instance();
+ ObjectImp* calc( const LineData& l, const Coordinate& c ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicAsymptoteType
+ : public ArgsParserObjectType
+{
+ ConicAsymptoteType();
+ ~ConicAsymptoteType();
+public:
+ static const ConicAsymptoteType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicRadicalType
+ : public ArgsParserObjectType
+{
+ ConicRadicalType();
+ ~ConicRadicalType();
+public:
+ static const ConicRadicalType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+ QStringList specialActions() const;
+ void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& t,
+ KigPart& d, KigWidget& w, NormalMode& m ) const;
+};
+
+#endif
+
diff --git a/kig/objects/cubic_imp.cc b/kig/objects/cubic_imp.cc
new file mode 100644
index 00000000..51bb5d9f
--- /dev/null
+++ b/kig/objects/cubic_imp.cc
@@ -0,0 +1,437 @@
+// 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 "cubic_imp.h"
+
+#include "bogus_imp.h"
+
+#include "../misc/kigpainter.h"
+#include "../misc/screeninfo.h"
+#include "../misc/kignumerics.h"
+#include "../misc/common.h"
+#include "../kig/kig_view.h"
+
+#include <math.h>
+#include <klocale.h>
+
+CubicImp::CubicImp( const CubicCartesianData& data )
+ : CurveImp(), mdata( data )
+{
+}
+
+CubicImp::~CubicImp()
+{
+}
+
+ObjectImp* CubicImp::transform( const Transformation& t ) const
+{
+ bool valid = true;
+ CubicCartesianData d = calcCubicTransformation( data(), t, valid );
+ if ( valid ) return new CubicImp( d );
+ else return new InvalidImp;
+}
+
+void CubicImp::draw( KigPainter& p ) const
+{
+ p.drawCurve( this );
+}
+
+bool CubicImp::contains( const Coordinate& o, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( o, w.screenInfo().normalMiss( width ) );
+}
+
+bool CubicImp::inRect( const Rect&, int, const KigWidget& ) const
+{
+ // TODO ?
+ return false;
+}
+
+CubicImp* CubicImp::copy() const
+{
+ return new CubicImp( mdata );
+}
+
+double CubicImp::getParam( const Coordinate& p, const KigDocument& ) const
+{
+ double x = p.x;
+ double y = p.y;
+ double t;
+
+ double a000 = mdata.coeffs[0];
+ double a001 = mdata.coeffs[1];
+ double a002 = mdata.coeffs[2];
+ double a011 = mdata.coeffs[3];
+ double a012 = mdata.coeffs[4];
+ double a022 = mdata.coeffs[5];
+ double a111 = mdata.coeffs[6];
+ double a112 = mdata.coeffs[7];
+ double a122 = mdata.coeffs[8];
+ double a222 = mdata.coeffs[9];
+
+ /*
+ * first project p onto the cubic. This is done by computing the
+ * line through p in the direction of the gradient
+ */
+
+ double f = a000 + a001*x + a002*y + a011*x*x + a012*x*y + a022*y*y +
+ a111*x*x*x + a112*x*x*y + a122*x*y*y + a222*y*y*y;
+ if ( f != 0 )
+ {
+ double fx = a001 + 2*a011*x + a012*y + 3*a111*x*x + 2*a112*x*y + a122*y*y;
+ double fy = a002 + 2*a022*y + a012*x + 3*a222*y*y + 2*a122*x*y + a112*x*x;
+ Coordinate v = Coordinate (fx, fy);
+ if ( f < 0 ) v = -v; // the line points away from the intersection
+ double a, b, c, d;
+ calcCubicLineRestriction ( mdata, p, v, a, b, c, d );
+ if ( a < 0 )
+ {
+ a *= -1;
+ b *= -1;
+ c *= -1;
+ d *= -1;
+ }
+
+ // computing the coefficients of the Sturm sequence
+ double p1a = 2*b*b - 6*a*c;
+ double p1b = b*c - 9*a*d;
+ double p0a = c*p1a*p1a + p1b*(3*a*p1b - 2*b*p1a);
+ // compute the number of roots for negative lambda
+ int variations = calcCubicVariations ( 0, a, b, c, d, p1a, p1b, p0a );
+ bool valid;
+ int numroots;
+ double lambda = calcCubicRoot ( -1e10, 1e10, a, b, c, d, variations, valid,
+ numroots );
+ if ( valid )
+ {
+ Coordinate pnew = p + lambda*v;
+ x = pnew.x;
+ y = pnew.y;
+ }
+ }
+
+ if (x > 0) t = x/(1+x);
+ else t = x/(1-x);
+ t = 0.5*(t + 1);
+ t /= 3;
+
+ Coordinate p1 = getPoint ( t );
+ Coordinate p2 = getPoint ( t + 1.0/3.0 );
+ Coordinate p3 = getPoint ( t + 2.0/3.0 );
+
+ double mint = t;
+ double mindist = p1.valid() ? fabs ( y - p1.y ) : double_inf;
+ if ( p2.valid() && fabs ( y - p2.y ) < mindist )
+ {
+ mint = t + 1.0/3.0;
+ mindist = fabs ( y - p2.y );
+ }
+ if ( p3.valid() && fabs ( y - p3.y ) < mindist )
+ {
+ mint = t + 2.0/3.0;
+ }
+
+ return mint;
+}
+
+const Coordinate CubicImp::getPoint( double p, const KigDocument& ) const
+{
+ return getPoint( p );
+}
+
+const Coordinate CubicImp::getPoint( double p ) const
+{
+ /*
+ * this isn't really elegant...
+ * the magnitude of p tells which one of the maximum 3 intersections
+ * of the vertical line with the cubic to take.
+ */
+
+ p *= 3;
+ int root = (int) p;
+ assert ( root >= 0 );
+ assert ( root <= 3 );
+ if ( root == 3 ) root = 2;
+
+ p -= root;
+
+ assert ( 0 <= p && p <= 1 );
+ if ( p <= 0. ) p = 1e-6;
+ if ( p >= 1. ) p = 1 - 1e-6;
+ root++;
+ p = 2*p - 1;
+ double x;
+ if (p > 0) x = p/(1 - p);
+ else x = p/(1 + p);
+
+ // calc the third degree polynomial:
+ // compute the third degree polinomial:
+// double a000 = mdata.coeffs[0];
+// double a001 = mdata.coeffs[1];
+// double a002 = mdata.coeffs[2];
+// double a011 = mdata.coeffs[3];
+// double a012 = mdata.coeffs[4];
+// double a022 = mdata.coeffs[5];
+// double a111 = mdata.coeffs[6];
+// double a112 = mdata.coeffs[7];
+// double a122 = mdata.coeffs[8];
+// double a222 = mdata.coeffs[9];
+//
+// // first the y^3 coefficient, it coming only from a222:
+// double a = a222;
+// // next the y^2 coefficient (from a122 and a022):
+// double b = a122*x + a022;
+// // next the y coefficient (from a112, a012 and a002):
+// double c = a112*x*x + a012*x + a002;
+// // finally the constant coefficient (from a111, a011, a001 and a000):
+// double d = a111*x*x*x + a011*x*x + a001*x + a000;
+
+// commented out, since the bound is already computed when passing a huge
+// interval; the normalization is not needed also
+
+ // renormalize: positive a
+// if ( a < 0 )
+// {
+// a *= -1;
+// b *= -1;
+// c *= -1;
+// d *= -1;
+// }
+//
+// const double small = 1e-7;
+// int degree = 3;
+// if ( fabs(a) < small*fabs(b) ||
+// fabs(a) < small*fabs(c) ||
+// fabs(a) < small*fabs(d) )
+// {
+// degree = 2;
+// if ( fabs(b) < small*fabs(c) ||
+// fabs(b) < small*fabs(d) )
+// {
+// degree = 1;
+// }
+// }
+
+// and a bound for all the real roots:
+
+// double bound;
+// switch (degree)
+// {
+// case 3:
+// bound = fabs(d/a);
+// if ( fabs(c/a) + 1 > bound ) bound = fabs(c/a) + 1;
+// if ( fabs(b/a) + 1 > bound ) bound = fabs(b/a) + 1;
+// break;
+//
+// case 2:
+// bound = fabs(d/b);
+// if ( fabs(c/b) + 1 > bound ) bound = fabs(c/b) + 1;
+// break;
+//
+// case 1:
+// default:
+// bound = fabs(d/c) + 1;
+// break;
+// }
+
+ int numroots;
+ bool valid = true;
+ double y = calcCubicYvalue ( x, -double_inf, double_inf, root, mdata, valid,
+ numroots );
+ if ( ! valid ) return Coordinate::invalidCoord();
+ else return Coordinate(x,y);
+// if ( valid ) return Coordinate(x,y);
+// root--; if ( root <= 0) root += 3;
+// y = calcCubicYvalue ( x, -bound, bound, root, mdata, valid,
+// numroots );
+// if ( valid ) return Coordinate(x,y);
+// root--; if ( root <= 0) root += 3;
+// y = calcCubicYvalue ( x, -bound, bound, root, mdata, valid,
+// numroots );
+// assert ( valid );
+// return Coordinate(x,y);
+}
+
+const uint CubicImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 1;
+}
+
+const QCStringList CubicImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l << "cartesian-equation";
+ assert( l.size() == CubicImp::numberOfProperties() );
+ return l;
+
+}
+
+/*
+ * cartesian equation property contributed by Carlo Sardi
+ */
+
+const QCStringList CubicImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Cartesian Equation" );
+ assert( l.size() == CubicImp::numberOfProperties() );
+ return l;
+
+}
+
+const ObjectImpType* CubicImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return CubicImp::stype();
+}
+
+const char* CubicImp::iconForProperty( uint which ) const
+{
+ int pnum = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() + pnum++ )
+ return "kig_text"; // cartesian equation string
+ else
+ assert( false );
+ return "";
+}
+
+ObjectImp* CubicImp::property( uint which, const KigDocument& w ) const
+{
+ int pnum = 0;
+
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ if ( which == Parent::numberOfProperties() + pnum++ )
+ return new StringImp( cartesianEquationString( w ) );
+ else
+ assert( false );
+ return new InvalidImp;
+}
+
+const CubicCartesianData CubicImp::data() const
+{
+ return mdata;
+}
+
+void CubicImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool CubicImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( CubicImp::stype() ) &&
+ static_cast<const CubicImp&>( rhs ).data() == data();
+}
+
+const ObjectImpType* CubicImp::type() const
+{
+ return CubicImp::stype();
+}
+
+const ObjectImpType* CubicImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "cubic",
+ I18N_NOOP( "cubic curve" ),
+ I18N_NOOP( "Select this cubic curve" ),
+ I18N_NOOP( "Select cubic curve %1" ),
+ I18N_NOOP( "Remove a Cubic Curve" ),
+ I18N_NOOP( "Add a Cubic Curve" ),
+ I18N_NOOP( "Move a Cubic Curve" ),
+ I18N_NOOP( "Attach to this cubic curve" ),
+ I18N_NOOP( "Show a Cubic Curve" ),
+ I18N_NOOP( "Hide a Cubic Curve" )
+ );
+ return &t;
+}
+
+bool CubicImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool CubicImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ double a000 = mdata.coeffs[0];
+ double a001 = mdata.coeffs[1];
+ double a002 = mdata.coeffs[2];
+ double a011 = mdata.coeffs[3];
+ double a012 = mdata.coeffs[4];
+ double a022 = mdata.coeffs[5];
+ double a111 = mdata.coeffs[6];
+ double a112 = mdata.coeffs[7];
+ double a122 = mdata.coeffs[8];
+ double a222 = mdata.coeffs[9];
+
+ double x = p.x;
+ double y = p.y;
+
+ double f = a000 + a001*x + a002*y + a011*x*x + a012*x*y + a022*y*y +
+ a111*x*x*x + a112*x*x*y + a122*x*y*y + a222*y*y*y;
+ double fx = a001 + 2*a011*x + a012*y + 3*a111*x*x + 2*a112*x*y + a122*y*y;
+ double fy = a002 + a012*x + 2*a022*y + a112*x*x + 2*a122*x*y + 3*a222*y*y;
+
+ double dist = fabs(f)/(fabs(fx) + fabs(fy));
+
+ return dist <= threshold;
+}
+
+bool CubicImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+}
+
+Rect CubicImp::surroundingRect() const
+{
+ // it's probably possible to calculate this if it exists, but for
+ // now we don't.
+ return Rect::invalidRect();
+}
+
+QString CubicImp::cartesianEquationString( const KigDocument& ) const
+{
+ /*
+ * unfortunately QStrings.arg method is limited to %1, %9, so we cannot
+ * treat all 10 arguments! Let's split the equation in two parts...
+ * Now this ends up also in the translation machinery, is this really
+ * necessary? Otherwise we could do a little bit of tidy up on the
+ * the equation (removal of zeros, avoid " ... + -1234 x ", etc.)
+ */
+
+ QString ret = i18n( "%6 x³ + %9 y³ + %7 x²y + %8 xy² + %5 y² + %3 x² + %4 xy + %1 x + %2 y" );
+ ret = ret.arg( mdata.coeffs[1], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[2], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[3], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[4], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[5], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[6], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[7], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[8], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[9], 0, 'g', 3 );
+
+ ret.append( i18n( " + %1 = 0" ) );
+ ret = ret.arg( mdata.coeffs[0], 0, 'g', 3 );
+
+ // we should find a common place to do this...
+ ret.replace( "+ -", "- " );
+ ret.replace( "+-", "-" );
+ return ret;
+}
diff --git a/kig/objects/cubic_imp.h b/kig/objects/cubic_imp.h
new file mode 100644
index 00000000..bb7d89c7
--- /dev/null
+++ b/kig/objects/cubic_imp.h
@@ -0,0 +1,81 @@
+// 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.
+
+#ifndef KIG_OBJECTS_CUBIC_IMP_H
+#define KIG_OBJECTS_CUBIC_IMP_H
+
+#include "curve_imp.h"
+
+#include "../misc/cubic-common.h"
+
+class LineData;
+
+/**
+ * An ObjectImp representing a cubic.
+ */
+class CubicImp
+ : public CurveImp
+{
+ const CubicCartesianData mdata;
+public:
+ typedef CurveImp Parent;
+ static const ObjectImpType* stype();
+
+ CubicImp( const CubicCartesianData& data );
+ ~CubicImp();
+
+ ObjectImp* transform( const Transformation& ) const;
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ Rect surroundingRect() const;
+ QString cartesianEquationString( const KigDocument& ) const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ CubicImp* copy() const;
+
+ double getParam( const Coordinate& point, const KigDocument& ) const;
+
+ // The getPoint function doesn't need the KigDocument argument, the
+ // first getPoint function is identical to the other one. It is
+ // only provided for implementing the CurveImp interface.
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+ const Coordinate getPoint( double param ) const;
+
+public:
+ /**
+ * Return the cartesian representation of this cubic.
+ */
+ const CubicCartesianData data() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+#endif
diff --git a/kig/objects/cubic_type.cc b/kig/objects/cubic_type.cc
new file mode 100644
index 00000000..c322b8c3
--- /dev/null
+++ b/kig/objects/cubic_type.cc
@@ -0,0 +1,185 @@
+// 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 "cubic_type.h"
+
+#include "cubic_imp.h"
+#include "point_imp.h"
+#include "bogus_imp.h"
+
+#include <klocale.h>
+
+static const char cubictpstatement[] = I18N_NOOP( "Construct a cubic curve through this point" );
+
+static const struct ArgsParser::spec argsspecCubicB9P[] =
+{
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CubicB9PType )
+
+CubicB9PType::CubicB9PType()
+ : ArgsParserObjectType( "CubicB9P", argsspecCubicB9P, 9 )
+{
+}
+
+CubicB9PType::~CubicB9PType()
+{
+}
+
+const CubicB9PType* CubicB9PType::instance()
+{
+ static const CubicB9PType t;
+ return &t;
+}
+
+ObjectImp* CubicB9PType::calc( const Args& os, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( os, 2 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> points;
+ for ( uint i = 0; i < os.size(); ++i )
+ points.push_back( static_cast<const PointImp*>( os[i] )->coordinate() );
+
+ CubicCartesianData d = calcCubicThroughPoints( points );
+ if ( d.valid() )
+ return new CubicImp( d );
+ else
+ return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecCubicNodeB6P[] =
+{
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CubicNodeB6PType )
+
+CubicNodeB6PType::CubicNodeB6PType()
+ : ArgsParserObjectType( "CubicNodeB6P", argsspecCubicNodeB6P, 6 )
+{
+}
+
+CubicNodeB6PType::~CubicNodeB6PType()
+{
+}
+
+const CubicNodeB6PType* CubicNodeB6PType::instance()
+{
+ static const CubicNodeB6PType t;
+ return &t;
+}
+
+ObjectImp* CubicNodeB6PType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> points;
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ points.push_back( static_cast<const PointImp*>( *i )->coordinate() );
+
+ CubicCartesianData d = calcCubicNodeThroughPoints( points );
+ if ( d.valid() )
+ return new CubicImp( d );
+ else
+ return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecCubicCuspB4P[] =
+{
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CubicCuspB4PType )
+
+CubicCuspB4PType::CubicCuspB4PType()
+ : ArgsParserObjectType( "CubicCuspB4P", argsspecCubicCuspB4P, 4 )
+{
+}
+
+CubicCuspB4PType::~CubicCuspB4PType()
+{
+}
+
+const CubicCuspB4PType* CubicCuspB4PType::instance()
+{
+ static const CubicCuspB4PType t;
+ return &t;
+}
+
+ObjectImp* CubicCuspB4PType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> points;
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ points.push_back( static_cast<const PointImp*>( *i )->coordinate() );
+
+ CubicCartesianData d = calcCubicCuspThroughPoints( points );
+ if ( d.valid() ) return new CubicImp( d );
+ else return new InvalidImp;
+}
+
+const ObjectImpType* CubicB9PType::resultId() const
+{
+ return CubicImp::stype();
+}
+
+const ObjectImpType* CubicNodeB6PType::resultId() const
+{
+ return CubicImp::stype();
+}
+
+const ObjectImpType* CubicCuspB4PType::resultId() const
+{
+ return CubicImp::stype();
+}
diff --git a/kig/objects/cubic_type.h b/kig/objects/cubic_type.h
new file mode 100644
index 00000000..39be7387
--- /dev/null
+++ b/kig/objects/cubic_type.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef KIG_OBJECTS_CUBIC_TYPE_H
+#define KIG_OBJECTS_CUBIC_TYPE_H
+
+#include "object_type.h"
+
+class CubicB9PType
+ : public ArgsParserObjectType
+{
+ CubicB9PType();
+ ~CubicB9PType();
+public:
+ static const CubicB9PType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class CubicNodeB6PType
+ : public ArgsParserObjectType
+{
+ CubicNodeB6PType();
+ ~CubicNodeB6PType();
+public:
+ static const CubicNodeB6PType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class CubicCuspB4PType
+ : public ArgsParserObjectType
+{
+ CubicCuspB4PType();
+ ~CubicCuspB4PType();
+public:
+ static const CubicCuspB4PType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/curve_imp.cc b/kig/objects/curve_imp.cc
new file mode 100644
index 00000000..315cd8cb
--- /dev/null
+++ b/kig/objects/curve_imp.cc
@@ -0,0 +1,41 @@
+// Copyright (C) 2002 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 "curve_imp.h"
+#include "../misc/coordinate.h"
+
+const ObjectImpType* CurveImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "curve",
+ I18N_NOOP( "curve" ),
+ I18N_NOOP( "Select this curve" ),
+ I18N_NOOP( "Select curve %1" ),
+ I18N_NOOP( "Remove a Curve" ),
+ I18N_NOOP( "Add a Curve" ),
+ I18N_NOOP( "Move a Curve" ),
+ I18N_NOOP( "Attach to this curve" ),
+ I18N_NOOP( "Show a Curve" ),
+ I18N_NOOP( "Hide a Curve" )
+ );
+ return &t;
+}
+
+Coordinate CurveImp::attachPoint() const
+{
+ return Coordinate::invalidCoord();
+}
diff --git a/kig/objects/curve_imp.h b/kig/objects/curve_imp.h
new file mode 100644
index 00000000..3a33a722
--- /dev/null
+++ b/kig/objects/curve_imp.h
@@ -0,0 +1,62 @@
+// Copyright (C) 2002 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.
+
+#ifndef KIG_OBJECTS_CURVE_IMP_H
+#define KIG_OBJECTS_CURVE_IMP_H
+
+#include "object_imp.h"
+
+/**
+ * This class represents a curve: something which is composed of
+ * points, like a line, a circle, a locus...
+ */
+class CurveImp
+ : public ObjectImp
+{
+public:
+ typedef ObjectImp Parent;
+
+ /**
+ * Returns the ObjectImpType representing the CurveImp type.
+ */
+ static const ObjectImpType* stype();
+
+ Coordinate attachPoint() const;
+
+ // param is between 0 and 1. Note that 0 and 1 should be the
+ // end-points. E.g. for a Line, getPoint(0) returns a more or less
+ // infinite point. getPoint(0.5) should return the point in the
+ // middle.
+ virtual double getParam( const Coordinate& point, const KigDocument& ) const = 0;
+ // this should be the inverse function of getPoint().
+ // Note that it should also do something reasonable when p is not on
+ // the curve. You can return an invalid Coordinate(
+ // Coordinate::invalidCoord() ) if you need to in some cases.
+ virtual const Coordinate getPoint( double param, const KigDocument& ) const = 0;
+
+ virtual CurveImp* copy() const = 0;
+
+ /**
+ * Return whether this Curve contains the given point. This is
+ * implemented as a numerical approximation. Implementations
+ * can/should use the value test_threshold in common.h as a
+ * threshold value.
+ */
+ virtual bool containsPoint( const Coordinate& p, const KigDocument& ) const = 0;
+};
+
+#endif
diff --git a/kig/objects/intersection_types.cc b/kig/objects/intersection_types.cc
new file mode 100644
index 00000000..804d498d
--- /dev/null
+++ b/kig/objects/intersection_types.cc
@@ -0,0 +1,338 @@
+// 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 "intersection_types.h"
+
+#include "bogus_imp.h"
+#include "circle_imp.h"
+#include "conic_imp.h"
+#include "cubic_imp.h"
+#include "line_imp.h"
+#include "other_imp.h"
+#include "point_imp.h"
+
+#include <klocale.h>
+
+static const char intersectlinestat[] = I18N_NOOP( "Intersect with this line" );
+
+static const ArgsParser::spec argsspecConicLineIntersection[] =
+{
+ { ConicImp::stype(), I18N_NOOP( "Intersect with this conic" ),
+ "SHOULD NOT BE SEEN", true },
+ { AbstractLineImp::stype(), intersectlinestat, "SHOULD NOT BE SEEN", true },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicLineIntersectionType )
+
+ConicLineIntersectionType::ConicLineIntersectionType()
+ : ArgsParserObjectType( "ConicLineIntersection",
+ argsspecConicLineIntersection, 3 )
+{
+}
+
+ConicLineIntersectionType::~ConicLineIntersectionType()
+{
+}
+
+const ConicLineIntersectionType* ConicLineIntersectionType::instance()
+{
+ static const ConicLineIntersectionType t;
+ return &t;
+}
+
+ObjectImp* ConicLineIntersectionType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ int side = static_cast<const IntImp*>( parents[2] )->data();
+ assert( side == 1 || side == -1 );
+ const LineData line = static_cast<const AbstractLineImp*>( parents[1] )->data();
+
+ Coordinate ret;
+ if ( parents[0]->inherits( CircleImp::stype() ) )
+ {
+ // easy case..
+ const CircleImp* c = static_cast<const CircleImp*>( parents[0] );
+ ret = calcCircleLineIntersect(
+ c->center(), c->squareRadius(), line, side );
+ }
+ else
+ {
+ // harder case..
+ ret = calcConicLineIntersect(
+ static_cast<const ConicImp*>( parents[0] )->cartesianData(),
+ line, 0.0, side );
+ }
+ if ( ret.valid() ) return new PointImp( ret );
+ else return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecConicLineOtherIntersection[] =
+{
+ { ConicImp::stype(), I18N_NOOP( "Intersect with this conic" ),
+ "SHOULD NOT BE SEEN", true },
+ { AbstractLineImp::stype(), intersectlinestat, "SHOULD NOT BE SEEN", true },
+ { PointImp::stype(), I18N_NOOP( "Already computed intersection point"),
+ "SHOULD NOT BE SEEN", true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicLineOtherIntersectionType )
+
+ConicLineOtherIntersectionType::ConicLineOtherIntersectionType()
+ : ArgsParserObjectType( "ConicLineOtherIntersection",
+ argsspecConicLineOtherIntersection, 3 )
+{
+}
+
+ConicLineOtherIntersectionType::~ConicLineOtherIntersectionType()
+{
+}
+
+const ConicLineOtherIntersectionType* ConicLineOtherIntersectionType::instance()
+{
+ static const ConicLineOtherIntersectionType t;
+ return &t;
+}
+
+ObjectImp* ConicLineOtherIntersectionType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ Coordinate p = static_cast<const PointImp*>( parents[2] )->coordinate();
+ const LineData line = static_cast<const AbstractLineImp*>( parents[1] )->data();
+
+ Coordinate ret;
+// if ( parents[0]->inherits( CircleImp::stype() ) )
+// {
+// // easy case..
+// const CircleImp* c = static_cast<const CircleImp*>( parents[0] );
+// ret = calcCircleLineIntersect(
+// c->center(), c->squareRadius(), line, side, valid );
+// }
+// else
+// {
+ // harder case..
+ double pax = p.x - line.a.x;
+ double pay = p.y - line.a.y;
+ double bax = line.b.x - line.a.x;
+ double bay = line.b.y - line.a.y;
+ double knownparam = (pax*bax + pay*bay)/(bax*bax + bay*bay);
+ ret = calcConicLineIntersect(
+ static_cast<const ConicImp*>( parents[0] )->cartesianData(),
+ line, knownparam, 0 );
+// }
+ if ( ret.valid() ) return new PointImp( ret );
+ else return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecLineLineIntersection[] =
+{
+ { AbstractLineImp::stype(), intersectlinestat, "SHOULD NOT BE SEEN", true },
+ { AbstractLineImp::stype(), intersectlinestat, "SHOULD NOT BE SEEN", true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LineLineIntersectionType )
+
+LineLineIntersectionType::LineLineIntersectionType()
+ : ArgsParserObjectType( "LineLineIntersection",
+ argsspecLineLineIntersection, 2 )
+{
+}
+
+LineLineIntersectionType::~LineLineIntersectionType()
+{
+}
+
+const LineLineIntersectionType* LineLineIntersectionType::instance()
+{
+ static const LineLineIntersectionType t;
+ return &t;
+}
+
+ObjectImp* LineLineIntersectionType::calc( const Args& parents, const KigDocument& d ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ Coordinate p =
+ calcIntersectionPoint(
+ static_cast<const AbstractLineImp*>( parents[0] )->data(),
+ static_cast<const AbstractLineImp*>( parents[1] )->data() );
+ if ( static_cast<const AbstractLineImp*>( parents[0] )->containsPoint( p, d ) &&
+ static_cast<const AbstractLineImp*>( parents[1] )->containsPoint( p, d ) )
+ return new PointImp( p );
+ else return new InvalidImp();
+}
+
+static const ArgsParser::spec argsspecLineCubicIntersection[] =
+{
+ { CubicImp::stype(), I18N_NOOP( "Intersect with this cubic curve" ),
+ "SHOULD NOT BE SEEN", true },
+ { AbstractLineImp::stype(), intersectlinestat, "SHOULD NOT BE SEEN", true },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LineCubicIntersectionType )
+
+LineCubicIntersectionType::LineCubicIntersectionType()
+ : ArgsParserObjectType( "LineCubicIntersection",
+ argsspecLineCubicIntersection, 3 )
+{
+}
+
+LineCubicIntersectionType::~LineCubicIntersectionType()
+{
+}
+
+const LineCubicIntersectionType* LineCubicIntersectionType::instance()
+{
+ static const LineCubicIntersectionType t;
+ return &t;
+}
+
+ObjectImp* LineCubicIntersectionType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ int which = static_cast<const IntImp*>( parents[2] )->data();
+ bool valid = true;
+ const Coordinate c = calcCubicLineIntersect(
+ static_cast<const CubicImp*>( parents[0] )->data(),
+ static_cast<const AbstractLineImp*>( parents[1] )->data(),
+ which, valid );
+ if ( valid ) return new PointImp( c );
+ else return new InvalidImp;
+}
+
+const ObjectImpType* ConicLineIntersectionType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* ConicLineOtherIntersectionType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* LineLineIntersectionType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* LineCubicIntersectionType::resultId() const
+{
+ return PointImp::stype();
+}
+
+static const ArgsParser::spec argsspecCircleCircleIntersection[] =
+{
+ { CircleImp::stype(), I18N_NOOP( "Intersect with this circle" ),
+ "SHOULD NOT BE SEEN", true },
+ { CircleImp::stype(), I18N_NOOP( "Intersect with this circle" ),
+ "SHOULD NOT BE SEEN", true },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CircleCircleIntersectionType )
+
+CircleCircleIntersectionType::CircleCircleIntersectionType()
+ : ArgsParserObjectType( "CircleCircleIntersection",
+ argsspecCircleCircleIntersection, 3 )
+{
+}
+
+CircleCircleIntersectionType::~CircleCircleIntersectionType()
+{
+}
+
+const CircleCircleIntersectionType* CircleCircleIntersectionType::instance()
+{
+ static const CircleCircleIntersectionType t;
+ return &t;
+}
+
+ObjectImp* CircleCircleIntersectionType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ int side = static_cast<const IntImp*>( parents[2] )->data();
+ assert( side == 1 || side == -1 );
+ const CircleImp* c1 = static_cast<const CircleImp*>( parents[0] );
+ const CircleImp* c2 = static_cast<const CircleImp*>( parents[1] );
+ const Coordinate o1 = c1->center();
+ const Coordinate o2 = c2->center();
+ const double r1sq = c1->squareRadius();
+ const Coordinate a = calcCircleRadicalStartPoint(
+ o1, o2, r1sq, c2->squareRadius()
+ );
+ const LineData line = LineData (a, Coordinate ( a.x -o2.y + o1.y, a.y + o2.x - o1.x ));
+ Coordinate ret = calcCircleLineIntersect( o1, r1sq, line, side );
+ if ( ret.valid() ) return new PointImp( ret );
+ else return new InvalidImp;
+}
+
+const ObjectImpType* CircleCircleIntersectionType::resultId() const
+{
+ return PointImp::stype();
+}
+
+static const ArgsParser::spec argsspecArcLineIntersection[] =
+{
+ { ArcImp::stype(), I18N_NOOP( "Intersect with this arc" ),
+ "SHOULD NOT BE SEEN", true },
+ { AbstractLineImp::stype(), intersectlinestat, "SHOULD NOT BE SEEN", true },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ArcLineIntersectionType )
+
+ArcLineIntersectionType::ArcLineIntersectionType()
+ : ArgsParserObjectType( "ArcLineIntersection",
+ argsspecArcLineIntersection, 3 )
+{
+}
+
+ArcLineIntersectionType::~ArcLineIntersectionType()
+{
+}
+
+const ArcLineIntersectionType* ArcLineIntersectionType::instance()
+{
+ static const ArcLineIntersectionType t;
+ return &t;
+}
+
+ObjectImp* ArcLineIntersectionType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ int side = static_cast<const IntImp*>( parents[2] )->data();
+ assert( side == 1 || side == -1 );
+ const LineData line = static_cast<const AbstractLineImp*>( parents[1] )->data();
+
+ const ArcImp* c = static_cast<const ArcImp*>( parents[0] );
+ const double r = c->radius();
+ Coordinate ret = calcArcLineIntersect( c->center(), r*r, c->startAngle(),
+ c->angle(), line, side );
+ if ( ret.valid() ) return new PointImp( ret );
+ else return new InvalidImp;
+}
+
+const ObjectImpType* ArcLineIntersectionType::resultId() const
+{
+ return PointImp::stype();
+}
diff --git a/kig/objects/intersection_types.h b/kig/objects/intersection_types.h
new file mode 100644
index 00000000..9e1df62e
--- /dev/null
+++ b/kig/objects/intersection_types.h
@@ -0,0 +1,105 @@
+// 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.
+
+#ifndef KIG_OBJECTS_INTERSECTION_TYPES_H
+#define KIG_OBJECTS_INTERSECTION_TYPES_H
+
+#include "object_type.h"
+
+/**
+ * conic line intersection. This also serves as circle-line
+ * intersection, in which case it uses the easier way to calc
+ * ... There is no separate CircleLineIntersectionPoint, since the
+ * difference between both types is quite small ( same number of
+ * intersections with a line, for example.. ), and since with
+ * transformations, Circles might dynamically change types to
+ * Conics..
+ */
+class ConicLineIntersectionType
+ : public ArgsParserObjectType
+{
+ ConicLineIntersectionType();
+ ~ConicLineIntersectionType();
+public:
+ static const ConicLineIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * conic line 'other' intersection. In case we already know one of the
+ * two intersections
+ */
+class ConicLineOtherIntersectionType
+ : public ArgsParserObjectType
+{
+ ConicLineOtherIntersectionType();
+ ~ConicLineOtherIntersectionType();
+public:
+ static const ConicLineOtherIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class LineLineIntersectionType
+ : public ArgsParserObjectType
+{
+ LineLineIntersectionType();
+ ~LineLineIntersectionType();
+public:
+ static const LineLineIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class LineCubicIntersectionType
+ : public ArgsParserObjectType
+{
+ LineCubicIntersectionType();
+ ~LineCubicIntersectionType();
+public:
+ static const LineCubicIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class CircleCircleIntersectionType
+ : public ArgsParserObjectType
+{
+ CircleCircleIntersectionType();
+ ~CircleCircleIntersectionType();
+public:
+ static const CircleCircleIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * arc line intersection.
+ */
+class ArcLineIntersectionType
+ : public ArgsParserObjectType
+{
+ ArcLineIntersectionType();
+ ~ArcLineIntersectionType();
+public:
+ static const ArcLineIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/inversion_type.cc b/kig/objects/inversion_type.cc
new file mode 100644
index 00000000..0ab77780
--- /dev/null
+++ b/kig/objects/inversion_type.cc
@@ -0,0 +1,412 @@
+// Copyright (C) 2005 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+// 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 "inversion_type.h"
+#include "point_imp.h"
+#include "line_imp.h"
+#include "circle_imp.h"
+#include "other_imp.h"
+#include "bogus_imp.h"
+
+#include "../misc/common.h"
+
+#include <klocale.h>
+
+static const char str1[] = I18N_NOOP( "Invert with respect to this circle" );
+static const char str2[] = I18N_NOOP( "Select the circle we want to invert against..." );
+
+static const ArgsParser::spec argsspecInvertPoint[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Compute the inversion of this point" ),
+ I18N_NOOP( "Select the point to invert..." ), false },
+ { CircleImp::stype(), str1, str2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertPointType )
+
+InvertPointType::InvertPointType()
+ : ArgsParserObjectType( "InvertPoint", argsspecInvertPoint, 2 )
+{
+}
+
+InvertPointType::~InvertPointType()
+{
+}
+
+const InvertPointType* InvertPointType::instance()
+{
+ static const InvertPointType s;
+ return &s;
+}
+
+const ObjectImpType* InvertPointType::resultId() const
+{
+ return PointImp::stype();
+}
+
+ObjectImp* InvertPointType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const CircleImp* c = static_cast<const CircleImp*>( args[1] );
+ Coordinate center = c->center();
+ Coordinate relp = static_cast<const PointImp*>( args[0] )->coordinate() - center;
+ double radiussq = c->squareRadius();
+ double normsq = relp.x*relp.x + relp.y*relp.y;
+ if ( normsq == 0 ) return new InvalidImp;
+ return new PointImp( center + (radiussq/normsq)*relp );
+}
+
+/*
+ * inversion of a line
+ */
+
+static const ArgsParser::spec argsspecInvertLine[] =
+{
+ { LineImp::stype(), I18N_NOOP( "Compute the inversion of this line" ),
+ I18N_NOOP( "Select the line to invert..." ), false },
+ { CircleImp::stype(), str1, str2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertLineType )
+
+InvertLineType::InvertLineType()
+ : ArgsParserObjectType( "InvertLine", argsspecInvertLine, 2 )
+{
+}
+
+InvertLineType::~InvertLineType()
+{
+}
+
+const InvertLineType* InvertLineType::instance()
+{
+ static const InvertLineType s;
+ return &s;
+}
+
+const ObjectImpType* InvertLineType::resultId() const
+{
+ return CircleImp::stype();
+}
+
+ObjectImp* InvertLineType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const CircleImp* c = static_cast<const CircleImp*>( args[1] );
+ Coordinate center = c->center();
+ double radiussq = c->squareRadius();
+ const LineData line = static_cast<const AbstractLineImp*>( args[0] )->data();
+ Coordinate relb = line.b - center;
+ Coordinate ab = line.b - line.a;
+ double t = (relb.x*ab.x + relb.y*ab.y)/(ab.x*ab.x + ab.y*ab.y);
+ Coordinate relh = relb - t*ab;
+ double normhsq = relh.x*relh.x + relh.y*relh.y;
+ if ( normhsq < 1e-12*radiussq ) return new LineImp( line.a, line.b );
+ Coordinate newcenter = center + 0.5*radiussq/normhsq*relh;
+ double newradius = 0.5*radiussq/sqrt(normhsq);
+
+ return new CircleImp( newcenter, newradius );
+}
+
+/*
+ * inversion of a segment
+ */
+
+static const ArgsParser::spec argsspecInvertSegment[] =
+{
+ { SegmentImp::stype(), I18N_NOOP( "Compute the inversion of this segment" ),
+ I18N_NOOP( "Select the segment to invert..." ), false },
+ { CircleImp::stype(), str1, str2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertSegmentType )
+
+InvertSegmentType::InvertSegmentType()
+ : ArgsParserObjectType( "InvertSegment", argsspecInvertSegment, 2 )
+{
+}
+
+InvertSegmentType::~InvertSegmentType()
+{
+}
+
+const InvertSegmentType* InvertSegmentType::instance()
+{
+ static const InvertSegmentType s;
+ return &s;
+}
+
+const ObjectImpType* InvertSegmentType::resultId() const
+{
+ return ArcImp::stype();
+}
+
+ObjectImp* InvertSegmentType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const CircleImp* c = static_cast<const CircleImp*>( args[1] );
+ Coordinate center = c->center();
+ double radiussq = c->squareRadius();
+ const LineData line = static_cast<const AbstractLineImp*>( args[0] )->data();
+ Coordinate rela = line.a - center;
+ Coordinate relb = line.b - center;
+ Coordinate ab = relb - rela;
+ double t = (relb.x*ab.x + relb.y*ab.y)/(ab.x*ab.x + ab.y*ab.y);
+ Coordinate relh = relb - t*ab;
+ double normhsq = relh.x*relh.x + relh.y*relh.y;
+
+ /*
+ * compute the inversion of the two endpoints
+ */
+
+ Coordinate newcenterrel = 0.5*radiussq/normhsq*relh;
+ Coordinate relainv = radiussq/rela.squareLength() * rela;
+ Coordinate relbinv = radiussq/relb.squareLength() * relb;
+
+ if ( normhsq < 1e-12*radiussq )
+ {
+ if ( rela.squareLength() < 1e-12 )
+ {
+ return new RayImp( relbinv + center, 2*relbinv + center );
+ }
+ if ( relb.squareLength() < 1e-12 )
+ {
+ return new RayImp( relainv + center, 2*relainv + center );
+ }
+ if ( relb.x*rela.x + relb.y*rela.y > 0 )
+ {
+ return new SegmentImp( relainv + center, relbinv + center );
+ }
+ return new InvalidImp();
+ }
+ double newradius = 0.5*radiussq/sqrt(normhsq);
+
+ relainv -= newcenterrel;
+ relbinv -= newcenterrel;
+ double angle1 = atan2( relainv.y, relainv.x );
+ double angle2 = atan2( relbinv.y, relbinv.x );
+ double angle = angle2 - angle1;
+ if ( ab.x*rela.y - ab.y*rela.x > 0 )
+ {
+ angle1 = angle2;
+ angle = -angle;
+ }
+ while ( angle1 < 0 ) angle1 += 2*M_PI;
+ while ( angle1 >= 2*M_PI ) angle1 -= 2*M_PI;
+ while ( angle < 0 ) angle += 2*M_PI;
+ while ( angle >= 2*M_PI ) angle -= 2*M_PI;
+ return new ArcImp( newcenterrel + center, newradius, angle1, angle );
+}
+
+/*
+ * inversion of a circle
+ */
+
+static const ArgsParser::spec argsspecInvertCircle[] =
+{
+ { CircleImp::stype(), I18N_NOOP( "Compute the inversion of this circle" ),
+ I18N_NOOP( "Select the circle to invert..." ), false },
+ { CircleImp::stype(), str1, str2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertCircleType )
+
+InvertCircleType::InvertCircleType()
+ : ArgsParserObjectType( "InvertCircle", argsspecInvertCircle, 2 )
+{
+}
+
+InvertCircleType::~InvertCircleType()
+{
+}
+
+const InvertCircleType* InvertCircleType::instance()
+{
+ static const InvertCircleType s;
+ return &s;
+}
+
+const ObjectImpType* InvertCircleType::resultId() const
+{
+ return CircleImp::stype();
+}
+
+ObjectImp* InvertCircleType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const CircleImp* refcircle = static_cast<const CircleImp*>( args[1] );
+ Coordinate refc = refcircle->center();
+ double refrsq = refcircle->squareRadius();
+ const CircleImp* circle = static_cast<const CircleImp*>( args[0] );
+ Coordinate c = circle->center() - refc;
+ double clength = c.length();
+ Coordinate cnorm = Coordinate (1.,0.);
+ if ( clength != 0.0 ) cnorm = c/clength;
+ double r = circle->radius();
+ Coordinate tc = r*cnorm;
+ Coordinate b = c + tc; //(1 + t)*c;
+ double bsq = b.x*b.x + b.y*b.y;
+ Coordinate bprime = refrsq*b/bsq;
+ if ( std::fabs( clength - r ) < 1e-6*clength ) // circle through origin -> line
+ {
+ return new LineImp( bprime+refc, bprime+refc+Coordinate( -c.y, c.x ) );
+ }
+
+ Coordinate a = c - tc;
+ double asq = a.x*a.x + a.y*a.y;
+ Coordinate aprime = refrsq*a/asq;
+
+ Coordinate cprime = 0.5*(aprime + bprime);
+ double rprime = 0.5*( bprime - aprime ).length();
+
+ return new CircleImp( cprime + refc, rprime );
+}
+
+/*
+ * inversion of an arc
+ */
+
+static const ArgsParser::spec argsspecInvertArc[] =
+{
+ { ArcImp::stype(), I18N_NOOP( "Compute the inversion of this arc" ),
+ I18N_NOOP( "Select the arc to invert..." ), false },
+ { CircleImp::stype(), str1, str2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertArcType )
+
+InvertArcType::InvertArcType()
+ : ArgsParserObjectType( "InvertArc", argsspecInvertArc, 2 )
+{
+}
+
+InvertArcType::~InvertArcType()
+{
+}
+
+const InvertArcType* InvertArcType::instance()
+{
+ static const InvertArcType s;
+ return &s;
+}
+
+const ObjectImpType* InvertArcType::resultId() const
+{
+ return ArcImp::stype();
+}
+
+ObjectImp* InvertArcType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const CircleImp* refcircle = static_cast<const CircleImp*>( args[1] );
+ Coordinate refc = refcircle->center();
+ double refrsq = refcircle->squareRadius();
+ const ArcImp* arc = static_cast<const ArcImp*>( args[0] );
+ Coordinate c = arc->center() - refc;
+ double clength = c.length();
+ Coordinate cnorm = Coordinate (1.,0.);
+ if ( clength != 0.0 ) cnorm = c/clength;
+ double r = arc->radius();
+ /*
+ * r > clength means center of inversion circle inside of circle supporting arc
+ */
+ Coordinate tc = r*cnorm;
+ Coordinate b = c + tc;
+ double bsq = b.x*b.x + b.y*b.y;
+ Coordinate bprime = refrsq*b/bsq;
+ if ( std::fabs( clength - r ) < 1e-6*clength ) // support circle through origin ->
+ // segment, ray or invalid
+ // (reversed segment, union of two rays)
+ {
+ bool valid1 = false;
+ bool valid2 = false;
+ Coordinate ep1 = arc->firstEndPoint() - refc;
+ Coordinate ep2 = arc->secondEndPoint() - refc;
+ Coordinate ep1inv = Coordinate::invalidCoord();
+ Coordinate ep2inv = Coordinate::invalidCoord();
+ double ep1sq = ep1.squareLength();
+ if ( ep1sq > 1e-12 )
+ {
+ valid1 = true;
+ ep1inv = refrsq/ep1sq * ep1;
+ }
+ Coordinate rayendp = ep1inv;
+ int sign = 1;
+ double ep2sq = ep2.squareLength();
+ if ( ep2sq > 1e-12 )
+ {
+ valid2 = true;
+ ep2inv = refrsq/ep2sq * ep2;
+ rayendp = ep2inv;
+ sign = -1;
+ }
+ if ( valid1 || valid2 )
+ {
+ if ( valid1 && valid2 )
+ {
+ // this gives either a segment or the complement of a segment (relative
+ // to its support line). We return a segment in any case (fixme)
+ double ang = atan2( -c.y, -c.x );
+ double sa = arc->startAngle();
+ if ( ang < sa ) ang += 2*M_PI;
+ if ( ang - sa - arc->angle() < 0 ) return new InvalidImp();
+ return new SegmentImp( ep1inv + refc, ep2inv + refc );
+ } else
+ return new RayImp ( rayendp + refc,
+ rayendp + refc + sign*Coordinate( -c.y, c.x ) ); // this should give a Ray
+ } else
+ return new LineImp( bprime+refc, bprime+refc+Coordinate( -c.y, c.x ) );
+ }
+
+ Coordinate a = c - tc;
+ double asq = a.x*a.x + a.y*a.y;
+ Coordinate aprime = refrsq*a/asq;
+
+ Coordinate cprime = 0.5*(aprime + bprime);
+ double rprime = 0.5*( bprime - aprime ).length();
+
+ Coordinate ep1 = arc->firstEndPoint() - refc;
+ double ang1 = arc->startAngle();
+ double newstartangle = 2*atan2(ep1.y,ep1.x) - ang1;
+ Coordinate ep2 = arc->secondEndPoint() - refc;
+ double ang2 = ang1 + arc->angle();
+ double newendangle = 2*atan2(ep2.y,ep2.x) - ang2;
+ double newangle = newendangle - newstartangle;
+
+ /*
+ * newstartangle and newendangle might have to be exchanged:
+ * this is the case if the circle supporting our arc does not
+ * contain the center of the inversion circle
+ */
+ if ( r < clength )
+ {
+ newstartangle = newendangle - M_PI;
+ newangle = - newangle;
+ // newendangle is no-longer valid
+ }
+ while ( newstartangle < 0 ) newstartangle += 2*M_PI;
+ while ( newstartangle >= 2*M_PI ) newstartangle -= 2*M_PI;
+ while ( newangle < 0 ) newangle += 2*M_PI;
+ while ( newangle >= 2*M_PI ) newangle -= 2*M_PI;
+ return new ArcImp( cprime + refc, rprime, newstartangle, newangle );
+}
+
diff --git a/kig/objects/inversion_type.h b/kig/objects/inversion_type.h
new file mode 100644
index 00000000..d7b97957
--- /dev/null
+++ b/kig/objects/inversion_type.h
@@ -0,0 +1,86 @@
+// Copyright (C) 2005 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+// 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.
+
+#ifndef KIG_OBJECTS_INVERSION_TYPE_H
+#define KIG_OBJECTS_INVERSION_TYPE_H
+
+#include "base_type.h"
+
+/**
+ * Inversion of a point, line
+ */
+class InvertPointType
+ : public ArgsParserObjectType
+{
+ InvertPointType();
+ ~InvertPointType();
+public:
+ static const InvertPointType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class InvertLineType
+ : public ArgsParserObjectType
+{
+ InvertLineType();
+ ~InvertLineType();
+public:
+ static const InvertLineType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class InvertSegmentType
+ : public ArgsParserObjectType
+{
+ InvertSegmentType();
+ ~InvertSegmentType();
+public:
+ static const InvertSegmentType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class InvertCircleType
+ : public ArgsParserObjectType
+{
+ InvertCircleType();
+ ~InvertCircleType();
+public:
+ static const InvertCircleType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class InvertArcType
+ : public ArgsParserObjectType
+{
+ InvertArcType();
+ ~InvertArcType();
+public:
+ static const InvertArcType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/line_imp.cc b/kig/objects/line_imp.cc
new file mode 100644
index 00000000..6f3c6002
--- /dev/null
+++ b/kig/objects/line_imp.cc
@@ -0,0 +1,571 @@
+// Copyright (C) 2002 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 "line_imp.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+
+#include "../misc/rect.h"
+#include "../misc/common.h"
+#include "../misc/kigtransform.h"
+#include "../misc/kigpainter.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+#include <cmath>
+using namespace std;
+
+AbstractLineImp::AbstractLineImp( const Coordinate& a, const Coordinate& b )
+ : mdata( a, b )
+{
+}
+
+AbstractLineImp::~AbstractLineImp()
+{
+}
+
+bool AbstractLineImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ return lineInRect( r, mdata.a, mdata.b, width, this, w );
+}
+
+const uint AbstractLineImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 2;
+}
+
+const ObjectImpType* AbstractLineImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return AbstractLineImp::stype();
+}
+
+const char* AbstractLineImp::iconForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() )
+ return "slope"; // slope
+ if ( which == Parent::numberOfProperties() + 1 )
+ return "kig_text"; // equation
+ else assert( false );
+ return "";
+}
+
+ObjectImp* AbstractLineImp::property( uint which, const KigDocument& w ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ if ( which == Parent::numberOfProperties() )
+ return new DoubleImp( slope() );
+ if ( which == Parent::numberOfProperties() + 1 )
+ return new StringImp( equationString() );
+ else assert( false );
+ return new InvalidImp;
+}
+
+const QCStringList AbstractLineImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l << "slope";
+ l << "equation";
+ assert( l.size() == AbstractLineImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList AbstractLineImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Slope" );
+ l << I18N_NOOP( "Equation" );
+ assert( l.size() == AbstractLineImp::numberOfProperties() );
+ return l;
+}
+
+const uint SegmentImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 4;
+}
+
+const QCStringList SegmentImp::propertiesInternalNames() const
+{
+ QCStringList s = Parent::propertiesInternalNames();
+ s << "length";
+ s << "mid-point";
+ s << "end-point-A";
+ s << "end-point-B";
+ assert( s.size() == SegmentImp::numberOfProperties() );
+ return s;
+}
+
+const QCStringList SegmentImp::properties() const
+{
+ QCStringList s = Parent::properties();
+ s << I18N_NOOP( "Length" );
+ s << I18N_NOOP( "Mid Point" );
+ s << I18N_NOOP( "First End Point" );
+ s << I18N_NOOP( "Second End Point" );
+ assert( s.size() == SegmentImp::numberOfProperties() );
+ return s;
+}
+
+const ObjectImpType* SegmentImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return SegmentImp::stype();
+}
+
+const char* SegmentImp::iconForProperty( uint which ) const
+{
+ int pnum = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return "distance"; // length
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return "segment_midpoint"; // mid point
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return "endpoint1"; // mid point
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return "endpoint2"; // mid point
+ else assert( false );
+ return "";
+}
+
+ObjectImp* SegmentImp::property( uint which, const KigDocument& w ) const
+{
+ int pnum = 0;
+
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new DoubleImp( mdata.dir().length() );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new PointImp( ( mdata.a + mdata.b ) / 2 );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new PointImp( mdata.a );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new PointImp( mdata.b );
+ else assert( false );
+ return new InvalidImp;
+}
+
+double AbstractLineImp::slope() const
+{
+ Coordinate diff = mdata.dir();
+ return diff.y / diff.x;
+}
+
+const QString AbstractLineImp::equationString() const
+{
+ Coordinate p = mdata.a;
+ Coordinate q = mdata.b;
+
+ double m = ( q.y - p.y ) / ( q.x - p.x );
+ double r = - ( q.y - p.y ) * p.x / ( q.x - p.x ) + p.y;
+
+ QString ret = QString::fromUtf8( "y = %1x " ) +
+ QString::fromUtf8( r > 0 ? "+" : "-" ) +
+ QString::fromUtf8( " %2" );
+
+ ret = ret.arg( m, 0, 'g', 3 );
+ ret = ret.arg( abs( r ), 0, 'g', 3 );
+
+ return ret;
+}
+
+void SegmentImp::draw( KigPainter& p ) const
+{
+ p.drawSegment( mdata );
+}
+
+bool SegmentImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( p, w.screenInfo().normalMiss( width ) );
+}
+
+void RayImp::draw( KigPainter& p ) const
+{
+ p.drawRay( mdata );
+}
+
+bool RayImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( p, w.screenInfo().normalMiss( width ) );
+}
+
+void LineImp::draw( KigPainter& p ) const
+{
+ p.drawLine( mdata );
+}
+
+bool LineImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( p, w.screenInfo().normalMiss( width ) );
+}
+
+SegmentImp::SegmentImp( const Coordinate& a, const Coordinate& b )
+ : AbstractLineImp( a, b )
+{
+}
+
+RayImp::RayImp( const Coordinate& a, const Coordinate& b )
+ : AbstractLineImp( a, b )
+{
+}
+
+LineImp::LineImp( const Coordinate& a, const Coordinate& b )
+ : AbstractLineImp( a, b )
+{
+}
+
+SegmentImp* SegmentImp::copy() const
+{
+ return new SegmentImp( mdata );
+}
+
+RayImp* RayImp::copy() const
+{
+ return new RayImp( mdata );
+}
+
+LineImp* LineImp::copy() const
+{
+ return new LineImp( mdata );
+}
+
+const Coordinate SegmentImp::getPoint( double param, const KigDocument& ) const
+{
+ return mdata.a + mdata.dir()*param;
+}
+
+double SegmentImp::getParam( const Coordinate& p, const KigDocument& ) const
+{
+ Coordinate pt = calcPointOnPerpend( data(), p );
+ pt = calcIntersectionPoint( data(), LineData( p, pt ) );
+ // if pt is over the end of the segment ( i.e. it's on the line
+ // which the segment is a part of, but not of the segment itself..;
+ // ) we set it to one of the end points of the segment...
+ if ((pt - mdata.a).length() > mdata.dir().length() )
+ pt = mdata.b;
+ else if ( (pt- mdata.b).length() > mdata.dir().length() )
+ pt = mdata.a;
+ if (mdata.b == mdata.a) return 0;
+ return ((pt - mdata.a).length())/(mdata.dir().length());
+}
+
+LineData AbstractLineImp::data() const
+{
+ return mdata;
+}
+
+const Coordinate RayImp::getPoint( double param, const KigDocument& ) const
+{
+ param = 1.0/param - 1.0;
+ return mdata.a + mdata.dir()*param;
+}
+
+double RayImp::getParam( const Coordinate& p, const KigDocument& ) const
+{
+ const LineData ld = data();
+ Coordinate pt = calcPointOnPerpend( ld, p );
+ pt = calcIntersectionPoint( ld, LineData( p, pt ));
+ // if pt is over the end of the ray ( i.e. it's on the line
+ // which the ray is a part of, but not of the ray itself..;
+ // ) we set it to the start point of the ray...
+ Coordinate dir = ld.dir();
+ pt -= ld.a;
+ double param;
+ if ( dir.x != 0 ) param = pt.x / dir.x;
+ else if ( dir.y != 0 ) param = pt.y / dir.y;
+ else param = 0.;
+ if ( param < 0. ) param = 0.;
+
+ // mp: let's try with 1/(x+1), this reverses the mapping, but
+ // should allow to take advantage of the tightness of floating point
+ // numbers near zero, in order to get more possible positions near
+ // infinity
+
+ param = 1./( param + 1. );
+
+ assert( param >= 0. && param <= 1. );
+ return param;
+}
+
+const Coordinate LineImp::getPoint( double p, const KigDocument& ) const
+{
+ // inspired upon KSeg
+
+ // we need to spread the points over the line, it should also come near
+ // the (infinite) end of the line, but most points should be near
+ // the two points we contain...
+ if ( p <= 0. ) p = 1e-6;
+ if ( p >= 1. ) p = 1 - 1e-6;
+ p = 2*p - 1;
+ if (p > 0) p = p/(1 - p);
+ else p = p/(1 + p);
+// p *= 1024; // such multiplying factor could be useful in order to
+ // have more points near infinity, at the expense of
+ // points near ma and mb
+ return mdata.a + p*mdata.dir();
+}
+
+double LineImp::getParam( const Coordinate& point, const KigDocument& ) const
+{
+ // somewhat the reverse of getPoint, although it also supports
+ // points not on the line...
+
+ Coordinate pa = point - mdata.a;
+ Coordinate ba = mdata.dir();
+ double balsq = ba.x*ba.x + ba.y*ba.y;
+ assert (balsq > 0);
+
+ double p = (pa.x*ba.x + pa.y*ba.y)/balsq;
+// p /= 1024;
+ if (p > 0) p = p/(1+p);
+ else p = p/(1-p);
+
+ return 0.5*(p + 1);
+}
+
+ObjectImp* SegmentImp::transform( const Transformation& t ) const
+{
+ if ( ! t.isAffine() ) /* we need to check the position of the two points */
+ {
+ if ( t.getProjectiveIndicator( mdata.a ) *
+ t.getProjectiveIndicator( mdata.b ) < 0 )
+ return new InvalidImp();
+ }
+ Coordinate na = t.apply( mdata.a );
+ Coordinate nb = t.apply( mdata.b );
+ if( na.valid() && nb.valid() ) return new SegmentImp( na, nb );
+ else return new InvalidImp();
+}
+
+ObjectImp* LineImp::transform( const Transformation& t ) const
+{
+ Coordinate na = t.apply( mdata.a );
+ Coordinate nb = t.apply( mdata.b );
+ if ( na.valid() && nb.valid() ) return new LineImp( na, nb );
+ else return new InvalidImp();
+}
+
+ObjectImp* RayImp::transform( const Transformation& t ) const
+{
+ if ( ! t.isAffine() ) /* we need to check the position of the two points */
+ {
+ double pa = t.getProjectiveIndicator( mdata.a );
+ double pb = t.getProjectiveIndicator( mdata.b );
+ if ( pa < 0 ) pb = -pb;
+ if ( pb < fabs (pa) ) return new InvalidImp();
+ Coordinate na = t.apply( mdata.a );
+ Coordinate nb = t.apply0( mdata.b - mdata.a );
+ if ( na.valid() && nb.valid() ) return new SegmentImp( na, nb );
+ else return new InvalidImp();
+ }
+ Coordinate na = t.apply( mdata.a );
+ Coordinate nb = t.apply( mdata.b );
+ if ( na.valid() && nb.valid() ) return new RayImp( na, nb );
+ else return new InvalidImp();
+}
+
+AbstractLineImp::AbstractLineImp( const LineData& d )
+ : mdata( d )
+{
+}
+
+SegmentImp::SegmentImp( const LineData& d )
+ : AbstractLineImp( d )
+{
+}
+
+RayImp::RayImp( const LineData& d )
+ : AbstractLineImp( d )
+{
+}
+
+LineImp::LineImp( const LineData& d )
+ : AbstractLineImp( d )
+{
+}
+
+double SegmentImp::length() const
+{
+ return mdata.length();
+}
+
+void SegmentImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void RayImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void LineImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool AbstractLineImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.type() == type() &&
+ static_cast<const AbstractLineImp&>( rhs ).data() == data();
+}
+
+const ObjectImpType* AbstractLineImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "line", I18N_NOOP( "line" ),
+ I18N_NOOP( "Select a Line" ), 0, 0, 0, 0, 0, 0, 0 );
+ return &t;
+}
+
+const ObjectImpType* LineImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "line",
+ I18N_NOOP( "line" ),
+ I18N_NOOP( "Select this line" ),
+ I18N_NOOP( "Select line %1" ),
+ I18N_NOOP( "Remove a Line" ),
+ I18N_NOOP( "Add a Line" ),
+ I18N_NOOP( "Move a Line" ),
+ I18N_NOOP( "Attach to this line" ),
+ I18N_NOOP( "Show a Line" ),
+ I18N_NOOP( "Hide a Line" )
+ );
+ return &t;
+}
+
+const ObjectImpType* SegmentImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "segment",
+ I18N_NOOP( "segment" ),
+ I18N_NOOP( "Select this segment" ),
+ I18N_NOOP( "Select segment %1" ),
+ I18N_NOOP( "Remove a Segment" ),
+ I18N_NOOP( "Add a Segment" ),
+ I18N_NOOP( "Move a Segment" ),
+ I18N_NOOP( "Attach to this segment" ),
+ I18N_NOOP( "Show a Segment" ),
+ I18N_NOOP( "Hide a Segment" )
+ );
+ return &t;
+}
+
+const ObjectImpType* RayImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "ray",
+ I18N_NOOP( "half-line" ),
+ I18N_NOOP( "Select this half-line" ),
+ I18N_NOOP( "Select half-line %1" ),
+ I18N_NOOP( "Remove a Half-Line" ),
+ I18N_NOOP( "Add a Half-Line" ),
+ I18N_NOOP( "Move a Half-Line" ),
+ I18N_NOOP( "Attach to this half-line" ),
+ I18N_NOOP( "Show a Half-Line" ),
+ I18N_NOOP( "Hide a Half-Line" )
+ );
+ return &t;
+}
+
+const ObjectImpType* SegmentImp::type() const
+{
+ return SegmentImp::stype();
+}
+
+const ObjectImpType* RayImp::type() const
+{
+ return RayImp::stype();
+}
+
+const ObjectImpType* LineImp::type() const
+{
+ return LineImp::stype();
+}
+
+bool SegmentImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool SegmentImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ return isOnSegment( p, mdata.a, mdata.b, threshold );
+}
+
+bool RayImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool RayImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ return isOnRay( p, mdata.a, mdata.b, threshold );
+}
+
+bool LineImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool LineImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ return isOnLine( p, mdata.a, mdata.b, threshold );
+}
+
+bool AbstractLineImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ int pnum = 0;
+
+ if ( which < Parent::numberOfProperties() )
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return false;
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return true;
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return true;
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return true;
+ else assert( false );
+ return false;
+}
+
+Rect SegmentImp::surroundingRect() const
+{
+ return Rect( mdata.a, mdata.b );
+}
+
+Rect RayImp::surroundingRect() const
+{
+ return Rect::invalidRect();
+}
+
+Rect LineImp::surroundingRect() const
+{
+ return Rect::invalidRect();
+}
diff --git a/kig/objects/line_imp.h b/kig/objects/line_imp.h
new file mode 100644
index 00000000..c9014613
--- /dev/null
+++ b/kig/objects/line_imp.h
@@ -0,0 +1,215 @@
+// Copyright (C) 2002 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.
+
+#ifndef KIG_OBJECTS_LINE_IMP_H
+#define KIG_OBJECTS_LINE_IMP_H
+
+#include "curve_imp.h"
+
+#include "../misc/common.h"
+
+class LineData;
+
+/**
+ * An ObjectImp class that is the base of the line-like ObjectImp's:
+ * SegmentImp, LineImp and RayImp..
+ */
+class AbstractLineImp
+ : public CurveImp
+{
+protected:
+ LineData mdata;
+ AbstractLineImp( const LineData& d );
+ AbstractLineImp( const Coordinate& a, const Coordinate& b );
+
+public:
+ typedef CurveImp Parent;
+ /**
+ * Returns the ObjectImpType representing the AbstractLineImp
+ * type..
+ */
+ static const ObjectImpType* stype();
+
+ ~AbstractLineImp();
+
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& d ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ /**
+ * Get the slope of this AbstractLineImp.. For a line through
+ * points a( xa, ya ) and b ( xb, yb ), this means the value ( yb -
+ * ya ) / ( xb - xa ).
+ */
+ double slope() const;
+ /**
+ * Get a string containing the equation of this line in the form "y
+ * = a * x + b ".
+ */
+ const QString equationString() const;
+ /**
+ * Get the LineData for this AbstractLineImp.
+ */
+ LineData data() const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+/**
+ * An ObjectImp representing a segment
+ */
+class SegmentImp
+ : public AbstractLineImp
+{
+public:
+ typedef AbstractLineImp Parent;
+ /**
+ * Returns the ObjectImpType representing the SegmentImp
+ * type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct a new segment from point a to point b.
+ */
+ SegmentImp( const Coordinate& a, const Coordinate& b );
+ /**
+ * Construct a new segment from a LineData.
+ */
+ SegmentImp( const LineData& d );
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& si ) const;
+ Rect surroundingRect() const;
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+ double getParam( const Coordinate&, const KigDocument& ) const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& d ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+
+ SegmentImp* copy() const;
+
+ /**
+ * Get the length of this segment.
+ */
+ double length() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+/**
+ * An ObjectImp representing a ray. This means half of a line, it is
+ * infinite in one direction, but ends at a certain point in the other
+ * direction..
+ */
+class RayImp
+ : public AbstractLineImp
+{
+public:
+ typedef AbstractLineImp Parent;
+ /**
+ * Returns the ObjectImpType representing the RayImp
+ * type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct a ray, starting at a, and going through b.
+ */
+ RayImp( const Coordinate& a, const Coordinate& b );
+ /**
+ * Construct a ray from a LineData.
+ */
+ RayImp( const LineData& d );
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& si ) const;
+ Rect surroundingRect() const;
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+ double getParam( const Coordinate&, const KigDocument& ) const;
+
+ RayImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+/**
+ * An ObjectImp representing a line.
+ */
+class LineImp
+ : public AbstractLineImp
+{
+public:
+ typedef AbstractLineImp Parent;
+
+ /**
+ * Returns the ObjectImpType representing the LineImp
+ * type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct a LineImp going through points a and b.
+ */
+ LineImp( const Coordinate& a, const Coordinate& b );
+ /**
+ * Construct a LineImp from a LineData.
+ */
+ LineImp( const LineData& d );
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& si ) const;
+ Rect surroundingRect() const;
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+ double getParam( const Coordinate&, const KigDocument& ) const;
+
+ LineImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+#endif
diff --git a/kig/objects/line_type.cc b/kig/objects/line_type.cc
new file mode 100644
index 00000000..a2c0734b
--- /dev/null
+++ b/kig/objects/line_type.cc
@@ -0,0 +1,334 @@
+// Copyright (C) 2002 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 "line_type.h"
+
+#include "bogus_imp.h"
+#include "line_imp.h"
+#include "object_holder.h"
+#include "other_imp.h"
+#include "point_imp.h"
+
+#include "../kig/kig_view.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_commands.h"
+#include "../misc/common.h"
+#include "../misc/calcpaths.h"
+
+#include <qstringlist.h>
+
+#include <klocale.h>
+
+static const ArgsParser::spec argsspecSegmentAB[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Construct a segment starting at this point" ),
+ I18N_NOOP( "Select the start point of the new segment..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct a segment ending at this point" ),
+ I18N_NOOP( "Select the end point of the new segment..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( SegmentABType )
+
+SegmentABType::SegmentABType()
+ : ObjectABType( "SegmentAB", argsspecSegmentAB, 2 )
+{
+}
+
+SegmentABType::~SegmentABType()
+{
+}
+
+const SegmentABType* SegmentABType::instance()
+{
+ static const SegmentABType s;
+ return &s;
+}
+
+ObjectImp* SegmentABType::calc( const Coordinate& a, const Coordinate& b ) const
+{
+ return new SegmentImp( a, b );
+}
+
+static const char constructlineabstat[] = I18N_NOOP( "Construct a line through this point" );
+
+static const ArgsParser::spec argsspecLineAB[] =
+{
+ { PointImp::stype(), constructlineabstat,
+ I18N_NOOP( "Select a point for the line to go through..." ), true },
+ { PointImp::stype(), constructlineabstat,
+ I18N_NOOP( "Select another point for the line to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LineABType )
+
+LineABType::LineABType()
+ : ObjectABType( "LineAB", argsspecLineAB, 2 )
+{
+}
+
+LineABType::~LineABType()
+{
+}
+
+const LineABType* LineABType::instance()
+{
+ static const LineABType s;
+ return &s;
+}
+
+ObjectImp* LineABType::calc( const Coordinate& a, const Coordinate& b ) const
+{
+ return new LineImp( a, b );
+}
+
+static const char constructhalflinestartingstat[] = I18N_NOOP( "Construct a half-line starting at this point" );
+
+static const ArgsParser::spec argsspecRayAB[] =
+{
+ { PointImp::stype(), constructhalflinestartingstat,
+ I18N_NOOP( "Select the start point of the new half-line..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct a half-line through this point" ),
+ I18N_NOOP( "Select a point for the half-line to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( RayABType )
+
+RayABType::RayABType()
+ : ObjectABType( "RayAB", argsspecRayAB, 2 )
+{
+}
+
+RayABType::~RayABType()
+{
+}
+
+const RayABType* RayABType::instance()
+{
+ static const RayABType s;
+ return &s;
+}
+
+ObjectImp* RayABType::calc( const Coordinate& a, const Coordinate& b ) const
+{
+ return new RayImp( a, b );
+}
+
+LinePerpendLPType* LinePerpendLPType::instance()
+{
+ static LinePerpendLPType l;
+ return &l;
+}
+
+ObjectImp* LinePerpendLPType::calc(
+ const LineData& a,
+ const Coordinate& b ) const
+{
+ Coordinate p = calcPointOnPerpend( a, b );
+ return new LineImp( b, p );
+}
+
+static const ArgsParser::spec argsspecLineParallel[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct a line parallel to this line" ),
+ I18N_NOOP( "Select a line parallel to the new line..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct the parallel line through this point" ),
+ I18N_NOOP( "Select a point for the new line to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LineParallelLPType )
+
+LineParallelLPType::LineParallelLPType()
+ : ObjectLPType( "LineParallel", argsspecLineParallel, 2 )
+{
+}
+
+LineParallelLPType::~LineParallelLPType()
+{
+}
+
+LineParallelLPType* LineParallelLPType::instance()
+{
+ static LineParallelLPType l;
+ return &l;
+}
+
+ObjectImp* LineParallelLPType::calc(
+ const LineData& a,
+ const Coordinate& b ) const
+{
+ Coordinate r = calcPointOnParallel( a, b );
+ return new LineImp( r, b );
+}
+
+static const ArgsParser::spec argsspecLinePerpend[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct a line perpendicular to this line" ),
+ I18N_NOOP( "Select a line perpendicular to the new line..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct a perpendicular line through this point" ),
+ I18N_NOOP( "Select a point for the new line to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LinePerpendLPType )
+
+LinePerpendLPType::LinePerpendLPType()
+ : ObjectLPType( "LinePerpend", argsspecLinePerpend, 2 )
+{
+}
+
+LinePerpendLPType::~LinePerpendLPType()
+{
+}
+
+const ObjectImpType* SegmentABType::resultId() const
+{
+ return SegmentImp::stype();
+}
+
+const ObjectImpType* LineABType::resultId() const
+{
+ return LineImp::stype();
+}
+
+const ObjectImpType* RayABType::resultId() const
+{
+ return RayImp::stype();
+}
+
+const ObjectImpType* LinePerpendLPType::resultId() const
+{
+ return LineImp::stype();
+}
+
+const ObjectImpType* LineParallelLPType::resultId() const
+{
+ return LineImp::stype();
+}
+
+QStringList SegmentABType::specialActions() const
+{
+ QStringList ret;
+ ret << i18n( "Set &Length..." );
+ return ret;
+}
+
+void SegmentABType::executeAction( int i, ObjectHolder&, ObjectTypeCalcer& c,
+ KigPart& d, KigWidget& w, NormalMode& ) const
+{
+ assert( i == 0 );
+ // pretend to use this var..
+ (void) i;
+
+ std::vector<ObjectCalcer*> parents = c.parents();
+ assert( margsparser.checkArgs( parents ) );
+
+ Coordinate a = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ Coordinate b = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
+
+ bool ok = true;
+ double length = getDoubleFromUser(
+ i18n( "Set Segment Length" ), i18n( "Choose the new length: " ),
+ (b-a).length(), &w, &ok, -2147483647, 2147483647, 3 );
+ if ( ! ok ) return;
+
+ Coordinate nb = a + ( b - a ).normalize( length );
+
+ MonitorDataObjects mon( getAllParents( parents ) );
+ parents[1]->move( nb, d.document() );
+ KigCommand* cd = new KigCommand( d, i18n( "Resize Segment" ) );
+ mon.finish( cd );
+ d.history()->addCommand( cd );
+}
+
+static const ArgsParser::spec argsspecLineByVector[] =
+{
+ { VectorImp::stype(), I18N_NOOP( "Construct a line by this vector" ),
+ I18N_NOOP( "Select a vector in the direction of the new line..." ), true },
+ { PointImp::stype(), constructlineabstat,
+ I18N_NOOP( "Select a point for the new line to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LineByVectorType )
+
+LineByVectorType::LineByVectorType()
+ : ArgsParserObjectType( "LineByVector", argsspecLineByVector, 2 )
+{
+}
+
+LineByVectorType::~LineByVectorType()
+{
+}
+
+const LineByVectorType* LineByVectorType::instance()
+{
+ static const LineByVectorType s;
+ return &s;
+}
+
+ObjectImp* LineByVectorType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const VectorImp& a = *static_cast<const VectorImp*>( args[0] );
+ const PointImp& b = *static_cast<const PointImp*>( args[1] );
+
+ return new LineImp( b.coordinate(), b.coordinate() + a.dir() );
+}
+
+const ObjectImpType* LineByVectorType::resultId() const
+{
+ return LineImp::stype();
+}
+
+static const ArgsParser::spec argsspecHalflineByVector[] =
+{
+ { VectorImp::stype(), I18N_NOOP( "Construct a half-line by this vector" ),
+ I18N_NOOP( "Select a vector in the direction of the new half-line..." ), true },
+ { PointImp::stype(), constructhalflinestartingstat,
+ I18N_NOOP( "Select the start point of the new half-line..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( HalflineByVectorType )
+
+HalflineByVectorType::HalflineByVectorType()
+ : ArgsParserObjectType( "HalflineByVector", argsspecHalflineByVector, 2 )
+{
+}
+
+HalflineByVectorType::~HalflineByVectorType()
+{
+}
+
+const HalflineByVectorType* HalflineByVectorType::instance()
+{
+ static const HalflineByVectorType s;
+ return &s;
+}
+
+ObjectImp* HalflineByVectorType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const VectorImp& a = *static_cast<const VectorImp*>( args[0] );
+ const PointImp& b = *static_cast<const PointImp*>( args[1] );
+
+ return new RayImp( b.coordinate(), b.coordinate() + a.dir() );
+}
+
+const ObjectImpType* HalflineByVectorType::resultId() const
+{
+ return RayImp::stype();
+}
diff --git a/kig/objects/line_type.h b/kig/objects/line_type.h
new file mode 100644
index 00000000..a3ded322
--- /dev/null
+++ b/kig/objects/line_type.h
@@ -0,0 +1,110 @@
+// Copyright (C) 2002 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.
+
+#ifndef KIG_OBJECTS_SEGMENT_H
+#define KIG_OBJECTS_SEGMENT_H
+
+#include "base_type.h"
+
+class LineData;
+
+class SegmentABType
+ : public ObjectABType
+{
+ SegmentABType();
+ ~SegmentABType();
+public:
+ static const SegmentABType* instance();
+
+ ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+
+ QStringList specialActions() const;
+ /**
+ * execute the \p i 'th action from the specialActions above..
+ */
+ void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& c,
+ KigPart& d, KigWidget& w, NormalMode& m ) const;
+};
+
+class LineABType
+ : public ObjectABType
+{
+ LineABType();
+ ~LineABType();
+public:
+ static const LineABType* instance();
+ ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class RayABType
+ : public ObjectABType
+{
+ RayABType();
+ ~RayABType();
+public:
+ static const RayABType* instance();
+ ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class LinePerpendLPType
+ : public ObjectLPType
+{
+ LinePerpendLPType();
+ ~LinePerpendLPType();
+public:
+ static LinePerpendLPType* instance();
+ ObjectImp* calc( const LineData& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class LineParallelLPType
+ : public ObjectLPType
+{
+ LineParallelLPType();
+ ~LineParallelLPType();
+public:
+ static LineParallelLPType* instance();
+ ObjectImp* calc( const LineData& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class LineByVectorType
+ : public ArgsParserObjectType
+{
+ LineByVectorType();
+ ~LineByVectorType();
+public:
+ static const LineByVectorType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class HalflineByVectorType
+ : public ArgsParserObjectType
+{
+ HalflineByVectorType();
+ ~HalflineByVectorType();
+public:
+ static const HalflineByVectorType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/locus_imp.cc b/kig/objects/locus_imp.cc
new file mode 100644
index 00000000..edbdc88b
--- /dev/null
+++ b/kig/objects/locus_imp.cc
@@ -0,0 +1,397 @@
+// 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 "locus_imp.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+#include "../misc/object_hierarchy.h"
+#include "../misc/kigpainter.h"
+#include "../misc/coordinate.h"
+#include "../misc/common.h"
+
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+#include <cmath>
+
+using namespace std;
+
+static double cachedparam = 0.0;
+
+LocusImp::~LocusImp()
+{
+ delete mcurve;
+}
+
+ObjectImp* LocusImp::transform( const Transformation& t ) const
+{
+ return new LocusImp( mcurve->copy(), mhier.transformFinalObject( t ) );
+}
+
+void LocusImp::draw( KigPainter& p ) const
+{
+ p.drawCurve( this );
+}
+
+bool LocusImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( p, w.screenInfo().normalMiss( width ), w.document() );
+}
+
+bool LocusImp::inRect( const Rect&, int, const KigWidget& ) const
+{
+ // TODO ?
+ return false;
+}
+
+const Coordinate LocusImp::getPoint( double param, const KigDocument& doc ) const
+{
+ Coordinate arg = mcurve->getPoint( param, doc );
+ if ( ! arg.valid() ) return arg;
+ PointImp argimp( arg );
+ Args args;
+ args.push_back( &argimp );
+ vector<ObjectImp*> calcret = mhier.calc( args, doc );
+ assert( calcret.size() == 1 );
+ ObjectImp* imp = calcret.front();
+ Coordinate ret;
+ if ( imp->inherits( PointImp::stype() ) )
+ {
+ cachedparam = param;
+ ret = static_cast<PointImp*>( imp )->coordinate();
+ }
+ else
+ ret = Coordinate::invalidCoord();
+
+ delete imp;
+ return ret;
+}
+
+LocusImp::LocusImp( CurveImp* curve, const ObjectHierarchy& hier )
+ : mcurve( curve ), mhier( hier )
+{
+}
+
+const uint LocusImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties();
+}
+
+const QCStringList LocusImp::propertiesInternalNames() const
+{
+ return Parent::propertiesInternalNames();
+}
+
+const QCStringList LocusImp::properties() const
+{
+ return Parent::properties();
+}
+
+const ObjectImpType* LocusImp::impRequirementForProperty( uint which ) const
+{
+ return Parent::impRequirementForProperty( which );
+}
+
+const char* LocusImp::iconForProperty( uint which ) const
+{
+ return Parent::iconForProperty( which );
+}
+
+ObjectImp* LocusImp::property( uint which, const KigDocument& w ) const
+{
+ return Parent::property( which, w );
+}
+
+LocusImp* LocusImp::copy() const
+{
+ return new LocusImp( mcurve->copy(), mhier );
+}
+
+const CurveImp* LocusImp::curve() const
+{
+ return mcurve;
+}
+
+const ObjectHierarchy& LocusImp::hierarchy() const
+{
+ return mhier;
+}
+
+/**
+ * This function returns the distance between the point with parameter
+ * param and point p. param is allowed to not be between 0 and 1, in
+ * which case we consider only the decimal part.
+ */
+double LocusImp::getDist(double param, const Coordinate& p, const KigDocument& doc) const
+{
+ param = fmod( param, 1 );
+ if( param < 0 ) param += 1.;
+ Coordinate p1 = getPoint( param, doc );
+ // i don't think the p1.valid() switch is really necessary, but I
+ // prefer to not take any chances :)
+ return p1.valid() ? ( p1 - p ).length() : +double_inf;
+}
+
+/**
+ * This function searches starting from x1 for the first interval in
+ * which the function of the distance from the point at coordinate x
+ * starts to increase. The range found is returned in the parameters
+ * x1 and x2: [x1,x2].
+ */
+void LocusImp::getInterval( double& x1, double& x2,
+ double incr,const Coordinate& p,
+ const KigDocument& doc) const
+{
+ double mm = getDist( x1, p, doc);
+ double mm1 = getDist( x2, p, doc);
+ if( mm <= mm1 ) return;
+ else
+ {
+ double x3 = x2 + incr;
+ double mm2 = getDist (x3, p, doc);
+ while( mm > mm1 & mm1 > mm2 )
+ {
+ x1 = x2;
+ x2 = x3;
+ x3 = x2 + incr;
+ mm = mm1;
+ mm1 = mm2;
+ mm2 = getDist (x3, p, doc);
+ }
+ x2=x3;
+ }
+}
+
+double LocusImp::getParam( const Coordinate& p, const KigDocument& doc ) const
+{
+ // this function ( and related functions like getInterval etc. ) is
+ // written by Franco Pasquarelli <pasqui@dmf.bs.unicatt.it>.
+ // I ( domi ) have adapted and documented it a bit.
+
+ if ( cachedparam >= 0. && cachedparam <= 1. &&
+ getPoint ( cachedparam, doc ) == p ) return cachedparam;
+
+ // consider the function that returns the distance for a point at
+ // parameter x to the locus for a given parameter x. What we do
+ // here is look for the global minimum of this function. We do that
+ // by dividing the range ( [0,1] ) into N parts, and start looking
+ // for a local minimum from there on. If we find one, we keep it if
+ // it is the lowest of all the ones we've already found..
+
+ const int N = 50;
+ const double incr = 1. / (double) N;
+
+ // xm is the best parameter we've found so far, fxm is the distance
+ // to the locus from that point. We start with some
+ // pseudo-values.
+ // (mp) note that if the distance is actually increasing in the
+ // whole interval [0,1] this value will be returned in the end.
+ double xm = 0.;
+ double fxm = getDist( xm, p, doc );
+
+ int j = 0;
+ double mm = fxm;
+
+ while( j < N )
+ {
+ // [x1,x2] is the range we're currently considering..
+ double x1 = j * incr;
+ double x2 = x1 + incr;
+
+ // check the range x1,x2 for the first local maximum..
+ double mm1 = getDist( x2, p, doc);
+ double mm2;
+ j++;
+ if( mm < mm1 )
+ mm = mm1;
+
+ else
+ {
+ if ( mm > mm1 )
+ {
+ double x3 = x2 + incr;
+ mm2 = getDist (x3, p, doc);
+ j++;
+ while( mm1 > mm2 & j <= N )
+ {
+ x1 = x2;
+ x2 = x3;
+ x3 = x2 + incr;
+ mm = mm1;
+ mm1 = mm2;
+ mm2 = getDist (x3, p, doc);
+ j++;
+ }
+ x2 = x3;
+ }
+ else
+ mm2 = mm1;
+
+ if ( mm1 <= mm2 )
+ {
+ mm = mm2;
+
+ double xm1 = getParamofmin( x1, x2, p, doc);
+ double fxm1 = getDist( xm1, p, doc );
+ if( fxm1 < fxm )
+ {
+ // we found a new minimum, save it..
+ xm=xm1;
+ fxm=fxm1;
+ }
+ }
+ }
+ }
+ return xm;
+}
+
+/**
+ * This function calculates the parameter of the point that realizes the
+ * minimum in [a,b] of the distance between the points of the locus and
+ * the point of coordinate p, using the golden ration method.
+ */
+double LocusImp::getParamofmin( double a, double b,
+ const Coordinate& p,
+ const KigDocument& doc ) const
+{
+ double epsilons = 1.e-08;
+ double epsilonl = 2.e-02;
+
+ //assert( a < b && a >= 0. && b <= 1.0);
+ assert( a < b && a >= 0.);
+
+ double r2 = ( sqrt( 5. ) - 1 ) / 2.; // golden ratio
+ double r1 = 1. - r2;
+
+ double t2 = a + r2 * ( b - a );
+ double t1 = a + r1 * ( b - a );
+ Coordinate p1 = getPoint( fmod( t1, 1. ), doc);
+ double f1 = (p1 - p).length();
+ Coordinate p2 = getPoint( fmod( t2, 1. ), doc);
+ double f2 = (p2 - p).length();
+
+ double fmin, tmin;
+ if (f1 < f2)
+ {
+ b = t2;
+ fmin = f1;
+ tmin = t1;
+ }
+ else
+ {
+ a = t1;
+ fmin = f2;
+ tmin = t2;
+ }
+
+ while ( ( b - a ) > epsilons &&
+ ( (p1 - p2).length() > 0.4 * fmin
+ || (b - a) > epsilonl) &&
+ fmin > 1.e-8 )
+ {
+ if ( f1 < f2 )
+ {
+ t2 = t1;
+ t1 = a + r1*(b - a);
+ f2 = f1;
+ p1 = getPoint( fmod( t1, 1. ), doc);
+ f1 = (p1 - p).length();
+ }
+ else
+ {
+ t1 = t2;
+ t2 = a + r2*(b - a);
+ f1 = f2;
+ p2 = getPoint( fmod( t2, 1. ), doc);
+ f2 = (p2 - p).length();
+ }
+ if ( f1 < f2 )
+ {
+ b = t2;
+ fmin = f1;
+ tmin = t1;
+ }
+ else
+ {
+ a = t1;
+ fmin = f2;
+ tmin = t2;
+ }
+ }
+
+ return(tmin);
+}
+
+void LocusImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool LocusImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( LocusImp::stype() ) &&
+ static_cast<const LocusImp&>( rhs ).curve()->equals( *curve() ) &&
+ static_cast<const LocusImp&>( rhs ).hierarchy() == hierarchy();
+}
+
+const ObjectImpType* LocusImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "locus",
+ I18N_NOOP( "locus" ),
+ I18N_NOOP( "Select this locus" ),
+ I18N_NOOP( "Select locus %1" ),
+ I18N_NOOP( "Remove a Locus" ),
+ I18N_NOOP( "Add a Locus" ),
+ I18N_NOOP( "Move a Locus" ),
+ I18N_NOOP( "Attach to this locus" ),
+ I18N_NOOP( "Show a Locus" ),
+ I18N_NOOP( "Hide a Locus" )
+ );
+ return &t;
+}
+
+const ObjectImpType* LocusImp::type() const
+{
+ return LocusImp::stype();
+}
+
+bool LocusImp::containsPoint( const Coordinate& p, const KigDocument& doc ) const
+{
+ return internalContainsPoint( p, test_threshold, doc );
+}
+
+bool LocusImp::internalContainsPoint( const Coordinate& p, double threshold, const KigDocument& doc ) const
+{
+ double param = getParam( p, doc );
+ double dist = getDist( param, p, doc );
+ return fabs( dist ) <= threshold;
+}
+
+bool LocusImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+}
+
+Rect LocusImp::surroundingRect() const
+{
+ // it's probably possible to calculate this, if it exists, but we
+ // don't for now.
+ return Rect::invalidRect();
+}
diff --git a/kig/objects/locus_imp.h b/kig/objects/locus_imp.h
new file mode 100644
index 00000000..568e0e7c
--- /dev/null
+++ b/kig/objects/locus_imp.h
@@ -0,0 +1,96 @@
+// 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.
+
+#ifndef KIG_OBJECTS_LOCUS_IMP_H
+#define KIG_OBJECTS_LOCUS_IMP_H
+
+#include "curve_imp.h"
+#include "../misc/object_hierarchy.h"
+
+/**
+ * LocusImp is an imp that consists of a copy of the curveimp that the
+ * moving point moves over, and an ObjectHierarchy that can calc (
+ * given a point, and optionally some more parent objects the position
+ * of the moving point. The hierarchy should take the moving point as
+ * its *first* argument and all others after that. The others are
+ * used to make it possible for Locus to be updated when some of the
+ * other objects that appear in the path from the moving point to the
+ * dependent point change.
+ *
+ * This may seem rather complicated, but I think it is absolutely
+ * necessary to support locuses using Kig's object system. It would
+ * be very bad for LocusImp to have to keep references to its parents
+ * as Objects ( since only the objects know how they are related to
+ * their parents ). This is how we used to do it, but the current
+ * method is far superior. First and foremost because the separation
+ * between ObjectImp and Object is something that Kig depends on very
+ * much, and because every ObjectImp should contain all the data it
+ * needs itself. ObjectImp's are entirely independent objects.
+ * That's also why we don't keep a pointer to the old CurveImp, but a
+ * copy of it..
+ *
+ * i hope this is a bit clear, if not, feel free to ask for
+ * explanation of what you don't understand..
+ */
+class LocusImp
+ : public CurveImp
+{
+ CurveImp* mcurve;
+ const ObjectHierarchy mhier;
+
+ double getDist(double param, const Coordinate& p, const KigDocument& doc) const;
+ void getInterval(double& x1,double& x2,double incr,const Coordinate& p, const KigDocument& doc) const;
+ double getParamofmin(double a, double b, const Coordinate& p, const KigDocument& doc) const;
+public:
+ typedef CurveImp Parent;
+ static const ObjectImpType* stype();
+
+ LocusImp( CurveImp*, const ObjectHierarchy& );
+ ~LocusImp();
+ LocusImp* copy() const;
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ Rect surroundingRect() const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ double getParam( const Coordinate& point, const KigDocument& ) const;
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+
+ // TODO ?
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ const CurveImp* curve() const;
+ const ObjectHierarchy& hierarchy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& d ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold, const KigDocument& doc ) const;
+};
+
+#endif
diff --git a/kig/objects/object_calcer.cc b/kig/objects/object_calcer.cc
new file mode 100644
index 00000000..40545ed1
--- /dev/null
+++ b/kig/objects/object_calcer.cc
@@ -0,0 +1,323 @@
+// 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 "object_calcer.h"
+
+#include "object_holder.h"
+#include "object_imp.h"
+#include "object_type.h"
+#include "../misc/coordinate.h"
+#include "common.h"
+
+#include <algorithm>
+#include <set>
+
+void ObjectTypeCalcer::calc( const KigDocument& doc )
+{
+ Args a;
+ a.reserve( mparents.size() );
+ std::transform( mparents.begin(), mparents.end(),
+ std::back_inserter( a ), std::mem_fun( &ObjectCalcer::imp ) );
+ ObjectImp* n = mtype->calc( a, doc );
+ delete mimp;
+ mimp = n;
+}
+
+ObjectTypeCalcer::ObjectTypeCalcer( const ObjectType* type,
+ const std::vector<ObjectCalcer*>& parents, bool sort )
+ : mparents( ( sort )?type->sortArgs( parents ):parents ), mtype( type ), mimp( 0 )
+{
+ std::for_each( mparents.begin(), mparents.end(),
+ std::bind2nd( std::mem_fun( &ObjectCalcer::addChild ), this ) );
+}
+
+ObjectCalcer::~ObjectCalcer()
+{
+}
+
+ObjectConstCalcer::ObjectConstCalcer( ObjectImp* imp )
+ : mimp( imp )
+{
+}
+
+ObjectConstCalcer::~ObjectConstCalcer()
+{
+ delete mimp;
+}
+
+const ObjectImp* ObjectConstCalcer::imp() const
+{
+ return mimp;
+}
+
+void ObjectConstCalcer::calc( const KigDocument& )
+{
+}
+
+std::vector<ObjectCalcer*> ObjectConstCalcer::parents() const
+{
+ // we have no parents..
+ return std::vector<ObjectCalcer*>();
+}
+
+void ObjectCalcer::ref()
+{
+ ++refcount;
+}
+
+void ObjectCalcer::deref()
+{
+ if ( --refcount <= 0 ) delete this;
+}
+
+void intrusive_ptr_add_ref( ObjectCalcer* p )
+{
+ p->ref();
+}
+
+void intrusive_ptr_release( ObjectCalcer* p )
+{
+ p->deref();
+}
+
+const ObjectImp* ObjectTypeCalcer::imp() const
+{
+ return mimp;
+}
+
+std::vector<ObjectCalcer*> ObjectTypeCalcer::parents() const
+{
+ return mparents;
+}
+
+void ObjectCalcer::addChild( ObjectCalcer* c )
+{
+ mchildren.push_back( c );
+ ref();
+}
+
+void ObjectCalcer::delChild( ObjectCalcer* c )
+{
+ std::vector<ObjectCalcer*>::iterator i = std::find( mchildren.begin(), mchildren.end(), c );
+ assert( i != mchildren.end() );
+
+ mchildren.erase( i );
+ deref();
+}
+
+ObjectTypeCalcer::~ObjectTypeCalcer()
+{
+ std::for_each( mparents.begin(), mparents.end(),
+ std::bind2nd( std::mem_fun( &ObjectCalcer::delChild ), this ) );
+ delete mimp;
+}
+
+const ObjectType* ObjectTypeCalcer::type() const
+{
+ return mtype;
+}
+
+ObjectPropertyCalcer::ObjectPropertyCalcer( ObjectCalcer* parent, int propid )
+ : mimp( 0 ), mparent( parent ), mpropid( propid )
+{
+ // Some weird C++ thing prevents me from calling protected members
+ // of ObjectCalcer on mparent.. This is an ugly workaround..
+ ( mparent->*&ObjectCalcer::addChild )( this );
+ //mparent->addChild( this );
+}
+
+ObjectPropertyCalcer::~ObjectPropertyCalcer()
+{
+ // Some weird C++ thing prevents me from calling protected members
+ // of ObjectCalcer on mparent.. This is an ugly workaround..
+ ( mparent->*&ObjectCalcer::delChild )( this );
+ //mparent->delChild( this );
+ delete mimp;
+}
+
+const ObjectImp* ObjectPropertyCalcer::imp() const
+{
+ return mimp;
+}
+
+std::vector<ObjectCalcer*> ObjectPropertyCalcer::parents() const
+{
+ std::vector<ObjectCalcer*> ret;
+ ret.push_back( mparent );
+ return ret;
+}
+
+void ObjectPropertyCalcer::calc( const KigDocument& doc )
+{
+ ObjectImp* n = mparent->imp()->property( mpropid, doc );
+ delete mimp;
+ mimp = n;
+}
+
+ObjectImp* ObjectConstCalcer::switchImp( ObjectImp* newimp )
+{
+ ObjectImp* ret = mimp;
+ mimp = newimp;
+ return ret;
+}
+
+std::vector<ObjectCalcer*> ObjectCalcer::children() const
+{
+ return mchildren;
+}
+
+const ObjectImpType* ObjectPropertyCalcer::impRequirement(
+ ObjectCalcer*, const std::vector<ObjectCalcer*>& ) const
+{
+ return mparent->imp()->impRequirementForProperty( mpropid );
+}
+
+const ObjectImpType* ObjectConstCalcer::impRequirement(
+ ObjectCalcer*, const std::vector<ObjectCalcer*>& ) const
+{
+ assert( false );
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ObjectTypeCalcer::impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const
+{
+ Args args;
+ args.reserve( mparents.size() );
+ std::transform(
+ os.begin(), os.end(),
+ std::back_inserter( args ),
+ std::mem_fun( &ObjectCalcer::imp ) );
+ assert( std::find( args.begin(), args.end(), o->imp() ) != args.end() );
+ return mtype->impRequirement( o->imp(), args );
+}
+
+int ObjectPropertyCalcer::propId() const
+{
+ return mpropid;
+}
+
+void ObjectConstCalcer::setImp( ObjectImp* newimp )
+{
+ delete switchImp( newimp );
+}
+
+void ObjectTypeCalcer::setParents( const std::vector<ObjectCalcer*> np )
+{
+ std::for_each( np.begin(), np.end(),
+ std::bind2nd( std::mem_fun( &ObjectCalcer::addChild ), this ) );
+ std::for_each( mparents.begin(), mparents.end(),
+ std::bind2nd( std::mem_fun( &ObjectCalcer::delChild ), this ) );
+ mparents = np;
+}
+
+void ObjectTypeCalcer::setType( const ObjectType* t )
+{
+ mtype = t;
+}
+
+bool ObjectCalcer::canMove() const
+{
+ return false;
+}
+
+bool ObjectCalcer::isFreelyTranslatable() const
+{
+ return false;
+}
+
+Coordinate ObjectCalcer::moveReferencePoint() const
+{
+ assert( false );
+ return Coordinate::invalidCoord();
+}
+
+void ObjectCalcer::move( const Coordinate&, const KigDocument& )
+{
+ assert( false );
+}
+
+bool ObjectTypeCalcer::canMove() const
+{
+ return mtype->canMove( *this );
+}
+
+bool ObjectTypeCalcer::isFreelyTranslatable() const
+{
+ return mtype->isFreelyTranslatable( *this );
+}
+
+Coordinate ObjectTypeCalcer::moveReferencePoint() const
+{
+ return mtype->moveReferencePoint( *this );
+}
+
+void ObjectTypeCalcer::move( const Coordinate& to, const KigDocument& doc )
+{
+ // we need to check if type can in fact move, because this check is
+ // not done for us in all circumstances ( e.g. LineABType::move uses
+ // move on its parents to move them ), and the ObjectType's depend
+ // on move only being called if canMove() returns true..
+ if ( mtype->canMove( *this ) )
+ mtype->move( *this, to, doc );
+}
+
+ObjectCalcer* ObjectPropertyCalcer::parent() const
+{
+ return mparent;
+}
+
+ObjectCalcer::ObjectCalcer()
+ : refcount( 0 )
+{
+}
+
+std::vector<ObjectCalcer*> ObjectCalcer::movableParents() const
+{
+ return std::vector<ObjectCalcer*>();
+}
+
+std::vector<ObjectCalcer*> ObjectTypeCalcer::movableParents() const
+{
+ return mtype->movableParents( *this );
+}
+
+bool ObjectConstCalcer::isDefinedOnOrThrough( const ObjectCalcer* ) const
+{
+ return false;
+}
+
+bool ObjectPropertyCalcer::isDefinedOnOrThrough( const ObjectCalcer* o ) const
+{
+ return o == mparent &&
+ mparent->imp()->isPropertyDefinedOnOrThroughThisImp( propId() );
+}
+
+bool ObjectTypeCalcer::isDefinedOnOrThrough( const ObjectCalcer* o ) const
+{
+ Args args;
+ args.reserve( mparents.size() );
+ std::transform(
+ mparents.begin(), mparents.end(),
+ std::back_inserter( args ),
+ std::mem_fun( &ObjectCalcer::imp ) );
+ if ( std::find( args.begin(), args.end(), o->imp() ) == args.end() )
+ return false;
+
+ return mtype->isDefinedOnOrThrough( o->imp(), args );
+}
+
diff --git a/kig/objects/object_calcer.h b/kig/objects/object_calcer.h
new file mode 100644
index 00000000..6df94fe8
--- /dev/null
+++ b/kig/objects/object_calcer.h
@@ -0,0 +1,301 @@
+// 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.
+
+#ifndef KIG_OBJECTS_OBJECT_CALCER_H
+#define KIG_OBJECTS_OBJECT_CALCER_H
+
+#include "common.h"
+#include "../misc/boost_intrusive_pointer.hpp"
+
+class ObjectCalcer;
+
+void intrusive_ptr_add_ref( ObjectCalcer* p );
+void intrusive_ptr_release( ObjectCalcer* p );
+
+/**
+ * An ObjectCalcer is an object that represents an algorithm for
+ * calculating an ObjectImp from other ObjectImp's. It is also a node
+ * in the dependency graph of a certain document. E.g. a LineImp can
+ * be calculated from the two PointImp's it has to go through; every
+ * time either of them moves, this calculation is redone. In this
+ * case, there would be an ObjectCalcer that keeps a reference to its
+ * two parents ( the ObjectCalcer's representing the points ), and
+ * that will calculate its ObjectImp value every time it is asked to
+ * do so ( i.e. every time one of its parents moves.. ).
+ *
+ * Each ObjectHolder keeps its ObjectImp itself, and recalculates it
+ * from its parents in its calc() method ( if necessary ).
+ *
+ * Because of the complex relations that ObjectCalcer's hold to other
+ * ObjectCalcer's and to other classes, they have been made
+ * reference-counted. This means that they keep a count internally of
+ * how much times a pointer to them is held. If this count reaches 0,
+ * this means that nobody needs them anymore, and they delete
+ * themselves. E.g. an ObjectCalcer always keeps a reference to its
+ * parents, to ensure that those aren't deleted before it is deleted.
+ *
+ * At runtime, there will be an entire graph of ObjectCalcer that
+ * depend on their parents.. At the bottom, there are Calcer's that
+ * the user is aware of, and that are held by ObjectHolder's. At the
+ * top, there are Calcer's without parents that serve only to hold
+ * some data. Those are most likely ObjectConstCalcer's. There are
+ * some algorithms to work with the dependency graph in various ways
+ * in ../misc/calcpath.h
+ *
+ * ObjectCalcer's also decide how an object should be allowed to
+ * move. If the user selects a point, and tries to move it, then its
+ * ObjectCalcer will be asked whether it can move, and if so, will be
+ * asked to move. See below with the canMove(), move() and
+ * moveReferencePoint() methods..
+ */
+class ObjectCalcer
+{
+protected:
+ /**
+ * ObjectCalcer's are reference counted.. They all take a reference
+ * to their parents, and some other classes like ObjectHolder take a
+ * reference to some ObjectCalcer's that they don't want to see
+ * deleted..
+ */
+ friend void intrusive_ptr_add_ref( ObjectCalcer* p );
+ friend void intrusive_ptr_release( ObjectCalcer* p );
+ int refcount;
+ void ref();
+ void deref();
+
+ // we keep track of our children, so algorithms can easily walk over
+ // the dependency graph..
+
+ std::vector<ObjectCalcer*> mchildren;
+
+ ObjectCalcer();
+public:
+ /**
+ * a calcer should call this to register itself as a child of this
+ * calcer. This automatically takes a reference.
+ */
+ void addChild( ObjectCalcer* c );
+ /**
+ * a calcer should call this in its destructor, to inform its parent
+ * that it is no longer a child of this calcer. This will release
+ * the reference taken in addChild..
+ */
+ void delChild( ObjectCalcer* c );
+
+ // use this pointer type to keep a reference to an ObjectCalcer...
+ typedef myboost::intrusive_ptr<ObjectCalcer> shared_ptr;
+
+ /**
+ * Returns the child ObjectCalcer's of this ObjectCalcer.
+ */
+ std::vector<ObjectCalcer*> children() const;
+
+ virtual ~ObjectCalcer();
+ /**
+ * Returns the parent ObjectCalcer's of this ObjectCalcer.
+ */
+ virtual std::vector<ObjectCalcer*> parents() const = 0;
+ /**
+ * Returns the ObjectImp of this ObjectCalcer.
+ */
+ virtual const ObjectImp* imp() const = 0;
+ /**
+ * Makes the ObjectCalcer recalculate its ObjectImp from its
+ * parents.
+ */
+ virtual void calc( const KigDocument& ) = 0;
+
+ /**
+ * An ObjectCalcer expects its parents to have an ObjectImp of a
+ * certain type. This method returns the ObjectImpType that \p o
+ * should have. \p os is a list of all the parents in order, and
+ * \p o is part of it. This method will return the ObjectImpType
+ * that the parent should *at least* be. For example, a Translated
+ * object can translate any sort of object, so it will return
+ * ObjectImp::stype() here ( the topmost ObjectImpType, that all
+ * other ObjectImpType's inherit ).
+ */
+ virtual const ObjectImpType* impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const = 0;
+
+ /**
+ * Returns whether this ObjectCalcer supports moving.
+ */
+ virtual bool canMove() const;
+ /**
+ * Returns whether this ObjectCalcer can be translated at any position
+ * in the coordinate plane. Note that a ConstrainedPointType can be
+ * moved, but cannot be moved everywhere.
+ */
+ virtual bool isFreelyTranslatable() const;
+ /**
+ * Moving an object most of the time signifies invoking changes in
+ * some of its parents. This method returns the set of parents that
+ * will be changed in the move() method. The object itself should
+ * not be included.
+ */
+ virtual std::vector<ObjectCalcer*> movableParents() const;
+ /**
+ * In order to support simultaneously moving objects that are in
+ * different locations, we need for each object a location that it
+ * is assumed to be at, at the moment the moving starts. This
+ * method returns such a point.
+ */
+ virtual Coordinate moveReferencePoint() const;
+ /**
+ * This is the method that does the real moving work. It will be
+ * invoked to tell the object to move to the new location to. After
+ * this, the calc() method will be calced, so you only need to do
+ * the real changes in this method, updating the ObjectImp should be
+ * done in the calc() method, not here.
+ */
+ virtual void move( const Coordinate& to, const KigDocument& doc );
+
+ /**
+ * If this ObjectCalcer represents a curve, return true if the given
+ * point is by construction on this curve. If this ObjectCalcer
+ * represents a point, return true if this point is by construction
+ * on the given curve.
+ */
+ virtual bool isDefinedOnOrThrough( const ObjectCalcer* o ) const = 0;
+};
+
+/**
+ * This is an ObjectCalcer that uses one of the various ObjectType's
+ * to calculate its ObjectImp. It basically forwards all of its
+ * functionality to the ObjectType that it holds a pointer to.
+ */
+class ObjectTypeCalcer
+ : public ObjectCalcer
+{
+ std::vector<ObjectCalcer*> mparents;
+ const ObjectType* mtype;
+ ObjectImp* mimp;
+public:
+ typedef myboost::intrusive_ptr<ObjectTypeCalcer> shared_ptr;
+ /**
+ * Construct a new ObjectTypeCalcer with a given type and parents.
+ */
+// ObjectTypeCalcer( const ObjectType* type, const std::vector<ObjectCalcer*>& parents );
+ /**
+ * the sort boolean tells whether the sortArgs method should be invoked or not;
+ * if not present
+ */
+ ObjectTypeCalcer( const ObjectType* type, const std::vector<ObjectCalcer*>& parents, bool sort=true );
+ ~ObjectTypeCalcer();
+
+ const ObjectImp* imp() const;
+ std::vector<ObjectCalcer*> parents() const;
+ void calc( const KigDocument& doc );
+
+ /**
+ * Set the parents of this ObjectTypeCalcer to np. This object will
+ * release the reference it had to its old parents, and take a new
+ * one on the new parents.
+ */
+ void setParents( const std::vector<ObjectCalcer*> np );
+ void setType( const ObjectType* t );
+
+ const ObjectType* type() const;
+
+ const ObjectImpType* impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const;
+ bool isDefinedOnOrThrough( const ObjectCalcer* o ) const;
+ bool canMove() const;
+ bool isFreelyTranslatable() const;
+ std::vector<ObjectCalcer*> movableParents() const;
+ Coordinate moveReferencePoint() const;
+ void move( const Coordinate& to, const KigDocument& doc );
+};
+
+/**
+ * This is an ObjectCalcer that keeps an ObjectImp, and never
+ * calculates a new one. It is a trivial, but very useful
+ * ObjectCalcer. It is used often in Kig, for holding data to be used
+ * by other ObjectCalcer's.
+ */
+class ObjectConstCalcer
+ : public ObjectCalcer
+{
+ ObjectImp* mimp;
+public:
+ typedef myboost::intrusive_ptr<ObjectConstCalcer> shared_ptr;
+
+ /**
+ * Construct a new ObjectConstCalcer with the given imp as the
+ * stored ObjectImp.
+ *
+ * This class takes ownership of the imp you pass it, it should have
+ * been constructed using new, and this class is responsible for
+ * deleting it.
+ */
+ ObjectConstCalcer( ObjectImp* imp );
+ ~ObjectConstCalcer();
+
+ const ObjectImp* imp() const;
+ void calc( const KigDocument& doc );
+ std::vector<ObjectCalcer*> parents() const;
+
+ /**
+ * Set the ObjectImp of this ObjectConstCalcer to the given
+ * newimp. The old one will be deleted.
+ */
+ void setImp( ObjectImp* newimp );
+ /**
+ * Set the ObjectImp of this ObjectConstCalcer to the given
+ * newimp. The old one will not be deleted, but returned.
+ */
+ ObjectImp* switchImp( ObjectImp* newimp );
+
+ const ObjectImpType* impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const;
+ bool isDefinedOnOrThrough( const ObjectCalcer* o ) const;
+};
+
+/**
+ * This is an ObjectCalcer that has a single parent, and gets a
+ * certain property from it in its calc() method.
+ *
+ * \see ObjectImp::property
+ */
+class ObjectPropertyCalcer
+ : public ObjectCalcer
+{
+ ObjectImp* mimp;
+ ObjectCalcer* mparent;
+ int mpropid;
+public:
+ /**
+ * Construct a new ObjectPropertyCalcer, that will get the property
+ * from parent with number propid.
+ */
+ ObjectPropertyCalcer( ObjectCalcer* parent, int propid );
+ ~ObjectPropertyCalcer();
+
+ const ObjectImp* imp() const;
+ std::vector<ObjectCalcer*> parents() const;
+ void calc( const KigDocument& doc );
+
+ int propId() const;
+ ObjectCalcer* parent() const;
+
+ const ObjectImpType* impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const;
+ bool isDefinedOnOrThrough( const ObjectCalcer* o ) const;
+};
+
+#endif
diff --git a/kig/objects/object_drawer.cc b/kig/objects/object_drawer.cc
new file mode 100644
index 00000000..0989d4f2
--- /dev/null
+++ b/kig/objects/object_drawer.cc
@@ -0,0 +1,204 @@
+// 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 "object_drawer.h"
+
+#include "object_imp.h"
+#include "../misc/kigpainter.h"
+
+#include <qpen.h>
+#include <qnamespace.h>
+#include <cassert>
+
+#include <kdebug.h>
+
+void ObjectDrawer::draw( const ObjectImp& imp, KigPainter& p, bool sel ) const
+{
+ bool nv = p.getNightVision( );
+ if ( mshown || nv )
+ {
+ p.setBrushStyle( Qt::NoBrush );
+ p.setBrushColor( sel ? Qt::red : ( mshown?mcolor:Qt::gray ) );
+ p.setPen( QPen ( sel ? Qt::red : ( mshown?mcolor:Qt::gray ), 1) );
+ p.setWidth( mwidth );
+ p.setStyle( mstyle );
+ p.setPointStyle( mpointstyle );
+ imp.draw( p );
+ }
+}
+
+bool ObjectDrawer::contains( const ObjectImp& imp, const Coordinate& pt, const KigWidget& w, bool nv ) const
+{
+ bool shownornv = mshown || nv;
+ return shownornv && imp.contains( pt, mwidth, w );
+}
+
+bool ObjectDrawer::shown( ) const
+{
+ return mshown;
+}
+
+QColor ObjectDrawer::color() const
+{
+ return mcolor;
+}
+
+ObjectDrawer* ObjectDrawer::getCopyShown( bool s ) const
+{
+ ObjectDrawer* ret = new ObjectDrawer;
+ ret->mcolor = mcolor;
+ ret->mshown = s;
+ ret->mwidth = mwidth;
+ ret->mstyle = mstyle;
+ ret->mpointstyle = mpointstyle;
+ return ret;
+}
+
+ObjectDrawer* ObjectDrawer::getCopyColor( const QColor& c ) const
+{
+ ObjectDrawer* ret = new ObjectDrawer;
+ ret->mcolor = c;
+ ret->mshown = mshown;
+ ret->mwidth = mwidth;
+ ret->mstyle = mstyle;
+ ret->mpointstyle = mpointstyle;
+ return ret;
+}
+
+ObjectDrawer* ObjectDrawer::getCopyWidth( int w ) const
+{
+ ObjectDrawer* ret = new ObjectDrawer;
+ ret->mcolor = mcolor;
+ ret->mshown = mshown;
+ ret->mwidth = w;
+ ret->mstyle = mstyle;
+ ret->mpointstyle = mpointstyle;
+ return ret;
+}
+
+ObjectDrawer* ObjectDrawer::getCopyStyle( Qt::PenStyle s ) const
+{
+ ObjectDrawer* ret = new ObjectDrawer;
+ ret->mcolor = mcolor;
+ ret->mshown = mshown;
+ ret->mwidth = mwidth;
+ ret->mstyle = s;
+ ret->mpointstyle = mpointstyle;
+ return ret;
+}
+
+ObjectDrawer* ObjectDrawer::getCopyPointStyle( int p ) const
+{
+ ObjectDrawer* ret = new ObjectDrawer;
+ ret->mcolor = mcolor;
+ ret->mshown = mshown;
+ ret->mwidth = mwidth;
+ ret->mstyle = mstyle;
+ ret->mpointstyle = p;
+ return ret;
+}
+
+int ObjectDrawer::width() const
+{
+ return mwidth;
+}
+
+Qt::PenStyle ObjectDrawer::style() const
+{
+ return mstyle;
+}
+
+int ObjectDrawer::pointStyle() const
+{
+ return mpointstyle;
+}
+
+ObjectDrawer::ObjectDrawer( const QColor& color, int width, bool shown, Qt::PenStyle style, int pointStyle )
+ : mcolor( color ), mshown( shown ), mwidth( width ), mstyle( style ), mpointstyle( pointStyle )
+{
+}
+
+ObjectDrawer::ObjectDrawer()
+ : mcolor( Qt::blue ), mshown( true ), mwidth( -1 ), mstyle( Qt::SolidLine ), mpointstyle( 0 )
+{
+}
+
+bool ObjectDrawer::inRect( const ObjectImp& imp, const Rect& r, const KigWidget& w ) const
+{
+ return mshown && imp.inRect( r, mwidth, w );
+}
+
+int ObjectDrawer::pointStyleFromString( const QString& style )
+{
+ if ( style == "Round" )
+ return 0;
+ else if ( style == "RoundEmpty" )
+ return 1;
+ else if ( style == "Rectangular" )
+ return 2;
+ else if ( style == "RectangularEmpty" )
+ return 3;
+ else if ( style == "Cross" )
+ return 4;
+ return 0;
+}
+
+QString ObjectDrawer::pointStyleToString() const
+{
+ if ( mpointstyle == 0 )
+ return "Round";
+ else if ( mpointstyle == 1 )
+ return "RoundEmpty";
+ else if ( mpointstyle == 2 )
+ return "Rectangular";
+ else if ( mpointstyle == 3 )
+ return "RectangularEmpty";
+ else if ( mpointstyle == 4 )
+ return "Cross";
+ assert( false );
+ return QString::null;
+}
+
+Qt::PenStyle ObjectDrawer::styleFromString( const QString& style )
+{
+ if ( style == "SolidLine" )
+ return Qt::SolidLine;
+ else if ( style == "DashLine" )
+ return Qt::DashLine;
+ else if ( style == "DotLine" )
+ return Qt::DotLine;
+ else if ( style == "DashDotLine" )
+ return Qt::DashDotLine;
+ else if ( style == "DashDotDotLine" )
+ return Qt::DashDotDotLine;
+ else return Qt::SolidLine;
+}
+
+QString ObjectDrawer::styleToString() const
+{
+ if ( mstyle == Qt::SolidLine )
+ return "SolidLine";
+ else if ( mstyle == Qt::DashLine )
+ return "DashLine";
+ else if ( mstyle == Qt::DotLine )
+ return "DotLine";
+ else if ( mstyle == Qt::DashDotLine )
+ return "DashDotLine";
+ else if ( mstyle == Qt::DashDotDotLine )
+ return "DashDotDotLine";
+ return "SolidLine";
+}
diff --git a/kig/objects/object_drawer.h b/kig/objects/object_drawer.h
new file mode 100644
index 00000000..2781acdc
--- /dev/null
+++ b/kig/objects/object_drawer.h
@@ -0,0 +1,146 @@
+// 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.
+
+#ifndef KIG_OBJECTS_OBJECT_DRAWER_H
+#define KIG_OBJECTS_OBJECT_DRAWER_H
+
+#include <qcolor.h>
+#include <qnamespace.h>
+
+class ObjectImp;
+class KigPainter;
+class Coordinate;
+class KigWidget;
+class Rect;
+
+/**
+ * A class holding some information about how a certain object is
+ * drawn on the window.
+ *
+ * An ObjectDrawer is used by an ObjectHolder to keep information
+ * about how to draw an ObjectImp on the window. It is really nothing
+ * more than a struct with some convenience methods. It does not have
+ * any virtual methods, or have any complex semantics. It keeps
+ * information like the thickness of an object, its color, and whether
+ * or not it is hidden.
+ *
+ * \note The default width of an object depends on its type. E.g. A
+ * point is by default drawn at width 5, a line at width 1.
+ * Therefore, there is a special width -1, which means "the default
+ * width for this object".
+ */
+class ObjectDrawer
+{
+ QColor mcolor;
+ bool mshown;
+ int mwidth;
+ Qt::PenStyle mstyle;
+ int mpointstyle;
+public:
+ /**
+ * Construct a new ObjectDrawer with a default color ( Qt::blue ),
+ * width ( -1 ), shown state ( true ), PenStyle ( Qt::SolidLine ),
+ * and pointstyle ( 0 )
+ */
+ ObjectDrawer();
+ ObjectDrawer( const QColor& color, int width = -1, bool shown = true, Qt::PenStyle = Qt::SolidLine, int pointStyle = 0 );
+ /**
+ * Draw the object \p imp on kigpainter \p p . If \p selected is true, it is
+ * drawn in red, otherwise in its normal color.
+ */
+ void draw( const ObjectImp& imp, KigPainter& p, bool selected ) const;
+ /**
+ * returns whether the object \p imp contains coordinate \p p . This is
+ * dependent on whether it is shown ( when it will never contain
+ * anything ), and on its width..
+ */
+ bool contains( const ObjectImp& imp, const Coordinate& pt, const KigWidget& w, bool nv = false ) const;
+ /**
+ * returns whether the object \p imp is in the rectangle \p r . This is
+ * dependent on whether it is shown and on its width..
+ */
+ bool inRect( const ObjectImp& imp, const Rect& r, const KigWidget& w ) const;
+
+ /**
+ * returns whether the object this ObjectDrawer is responsible for
+ * will be drawn or not..
+ */
+ bool shown() const;
+ /**
+ * returns the color that the object will be drawn in
+ */
+ QColor color() const;
+ /**
+ * return the width of the object
+ */
+ int width() const;
+ /**
+ * return PenStyle for all objects except points
+ */
+ Qt::PenStyle style() const;
+ /**
+ * return pointStyle for points
+ */
+ int pointStyle() const;
+ /**
+ * return pointStyle trasnformed in a string
+ */
+ QString pointStyleToString() const;
+ /**
+ * return style trasnformed in a string
+ */
+ QString styleToString() const;
+ /**
+ * returns a new ObjectDrawer that is identical to this one.. except
+ * that the shown state is set to \p s ..
+ */
+ ObjectDrawer* getCopyShown( bool s ) const;
+ /**
+ * returns a new ObjectDrawer that is identical to this one.. except
+ * that the color is set to \p c ..
+ */
+ ObjectDrawer* getCopyColor( const QColor& c ) const;
+ /**
+ * returns a new ObjectDrawer that is identical to this one.. except
+ * that the width is set to \p w ..
+ */
+ ObjectDrawer* getCopyWidth( int w ) const;
+ /**
+ * returns a new ObjectDrawer that is identical to this one.. except
+ * that the PenStyle state is set to \p s ..
+ */
+ ObjectDrawer* getCopyStyle( Qt::PenStyle s ) const;
+ /**
+ * returns a new ObjectDrawer that is identical to this one.. except
+ * that the pointStyle state is set to \p p ..
+ */
+ ObjectDrawer* getCopyPointStyle( int p ) const;
+ /**
+ * Note that this returns a valid point style in every case, even if
+ * the given \p style string is unknown. In that case it returns a
+ * default value.
+ */
+ static int pointStyleFromString( const QString& style );
+ /**
+ * Note that this returns a valid style in every case, even if the
+ * given \p style string is unknown. In that case it returns a default
+ * value.
+ */
+ static Qt::PenStyle styleFromString( const QString& style );
+};
+
+#endif
diff --git a/kig/objects/object_factory.cc b/kig/objects/object_factory.cc
new file mode 100644
index 00000000..a54e01f0
--- /dev/null
+++ b/kig/objects/object_factory.cc
@@ -0,0 +1,369 @@
+// Copyright (C) 2002 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 "object_factory.h"
+
+#include "bogus_imp.h"
+#include "curve_imp.h"
+#include "intersection_types.h"
+#include "line_imp.h"
+#include "object_drawer.h"
+#include "object_holder.h"
+#include "other_type.h"
+#include "point_imp.h"
+#include "point_type.h"
+#include "text_type.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+#include "../misc/calcpaths.h"
+#include "../misc/coordinate.h"
+#include "../misc/object_hierarchy.h"
+
+#include <algorithm>
+#include <functional>
+
+ObjectHolder* ObjectFactory::fixedPoint( const Coordinate& c ) const
+{
+ ObjectHolder* o = new ObjectHolder( fixedPointCalcer( c ) );
+ return o;
+}
+
+ObjectTypeCalcer* ObjectFactory::fixedPointCalcer( const Coordinate& c ) const
+{
+ std::vector<ObjectCalcer*> args;
+ args.push_back( new ObjectConstCalcer( new DoubleImp( c.x ) ) );
+ args.push_back( new ObjectConstCalcer( new DoubleImp( c.y ) ) );
+ ObjectTypeCalcer* oc = new ObjectTypeCalcer( FixedPointType::instance(), args );
+ return oc;
+}
+
+ObjectTypeCalcer* ObjectFactory::cursorPointCalcer( const Coordinate& c ) const
+{
+ std::vector<ObjectCalcer*> args;
+ args.push_back( new ObjectConstCalcer( new DoubleImp( c.x ) ) );
+ args.push_back( new ObjectConstCalcer( new DoubleImp( c.y ) ) );
+ ObjectTypeCalcer* oc = new ObjectTypeCalcer( CursorPointType::instance(), args );
+ return oc;
+}
+
+const ObjectFactory* ObjectFactory::instance()
+{
+ static ObjectFactory f;
+ return &f;
+}
+
+ObjectTypeCalcer* ObjectFactory::sensiblePointCalcer(
+ const Coordinate& c, const KigDocument& d, const KigWidget& w ) const
+{
+ std::vector<ObjectHolder*> os = d.whatAmIOn( c, w );
+ if ( os.size() == 2 )
+ {
+ // we can calc intersection point *olny* between two objects...
+ std::vector<ObjectCalcer*> args;
+ args.push_back( os[0]->calcer() );
+ args.push_back( os[1]->calcer() );
+ // the simpliest case: two lines...
+ if ( ( os[0]->imp()->inherits( AbstractLineImp::stype() ) ) &&
+ ( os[1]->imp()->inherits( AbstractLineImp::stype() ) ) )
+ return new ObjectTypeCalcer( LineLineIntersectionType::instance(), args );
+ // other cases will follow...
+ }
+ for ( std::vector<ObjectHolder*>::iterator i = os.begin(); i != os.end(); ++i )
+ if ( (*i)->imp()->inherits( CurveImp::stype() ) )
+ return constrainedPointCalcer( (*i)->calcer(), c, d );
+ return fixedPointCalcer( c );
+}
+
+ObjectHolder* ObjectFactory::sensiblePoint(
+ const Coordinate& c, const KigDocument& d, const KigWidget& w ) const
+{
+ return new ObjectHolder( sensiblePointCalcer( c, d, w ) );
+}
+
+ObjectTypeCalcer* ObjectFactory::relativePointCalcer(
+ ObjectCalcer* o, const Coordinate& loc ) const
+{
+ Coordinate reference =
+ static_cast<const ObjectImp*>( o->imp() )->attachPoint();
+ assert( reference.valid() );
+
+ double x = 0.0;
+ double y = 0.0;
+ if ( loc.valid() )
+ {
+ x = loc.x - reference.x;
+ y = loc.y - reference.y;
+ }
+ std::vector<ObjectCalcer*> parents;
+ parents.push_back( new ObjectConstCalcer( new DoubleImp( x ) ) );
+ parents.push_back( new ObjectConstCalcer( new DoubleImp( y ) ) );
+ parents.push_back( o );
+ return new ObjectTypeCalcer( RelativePointType::instance(), parents );
+}
+
+ObjectTypeCalcer* ObjectFactory::constrainedPointCalcer(
+ ObjectCalcer* curve, double param ) const
+{
+ assert( curve->imp()->inherits( CurveImp::stype() ) );
+ std::vector<ObjectCalcer*> parents;
+ parents.push_back( new ObjectConstCalcer( new DoubleImp( param ) ) );
+ parents.push_back( curve );
+ return new ObjectTypeCalcer( ConstrainedPointType::instance(), parents );
+}
+
+ObjectHolder* ObjectFactory::constrainedPoint(
+ ObjectCalcer* curve, double param ) const
+{
+ return new ObjectHolder( constrainedPointCalcer( curve, param ) );
+}
+
+ObjectTypeCalcer* ObjectFactory::constrainedPointCalcer(
+ ObjectCalcer* curve, const Coordinate& c, const KigDocument& d ) const
+{
+ assert( curve->imp()->inherits( CurveImp::stype() ) );
+ double param = static_cast<const CurveImp*>( curve->imp() )->getParam( c, d );
+ return constrainedPointCalcer( curve, param );
+}
+
+ObjectHolder* ObjectFactory::constrainedPoint(
+ ObjectCalcer* curve, const Coordinate& c, const KigDocument& d ) const
+{
+ return new ObjectHolder( constrainedPointCalcer( curve, c, d ) );
+}
+
+ObjectTypeCalcer* ObjectFactory::locusCalcer(
+ ObjectCalcer* a, ObjectCalcer* b ) const
+{
+ assert( dynamic_cast<const ObjectTypeCalcer*>( a ) );
+ ObjectTypeCalcer* constrained = static_cast<ObjectTypeCalcer*>( a );
+ assert( constrained->type()->inherits( ObjectType::ID_ConstrainedPointType ) );
+ assert( constrained->parents().size() == 2 );
+ ObjectCalcer* curve = a->parents().back();
+
+ const ObjectCalcer* moving = b;
+
+ std::vector<ObjectCalcer*> hierparents;
+ hierparents.push_back( constrained );
+ std::vector<ObjectCalcer*> sideOfTree = sideOfTreePath( hierparents, moving );
+ std::copy( sideOfTree.begin(), sideOfTree.end(), std::back_inserter( hierparents ) );
+
+ ObjectHierarchy hier( hierparents, moving );
+
+ std::vector<ObjectCalcer*> realparents( 2 + sideOfTree.size(), 0 );
+ realparents[0] = new ObjectConstCalcer( new HierarchyImp( hier ) );
+ realparents[1] = curve;
+ copy( sideOfTree.begin(), sideOfTree.end(), realparents.begin() + 2 );
+
+ return new ObjectTypeCalcer( LocusType::instance(), realparents );
+}
+
+ObjectHolder* ObjectFactory::locus( ObjectCalcer* a, ObjectCalcer* b ) const
+{
+ return new ObjectHolder( locusCalcer( a, b ) );
+}
+
+ObjectHolder* ObjectFactory::label(
+ const QString& s, const Coordinate& loc,
+ bool needframe, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const
+{
+ return new ObjectHolder( labelCalcer( s, loc, needframe, parents, doc ) );
+}
+
+ObjectTypeCalcer* ObjectFactory::labelCalcer(
+ const QString& s, const Coordinate& loc,
+ bool needframe, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const
+{
+ return attachedLabelCalcer( s, 0, loc, needframe, parents, doc );
+}
+
+ObjectTypeCalcer* ObjectFactory::attachedLabelCalcer(
+ const QString& s, ObjectCalcer* p,
+ const Coordinate& loc, bool needframe,
+ const std::vector<ObjectCalcer*>& nparents,
+ const KigDocument& doc ) const
+{
+ std::vector<ObjectCalcer*> parents;
+ parents.reserve( nparents.size() + 3 );
+ parents.push_back( new ObjectConstCalcer( new IntImp( needframe ? 1 : 0 ) ) );
+
+ parents.push_back( getAttachPoint( p, loc, doc ) );
+
+ parents.push_back( new ObjectConstCalcer( new StringImp( s ) ) );
+ std::copy( nparents.begin(), nparents.end(), std::back_inserter( parents ) );
+ ObjectTypeCalcer* ret = new ObjectTypeCalcer( TextType::instance(), parents );
+ ret->calc( doc );
+ return ret;
+}
+
+ObjectCalcer* ObjectFactory::getAttachPoint(
+ ObjectCalcer* p,
+ const Coordinate& loc,
+ const KigDocument& doc ) const
+{
+/*
+ * mp: (changes to add relative-attachment). Now an object is tested
+ * as follows:
+ * - if attachPoint() returns a valid coordinate, then we use the new method
+ * - if it is a point: 'old-style' treatment (we can change this shortly)
+ * - if it is a curve: 'old-style' treatment (we could use the new approach,
+ * which can be better/worse depending on personal taste, I think)
+ *
+ * the first condition that matches determines the behaviour.
+ * the new method works similarly to the curve case, but we generate a new
+ * RelativePointType instead of a ConstrainedPointType; this will in turn make use
+ * of the new attachPoint() method for objects.
+ *
+ * changed the preference order 2005/01/21 (now attachPoint has preference over points)
+ *
+ * NOTE: changes in the tests performed should be matched also in
+ * modes/popup.cc (addNameLabel) and in label.cc (TextLabelModeBase::mouseMoved)
+ */
+
+ if ( p && p->imp()->attachPoint().valid() )
+ {
+ ObjectCalcer* o = relativePointCalcer( p, loc );
+ o->calc( doc );
+ return o;
+ }
+ else if ( p && p->imp()->inherits( PointImp::stype() ) )
+ {
+ return p;
+ }
+ else if ( p && p->imp()->inherits( CurveImp::stype() ) )
+ {
+ double param = 0.5;
+ if ( loc.valid() )
+ param = static_cast<const CurveImp*>( p->imp() )->getParam( loc, doc );
+
+ ObjectCalcer* o = constrainedPointCalcer( p, param );
+ o->calc( doc );
+ return o;
+ }
+ else
+ {
+ if ( loc.valid() )
+ return new ObjectConstCalcer( new PointImp( loc ) );
+ else
+ return new ObjectConstCalcer( new PointImp( Coordinate( 0, 0 ) ) );
+ }
+}
+
+ObjectHolder* ObjectFactory::attachedLabel(
+ const QString& s, ObjectCalcer* locationparent,
+ const Coordinate& loc, bool needframe,
+ const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const
+{
+ return new ObjectHolder( attachedLabelCalcer( s, locationparent, loc, needframe, parents, doc ) );
+}
+
+ObjectPropertyCalcer* ObjectFactory::propertyObjectCalcer(
+ ObjectCalcer* o, const char* p ) const
+{
+ int wp = o->imp()->propertiesInternalNames().findIndex( p );
+ if ( wp == -1 ) return 0;
+ return new ObjectPropertyCalcer( o, wp );
+}
+
+ObjectHolder* ObjectFactory::propertyObject(
+ ObjectCalcer* o, const char* p ) const
+{
+ return new ObjectHolder( propertyObjectCalcer( o, p ) );
+}
+
+void ObjectFactory::redefinePoint(
+ ObjectTypeCalcer* point, const Coordinate& c,
+ KigDocument& doc, const KigWidget& w ) const
+{
+ std::vector<ObjectHolder*> hos = doc.whatAmIOn( c, w );
+ std::vector<ObjectCalcer*> os;
+ ObjectCalcer* (ObjectHolder::*calcmeth)() = &ObjectHolder::calcer;
+ std::transform( hos.begin(), hos.end(), std::back_inserter( os ),
+ std::mem_fun( calcmeth ) );
+ ObjectCalcer* v = 0;
+
+ // we don't want one of our children as a parent...
+ std::set<ObjectCalcer*> children = getAllChildren( point );
+ for ( std::vector<ObjectCalcer*>::iterator i = os.begin();
+ i != os.end(); ++i )
+ if ( (*i)->imp()->inherits( CurveImp::stype() ) &&
+ children.find( *i ) == children.end() )
+ {
+ v = *i;
+ break;
+ };
+
+ if ( v )
+ {
+ // we want a constrained point...
+ const CurveImp* curveimp = static_cast<const CurveImp*>( v->imp() );
+ double newparam = curveimp->getParam( c, doc );
+
+ if ( point->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
+ {
+ // point already was constrained -> simply update the param
+ // DataObject and make sure point is on the right curve...
+ ObjectCalcer* dataobj = 0;
+ std::vector<ObjectCalcer*> parents = point->parents();
+ assert( parents.size() == 2 );
+ assert ( parents[0]->imp()->inherits( DoubleImp::stype() ) );
+ dataobj = parents[0];
+
+ parents.clear();
+ parents.push_back( dataobj );
+ parents.push_back( v );
+ point->setParents( parents );
+
+ assert( dynamic_cast<ObjectConstCalcer*>( dataobj ) );
+ static_cast<ObjectConstCalcer*>( dataobj )->setImp(
+ new DoubleImp( newparam ) );
+ }
+ else
+ {
+ // point used to be fixed -> add a new DataObject etc.
+ std::vector<ObjectCalcer*> args;
+ args.push_back( new ObjectConstCalcer( new DoubleImp( newparam ) ) );
+ args.push_back( v );
+ point->setType( ConstrainedPointType::instance() );
+ point->setParents( args );
+ }
+ }
+ else
+ {
+ // a fixed point...
+ if ( point->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
+ {
+ // point used to be constrained..
+ std::vector<ObjectCalcer*> a;
+ a.push_back( new ObjectConstCalcer( new DoubleImp( c.x ) ) );
+ a.push_back( new ObjectConstCalcer( new DoubleImp( c.y ) ) );
+
+ point->setType( FixedPointType::instance() );
+ point->setParents( a );
+ }
+ else
+ {
+ // point used to be fixed -> simply update the DataObject's
+ // we can use the point's move function for that..
+ point->move( c, doc );
+ };
+ }
+}
+
diff --git a/kig/objects/object_factory.h b/kig/objects/object_factory.h
new file mode 100644
index 00000000..0ce6ce62
--- /dev/null
+++ b/kig/objects/object_factory.h
@@ -0,0 +1,145 @@
+// Copyright (C) 2002 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.
+
+#ifndef KIG_OBJECTS_OBJECT_FACTORY_H
+#define KIG_OBJECTS_OBJECT_FACTORY_H
+
+#include "common.h"
+
+class ObjectFactory
+{
+public:
+
+ static const ObjectFactory* instance();
+
+ /**
+ * this returns a fixed point. Note that the returned object is
+ * not added to the document..
+ */
+ ObjectHolder* fixedPoint( const Coordinate& c ) const;
+ ObjectTypeCalcer* fixedPointCalcer( const Coordinate& c ) const;
+
+ /**
+ * this returns a CursorPointType; this is used during special
+ * constructions (e.g. regular polygons) where the constructor
+ * wants to use the cursor position without actually generating
+ * an object depending on a new point there.
+ */
+ ObjectTypeCalcer* cursorPointCalcer( const Coordinate& c ) const;
+
+ /**
+ * this returns a relative point (to an object). Note that the returned object
+ * is not added to the document..
+ */
+ ObjectTypeCalcer* relativePointCalcer( ObjectCalcer* o, const Coordinate& loc ) const;
+
+ /**
+ * this returns a constrained point. Note that the returned object
+ * is not added to the document..
+ */
+ ObjectHolder* constrainedPoint( ObjectCalcer* curve, double param ) const;
+ ObjectTypeCalcer* constrainedPointCalcer( ObjectCalcer* curve, double param ) const;
+ /**
+ * \overload, changes nothing to the semantics, only calcs the param
+ * value for you..
+ */
+ ObjectTypeCalcer* constrainedPointCalcer(
+ ObjectCalcer* curve, const Coordinate& c, const KigDocument& ) const;
+ ObjectHolder* constrainedPoint(
+ ObjectCalcer* curve, const Coordinate& c, const KigDocument& ) const;
+
+ /**
+ * this returns a "sensible point".
+ * By a "sensible point", I mean a point that would be about what
+ * the user expects when he asks for a point at point \p c . This is a
+ * constrained point if \p c is on a curve, and otherwise a fixed
+ * point. I might add the possibility for an intersection point
+ * sometime.. Note that the returned object is not added to
+ * the document..
+ */
+ ObjectTypeCalcer* sensiblePointCalcer(
+ const Coordinate& c, const KigDocument& d, const KigWidget& w ) const;
+ ObjectHolder* sensiblePoint(
+ const Coordinate& c, const KigDocument& d, const KigWidget& w ) const;
+
+ /**
+ * set point to what sensiblePoint would have returned..
+ */
+ void redefinePoint( ObjectTypeCalcer* point, const Coordinate& c,
+ KigDocument& d, const KigWidget& w ) const;
+
+ /**
+ * return a locus, defined by the two points ( one constrained, and
+ * one following ) \p a and \p b . \p a should be the constrained point,
+ * and thus, it has to be of type ObjectTypeCalcer where a->type() is of
+ * type ConstrainedPointType. The semantics of LocusType are a bit
+ * weird ( but I believe correct :) ), so this function takes care
+ * of the complication there..
+ */
+ ObjectTypeCalcer* locusCalcer( ObjectCalcer* a, ObjectCalcer* b ) const;
+ ObjectHolder* locus( ObjectCalcer* a, ObjectCalcer* b ) const;
+
+ /**
+ * returns a label with text \p s at point \p c .. It ( and its parents )
+ * is calced already...
+ */
+ ObjectHolder* label(
+ const QString& s, const Coordinate& loc,
+ bool needframe, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const;
+ ObjectTypeCalcer* labelCalcer(
+ const QString& s, const Coordinate& loc,
+ bool needframe, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const;
+
+ /**
+ * this one does the same as the above, only that the new label is
+ * attached to locationparent if it is non-null..
+ */
+ ObjectTypeCalcer* attachedLabelCalcer(
+ const QString& s, ObjectCalcer* locationparent,
+ const Coordinate& loc, bool needframe,
+ const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const;
+ /**
+ * this has been added because it comes handy when redefining
+ * a text label, we move here all the code for getting an
+ * attach point from the method above
+ */
+ ObjectCalcer* getAttachPoint(
+ ObjectCalcer* locationparent,
+ const Coordinate& loc,
+ const KigDocument& doc ) const;
+ ObjectHolder* attachedLabel(
+ const QString& s, ObjectCalcer* locationparent,
+ const Coordinate& loc, bool needframe,
+ const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const;
+
+ /**
+ * returns a property object for the property \p p of object \p o .
+ *
+ * \note
+ * \p o should have already been calc'd, or this will fail and
+ * return 0.. The returned object also needs to be calced after
+ * this..
+ */
+ ObjectPropertyCalcer* propertyObjectCalcer( ObjectCalcer* o, const char* p ) const;
+ ObjectHolder* propertyObject( ObjectCalcer* o, const char* p ) const;
+};
+
+#endif
diff --git a/kig/objects/object_holder.cc b/kig/objects/object_holder.cc
new file mode 100644
index 00000000..5a2c0765
--- /dev/null
+++ b/kig/objects/object_holder.cc
@@ -0,0 +1,164 @@
+// 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 "object_holder.h"
+
+#include "bogus_imp.h"
+#include "object_calcer.h"
+#include "object_drawer.h"
+
+#include "../misc/coordinate.h"
+
+ObjectHolder::ObjectHolder( ObjectCalcer* calcer )
+ : mcalcer( calcer ), mdrawer( new ObjectDrawer ), mnamecalcer( 0 )
+{
+}
+
+ObjectHolder::ObjectHolder( ObjectCalcer* calcer, ObjectDrawer* drawer,
+ ObjectConstCalcer* namecalcer )
+ : mcalcer( calcer ), mdrawer( drawer ), mnamecalcer( namecalcer )
+{
+ assert( !namecalcer || namecalcer->imp()->inherits( StringImp::stype() ) );
+}
+
+ObjectHolder::ObjectHolder( ObjectCalcer* calcer, ObjectDrawer* drawer )
+ : mcalcer( calcer ), mdrawer( drawer ), mnamecalcer( 0 )
+{
+}
+
+ObjectHolder::~ObjectHolder()
+{
+ delete mdrawer;
+}
+
+const ObjectImp* ObjectHolder::imp() const
+{
+ return mcalcer->imp();
+}
+
+const ObjectCalcer* ObjectHolder::calcer() const
+{
+ return mcalcer.get();
+}
+
+const ObjectDrawer* ObjectHolder::drawer() const
+{
+ return mdrawer;
+}
+
+const ObjectConstCalcer* ObjectHolder::nameCalcer() const
+{
+ return mnamecalcer.get();
+}
+
+void ObjectHolder::setDrawer( ObjectDrawer* d )
+{
+ delete switchDrawer( d );
+}
+
+void ObjectHolder::calc( const KigDocument& d )
+{
+ mcalcer->calc( d );
+}
+
+void ObjectHolder::draw( KigPainter& p, bool selected ) const
+{
+ mdrawer->draw( *imp(), p, selected );
+}
+
+bool ObjectHolder::contains( const Coordinate& pt, const KigWidget& w, bool nv ) const
+{
+ return mdrawer->contains( *imp(), pt, w, nv );
+}
+
+bool ObjectHolder::inRect( const Rect& r, const KigWidget& w ) const
+{
+ return mdrawer->inRect( *imp(), r, w );
+}
+
+ObjectCalcer* ObjectHolder::calcer()
+{
+ return mcalcer.get();
+}
+
+ObjectDrawer* ObjectHolder::drawer()
+{
+ return mdrawer;
+}
+
+ObjectConstCalcer* ObjectHolder::nameCalcer()
+{
+ return mnamecalcer.get();
+}
+
+const Coordinate ObjectHolder::moveReferencePoint() const
+{
+ return mcalcer->moveReferencePoint();
+}
+
+void ObjectHolder::move( const Coordinate& to, const KigDocument& doc )
+{
+ mcalcer->move( to, doc );
+}
+
+bool ObjectHolder::canMove() const
+{
+ return mcalcer->canMove();
+}
+
+bool ObjectHolder::isFreelyTranslatable() const
+{
+ return mcalcer->isFreelyTranslatable();
+}
+
+ObjectDrawer* ObjectHolder::switchDrawer( ObjectDrawer* d )
+{
+ ObjectDrawer* tmp = mdrawer;
+ mdrawer = d;
+ return tmp;
+}
+
+bool ObjectHolder::shown( ) const
+{
+ return mdrawer->shown( );
+}
+
+const QString ObjectHolder::name() const
+{
+ if ( mnamecalcer )
+ {
+ assert( mnamecalcer->imp()->inherits( StringImp::stype() ) );
+ return static_cast<const StringImp*>( mnamecalcer->imp() )->data();
+ }
+ else
+ return QString::null;
+}
+
+void ObjectHolder::setNameCalcer( ObjectConstCalcer* namecalcer )
+{
+ assert( !mnamecalcer );
+ mnamecalcer = namecalcer;
+}
+
+QString ObjectHolder::selectStatement() const
+{
+ const QString n = name();
+ if ( n.isEmpty() )
+ return i18n( imp()->type()->selectStatement() );
+ else
+ return i18n( imp()->type()->selectNameStatement() ).arg( n );
+}
diff --git a/kig/objects/object_holder.h b/kig/objects/object_holder.h
new file mode 100644
index 00000000..9b30453d
--- /dev/null
+++ b/kig/objects/object_holder.h
@@ -0,0 +1,145 @@
+// 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.
+
+#ifndef KIG_OBJECTS_OBJECT_HOLDER_H
+#define KIG_OBJECTS_OBJECT_HOLDER_H
+
+#include "object_calcer.h"
+
+#include <qstring.h>
+
+/**
+ * An ObjectHolder represents an object as it is known to the
+ * document. It keeps a pointer to an ObjectCalcer, where it gets its
+ * data ( the ObjectImp that the ObjectCalcer holds ) from. It also
+ * holds information about how to draw this ObjectImp on the window,
+ * by keeping a pointer to an ObjectDrawer ( see below ). In its draw
+ * method, it gets the ObjectImp from the ObjectCalcer, and passes it
+ * to the ObjectDrawer, asking it to draw the ObjectImp on the window.
+ *
+ * The document ( check the KigDocument class ) holds a list of these
+ * ObjectHolder's. This is its only link with the ObjectCalcer
+ * dependency graph.
+ *
+ * An ObjectHolder keeps a reference to its * ObjectCalcer.
+ */
+class ObjectHolder
+{
+ ObjectCalcer::shared_ptr mcalcer;
+ ObjectDrawer* mdrawer;
+ ObjectConstCalcer::shared_ptr mnamecalcer;
+
+public:
+ /**
+ * Construct a new ObjectHolder with a given ObjectCalcer and
+ * ObjectDrawer, with a given name calcer.
+ */
+ ObjectHolder( ObjectCalcer* calcer, ObjectDrawer* drawer, ObjectConstCalcer* namecalcer );
+ /**
+ * Construct a new ObjectHolder with a given ObjectCalcer and
+ * ObjectDrawer.
+ */
+ ObjectHolder( ObjectCalcer* calcer, ObjectDrawer* drawer );
+ /**
+ * equivalent to the previous constructor, but with a default
+ * ObjectDrawer and no name.
+ */
+ ObjectHolder( ObjectCalcer* calcer );
+ ~ObjectHolder();
+
+ const ObjectImp* imp() const;
+ const ObjectCalcer* calcer() const;
+ ObjectCalcer* calcer();
+ const ObjectDrawer* drawer() const;
+ ObjectDrawer* drawer();
+ // the following two return zero if no name is set.
+ const ObjectConstCalcer* nameCalcer() const;
+ ObjectConstCalcer* nameCalcer();
+ /**
+ * Setting the namecalcer is only allowed if previously none was
+ * set. This way, we avoid keeping a useless namecalcer around if
+ * no name is set.
+ */
+ void setNameCalcer( ObjectConstCalcer* namecalcer );
+
+ /**
+ * returns QString::null if no name is set.
+ */
+ const QString name() const;
+ /**
+ * Set the ObjectDrawer of this ObjectHolder to \p d , the old
+ * ObjectDrawer is deleted.
+ */
+ void setDrawer( ObjectDrawer* d );
+ /**
+ * Set the ObjectDrawer of this ObjectHolder to \p d , the old
+ * ObjectDrawer is not deleted, but returned.
+ */
+ ObjectDrawer* switchDrawer( ObjectDrawer* d );
+
+ /**
+ * Make our ObjectCalcer recalculate its ObjectImp.
+ */
+ void calc( const KigDocument& );
+ /**
+ * Draw this object on the given KigPainter. If \p selected is true,
+ * then it will be drawn in red, instead of its normal color.
+ */
+ void draw( KigPainter& p, bool selected ) const;
+ /**
+ * Returns whether this object contains the point \p p .
+ */
+ bool contains( const Coordinate& p, const KigWidget& w, bool nv = false ) const;
+ /**
+ * Returns whether this object is in the rectangle \p r .
+ */
+ bool inRect( const Rect& r, const KigWidget& w ) const;
+ /**
+ * Returns whether this object is shown.
+ */
+ bool shown() const;
+
+ /**
+ * This call is simply forwarded to the ObjectCalcer. Check the
+ * documentation of ObjectCalcer::moveReferencePoint() for more info.
+ */
+ const Coordinate moveReferencePoint() const;
+ /**
+ * This call is simply forwarded to the ObjectCalcer. Check the
+ * documentation of ObjectCalcer::move() for more info.
+ */
+ void move( const Coordinate& to, const KigDocument& );
+ /**
+ * This call is simply forwarded to the ObjectCalcer. Check the
+ * documentation of ObjectCalcer::canMove() for more info.
+ */
+ bool canMove() const;
+ /**
+ * This call is simply forwarded to the ObjectCalcer. Check the
+ * documentation of ObjectCalcer::isFreelyTranslatable() for more info.
+ */
+ bool isFreelyTranslatable() const;
+
+ /**
+ * Return a statement saying something like "select this segment" or
+ * "select segment ab" depending on whether this ObjectHolder has a
+ * name.
+ */
+ QString selectStatement() const;
+};
+
+#endif
diff --git a/kig/objects/object_imp.cc b/kig/objects/object_imp.cc
new file mode 100644
index 00000000..6cb6650f
--- /dev/null
+++ b/kig/objects/object_imp.cc
@@ -0,0 +1,308 @@
+// Copyright (C) 2002 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 "object_imp.h"
+
+#include "bogus_imp.h"
+
+#include "../misc/coordinate.h"
+
+#include <klocale.h>
+#include <map>
+
+class ObjectImpType::StaticPrivate
+{
+public:
+ std::map<QCString, const ObjectImpType*> namemap;
+};
+
+ObjectImp::ObjectImp()
+{
+}
+
+ObjectImp::~ObjectImp()
+{
+}
+
+bool ObjectImp::valid() const
+{
+ return ! type()->inherits( InvalidImp::stype() );
+}
+
+void ObjectImp::fillInNextEscape( QString&, const KigDocument& ) const
+{
+ assert( false );
+}
+
+const QCStringList ObjectImp::properties() const
+{
+ QCStringList ret;
+ ret << I18N_NOOP( "Object Type" );
+ return ret;
+}
+
+const uint ObjectImp::numberOfProperties() const
+{
+ return 1;
+}
+
+const QCStringList ObjectImp::propertiesInternalNames() const
+{
+ QCStringList ret;
+ ret << "base-object-type";
+ return ret;
+}
+
+ObjectImp* ObjectImp::property( uint i, const KigDocument& ) const
+{
+ if ( i == 0 ) return new StringImp( type()->translatedName() );
+ return new InvalidImp;
+}
+
+const ObjectImpType* ObjectImp::impRequirementForProperty( uint ) const
+{
+ return ObjectImp::stype();
+}
+
+void ObjectImpVisitor::visit( const ObjectImp* imp )
+{
+ imp->visit( this );
+}
+
+void ObjectImpVisitor::visit( const IntImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const DoubleImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const StringImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const InvalidImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const HierarchyImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const LineImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const PointImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const TextImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const AngleImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const VectorImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const LocusImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const CircleImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const ConicImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const CubicImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const SegmentImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const RayImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const ArcImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const PolygonImp* )
+{
+}
+
+ObjectImpVisitor::~ObjectImpVisitor()
+{
+
+}
+
+void ObjectImpVisitor::visit( const TransformationImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const TestResultImp* )
+{
+}
+
+const char* ObjectImp::iconForProperty( uint ) const
+{
+ return "kig_text";
+}
+
+bool ObjectImp::canFillInNextEscape() const
+{
+ return false;
+}
+
+ObjectImpType::ObjectImpType( const ObjectImpType* parent,
+ const char* internalname,
+ const char* translatedname,
+ const char* selectstatement,
+ const char* selectnamestatement,
+ const char* removeastatement,
+ const char* addastatement,
+ const char* moveastatement,
+ const char* attachtothisstatement,
+ const char* showastatement,
+ const char* hideastatement )
+ : mparent( parent ), minternalname( internalname ),
+ mtranslatedname( translatedname ), mselectstatement( selectstatement ),
+ mselectnamestatement( selectnamestatement ),
+ mremoveastatement( removeastatement ), maddastatement( addastatement ),
+ mmoveastatement( moveastatement ),
+ mattachtothisstatement( attachtothisstatement ),
+ mshowastatement( showastatement ),
+ mhideastatement( hideastatement )
+{
+ sd()->namemap[minternalname] = this;
+}
+
+ObjectImpType::~ObjectImpType()
+{
+}
+
+bool ObjectImpType::inherits( const ObjectImpType* t ) const
+{
+ return t == this || (mparent && mparent->inherits( t ) );
+}
+
+const char* ObjectImpType::internalName() const
+{
+ return minternalname;
+}
+
+QString ObjectImpType::translatedName() const
+{
+ return i18n( mtranslatedname );
+}
+
+const char* ObjectImpType::selectStatement() const
+{
+ return mselectstatement;
+}
+
+const char* ObjectImpType::selectNameStatement() const
+{
+ return mselectnamestatement;
+}
+
+QString ObjectImpType::removeAStatement() const
+{
+ return i18n( mremoveastatement );
+}
+
+QString ObjectImpType::addAStatement() const
+{
+ return i18n( maddastatement );
+}
+
+QString ObjectImpType::moveAStatement() const
+{
+ return i18n( mmoveastatement );
+}
+
+const ObjectImpType* ObjectImpType::typeFromInternalName( const char* string )
+{
+ QCString s( string );
+ std::map<QCString, const ObjectImpType*>::iterator i = sd()->namemap.find( s );
+ if ( i == sd()->namemap.end() )
+ return 0;
+ else return i->second;
+}
+
+bool ObjectImp::inherits( const ObjectImpType* t ) const
+{
+ return type()->inherits( t );
+}
+
+const ObjectImpType* ObjectImp::stype()
+{
+ static const ObjectImpType t(
+ 0, "any",
+ I18N_NOOP( "Object" ),
+ I18N_NOOP( "Select this object" ),
+ I18N_NOOP( "Select object %1" ),
+ I18N_NOOP( "Remove an object" ),
+ I18N_NOOP( "Add an object" ),
+ I18N_NOOP( "Move an object" ),
+ I18N_NOOP( "Attach to this object" ),
+ I18N_NOOP( "Show an object" ),
+ I18N_NOOP( "Hide an object" ) );
+ return &t;
+}
+
+ObjectImpType::StaticPrivate* ObjectImpType::sd()
+{
+ static StaticPrivate d;
+ return &d;
+}
+
+bool ObjectImp::isCache() const
+{
+ return false;
+}
+
+QString ObjectImpType::attachToThisStatement() const
+{
+ return i18n( mattachtothisstatement );
+}
+
+QString ObjectImpType::showAStatement() const
+{
+ return i18n( mshowastatement );
+}
+
+QString ObjectImpType::hideAStatement() const
+{
+ return i18n( mhideastatement );
+}
+
+bool ObjectImp::isPropertyDefinedOnOrThroughThisImp( uint ) const
+{
+ return false;
+}
+
diff --git a/kig/objects/object_imp.h b/kig/objects/object_imp.h
new file mode 100644
index 00000000..2c032f99
--- /dev/null
+++ b/kig/objects/object_imp.h
@@ -0,0 +1,360 @@
+// Copyright (C) 2002 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.
+
+#ifndef KIG_OBJECTS_OBJECT_IMP_H
+#define KIG_OBJECTS_OBJECT_IMP_H
+
+#include "common.h"
+
+class IntImp;
+class DoubleImp;
+class StringImp;
+class InvalidImp;
+class HierarchyImp;
+class TransformationImp;
+class TestResultImp;
+class CurveImp;
+class LineImp;
+class PointImp;
+class TextImp;
+class AngleImp;
+class VectorImp;
+class LocusImp;
+class CircleImp;
+class ConicImp;
+class CubicImp;
+class SegmentImp;
+class RayImp;
+class ArcImp;
+class PolygonImp;
+
+/**
+ * \internal This is some OO magic commonly referred to as "double
+ * dispatch". If you need to do some action on an ObjectImp, and you
+ * need to do something different dependent on the type of o, then
+ * make a Visitor class that inherits this interface, and implements
+ * the appropriate functions properly, and call "o->visit( my_visitor
+ * );".
+ */
+class ObjectImpVisitor
+{
+public:
+ virtual ~ObjectImpVisitor();
+ void visit( const ObjectImp* imp );
+ virtual void visit( const IntImp* imp );
+ virtual void visit( const DoubleImp* imp );
+ virtual void visit( const StringImp* imp );
+ virtual void visit( const InvalidImp* imp );
+ virtual void visit( const HierarchyImp* imp );
+ virtual void visit( const TransformationImp* imp );
+ virtual void visit( const TestResultImp* imp );
+ virtual void visit( const LineImp* imp );
+ virtual void visit( const PointImp* imp );
+ virtual void visit( const TextImp* imp );
+ virtual void visit( const AngleImp* imp );
+ virtual void visit( const VectorImp* imp );
+ virtual void visit( const LocusImp* imp );
+ virtual void visit( const CircleImp* imp );
+ virtual void visit( const ConicImp* imp );
+ virtual void visit( const CubicImp* imp );
+ virtual void visit( const SegmentImp* imp );
+ virtual void visit( const RayImp* imp );
+ virtual void visit( const ArcImp* imp );
+ virtual void visit( const PolygonImp* imp );
+};
+
+typedef unsigned int uint;
+
+/**
+ * Instances of this class represent a certain ObjectImp type. Every
+ * ObjectImp type has a static ObjectImpType member, that it returns a
+ * reference to in its type() function.. Think of it as a nice enum,
+ * that you can also get some data from..
+ */
+class ObjectImpType
+{
+ const ObjectImpType* mparent;
+ const char* minternalname;
+ const char* mtranslatedname;
+ const char* mselectstatement;
+ const char* mselectnamestatement;
+ const char* mremoveastatement;
+ const char* maddastatement;
+ const char* mmoveastatement;
+ const char* mattachtothisstatement;
+ const char* mshowastatement;
+ const char* mhideastatement;
+ class StaticPrivate;
+ static StaticPrivate* sd();
+public:
+ /**
+ * Returns the type with name n.
+ *
+ * \internal Do *not* call this from functions that can be called at
+ * static initializer time ! It depends on information that is only
+ * available after that stage and will crash if used too early..
+ */
+ static const ObjectImpType* typeFromInternalName( const char* n );
+
+ /**
+ * \internal Construct an ObjectImpType, with a lot of data about
+ * your ObjectImp type.
+ *
+ * translatedname is a translatable string like "segment"
+ * selectstatement is a translatable string like "Select this segment"
+ * selectnamestatement is a translatable string like "Select segment %1"
+ * removeastatement is a translatable string like "Remove a Segment"
+ * addastatement is a translatable string like "Add a Segment"
+ * moveastatement is a translatable string like "Move a Segment"
+ * attachtothisstatement is a translatable string like "Attach to
+ * this segment"
+ * showastatement is a translatable string like "Show a Segment"
+ * hideastatement is a translatable string like "Hide a Segment"
+ *
+ * All translatable strings should have
+ * I18N_NOOP around them ! @param parent is the ObjectImpType of
+ * your parent ObjectImp type. Never give 0 as parent, except for
+ * the top ObjectImp ObjectImpType..
+ */
+ ObjectImpType(
+ const ObjectImpType* parent, const char* internalname,
+ const char* translatedname,
+ const char* selectstatement,
+ const char* selectnamestatement,
+ const char* removeastatement,
+ const char* addastatement,
+ const char* moveastatement,
+ const char* attachtothisstatement,
+ const char* showastatement,
+ const char* hideastatement );
+ ~ObjectImpType();
+
+ /**
+ * Does the ObjectImp type represented by this instance inherit the
+ * ObjectImp type represented by t ?
+ */
+ bool inherits( const ObjectImpType* t ) const;
+
+ /**
+ * Returns an internal name for this ObjectImp type. This name is
+ * guaranteed unique, and mostly corresponds with the class name of
+ * the corresponding ObjectImp..
+ */
+ const char* internalName() const;
+ /**
+ * The name of this type, translated to the currently used language.
+ */
+ QString translatedName() const;
+ /**
+ * Returns a translatable string of the form "Select this %1".
+ * E.g. "Select this segment". Note that users of this function
+ * should use i18n on the returned string before using it.
+ */
+ const char* selectStatement() const;
+
+ /**
+ * Returns a translatable string of the form "Select point %1". %1
+ * will be filled in by whomever calls this function with the name
+ * of the object in question. This function should be used as
+ * follows: i18n( x->selectNameStatement() ).arg( xname ).
+ */
+ const char* selectNameStatement() const;
+
+ /**
+ * Returns a translated string of the form "Remove a xxx".
+ * E.g. "Remove a Segment".
+ */
+ QString removeAStatement() const;
+ /**
+ * Returns a translated string of the form "Add a xxx".
+ * E.g. "Add a Segment".
+ */
+ QString addAStatement() const;
+ /**
+ * Returns a translated string of the form "Move a xxx".
+ * E.g. "Move a Segment".
+ */
+ QString moveAStatement() const;
+ /**
+ * Returns a translated string of the form "Attach to this xxx".
+ * E.g. "Attach to this segment".
+ * \internal This is used by the text label construction mode
+ */
+ QString attachToThisStatement() const;
+
+ /**
+ * Returns a translated string of the form "Show a xxx".
+ * E.g. "Show a Segment".
+ */
+ QString showAStatement() const;
+
+ /**
+ * Returns a translated string of the form "Hide a xxx".
+ * E.g. "Hide a Segment".
+ */
+ QString hideAStatement() const;
+};
+
+/**
+ * The ObjectImp class represents the behaviour of an object after it
+ * is calculated. This means how to draw() it, whether it claims to
+ * contain a certain point etc. It is also the class where the
+ * ObjectType's get their information from..
+ */
+class ObjectImp
+{
+protected:
+ ObjectImp();
+public:
+ /**
+ * The ObjectImpType representing the base ObjectImp class. All
+ * other ObjectImp's inherit from this type.
+ */
+ static const ObjectImpType* stype();
+
+ virtual ~ObjectImp();
+
+ /**
+ * Returns true if this ObjectImp inherits the ObjectImp type
+ * represented by t.
+ * E.g. you can check whether an ObjectImp is a LineImp by doing:
+ * \if creating-python-scripting-doc
+ * \code
+ * if object.inherits( LineImp.stype() ):
+ * \endcode
+ * \else
+ * \code
+ * if( object.inherits( LineImp::stype() )
+ * \endcode
+ * \endif
+ */
+ bool inherits( const ObjectImpType* t ) const;
+
+ /**
+ * Returns a reference point where to attach labels; when this
+ * returns an invalidCoord then the attachment is either not
+ * done at all, or done in a specific way (like for curves,
+ * or for points) The treatment of points could also take
+ * advantage of this attachment mechanism.
+ *
+ * If this method returns a valid Coordinate, then this is
+ * interpreted as a pivot point for the label, which can still
+ * be moved relative to that point, but follows the object when
+ * the object changes.
+ * In practice a new RelativePointType is created (position of
+ * the string), this type in turn depends on the object (to get
+ * its attachPoint) and two DoubleImp that are interpreted as
+ * relative displacement (x and y)
+ */
+ virtual Coordinate attachPoint( ) const = 0;
+
+ /**
+ * Return this ObjectImp, transformed by the transformation t.
+ */
+ virtual ObjectImp* transform( const Transformation& t ) const = 0;
+
+ virtual void draw( KigPainter& p ) const = 0;
+ virtual bool contains( const Coordinate& p, int width,
+ const KigWidget& si ) const = 0;
+ virtual bool inRect( const Rect& r, int width,
+ const KigWidget& si ) const = 0;
+ virtual Rect surroundingRect() const = 0;
+
+ /**
+ * Returns true if this is a valid ObjectImp.
+ * If you want to return an invalid ObjectImp, you should return an
+ * InvalidImp instance.
+ */
+ bool valid() const;
+
+ virtual const uint numberOfProperties() const;
+ // the names of the properties as perceived by the user.. put
+ // I18N_NOOP's around them here..
+ virtual const QCStringList properties() const;
+ // the names of the properties as known only by kig internally. No
+ // need for I18N_NOOP. Preferably choose some lowercase name with
+ // only letters and dashes, no spaces..
+ virtual const QCStringList propertiesInternalNames() const;
+ virtual ObjectImp* property( uint which, const KigDocument& d ) const;
+ // Sometimes we need to know which type an imp needs to be at least
+ // in order to have the imp with number which. Macro's need it
+ // foremost. This function answers that question..
+ virtual const ObjectImpType* impRequirementForProperty( uint which ) const;
+ // Return whether the property with number which is by construction
+ // always a point on this curve ( if this is a curve ), or always a
+ // curve through this point ( if this is a curve ).
+ virtual bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+ // What icon should be shown when talking about this property ?
+ virtual const char* iconForProperty( uint which ) const;
+
+ /**
+ * Returns the lowermost ObjectImpType that this object is an
+ * instantiation of.
+ * E.g. if you want to get a string containing the internal name of
+ * the type of an object, you can do:
+ * \if creating-python-scripting-doc
+ * \code
+ * tn = object.type().internalName()
+ * \endcode
+ * \else
+ * \code
+ * std::string typename = object.type()->internalName();
+ * \endcode
+ * \endif
+ */
+ virtual const ObjectImpType* type() const = 0;
+ virtual void visit( ObjectImpVisitor* vtor ) const = 0;
+
+ /**
+ * Returns a copy of this ObjectImp.
+ * The copy is an exact copy. Changes to the copy don't affect the
+ * original.
+ */
+ virtual ObjectImp* copy() const = 0;
+
+ // s is a string with at least one escape ( "%N" where N is a
+ // number ) somewhere. This function replaces the first escape it
+ // sees with the "value" of this imp ( using the QString::arg
+ // functions ). This is e.g. used by TextType to turn its variable
+ // args into strings..
+ // if you implement this, then you should return true in
+ // canFillInEscape() ( standard implementation returns false ), and
+ // override fillInNextEscape() ( standard implementation does an
+ // assert( false ) )..
+ virtual bool canFillInNextEscape() const;
+ virtual void fillInNextEscape( QString& s, const KigDocument& ) const;
+
+ /**
+ * Returns true if this ObjectImp is equal to rhs.
+ * This function checks whether rhs is of the same ObjectImp type,
+ * and whether it contains the same data as this ObjectImp.
+ * \internal It is used e.g. by the KigCommand stuff to see what the
+ * user has changed during a move..
+ */
+ virtual bool equals( const ObjectImp& rhs ) const = 0;
+
+ /**
+ * \internal Return true if this imp is just a cache imp. This
+ * means that it will never be considered to be stored in a file or
+ * in an ObjectHierarchy. This is useful for objects which cannot
+ * (easily and usefully) be (de)serialized, like e.g.
+ * PythonCompiledScriptImp.. For normal objects, the default
+ * implementation returns false, which is fine.
+ */
+ virtual bool isCache() const;
+};
+#endif
diff --git a/kig/objects/object_imp_factory.cc b/kig/objects/object_imp_factory.cc
new file mode 100644
index 00000000..bfeb1358
--- /dev/null
+++ b/kig/objects/object_imp_factory.cc
@@ -0,0 +1,510 @@
+// Copyright (C) 2002 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 "object_imp_factory.h"
+
+#include "object_imp.h"
+#include "bogus_imp.h"
+#include "circle_imp.h"
+#include "conic_imp.h"
+#include "cubic_imp.h"
+#include "line_imp.h"
+#include "locus_imp.h"
+#include "other_imp.h"
+#include "point_imp.h"
+#include "text_imp.h"
+
+#include "../misc/coordinate.h"
+
+#include <qdom.h>
+
+#include <klocale.h>
+
+const ObjectImpFactory* ObjectImpFactory::instance()
+{
+ static const ObjectImpFactory t;
+ return &t;
+}
+
+ObjectImpFactory::ObjectImpFactory()
+{
+}
+
+ObjectImpFactory::~ObjectImpFactory()
+{
+}
+
+static void addXYElements( const Coordinate& c, QDomElement& parent, QDomDocument& doc )
+{
+ QDomElement xe = doc.createElement( "x" );
+ xe.appendChild(
+ doc.createTextNode(
+ QString::number( c.x ) ) );
+ parent.appendChild( xe );
+ QDomElement ye = doc.createElement( "y" );
+ ye.appendChild(
+ doc.createTextNode(
+ QString::number( c.y ) ) );
+ parent.appendChild( ye );
+}
+
+static void addDoubleElement( const char* name, double d, QDomElement& parent, QDomDocument& doc )
+{
+ QDomElement e = doc.createElement( name );
+ e.appendChild( doc.createTextNode( QString::number( d ) ) );
+ parent.appendChild( e );
+}
+
+static void addCoordinateElement( const char* name, const Coordinate& d, QDomElement& p, QDomDocument& doc )
+{
+ QDomElement e = doc.createElement( name );
+ addXYElements( d, e, doc );
+ p.appendChild( e );
+}
+
+QString ObjectImpFactory::serialize( const ObjectImp& d, QDomElement& parent,
+ QDomDocument& doc ) const
+{
+ if( d.inherits( IntImp::stype() ) )
+ {
+ parent.appendChild(
+ doc.createTextNode(
+ QString::number( static_cast<const IntImp&>( d ).data() ) ) );
+ return QString::fromLatin1( "int" );
+ }
+ else if ( d.inherits( DoubleImp::stype() ) )
+ {
+ parent.appendChild(
+ doc.createTextNode(
+ QString::number( static_cast<const DoubleImp&>( d ).data() ) ) );
+ return QString::fromLatin1( "double" );
+ }
+ else if( d.inherits( StringImp::stype() ) )
+ {
+ parent.appendChild(
+ doc.createTextNode(
+ static_cast<const StringImp&>( d ).data() ) );
+ return QString::fromLatin1( "string" );
+ }
+ else if ( d.inherits( TestResultImp::stype() ) )
+ {
+ parent.appendChild(
+ doc.createTextNode(
+ static_cast<const TestResultImp&>( d ).data() ) );
+ return QString::fromLatin1( "testresult" );
+ }
+ else if( d.inherits( HierarchyImp::stype() ) )
+ {
+ static_cast<const HierarchyImp&>( d ).data().serialize( parent, doc );
+ return QString::fromLatin1( "hierarchy" );
+ }
+ else if ( d.inherits( TransformationImp::stype() ) )
+ {
+ const Transformation& trans = static_cast<const TransformationImp&>( d ).data();
+
+ QDomElement matrixe = doc.createElement( "matrix" );
+ for ( int i = 0; i < 3; ++i )
+ {
+ for ( int j = 0; j < 3; ++j )
+ {
+ QDomElement elel = doc.createElement( "element" );
+ elel.setAttribute( "row", QString::number( i ) );
+ elel.setAttribute( "column", QString::number( j ) );
+ elel.appendChild( doc.createTextNode( QString::number( trans.data( i, j ) ) ) );
+ matrixe.appendChild( elel );
+ };
+ }
+ parent.appendChild( matrixe );
+
+ QDomElement homothetye = doc.createElement( "homothetic" );
+ const char* ishomothety = trans.isHomothetic() ? "true" : "false";
+ homothetye.appendChild( doc.createTextNode( ishomothety ) );
+ parent.appendChild( homothetye );
+
+ return QString::fromLatin1( "transformation" );
+ }
+ else if( d.inherits( AbstractLineImp::stype() ) )
+ {
+ LineData l = static_cast<const AbstractLineImp&>( d ).data();
+ addCoordinateElement( "a", l.a, parent, doc );
+ addCoordinateElement( "b", l.b, parent, doc );
+ if( d.inherits( SegmentImp::stype() ) )
+ return QString::fromLatin1( "segment" );
+ else if( d.inherits( RayImp::stype() ) )
+ return QString::fromLatin1( "ray" );
+ else return QString::fromLatin1( "line" );
+ }
+ else if( d.inherits( PointImp::stype() ) )
+ {
+ addXYElements( static_cast<const PointImp&>( d ).coordinate(),
+ parent, doc );
+ return QString::fromLatin1( "point" );
+ }
+ else if( d.inherits( TextImp::stype() ) )
+ {
+ QString text = static_cast<const TextImp&>( d ).text();
+ parent.appendChild(
+ doc.createTextNode( text ) );
+ return QString::fromLatin1( "text" );
+ }
+ else if( d.inherits( AngleImp::stype() ) )
+ {
+ addDoubleElement( "size", static_cast<const AngleImp&>( d ).size(), parent, doc );
+ return QString::fromLatin1( "angle" );
+ }
+ else if ( d.inherits( ArcImp::stype() ) )
+ {
+ const ArcImp& a = static_cast<const ArcImp&>( d );
+ addCoordinateElement( "center", a.center(), parent, doc );
+ addDoubleElement( "radius", a.radius(), parent, doc );
+ addDoubleElement( "startangle", a.startAngle(), parent, doc );
+ addDoubleElement( "angle", a.angle(), parent, doc );
+ return QString::fromLatin1( "arc" );
+ }
+ else if( d.inherits( VectorImp::stype() ) )
+ {
+ Coordinate dir = static_cast<const VectorImp&>( d ).dir();
+ addXYElements( dir, parent, doc );
+ return QString::fromLatin1( "vector" );
+ }
+ else if( d.inherits( LocusImp::stype() ) )
+ {
+ const LocusImp& locus = static_cast<const LocusImp&>( d );
+
+ // serialize the curve..
+ QDomElement curve = doc.createElement( "curve" );
+ const CurveImp& curveimp = *locus.curve();
+ QString type = serialize( curveimp, curve, doc );
+ curve.setAttribute( "type", type );
+ parent.appendChild( curve );
+
+ // serialize the hierarchy..
+ QDomElement hier = doc.createElement( "calculation" );
+ locus.hierarchy().serialize( hier, doc );
+ parent.appendChild( hier );
+
+ return QString::fromLatin1( "locus" );
+ }
+ else if( d.inherits( CircleImp::stype() ) )
+ {
+ const CircleImp& c = static_cast<const CircleImp&>( d );
+ addCoordinateElement( "center", c.center(), parent, doc );
+ addDoubleElement( "radius", c.radius(), parent, doc );
+ return QString::fromLatin1( "circle" );
+ }
+ else if( d.inherits( ConicImp::stype() ) )
+ {
+ const ConicPolarData data = static_cast<const ConicImp&>( d ).polarData();
+ addCoordinateElement( "focus1", data.focus1, parent, doc );
+ addDoubleElement( "pdimen", data.pdimen, parent, doc );
+ addDoubleElement( "ecostheta0", data.ecostheta0, parent, doc );
+ addDoubleElement( "esintheta0", data.esintheta0, parent, doc );
+ return QString::fromLatin1( "conic" );
+ }
+ else if( d.inherits( CubicImp::stype() ) )
+ {
+ const CubicCartesianData data = static_cast<const CubicImp&>( d ).data();
+ QDomElement coeffs = doc.createElement( "coefficients" );
+ addDoubleElement( "a000", data.coeffs[0], coeffs, doc );
+ addDoubleElement( "a001", data.coeffs[1], coeffs, doc );
+ addDoubleElement( "a002", data.coeffs[2], coeffs, doc );
+ addDoubleElement( "a011", data.coeffs[3], coeffs, doc );
+ addDoubleElement( "a012", data.coeffs[4], coeffs, doc );
+ addDoubleElement( "a022", data.coeffs[5], coeffs, doc );
+ addDoubleElement( "a111", data.coeffs[6], coeffs, doc );
+ addDoubleElement( "a112", data.coeffs[7], coeffs, doc );
+ addDoubleElement( "a122", data.coeffs[8], coeffs, doc );
+ addDoubleElement( "a222", data.coeffs[9], coeffs, doc );
+ parent.appendChild( coeffs );
+ return QString::fromLatin1( "cubic" );
+ }
+ assert( false );
+ return QString::null;
+}
+
+static Coordinate readXYElements( const QDomElement& e, bool& ok )
+{
+ double x, y;
+ ok = true;
+ QDomElement xe = e.firstChild().toElement();
+ if ( xe.isNull() || xe.tagName() != "x" )
+ {
+ ok = false;
+ return Coordinate();
+ }
+ else x = xe.text().toDouble( &ok );
+
+ QDomElement ye = xe.nextSibling().toElement();
+ if ( ye.isNull() || ye.tagName() != "y" )
+ {
+ ok = false;
+ return Coordinate();
+ }
+ else y = ye.text().toDouble( &ok );
+
+ return Coordinate( x, y );
+}
+
+static Coordinate readCoordinateElement( QDomNode n, bool& ok,
+ const char* tagname )
+{
+ QDomElement e = n.toElement();
+ if ( e.isNull() || e.tagName() != tagname )
+ {
+ ok = false;
+ Coordinate ret;
+ return ret;
+ }
+ return readXYElements( e, ok );
+}
+
+static double readDoubleElement( QDomNode n, bool& ok,
+ const char* tagname )
+{
+ QDomElement e = n.toElement();
+ if ( e.isNull() || e.tagName() != tagname )
+ {
+ ok = false;
+ return 0.;
+ };
+ return e.text().toDouble( &ok );
+}
+
+ObjectImp* ObjectImpFactory::deserialize( const QString& type,
+ const QDomElement& parent,
+ QString& error ) const
+{
+#define KIG_GENERIC_PARSE_ERROR \
+ { \
+ error = i18n( "An error was encountered at line %1 in file %2." ) \
+ .arg( __LINE__ ).arg( __FILE__ ); \
+ return 0; \
+ }
+
+ bool ok = true;
+ if ( type == "int" )
+ {
+ int ret = parent.text().toInt( &ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ return new IntImp( ret );
+ }
+ else if ( type == "double" )
+ {
+ double ret = parent.text().toDouble( &ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ return new DoubleImp( ret );
+ }
+ else if ( type == "string" )
+ {
+ return new StringImp( parent.text() );
+ }
+ else if ( type == "testresult" )
+ {
+ return new TestResultImp( parent.text() );
+ }
+ else if ( type == "hierarchy" )
+ {
+ ObjectHierarchy* hier = ObjectHierarchy::buildSafeObjectHierarchy( parent, error );
+ if ( ! hier ) return 0;
+ HierarchyImp* imp = new HierarchyImp( *hier );
+ delete hier;
+ return imp;
+ }
+ else if ( type == "transformation" )
+ {
+ double data[3][3];
+ bool homothetic = false;
+ for ( QDomElement childe = parent.firstChild().toElement();
+ ! childe.isNull(); childe = childe.nextSibling().toElement() )
+ {
+ if ( childe.tagName() == "matrix" )
+ {
+ for ( QDomElement elel = childe.firstChild().toElement();
+ ! elel.isNull(); elel = elel.nextSibling().toElement() )
+ {
+ if ( elel.tagName() != "element" ) KIG_GENERIC_PARSE_ERROR;
+ bool ok = true;
+ int row = elel.attribute( "row" ).toInt( &ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ int column = elel.attribute( "column" ).toInt( &ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ data[row][column] = elel.text().toDouble( &ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ };
+ }
+ else if ( childe.tagName() == "homothetic" )
+ {
+ homothetic = childe.text() == "true";
+ }
+ else continue;
+ };
+ Transformation trans( data, homothetic );
+ return new TransformationImp( trans );
+ }
+ else if ( type == "point" )
+ {
+ Coordinate ret = readXYElements( parent, ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ return new PointImp( ret );
+ }
+ else if ( type == "line" || type == "segment" || type == "ray" )
+ {
+ QDomNode n = parent.firstChild();
+ Coordinate a = readCoordinateElement( n, ok, "a" );
+ if ( !ok ) KIG_GENERIC_PARSE_ERROR;
+ n = n.nextSibling();
+ Coordinate b = readCoordinateElement( n, ok, "b" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ if ( type == "line" ) return new LineImp( a, b );
+ else if ( type == "segment" ) return new SegmentImp( a, b );
+ else return new RayImp( a, b );
+ }
+ else if( type == "angle" )
+ {
+ double size = readDoubleElement( parent.firstChild(), ok, "size" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ return new AngleImp( Coordinate(), 0, size );
+ }
+ else if ( type == "arc" )
+ {
+ QDomNode n = parent.firstChild();
+ Coordinate center = readCoordinateElement( n, ok, "center" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ n = n.nextSibling();
+ double radius = readDoubleElement( n, ok, "radius" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ n = n.nextSibling();
+ double startangle = readDoubleElement( n, ok, "startangle" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ n = n.nextSibling();
+ double angle = readDoubleElement( n, ok, "angle" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ return new ArcImp( center, radius, startangle, angle );
+ }
+ else if( type == "vector" )
+ {
+ Coordinate dir = readXYElements( parent, ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ return new VectorImp( Coordinate(), dir );
+ }
+ else if( type == "locus" )
+ {
+ QDomElement curvee = parent.firstChild().toElement();
+ if ( curvee.isNull() || curvee.tagName() != "curve" ) KIG_GENERIC_PARSE_ERROR;
+ QString type = curvee.attribute( "type" );
+ ObjectImp* oi = deserialize( type, curvee, error );
+ if ( ! oi || ! oi->inherits( CurveImp::stype() ) ) KIG_GENERIC_PARSE_ERROR;
+ //CurveImp* curvei = static_cast<CurveImp*>( oi );
+
+ QDomElement hiere = curvee.nextSibling().toElement();
+ if ( hiere.isNull() || hiere.tagName() != "calculation" ) KIG_GENERIC_PARSE_ERROR;
+ assert( false ); // TODO
+// return new LocusImp( curvei, hier );
+ }
+ else if( type == "circle" )
+ {
+ QDomNode n = parent.firstChild();
+ Coordinate center = readCoordinateElement( n, ok, "center" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double radius = readDoubleElement( n, ok, "radius" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ return new CircleImp( center, radius );
+ }
+ else if( type == "conic" )
+ {
+ QDomNode n = parent.firstChild();
+ Coordinate focus1 = readCoordinateElement( n, ok, "focus1" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double pdimen = readDoubleElement( n, ok, "pdimen" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double ecostheta0 = readDoubleElement( n, ok, "ecostheta0" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double esintheta0 = readDoubleElement( n, ok, "esintheta0" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ return new ConicImpPolar(
+ ConicPolarData( focus1, pdimen, ecostheta0, esintheta0 ) );
+ }
+ else if( type == "cubic" )
+ {
+ QDomElement coeffse = parent.firstChild().toElement();
+ if ( coeffse.isNull() || coeffse.tagName() != "coefficients" )
+ KIG_GENERIC_PARSE_ERROR;
+
+ QDomNode n = coeffse.firstChild();
+ double a000 = readDoubleElement( n, ok, "a000" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a001 = readDoubleElement( n, ok, "a001" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a002 = readDoubleElement( n, ok, "a002" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a011 = readDoubleElement( n, ok, "a011" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a012 = readDoubleElement( n, ok, "a012" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a022 = readDoubleElement( n, ok, "a022" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a111 = readDoubleElement( n, ok, "a111" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a112 = readDoubleElement( n, ok, "a112" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a122 = readDoubleElement( n, ok, "a112" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a222 = readDoubleElement( n, ok, "a222" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ return new CubicImp( CubicCartesianData( a000, a001, a002,
+ a011, a012, a022,
+ a111, a112, a122,
+ a222 ) );
+ }
+
+ error = i18n( "This Kig file uses an object of type \"%1\", "
+ "which this Kig version does not support."
+ "Perhaps you have compiled Kig without support "
+ "for this object type,"
+ "or perhaps you are using an older Kig version." ).arg( type );
+ return 0;
+}
+
diff --git a/kig/objects/object_imp_factory.h b/kig/objects/object_imp_factory.h
new file mode 100644
index 00000000..1ab82bb4
--- /dev/null
+++ b/kig/objects/object_imp_factory.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2002 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.
+
+#ifndef KIG_OBJECTS_OBJECT_IMP_FACTORY_H
+#define KIG_OBJECTS_OBJECT_IMP_FACTORY_H
+
+#include "common.h"
+
+class ObjectImpFactory
+{
+ ObjectImpFactory();
+ ~ObjectImpFactory();
+public:
+ static const ObjectImpFactory* instance();
+ /**
+ * loads data from \p parent , and returns a new ObjectImp from the type
+ * string \p type .
+ */
+ ObjectImp* deserialize( const QString& type, const QDomElement& parent, QString& error ) const;
+ /**
+ * adds data to \p parent , and returns a type string..
+ */
+ QString serialize( const ObjectImp& d, QDomElement& parent, QDomDocument& doc ) const;
+};
+
+#endif
diff --git a/kig/objects/object_type.cc b/kig/objects/object_type.cc
new file mode 100644
index 00000000..9ac2845b
--- /dev/null
+++ b/kig/objects/object_type.cc
@@ -0,0 +1,125 @@
+// Copyright (C) 2002 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 "object_type.h"
+
+#include "bogus_imp.h"
+#include "object_type_factory.h"
+
+#include "../misc/coordinate.h"
+
+#include <qstringlist.h>
+
+#include <klocale.h>
+
+const char* ObjectType::fullName() const
+{
+ return mfulltypename;
+}
+
+ObjectType::~ObjectType()
+{
+}
+
+ObjectType::ObjectType( const char fulltypename[] )
+ : mfulltypename( fulltypename )
+{
+ ObjectTypeFactory::instance()->add( this );
+}
+
+bool ObjectType::canMove( const ObjectTypeCalcer& ) const
+{
+ return false;
+}
+
+bool ObjectType::isFreelyTranslatable( const ObjectTypeCalcer& ) const
+{
+ return false;
+}
+
+void ObjectType::move( ObjectTypeCalcer&, const Coordinate&, const KigDocument& ) const
+{
+ // we can't do an assert here, because sometimes ( like in
+ // ObjectABType::move, ObjectType::move is called without checking
+ // the object's canMove().
+// assert( false );
+}
+
+bool ObjectType::inherits( int ) const
+{
+ return false;
+}
+
+ArgsParserObjectType::ArgsParserObjectType( const char fulltypename[],
+ const struct ArgsParser::spec argsspec[],
+ int n )
+ : ObjectType( fulltypename ), margsparser( argsspec, n )
+{
+}
+
+const ObjectImpType* ArgsParserObjectType::impRequirement( const ObjectImp* o, const Args& parents ) const
+{
+ return margsparser.impRequirement( o, parents );
+}
+
+const ArgsParser& ArgsParserObjectType::argsParser() const
+{
+ return margsparser;
+}
+
+bool ObjectType::isTransform() const
+{
+ return false;
+}
+
+QStringList ObjectType::specialActions() const
+{
+ return QStringList();
+}
+
+void ObjectType::executeAction( int, ObjectHolder&, ObjectTypeCalcer&, KigPart&, KigWidget&,
+ NormalMode& ) const
+{
+ assert( false );
+}
+
+const Coordinate ObjectType::moveReferencePoint( const ObjectTypeCalcer& ) const
+{
+ assert( false );
+ return Coordinate::invalidCoord();
+}
+
+std::vector<ObjectCalcer*> ArgsParserObjectType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ return margsparser.parse( args );
+}
+
+Args ArgsParserObjectType::sortArgs( const Args& args ) const
+{
+ return margsparser.parse( args );
+}
+
+std::vector<ObjectCalcer*> ObjectType::movableParents( const ObjectTypeCalcer& ) const
+{
+ return std::vector<ObjectCalcer*>();
+}
+
+bool ArgsParserObjectType::isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const
+{
+ return margsparser.isDefinedOnOrThrough( o, parents );
+}
+
diff --git a/kig/objects/object_type.h b/kig/objects/object_type.h
new file mode 100644
index 00000000..f0ac49af
--- /dev/null
+++ b/kig/objects/object_type.h
@@ -0,0 +1,130 @@
+// Copyright (C) 2002 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.
+
+#ifndef KIG_OBJECTS_OBJECT_TYPE_H
+#define KIG_OBJECTS_OBJECT_TYPE_H
+
+#include "common.h"
+#include "../misc/argsparser.h"
+
+class ObjectTypeCalcer;
+
+/**
+ * The ObjectType class is a thing that represents the "behaviour" for
+ * a certain type.. This basically means that it decides what
+ * \ref ObjectImp the object gets in the calc() function, how the
+ * object move()'s etc.
+ */
+class ObjectType
+{
+ const char* mfulltypename;
+protected:
+ ObjectType( const char fulltypename[] );
+public:
+ virtual ~ObjectType();
+
+ enum {
+ ID_ConstrainedPointType,
+ ID_LocusType,
+ ID_FixedPointType
+ };
+
+ virtual bool inherits( int type ) const;
+
+ virtual ObjectImp* calc( const Args& parents, const KigDocument& d ) const = 0;
+
+ virtual bool canMove( const ObjectTypeCalcer& ourobj ) const;
+ virtual bool isFreelyTranslatable( const ObjectTypeCalcer& ourobj ) const;
+ virtual std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ virtual const Coordinate moveReferencePoint( const ObjectTypeCalcer& ourobj ) const;
+ virtual void move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& d ) const;
+
+ const char* fullName() const;
+
+ /**
+ * Supposing that \p parents would be given as parents to
+ * this type's calc function, this function returns the ObjectImp id
+ * that \p o should at least have.. ( \p o should be part of \p parents )
+ */
+ virtual const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const = 0;
+
+ /**
+ * Supposing that \p parents would be given as parents to this type's
+ * calc function, this function returns whether the returned
+ * ObjectImp will be, by construction, on \p o ( if \p o is a curve ), or
+ * through \p o ( if \p o is a point ).
+ */
+ virtual bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const = 0;
+
+ /**
+ * returns the ObjectImp id of the ObjectImp's produced by this
+ * ObjectType.. if the ObjectType can return different sorts of
+ * ObjectImp's, it should return the biggest common id, or
+ * ID_AnyImp..
+ */
+ virtual const ObjectImpType* resultId() const = 0;
+
+ virtual std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const = 0;
+
+ virtual Args sortArgs( const Args& args ) const = 0;
+
+ /**
+ * is this object type a transformation type. We want to know this
+ * cause transform types are shown separately in an object's RMB
+ * menu..
+ */
+ virtual bool isTransform() const;
+
+ // ObjectType's can define some special actions, that are strictly
+ // specific to the type at hand. E.g. a text label allows to toggle
+ // the display of a frame around the text. Constrained and fixed
+ // points can be redefined etc.
+
+ /**
+ * return i18n'd names for the special actions..
+ */
+ virtual QStringList specialActions() const;
+ /**
+ * execute the \p i 'th action from the specialActions above..
+ */
+ virtual void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& t,
+ KigPart& d, KigWidget& w, NormalMode& m ) const;
+};
+
+/**
+ * This is a convenience subclass of ObjectType that a type should
+ * inherit from if its parents can be specified in an ArgsParser..
+ */
+class ArgsParserObjectType
+ : public ObjectType
+{
+protected:
+ const ArgsParser margsparser;
+ ArgsParserObjectType( const char fulltypename[],
+ const struct ArgsParser::spec argsspec[],
+ int n );
+public:
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ const ArgsParser& argsParser() const;
+
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const;
+ Args sortArgs( const Args& args ) const;
+};
+
+#endif
diff --git a/kig/objects/object_type_factory.cc b/kig/objects/object_type_factory.cc
new file mode 100644
index 00000000..ee3024fd
--- /dev/null
+++ b/kig/objects/object_type_factory.cc
@@ -0,0 +1,148 @@
+// 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 "object_type_factory.h"
+
+#include <config.h>
+
+#include "object_type.h"
+#include "circle_type.h"
+#include "conic_types.h"
+#include "cubic_type.h"
+#include "intersection_types.h"
+#include "line_type.h"
+#include "text_type.h"
+#include "other_type.h"
+#include "transform_types.h"
+#include "point_type.h"
+#include "tests_type.h"
+
+#ifdef KIG_ENABLE_PYTHON_SCRIPTING
+#include "../scripting/python_type.h"
+#endif
+
+#include <qdom.h>
+#include <string>
+
+ObjectTypeFactory::ObjectTypeFactory()
+ : malreadysetup( false )
+{
+ setupBuiltinTypes();
+}
+
+ObjectTypeFactory::~ObjectTypeFactory()
+{
+}
+
+ObjectTypeFactory* ObjectTypeFactory::instance()
+{
+ static ObjectTypeFactory fact;
+ return &fact;
+}
+
+void ObjectTypeFactory::add( const ObjectType* type )
+{
+ assert( mmap.find( std::string( type->fullName() ) ) == mmap.end() );
+ mmap[std::string( type->fullName() )] = type;
+}
+
+const ObjectType* ObjectTypeFactory::find( const char* name ) const
+{
+ maptype::const_iterator i = mmap.find( std::string( name ) );
+ if ( i == mmap.end() ) return 0;
+ else return i->second;
+}
+
+void ObjectTypeFactory::setupBuiltinTypes()
+{
+// assert( ! malreadysetup );
+// malreadysetup = true;
+
+// // circle_type.h
+// add( CircleBCPType::instance() );
+// add( CircleBPRType::instance() );
+// add( CircleBTPType::instance() );
+
+// // conic_types.h
+// add( ConicB5PType::instance() );
+// add( ConicBAAPType::instance() );
+// add( EllipseBFFPType::instance() );
+// add( HyperbolaBFFPType::instance() );
+// add( ConicBDFPType::instance() );
+// add( ParabolaBTPType::instance() );
+// add( EquilateralHyperbolaB4PType::instance() );
+// add( ConicPolarPointType::instance() );
+// add( ConicPolarLineType::instance() );
+// add( ConicDirectrixType::instance() );
+// add( ParabolaBDPType::instance() );
+// add( ConicAsymptoteType::instance() );
+// add( ConicRadicalType::instance() );
+
+// // cubic_type.h
+// add( CubicB9PType::instance() );
+// add( CubicNodeB6PType::instance() );
+// add( CubicCuspB4PType::instance() );
+
+// // intersection_types.h
+// add( ConicLineIntersectionType::instance() );
+// add( ConicLineOtherIntersectionType::instance() );
+// add( LineLineIntersectionType::instance() );
+// add( LineCubicIntersectionType::instance() );
+// add( CircleCircleIntersectionType::instance() );
+
+// // line_type.h
+// add( SegmentABType::instance() );
+// add( LineABType::instance() );
+// add( RayABType::instance() );
+// add( LinePerpendLPType::instance() );
+// add( LineParallelLPType::instance() );
+
+// // other_type.h
+// add( AngleType::instance() );
+// add( VectorType::instance() );
+// add( LocusType::instance() );
+// add( ArcBTPType::instance() );
+// add( CopyObjectType::instance() );
+
+// // point_type.h
+// add( FixedPointType::instance() );
+// add( ConstrainedPointType::instance() );
+// add( MidPointType::instance() );
+// add( MeasureTransportType::instance() );
+
+// // text_type.h
+// add( TextType::instance() );
+
+// // tests_type.h
+// add( AreParallelType::instance() );
+
+// // transform_types.h
+// add( TranslatedType::instance() );
+// add( PointReflectionType::instance() );
+// add( LineReflectionType::instance() );
+// add( RotationType::instance() );
+// add( ScalingOverCenterType::instance() );
+// add( ScalingOverLineType::instance() );
+// add( ProjectiveRotationType::instance() );
+// add( CastShadowType::instance() );
+
+// #ifdef KIG_ENABLE_PYTHON_SCRIPTING
+// // python types
+// add( PythonCompileType::instance() );
+// add( PythonExecuteType::instance() );
+// #endif
+}
diff --git a/kig/objects/object_type_factory.h b/kig/objects/object_type_factory.h
new file mode 100644
index 00000000..c1371d67
--- /dev/null
+++ b/kig/objects/object_type_factory.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2002 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.
+
+#ifndef OBJECT_TYPE_FACTORY_H
+#define OBJECT_TYPE_FACTORY_H
+
+#include "common.h"
+
+#include <map>
+#include <string>
+
+class ObjectTypeFactory
+{
+ typedef std::map<std::string, const ObjectType*> maptype;
+ maptype mmap;
+ bool malreadysetup;
+ ObjectTypeFactory();
+ ~ObjectTypeFactory();
+ void setupBuiltinTypes();
+public:
+ static ObjectTypeFactory* instance();
+ void add( const ObjectType* type );
+ const ObjectType* find( const char* name ) const;
+};
+
+#endif
diff --git a/kig/objects/other_imp.cc b/kig/objects/other_imp.cc
new file mode 100644
index 00000000..137a3e93
--- /dev/null
+++ b/kig/objects/other_imp.cc
@@ -0,0 +1,710 @@
+// 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 "other_imp.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+#include "line_imp.h"
+
+#include "../misc/screeninfo.h"
+#include "../misc/common.h"
+#include "../misc/kigtransform.h"
+#include "../misc/kigpainter.h"
+#include "../misc/goniometry.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+#include <cmath>
+#include <utility>
+using namespace std;
+
+AngleImp::~AngleImp()
+{
+}
+
+ObjectImp* AngleImp::transform( const Transformation& ) const
+{
+ // TODO ?
+ return new InvalidImp;
+}
+
+void AngleImp::draw( KigPainter& p ) const
+{
+ p.drawAngle( mpoint, mstartangle, mangle );
+}
+
+AngleImp::AngleImp( const Coordinate& pt, double start_angle_in_radials,
+ double angle_in_radials )
+ : mpoint( pt ), mstartangle( start_angle_in_radials ),
+ mangle( angle_in_radials )
+{
+}
+
+bool AngleImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ double radius = 50*w.screenInfo().pixelWidth();
+
+ if ( fabs( (p-mpoint).length() - radius ) > w.screenInfo().normalMiss( width ) )
+ return false;
+
+ // and next we check if the angle is appropriate...
+ Coordinate vect = p - mpoint;
+ double angle = atan2( vect.y, vect.x );
+ while ( angle < mstartangle ) angle += 2*M_PI;
+ return angle <= mstartangle + mangle;
+}
+
+bool AngleImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ // TODO ?
+ return r.contains( mpoint, w.screenInfo().normalMiss( width ) );
+}
+
+Coordinate AngleImp::attachPoint() const
+{
+ return mpoint;
+}
+
+const uint AngleImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 3;
+}
+
+const QCStringList AngleImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l << "angle-radian";
+ l << "angle-degrees";
+ l << "angle-bisector";
+ assert( l.size() == AngleImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList AngleImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Angle in Radians" );
+ l << I18N_NOOP( "Angle in Degrees" );
+ l << I18N_NOOP( "Angle Bisector" );
+ assert( l.size() == AngleImp::numberOfProperties() );
+ return l;
+}
+
+const ObjectImpType* AngleImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return AngleImp::stype();
+}
+
+const char* AngleImp::iconForProperty( uint which ) const
+{
+ int numprop = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_size"; // size in radians
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_size"; // size in degrees
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_bisector"; // angle bisector..
+ else assert( false );
+ return "";
+}
+
+ObjectImp* AngleImp::property( uint which, const KigDocument& w ) const
+{
+ int numprop = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( size() );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( Goniometry::convert( size(), Goniometry::Rad, Goniometry::Deg ) );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ {
+ const double angle = mstartangle + mangle / 2;
+ Coordinate p2 = mpoint + Coordinate( cos( angle ), sin( angle ) ) * 10;
+ return new RayImp( mpoint, p2 );
+ }
+ else assert( false );
+ return new InvalidImp;
+}
+
+const double AngleImp::size() const
+{
+ return mangle;
+}
+
+ObjectImp* AngleImp::copy() const
+{
+ return new AngleImp( mpoint, mstartangle, mangle );
+}
+
+VectorImp::VectorImp( const Coordinate& a, const Coordinate& b )
+ : mdata( a, b )
+{
+}
+
+VectorImp::~VectorImp()
+{
+}
+
+ObjectImp* VectorImp::transform( const Transformation& t ) const
+{
+ Coordinate ta = t.apply( mdata.a );
+ Coordinate tb = t.apply( mdata.b );
+ if ( ta.valid() && tb.valid() ) return new VectorImp( ta, tb );
+ else return new InvalidImp;
+}
+
+void VectorImp::draw( KigPainter& p ) const
+{
+ p.drawVector( mdata.a, mdata.b );
+}
+
+bool VectorImp::contains( const Coordinate& o, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( o, w.screenInfo().normalMiss( width ) );
+}
+
+bool VectorImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ return lineInRect( r, mdata.a, mdata.b, width, this, w );
+}
+
+const uint VectorImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 5;
+}
+
+const QCStringList VectorImp::propertiesInternalNames() const
+{
+ QCStringList ret = Parent::propertiesInternalNames();
+ ret << "length";
+ ret << "vect-mid-point";
+ ret << "length-x";
+ ret << "length-y";
+ ret << "vector-opposite";
+ assert( ret.size() == VectorImp::numberOfProperties() );
+ return ret;
+}
+
+const QCStringList VectorImp::properties() const
+{
+ QCStringList ret = Parent::properties();
+ ret << I18N_NOOP( "Length" );
+ ret << I18N_NOOP( "Midpoint" );
+ ret << I18N_NOOP( "X length" );
+ ret << I18N_NOOP( "Y length" );
+ ret << I18N_NOOP( "Opposite Vector" );
+ assert( ret.size() == VectorImp::numberOfProperties() );
+ return ret;
+}
+
+const ObjectImpType* VectorImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return VectorImp::stype();
+}
+
+const char* VectorImp::iconForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ else if ( which == Parent::numberOfProperties() )
+ return "distance"; // length
+ else if ( which == Parent::numberOfProperties() + 1 )
+ return "bisection"; // mid point
+ else if ( which == Parent::numberOfProperties() + 2 )
+ return "distance"; // length-x
+ else if ( which == Parent::numberOfProperties() + 3 )
+ return "distance"; // length-y
+ else if ( which == Parent::numberOfProperties() + 4 )
+ return "opposite-vector"; // opposite vector
+ else assert( false );
+ return "";
+}
+
+ObjectImp* VectorImp::property( uint which, const KigDocument& w ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ else if ( which == Parent::numberOfProperties() )
+ return new DoubleImp( length() );
+ else if ( which == Parent::numberOfProperties() + 1 )
+ return new PointImp( ( mdata.a + mdata.b ) / 2 );
+ else if ( which == Parent::numberOfProperties() + 2 )
+ return new DoubleImp( fabs( mdata.a.x - mdata.b.x ) );
+ else if ( which == Parent::numberOfProperties() + 3 )
+ return new DoubleImp( fabs( mdata.a.y - mdata.b.y ) );
+ else if ( which == Parent::numberOfProperties() + 4 ) // opposite
+ return new VectorImp( mdata.a, 2*mdata.a-mdata.b );
+ else assert( false );
+ return new InvalidImp;
+}
+
+VectorImp* VectorImp::copy() const
+{
+ return new VectorImp( mdata.a, mdata.b );
+}
+
+const Coordinate VectorImp::dir() const
+{
+ return mdata.dir();
+}
+
+void AngleImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void VectorImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+const double VectorImp::length() const
+{
+ return ( mdata.a - mdata.b ).length();
+}
+
+ArcImp::ArcImp( const Coordinate& center, const double radius,
+ const double startangle, const double angle )
+ : CurveImp(), mcenter( center ), mradius( radius ),
+ msa( startangle ), ma( angle )
+{
+ if ( ma < 0 )
+ {
+ // we want a positive angle..
+ msa = msa + ma;
+ ma = -ma;
+ };
+}
+
+ArcImp::~ArcImp()
+{
+}
+
+ArcImp* ArcImp::copy() const
+{
+ return new ArcImp( mcenter, mradius, msa, ma );
+}
+
+ObjectImp* ArcImp::transform( const Transformation& t ) const
+{
+ //
+ // we don't have conic arcs! So it is invalid to transform an arc
+ // with a nonhomothetic transformation
+ //
+ if ( ! t.isHomothetic() ) return new InvalidImp();
+
+ Coordinate nc = t.apply( mcenter );
+ double nr = t.apply( mradius );
+ // transform msa...
+ double nmsa = msa;
+ if ( t.getAffineDeterminant() > 0 )
+ {
+ nmsa = msa - t.getRotationAngle();
+ } else
+ {
+ Coordinate ar = t.apply2by2only( Coordinate( cos(msa), sin(msa) ) );
+ nmsa = atan2( ar.y, ar.x );
+ nmsa -= ma;
+ }
+ while ( nmsa < -M_PI ) nmsa += 2*M_PI;
+ while ( nmsa > M_PI ) nmsa -= 2*M_PI;
+ if ( nc.valid() ) return new ArcImp( nc, nr, nmsa, ma );
+ else return new InvalidImp;
+}
+
+void ArcImp::draw( KigPainter& p ) const
+{
+ p.drawArc( mcenter, mradius, msa, ma );
+}
+
+bool ArcImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( p, w.screenInfo().normalMiss( width ) );
+}
+
+bool ArcImp::inRect( const Rect&, int, const KigWidget& ) const
+{
+ // TODO
+ return false;
+}
+
+bool ArcImp::valid() const
+{
+ return true;
+}
+
+const uint ArcImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 9;
+}
+
+const QCStringList ArcImp::properties() const
+{
+ QCStringList ret = Parent::properties();
+ ret << I18N_NOOP( "Center" );
+ ret << I18N_NOOP( "Radius" );
+ ret << I18N_NOOP( "Angle" );
+ ret << I18N_NOOP( "Angle in Degrees" );
+ ret << I18N_NOOP( "Angle in Radians" );
+ ret << I18N_NOOP( "Sector Surface" );
+ ret << I18N_NOOP( "Arc Length" );
+ ret << I18N_NOOP( "First End Point" );
+ ret << I18N_NOOP( "Second End Point" );
+ assert( ret.size() == ArcImp::numberOfProperties() );
+ return ret;
+}
+
+const QCStringList ArcImp::propertiesInternalNames() const
+{
+ QCStringList ret = Parent::propertiesInternalNames();
+ ret << "center";
+ ret << "radius";
+ ret << "angle";
+ ret << "angle-degrees";
+ ret << "angle-radians";
+ ret << "sector-surface";
+ ret << "arc-length";
+ ret << "end-point-A";
+ ret << "end-point-B";
+ return ret;
+}
+
+const char* ArcImp::iconForProperty( uint which ) const
+{
+ int numprop = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "arc_center"; // center
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_size";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_size";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else assert( false );
+ return "";
+}
+
+ObjectImp* ArcImp::property( uint which, const KigDocument& d ) const
+{
+ int numprop = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, d );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new PointImp( mcenter );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( mradius );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new AngleImp( mcenter, msa, ma );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new IntImp( static_cast<int>( Goniometry::convert( ma, Goniometry::Rad, Goniometry::Deg ) ) );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( ma );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( sectorSurface() );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( mradius * ma );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new PointImp( firstEndPoint() );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new PointImp( secondEndPoint() );
+ else assert( false );
+ return new InvalidImp;
+}
+
+const double ArcImp::sectorSurface() const
+{
+ return mradius * mradius * ma / 2;
+}
+
+const ObjectImpType* ArcImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else
+ return ArcImp::stype();
+}
+
+void ArcImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+double ArcImp::getParam( const Coordinate& c, const KigDocument& ) const
+{
+ Coordinate d = (c - mcenter).normalize();
+ double angle = atan2( d.y, d.x );
+ angle -= msa;
+// mp: problems with large arcs
+ while ( angle > ma/2 + M_PI ) angle -= 2*M_PI;
+ while ( angle < ma/2 - M_PI ) angle += 2*M_PI;
+//
+ angle = max( 0., min( angle, ma ) );
+ angle /= ma;
+ return angle;
+}
+
+const Coordinate ArcImp::getPoint( double p, const KigDocument& ) const
+{
+ double angle = msa + p * ma;
+ Coordinate d = Coordinate( cos( angle ), sin( angle ) ) * mradius;
+ return mcenter + d;
+}
+
+const Coordinate ArcImp::center() const
+{
+ return mcenter;
+}
+
+double ArcImp::radius() const
+{
+ return mradius;
+}
+
+double ArcImp::startAngle() const
+{
+ return msa;
+}
+
+double ArcImp::angle() const
+{
+ return ma;
+}
+
+Coordinate ArcImp::firstEndPoint() const
+{
+ double angle = msa;
+ return mcenter + Coordinate( cos( angle ), sin( angle ) ) * mradius;
+}
+
+Coordinate ArcImp::secondEndPoint() const
+{
+ double angle = msa + ma;
+ return mcenter + Coordinate( cos( angle ), sin( angle ) ) * mradius;
+}
+
+const Coordinate VectorImp::a() const
+{
+ return mdata.a;
+}
+
+const Coordinate VectorImp::b() const
+{
+ return mdata.b;
+}
+
+bool ArcImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( ArcImp::stype() ) &&
+ static_cast<const ArcImp&>( rhs ).radius() == radius() &&
+ static_cast<const ArcImp&>( rhs ).startAngle() == startAngle() &&
+ static_cast<const ArcImp&>( rhs ).angle() == angle();
+}
+
+bool AngleImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( AngleImp::stype() ) &&
+ static_cast<const AngleImp&>( rhs ).point() == point() &&
+ static_cast<const AngleImp&>( rhs ).startAngle() == startAngle() &&
+ static_cast<const AngleImp&>( rhs ).angle() == angle();
+}
+
+bool VectorImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( VectorImp::stype() ) &&
+ static_cast<const VectorImp&>( rhs ).a() == a() &&
+ static_cast<const VectorImp&>( rhs ).b() == b();
+}
+
+const ObjectImpType* AngleImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "angle",
+ I18N_NOOP( "angle" ),
+ I18N_NOOP( "Select this angle" ),
+ I18N_NOOP( "Select angle %1" ),
+ I18N_NOOP( "Remove an Angle" ),
+ I18N_NOOP( "Add an Angle" ),
+ I18N_NOOP( "Move an Angle" ),
+ I18N_NOOP( "Attach to this angle" ),
+ I18N_NOOP( "Show an Angle" ),
+ I18N_NOOP( "Hide an Angle" )
+ );
+ return &t;
+}
+const ObjectImpType* VectorImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "vector",
+ I18N_NOOP( "vector" ),
+ I18N_NOOP( "Select this vector" ),
+ I18N_NOOP( "Select vector %1" ),
+ I18N_NOOP( "Remove a Vector" ),
+ I18N_NOOP( "Add a Vector" ),
+ I18N_NOOP( "Move a Vector" ),
+ I18N_NOOP( "Attach to this vector" ),
+ I18N_NOOP( "Show a Vector" ),
+ I18N_NOOP( "Hide a Vector" )
+ );
+ return &t;
+}
+const ObjectImpType* ArcImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "arc",
+ I18N_NOOP( "arc" ),
+ I18N_NOOP( "Select this arc" ),
+ I18N_NOOP( "Select arc %1" ),
+ I18N_NOOP( "Remove an Arc" ),
+ I18N_NOOP( "Add an Arc" ),
+ I18N_NOOP( "Move an Arc" ),
+ I18N_NOOP( "Attach to this arc" ),
+ I18N_NOOP( "Show an Arc" ),
+ I18N_NOOP( "Hide an Arc" )
+ );
+ return &t;
+}
+
+const ObjectImpType* AngleImp::type() const
+{
+ return AngleImp::stype();
+}
+
+const ObjectImpType* VectorImp::type() const
+{
+ return VectorImp::stype();
+}
+
+const ObjectImpType* ArcImp::type() const
+{
+ return ArcImp::stype();
+}
+
+bool ArcImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool ArcImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ return isOnArc( p, mcenter, mradius, msa, ma, threshold );
+}
+
+bool AngleImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+ return false;
+}
+
+bool VectorImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+}
+
+bool ArcImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+ else if ( which == Parent::numberOfProperties() )
+ return true;
+ else
+ return false;
+}
+
+Rect AngleImp::surroundingRect() const
+{
+ return Rect( mpoint, 0, 0 );
+}
+
+Rect VectorImp::surroundingRect() const
+{
+ return Rect( mdata.a, mdata.b );
+}
+
+Rect ArcImp::surroundingRect() const
+{
+ // the returned rect should contain the center point(?), the two end
+ // points, and all extreme x and y positions in between.
+ //Rect ret( mcenter, 0, 0 );
+ double a = msa;
+ //ret.setContains( mcenter + mradius*Coordinate( cos( a ), sin( a ) ) );
+ Rect ret ( mcenter + mradius*Coordinate( cos( a ), sin( a ) ), 0, 0 );
+ a = msa + ma;
+ ret.setContains( mcenter + mradius*Coordinate( cos( a ), sin( a ) ) );
+ for ( a = -2*M_PI; a <= 2*M_PI; a+=M_PI/2 )
+ {
+ Coordinate d = mcenter + mradius*Coordinate( cos( a ), sin( a ) );
+ if ( msa <= a && a <= msa + ma )
+ ret.setContains( d );
+ }
+ return ret;
+}
+
+const Coordinate VectorImp::getPoint( double param, const KigDocument& ) const
+{
+ return mdata.a + mdata.dir() * param;
+}
+
+double VectorImp::getParam( const Coordinate& p, const KigDocument& ) const
+{
+ Coordinate pt = calcPointOnPerpend( mdata, p );
+ pt = calcIntersectionPoint( mdata, LineData( p, pt ) );
+ // if pt is over the end of the vector we set it to one of the end
+ // points of the vector...
+ if ( ( pt - mdata.a ).length() > dir().length() )
+ pt = mdata.b;
+ else if ( ( pt - mdata.b ).length() > dir().length() )
+ pt = mdata.a;
+ if ( mdata.b == mdata.a ) return 0;
+ return ( ( pt - mdata.a ).length() ) / ( dir().length() );
+}
+
+bool VectorImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool VectorImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ return isOnSegment( p, mdata.a, mdata.b, threshold );
+}
+
+LineData VectorImp::data() const
+{
+ return mdata;
+}
diff --git a/kig/objects/other_imp.h b/kig/objects/other_imp.h
new file mode 100644
index 00000000..8e716fa6
--- /dev/null
+++ b/kig/objects/other_imp.h
@@ -0,0 +1,243 @@
+// 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.
+
+#ifndef KIG_OBJECTS_OTHER_IMP_H
+#define KIG_OBJECTS_OTHER_IMP_H
+
+#include "curve_imp.h"
+#include "../misc/common.h"
+#include "../misc/coordinate.h"
+
+/**
+ * An ObjectImp representing an angle.
+ */
+class AngleImp
+ : public ObjectImp
+{
+ const Coordinate mpoint;
+ const double mstartangle;
+ const double mangle;
+public:
+ typedef ObjectImp Parent;
+ /**
+ * Returns the ObjectImpType representing the AngleImp type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct an Angle with a given center, start angle and
+ * dimension (both in radians).
+ */
+ AngleImp( const Coordinate& pt, double start_angle_in_radials,
+ double angle_in_radials );
+ ~AngleImp();
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ Rect surroundingRect() const;
+
+ Coordinate attachPoint() const;
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ ObjectImp* copy() const;
+
+ /**
+ * Return the size in radians of this angle.
+ */
+ const double size() const;
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ /**
+ * Return the center of this angle.
+ */
+ const Coordinate point() const { return mpoint; }
+ /**
+ * Return the start angle in radians of this angle.
+ */
+ const double startAngle() const { return mstartangle; }
+ /**
+ * Return the dimension in radians of this angle.
+ */
+ const double angle() const { return mangle; }
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+/**
+ * An ObjectImp representing a vector.
+ */
+class VectorImp
+ : public CurveImp
+{
+ LineData mdata;
+public:
+ typedef CurveImp Parent;
+ /**
+ * Returns the ObjectImpType representing the VectorImp type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct a Vector with a given start point and end point.
+ */
+ VectorImp( const Coordinate& a, const Coordinate& b );
+ ~VectorImp();
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+ double getParam( const Coordinate&, const KigDocument& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ Rect surroundingRect() const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ VectorImp* copy() const;
+
+ /**
+ * Return the direction of this vector.
+ */
+ const Coordinate dir() const;
+ /**
+ * Return the start point of this vector.
+ */
+ const Coordinate a() const;
+ /**
+ * Return the end point of this vector.
+ */
+ const Coordinate b() const;
+ /**
+ * Return the length of this vector.
+ */
+ const double length() const;
+ /**
+ * Get the LineData for this vector.
+ */
+ LineData data() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+/**
+ * An ObjectImp representing an arc.
+ */
+class ArcImp
+ : public CurveImp
+{
+ Coordinate mcenter;
+ double mradius;
+ double msa;
+ double ma;
+public:
+ typedef CurveImp Parent;
+ /**
+ * Returns the ObjectImpType representing the ArcImp type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct an Arc with a given center, radius, start angle and
+ * dimension (both in radians).
+ */
+ ArcImp( const Coordinate& center, const double radius,
+ const double startangle, const double angle );
+ ~ArcImp();
+ ArcImp* copy() const;
+
+ ObjectImp* transform( const Transformation& t ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& w ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& si ) const;
+ Rect surroundingRect() const;
+ bool valid() const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& d ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ double getParam( const Coordinate& c, const KigDocument& d ) const;
+ const Coordinate getPoint( double p, const KigDocument& d ) const;
+
+ /**
+ * Return the center of this arc.
+ */
+ const Coordinate center() const;
+ /**
+ * Return the radius of this arc.
+ */
+ double radius() const;
+ /**
+ * Return the start angle in radians of this arc.
+ */
+ double startAngle() const;
+ /**
+ * Return the dimension in radians of this arc.
+ */
+ double angle() const;
+ /**
+ * Return the start point of this arc.
+ */
+ Coordinate firstEndPoint() const;
+ /**
+ * Return the end point of this arc.
+ */
+ Coordinate secondEndPoint() const;
+ /**
+ * Return the size of the sector surface of this arc.
+ */
+ const double sectorSurface() const;
+
+ bool equals( const ObjectImp& rhs ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+#endif
diff --git a/kig/objects/other_type.cc b/kig/objects/other_type.cc
new file mode 100644
index 00000000..27787986
--- /dev/null
+++ b/kig/objects/other_type.cc
@@ -0,0 +1,189 @@
+// 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 "other_type.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+#include "locus_imp.h"
+
+#include "../misc/common.h"
+#include "../misc/calcpaths.h"
+#include "../misc/goniometry.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../kig/kig_commands.h"
+
+#include <functional>
+#include <algorithm>
+#include <cmath>
+
+using std::find;
+
+static const struct ArgsParser::spec argsspecLocus[] =
+{
+ { HierarchyImp::stype(), "hierarchy", "SHOULD NOT BE SEEN", false },
+ { CurveImp::stype(), "curve", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LocusType )
+
+LocusType::LocusType()
+ : ArgsParserObjectType( "Locus", argsspecLocus, 2 )
+{
+}
+
+LocusType::~LocusType()
+{
+}
+
+ObjectImp* LocusType::calc( const Args& args, const KigDocument& ) const
+{
+ using namespace std;
+
+ assert( args.size() >= 2 );
+ const Args firsttwo( args.begin(), args.begin() + 2 );
+ Args fixedargs( args.begin() + 2, args.end() );
+
+ if ( ! margsparser.checkArgs( firsttwo ) ) return new InvalidImp;
+ for ( Args::iterator i = fixedargs.begin(); i != fixedargs.end(); ++i )
+ if ( ! (*i)->valid() )
+ return new InvalidImp;
+
+ const ObjectHierarchy& hier =
+ static_cast<const HierarchyImp*>( args[0] )->data();
+ const CurveImp* curveimp = static_cast<const CurveImp*>( args[1] );
+
+ return new LocusImp( curveimp->copy(), hier.withFixedArgs( fixedargs ) );
+}
+
+bool LocusType::inherits( int type ) const
+{
+ return type == ID_LocusType ? true : Parent::inherits( type );
+}
+
+const ObjectImpType* LocusType::resultId() const
+{
+ return LocusImp::stype();
+}
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CopyObjectType )
+
+CopyObjectType::CopyObjectType()
+ : ObjectType( "Copy" )
+{
+}
+
+CopyObjectType::~CopyObjectType()
+{
+}
+
+CopyObjectType* CopyObjectType::instance()
+{
+ static CopyObjectType t;
+ return &t;
+}
+
+bool CopyObjectType::inherits( int ) const
+{
+ return false;
+}
+
+ObjectImp* CopyObjectType::calc( const Args& parents, const KigDocument& ) const
+{
+ assert( parents.size() == 1 );
+ return parents[0]->copy();
+}
+
+const ObjectImpType* CopyObjectType::impRequirement( const ObjectImp*, const Args& ) const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* CopyObjectType::resultId() const
+{
+ // we don't know what we return..
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* LocusType::impRequirement( const ObjectImp* o, const Args& parents ) const
+{
+ assert( parents.size() >= 2 );
+ Args firsttwo( parents.begin(), parents.begin() + 2 );
+ if ( o == parents[0] || o == parents[1] )
+ return margsparser.impRequirement( o, firsttwo );
+ else
+ {
+ const HierarchyImp* h = dynamic_cast<const HierarchyImp*>( parents[0] );
+ if ( h )
+ {
+ PointImp* p = new PointImp( Coordinate() );
+ Args hargs( parents.begin()+ 2, parents.end() );
+ hargs.push_back( p );
+ ArgsParser hparser = h->data().argParser();
+ const ObjectImpType* ret = hparser.impRequirement( o, hargs );
+ delete p;
+ return ret;
+ }
+ else
+ return ObjectImp::stype();
+ };
+}
+
+const LocusType* LocusType::instance()
+{
+ static const LocusType t;
+ return &t;
+}
+
+std::vector<ObjectCalcer*> CopyObjectType::sortArgs( const std::vector<ObjectCalcer*>& os ) const
+{
+ assert( os.size() == 1 );
+ return os;
+}
+
+std::vector<ObjectCalcer*> LocusType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ assert( args.size() >= 2 );
+ std::vector<ObjectCalcer*> firsttwo( args.begin(), args.begin() + 2 );
+ firsttwo = margsparser.parse( firsttwo );
+ std::copy( args.begin() + 2, args.end(), std::back_inserter( firsttwo ) );
+ return firsttwo;
+}
+
+Args LocusType::sortArgs( const Args& args ) const
+{
+ assert( args.size() >= 2 );
+ Args firsttwo( args.begin(), args.begin() + 2 );
+ firsttwo = margsparser.parse( firsttwo );
+ std::copy( args.begin() + 2, args.end(), std::back_inserter( firsttwo ) );
+ return firsttwo;
+}
+
+Args CopyObjectType::sortArgs( const Args& args ) const
+{
+ assert( args.size() == 1 );
+ return args;
+}
+
+bool CopyObjectType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
+{
+ // TODO: vragen aan parent ?
+ // TODO: translate the above TODO ?
+ return false;
+}
+
diff --git a/kig/objects/other_type.h b/kig/objects/other_type.h
new file mode 100644
index 00000000..6bbcead1
--- /dev/null
+++ b/kig/objects/other_type.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2003-2004 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.
+
+#ifndef KIG_MISC_OTHER_TYPE_H
+#define KIG_MISC_OTHER_TYPE_H
+
+#include "base_type.h"
+#include "../misc/object_hierarchy.h"
+
+class LocusType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ LocusType();
+ ~LocusType();
+public:
+ static const LocusType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+
+ bool inherits( int type ) const;
+ const ObjectImpType* resultId() const;
+
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const;
+ Args sortArgs( const Args& args ) const;
+};
+
+class CopyObjectType
+ : public ObjectType
+{
+protected:
+ CopyObjectType();
+ ~CopyObjectType();
+public:
+ static CopyObjectType* instance();
+ bool inherits( int type ) const;
+ ObjectImp* calc( const Args& parents, const KigDocument& d ) const;
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ const ObjectImpType* resultId() const;
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& os ) const;
+ Args sortArgs( const Args& args ) const;
+};
+
+#endif
diff --git a/kig/objects/point_imp.cc b/kig/objects/point_imp.cc
new file mode 100644
index 00000000..02d4d360
--- /dev/null
+++ b/kig/objects/point_imp.cc
@@ -0,0 +1,223 @@
+// Copyright (C) 2002 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 "point_imp.h"
+
+#include "bogus_imp.h"
+#include "../misc/kigtransform.h"
+#include "../misc/kigpainter.h"
+#include "../misc/coordinate_system.h"
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+PointImp::PointImp( const Coordinate& c )
+ : mc( c )
+{
+}
+
+Coordinate PointImp::attachPoint() const
+{
+ return mc;
+// return Coordinate::invalidCoord();
+}
+
+void PointImp::draw( KigPainter& p ) const
+{
+ p.drawFatPoint( mc );
+}
+
+bool PointImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ int twidth = width == -1 ? 5 : width;
+ return (p - mc).length() - twidth*w.screenInfo().pixelWidth() < 0;
+}
+
+bool PointImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ double am = w.screenInfo().normalMiss( width );
+ return r.contains( mc, am );
+}
+
+const uint PointImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 3;
+}
+
+const QCStringList PointImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l << "coordinate";
+ l << "coordinate-x";
+ l << "coordinate-y";
+ assert( l.size() == PointImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList PointImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Coordinate" );
+ l << I18N_NOOP( "X coordinate" );
+ l << I18N_NOOP( "Y coordinate" );
+ assert( l.size() == PointImp::numberOfProperties() );
+ return l;
+}
+
+const ObjectImpType* PointImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return PointImp::stype();
+}
+
+const char* PointImp::iconForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() )
+ return "pointxy"; // coordinate
+ if ( which == Parent::numberOfProperties() + 1 )
+ return "pointxy"; // coordinate-x
+ if ( which == Parent::numberOfProperties() + 2 )
+ return "pointxy"; // coordinate-y
+ else assert( false );
+ return "";
+}
+
+ObjectImp* PointImp::property( uint which, const KigDocument& d ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, d );
+ if ( which == Parent::numberOfProperties() )
+ return new PointImp( mc );
+ if ( which == Parent::numberOfProperties() + 1 )
+ return new DoubleImp( mc.x );
+ if ( which == Parent::numberOfProperties() + 2 )
+ return new DoubleImp( mc.y );
+// else assert( false );
+ return new InvalidImp;
+}
+
+PointImp::~PointImp()
+{
+}
+
+PointImp* PointImp::copy() const
+{
+ return new PointImp( mc );
+}
+
+ObjectImp* PointImp::transform( const Transformation& t ) const
+{
+ Coordinate nc = t.apply( mc );
+ if ( nc.valid() ) return new PointImp( nc );
+ else return new InvalidImp();
+}
+
+void PointImp::setCoordinate( const Coordinate& c )
+{
+ mc = c;
+}
+
+void PointImp::fillInNextEscape( QString& s, const KigDocument& doc ) const
+{
+ s = s.arg( doc.coordinateSystem().fromScreen( mc, doc ) );
+}
+
+void PointImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool PointImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( PointImp::stype() ) &&
+ static_cast<const PointImp&>( rhs ).coordinate() == coordinate();
+}
+
+bool PointImp::canFillInNextEscape() const
+{
+ return true;
+}
+
+const ObjectImpType* PointImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "point",
+ I18N_NOOP( "point" ),
+ I18N_NOOP( "Select this point" ),
+ I18N_NOOP( "Select point %1" ),
+ I18N_NOOP( "Remove a Point" ),
+ I18N_NOOP( "Add a Point" ),
+ I18N_NOOP( "Move a Point" ),
+ I18N_NOOP( "Attach to this point" ),
+ I18N_NOOP( "Show a Point" ),
+ I18N_NOOP( "Hide a Point" )
+ );
+ return &t;
+}
+
+const ObjectImpType* PointImp::type() const
+{
+ return PointImp::stype();
+}
+
+bool PointImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+}
+
+Rect PointImp::surroundingRect() const
+{
+ return Rect( mc, 0., 0. );
+}
+
+/*
+ */
+
+BogusPointImp::BogusPointImp( const Coordinate& c )
+ : PointImp( c )
+{
+}
+
+BogusPointImp::~BogusPointImp()
+{
+}
+
+const ObjectImpType* BogusPointImp::stype()
+{
+ static const ObjectImpType t(
+ 0, "boguspoint",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN"
+ );
+ return &t;
+}
+
+const ObjectImpType* BogusPointImp::type() const
+{
+ return BogusPointImp::stype();
+}
diff --git a/kig/objects/point_imp.h b/kig/objects/point_imp.h
new file mode 100644
index 00000000..a5e8eb98
--- /dev/null
+++ b/kig/objects/point_imp.h
@@ -0,0 +1,91 @@
+// Copyright (C) 2002 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.
+
+#ifndef KIG_OBJECTS_POINT_IMP_H
+#define KIG_OBJECTS_POINT_IMP_H
+
+#include "object_imp.h"
+#include "../misc/coordinate.h"
+
+/**
+ * An ObjectImp representing a point..
+ */
+class PointImp
+ : public ObjectImp
+{
+ Coordinate mc;
+public:
+ typedef ObjectImp Parent;
+ /**
+ * Returns the ObjectImpType representing PointImp's.
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct a PointImp with coordinate c.
+ */
+ PointImp( const Coordinate& c );
+ ~PointImp();
+
+ Rect surroundingRect() const;
+ Coordinate attachPoint() const;
+
+ /**
+ * Get the coordinate of this PointImp.
+ */
+ const Coordinate& coordinate() const { return mc; }
+ /**
+ * Set the coordinate of this PointImp.
+ */
+ void setCoordinate( const Coordinate& c );
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& d ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ PointImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ void fillInNextEscape( QString& s, const KigDocument& ) const;
+ bool canFillInNextEscape() const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+class BogusPointImp
+ : public PointImp
+{
+public:
+ BogusPointImp( const Coordinate& c );
+ ~BogusPointImp();
+ static const ObjectImpType* stype();
+ const ObjectImpType* type() const;
+};
+
+#endif
diff --git a/kig/objects/point_type.cc b/kig/objects/point_type.cc
new file mode 100644
index 00000000..04f8272c
--- /dev/null
+++ b/kig/objects/point_type.cc
@@ -0,0 +1,665 @@
+// Copyright (C) 2002 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 "point_type.h"
+
+#include "point_imp.h"
+#include "curve_imp.h"
+#include "line_imp.h"
+#include "other_imp.h"
+#include "bogus_imp.h"
+
+#include "../modes/moving.h"
+#include "../misc/coordinate_system.h"
+#include "../misc/common.h"
+#include "../misc/calcpaths.h"
+#include "../misc/kiginputdialog.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+#include "../kig/kig_commands.h"
+
+#include <klocale.h>
+
+static const ArgsParser::spec argsspecFixedPoint[] =
+{
+ { DoubleImp::stype(), "x", "SHOULD NOT BE SEEN", false },
+ { DoubleImp::stype(), "y", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( FixedPointType )
+
+FixedPointType::FixedPointType()
+ : ArgsParserObjectType( "FixedPoint", argsspecFixedPoint, 2 )
+{
+}
+
+FixedPointType::~FixedPointType()
+{
+}
+
+ObjectImp* FixedPointType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ double a = static_cast<const DoubleImp*>( parents[0] )->data();
+ double b = static_cast<const DoubleImp*>( parents[1] )->data();
+
+ return new PointImp( Coordinate( a, b ) );
+}
+
+static const ArgsParser::spec argsspecRelativePoint[] =
+{
+ { DoubleImp::stype(), "relative-x", "SHOULD NOT BE SEEN", false },
+ { DoubleImp::stype(), "relative-y", "SHOULD NOT BE SEEN", false },
+ { ObjectImp::stype(), "object", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( RelativePointType )
+
+RelativePointType::RelativePointType()
+ : ArgsParserObjectType( "RelativePoint", argsspecRelativePoint, 3 )
+{
+}
+
+RelativePointType::~RelativePointType()
+{
+}
+
+ObjectImp* RelativePointType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ if ( ! parents[2]->attachPoint().valid() ) return new InvalidImp;
+
+ Coordinate reference = static_cast<const ObjectImp*>( parents[2] )->attachPoint();
+ double a = static_cast<const DoubleImp*>( parents[0] )->data();
+ double b = static_cast<const DoubleImp*>( parents[1] )->data();
+
+ return new PointImp( reference + Coordinate( a, b ) );
+}
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CursorPointType )
+
+CursorPointType::CursorPointType()
+ : ObjectType( "CursorPoint" )
+{
+}
+
+CursorPointType::~CursorPointType()
+{
+}
+
+const CursorPointType* CursorPointType::instance()
+{
+ static const CursorPointType t;
+ return &t;
+}
+
+ObjectImp* CursorPointType::calc( const Args& parents, const KigDocument& ) const
+{
+ assert ( parents[0]->inherits( DoubleImp::stype() ) );
+ assert ( parents[1]->inherits( DoubleImp::stype() ) );
+ double a = static_cast<const DoubleImp*>( parents[0] )->data();
+ double b = static_cast<const DoubleImp*>( parents[1] )->data();
+
+ return new BogusPointImp( Coordinate( a, b ) );
+}
+
+const ObjectImpType* CursorPointType::resultId() const
+{
+ return BogusPointImp::stype();
+}
+
+ObjectImp* ConstrainedPointType::calc( const Args& parents, const KigDocument& doc ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ double param = static_cast<const DoubleImp*>( parents[0] )->data();
+ const Coordinate nc = static_cast<const CurveImp*>( parents[1] )->getPoint( param, doc );
+ if ( nc.valid() ) return new PointImp( nc );
+ else return new InvalidImp;
+}
+
+const ArgsParser::spec argsspecConstrainedPoint[] =
+{
+ { DoubleImp::stype(), "parameter", "SHOULD NOT BE SEEN", false },
+ { CurveImp::stype(), "Constrain the point to this curve", "SHOULD NOT BE SEEN", true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConstrainedPointType )
+
+ConstrainedPointType::ConstrainedPointType()
+ : ArgsParserObjectType( "ConstrainedPoint", argsspecConstrainedPoint, 2 )
+{
+}
+
+ConstrainedPointType::~ConstrainedPointType()
+{
+}
+
+void FixedPointType::move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const
+{
+ // fetch the old coord..;
+ std::vector<ObjectCalcer*> pa = ourobj.parents();
+ assert( margsparser.checkArgs( pa ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( pa.front() ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( pa.back() ) );
+
+ ObjectConstCalcer* ox = static_cast<ObjectConstCalcer*>( pa.front() );
+ ObjectConstCalcer* oy = static_cast<ObjectConstCalcer*>( pa.back() );
+
+ ox->setImp( new DoubleImp( to.x ) );
+ oy->setImp( new DoubleImp( to.y ) );
+}
+
+void RelativePointType::move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const
+{
+ // fetch the attach point..;
+ // this routine is tightly paired with what moveReferencePoint returns!
+ // right now moveReferencePoint always returns the origin
+ std::vector<ObjectCalcer*> pa = ourobj.parents();
+ assert( margsparser.checkArgs( pa ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( pa[0] ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( pa[1] ) );
+
+ ObjectConstCalcer* ox = static_cast<ObjectConstCalcer*>( pa[0] );
+ ObjectConstCalcer* oy = static_cast<ObjectConstCalcer*>( pa[1] );
+ ObjectCalcer* ob = static_cast<ObjectCalcer*>( pa[2] );
+
+ Coordinate attach = ob->imp()->attachPoint();
+ ox->setImp( new DoubleImp( to.x - attach.x ) );
+ oy->setImp( new DoubleImp( to.y - attach.y ) );
+}
+
+void CursorPointType::move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const
+{
+ // fetch the old coord..;
+
+ std::vector<ObjectCalcer*> pa = ourobj.parents();
+ assert( pa.size() == 2 );
+ assert( dynamic_cast<ObjectConstCalcer*>( pa.front() ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( pa.back() ) );
+
+ ObjectConstCalcer* ox = static_cast<ObjectConstCalcer*>( pa.front() );
+ ObjectConstCalcer* oy = static_cast<ObjectConstCalcer*>( pa.back() );
+
+ ox->setImp( new DoubleImp( to.x ) );
+ oy->setImp( new DoubleImp( to.y ) );
+}
+
+void ConstrainedPointType::move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& d ) const
+{
+ // fetch the CurveImp..
+ std::vector<ObjectCalcer*> parents = ourobj.parents();
+ assert( margsparser.checkArgs( parents ) );
+
+ assert( dynamic_cast<ObjectConstCalcer*>( parents[0] ) );
+ ObjectConstCalcer* paramo = static_cast<ObjectConstCalcer*>( parents[0] );
+ const CurveImp* ci = static_cast<const CurveImp*>( parents[1]->imp() );
+
+ // fetch the new param..
+ const double np = ci->getParam( to, d );
+
+ paramo->setImp( new DoubleImp( np ) );
+}
+
+bool ConstrainedPointType::canMove( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+bool ConstrainedPointType::isFreelyTranslatable( const ObjectTypeCalcer& ) const
+{
+ return false;
+}
+
+bool FixedPointType::canMove( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+bool FixedPointType::isFreelyTranslatable( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+bool RelativePointType::canMove( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+bool RelativePointType::isFreelyTranslatable( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+bool CursorPointType::canMove( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+static const ArgsParser::spec argsspecMidPoint[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Construct the midpoint of this point and another point" ),
+ I18N_NOOP( "Select the first of the two points of which you want to construct the midpoint..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct the midpoint of this point and another point" ),
+ I18N_NOOP( "Select the other of the two points of which you want to construct the midpoint..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( MidPointType )
+
+MidPointType::MidPointType()
+ : ObjectABType( "MidPoint", argsspecMidPoint, 2 )
+{
+}
+
+MidPointType::~MidPointType()
+{
+}
+
+const MidPointType* MidPointType::instance()
+{
+ static const MidPointType t;
+ return &t;
+}
+
+ObjectImp* MidPointType::calc( const Coordinate& a, const Coordinate& b ) const
+{
+ return new PointImp( ( a + b ) / 2 );
+}
+
+bool ConstrainedPointType::inherits( int type ) const
+{
+ return type == ID_ConstrainedPointType;
+}
+
+const ConstrainedPointType* ConstrainedPointType::instance()
+{
+ static const ConstrainedPointType t;
+ return &t;
+}
+
+bool FixedPointType::inherits( int type ) const
+{
+ return type == ID_FixedPointType;
+}
+
+const FixedPointType* FixedPointType::instance()
+{
+ static const FixedPointType t;
+ return &t;
+}
+
+const ObjectImpType* FixedPointType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const RelativePointType* RelativePointType::instance()
+{
+ static const RelativePointType t;
+ return &t;
+}
+
+const ObjectImpType* RelativePointType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* ConstrainedPointType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* CursorPointType::impRequirement( const ObjectImp* o, const Args& ) const
+{
+ if ( o->inherits( DoubleImp::stype() ) )
+ return DoubleImp::stype();
+
+ if ( o->inherits( PointImp::stype() ) )
+ return PointImp::stype();
+
+ return 0;
+}
+
+bool CursorPointType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
+{
+ return false;
+}
+
+std::vector<ObjectCalcer*> CursorPointType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ return args;
+}
+
+Args CursorPointType::sortArgs( const Args& args ) const
+{
+ return args;
+}
+
+const ObjectImpType* MidPointType::resultId() const
+{
+ return PointImp::stype();
+}
+
+QStringList FixedPointType::specialActions() const
+{
+ QStringList ret;
+ ret << i18n( "Set &Coordinate..." );
+ ret << i18n( "Redefine" );
+ return ret;
+}
+
+QStringList ConstrainedPointType::specialActions() const
+{
+ QStringList ret;
+ ret << i18n( "Set &Parameter..." );
+ ret << i18n( "Redefine" );
+ return ret;
+}
+
+static void redefinePoint( ObjectHolder* o, KigPart& d, KigWidget& w )
+{
+ PointRedefineMode pm( o, d, w );
+ d.runMode( &pm );
+}
+
+void FixedPointType::executeAction(
+ int i, ObjectHolder& oh, ObjectTypeCalcer& o,
+ KigPart& d, KigWidget& w, NormalMode& ) const
+{
+ switch( i )
+ {
+ case 0:
+ {
+ bool ok = true;
+ assert ( o.imp()->inherits( PointImp::stype() ) );
+ Coordinate oldc = static_cast<const PointImp*>( o.imp() )->coordinate();
+ KigInputDialog::getCoordinate(
+ i18n( "Set Coordinate" ),
+ i18n( "Enter the new coordinate." ) + QString::fromLatin1( "<br>" ) +
+ d.document().coordinateSystem().coordinateFormatNoticeMarkup(),
+ &w, &ok, d.document(), &oldc );
+ if ( ! ok ) break;
+
+ MonitorDataObjects mon( getAllParents( &o ) );
+ o.move( oldc, d.document() );
+ KigCommand* kc = new KigCommand( d, PointImp::stype()->moveAStatement() );
+ mon.finish( kc );
+
+ d.history()->addCommand( kc );
+ break;
+ };
+ case 1:
+ redefinePoint( &oh, d, w );
+ break;
+ default:
+ assert( false );
+ };
+}
+
+void ConstrainedPointType::executeAction(
+ int i, ObjectHolder& oh, ObjectTypeCalcer& o, KigPart& d, KigWidget& w,
+ NormalMode& ) const
+{
+ switch( i )
+ {
+ case 1:
+ redefinePoint( &oh, d, w );
+ break;
+ case 0:
+ {
+ std::vector<ObjectCalcer*> parents = o.parents();
+ assert( dynamic_cast<ObjectConstCalcer*>( parents[0] ) &&
+ parents[0]->imp()->inherits( DoubleImp::stype() ) );
+
+ ObjectConstCalcer* po = static_cast<ObjectConstCalcer*>( parents[0] );
+ double oldp = static_cast<const DoubleImp*>( po->imp() )->data();
+
+ bool ok = true;
+ double newp = getDoubleFromUser(
+ i18n( "Set Point Parameter" ), i18n( "Choose the new parameter: " ),
+ oldp, &w, &ok, 0, 1, 4 );
+ if ( ! ok ) return;
+
+ MonitorDataObjects mon( parents );
+ po->setImp( new DoubleImp( newp ) );
+ KigCommand* kc = new KigCommand( d, i18n( "Change Parameter of Constrained Point" ) );
+ mon.finish( kc );
+ d.history()->addCommand( kc );
+ break;
+ };
+ default:
+ assert( false );
+ };
+}
+
+const Coordinate FixedPointType::moveReferencePoint( const ObjectTypeCalcer& ourobj ) const
+{
+ assert( ourobj.imp()->inherits( PointImp::stype() ) );
+ return static_cast<const PointImp*>( ourobj.imp() )->coordinate();
+}
+
+const Coordinate RelativePointType::moveReferencePoint( const ObjectTypeCalcer& ourobj ) const
+{
+ assert( ourobj.imp()->inherits( PointImp::stype() ) );
+// return static_cast<const PointImp*>( ourobj.imp() )->coordinate();
+ return Coordinate( 0., 0. );
+}
+
+const Coordinate ConstrainedPointType::moveReferencePoint( const ObjectTypeCalcer& ourobj ) const
+{
+ assert( ourobj.imp()->inherits( PointImp::stype() ) );
+ return static_cast<const PointImp*>( ourobj.imp() )->coordinate();
+}
+
+std::vector<ObjectCalcer*> FixedPointType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ return ourobj.parents();
+}
+
+std::vector<ObjectCalcer*> RelativePointType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ std::vector<ObjectCalcer*> ret;
+ ret.push_back( ourobj.parents()[0] );
+ ret.push_back( ourobj.parents()[1] );
+ return ret;
+}
+
+std::vector<ObjectCalcer*> ConstrainedPointType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ std::vector<ObjectCalcer*> ret;
+ ret.push_back( ourobj.parents()[0] );
+ return ret;
+}
+
+/* ----------------- Transport of measure ------------------------------ */
+
+ObjectImp* MeasureTransportType::calc( const Args& parents, const KigDocument& doc ) const
+{
+ double measure;
+
+ if ( parents.size() != 3 ) return new InvalidImp;
+
+ if ( parents[0]->inherits (SegmentImp::stype()) )
+ {
+ const SegmentImp* s = static_cast<const SegmentImp*>( parents[0] );
+ measure = s->length();
+ } else if ( parents[0]->inherits (ArcImp::stype()) )
+ {
+ const ArcImp* s = static_cast<const ArcImp*>( parents[0] );
+ measure = s->radius()*s->angle();
+ } else return new InvalidImp;
+
+ const Coordinate& p = static_cast<const PointImp*>( parents[2] )->coordinate();
+ if ( parents[1]->inherits (LineImp::stype()) )
+ {
+ const LineImp* c = static_cast<const LineImp*>( parents[1] );
+
+ if ( !c->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ const LineData line = c->data();
+ const Coordinate dir = line.dir()/line.length();
+ const Coordinate nc = p + measure*dir;
+
+ if ( nc.valid() ) return new PointImp( nc );
+ else return new InvalidImp;
+ } else if ( parents[1]->inherits (CircleImp::stype()) )
+ {
+ const CircleImp* c = static_cast<const CircleImp*>( parents[1] );
+ if ( !c->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ double param = c->getParam( p, doc );
+ measure /= 2*c->radius()*M_PI;
+ param += measure;
+ while (param > 1) param -= 1;
+
+ const Coordinate nc = c->getPoint( param, doc );
+ if ( nc.valid() ) return new PointImp( nc );
+ else return new InvalidImp;
+ }
+
+ return new InvalidImp;
+}
+
+// I18N_NOOP( "Select the segment/arc to transport on the circle/line..." ), false },
+// I18N_NOOP( "Select the circle/line on which to transport a measure..." ), true },
+// I18N_NOOP( "Select a point on the circle/line..." ), false }
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( MeasureTransportType )
+
+MeasureTransportType::MeasureTransportType()
+ : ObjectType( "TransportOfMeasure" )
+{
+}
+
+MeasureTransportType::~MeasureTransportType()
+{
+}
+
+const MeasureTransportType* MeasureTransportType::instance()
+{
+ static const MeasureTransportType t;
+ return &t;
+}
+
+const ObjectImpType* MeasureTransportType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* MeasureTransportType::impRequirement( const ObjectImp* obj, const Args& ) const
+{
+ if ( obj->inherits( PointImp::stype () ) )
+ return PointImp::stype ();
+
+ if ( obj->inherits( LineImp::stype () ) )
+ return LineImp::stype ();
+
+ if ( obj->inherits( CircleImp::stype () ) )
+ return CircleImp::stype ();
+
+ if ( obj->inherits( SegmentImp::stype () ) )
+ return SegmentImp::stype ();
+
+ if ( obj->inherits( ArcImp::stype () ) )
+ return ArcImp::stype ();
+
+ return 0;
+}
+
+bool MeasureTransportType::isDefinedOnOrThrough( const ObjectImp* o, const Args& ) const
+{
+ if ( o->inherits( LineImp::stype() ) ) return true;
+ if ( o->inherits( CircleImp::stype() ) ) return true;
+ return false;
+}
+
+std::vector<ObjectCalcer*> MeasureTransportType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ return args; /* should already be in correct order */
+}
+
+Args MeasureTransportType::sortArgs( const Args& args ) const
+{
+ return args;
+}
+
+/* - transport of measure (old, for compatibility with prev. kig files) - */
+
+ObjectImp* MeasureTransportTypeOld::calc( const Args& parents, const KigDocument& doc ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const CircleImp* c = static_cast<const CircleImp*>( parents[0] );
+ const Coordinate& p = static_cast<const PointImp*>( parents[1] )->coordinate();
+
+ if ( !c->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ const SegmentImp* s = static_cast<const SegmentImp*>( parents[2] );
+ double param = c->getParam( p, doc );
+ double measure = s->length();
+ measure /= 2*c->radius()*M_PI;
+ param += measure;
+ while (param > 1) param -= 1;
+
+ const Coordinate nc = c->getPoint( param, doc );
+ if ( nc.valid() ) return new PointImp( nc );
+ else return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecMeasureTransportOld[] =
+{
+ { CircleImp::stype(), "Transport a measure on this circle",
+ I18N_NOOP( "Select the circle on which to transport a measure..." ), true },
+ { PointImp::stype(), "Start transport from this point of the circle",
+ I18N_NOOP( "Select a point on the circle..." ), false },
+ { SegmentImp::stype(), "Segment to transport",
+ I18N_NOOP( "Select the segment to transport on the circle..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( MeasureTransportTypeOld )
+
+MeasureTransportTypeOld::MeasureTransportTypeOld()
+ : ArgsParserObjectType( "MeasureTransport", argsspecMeasureTransportOld, 3 )
+{
+}
+
+MeasureTransportTypeOld::~MeasureTransportTypeOld()
+{
+}
+
+const MeasureTransportTypeOld* MeasureTransportTypeOld::instance()
+{
+ static const MeasureTransportTypeOld t;
+ return &t;
+}
+
+const ObjectImpType* MeasureTransportTypeOld::resultId() const
+{
+ return PointImp::stype();
+}
+
+/* ----------------- end transport of measure ------------------------- */
+
diff --git a/kig/objects/point_type.h b/kig/objects/point_type.h
new file mode 100644
index 00000000..231ad6c5
--- /dev/null
+++ b/kig/objects/point_type.h
@@ -0,0 +1,159 @@
+// Copyright (C) 2002 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.
+
+#ifndef KIG_OBJECTS_POINT_TYPE_H
+#define KIG_OBJECTS_POINT_TYPE_H
+
+#include "base_type.h"
+#include "common.h"
+#include "circle_imp.h"
+
+class FixedPointType
+ : public ArgsParserObjectType
+{
+ FixedPointType();
+ ~FixedPointType();
+
+ static const ArgsParser::spec argsspec[1];
+public:
+ static const FixedPointType* instance();
+
+ bool inherits( int type ) const;
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ bool canMove( const ObjectTypeCalcer& ourobj ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& ourobj ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ QStringList specialActions() const;
+ void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& t,
+ KigPart& d, KigWidget& w, NormalMode& m ) const;
+};
+
+class RelativePointType
+ : public ArgsParserObjectType
+{
+ RelativePointType();
+ ~RelativePointType();
+
+ static const ArgsParser::spec argsspec[1];
+public:
+ static const RelativePointType* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ bool canMove( const ObjectTypeCalcer& ourobj ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& ourobj ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+// QStringList specialActions() const;
+// void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& t,
+// KigPart& d, KigWidget& w, NormalMode& m ) const;
+};
+
+class CursorPointType
+ : public ObjectType
+{
+ CursorPointType();
+ ~CursorPointType();
+
+public:
+ static const CursorPointType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const;
+ Args sortArgs( const Args& args ) const;
+ bool canMove( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConstrainedPointType
+ : public ArgsParserObjectType
+{
+ ConstrainedPointType();
+ ~ConstrainedPointType();
+public:
+ static const ConstrainedPointType* instance();
+
+ bool inherits( int type ) const;
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+
+ bool canMove( const ObjectTypeCalcer& ourobj ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& ourobj ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ QStringList specialActions() const;
+ void executeAction( int i, ObjectHolder&, ObjectTypeCalcer& o, KigPart& d, KigWidget& w,
+ NormalMode& m ) const;
+};
+
+class MidPointType
+ : public ObjectABType
+{
+ MidPointType();
+ ~MidPointType();
+public:
+ static const MidPointType* instance();
+ ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class MeasureTransportType
+ : public ObjectType
+{
+ MeasureTransportType();
+ ~MeasureTransportType();
+public:
+ static const MeasureTransportType* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args )const;
+ Args sortArgs( const Args& args ) const;
+};
+
+class MeasureTransportTypeOld
+ : public ArgsParserObjectType
+{
+ MeasureTransportTypeOld();
+ ~MeasureTransportTypeOld();
+public:
+ static const MeasureTransportTypeOld* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/polygon_imp.cc b/kig/objects/polygon_imp.cc
new file mode 100644
index 00000000..08215bfb
--- /dev/null
+++ b/kig/objects/polygon_imp.cc
@@ -0,0 +1,550 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// 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 "polygon_imp.h"
+
+#include "bogus_imp.h"
+#include "line_imp.h"
+#include "point_imp.h"
+
+#include "../misc/common.h"
+#include "../misc/coordinate.h"
+#include "../misc/kigpainter.h"
+#include "../misc/kigtransform.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+#include <cmath>
+
+PolygonImp::PolygonImp( uint npoints, const std::vector<Coordinate>& points,
+ const Coordinate& centerofmass )
+ : mnpoints( npoints ), mpoints( points ), mcenterofmass( centerofmass )
+{
+// mpoints = points;
+}
+
+PolygonImp::PolygonImp( const std::vector<Coordinate>& points )
+{
+ uint npoints = points.size();
+ Coordinate centerofmassn = Coordinate( 0, 0 );
+
+ for ( uint i = 0; i < npoints; ++i )
+ {
+ centerofmassn += points[i];
+ }
+ mpoints = points;
+ mcenterofmass = centerofmassn/npoints;
+ mnpoints = npoints;
+}
+
+PolygonImp::~PolygonImp()
+{
+}
+
+Coordinate PolygonImp::attachPoint() const
+{
+ return mcenterofmass;
+}
+
+ObjectImp* PolygonImp::transform( const Transformation& t ) const
+{
+/*mp:
+ * any projective transformation makes sense for a polygon,
+ * since segments transform into segments (but see below...)
+ * of course regular polygons will no longer be
+ * regular if t is not homothetic.
+ * for projective transformations the polygon could transform to
+ * an unbounded nonconnected polygon; this happens if some side
+ * of the polygon crosses the critical line that maps to infinity
+ * this can be easily checked using the getProjectiveIndicator
+ * function
+ */
+// if ( ! t.isHomothetic() )
+// return new InvalidImp();
+
+ if ( ! t.isAffine() ) /* in this case we need a more extensive test */
+ {
+ double maxp = -1.0;
+ double minp = 1.0;
+ for ( uint i = 0; i < mpoints.size(); ++i )
+ {
+ double p = t.getProjectiveIndicator( mpoints[i] );
+ if ( p > maxp ) maxp = p;
+ if ( p < minp ) minp = p;
+ }
+ if ( maxp > 0 && minp < 0 ) return new InvalidImp;
+ }
+ std::vector<Coordinate> np;
+ for ( uint i = 0; i < mpoints.size(); ++i )
+ {
+ Coordinate nc = t.apply( mpoints[i] );
+ if ( !nc.valid() )
+ return new InvalidImp;
+ np.push_back( nc );
+ }
+ return new PolygonImp( np );
+}
+
+void PolygonImp::draw( KigPainter& p ) const
+{
+ p.drawPolygon( mpoints );
+}
+
+bool PolygonImp::isInPolygon( const Coordinate& p ) const
+{
+ // (algorithm sent to me by domi)
+ // We intersect with the horizontal ray from point to the right and
+ // count the number of intersections. That, along with some
+ // minor optimalisations of the intersection test..
+ bool inside_flag = false;
+ double cx = p.x;
+ double cy = p.y;
+
+ Coordinate prevpoint = mpoints.back();
+ bool prevpointbelow = mpoints.back().y >= cy;
+ for ( uint i = 0; i < mpoints.size(); ++i )
+ {
+ Coordinate point = mpoints[i];
+ bool pointbelow = point.y >= cy;
+ if ( prevpointbelow != pointbelow )
+ {
+ // possibility of intersection: points on different side from
+ // the X axis
+ //bool rightofpt = point.x >= cx;
+ // mp: we need to be a little bit more conservative here, in
+ // order to treat properly the case when the point is on the
+ // boundary
+ //if ( rightofpt == ( prevpoint.x >= cx ) )
+ if ( ( point.x - cx )*(prevpoint.x - cx ) > 0 )
+ {
+ // points on same side of Y axis -> easy to test intersection
+ // intersection iff one point to the right of c
+ if ( point.x >= cx )
+ inside_flag = !inside_flag;
+ }
+ else
+ {
+ // points on different sides of Y axis -> we need to calculate
+ // the intersection.
+ // mp: we want to check if the point is on the boundary, and
+ // return false in such case
+ double num = ( point.y - cy )*( prevpoint.x - point.x );
+ double den = prevpoint.y - point.y;
+ if ( num == den*( point.x - cx ) ) return false;
+ if ( num/den <= point.x - cx )
+ inside_flag = !inside_flag;
+ }
+ }
+ prevpoint = point;
+ prevpointbelow = pointbelow;
+ }
+ return inside_flag;
+}
+#define selectpolygonwithinside 1
+#ifdef selectpolygonwithinside
+bool PolygonImp::contains( const Coordinate& p, int, const KigWidget& ) const
+{
+ return isInPolygon( p );
+}
+#else
+bool PolygonImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ bool ret = false;
+ uint reduceddim = mpoints.size() - 1;
+ for ( uint i = 0; i < reduceddim; ++i )
+ {
+ ret |= isOnSegment( p, mpoints[i], mpoints[i+1], w.screenInfo().normalMiss( width ) );
+ }
+ ret |= isOnSegment( p, mpoints[reduceddim], mpoints[0], w.screenInfo().normalMiss( width ) );
+
+ return ret;
+}
+#endif
+
+bool PolygonImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ bool ret = false;
+ uint reduceddim = mpoints.size() - 1;
+ for ( uint i = 0; i < reduceddim; ++i )
+ {
+ SegmentImp* s = new SegmentImp( mpoints[i], mpoints[i+1] );
+ ret |= lineInRect( r, mpoints[i], mpoints[i+1], width, s, w );
+ delete s;
+ s = 0;
+ }
+ SegmentImp* t = new SegmentImp( mpoints[reduceddim], mpoints[0] );
+ ret |= lineInRect( r, mpoints[reduceddim], mpoints[0], width, t, w );
+ delete t;
+ t = 0;
+
+ return ret;
+}
+
+bool PolygonImp::valid() const
+{
+ return true;
+}
+
+const uint PolygonImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 5;
+}
+
+const QCStringList PolygonImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l += "polygon-number-of-sides";
+ l += "polygon-perimeter";
+ l += "polygon-surface";
+ l += "polygon-center-of-mass";
+ l += "polygon-winding-number";
+ assert( l.size() == PolygonImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList PolygonImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l += I18N_NOOP( "Number of sides" );
+ l += I18N_NOOP( "Perimeter" );
+ l += I18N_NOOP( "Surface" );
+ l += I18N_NOOP( "Center of Mass of the Vertices" );
+ l += I18N_NOOP( "Winding Number" );
+ assert( l.size() == PolygonImp::numberOfProperties() );
+ return l;
+}
+
+const ObjectImpType* PolygonImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return PolygonImp::stype();
+}
+
+const char* PolygonImp::iconForProperty( uint which ) const
+{
+ assert( which < PolygonImp::numberOfProperties() );
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ else if ( which == Parent::numberOfProperties() )
+ return "en"; // number of sides
+ else if ( which == Parent::numberOfProperties() + 1 )
+ return "circumference"; // perimeter
+ else if ( which == Parent::numberOfProperties() + 2 )
+ return "areaCircle"; // surface
+ else if ( which == Parent::numberOfProperties() + 3 )
+ return "point"; // center of mass
+ else if ( which == Parent::numberOfProperties() + 4 )
+ return "w"; // winding number
+ else assert( false );
+ return "";
+}
+
+ObjectImp* PolygonImp::property( uint which, const KigDocument& w ) const
+{
+ assert( which < PolygonImp::numberOfProperties() );
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ else if ( which == Parent::numberOfProperties() )
+ {
+ // number of points
+ return new IntImp( mnpoints );
+ }
+ else if ( which == Parent::numberOfProperties() + 1)
+ {
+ double circumference = 0.;
+ // circumference
+ for ( uint i = 0; i < mpoints.size(); ++i )
+ {
+ uint prev = ( i + mpoints.size() - 1 ) % mpoints.size();
+ circumference += ( mpoints[i] - mpoints[prev] ).length();
+ }
+ return new DoubleImp( circumference );
+ }
+ else if ( which == Parent::numberOfProperties() + 2)
+ {
+ int wn = windingNumber (); // not able to compute area for such polygons...
+ if ( wn < 0 ) wn = -wn;
+ if ( wn != 1 ) return new InvalidImp;
+ double surface2 = 0.0;
+ Coordinate prevpoint = mpoints.back();
+ for ( uint i = 0; i < mpoints.size(); ++i )
+ {
+ Coordinate point = mpoints[i];
+ surface2 += ( point.x - prevpoint.x ) * ( point.y + prevpoint.y );
+ prevpoint = point;
+ }
+ return new DoubleImp( fabs( surface2 / 2 ) );
+ }
+ else if ( which == Parent::numberOfProperties() + 3 )
+ {
+ return new PointImp( mcenterofmass );
+ }
+ else if ( which == Parent::numberOfProperties() + 4 )
+ {
+ // winding number
+ return new IntImp( windingNumber() );
+ }
+ else assert( false );
+ return new InvalidImp;
+}
+
+const std::vector<Coordinate> PolygonImp::points() const
+{
+ std::vector<Coordinate> np;
+ np.reserve( mpoints.size() );
+ std::copy( mpoints.begin(), mpoints.end(), std::back_inserter( np ) );
+ return np;
+}
+
+const uint PolygonImp::npoints() const
+{
+ return mnpoints;
+}
+
+PolygonImp* PolygonImp::copy() const
+{
+ return new PolygonImp( mpoints );
+}
+
+void PolygonImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool PolygonImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( PolygonImp::stype() ) &&
+ static_cast<const PolygonImp&>( rhs ).points() == mpoints;
+}
+
+const ObjectImpType* PolygonImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "polygon",
+ I18N_NOOP( "polygon" ),
+ I18N_NOOP( "Select this polygon" ),
+ I18N_NOOP( "Select polygon %1" ),
+ I18N_NOOP( "Remove a Polygon" ),
+ I18N_NOOP( "Add a Polygon" ),
+ I18N_NOOP( "Move a Polygon" ),
+ I18N_NOOP( "Attach to this polygon" ),
+ I18N_NOOP( "Show a Polygon" ),
+ I18N_NOOP( "Hide a Polygon" )
+ );
+
+ return &t;
+}
+
+const ObjectImpType* PolygonImp::stype3()
+{
+ static const ObjectImpType t3(
+ PolygonImp::stype(), "triangle",
+ I18N_NOOP( "triangle" ),
+ I18N_NOOP( "Select this triangle" ),
+ I18N_NOOP( "Select triangle %1" ),
+ I18N_NOOP( "Remove a Triangle" ),
+ I18N_NOOP( "Add a Triangle" ),
+ I18N_NOOP( "Move a Triangle" ),
+ I18N_NOOP( "Attach to this triangle" ),
+ I18N_NOOP( "Show a Triangle" ),
+ I18N_NOOP( "Hide a Triangle" )
+ );
+
+ return &t3;
+}
+
+const ObjectImpType* PolygonImp::stype4()
+{
+ static const ObjectImpType t4(
+ PolygonImp::stype(), "quadrilateral",
+ I18N_NOOP( "quadrilateral" ),
+ I18N_NOOP( "Select this quadrilateral" ),
+ I18N_NOOP( "Select quadrilateral %1" ),
+ I18N_NOOP( "Remove a Quadrilateral" ),
+ I18N_NOOP( "Add a Quadrilateral" ),
+ I18N_NOOP( "Move a Quadrilateral" ),
+ I18N_NOOP( "Attach to this quadrilateral" ),
+ I18N_NOOP( "Show a Quadrilateral" ),
+ I18N_NOOP( "Hide a Quadrilateral" )
+ );
+
+ return &t4;
+}
+
+const ObjectImpType* PolygonImp::type() const
+{
+ uint n = mpoints.size();
+
+ if ( n == 3 ) return PolygonImp::stype3();
+ if ( n == 4 ) return PolygonImp::stype4();
+ return PolygonImp::stype();
+}
+
+bool PolygonImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ assert( which < PolygonImp::numberOfProperties() );
+ if ( which < Parent::numberOfProperties() )
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+ return false;
+}
+
+Rect PolygonImp::surroundingRect() const
+{
+ Rect r( 0., 0., 0., 0. );
+ for ( uint i = 0; i < mpoints.size(); ++i )
+ {
+ r.setContains( mpoints[i] );
+ }
+ return r;
+}
+
+int PolygonImp::windingNumber() const
+{
+ /*
+ * this is defined as the sum of the external angles while at
+ * all vertices, then normalized by 2pi. The external angle
+ * is the angle we steer at each vertex while we walk along the
+ * boundary of the polygon.
+ * In the end we only need to count how many time we cross the (1,0)
+ * direction (positive x-axis) with a positive sign if we cross while
+ * steering left and a negative sign viceversa
+ */
+
+ int winding = 0;
+ uint npoints = mpoints.size();
+ Coordinate prevside = mpoints[0] - mpoints[npoints-1];
+ for ( uint i = 0; i < npoints; ++i )
+ {
+ uint nexti = i + 1;
+ if ( nexti >= npoints ) nexti = 0;
+ Coordinate side = mpoints[nexti] - mpoints[i];
+ double vecprod = side.x*prevside.y - side.y*prevside.x;
+ int steeringdir = ( vecprod > 0 ) ? 1 : -1;
+ if ( vecprod == 0.0 || side.y*prevside.y > 0 )
+ {
+ prevside = side;
+ continue; // cannot cross the (1,0) direction
+ }
+ if ( side.y*steeringdir < 0 && prevside.y*steeringdir >= 0 )
+ winding -= steeringdir;
+ prevside = side;
+ }
+ return winding;
+}
+
+bool PolygonImp::isMonotoneSteering() const
+{
+ /*
+ * returns true if while walking along the boundary,
+ * steering is always in the same direction
+ */
+
+ uint npoints = mpoints.size();
+ Coordinate prevside = mpoints[0] - mpoints[npoints-1];
+ int prevsteeringdir = 0;
+ for ( uint i = 0; i < npoints; ++i )
+ {
+ uint nexti = i + 1;
+ if ( nexti >= npoints ) nexti = 0;
+ Coordinate side = mpoints[nexti] - mpoints[i];
+ double vecprod = side.x*prevside.y - side.y*prevside.x;
+ int steeringdir = ( vecprod > 0 ) ? 1 : -1;
+ if ( vecprod == 0.0 )
+ {
+ prevside = side;
+ continue; // going straight
+ }
+ if ( prevsteeringdir*steeringdir < 0 ) return false;
+ prevside = side;
+ prevsteeringdir = steeringdir;
+ }
+ return true;
+}
+
+bool PolygonImp::isConvex() const
+{
+ if ( ! isMonotoneSteering() ) return false;
+ int winding = windingNumber();
+ if ( winding < 0 ) winding = -winding;
+ assert ( winding > 0 );
+ return winding == 1;
+}
+
+std::vector<Coordinate> computeConvexHull( const std::vector<Coordinate>& points )
+{
+ /*
+ * compute the convex hull of the set of points, the resulting list
+ * is the vertices of the resulting polygon listed in a counter clockwise
+ * order. This algorithm is on order n^2, probably suboptimal, but
+ * we don't expect to have large values for n.
+ */
+
+ if ( points.size() < 3 ) return points;
+ std::vector<Coordinate> worklist = points;
+ std::vector<Coordinate> result;
+
+ double ymin = worklist[0].y;
+ uint imin = 0;
+ for ( uint i = 1; i < worklist.size(); ++i )
+ {
+ if ( worklist[i].y < ymin )
+ {
+ ymin = worklist[i].y;
+ imin = i;
+ }
+ }
+
+ // worklist[imin] is definitely on the convex hull, let's start from there
+ result.push_back( worklist[imin] );
+ Coordinate startpoint = worklist[imin];
+ Coordinate apoint = worklist[imin];
+ double aangle = 0.0;
+
+ while ( ! worklist.empty() )
+ {
+ int besti = -1;
+ double anglemin = 10000.0;
+ for ( uint i = 0; i < worklist.size(); ++i )
+ {
+ if ( worklist[i] == apoint ) continue;
+ Coordinate v = worklist[i] - apoint;
+ double angle = std::atan2( v.y, v.x );
+ while ( angle < aangle ) angle += 2*M_PI;
+ if ( angle < anglemin )
+ { // found a better point
+ besti = i;
+ anglemin = angle;
+ }
+ }
+
+ if ( besti < 0 ) return result; // this happens, e.g. if all points coincide
+ apoint = worklist[besti];
+ aangle = anglemin;
+ if ( apoint == startpoint )
+ {
+ return result;
+ }
+ result.push_back( apoint );
+ worklist.erase( worklist.begin() + besti, worklist.begin() + besti + 1 );
+ }
+ assert( false );
+ return result;
+}
diff --git a/kig/objects/polygon_imp.h b/kig/objects/polygon_imp.h
new file mode 100644
index 00000000..9a25d516
--- /dev/null
+++ b/kig/objects/polygon_imp.h
@@ -0,0 +1,94 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// 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.
+
+#ifndef KIG_OBJECTS_POLYGON_IMP_H
+#define KIG_OBJECTS_POLYGON_IMP_H
+
+#include "object_imp.h"
+#include "../misc/coordinate.h"
+#include <vector>
+
+/**
+ * An ObjectImp representing a polygon.
+ */
+class PolygonImp
+ : public ObjectImp
+{
+ uint mnpoints;
+ std::vector<Coordinate> mpoints;
+ Coordinate mcenterofmass;
+public:
+ typedef ObjectImp Parent;
+ /**
+ * Returns the ObjectImpType representing the PolygonImp type..
+ */
+ static const ObjectImpType* stype();
+ static const ObjectImpType* stype3();
+ static const ObjectImpType* stype4();
+
+ /**
+ * Constructs a polygon.
+ */
+ PolygonImp( const std::vector<Coordinate>& points );
+ PolygonImp( const uint nsides, const std::vector<Coordinate>& points,
+ const Coordinate& centerofmass );
+ ~PolygonImp();
+ PolygonImp* copy() const;
+
+ Coordinate attachPoint() const;
+ ObjectImp* transform( const Transformation& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ bool valid() const;
+ Rect surroundingRect() const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ /**
+ * Returns the vector with polygon points.
+ */
+ const std::vector<Coordinate> points() const;
+ /**
+ * Returns the center of mass of the polygon.
+ */
+ const Coordinate centerOfMass() const;
+ /**
+ * Returns the number of points of this polygon.
+ */
+ const uint npoints() const;
+
+ bool equals( const ObjectImp& rhs ) const;
+ bool isInPolygon( const Coordinate& p ) const;
+ int windingNumber() const;
+ bool isMonotoneSteering() const;
+ bool isConvex() const;
+};
+
+std::vector<Coordinate> computeConvexHull( const std::vector<Coordinate>& points );
+
+#endif
diff --git a/kig/objects/polygon_type.cc b/kig/objects/polygon_type.cc
new file mode 100644
index 00000000..bca867da
--- /dev/null
+++ b/kig/objects/polygon_type.cc
@@ -0,0 +1,669 @@
+// Copyright (C) 2003 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+// 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 "polygon_type.h"
+
+#include "bogus_imp.h"
+#include "line_imp.h"
+#include "point_imp.h"
+#include "polygon_imp.h"
+#include "object_calcer.h"
+
+#include "../misc/common.h"
+
+#include <klocale.h>
+#include <cmath>
+#include <vector>
+
+/*
+ * triangle by its vertices
+ */
+
+static const char triangle_constructstatement[] = I18N_NOOP( "Construct a triangle with this vertex" );
+static const char triangle_constructstatement2[] = I18N_NOOP( "Select a point to be a vertex of the new triangle..." );
+
+static const struct ArgsParser::spec argsspecTriangleB3P[] =
+{
+ { PointImp::stype(), triangle_constructstatement, triangle_constructstatement2, true },
+ { PointImp::stype(), triangle_constructstatement, triangle_constructstatement2, true },
+ { PointImp::stype(), triangle_constructstatement, triangle_constructstatement2, true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TriangleB3PType )
+
+TriangleB3PType::TriangleB3PType()
+ : ArgsParserObjectType( "TriangleB3P", argsspecTriangleB3P, 3 )
+{
+}
+
+TriangleB3PType::~TriangleB3PType()
+{
+}
+
+const TriangleB3PType* TriangleB3PType::instance()
+{
+ static const TriangleB3PType s;
+ return &s;
+}
+
+ObjectImp* TriangleB3PType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 1 ) ) return new InvalidImp;
+ std::vector<Coordinate> points;
+
+ Coordinate centerofmass3 = Coordinate( 0, 0 );
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ {
+ Coordinate point = static_cast<const PointImp*>( *i )->coordinate();
+ centerofmass3 += point;
+ points.push_back( point );
+ }
+ return new PolygonImp( 3, points, centerofmass3/3 );
+}
+
+const ObjectImpType* TriangleB3PType::resultId() const
+{
+ return PolygonImp::stype();
+}
+
+bool TriangleB3PType::canMove( const ObjectTypeCalcer& o ) const
+{
+ return isFreelyTranslatable( o );
+}
+
+bool TriangleB3PType::isFreelyTranslatable( const ObjectTypeCalcer& o ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ return parents[0]->isFreelyTranslatable() &&
+ parents[1]->isFreelyTranslatable() &&
+ parents[2]->isFreelyTranslatable();
+}
+
+void TriangleB3PType::move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ assert( margsparser.checkArgs( parents ) );
+ const Coordinate a = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ const Coordinate b = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
+ const Coordinate c = static_cast<const PointImp*>( parents[2]->imp() )->coordinate();
+ if ( parents[0]->canMove() )
+ parents[0]->move( to, d );
+ if ( parents[1]->canMove() )
+ parents[1]->move( to + b - a, d );
+ if ( parents[2]->canMove() )
+ parents[2]->move( to + c - a, d );
+}
+
+const Coordinate TriangleB3PType::moveReferencePoint( const ObjectTypeCalcer& o ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ assert( margsparser.checkArgs( parents ) );
+ return static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+}
+
+std::vector<ObjectCalcer*> TriangleB3PType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ std::vector<ObjectCalcer*> parents = ourobj.parents();
+ std::set<ObjectCalcer*> ret;
+ std::vector<ObjectCalcer*> tmp = parents[0]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ tmp = parents[1]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ tmp = parents[2]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ ret.insert( parents.begin(), parents.end() );
+ return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
+}
+
+/*
+ * generic polygon
+ */
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonBNPType )
+
+PolygonBNPType::PolygonBNPType()
+ : ObjectType( "PolygonBNP" )
+{
+}
+
+PolygonBNPType::~PolygonBNPType()
+{
+}
+
+const PolygonBNPType* PolygonBNPType::instance()
+{
+ static const PolygonBNPType s;
+ return &s;
+}
+
+ObjectImp* PolygonBNPType::calc( const Args& parents, const KigDocument& ) const
+{
+ uint count = parents.size();
+ assert (count >= 3); /* non sono ammessi poligoni con meno di tre lati */
+// if ( parents[0] != parents[count] ) return new InvalidImp;
+ std::vector<Coordinate> points;
+
+ uint npoints = 0;
+ Coordinate centerofmassn = Coordinate( 0, 0 );
+
+ for ( uint i = 0; i < count; ++i )
+ {
+ npoints++;
+ if ( ! parents[i]->inherits( PointImp::stype() ) ) return new InvalidImp;
+ Coordinate point = static_cast<const PointImp*>( parents[i] )->coordinate();
+ centerofmassn += point;
+ points.push_back( point );
+ }
+ return new PolygonImp( npoints, points, centerofmassn/npoints );
+}
+
+const ObjectImpType* PolygonBNPType::resultId() const
+{
+ return PolygonImp::stype();
+}
+
+const ObjectImpType* PolygonBNPType::impRequirement( const ObjectImp*, const Args& ) const
+{
+ return PointImp::stype();
+}
+
+bool PolygonBNPType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
+{
+ return false; /* should be true? */
+}
+
+std::vector<ObjectCalcer*> PolygonBNPType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ return args; /* should already be in correct order */
+}
+
+Args PolygonBNPType::sortArgs( const Args& args ) const
+{
+ return args;
+}
+
+bool PolygonBNPType::canMove( const ObjectTypeCalcer& o ) const
+{
+ return isFreelyTranslatable( o );
+}
+
+bool PolygonBNPType::isFreelyTranslatable( const ObjectTypeCalcer& o ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ for ( uint i = 0; i < parents.size(); ++i )
+ {
+ if ( !parents[i]->isFreelyTranslatable() ) return false;
+ }
+ return true;
+}
+
+void PolygonBNPType::move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ const Coordinate ref = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ for ( uint i = 0; i < parents.size(); ++i )
+ {
+ const Coordinate a = static_cast<const PointImp*>( parents[i]->imp() )->coordinate();
+ parents[i]->move( to + a - ref, d );
+ }
+}
+
+const Coordinate PolygonBNPType::moveReferencePoint( const ObjectTypeCalcer& o
+) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ return static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+}
+
+std::vector<ObjectCalcer*> PolygonBNPType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ std::vector<ObjectCalcer*> parents = ourobj.parents();
+ std::set<ObjectCalcer*> ret;
+ for ( uint i = 0; i < parents.size(); ++i )
+ {
+ std::vector<ObjectCalcer*> tmp = parents[i]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ }
+ ret.insert( parents.begin(), parents.end() );
+ return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
+}
+
+/*
+ * regular polygon by center and vertex
+ */
+
+//static const char constructpoligonthroughpointstat[] = I18N_NOOP( "Construct a polygon with this vertex" );
+//
+//static const char constructpoligonwithcenterstat[] = I18N_NOOP( "Construct a polygon with this center" );
+//
+//static const ArgsParser::spec argsspecPoligonBCV[] =
+//{
+// { PointImp::stype(), constructpoligonwithcenterstat,
+// I18N_NOOP( "Select the center of the new polygon..." ), false },
+// { PointImp::stype(), constructpoligonthroughpointstat,
+// I18N_NOOP( "Select a vertex for the new polygon..." ), true },
+// { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+//};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonBCVType )
+
+PolygonBCVType::PolygonBCVType()
+ : ObjectType( "PoligonBCV" )
+// we keep the name "PoligonBCV" although syntactically incorrect for
+// compatibility reasons with old kig files
+// : ArgsParserObjectType( "PoligonBCV", argsspecPoligonBCV, 3 )
+{
+}
+
+PolygonBCVType::~PolygonBCVType()
+{
+}
+
+const PolygonBCVType* PolygonBCVType::instance()
+{
+ static const PolygonBCVType s;
+ return &s;
+}
+
+ObjectImp* PolygonBCVType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( parents.size() < 3 || parents.size() > 4 ) return new InvalidImp;
+
+ if ( ( ! parents[0]->inherits( PointImp::stype() ) ) ||
+ ( ! parents[1]->inherits( PointImp::stype() ) ) ||
+ ( ! parents[2]->inherits( IntImp::stype() ) ) )
+ return new InvalidImp;
+
+ const Coordinate center =
+ static_cast<const PointImp*>( parents[0] )->coordinate();
+ const Coordinate vertex =
+ static_cast<const PointImp*>( parents[1] )->coordinate();
+ const int sides =
+ static_cast<const IntImp*>( parents[2] )->data();
+ int twist = 1;
+ if ( parents.size() == 4 )
+ {
+ if ( ! parents[3]->inherits( IntImp::stype() ) ) return new InvalidImp;
+ twist = static_cast<const IntImp*>( parents[3] )->data();
+ }
+ std::vector<Coordinate> vertexes;
+
+ double dx = vertex.x - center.x;
+ double dy = vertex.y - center.y;
+
+ for ( int i = 1; i <= sides; i++ )
+ {
+ double alfa = 2*twist*M_PI/sides;
+ double theta1 = alfa*i - alfa;
+ double ctheta1 = cos(theta1);
+ double stheta1 = sin(theta1);
+
+ Coordinate v1 = center + Coordinate( ctheta1*dx - stheta1*dy,
+ stheta1*dx + ctheta1*dy );
+ vertexes.push_back( v1 );
+ }
+ return new PolygonImp( uint (sides), vertexes, center );
+}
+
+const ObjectImpType* PolygonBCVType::resultId() const
+{
+ return SegmentImp::stype();
+}
+
+const ObjectImpType* PolygonBCVType::impRequirement( const ObjectImp* obj, const Args& ) const
+{
+ if ( obj->inherits( PointImp::stype() ) )
+ return PointImp::stype();
+
+ if ( obj->inherits( IntImp::stype() ) )
+ return IntImp::stype();
+
+ return 0;
+}
+
+bool PolygonBCVType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
+{
+ return false; /* should be true? */
+}
+
+std::vector<ObjectCalcer*> PolygonBCVType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ return args; /* should already be in correct order */
+}
+
+Args PolygonBCVType::sortArgs( const Args& args ) const
+{
+ return args;
+}
+
+bool PolygonBCVType::canMove( const ObjectTypeCalcer& o ) const
+{
+ return isFreelyTranslatable( o );
+}
+
+bool PolygonBCVType::isFreelyTranslatable( const ObjectTypeCalcer& o ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ return parents[0]->isFreelyTranslatable() &&
+ parents[1]->isFreelyTranslatable();
+}
+
+void PolygonBCVType::move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ // assert( margsparser.checkArgs( parents ) );
+ if ( ! parents[0]->imp()->inherits( PointImp::stype() ) ||
+ ! parents[1]->imp()->inherits( PointImp::stype() ) ) return;
+
+ const Coordinate a = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ const Coordinate b = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
+ parents[0]->move( to, d );
+ parents[1]->move( to + b - a, d );
+}
+
+const Coordinate PolygonBCVType::moveReferencePoint( const ObjectTypeCalcer& o) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ // assert( margsparser.checkArgs( parents ) );
+ if ( ! parents[0]->imp()->inherits( PointImp::stype() ) ) return Coordinate::invalidCoord();
+
+ return static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+}
+
+std::vector<ObjectCalcer*> PolygonBCVType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ std::vector<ObjectCalcer*> parents = ourobj.parents();
+ std::set<ObjectCalcer*> ret;
+ std::vector<ObjectCalcer*> tmp = parents[0]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ tmp = parents[1]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ ret.insert( &parents[0], &parents[1] );
+ return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
+}
+
+/* polygon-line intersection */
+
+static const ArgsParser::spec argsspecPolygonLineIntersection[] =
+{
+ { PolygonImp::stype(), I18N_NOOP( "Intersect this polygon with a line" ),
+ I18N_NOOP( "Select the polygon of which you want the intersection with a line..." ), false },
+ { AbstractLineImp::stype(), "Intersect this line with a polygon", "Select the line of which you want the intersection with a polygon...", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonLineIntersectionType )
+
+PolygonLineIntersectionType::PolygonLineIntersectionType()
+ : ArgsParserObjectType( "PolygonLineIntersection", argsspecPolygonLineIntersection, 2 )
+{
+}
+
+PolygonLineIntersectionType::~PolygonLineIntersectionType()
+{
+}
+
+const PolygonLineIntersectionType* PolygonLineIntersectionType::instance()
+{
+ static const PolygonLineIntersectionType t;
+ return &t;
+}
+
+/*
+ * Intersection of a polygon and a line/ray/segment.
+ *
+ * geometrically speaking the result is always a collection of
+ * collinear nonintersecting open segments (at most one if the
+ * polygon is convex). Since we don't know in advance how many
+ * segments will result, the obvious choice is to return an
+ * InvalidImp in cases when the result is *not* a single segment
+ *
+ * computing the two ends of this segment is more tricky then one
+ * expects especially when intersecting segments/rays.
+ *
+ * particularly "difficult" situations are those where we intersect
+ * a segment/ray with an/the endpoint coinciding with a vertex of
+ * the polygon, especially if that vertex is a "reentrant" (concave)
+ * vertex of the polygon.
+ */
+
+ObjectImp* PolygonLineIntersectionType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const PolygonImp* polygon = static_cast<const PolygonImp*>( parents[0] );
+ const std::vector<Coordinate> ppoints = polygon->points();
+ const LineData line = static_cast<const AbstractLineImp*>( parents[1] )->data();
+ Coordinate intersections[2];
+ uint whichintersection = 0;
+
+ bool boundleft = false;
+ bool boundright = false;
+ if ( parents[1]->inherits( SegmentImp::stype() ) )
+ {
+ boundleft = boundright = true;
+ }
+ if ( parents[1]->inherits( RayImp::stype() ) )
+ {
+ boundleft = true;
+ }
+ Coordinate a = line.a;
+ double abx = line.b.x - a.x;
+ double aby = line.b.y - a.y;
+
+ double leftendinside = false;
+ double rightendinside = false;
+ Coordinate prevpoint = ppoints.back() - a;
+ bool prevpointbelow = ( abx*prevpoint.y <= aby*prevpoint.x );
+ for ( uint i = 0; i < ppoints.size(); ++i )
+ {
+ Coordinate point = ppoints[i] - a;
+ bool pointbelow = ( abx*point.y <= aby*point.x );
+ if ( pointbelow != prevpointbelow )
+ {
+ /* found an intersection with the support line
+ * compute the value of the parameter...
+ */
+ double dcx = point.x - prevpoint.x;
+ double dcy = point.y - prevpoint.y;
+ double num = point.x*dcy - point.y*dcx;
+ double den = abx*dcy - aby*dcx;
+ if ( std::fabs( den ) <= 1.e-6*std::fabs( num ) ) continue; //parallel
+ double t = num/den;
+ if ( boundleft && t <= 0 )
+ {
+ leftendinside = !leftendinside;
+ }
+ else if ( boundright && t >= 1 )
+ {
+ rightendinside = !rightendinside;
+ }
+ else
+ {
+ if ( whichintersection >= 2 ) return new InvalidImp;
+ intersections[whichintersection++] = a + t*Coordinate( abx, aby );
+ }
+ }
+ prevpoint = point;
+ prevpointbelow = pointbelow;
+ }
+
+ if ( leftendinside )
+ {
+ if ( whichintersection >= 2 ) return new InvalidImp;
+ intersections[whichintersection++] = a;
+ }
+
+ if ( rightendinside )
+ {
+ if ( whichintersection >= 2 ) return new InvalidImp;
+ intersections[whichintersection++] = line.b;
+ }
+
+ switch (whichintersection)
+ {
+ case 1: /* just for completeness: this should never happen */
+ return new PointImp( intersections[0] );
+ break;
+ case 2:
+ return new SegmentImp( intersections[0], intersections[1] );
+ break;
+ case 0:
+ default:
+ return new InvalidImp;
+ break;
+ }
+}
+
+const ObjectImpType* PolygonLineIntersectionType::resultId() const
+{
+ return SegmentImp::stype();
+}
+
+/* polygon vertices */
+
+static const ArgsParser::spec argsspecPolygonVertex[] =
+{
+ { PolygonImp::stype(), I18N_NOOP( "Construct the vertices of this polygon" ),
+ I18N_NOOP( "Select the polygon of which you want to construct the vertices..." ), true },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonVertexType )
+
+PolygonVertexType::PolygonVertexType()
+ : ArgsParserObjectType( "PolygonVertex", argsspecPolygonVertex, 2 )
+{
+}
+
+PolygonVertexType::~PolygonVertexType()
+{
+}
+
+const PolygonVertexType* PolygonVertexType::instance()
+{
+ static const PolygonVertexType t;
+ return &t;
+}
+
+ObjectImp* PolygonVertexType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const std::vector<Coordinate> ppoints = static_cast<const PolygonImp*>( parents[0] )->points();
+ const uint i = static_cast<const IntImp*>( parents[1] )->data();
+
+ if ( i >= ppoints.size() ) return new InvalidImp;
+
+ return new PointImp( ppoints[i] );
+}
+
+const ObjectImpType* PolygonVertexType::resultId() const
+{
+ return PointImp::stype();
+}
+
+/* polygon sides */
+
+static const ArgsParser::spec argsspecPolygonSide[] =
+{
+ { PolygonImp::stype(), I18N_NOOP( "Construct the sides of this polygon" ),
+ I18N_NOOP( "Select the polygon of which you want to construct the sides..." ), false },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonSideType )
+
+PolygonSideType::PolygonSideType()
+ : ArgsParserObjectType( "PolygonSide", argsspecPolygonSide, 2 )
+{
+}
+
+PolygonSideType::~PolygonSideType()
+{
+}
+
+const PolygonSideType* PolygonSideType::instance()
+{
+ static const PolygonSideType t;
+ return &t;
+}
+
+ObjectImp* PolygonSideType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const std::vector<Coordinate> ppoints = static_cast<const PolygonImp*>( parents[0] )->points();
+ const uint i = static_cast<const IntImp*>( parents[1] )->data();
+
+ if ( i >= ppoints.size() ) return new InvalidImp;
+
+ uint nexti = i + 1;
+ if ( nexti >= ppoints.size() ) nexti = 0;
+
+ return new SegmentImp( ppoints[i], ppoints[nexti] );
+}
+
+const ObjectImpType* PolygonSideType::resultId() const
+{
+ return SegmentImp::stype();
+}
+
+/* convex hull of a polygon */
+
+static const ArgsParser::spec argsspecConvexHull[] =
+{
+ { PolygonImp::stype(), I18N_NOOP( "Construct the convex hull of this polygon" ),
+ I18N_NOOP( "Select the polygon of which you want to construct the convex hull..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConvexHullType )
+
+ConvexHullType::ConvexHullType()
+ : ArgsParserObjectType( "ConvexHull", argsspecConvexHull, 1 )
+{
+}
+
+ConvexHullType::~ConvexHullType()
+{
+}
+
+const ConvexHullType* ConvexHullType::instance()
+{
+ static const ConvexHullType t;
+ return &t;
+}
+
+ObjectImp* ConvexHullType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const std::vector<Coordinate> ppoints = static_cast<const PolygonImp*>( parents[0] )->points();
+
+ if ( ppoints.size() < 3 ) return new InvalidImp;
+
+ std::vector<Coordinate> hull = computeConvexHull( ppoints );
+ if ( hull.size() < 3 ) return new InvalidImp;
+ return new PolygonImp( hull );
+}
+
+const ObjectImpType* ConvexHullType::resultId() const
+{
+ return PolygonImp::stype();
+}
diff --git a/kig/objects/polygon_type.h b/kig/objects/polygon_type.h
new file mode 100644
index 00000000..a49100bd
--- /dev/null
+++ b/kig/objects/polygon_type.h
@@ -0,0 +1,139 @@
+// Copyright (C) 2003 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+// 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.
+
+#ifndef KIG_OBJECTS_POLIGON_TYPE_H
+#define KIG_OBJECTS_POLIGON_TYPE_H
+
+#include "base_type.h"
+
+/**
+ * Triangle by its vertices
+ */
+class TriangleB3PType
+ : public ArgsParserObjectType
+{
+ TriangleB3PType();
+ ~TriangleB3PType();
+public:
+ static const TriangleB3PType* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+ bool canMove( const ObjectTypeCalcer& o ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& o ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& o ) const;
+};
+
+/**
+ * Polygon by its vertices
+ */
+class PolygonBNPType
+ : public ObjectType
+{
+ PolygonBNPType();
+ ~PolygonBNPType();
+public:
+ static const PolygonBNPType* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const;
+ Args sortArgs( const Args& args ) const;
+
+ bool canMove( const ObjectTypeCalcer& o ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& o ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& o ) const;
+};
+
+/**
+ * Polygon by center and vertex
+ */
+class PolygonBCVType
+ : public ObjectType
+{
+ PolygonBCVType();
+ ~PolygonBCVType();
+public:
+ static const PolygonBCVType* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const;
+ Args sortArgs( const Args& args ) const;
+ bool canMove( const ObjectTypeCalcer& o ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& o ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& o ) const;
+};
+
+class PolygonLineIntersectionType
+ : public ArgsParserObjectType
+{
+ PolygonLineIntersectionType();
+ ~PolygonLineIntersectionType();
+public:
+ static const PolygonLineIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class PolygonVertexType
+ : public ArgsParserObjectType
+{
+ PolygonVertexType();
+ ~PolygonVertexType();
+public:
+ static const PolygonVertexType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class PolygonSideType
+ : public ArgsParserObjectType
+{
+ PolygonSideType();
+ ~PolygonSideType();
+public:
+ static const PolygonSideType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConvexHullType
+ : public ArgsParserObjectType
+{
+ ConvexHullType();
+ ~ConvexHullType();
+public:
+ static const ConvexHullType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+#endif
diff --git a/kig/objects/special_calcers.cc b/kig/objects/special_calcers.cc
new file mode 100644
index 00000000..e70bd4e9
--- /dev/null
+++ b/kig/objects/special_calcers.cc
@@ -0,0 +1,84 @@
+// Copyright (C) 2004 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_calcers.h"
+
+static const ArgsParser::spec argsspecMeasureTransport[] =
+{
+ { CircleImp::stype(), I18N_NOOP( "Transport a measure on this circle" ) },
+ { PointImp::stype(), I18N_NOOP( "Project this point onto the circle" ) },
+ { SegmentImp::stype(), I18N_NOOP( "Segment to transport" ) }
+};
+
+static ArgsParser measuretransportargsparser( argsspecMeasureTransport, 3 );
+
+std::vector<ObjectCalcer*> MeasureTransportCalcer::parents() const
+{
+ std::vector<ObjectCalcer*> ret;
+ ret.push_back( mcircle );
+ ret.push_back( mpoint );
+ ret.push_back( msegment );
+ return ret;
+}
+
+MeasureTransportCalcer::MeasureTransportCalcer(ObjectCalcer* circle, ObjectCalcer* point, ObjectCalcer* segment )
+ : mcircle( circle ), mpoint( point ), msegment( segment ), mimp( 0 )
+{
+}
+
+MeasureTransportCalcer::~MeasureTransportCalcer()
+{
+}
+
+void MeasureTransportCalcer::calc( const KigDocument& )
+{
+ if ( ! measuretransportargsparser.checkArgs( parents() ) )
+ return new InvalidImp();
+
+ if ( ! isPointOnCurve( mpoint, mcircle ) )
+ return new InvalidImp();
+
+ const CircleImp* c = static_cast<const CircleImp*>( mcircle->imp() );
+ const PointImp* p = static_cast<const PointImp*>( mpoint->imp() );
+ const SegmentImp* s = static_cast<const SegmentImp*>( msegment->imp() );
+ double param = c->getParam( p->coordinate(), doc );
+ double measure = s->length();
+ measure /= 2*c->radius()*M_PI;
+ param += measure;
+ while (param > 1) param -= 1;
+
+ const Coordinate nc = c->getPoint( param, doc );
+ if ( nc.valid() ) return new PointImp( nc );
+ else return new InvalidImp;
+}
+
+const ObjectImpType* MeasureTransportCalcer::impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const
+{
+ if ( o->imp()->inherits( CircleImp::stype() ) )
+ return CircleImp::stype();
+ else if ( o->imp()->inherits( PointImp::stype() ) )
+ return PointImp::stype();
+ else if ( o->imp()->inherits( SegmentImp::stype() ) )
+ return SegmentImp::stype();
+ else
+ {
+ assert( false );
+ return 0;
+ }
+}
+
diff --git a/kig/objects/special_calcers.h b/kig/objects/special_calcers.h
new file mode 100644
index 00000000..640587cc
--- /dev/null
+++ b/kig/objects/special_calcers.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2004 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.
+
+#ifndef KIG_OBJECTS_SPECIAL_CALCERS_H
+#define KIG_OBJECTS_SPECIAL_CALCERS_H
+
+class MeasureTransportCalcer
+ : public ObjectCalcer
+{
+ ObjectCalcer* mcircle;
+ ObjectCalcer* mpoint;
+ ObjectCalcer* msegment;
+ ObjectImp* mimp;
+public:
+ MeasureTransportCalcer(ObjectCalcer* circle, ObjectCalcer* point, ObjectCalcer* segment );
+ ~MeasureTransportCalcer();
+
+ std::vector<ObjectCalcer*> parents() const;
+ void calc( const KigDocument& );
+ const ObjectImpType* impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const;
+};
+
+#endif
diff --git a/kig/objects/tangent_type.cc b/kig/objects/tangent_type.cc
new file mode 100644
index 00000000..12ebda23
--- /dev/null
+++ b/kig/objects/tangent_type.cc
@@ -0,0 +1,285 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// 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 "tangent_type.h"
+
+#include "bogus_imp.h"
+#include "conic_imp.h"
+#include "cubic_imp.h"
+#include "curve_imp.h"
+#include "other_imp.h"
+#include "point_imp.h"
+#include "line_imp.h"
+
+#include "../misc/common.h"
+#include "../misc/conic-common.h"
+//#include "../misc/calcpaths.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+
+static const char constructlinetangentpoint[] = "SHOULDNOTBESEEN";
+static const char selecttangent1[] =
+ I18N_NOOP( "Select the curve..." );
+static const char selecttangent2[] =
+ I18N_NOOP( "Select the point for the tangent to go through..." );
+
+static const ArgsParser::spec argsspecTangentConic[] =
+{
+ { ConicImp::stype(), "SHOULDNOTBESEEN", selecttangent1, false },
+ { PointImp::stype(), constructlinetangentpoint, selecttangent2, true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TangentConicType )
+
+TangentConicType::TangentConicType()
+ : ArgsParserObjectType( "TangentConic", argsspecTangentConic, 2 )
+{
+}
+
+TangentConicType::~TangentConicType()
+{
+}
+
+const TangentConicType* TangentConicType::instance()
+{
+ static const TangentConicType t;
+ return &t;
+}
+
+ObjectImp* TangentConicType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const ConicImp* c = static_cast<const ConicImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+
+ if ( !c->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ bool ok;
+ const LineData tangent = calcConicPolarLine( c->cartesianData(), p, ok );
+
+ if ( !ok )
+ return new InvalidImp;
+
+ return new LineImp( tangent );
+}
+
+const ObjectImpType* TangentConicType::resultId() const
+{
+ return LineImp::stype();
+}
+
+/*** Arc starts here ***/
+
+static const ArgsParser::spec argsspecTangentArc[] =
+{
+ { ArcImp::stype(), "SHOULDNOTBESEEN", selecttangent1, false },
+ { PointImp::stype(), constructlinetangentpoint, selecttangent2, true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TangentArcType )
+
+TangentArcType::TangentArcType()
+ : ArgsParserObjectType( "TangentArc", argsspecTangentArc, 2 )
+{
+}
+
+TangentArcType::~TangentArcType()
+{
+}
+
+const TangentArcType* TangentArcType::instance()
+{
+ static const TangentArcType t;
+ return &t;
+}
+
+ObjectImp* TangentArcType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const ArcImp* arc = static_cast<const ArcImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+
+ if ( !arc->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ Coordinate c = arc->center();
+ double sqr = arc->radius();
+ sqr *= sqr;
+ ConicCartesianData data( 1.0, 1.0, 0.0, -2*c.x, -2*c.y, c.x*c.x + c.y*c.y - sqr );
+
+ bool ok;
+ const LineData tangent = calcConicPolarLine( data, p, ok );
+
+ if ( !ok )
+ return new InvalidImp;
+
+ return new LineImp( tangent );
+}
+
+const ObjectImpType* TangentArcType::resultId() const
+{
+ return LineImp::stype();
+}
+
+/**** Cubic starts here ****/
+
+static const ArgsParser::spec argsspecTangentCubic[] =
+{
+ { CubicImp::stype(), "SHOULDNOTBESEEN", selecttangent1, false },
+ { PointImp::stype(), constructlinetangentpoint, selecttangent2, true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TangentCubicType )
+
+TangentCubicType::TangentCubicType()
+ : ArgsParserObjectType( "TangentCubic", argsspecTangentCubic, 2 )
+{
+}
+
+TangentCubicType::~TangentCubicType()
+{
+}
+
+const TangentCubicType* TangentCubicType::instance()
+{
+ static const TangentCubicType t;
+ return &t;
+}
+
+ObjectImp* TangentCubicType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const CubicImp* cubic = static_cast<const CubicImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+
+ if ( !cubic->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ double x = p.x;
+ double y = p.y;
+ CubicCartesianData data = cubic->data();
+// double aconst = data.coeffs[0];
+ double ax = data.coeffs[1];
+ double ay = data.coeffs[2];
+ double axx = data.coeffs[3];
+ double axy = data.coeffs[4];
+ double ayy = data.coeffs[5];
+ double axxx = data.coeffs[6];
+ double axxy = data.coeffs[7];
+ double axyy = data.coeffs[8];
+ double ayyy = data.coeffs[9];
+
+ /* mp: the tangent vector (-gy,gx) is orthogonal to the gradient (gx,gy)
+ * which is easy to compute from the CartesianData
+ *
+ * note: same thing could be done for conics, which would be
+ * much more efficient...
+ */
+
+ Coordinate tangvec = Coordinate (
+ - axxy*x*x - 2*axyy*x*y - 3*ayyy*y*y - axy*x - 2*ayy*y - ay,
+ 3*axxx*x*x + 2*axxy*x*y + axyy*y*y + 2*axx*x + axy*y + ax
+ );
+ const LineData tangent = LineData( p, p + tangvec );
+
+ return new LineImp( tangent );
+}
+
+const ObjectImpType* TangentCubicType::resultId() const
+{
+ return LineImp::stype();
+}
+
+/**** Curve (locus) starts here ****/
+
+static const ArgsParser::spec argsspecTangentCurve[] =
+{
+ { CurveImp::stype(), "SHOULDNOTBESEEN", selecttangent1, false },
+ { PointImp::stype(), constructlinetangentpoint, selecttangent2, true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TangentCurveType )
+
+TangentCurveType::TangentCurveType()
+ : ArgsParserObjectType( "TangentCurve", argsspecTangentCurve, 2 )
+{
+}
+
+TangentCurveType::~TangentCurveType()
+{
+}
+
+const TangentCurveType* TangentCurveType::instance()
+{
+ static const TangentCurveType t;
+ return &t;
+}
+
+ObjectImp* TangentCurveType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const CurveImp* curve = static_cast<const CurveImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+ if ( !curve->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ const double t = curve->getParam( p, doc );
+ const double tau0 = 1e-3;
+ const double sigma = 1e-5;
+ const int maxiter = 20;
+
+ double tau = tau0;
+ Coordinate tang, err;
+ double tplus = t + tau;
+ double tminus = t - tau;
+ if ( tplus > 1 ) {tplus = 1; tminus = 1 - 2*tau;}
+ if ( tminus < 0 ) {tminus = 0; tplus = 2*tau;}
+ Coordinate tangold = (curve->getPoint( tplus, doc ) - curve->getPoint( tminus, doc ))/(2*tau);
+
+ for (int i = 0; i < maxiter; i++)
+ {
+ tau = tau/2;
+ tplus = t + tau;
+ tminus = t - tau;
+ if ( tplus > 1 ) {tplus = 1; tminus = 1 - 2*tau;}
+ if ( tminus < 0 ) {tminus = 0; tplus = 2*tau;}
+ tang = (curve->getPoint( tplus, doc ) - curve->getPoint( tminus, doc ))/(2*tau);
+ err = (tangold - tang)/3;
+ if (err.length() < sigma)
+ {
+ tang = (4*tang - tangold)/3;
+ const LineData tangent = LineData( p, p + tang );
+ return new LineImp( tangent );
+ }
+ tangold = tang;
+ }
+ return new InvalidImp;
+}
+
+const ObjectImpType* TangentCurveType::resultId() const
+{
+ return LineImp::stype();
+}
diff --git a/kig/objects/tangent_type.h b/kig/objects/tangent_type.h
new file mode 100644
index 00000000..ccc00dea
--- /dev/null
+++ b/kig/objects/tangent_type.h
@@ -0,0 +1,83 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// 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.
+
+#ifndef KIG_OBJECTS_TANGENT_TYPE_H
+#define KIG_OBJECTS_TANGENT_TYPE_H
+
+#include "base_type.h"
+
+/**
+ * the line tangent to a generic conic
+ */
+class TangentConicType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ TangentConicType();
+ ~TangentConicType();
+public:
+ static const TangentConicType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * the line tangent to an arc
+ */
+class TangentArcType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ TangentArcType();
+ ~TangentArcType();
+public:
+ static const TangentArcType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * the line tangent to a cubic
+ */
+class TangentCubicType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ TangentCubicType();
+ ~TangentCubicType();
+public:
+ static const TangentCubicType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * the line tangent to a curve
+ */
+class TangentCurveType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ TangentCurveType();
+ ~TangentCurveType();
+public:
+ static const TangentCurveType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/tests_type.cc b/kig/objects/tests_type.cc
new file mode 100644
index 00000000..e85c111e
--- /dev/null
+++ b/kig/objects/tests_type.cc
@@ -0,0 +1,382 @@
+// Copyright (C) 2004 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 "tests_type.h"
+
+#include "line_imp.h"
+#include "polygon_imp.h"
+#include "point_imp.h"
+#include "bogus_imp.h"
+#include "other_imp.h"
+
+#include <cmath>
+
+static const ArgsParser::spec argsspecAreParallel[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Is this line parallel?" ),
+ I18N_NOOP( "Select the first of the two possibly parallel lines..." ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Parallel to this line?" ),
+ I18N_NOOP( "Select the other of the two possibly parallel lines..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( AreParallelType )
+
+AreParallelType::AreParallelType()
+ : ArgsParserObjectType( "AreParallel",
+ argsspecAreParallel, 2 )
+{
+}
+
+AreParallelType::~AreParallelType()
+{
+}
+
+const AreParallelType* AreParallelType::instance()
+{
+ static const AreParallelType t;
+ return &t;
+}
+
+ObjectImp* AreParallelType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const LineData& l1 = static_cast<const AbstractLineImp*>( parents[0] )->data();
+ const LineData& l2 = static_cast<const AbstractLineImp*>( parents[1] )->data();
+
+ if ( l1.isParallelTo( l2 ) )
+ return new TestResultImp( i18n( "These lines are parallel." ) );
+ else
+ return new TestResultImp( i18n( "These lines are not parallel." ) );
+
+}
+
+const ObjectImpType* AreParallelType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+static const ArgsParser::spec argsspecAreOrthogonal[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Is this line orthogonal?" ),
+ I18N_NOOP( "Select the first of the two possibly orthogonal lines..." ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Orthogonal to this line?" ),
+ I18N_NOOP( "Select the other of the two possibly orthogonal lines..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( AreOrthogonalType )
+
+AreOrthogonalType::AreOrthogonalType()
+ : ArgsParserObjectType( "AreOrthogonal",
+ argsspecAreOrthogonal, 2 )
+{
+}
+
+AreOrthogonalType::~AreOrthogonalType()
+{
+}
+
+const AreOrthogonalType* AreOrthogonalType::instance()
+{
+ static const AreOrthogonalType t;
+ return &t;
+}
+
+ObjectImp* AreOrthogonalType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const LineData& l1 = static_cast<const AbstractLineImp*>( parents[0] )->data();
+ const LineData& l2 = static_cast<const AbstractLineImp*>( parents[1] )->data();
+
+ if ( l1.isOrthogonalTo( l2 ) )
+ return new TestResultImp( i18n( "These lines are orthogonal." ) );
+ else
+ return new TestResultImp( i18n( "These lines are not orthogonal." ) );
+
+}
+
+const ObjectImpType* AreOrthogonalType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+static const ArgsParser::spec argsspecAreCollinear[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Check collinearity of this point" ),
+ I18N_NOOP( "Select the first of the three possibly collinear points..." ), false },
+ { PointImp::stype(), I18N_NOOP( "and this second point" ),
+ I18N_NOOP( "Select the second of the three possibly collinear points..." ), false },
+ { PointImp::stype(), I18N_NOOP( "with this third point" ),
+ I18N_NOOP( "Select the last of the three possibly collinear points..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( AreCollinearType )
+
+AreCollinearType::AreCollinearType()
+ : ArgsParserObjectType( "AreCollinear",
+ argsspecAreCollinear, 3 )
+{
+}
+
+AreCollinearType::~AreCollinearType()
+{
+}
+
+const AreCollinearType* AreCollinearType::instance()
+{
+ static const AreCollinearType t;
+ return &t;
+}
+
+ObjectImp* AreCollinearType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const Coordinate& p1 = static_cast<const PointImp*>( parents[0] )->coordinate();
+ const Coordinate& p2 = static_cast<const PointImp*>( parents[1] )->coordinate();
+ const Coordinate& p3 = static_cast<const PointImp*>( parents[2] )->coordinate();
+
+ if ( areCollinear( p1, p2, p3 ) )
+ return new TestResultImp( i18n( "These points are collinear." ) );
+ else
+ return new TestResultImp( i18n( "These points are not collinear." ) );
+}
+
+const ObjectImpType* AreCollinearType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+static const ArgsParser::spec containsTestArgsSpec[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Check whether this point is on a curve" ),
+ I18N_NOOP( "Select the point you want to test..." ), false },
+ { CurveImp::stype(), I18N_NOOP( "Check whether the point is on this curve" ),
+ I18N_NOOP( "Select the curve that the point might be on..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ContainsTestType )
+
+ContainsTestType::ContainsTestType()
+ : ArgsParserObjectType( "ContainsTest", containsTestArgsSpec, 2 )
+{
+}
+
+ContainsTestType::~ContainsTestType()
+{
+}
+
+const ContainsTestType* ContainsTestType::instance()
+{
+ static const ContainsTestType t;
+ return &t;
+}
+
+ObjectImp* ContainsTestType::calc( const Args& parents, const KigDocument& doc ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const Coordinate& p = static_cast<const PointImp*>( parents[0] )->coordinate();
+ const CurveImp* c = static_cast<const CurveImp*>( parents[1] );
+
+ if ( c->containsPoint( p, doc ) )
+ return new TestResultImp( i18n( "This curve contains the point." ) );
+ else
+ return new TestResultImp( i18n( "This curve does not contain the point." ) );
+}
+
+const ObjectImpType* ContainsTestType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+/*
+ * containment test of a point in a polygon
+ */
+
+static const ArgsParser::spec InPolygonTestArgsSpec[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Check whether this point is in a polygon" ),
+ I18N_NOOP( "Select the point you want to test..." ), false },
+ { PolygonImp::stype(), I18N_NOOP( "Check whether the point is in this polygon" ),
+ I18N_NOOP( "Select the polygon that the point might be in..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InPolygonTestType )
+
+InPolygonTestType::InPolygonTestType()
+ : ArgsParserObjectType( "InPolygonTest", InPolygonTestArgsSpec, 2 )
+{
+}
+
+InPolygonTestType::~InPolygonTestType()
+{
+}
+
+const InPolygonTestType* InPolygonTestType::instance()
+{
+ static const InPolygonTestType t;
+ return &t;
+}
+
+ObjectImp* InPolygonTestType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const Coordinate& p = static_cast<const PointImp*>( parents[0] )->coordinate();
+ const PolygonImp* pol = static_cast<const PolygonImp*>( parents[1] );
+
+ if ( pol->isInPolygon( p ) )
+ return new TestResultImp( i18n( "This polygon contains the point." ) );
+ else
+ return new TestResultImp( i18n( "This polygon does not contain the point." ) );
+}
+
+const ObjectImpType* InPolygonTestType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+/*
+ * test if a polygon is convex
+ */
+
+static const ArgsParser::spec ConvexPolygonTestArgsSpec[] =
+{
+ { PolygonImp::stype(), I18N_NOOP( "Check whether this polygon is convex" ),
+ I18N_NOOP( "Select the polygon you want to test for convexity..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConvexPolygonTestType )
+
+ConvexPolygonTestType::ConvexPolygonTestType()
+ : ArgsParserObjectType( "ConvexPolygonTest", ConvexPolygonTestArgsSpec, 1 )
+{
+}
+
+ConvexPolygonTestType::~ConvexPolygonTestType()
+{
+}
+
+const ConvexPolygonTestType* ConvexPolygonTestType::instance()
+{
+ static const ConvexPolygonTestType t;
+ return &t;
+}
+
+ObjectImp* ConvexPolygonTestType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const PolygonImp* pol = static_cast<const PolygonImp*>( parents[0] );
+
+ if ( pol->isConvex() )
+ return new TestResultImp( i18n( "This polygon is convex." ) );
+ else
+ return new TestResultImp( i18n( "This polygon is not convex." ) );
+}
+
+const ObjectImpType* ConvexPolygonTestType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+/*
+ * same distance test
+ */
+
+static const ArgsParser::spec argsspecSameDistanceType[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Check if this point has the same distance" ),
+ I18N_NOOP( "Select the point which might have the same distance from two other points..." ), false },
+ { PointImp::stype(), I18N_NOOP( "from this point" ),
+ I18N_NOOP( "Select the first of the two other points..." ), false },
+ { PointImp::stype(), I18N_NOOP( "and from this second point" ),
+ I18N_NOOP( "Select the other of the two other points..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( SameDistanceType )
+
+SameDistanceType::SameDistanceType()
+ : ArgsParserObjectType( "SameDistanceType", argsspecSameDistanceType, 3 )
+{
+}
+
+SameDistanceType::~SameDistanceType()
+{
+}
+
+const SameDistanceType* SameDistanceType::instance()
+{
+ static const SameDistanceType t;
+ return &t;
+}
+
+ObjectImp* SameDistanceType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const Coordinate& p1 = static_cast<const PointImp*>( parents[0] )->coordinate();
+ const Coordinate& p2 = static_cast<const PointImp*>( parents[1] )->coordinate();
+ const Coordinate& p3 = static_cast<const PointImp*>( parents[2] )->coordinate();
+
+ if ( fabs( ( p1 - p2 ).length() - ( p1 - p3 ).length() ) < 10e-5 )
+ return new TestResultImp( i18n( "The two distances are the same." ) );
+ else
+ return new TestResultImp( i18n( "The two distances are not the same." ) );
+}
+
+const ObjectImpType* SameDistanceType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+static const ArgsParser::spec vectorEqualityArgsSpec[] =
+{
+ { VectorImp::stype(), I18N_NOOP( "Check whether this vector is equal to another vector" ),
+ I18N_NOOP( "Select the first of the two possibly equal vectors..." ), false },
+ { VectorImp::stype(), I18N_NOOP( "Check whether this vector is equal to the other vector" ),
+ I18N_NOOP( "Select the other of the two possibly equal vectors..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( VectorEqualityTestType )
+
+VectorEqualityTestType::VectorEqualityTestType()
+ : ArgsParserObjectType( "VectorEquality", vectorEqualityArgsSpec, 2 )
+{
+}
+
+VectorEqualityTestType::~VectorEqualityTestType()
+{
+}
+
+const VectorEqualityTestType* VectorEqualityTestType::instance()
+{
+ static const VectorEqualityTestType t;
+ return &t;
+}
+
+ObjectImp* VectorEqualityTestType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const Coordinate& v1 = static_cast<const VectorImp*>( parents[0] )->dir();
+ const Coordinate& v2 = static_cast<const VectorImp*>( parents[1] )->dir();
+
+ if ( ( v1 - v2 ).length() < 10e-5 )
+ return new TestResultImp( i18n( "The two vectors are the same." ) );
+ else
+ return new TestResultImp( i18n( "The two vectors are not the same." ) );
+}
+
+const ObjectImpType* VectorEqualityTestType::resultId() const
+{
+ return TestResultImp::stype();
+}
diff --git a/kig/objects/tests_type.h b/kig/objects/tests_type.h
new file mode 100644
index 00000000..7498fc4f
--- /dev/null
+++ b/kig/objects/tests_type.h
@@ -0,0 +1,111 @@
+// Copyright (C) 2004 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.
+
+#ifndef KIG_OBJECTS_TESTS_TYPE_H
+#define KIG_OBJECTS_TESTS_TYPE_H
+
+#include "base_type.h"
+
+class AreParallelType
+ : public ArgsParserObjectType
+{
+ AreParallelType();
+ ~AreParallelType();
+public:
+ static const AreParallelType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class AreOrthogonalType
+ : public ArgsParserObjectType
+{
+ AreOrthogonalType();
+ ~AreOrthogonalType();
+public:
+ static const AreOrthogonalType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class AreCollinearType
+ : public ArgsParserObjectType
+{
+ AreCollinearType();
+ ~AreCollinearType();
+public:
+ static const AreCollinearType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ContainsTestType
+ : public ArgsParserObjectType
+{
+ ContainsTestType();
+ ~ContainsTestType();
+public:
+ static const ContainsTestType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class InPolygonTestType
+ : public ArgsParserObjectType
+{
+ InPolygonTestType();
+ ~InPolygonTestType();
+public:
+ static const InPolygonTestType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConvexPolygonTestType
+ : public ArgsParserObjectType
+{
+ ConvexPolygonTestType();
+ ~ConvexPolygonTestType();
+public:
+ static const ConvexPolygonTestType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class SameDistanceType
+ : public ArgsParserObjectType
+{
+ SameDistanceType();
+ ~SameDistanceType();
+public:
+ static const SameDistanceType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class VectorEqualityTestType
+ : public ArgsParserObjectType
+{
+ VectorEqualityTestType();
+ ~VectorEqualityTestType();
+public:
+ static const VectorEqualityTestType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/text_imp.cc b/kig/objects/text_imp.cc
new file mode 100644
index 00000000..f7b2f1be
--- /dev/null
+++ b/kig/objects/text_imp.cc
@@ -0,0 +1,173 @@
+// 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 "text_imp.h"
+
+#include "bogus_imp.h"
+#include "../misc/kigpainter.h"
+
+TextImp::TextImp( const QString& text, const Coordinate& loc, bool frame )
+ : mtext( text), mloc( loc ), mframe( frame ), mboundrect( Rect::invalidRect() )
+{
+}
+
+TextImp* TextImp::copy() const
+{
+ return new TextImp( mtext, mloc );
+}
+
+TextImp::~TextImp()
+{
+}
+
+Coordinate TextImp::attachPoint() const
+{
+ return Coordinate::invalidCoord();
+}
+
+ObjectImp* TextImp::transform( const Transformation& t ) const
+{
+ Coordinate nloc = t.apply( mloc );
+ return new TextImp( mtext, nloc, mframe );
+}
+
+void TextImp::draw( KigPainter& p ) const
+{
+ mboundrect = p.simpleBoundingRect( mloc, mtext );
+ p.drawTextFrame( mboundrect, mtext, mframe );
+}
+
+bool TextImp::contains( const Coordinate& p, int, const KigWidget& ) const
+{
+ return mboundrect.contains( p );
+}
+
+bool TextImp::inRect( const Rect& r, int, const KigWidget& ) const
+{
+ return mboundrect.intersects( r );
+}
+
+bool TextImp::valid() const
+{
+ return true;
+}
+
+const uint TextImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 1;
+}
+
+const QCStringList TextImp::propertiesInternalNames() const
+{
+ QCStringList ret = Parent::propertiesInternalNames();
+ ret << "kig_text";
+ return ret;
+}
+
+const QCStringList TextImp::properties() const
+{
+ QCStringList ret = Parent::properties();
+ ret << I18N_NOOP( "Text" );
+ return ret;
+}
+
+const ObjectImpType* TextImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ return TextImp::stype();
+}
+
+const char* TextImp::iconForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ else if ( which == Parent::numberOfProperties() )
+ return "text"; // text
+ else assert( false );
+ return "";
+}
+
+ObjectImp* TextImp::property( uint which, const KigDocument& w ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ else if ( which == Parent::numberOfProperties() )
+ return new StringImp( text() );
+ else assert( false );
+ return new InvalidImp;
+}
+
+QString TextImp::text() const
+{
+ return mtext;
+}
+
+void TextImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+const Coordinate TextImp::coordinate() const
+{
+ return mloc;
+}
+
+bool TextImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( TextImp::stype() ) &&
+ static_cast<const TextImp&>( rhs ).coordinate() == coordinate() &&
+ static_cast<const TextImp&>( rhs ).text() == text() &&
+ static_cast<const TextImp&>( rhs ).hasFrame() == hasFrame();
+}
+
+bool TextImp::hasFrame() const
+{
+ return mframe;
+}
+
+const ObjectImpType* TextImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "label",
+ I18N_NOOP( "label" ),
+ I18N_NOOP( "Select this label" ),
+ I18N_NOOP( "Select label %1" ),
+ I18N_NOOP( "Remove a Label" ),
+ I18N_NOOP( "Add a Label" ),
+ I18N_NOOP( "Move a Label" ),
+ I18N_NOOP( "Attach to this label" ),
+ I18N_NOOP( "Show a Label" ),
+ I18N_NOOP( "Hide a Label" )
+ );
+ return &t;
+}
+
+const ObjectImpType* TextImp::type() const
+{
+ return TextImp::stype();
+}
+
+bool TextImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+}
+
+Rect TextImp::surroundingRect() const
+{
+ return mboundrect;
+}
diff --git a/kig/objects/text_imp.h b/kig/objects/text_imp.h
new file mode 100644
index 00000000..8ad92b84
--- /dev/null
+++ b/kig/objects/text_imp.h
@@ -0,0 +1,70 @@
+// 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.
+
+#ifndef KIG_OBJECTS_TEXT_IMP_H
+#define KIG_OBJECTS_TEXT_IMP_H
+
+#include "object_imp.h"
+
+#include "../misc/coordinate.h"
+#include "../misc/rect.h"
+
+class TextImp
+ : public ObjectImp
+{
+ QString mtext;
+ Coordinate mloc;
+ bool mframe;
+ // with this var, we keep track of the place we drew in, for use in
+ // the contains() function..
+ mutable Rect mboundrect;
+public:
+ typedef ObjectImp Parent;
+ static const ObjectImpType* stype();
+
+ Coordinate attachPoint() const;
+ TextImp( const QString& text, const Coordinate& loc, bool frame = false );
+ TextImp* copy() const;
+ ~TextImp();
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ bool valid() const;
+ Rect surroundingRect() const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ QString text() const;
+ const Coordinate coordinate() const;
+ bool hasFrame() const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+#endif
diff --git a/kig/objects/text_type.cc b/kig/objects/text_type.cc
new file mode 100644
index 00000000..6594c05a
--- /dev/null
+++ b/kig/objects/text_type.cc
@@ -0,0 +1,215 @@
+// 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 "text_type.h"
+
+#include "text_imp.h"
+#include "bogus_imp.h"
+#include "point_imp.h"
+#include "line_imp.h"
+
+#include "../kig/kig_view.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_commands.h"
+#include "../modes/label.h"
+#include "../misc/coordinate_system.h"
+
+#include <algorithm>
+
+#include <qclipboard.h>
+#include <qstringlist.h>
+
+#include <kapplication.h>
+
+#include <cmath>
+
+static const ArgsParser::spec arggspeccs[] =
+{
+ { IntImp::stype(), "UNUSED", "SHOULD NOT BE SEEN", false },
+ { PointImp::stype(), "UNUSED", "SHOULD NOT BE SEEN", false },
+ { StringImp::stype(), "UNUSED", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TextType )
+
+TextType::TextType()
+ : ObjectType( "Label" ), mparser( arggspeccs, 3 )
+{
+}
+
+TextType::~TextType()
+{
+}
+
+const TextType* TextType::instance()
+{
+ static const TextType t;
+ return &t;
+}
+
+const ObjectImpType* TextType::resultId() const
+{
+ return TextImp::stype();
+}
+
+const ObjectImpType* TextType::impRequirement( const ObjectImp* o, const Args& args ) const
+{
+ assert( args.size() >= 3 );
+ Args firstthree( args.begin(), args.begin() + 3 );
+ if ( o == args[0] || o == args[1] || o == args[2] )
+ return mparser.impRequirement( o, firstthree );
+ else
+ return ObjectImp::stype();
+}
+
+ObjectImp* TextType::calc( const Args& parents, const KigDocument& doc ) const
+{
+ if( parents.size() < 3 ) return new InvalidImp;
+ Args firstthree( parents.begin(), parents.begin() + 3 );
+ Args varargs( parents.begin() + 3, parents.end() );
+
+ if ( ! mparser.checkArgs( firstthree ) ) return new InvalidImp;
+
+ int frame = static_cast<const IntImp*>( firstthree[0] )->data();
+ bool needframe = frame != 0;
+ const Coordinate t = static_cast<const PointImp*>( firstthree[1] )->coordinate();
+ QString s = static_cast<const StringImp*>( firstthree[2] )->data();
+
+ for ( Args::iterator i = varargs.begin(); i != varargs.end(); ++i )
+ (*i)->fillInNextEscape( s, doc );
+
+ return new TextImp( s, t, needframe );
+}
+
+bool TextType::canMove( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+bool TextType::isFreelyTranslatable( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+void TextType::move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& d ) const
+{
+ const std::vector<ObjectCalcer*> parents = ourobj.parents();
+ assert( parents.size() >= 3 );
+ const std::vector<ObjectCalcer*> firstthree( parents.begin(), parents.begin() + 3 );
+ if( dynamic_cast<ObjectConstCalcer*>( firstthree[1] ) )
+ {
+ ObjectConstCalcer* c = static_cast<ObjectConstCalcer*>( firstthree[1] );
+ c->setImp( new PointImp( to ) );
+ }
+ else
+ firstthree[1]->move( to, d );
+}
+
+QStringList TextType::specialActions() const
+{
+ QStringList ret;
+ ret << i18n( "&Copy Text" );
+ ret << i18n( "&Toggle Frame" );
+ ret << i18n( "&Redefine..." );
+ return ret;
+}
+
+void TextType::executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& c,
+ KigPart& doc, KigWidget&,
+ NormalMode& ) const
+{
+ std::vector<ObjectCalcer*> parents = c.parents();
+ assert( parents.size() >= 3 );
+
+ std::vector<ObjectCalcer*> firstthree( parents.begin(), parents.begin() + 3 );
+
+ assert( mparser.checkArgs( firstthree ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( firstthree[0] ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( firstthree[2] ) );
+
+ if ( i == 0 )
+ {
+ QClipboard* cb = kapp->clipboard();
+
+ // copy the text into the clipboard
+ const TextImp* ti = static_cast<const TextImp*>( c.imp() );
+ cb->setText( ti->text(), QClipboard::Clipboard );
+ }
+ else if ( i == 1 )
+ {
+ // toggle label frame
+ int n = (static_cast<const IntImp*>( firstthree[0]->imp() )->data() + 1) % 2;
+ KigCommand* kc = new KigCommand( doc, i18n( "Toggle Label Frame" ) );
+ kc->addTask( new ChangeObjectConstCalcerTask(
+ static_cast<ObjectConstCalcer*>( firstthree[0] ),
+ new IntImp( n ) ) );
+ doc.history()->addCommand( kc );
+ }
+ else if ( i == 2 )
+ {
+ assert( dynamic_cast<ObjectTypeCalcer*>( o.calcer() ) );
+ // redefine..
+ TextLabelRedefineMode m( doc, static_cast<ObjectTypeCalcer*>( o.calcer() ) );
+ doc.runMode( &m );
+ }
+ else assert( false );
+}
+
+const ArgsParser& TextType::argParser() const
+{
+ return mparser;
+}
+
+const Coordinate TextType::moveReferencePoint( const ObjectTypeCalcer& ourobj ) const
+{
+ assert( ourobj.imp()->inherits( TextImp::stype() ) );
+ return static_cast<const TextImp*>( ourobj.imp() )->coordinate();
+}
+
+std::vector<ObjectCalcer*> TextType::sortArgs( const std::vector<ObjectCalcer*>& os ) const
+{
+ assert( os.size() >= 3 );
+ std::vector<ObjectCalcer*> ret( os.begin(), os.begin() + 3 );
+ ret = mparser.parse( ret );
+ std::copy( os.begin() + 3, os.end(), std::back_inserter( ret ) );
+ return ret;
+}
+
+Args TextType::sortArgs( const Args& args ) const
+{
+ assert( args.size() >= 3 );
+ Args ret( args.begin(), args.begin() + 3 );
+ ret = mparser.parse( ret );
+ std::copy( args.begin() + 3, args.end(), std::back_inserter( ret ) );
+ return ret;
+}
+
+std::vector<ObjectCalcer*> TextType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ const std::vector<ObjectCalcer*> parents = ourobj.parents();
+ assert( parents.size() >= 3 );
+ std::vector<ObjectCalcer*> ret = parents[1]->movableParents();
+ ret.push_back( parents[1] );
+ return ret;
+}
+
+bool TextType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
+{
+ return false;
+}
+
diff --git a/kig/objects/text_type.h b/kig/objects/text_type.h
new file mode 100644
index 00000000..6368cafa
--- /dev/null
+++ b/kig/objects/text_type.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef KIG_OBJECTS_TEXT_TYPE_H
+#define KIG_OBJECTS_TEXT_TYPE_H
+
+#include "object_type.h"
+
+class TextType
+ : public ObjectType
+{
+ const ArgsParser mparser;
+ TextType();
+ ~TextType();
+public:
+ static const TextType* instance();
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ const ObjectImpType* resultId() const;
+
+ ObjectImp* calc( const Args& parents, const KigDocument& d ) const;
+
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& os ) const;
+ Args sortArgs( const Args& args ) const;
+
+ bool canMove( const ObjectTypeCalcer& ourobj ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& ourobj ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const;
+
+ QStringList specialActions() const;
+ void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& c,
+ KigPart& d, KigWidget& w, NormalMode& m ) const;
+
+ const ArgsParser& argParser() const;
+};
+
+#endif
diff --git a/kig/objects/transform_types.cc b/kig/objects/transform_types.cc
new file mode 100644
index 00000000..3a8d32db
--- /dev/null
+++ b/kig/objects/transform_types.cc
@@ -0,0 +1,874 @@
+// 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 "transform_types.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+#include "line_imp.h"
+#include "other_imp.h"
+#include "polygon_imp.h"
+#include "../misc/coordinate.h"
+#include "../misc/kigtransform.h"
+
+#include <cmath>
+
+static const ArgsParser::spec argsspecTranslation[] =
+{
+ { ObjectImp::stype(), I18N_NOOP("Translate this object"),
+ I18N_NOOP( "Select the object to translate..." ), false },
+ { VectorImp::stype(), I18N_NOOP("Translate by this vector"),
+ I18N_NOOP( "Select the vector to translate by..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TranslatedType )
+
+TranslatedType::TranslatedType()
+ : ArgsParserObjectType( "Translation", argsspecTranslation, 2 )
+{
+}
+
+TranslatedType::~TranslatedType()
+{
+}
+
+const TranslatedType* TranslatedType::instance()
+{
+ static const TranslatedType t;
+ return &t;
+}
+
+ObjectImp* TranslatedType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate dir = static_cast<const VectorImp*>( args[1] )->dir();
+ Transformation t = Transformation::translation( dir );
+
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecPointReflection[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Reflect this object" ),
+ I18N_NOOP( "Select the object to reflect..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Reflect in this point" ),
+ I18N_NOOP( "Select the point to reflect in..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PointReflectionType )
+
+PointReflectionType::PointReflectionType()
+ : ArgsParserObjectType( "PointReflection", argsspecPointReflection, 2 )
+{
+}
+
+PointReflectionType::~PointReflectionType()
+{
+}
+
+const PointReflectionType* PointReflectionType::instance()
+{
+ static const PointReflectionType t;
+ return &t;
+}
+
+ObjectImp* PointReflectionType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate center = static_cast<const PointImp*>( args[1] )->coordinate();
+ Transformation t = Transformation::pointReflection( center );
+
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecLineReflection[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Reflect this object" ),
+ I18N_NOOP( "Select the object to reflect..." ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Reflect in this line" ),
+ I18N_NOOP( "Select the line to reflect in..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LineReflectionType )
+
+LineReflectionType::LineReflectionType()
+ : ArgsParserObjectType( "LineReflection", argsspecLineReflection, 2 )
+{
+}
+
+LineReflectionType::~LineReflectionType()
+{
+}
+
+const LineReflectionType* LineReflectionType::instance()
+{
+ static const LineReflectionType t;
+ return &t;
+}
+
+ObjectImp* LineReflectionType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ LineData d = static_cast<const AbstractLineImp*>( args[1] )->data();
+ Transformation t = Transformation::lineReflection( d );
+
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecRotation[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Rotate this object" ),
+ I18N_NOOP( "Select the object to rotate..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Rotate around this point" ),
+ I18N_NOOP( "Select the center point of the rotation..." ), false },
+ { AngleImp::stype(), I18N_NOOP( "Rotate by this angle" ),
+ I18N_NOOP( "Select the angle of the rotation..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( RotationType )
+
+RotationType::RotationType()
+ : ArgsParserObjectType( "Rotation", argsspecRotation, 3 )
+{
+}
+
+RotationType::~RotationType()
+{
+}
+
+const RotationType* RotationType::instance()
+{
+ static const RotationType t;
+ return &t;
+}
+
+ObjectImp* RotationType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate center = static_cast<const PointImp*>( args[1] )->coordinate();
+ double angle = static_cast<const AngleImp*>( args[2] )->size();
+
+ return args[0]->transform( Transformation::rotation( angle, center ) );
+}
+
+static const ArgsParser::spec argsspecScalingOverCenter[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Scale this object" ),
+ I18N_NOOP( "Select the object to scale..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Scale with this center" ),
+ I18N_NOOP( "Select the center point of the scaling..." ), false },
+ { SegmentImp::stype(), I18N_NOOP( "Scale by the length of this segment" ),
+ I18N_NOOP( "Select a segment whose length is the factor of the scaling..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ScalingOverCenterType )
+
+ScalingOverCenterType::ScalingOverCenterType()
+ : ArgsParserObjectType( "ScalingOverCenter", argsspecScalingOverCenter, 3 )
+{
+}
+
+ScalingOverCenterType::~ScalingOverCenterType()
+{
+}
+
+const ScalingOverCenterType* ScalingOverCenterType::instance()
+{
+ static const ScalingOverCenterType t;
+ return &t;
+}
+
+ObjectImp* ScalingOverCenterType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate center = static_cast<const PointImp*>( args[1] )->coordinate();
+ double ratio = static_cast<const SegmentImp*>( args[2] )->length();
+
+ return args[0]->transform( Transformation::scalingOverPoint( ratio, center ) );
+}
+
+static const ArgsParser::spec argsspecScalingOverCenter2[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Scale this object" ),
+ I18N_NOOP( "Select the object to scale..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Scale with this center" ),
+ I18N_NOOP( "Select the center point of the scaling..." ), false },
+ { SegmentImp::stype(), I18N_NOOP( "Scale the length of this segment..." ),
+ I18N_NOOP( "Select the first of two segments whose ratio is the factor of the scaling..." ), false },
+ { SegmentImp::stype(), I18N_NOOP( "...to the length of this other segment" ),
+ I18N_NOOP( "Select the second of two segments whose ratio is the factor of the scaling..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ScalingOverCenter2Type )
+
+ScalingOverCenter2Type::ScalingOverCenter2Type()
+ : ArgsParserObjectType( "ScalingOverCenter2", argsspecScalingOverCenter2, 4 )
+{
+}
+
+ScalingOverCenter2Type::~ScalingOverCenter2Type()
+{
+}
+
+const ScalingOverCenter2Type* ScalingOverCenter2Type::instance()
+{
+ static const ScalingOverCenter2Type t;
+ return &t;
+}
+
+ObjectImp* ScalingOverCenter2Type::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate center = static_cast<const PointImp*>( args[1] )->coordinate();
+ double ratio = static_cast<const SegmentImp*>( args[3] )->length()/
+ static_cast<const SegmentImp*>( args[2] )->length();
+
+ return args[0]->transform( Transformation::scalingOverPoint( ratio, center ) );
+}
+
+static const ArgsParser::spec argsspecScalingOverLine[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Scale this object" ), I18N_NOOP( "Select the object to scale" ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Scale over this line" ), I18N_NOOP( "Select the line to scale over" ), false },
+ { SegmentImp::stype(), I18N_NOOP( "Scale by the length of this segment" ), I18N_NOOP( "Select a segment whose length is the factor for the scaling" ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ScalingOverLineType )
+
+ScalingOverLineType::ScalingOverLineType()
+ : ArgsParserObjectType( "ScalingOverLine", argsspecScalingOverLine, 3 )
+{
+}
+
+ScalingOverLineType::~ScalingOverLineType()
+{
+}
+
+const ScalingOverLineType* ScalingOverLineType::instance()
+{
+ static const ScalingOverLineType t;
+ return &t;
+}
+
+ObjectImp* ScalingOverLineType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ LineData line = static_cast<const AbstractLineImp*>( args[1] )->data();
+ double ratio = static_cast<const SegmentImp*>( args[2] )->length();
+
+ return args[0]->transform( Transformation::scalingOverLine( ratio, line ) );
+}
+
+static const ArgsParser::spec argsspecScalingOverLine2[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Scale this object" ), I18N_NOOP( "Select the object to scale" ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Scale over this line" ), I18N_NOOP( "Select the line to scale over" ), false },
+ { SegmentImp::stype(), I18N_NOOP( "Scale the length of this segment..." ), I18N_NOOP( "Select the first of two segments whose ratio is the factor for the scaling" ), false },
+ { SegmentImp::stype(), I18N_NOOP( "...to the length of this segment" ), I18N_NOOP( "Select the second of two segments whose ratio is the factor for the scaling" ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ScalingOverLine2Type )
+
+ScalingOverLine2Type::ScalingOverLine2Type()
+ : ArgsParserObjectType( "ScalingOverLine2", argsspecScalingOverLine2, 4 )
+{
+}
+
+ScalingOverLine2Type::~ScalingOverLine2Type()
+{
+}
+
+const ScalingOverLine2Type* ScalingOverLine2Type::instance()
+{
+ static const ScalingOverLine2Type t;
+ return &t;
+}
+
+ObjectImp* ScalingOverLine2Type::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ LineData line = static_cast<const AbstractLineImp*>( args[1] )->data();
+ double ratio = static_cast<const SegmentImp*>( args[3] )->length()/
+ static_cast<const SegmentImp*>( args[2] )->length();
+
+ return args[0]->transform( Transformation::scalingOverLine( ratio, line ) );
+}
+
+static const ArgsParser::spec argsspecProjectiveRotation[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Projectively rotate this object" ), I18N_NOOP( "Select the object to rotate projectively" ), false },
+ { RayImp::stype(), I18N_NOOP( "Projectively rotate with this half-line" ), I18N_NOOP( "Select the half line of the projective rotation that you want to apply to the object" ), false },
+ { AngleImp::stype(), I18N_NOOP( "Projectively rotate by this angle" ), I18N_NOOP( "Select the angle of the projective rotation that you want to apply to the object" ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ProjectiveRotationType )
+
+ProjectiveRotationType::ProjectiveRotationType()
+ : ArgsParserObjectType( "ProjectiveRotation", argsspecProjectiveRotation, 3 )
+{
+}
+
+ProjectiveRotationType::~ProjectiveRotationType()
+{
+}
+
+const ProjectiveRotationType* ProjectiveRotationType::instance()
+{
+ static const ProjectiveRotationType t;
+ return &t;
+}
+
+ObjectImp* ProjectiveRotationType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const RayImp* ray = static_cast<const RayImp*>( args[1] );
+ Coordinate c1 = ray->data().a;
+ Coordinate dir = ray->data().dir().normalize();
+ double alpha = static_cast<const AngleImp*>( args[2] )->size();
+
+ return args[0]->transform(
+ Transformation::projectiveRotation( alpha, dir, c1 ) );
+}
+
+static const ArgsParser::spec argsspecHarmonicHomology[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Harmonic Homology of this object" ),
+ I18N_NOOP( "Select the object to transform..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Harmonic Homology with this center" ),
+ I18N_NOOP( "Select the center point of the harmonic homology..." ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Harmonic Homology with this axis" ),
+ I18N_NOOP( "Select the axis of the harmonic homology..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( HarmonicHomologyType )
+
+HarmonicHomologyType::HarmonicHomologyType()
+ : ArgsParserObjectType( "HarmonicHomology", argsspecHarmonicHomology, 3 )
+{
+}
+
+HarmonicHomologyType::~HarmonicHomologyType()
+{
+}
+
+const HarmonicHomologyType* HarmonicHomologyType::instance()
+{
+ static const HarmonicHomologyType t;
+ return &t;
+}
+
+ObjectImp* HarmonicHomologyType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate center = static_cast<const PointImp*>( args[1] )->coordinate();
+ LineData axis = static_cast<const AbstractLineImp*>( args[2] )->data();
+ return args[0]->transform(
+ Transformation::harmonicHomology( center, axis ) );
+}
+
+static const ArgsParser::spec argsspecAffinityB2Tr[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Generic affinity of this object" ),
+ I18N_NOOP( "Select the object to transform..." ), false },
+ { PolygonImp::stype3(), I18N_NOOP( "Map this triangle" ),
+ I18N_NOOP( "Select the triangle that has to be transformed onto a given triangle..." ), false },
+ { PolygonImp::stype3(), I18N_NOOP( "onto this other triangle" ),
+ I18N_NOOP( "Select the triangle that is the image by the affinity of the first triangle..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( AffinityB2TrType )
+
+AffinityB2TrType::AffinityB2TrType()
+ : ArgsParserObjectType( "AffinityB2Tr", argsspecAffinityB2Tr, 3 )
+{
+}
+
+AffinityB2TrType::~AffinityB2TrType()
+{
+}
+
+const AffinityB2TrType* AffinityB2TrType::instance()
+{
+ static const AffinityB2TrType t;
+ return &t;
+}
+
+ObjectImp* AffinityB2TrType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ std::vector<Coordinate> frompoints = static_cast<const PolygonImp*>( args[1] )->points();
+ std::vector<Coordinate> topoints = static_cast<const PolygonImp*>( args[2] )->points();
+
+ bool valid = true;
+ Transformation t = Transformation::affinityGI3P( frompoints, topoints,
+ valid );
+
+ if (valid == false) return new InvalidImp;
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecAffinityGI3P[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Generic affinity of this object" ),
+ I18N_NOOP( "Select the object to transform..." ), false },
+ { PointImp::stype(), I18N_NOOP( "First of 3 starting points" ),
+ I18N_NOOP( "Select the first of the three starting points of the generic affinity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Second of 3 starting points" ),
+ I18N_NOOP( "Select the second of the three starting points of the generic affinity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Third of 3 starting points" ),
+ I18N_NOOP( "Select the third of the three starting points of the generic affinity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of first point" ),
+ I18N_NOOP( "Select the first of the three end points of the generic affinity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of second point" ),
+ I18N_NOOP( "Select the second of the three end points of the generic affinity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of third point" ),
+ I18N_NOOP( "Select the third of the three end points of the generic affinity..." ), false },
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( AffinityGI3PType )
+
+AffinityGI3PType::AffinityGI3PType()
+ : ArgsParserObjectType( "AffinityGI3P", argsspecAffinityGI3P, 7 )
+{
+}
+
+AffinityGI3PType::~AffinityGI3PType()
+{
+}
+
+const AffinityGI3PType* AffinityGI3PType::instance()
+{
+ static const AffinityGI3PType t;
+ return &t;
+}
+
+ObjectImp* AffinityGI3PType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ std::vector<Coordinate> frompoints;
+ std::vector<Coordinate> topoints;
+ for ( uint i = 0; i < 3; ++i )
+ {
+ frompoints.push_back(
+ static_cast<const PointImp*>( args[i+1] )->coordinate() );
+ topoints.push_back(
+ static_cast<const PointImp*>( args[i+4] )->coordinate() );
+ }
+
+ bool valid = true;
+ Transformation t = Transformation::affinityGI3P( frompoints, topoints,
+ valid );
+
+ if (valid == false) return new InvalidImp;
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecProjectivityB2Qu[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Generic projective transformation of this object" ),
+ I18N_NOOP( "Select the object to transform..." ), false },
+ { PolygonImp::stype4(), I18N_NOOP( "Map this quadrilateral" ),
+ I18N_NOOP( "Select the quadrilateral that has to be transformed onto a given quadrilateral..." ), false },
+ { PolygonImp::stype4(), I18N_NOOP( "onto this other quadrilateral" ),
+ I18N_NOOP( "Select the quadrilateral that is the image by the projective transformation of the first quadrilateral..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ProjectivityB2QuType )
+
+ProjectivityB2QuType::ProjectivityB2QuType()
+ : ArgsParserObjectType( "ProjectivityB2Qu", argsspecProjectivityB2Qu, 3 )
+{
+}
+
+ProjectivityB2QuType::~ProjectivityB2QuType()
+{
+}
+
+const ProjectivityB2QuType* ProjectivityB2QuType::instance()
+{
+ static const ProjectivityB2QuType t;
+ return &t;
+}
+
+ObjectImp* ProjectivityB2QuType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ std::vector<Coordinate> frompoints = static_cast<const PolygonImp*>( args[1] )->points();
+ std::vector<Coordinate> topoints = static_cast<const PolygonImp*>( args[2] )->points();
+
+ bool valid = true;
+ Transformation t = Transformation::projectivityGI4P( frompoints, topoints,
+ valid );
+
+ if (valid == false) return new InvalidImp;
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecProjectivityGI4P[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Generic projective transformation of this object" ),
+ I18N_NOOP( "Select the object to transform..." ), false },
+ { PointImp::stype(), I18N_NOOP( "First of 4 starting points" ),
+ I18N_NOOP( "Select the first of the four starting points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Second of 4 starting points" ),
+ I18N_NOOP( "Select the second of the four starting points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Third of 4 starting points" ),
+ I18N_NOOP( "Select the third of the four starting points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Fourth of 4 starting points" ),
+ I18N_NOOP( "Select the fourth of the four starting points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of first point" ),
+ I18N_NOOP( "Select the first of the four end points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of second point" ),
+ I18N_NOOP( "Select the second of the four end points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of third point" ),
+ I18N_NOOP( "Select the third of the four end points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of fourth point" ),
+ I18N_NOOP( "Select the fourth of the four end points of the generic projectivity..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ProjectivityGI4PType )
+
+ProjectivityGI4PType::ProjectivityGI4PType()
+ : ArgsParserObjectType( "ProjectivityGI4P", argsspecProjectivityGI4P, 9 )
+{
+}
+
+ProjectivityGI4PType::~ProjectivityGI4PType()
+{
+}
+
+const ProjectivityGI4PType* ProjectivityGI4PType::instance()
+{
+ static const ProjectivityGI4PType t;
+ return &t;
+}
+
+ObjectImp* ProjectivityGI4PType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ std::vector<Coordinate> frompoints;
+ std::vector<Coordinate> topoints;
+ for ( uint i = 0; i < 4; ++i )
+ {
+ frompoints.push_back(
+ static_cast<const PointImp*>( args[i+1] )->coordinate() );
+ topoints.push_back(
+ static_cast<const PointImp*>( args[i+5] )->coordinate() );
+ }
+
+ bool valid = true;
+ Transformation t = Transformation::projectivityGI4P( frompoints, topoints,
+ valid );
+
+ if (valid == false) return new InvalidImp;
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecCastShadow[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Cast the shadow of this object" ),
+ I18N_NOOP( "Select the object of which you want to construct the shadow..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Cast a shadow from this light source" ),
+ I18N_NOOP( "Select the light source from which the shadow should originate..." ), false },
+ { AbstractLineImp::stype(),
+ I18N_NOOP( "Cast a shadow on the horizon represented by this line" ),
+ I18N_NOOP( "Select the horizon for the shadow..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CastShadowType )
+
+CastShadowType::CastShadowType()
+ : ArgsParserObjectType( "CastShadow", argsspecCastShadow, 3 )
+{
+}
+
+CastShadowType::~CastShadowType()
+{
+}
+
+const CastShadowType* CastShadowType::instance()
+{
+ static const CastShadowType t;
+ return &t;
+}
+
+ObjectImp* CastShadowType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate lightsrc = static_cast<const PointImp*>( args[1] )->coordinate();
+ LineData d = static_cast<const AbstractLineImp*>( args[2] )->data();
+ return args[0]->transform(
+ Transformation::castShadow( lightsrc, d ) );
+}
+
+const ObjectImpType* TranslatedType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* PointReflectionType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* LineReflectionType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* RotationType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ScalingOverCenterType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ScalingOverCenter2Type::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ScalingOverLineType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ScalingOverLine2Type::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ProjectiveRotationType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* HarmonicHomologyType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* AffinityB2TrType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* AffinityGI3PType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ProjectivityB2QuType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ProjectivityGI4PType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* CastShadowType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+bool TranslatedType::isTransform() const
+{
+ return true;
+}
+
+bool PointReflectionType::isTransform() const
+{
+ return true;
+}
+
+bool LineReflectionType::isTransform() const
+{
+ return true;
+}
+
+bool RotationType::isTransform() const
+{
+ return true;
+}
+
+bool ScalingOverCenterType::isTransform() const
+{
+ return true;
+}
+
+bool ScalingOverCenter2Type::isTransform() const
+{
+ return true;
+}
+
+bool ScalingOverLineType::isTransform() const
+{
+ return true;
+}
+
+bool ScalingOverLine2Type::isTransform() const
+{
+ return true;
+}
+
+bool ProjectiveRotationType::isTransform() const
+{
+ return true;
+}
+
+bool HarmonicHomologyType::isTransform() const
+{
+ return true;
+}
+
+bool AffinityB2TrType::isTransform() const
+{
+ return true;
+}
+
+bool AffinityGI3PType::isTransform() const
+{
+ return true;
+}
+
+bool ProjectivityB2QuType::isTransform() const
+{
+ return true;
+}
+
+bool ProjectivityGI4PType::isTransform() const
+{
+ return true;
+}
+
+bool CastShadowType::isTransform() const
+{
+ return true;
+}
+
+static const ArgsParser::spec argsspecApplyTransformation[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Transform this object" ), "SHOULD NOT BE SEEN", false },
+ { TransformationImp::stype(), I18N_NOOP( "Transform using this transformation" ), "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ApplyTransformationObjectType )
+
+ApplyTransformationObjectType::ApplyTransformationObjectType()
+ : ArgsParserObjectType( "ApplyTransformation", argsspecApplyTransformation, 2 )
+{
+}
+
+ApplyTransformationObjectType::~ApplyTransformationObjectType()
+{
+}
+
+const ApplyTransformationObjectType* ApplyTransformationObjectType::instance()
+{
+ static const ApplyTransformationObjectType t;
+ return &t;
+}
+
+ObjectImp* ApplyTransformationObjectType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+ return args[0]->transform( static_cast<const TransformationImp*>( args[1] )->data() );
+}
+
+const ObjectImpType* ApplyTransformationObjectType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+bool ApplyTransformationObjectType::isTransform() const
+{
+ return true;
+}
+
+bool SimilitudeType::isTransform() const
+{
+ return true;
+}
+
+const ObjectImpType* SimilitudeType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const SimilitudeType* SimilitudeType::instance()
+{
+ static const SimilitudeType t;
+ return &t;
+}
+
+ObjectImp* SimilitudeType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate c = static_cast<const PointImp*>( args[1] )->coordinate();
+ Coordinate a = static_cast<const PointImp*>( args[2] )->coordinate();
+ Coordinate b = static_cast<const PointImp*>( args[3] )->coordinate();
+ a -= c;
+ b -= c;
+ double factor = sqrt( b.squareLength()/a.squareLength() );
+ double theta = atan2( b.y, b.x ) - atan2( a.y, a.x );
+
+ return args[0]->transform( Transformation::similitude( c, theta, factor ) );
+}
+
+SimilitudeType::~SimilitudeType()
+{
+}
+
+static const ArgsParser::spec argsspecSimilitude[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Apply a similitude to this object" ),
+ I18N_NOOP( "Select the object to transform..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Apply a similitude with this center" ),
+ I18N_NOOP( "Select the center for the similitude..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Apply a similitude mapping this point onto another point" ),
+ I18N_NOOP( "Select the point which the similitude should map onto another point..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Apply a similitude mapping a point onto this point" ),
+ I18N_NOOP( "Select the point onto which the similitude should map the first point..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( SimilitudeType )
+
+SimilitudeType::SimilitudeType()
+ : ArgsParserObjectType( "Similitude", argsspecSimilitude, 4 )
+{
+}
diff --git a/kig/objects/transform_types.h b/kig/objects/transform_types.h
new file mode 100644
index 00000000..038be068
--- /dev/null
+++ b/kig/objects/transform_types.h
@@ -0,0 +1,243 @@
+// 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.
+
+#ifndef KIG_OBJECTS_TRANSFORM_TYPES_H
+#define KIG_OBJECTS_TRANSFORM_TYPES_H
+
+#include "object_type.h"
+
+class TranslatedType
+ : public ArgsParserObjectType
+{
+ TranslatedType();
+ ~TranslatedType();
+public:
+ static const TranslatedType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class PointReflectionType
+ : public ArgsParserObjectType
+{
+ PointReflectionType();
+ ~PointReflectionType();
+public:
+ static const PointReflectionType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class LineReflectionType
+ : public ArgsParserObjectType
+{
+ LineReflectionType();
+ ~LineReflectionType();
+public:
+ static const LineReflectionType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class RotationType
+ : public ArgsParserObjectType
+{
+ RotationType();
+ ~RotationType();
+public:
+ static const RotationType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ScalingOverCenterType
+ : public ArgsParserObjectType
+{
+ ScalingOverCenterType();
+ ~ScalingOverCenterType();
+public:
+ static const ScalingOverCenterType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ScalingOverCenter2Type
+ : public ArgsParserObjectType
+{
+ ScalingOverCenter2Type();
+ ~ScalingOverCenter2Type();
+public:
+ static const ScalingOverCenter2Type* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ScalingOverLineType
+ : public ArgsParserObjectType
+{
+ ScalingOverLineType();
+ ~ScalingOverLineType();
+public:
+ static const ScalingOverLineType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ScalingOverLine2Type
+ : public ArgsParserObjectType
+{
+ ScalingOverLine2Type();
+ ~ScalingOverLine2Type();
+public:
+ static const ScalingOverLine2Type* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ProjectiveRotationType
+ : public ArgsParserObjectType
+{
+ ProjectiveRotationType();
+ ~ProjectiveRotationType();
+public:
+ static const ProjectiveRotationType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class HarmonicHomologyType
+ : public ArgsParserObjectType
+{
+ HarmonicHomologyType();
+ ~HarmonicHomologyType();
+public:
+ static const HarmonicHomologyType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class AffinityB2TrType
+ : public ArgsParserObjectType
+{
+ AffinityB2TrType();
+ ~AffinityB2TrType();
+public:
+ static const AffinityB2TrType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class AffinityGI3PType
+ : public ArgsParserObjectType
+{
+ AffinityGI3PType();
+ ~AffinityGI3PType();
+public:
+ static const AffinityGI3PType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ProjectivityB2QuType
+ : public ArgsParserObjectType
+{
+ ProjectivityB2QuType();
+ ~ProjectivityB2QuType();
+public:
+ static const ProjectivityB2QuType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ProjectivityGI4PType
+ : public ArgsParserObjectType
+{
+ ProjectivityGI4PType();
+ ~ProjectivityGI4PType();
+public:
+ static const ProjectivityGI4PType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class CastShadowType
+ : public ArgsParserObjectType
+{
+ CastShadowType();
+ ~CastShadowType();
+public:
+ static const CastShadowType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ApplyTransformationObjectType
+ : public ArgsParserObjectType
+{
+ ApplyTransformationObjectType();
+ ~ApplyTransformationObjectType();
+public:
+ static const ApplyTransformationObjectType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+ bool isTransform() const;
+};
+
+class SimilitudeType
+ : public ArgsParserObjectType
+{
+ SimilitudeType();
+ ~SimilitudeType();
+public:
+ static const SimilitudeType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+#endif
diff --git a/kig/objects/vector_type.cc b/kig/objects/vector_type.cc
new file mode 100644
index 00000000..d96be07b
--- /dev/null
+++ b/kig/objects/vector_type.cc
@@ -0,0 +1,100 @@
+// Copyright (C) 2004 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 "vector_type.h"
+
+#include "point_imp.h"
+#include "other_imp.h"
+#include "bogus_imp.h"
+
+static const ArgsParser::spec argsspecVector[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Construct a vector from this point" ),
+ I18N_NOOP( "Select the start point of the new vector..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct a vector to this point" ),
+ I18N_NOOP( "Select the end point of the new vector..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( VectorType )
+
+VectorType::VectorType()
+ : ObjectABType( "Vector", argsspecVector, 2 )
+{
+}
+
+VectorType::~VectorType()
+{
+}
+
+const VectorType* VectorType::instance()
+{
+ static const VectorType t;
+ return &t;
+}
+
+ObjectImp* VectorType::calc( const Coordinate& a, const Coordinate& b ) const
+{
+ return new VectorImp( a, b );
+}
+
+const ObjectImpType* VectorType::resultId() const
+{
+ return VectorImp::stype();
+}
+
+static const ArgsParser::spec argsspecVectorSum[] =
+{
+ { VectorImp::stype(), I18N_NOOP( "Construct the vector sum of this vector and another one." ),
+ I18N_NOOP( "Select the first of the two vectors of which you want to construct the sum..." ), false },
+ { VectorImp::stype(), I18N_NOOP( "Construct the vector sum of this vector and the other one." ),
+ I18N_NOOP( "Select the other of the two vectors of which you want to construct the sum..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct the vector sum starting at this point." ),
+ I18N_NOOP( "Select the point to construct the sum vector in..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( VectorSumType )
+
+VectorSumType::VectorSumType()
+ : ArgsParserObjectType( "VectorSum", argsspecVectorSum, 3 )
+{
+}
+
+VectorSumType::~VectorSumType()
+{
+}
+
+const VectorSumType* VectorSumType::instance()
+{
+ static const VectorSumType t;
+ return &t;
+}
+
+ObjectImp* VectorSumType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const VectorImp& a = *static_cast<const VectorImp*>( args[0] );
+ const VectorImp& b = *static_cast<const VectorImp*>( args[1] );
+ const PointImp& p = *static_cast<const PointImp*>( args[2] );
+
+ return new VectorImp( p.coordinate(), p.coordinate() + a.dir() + b.dir() );
+}
+
+const ObjectImpType* VectorSumType::resultId() const
+{
+ return VectorImp::stype();
+}
diff --git a/kig/objects/vector_type.h b/kig/objects/vector_type.h
new file mode 100644
index 00000000..e1756ba5
--- /dev/null
+++ b/kig/objects/vector_type.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2004 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.
+
+#ifndef KIG_OBJECTS_VECTOR_TYPE_H
+#define KIG_OBJECTS_VECTOR_TYPE_H
+
+#include "base_type.h"
+
+class VectorType
+ : public ObjectABType
+{
+ VectorType();
+ ~VectorType();
+public:
+ static const VectorType* instance();
+ ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class VectorSumType
+ : public ArgsParserObjectType
+{
+ VectorSumType();
+ ~VectorSumType();
+public:
+ static const VectorSumType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif