diff options
Diffstat (limited to 'kig/filters')
54 files changed, 7857 insertions, 0 deletions
diff --git a/kig/filters/Makefile.am b/kig/filters/Makefile.am new file mode 100644 index 00000000..bb827b5a --- /dev/null +++ b/kig/filters/Makefile.am @@ -0,0 +1,38 @@ +INCLUDES=$(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES=libfilters.la +noinst_HEADERS= \ + cabri-filter.h \ + exporter.h \ + filter.h \ + filters-common.h \ + imageexporteroptions.h \ + kgeo-filter.h \ + kgeo-resource.h \ + kseg-defs.h \ + kseg-filter.h \ + latexexporter.h \ + native-filter.h \ + svgexporter.h \ + drgeo-filter.h \ + drgeo-filter-chooser.h +libfilters_la_SOURCES= \ + cabri-filter.cc \ + exporter.cc \ + filter.cc \ + filters-common.cc \ + imageexporteroptions.cc \ + imageexporteroptionsbase.ui \ + kgeo-filter.cc \ + kseg-filter.cc \ + latexexporter.cc \ + latexexporteroptions.ui \ + native-filter.cc \ + svgexporter.cc \ + svgexporteroptions.ui \ + drgeo-filter.cc \ + drgeo-filter-chooser.cc \ + drgeo-filter-chooserbase.ui + diff --git a/kig/filters/cabri-filter.cc b/kig/filters/cabri-filter.cc new file mode 100644 index 00000000..6d19027b --- /dev/null +++ b/kig/filters/cabri-filter.cc @@ -0,0 +1,577 @@ +/** + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese <[email protected]> + + 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 "cabri-filter.h" + +#include "../kig/kig_document.h" +#include "../kig/kig_part.h" +#include "../misc/coordinate.h" +#include "../objects/arc_type.h" +#include "../objects/bogus_imp.h" +#include "../objects/circle_type.h" +#include "../objects/conic_types.h" +#include "../objects/curve_imp.h" +#include "../objects/line_imp.h" +#include "../objects/line_type.h" +#include "../objects/object_calcer.h" +#include "../objects/object_drawer.h" +#include "../objects/object_factory.h" +#include "../objects/object_holder.h" +#include "../objects/other_imp.h" +#include "../objects/other_type.h" +#include "../objects/point_type.h" +#include "../objects/polygon_type.h" +#include "../objects/transform_types.h" +#include "../objects/vector_type.h" + +#include <qcolor.h> +#include <qfile.h> +#include <qregexp.h> + +#include <kdebug.h> +#include <klocale.h> + +/** + * a line: + * "Nr": Type, Unknown, "CN:"NumberOfParents, "VN:"Unknown + * Color, FillType, Thickness, "DS":Dots, "GT":SpecialAppearance, Visible, Fixed + * ["Const": Parents] ["Val": Constants] + * + * Nr: Simple sequential numbering of the objects in a file. + * Type: seen so far: Pt, Axes, Line, Cir + * NumberOfParents: The number of parents that will be specified in + * Parents + * Color: + * R -> red + * O -> purple + * Y -> yellow + * P -> dark purple + * V -> dark blue + * Bl -> blue + * lBl -> bright blue + * G -> bright green + * dG -> dark green + * Br -> brown + * dBr -> beige + * lGr -> light grey + * Gr -> grey + * dGr -> dark grey + * B -> black + * FillType: + * W -> not filled ( white ? ) + * all values of the Color item are valid here too.. + * Thickness: + * t -> thin + * tT -> medium + * T -> Thick + * Dots: + * a specification for how a line should be drawn ( with many + * dots, with short lines, it's a pretty generic format: the first + * number signifies the number of sequential dots to draw first, and + * the next is the sum of this first number with the number of + * spaces to leave before starting a new segment. + * SpecialAppearance: + * a number indicating some way of specially drawing an object. This + * can be modified using the "Modify Appearance" button in + * Cabri. For example, for a segment, the number indicates the + * amount of ticks to put on the segment, to indicate + * correspondances between segments.. + * Visible: + * V means visible, I means invisible + * Fixed: + * St means fix this object ( if you move one of its parents, it + * won't move ), nSt ( the default ) means don't fix this object. + * Parents: + * The numbers of the objects this object depends on + * Constants: + * Constants whose meaning depends on the type of object. E.g. for + * a point, this means first x, then y component. + */ + +struct CabriObject +{ + uint id; + QCString type; + uint numberOfParents; + QColor color; + QColor fillColor; + int thick; + int lineSegLength; + int lineSegSplit; + int specialAppearanceSwitch; + bool visible; + bool fixed; + std::vector<int> parents; + std::vector<double> data; +}; + +KigFilterCabri::KigFilterCabri() +{ +} + +KigFilterCabri::~KigFilterCabri() +{ +} + +bool KigFilterCabri::supportMime( const QString& mime ) +{ + // ugly hack to avoid duplicate extension ( XFig and Cabri files + // have the same .fig extension ). + return ( mime == "image/x-xfig" ) || + ( mime == "application/x-cabri" ); +} + +static QString readLine( QFile& file ) +{ + QString ret; + file.readLine( ret, 10000L ); + if ( ret[ret.length() - 1] == '\n' ) + ret.truncate( ret.length() - 1 ); + if ( ret[ret.length() - 1] == '\r' ) + ret.truncate( ret.length() - 1 ); + return ret; +} + +static QColor translatecolor( const QString& s ) +{ + if ( s == "R" ) return Qt::red; + if ( s == "O" ) return Qt::magenta; + if ( s == "Y" ) return Qt::yellow; + if ( s == "P" ) return Qt::darkMagenta; + if ( s == "V" ) return Qt::darkBlue; + if ( s == "Bl" ) return Qt::blue; + if ( s == "lBl" ) return Qt::cyan; // TODO: bright blue + if ( s == "G" ) return Qt::green; + if ( s == "dG" ) return Qt::darkGreen; + if ( s == "Br" ) return QColor( 165, 42, 42 ); + if ( s == "dBr" ) return QColor( 128, 128, 0 ); + if ( s == "lGr" ) return Qt::lightGray; + if ( s == "Gr" ) return Qt::gray; + if ( s == "dGr" ) return Qt::darkGray; + if ( s == "B" ) return Qt::black; + if ( s == "W" ) return Qt::white; + + kdDebug() << k_funcinfo << "unknown color: " << s << endl; + return Qt::black; +} + +bool KigFilterCabri::readObject( QFile& f, CabriObject& myobj ) +{ + // there are 4 lines per object in the file, so we read them all + // four now. + QString line1, line2, line3, s; + QString file = f.name(); + line1 = readLine( f ); + line2 = readLine( f ); + line3 = readLine( f ); + // ignore line 4, it is empty.. + s = readLine( f ); + + QRegExp firstlinere( "^([^:]+): ([^,]+), ([^,]+), CN:([^,]*), VN:(.*)$" ); + if ( ! firstlinere.exactMatch( line1 ) ) + KIG_FILTER_PARSE_ERROR; + + bool ok; + QString tmp; + + tmp = firstlinere.cap( 1 ); + myobj.id = tmp.toInt( &ok ); + if ( !ok ) KIG_FILTER_PARSE_ERROR; + + tmp = firstlinere.cap( 2 ); + myobj.type = tmp.latin1(); + + tmp = firstlinere.cap( 3 ); + // i have no idea what this number means.. + + tmp = firstlinere.cap( 4 ); + myobj.numberOfParents = tmp.toInt( &ok ); + if ( ! ok ) KIG_FILTER_PARSE_ERROR; + + tmp = firstlinere.cap( 5 ); + // i have no idea what this number means.. + + QRegExp secondlinere( "^([^,]+), ([^,]+), ([^,]+), DS:([^ ]+) ([^,]+), GT:([^,]+), ([^,]+), (.*)$" ); + if ( ! secondlinere.exactMatch( line2 ) ) + KIG_FILTER_PARSE_ERROR; + + tmp = secondlinere.cap( 1 ); + myobj.color = translatecolor( tmp ); +// if ( ! color.isValid() ) KIG_FILTER_PARSE_ERROR; + + tmp = secondlinere.cap( 2 ); + myobj.fillColor = translatecolor( tmp ); +// if ( ! fillcolor.isValid() ) KIG_FILTER_PARSE_ERROR; + + tmp = secondlinere.cap( 3 ); + myobj.thick = tmp == "t" ? 1 : tmp == "tT" ? 2 : 3; + + tmp = secondlinere.cap( 4 ); + myobj.lineSegLength = tmp.toInt( &ok ); + if ( ! ok ) KIG_FILTER_PARSE_ERROR; + + tmp = secondlinere.cap( 5 ); + myobj.lineSegSplit = tmp.toInt( &ok ); + if ( ! ok ) KIG_FILTER_PARSE_ERROR; + + tmp = secondlinere.cap( 6 ); + myobj.specialAppearanceSwitch = tmp.toInt( &ok ); + if ( ! ok ) KIG_FILTER_PARSE_ERROR; + + tmp = secondlinere.cap( 7 ); + myobj.visible = tmp == "V"; + + tmp = secondlinere.cap( 8 ); + myobj.fixed = tmp == "St"; + + QRegExp thirdlinere( "^(Const: ([^,]*),? ?)?(Val: (.*))?$" ); + if ( ! thirdlinere.exactMatch( line3 ) ) + KIG_FILTER_PARSE_ERROR; + + tmp = thirdlinere.cap( 2 ); + QStringList parentsids = QStringList::split( ' ', tmp ); + for ( QStringList::iterator i = parentsids.begin(); + i != parentsids.end(); ++i ) + { + myobj.parents.push_back( ( *i ).toInt( &ok ) ); + if ( ! ok ) KIG_FILTER_PARSE_ERROR; + } + if ( myobj.parents.size() != myobj.numberOfParents ) + KIG_FILTER_PARSE_ERROR; + + tmp = thirdlinere.cap( 4 ); + QStringList valIds = QStringList::split( ' ', tmp ); + for ( QStringList::iterator i = valIds.begin(); + i != valIds.end(); ++i ) + { + myobj.data.push_back( ( *i ).toDouble( &ok ) ); + if ( ! ok ) KIG_FILTER_PARSE_ERROR; + } +// kdDebug() +// << k_funcinfo << endl +// << "id = " << myobj.id << endl +// << "type = " << myobj.type << endl +// << "numberOfParents = " << myobj.numberOfParents << endl +// << "color = " << myobj.color.name() << endl +// << "fillcolor = " << myobj.fillColor.name() << endl +// << "thick = " << myobj.thick << endl +// << "lineseglength = " << myobj.lineSegLength << endl +// << "linesegsplit = " << myobj.lineSegSplit << endl +// << "specialAppearanceSwitch = " << myobj.specialAppearanceSwitch << endl +// << "visible = " << visible << endl +// << "fixed = " << myobj.fixed << endl +// << "parents =" << endl; +// for ( std::vector<int>::iterator i = myobj.parents.begin(); i != myobj.parents.end(); ++i ) +// kdDebug() << " " << *i << endl; +// kdDebug() << "vals = " << endl; +// for ( std::vector<double>::iterator i = myobj.data.begin(); i != myobj.data.end(); ++i ) +// kdDebug() << " " << *i << endl; + + return true; +} + +KigDocument* KigFilterCabri::load( const QString& file ) +{ + QFile f( file ); + if ( ! f.open( IO_ReadOnly ) ) + { + fileNotFound( file ); + return 0; + } + + KigDocument* ret = new KigDocument(); + + QString s = readLine( f ); + QString a = s.left( 21 ); + QString b = s.mid( 21 ); + if( a != "FIGURE CabriII vers. " || + ( b != "DOS 1.0" && b != "MS-Windows 1.0" ) ) + { + if ( s.left( 5 ) == "#FIG " ) + { + notSupported( file, i18n( "This is an XFig file, not a Cabri figure." ) ); + return 0; + } + else + KIG_FILTER_PARSE_ERROR; + } + + // next we have: + // line 2: empty line + // line 3: window dimensions -> we don't need/use that... + // line 4: empty line + // line 5 through 8: center point + // line 9 through 12: axes + // so we skip 11 lines... + for( int i = 0; i != 11; ++i) + s = readLine( f ); + + // all Cabri files seem to at least have these center and axes... + if ( f.atEnd() ) + KIG_FILTER_PARSE_ERROR; + + std::vector<ObjectHolder*> holders; + std::vector<ObjectCalcer*> calcers; + + const ObjectFactory* fact = ObjectFactory::instance(); + + std::vector<ObjectCalcer*> args; + ObjectCalcer* oc = 0; + + while ( ! f.atEnd() ) + { + CabriObject obj; + // we do one object each iteration.. + if ( !readObject( f, obj ) ) + return 0; + +// reading linestyle + Qt::PenStyle ls = Qt::SolidLine; + if ( ( obj.lineSegLength > 1 ) && ( obj.lineSegLength < 6 ) && + ( obj.lineSegSplit > 1 ) && ( obj.lineSegSplit <= 10 ) ) + ls = Qt::DotLine; + else if ( ( obj.lineSegLength >= 6 ) && ( obj.lineSegSplit > 10 ) ) + ls = Qt::DashLine; + int ps = 0; + + args.clear(); + for ( std::vector<int>::iterator i = obj.parents.begin(); + i != obj.parents.end(); ++i ) + args.push_back( calcers[*i-3] ); + + // two fake objects at the start ( origin and axes.. ) + if ( obj.id != calcers.size() + 3 ) KIG_FILTER_PARSE_ERROR; + oc = 0; + if ( obj.type == "Pt" ) + { + if ( ! args.empty() ) KIG_FILTER_PARSE_ERROR; + if ( obj.data.size() != 2 ) KIG_FILTER_PARSE_ERROR; + + switch ( obj.specialAppearanceSwitch ) + { + case 0: + { + obj.thick -= 1; + break; + } + case 2: + { + obj.thick += 1; + break; + } + case 3: + { + obj.thick += 1; + ps = 1; + break; + } + case 4: + { + obj.thick += 2; + ps = 4; + break; + } + } + // different sizes for points.. + obj.thick *= 2; + + oc = fact->fixedPointCalcer( Coordinate( obj.data[0], obj.data[1] ) ); + } + else if ( obj.type == "Cir" ) + { + if ( args.size() == 1 ) + { + if ( obj.data.size() != 1 ) KIG_FILTER_PARSE_ERROR; + ObjectConstCalcer* radc = + new ObjectConstCalcer( new DoubleImp( obj.data[0] ) ); + args.push_back( radc ); + oc = new ObjectTypeCalcer( CircleBPRType::instance(), args ); + } + else if ( args.size() == 2 ) + { + if ( ! obj.data.empty() ) KIG_FILTER_PARSE_ERROR; + oc = new ObjectTypeCalcer( CircleBCPType::instance(), args ); + } + else KIG_FILTER_PARSE_ERROR; + } + else if ( obj.type == "Line" || obj.type == "Ray" || obj.type == "Seg" || + obj.type == "Vec" ) + { + if ( args.size() == 1 ) + { + if ( obj.data.size() != 2 ) KIG_FILTER_PARSE_ERROR; + Coordinate vect( obj.data[0], obj.data[1] ); + ObjectConstCalcer* vectorcalcer = + new ObjectConstCalcer( new VectorImp( Coordinate( 0, 0 ), vect ) ); + args.push_back( vectorcalcer ); + ObjectTypeCalcer* secondpoint = + new ObjectTypeCalcer( TranslatedType::instance(), args ); + secondpoint->calc( *ret ); + args[1] = secondpoint; + } + if ( args.size() != 2 ) KIG_FILTER_PARSE_ERROR; + const ObjectType* t = 0; + if ( obj.type == "Line" ) t = LineABType::instance(); + else if ( obj.type == "Ray" ) t = RayABType::instance(); + else if ( obj.type == "Seg" ) t = SegmentABType::instance(); + else if ( obj.type == "Vec" ) t = VectorType::instance(); + else assert( t ); + oc = new ObjectTypeCalcer( t, args ); + } + else if ( obj.type == "Pt/" ) + { + // different sizes for points.. + obj.thick *= 2; + if ( args.size() != 1 || obj.data.size() != 2 ) + KIG_FILTER_PARSE_ERROR; + ObjectCalcer* parent = args[0]; + if ( !parent->imp()->inherits( CurveImp::stype() ) ) + KIG_FILTER_PARSE_ERROR; + const CurveImp* curve = static_cast<const CurveImp*>( parent->imp() ); + Coordinate pt = Coordinate( obj.data[0], obj.data[1] ); + double param = curve->getParam( pt, *ret ); + args.push_back( new ObjectConstCalcer( new DoubleImp( param ) ) ); + oc = new ObjectTypeCalcer( ConstrainedPointType::instance(), args ); + } + else if ( obj.type == "Perp" || obj.type == "Par" ) + { + if ( args.size() != 2 || obj.data.size() != 0 ) + KIG_FILTER_PARSE_ERROR; + const ObjectType* t = 0; + if ( obj.type == "Perp" ) t = LinePerpendLPType::instance(); + else if ( obj.type == "Par" ) t = LineParallelLPType::instance(); + else assert( false ); + oc = new ObjectTypeCalcer( t, args ); + } + else if ( obj.type == "Arc" ) + { + if ( args.size() != 3 || ! obj.data.empty() ) + KIG_FILTER_PARSE_ERROR; + oc = new ObjectTypeCalcer( ArcBTPType::instance(), args ); + } + else if ( obj.type == "Con" ) + { + if ( args.size() != 5 || !obj.data.empty() ) + KIG_FILTER_PARSE_ERROR; + oc = new ObjectTypeCalcer( ConicB5PType::instance(), args ); + } + else if ( obj.type == "Mid" ) + { + if ( args.size() == 2 ) + { + ObjectCalcer* c = + new ObjectTypeCalcer( SegmentABType::instance(), args ); + c->calc( *ret ); + args.clear(); + args.push_back( c ); + } + // midpoint -> this can be the midpoint of a segment, two + // points, or a vector... + if ( args.size() != 1 || !obj.data.empty() ) + KIG_FILTER_PARSE_ERROR; + ObjectCalcer* parent = args[0]; + if ( parent->imp()->inherits( SegmentImp::stype() ) ) + oc = fact->propertyObjectCalcer( parent, "mid-point" ) ; + else if ( parent->imp()->inherits( VectorImp::stype() ) ) + oc = fact->propertyObjectCalcer( parent, "vect-mid-point" ); + else KIG_FILTER_PARSE_ERROR; + } + else if ( obj.type == "PBiss" ) + { + if ( args.size() == 2 ) + { + ObjectCalcer* c = + new ObjectTypeCalcer( SegmentABType::instance(), args ); + c->calc( *ret ); + args.clear(); + args.push_back( c ); + } + if ( args.size() != 1 || !obj.data.empty() ) + KIG_FILTER_PARSE_ERROR; + ObjectCalcer* parent = args[0]; + ObjectCalcer* midpoint = 0; + if ( parent->imp()->inherits( SegmentImp::stype() ) ) + midpoint = fact->propertyObjectCalcer( parent, "mid-point" ) ; +// else if ( parent->imp()->inherits( VectorImp::stype() ) ) +// midpoint = fact->propertyObjectCalcer( parent, "vect-mid-point" ); + else KIG_FILTER_PARSE_ERROR; + midpoint->calc( *ret ); + args.push_back( midpoint ); + oc = new ObjectTypeCalcer( LinePerpendLPType::instance(), args ); + } + else if ( obj.type == "Pol" ) + { + if ( args.size() < 3 || !obj.data.empty() ) + KIG_FILTER_PARSE_ERROR; + oc = new ObjectTypeCalcer( PolygonBNPType::instance(), args ); + } + else if ( obj.type == "Locus" ) + { + if ( args.size() != 2 || !obj.data.empty() ) + KIG_FILTER_PARSE_ERROR; + oc = fact->locusCalcer( args[0], args[1] ); + } + else if ( obj.type == "Refl" ) + { + if ( args.size() != 2 || !obj.data.empty() ) + KIG_FILTER_PARSE_ERROR; + oc = new ObjectTypeCalcer( LineReflectionType::instance(), args ); + } + else if ( obj.type == "Sym" ) + { + if ( args.size() != 2 || !obj.data.empty() ) + KIG_FILTER_PARSE_ERROR; + oc = new ObjectTypeCalcer( PointReflectionType::instance(), args ); + } + else if ( obj.type == "Tran" ) + { + if ( args.size() != 2 || !obj.data.empty() ) + KIG_FILTER_PARSE_ERROR; + oc = new ObjectTypeCalcer( TranslatedType::instance(), args ); + } + else + { + notSupported( file, i18n( "This Cabri file contains a \"%1\" object, " + "which Kig does not currently support." ).arg( obj.type ) ); + return 0; + } + + if ( oc == 0 ) KIG_FILTER_PARSE_ERROR; + + oc->calc( *ret ); + calcers.push_back( oc ); + ObjectDrawer* d = new ObjectDrawer( obj.color, obj.thick, obj.visible, ls, ps ); + ObjectHolder* oh = new ObjectHolder( oc, d ); + holders.push_back( oh ); + + oc = 0; + } + + ret->addObjects( holders ); + ret->setGrid( false ); + ret->setAxes( false ); + return ret; +} + +KigFilterCabri* KigFilterCabri::instance() +{ + static KigFilterCabri t; + return &t; +} diff --git a/kig/filters/cabri-filter.h b/kig/filters/cabri-filter.h new file mode 100644 index 00000000..5760040f --- /dev/null +++ b/kig/filters/cabri-filter.h @@ -0,0 +1,55 @@ +// This file is part of Kig, a KDE program for Interactive Geometry... +// Copyright (C) 2002 Dominique Devriese <[email protected]> + +// 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_FILTERS_CABRI_FILTER_H +#define KIG_FILTERS_CABRI_FILTER_H + +#include "filter.h" + +struct CabriObject; + +class QFile; + +/** + * This is an import filter for the output of the commercial program + * Cabri ("CAhier de BRouillon Interactif" or something like that), + * which is being pushed by Texas Instruments, but only exists for + * the Winblows(tm) platform and some TI scientific calculator... + * + * \note + * This is completely free code, i have not looked at any Cabri source + * code, and have implemented this implementation of the Cabri file + * format from zero, by just looking at the input and output from a + * (properly licensed) Cabri program... + */ +class KigFilterCabri + : public KigFilter +{ + KigFilterCabri(); + ~KigFilterCabri(); +public: + static KigFilterCabri* instance(); + + bool supportMime ( const QString& mime ); + KigDocument* load ( const QString& fromfile ); +private: + bool readObject( QFile& f, CabriObject& myobj ); + +}; + +#endif diff --git a/kig/filters/drgeo-filter-chooser.cc b/kig/filters/drgeo-filter-chooser.cc new file mode 100644 index 00000000..424a3462 --- /dev/null +++ b/kig/filters/drgeo-filter-chooser.cc @@ -0,0 +1,65 @@ +// Copyright (C) 2004 Pino Toscano <[email protected]> +// Copyright (C) 2004 Dominique Devriese <[email protected]> + +// 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 "drgeo-filter-chooser.h" +#include "drgeo-filter-chooser.moc" + +#include <klistbox.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpushbutton.h> +#include <kstdguiitem.h> + +KigFilterDrgeoChooser::KigFilterDrgeoChooser( const QStringList& l ) + : KigFilterDrgeoChooserBase( 0, "drgeo_filter", true ) +{ + OKButton->setGuiItem( KStdGuiItem::ok() ); + CancelButton->setGuiItem( KStdGuiItem::cancel() ); + + FigureListBox->insertStringList( l ); + + connect( OKButton, SIGNAL( clicked() ), SLOT( slotOKPressed() ) ); + connect( CancelButton, SIGNAL( clicked() ), SLOT( slotCancelPressed() ) ); + connect( FigureListBox, SIGNAL( executed( QListBoxItem* ) ), SLOT( slotExecuted( QListBoxItem* ) ) ); +} + +void KigFilterDrgeoChooser::slotOKPressed() +{ + const int r = FigureListBox->currentItem(); + if ( r == -1 ) + { + KMessageBox::sorry( 0, i18n( "Please select a figure." ) ); + return; + } + done( r ); +} + +void KigFilterDrgeoChooser::slotCancelPressed() +{ + done( -1 ); +} + +KigFilterDrgeoChooser::~KigFilterDrgeoChooser() +{ + +} + +void KigFilterDrgeoChooser::slotExecuted( QListBoxItem* i ) +{ + done( FigureListBox->index( i ) ); +} diff --git a/kig/filters/drgeo-filter-chooser.h b/kig/filters/drgeo-filter-chooser.h new file mode 100644 index 00000000..fd4ce606 --- /dev/null +++ b/kig/filters/drgeo-filter-chooser.h @@ -0,0 +1,41 @@ +// Copyright (C) 2004 Pino Toscano <[email protected]> +// Copyright (C) 2002 Dominique Devriese <[email protected]> + +// 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 DRGEOFILTERCHOOSER_H +#define DRGEOFILTERCHOOSER_H + +#include "drgeo-filter-chooserbase.h" + +class QListBoxItem; +class QStringList; + +class KigFilterDrgeoChooser + : public KigFilterDrgeoChooserBase +{ + Q_OBJECT + +public: + KigFilterDrgeoChooser( const QStringList& l ); + ~KigFilterDrgeoChooser(); +public slots: + void slotOKPressed(); + void slotCancelPressed(); + void slotExecuted( QListBoxItem* ); +}; + +#endif diff --git a/kig/filters/drgeo-filter-chooserbase.ui b/kig/filters/drgeo-filter-chooserbase.ui new file mode 100644 index 00000000..829d84cc --- /dev/null +++ b/kig/filters/drgeo-filter-chooserbase.ui @@ -0,0 +1,140 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>KigFilterDrgeoChooserBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>KigFilterDrgeoChooserBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>300</width> + <height>202</height> + </rect> + </property> + <property name="caption"> + <string>Dr. Geo Filter</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>ExplanationTextLabel</cstring> + </property> + <property name="text"> + <string>The current Dr. Geo file contains more than one figure. +Please select which to import:</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="KListBox"> + <property name="name"> + <cstring>FigureListBox</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>Line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout7</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <spacer> + <property name="name"> + <cstring>spacer</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KPushButton"> + <property name="name"> + <cstring>OKButton</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&OK</string> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>CancelButton</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistbox.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kig/filters/drgeo-filter-status.txt b/kig/filters/drgeo-filter-status.txt new file mode 100644 index 00000000..db399eae --- /dev/null +++ b/kig/filters/drgeo-filter-status.txt @@ -0,0 +1,50 @@ +Dr. Geo filter status +===================== + +Objects imported +---------------- + +Points most, On_curve (most) +Rays ok +Vectors ok +Lines most +Circles most +Numberics most (as a label) +Angles 3pts +Arcs ok +Locuses ok +Transformations most +Intersections most +Scripts as a label +Equations ok +Polygons ok + +Colors ok +Visibility ok +Styles ok +Grid ok + +Objects not imported +-------------------- + +Points Coordinate(*) +Lines pt_slope(*) +Circle radius(*) +Numberics distance_pt_circle +Angles vectors +Transformations scaling(*) +Intersections arc-circle(**), locus-other object(**) + +(*) objects which depend on numerics +(**) objects which currently are not implemented in Kig + +Objects ignored +--------------- + +boundingBox +customUI + +Known problems +-------------- + +* Point(On_curve): does not work with locuses diff --git a/kig/filters/drgeo-filter.cc b/kig/filters/drgeo-filter.cc new file mode 100644 index 00000000..8fa306cc --- /dev/null +++ b/kig/filters/drgeo-filter.cc @@ -0,0 +1,809 @@ +// Copyright (C) 2004 Pino Toscano <[email protected]> +// Copyright (C) 2004 Dominique Devriese <[email protected]> + +// 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 "drgeo-filter.h" + +#include "drgeo-filter-chooser.h" +#include "filters-common.h" + +#include "../kig/kig_document.h" +#include "../kig/kig_part.h" +#include "../misc/common.h" +#include "../misc/coordinate.h" +#include "../objects/angle_type.h" +#include "../objects/arc_type.h" +#include "../objects/bogus_imp.h" +#include "../objects/circle_imp.h" +#include "../objects/circle_type.h" +#include "../objects/conic_imp.h" +#include "../objects/conic_types.h" +#include "../objects/curve_imp.h" +#include "../objects/intersection_types.h" +#include "../objects/line_imp.h" +#include "../objects/line_type.h" +#include "../objects/object_calcer.h" +#include "../objects/object_drawer.h" +#include "../objects/object_factory.h" +#include "../objects/object_holder.h" +#include "../objects/object_type.h" +#include "../objects/other_imp.h" +#include "../objects/other_type.h" +#include "../objects/point_imp.h" +#include "../objects/point_type.h" +#include "../objects/polygon_type.h" +#include "../objects/transform_types.h" +#include "../objects/vector_type.h" + +#include <math.h> + +#include <qfile.h> +#include <qnamespace.h> + +#include <klocale.h> + +#undef DRGEO_DEBUG +//#define DRGEO_DEBUG + +struct DrGeoHierarchyElement +{ + QString id; + std::vector<QString> parents; +}; + +KigFilterDrgeo::KigFilterDrgeo() +{ +} + +KigFilterDrgeo::~KigFilterDrgeo() +{ +} + +bool KigFilterDrgeo::supportMime( const QString& mime ) +{ + return mime == "application/x-drgeo"; +} + +KigDocument* KigFilterDrgeo::load( const QString& file ) +{ + QFile f( file ); + if ( ! f.open( IO_ReadOnly ) ) + { + fileNotFound( file ); + return 0; + } + + QStringList figures; + QDomDocument doc( "drgenius" ); + if ( !doc.setContent( &f ) ) + KIG_FILTER_PARSE_ERROR; + QDomElement main = doc.documentElement(); + int nmacros = 0; + // reading figures... + for ( QDomNode n = main.firstChild(); ! n.isNull(); n = n.nextSibling() ) + { + QDomElement e = n.toElement(); + if ( e.isNull() ) continue; + else if ( e.tagName() == "drgeo" ) + figures.append( e.attribute( "name" ) ); + else if ( e.tagName() == "macro" ) + nmacros++; + } + if ( figures.isEmpty() ) { + if( nmacros > 0 ) + warning( i18n( "The Dr. Geo file \"%1\" is a macro file so it contains no " + "figures." ).arg( file ) ); + else + warning( i18n( "There are no figures in Dr. Geo file \"%1\"." ).arg( file ) ); + return false; + } + + int nfig = figures.count(); + // no figures, no party... + if ( nfig == 0 ) + return 0; + + int myfig = 0; + + if ( nfig > 1 ) + { + // Dr. Geo file has more than 1 figure, let the user choose one... + KigFilterDrgeoChooser* c = new KigFilterDrgeoChooser( figures ); + myfig = c->exec(); + delete c; + } + +#ifdef DRGEO_DEBUG + kdDebug() << "drgeo file " << file << endl; +#endif + int curfig = -1; + + for ( QDomNode n = main.firstChild(); ! n.isNull(); n = n.nextSibling() ) + { + QDomElement e = n.toElement(); + if ( e.isNull() ) continue; + else if ( e.tagName() == "drgeo" ) + { + curfig += 1; + if ( curfig == myfig ) + { +#ifdef DRGEO_DEBUG + kdDebug() << "- Figure: '" << e.attribute("name") << "'" << endl; +#endif + bool grid = !e.attribute( "grid" ).isEmpty() && + ( e.attribute( "grid" ) != "False" ); + return importFigure( e.firstChild(), file, grid ); + } + } + } + + return 0; +} + +int convertDrgeoIndex( const std::vector<DrGeoHierarchyElement> es, const QString myid ) +{ + for ( uint i = 0; i < es.size(); ++i ) + if ( es[i].id == myid ) + return i; + return -1; +} + +const Coordinate convertDrgeoLineParam( const double param, const LineData& line ) +{ + const double n = ( param - 0.5 ) * M_PI; + const Coordinate c = line.dir() / line.dir().length(); + const Coordinate p = line.a + tan( n ) * c; + return p; +} + +const Coordinate convertDrgeoHalflineParam( const double param, const LineData& line ) +{ + const double n = param * M_PI * 0.5; + const Coordinate c = line.dir() / line.dir().length(); + const Coordinate p = line.a + tan( n ) * c; + return p; +} + +KigDocument* KigFilterDrgeo::importFigure( QDomNode f, const QString& file, const bool grid ) +{ + KigDocument* ret = new KigDocument(); + + using namespace std; + std::vector<DrGeoHierarchyElement> elems; + int withoutid = 0; + + // 1st: fetch relationships and build an appropriate structure + for (QDomNode a = f; ! a.isNull(); a = a.nextSibling() ) + { + QDomElement domelem = a.toElement(); + if ( domelem.isNull() ) continue; + else + { + DrGeoHierarchyElement elem; +#ifdef DRGEO_DEBUG + kdDebug() << " * " << domelem.tagName() << "(" << domelem.attribute("type") << ")" << endl; +#endif + for ( QDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() ) + { + QDomElement ce = c.toElement(); + if ( ce.isNull() ) continue; + else if ( ce.tagName() == "parent" ) + elem.parents.push_back( ce.attribute( "ref" ) ); + } + QString curid = domelem.attribute( "id" ); + elem.id = !curid.isNull() ? curid : QString::number( withoutid++ ) ; + elems.push_back( elem ); + } + } + +#ifdef DRGEO_DEBUG + QString x; + kdDebug() << "+++ elems" << endl; + for ( uint i = 0; i < elems.size(); ++i ) + { + x = ""; + for ( uint j = 0; j < elems[i].parents.size(); ++j ) + { + x += elems[i].parents[j] + "_"; + } + kdDebug() << " --> " << i << " - " << elems[i].id << " - " << x << endl; + } +#endif + + // 2nd: let's draw! + int curid = 0; + const ObjectFactory* fact = ObjectFactory::instance(); + std::vector<ObjectHolder*> holders; + std::vector<ObjectHolder*> holders2; + ObjectTypeCalcer* oc = 0; + ObjectCalcer* oc2 = 0; + int nignored = 0; + + // there's no need to sort the objects because it seems that DrGeo objects + // appear in the right order... so let's go! + for (QDomNode a = f; ! a.isNull(); a = a.nextSibling() ) + { +#ifdef DRGEO_DEBUG + kdDebug() << "+++ id: " << curid << endl; +#endif + const DrGeoHierarchyElement& el = elems[curid]; + std::vector<ObjectCalcer*> parents; + for ( uint j = 0; j < el.parents.size(); ++j ) + { + int parentid = convertDrgeoIndex( elems, el.parents[j] ); + if ( parentid == -1 ) + KIG_FILTER_PARSE_ERROR; + parents.push_back( holders[parentid-nignored]->calcer() ); + }; + QDomElement domelem = a.toElement(); + +#ifdef DRGEO_DEBUG + if ( parents.size() > 0 ) + for ( uint j = 0; j < parents.size(); ++j ) + { + kdDebug() << "+++++++++ parent[" << j << "]: " << parents[j] << " - " + << parents[j]->imp()->type()->internalName() << endl; + } + else + kdDebug() << "+++++++++ parents: NO" << endl; + kdDebug() << "+++++++++ " << domelem.tagName() << " - " << domelem.attribute("type") << endl; +#endif + + if ( domelem.isNull() ) continue; + else if ( domelem.tagName() == "point" ) + { + QString xs; + QString ys; + QString values; + for ( QDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() ) + { + QDomElement ce = c.toElement(); + if ( ce.isNull() ) continue; + else if ( ce.tagName() == "x" ) + xs = ce.text(); + else if ( ce.tagName() == "y" ) + ys = ce.text(); + else if ( ce.tagName() == "value" ) + values = ce.text(); + } + if ( domelem.attribute( "type" ) == "Free" ) + { + bool ok; + bool ok2; + double x = xs.toDouble( &ok ); + double y = ys.toDouble( &ok2 ); + if ( ! ( ok && ok2 ) ) + KIG_FILTER_PARSE_ERROR; + oc = fact->fixedPointCalcer( Coordinate( x, y ) ); + } + else if ( domelem.attribute( "type" ) == "Middle_2pts" ) + oc = new ObjectTypeCalcer( MidPointType::instance(), parents ); + else if ( domelem.attribute( "type" ) == "Middle_segment" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + if ( !parents[0]->imp()->inherits( SegmentImp::stype() ) ) + KIG_FILTER_PARSE_ERROR; + ObjectPropertyCalcer* o1 = fact->propertyObjectCalcer( parents[0], "end-point-A" ); + o1->calc( *ret ); + ObjectPropertyCalcer* o2 = fact->propertyObjectCalcer( parents[0], "end-point-B" ); + o2->calc( *ret ); + std::vector<ObjectCalcer*> args; + args.push_back( o1 ); + args.push_back( o2 ); + oc = new ObjectTypeCalcer( MidPointType::instance(), args ); + } + else if ( domelem.attribute( "type" ) == "On_curve" ) + { + bool ok3; + double value = values.toDouble( &ok3 ); + if ( ! ok3 ) + KIG_FILTER_PARSE_ERROR; + if ( ( parents[0]->imp()->inherits( CircleImp::stype() ) ) || + ( parents[0]->imp()->inherits( SegmentImp::stype() ) ) ) + oc = fact->constrainedPointCalcer( parents[0], value ); + else if ( parents[0]->imp()->inherits( LineImp::stype() ) ) + { + const LineData l = static_cast<const LineImp*>( parents[0]->imp() )->data(); + const Coordinate p = convertDrgeoLineParam( value, l ); + oc = fact->constrainedPointCalcer( parents[0], p, *ret ); + } + else if ( parents[0]->imp()->inherits( RayImp::stype() ) ) + { + const LineData l = static_cast<const RayImp*>( parents[0]->imp() )->data(); + const Coordinate p = convertDrgeoHalflineParam( value, l ); + oc = fact->constrainedPointCalcer( parents[0], p, *ret ); + } + else if ( parents[0]->imp()->inherits( ArcImp::stype() ) ) + oc = fact->constrainedPointCalcer( parents[0], 1 - value ); + else + { +// oc = fact->constrainedPointCalcer( parents[0], value ); + notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, " + "which Kig does not currently support." ).arg( domelem.tagName() ).arg( + domelem.attribute( "type" ) ) ); + return false; + } + } + else if ( domelem.attribute( "type" ) == "Intersection" ) + { + if ( ( parents[0]->imp()->inherits( AbstractLineImp::stype() ) ) && + ( parents[1]->imp()->inherits( AbstractLineImp::stype() ) ) ) + oc = new ObjectTypeCalcer( LineLineIntersectionType::instance(), parents ); + else + { + bool ok; + int which = domelem.attribute( "extra" ).toInt( &ok ); + if ( !ok ) KIG_FILTER_PARSE_ERROR; + if ( which == 1 ) which = -1; + else if ( which == 0 ) which = 1; + else KIG_FILTER_PARSE_ERROR; + std::vector<ObjectCalcer*> args = parents; + const ObjectType* type = 0; + args.push_back( new ObjectConstCalcer( new IntImp( which ) ) ); + if ( ( parents[0]->imp()->inherits( CircleImp::stype() ) ) && + ( parents[1]->imp()->inherits( CircleImp::stype() ) ) ) + type = CircleCircleIntersectionType::instance(); + else if ( ( parents[0]->imp()->inherits( CircleImp::stype() ) && + parents[1]->imp()->inherits( AbstractLineImp::stype() ) ) || + ( parents[1]->imp()->inherits( CircleImp::stype() ) && + parents[0]->imp()->inherits( AbstractLineImp::stype() ) ) ) + type = ConicLineIntersectionType::instance(); + else if ( ( parents[0]->imp()->inherits( ArcImp::stype() ) && + parents[1]->imp()->inherits( AbstractLineImp::stype() ) ) || + ( parents[1]->imp()->inherits( ArcImp::stype() ) && + parents[0]->imp()->inherits( AbstractLineImp::stype() ) ) ) + type = ArcLineIntersectionType::instance(); + else + { + notSupported( file, i18n( "This Dr. Geo file contains an intersection type, " + "which Kig does not currently support." ) ); + return false; + } + oc = new ObjectTypeCalcer( type, args ); + } + } + else if ( domelem.attribute( "type" ) == "Reflexion" ) + oc = new ObjectTypeCalcer( LineReflectionType::instance(), parents ); + else if ( domelem.attribute( "type" ) == "Symmetry" ) + oc = new ObjectTypeCalcer( PointReflectionType::instance(), parents ); + else if ( domelem.attribute( "type" ) == "Translation" ) + oc = new ObjectTypeCalcer( TranslatedType::instance(), parents ); + else if ( domelem.attribute( "type" ) == "Rotation" ) + oc = new ObjectTypeCalcer( RotationType::instance(), parents ); + else + { + notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, " + "which Kig does not currently support." ).arg( domelem.tagName() ).arg( + domelem.attribute( "type" ) ) ); + return false; + } +#ifdef DRGEO_DEBUG + kdDebug() << "+++++++++ oc:" << oc << endl; +#endif + } + else if( ( domelem.tagName() == "line" ) || + ( domelem.tagName() == "halfLine" ) || + ( domelem.tagName() == "segment" ) || + ( domelem.tagName() == "vector" ) || + ( domelem.tagName() == "circle" ) || + ( domelem.tagName() == "arcCircle" ) || + ( domelem.tagName() == "polygon" ) ) + { + const ObjectType* type = 0; + if ( domelem.attribute( "type" ) == "2pts" ) + { + if( domelem.tagName() == "line" ) + type = LineABType::instance(); + else if( domelem.tagName() == "halfLine" ) + type = RayABType::instance(); + else if( domelem.tagName() == "segment" ) + type = SegmentABType::instance(); + else if( domelem.tagName() == "vector" ) + type = VectorType::instance(); + else if( domelem.tagName() == "circle" ) + type = CircleBCPType::instance(); + else + { + notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, " + "which Kig does not currently support." ).arg( domelem.tagName() ).arg( + domelem.attribute( "type" ) ) ); + return false; + } + oc = new ObjectTypeCalcer( type, parents ); + } + else if( domelem.attribute( "type" ) == "3pts" ) + { + if( domelem.tagName() == "arcCircle" ) + type = ArcBTPType::instance(); + else + { + notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, " + "which Kig does not currently support." ).arg( domelem.tagName() ).arg( + domelem.attribute( "type" ) ) ); + return false; + } + oc = new ObjectTypeCalcer( type, parents ); + } + else if( domelem.attribute( "type" ) == "segment" ) + { + if( domelem.tagName() == "circle" ) + { + type = CircleBPRType::instance(); + ObjectPropertyCalcer* o = fact->propertyObjectCalcer( parents[1], "length" ); + o->calc( *ret ); + ObjectCalcer* a = parents[0]; + parents.clear(); + parents.push_back( a ); + parents.push_back( o ); + } + else + { + notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, " + "which Kig does not currently support." ).arg( domelem.tagName() ).arg( + domelem.attribute( "type" ) ) ); + return false; + } + oc = new ObjectTypeCalcer( type, parents ); + } + else if( domelem.attribute( "type" ) == "npts" ) + { + if( domelem.tagName() == "polygon" ) + { + if ( parents.size() < 3 ) KIG_FILTER_PARSE_ERROR; + type = PolygonBNPType::instance(); + } + else + { + notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, " + "which Kig does not currently support." ).arg( domelem.tagName() ).arg( + domelem.attribute( "type" ) ) ); + return false; + } + oc = new ObjectTypeCalcer( type, parents ); + } + else if ( domelem.attribute( "type" ) == "perpendicular" ) + oc = new ObjectTypeCalcer( LinePerpendLPType::instance(), parents ); + else if ( domelem.attribute( "type" ) == "parallel" ) + oc = new ObjectTypeCalcer( LineParallelLPType::instance(), parents ); + else if ( domelem.attribute( "type" ) == "Reflexion" ) + oc = new ObjectTypeCalcer( LineReflectionType::instance(), parents ); + else if ( domelem.attribute( "type" ) == "Symmetry" ) + oc = new ObjectTypeCalcer( PointReflectionType::instance(), parents ); + else if ( domelem.attribute( "type" ) == "Translation" ) + oc = new ObjectTypeCalcer( TranslatedType::instance(), parents ); + else if ( domelem.attribute( "type" ) == "Rotation" ) + oc = new ObjectTypeCalcer( RotationType::instance(), parents ); + else + { + notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, " + "which Kig does not currently support." ).arg( domelem.tagName() ).arg( + domelem.attribute( "type" ) ) ); + return false; + } +#ifdef DRGEO_DEBUG + kdDebug() << "+++++++++ oc:" << oc << endl; +#endif + } + else if( ( domelem.tagName() == "numeric" ) || + ( domelem.tagName() == "equation" ) ) + { + QString xs; + QString ys; + QString value; + for ( QDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() ) + { + QDomElement ce = c.toElement(); + if ( ce.isNull() ) continue; + else if ( ce.tagName() == "x" ) + xs = ce.text(); + else if ( ce.tagName() == "y" ) + ys = ce.text(); + else if ( ce.tagName() == "value" ) + value = ce.text(); + } + bool ok; + bool ok2; + double x = xs.toDouble( &ok ); + double y = ys.toDouble( &ok2 ); + if ( ! ( ok && ok2 ) ) + KIG_FILTER_PARSE_ERROR; + Coordinate m( x, y ); + // types of 'numeric' + // ugly hack to show value numerics... + if ( domelem.attribute( "type" ) == "value" ) + { + bool ok3; + double dvalue = value.toDouble( &ok3 ); + if ( ok3 ) + value = QString( "%1" ).arg( dvalue, 0, 'g', 3 ); + oc = fact->labelCalcer( value, m, false, std::vector<ObjectCalcer*>(), *ret ); + } + else if ( domelem.attribute( "type" ) == "pt_abscissa" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + oc = filtersConstructTextObject( m, parents[0], "coordinate-x", *ret, false ); + } + else if ( domelem.attribute( "type" ) == "pt_ordinate" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + oc = filtersConstructTextObject( m, parents[0], "coordinate-y", *ret, false ); + } + else if ( domelem.attribute( "type" ) == "segment_length" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + oc = filtersConstructTextObject( m, parents[0], "length", *ret, false ); + } + else if ( domelem.attribute( "type" ) == "circle_perimeter" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + oc = filtersConstructTextObject( m, parents[0], "circumference", *ret, false ); + } + else if ( domelem.attribute( "type" ) == "arc_length" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + oc = filtersConstructTextObject( m, parents[0], "arc-length", *ret, false ); + } + else if ( domelem.attribute( "type" ) == "distance_2pts" ) + { + if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR; + ObjectTypeCalcer* so = new ObjectTypeCalcer( SegmentABType::instance(), parents ); + so->calc( *ret ); + oc = filtersConstructTextObject( m, so, "length", *ret, false ); + } + else if ( domelem.attribute( "type" ) == "vector_norm" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + oc = filtersConstructTextObject( m, parents[0], "length", *ret, false ); + } + else if ( domelem.attribute( "type" ) == "vector_abscissa" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + oc = filtersConstructTextObject( m, parents[0], "length-x", *ret, false ); + } + else if ( domelem.attribute( "type" ) == "vector_ordinate" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + oc = filtersConstructTextObject( m, parents[0], "length-y", *ret, false ); + } + else if ( domelem.attribute( "type" ) == "slope" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + oc = filtersConstructTextObject( m, parents[0], "slope", *ret, false ); + } + else if ( domelem.attribute( "type" ) == "distance_pt_line" ) + { + if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR; + std::vector<ObjectCalcer*> args; + args.push_back( parents[1] ); + args.push_back( parents[0] ); + ObjectTypeCalcer* po = new ObjectTypeCalcer( LinePerpendLPType::instance(), args ); + po->calc( *ret ); + args.clear(); + args.push_back( parents[1] ); + args.push_back( po ); + ObjectTypeCalcer* io = new ObjectTypeCalcer( LineLineIntersectionType::instance(), args ); + io->calc( *ret ); + args.clear(); + args.push_back( parents[0] ); + args.push_back( io ); + ObjectTypeCalcer* so = new ObjectTypeCalcer( SegmentABType::instance(), args ); + so->calc( *ret ); + oc = filtersConstructTextObject( m, so, "length", *ret, false ); + } + // types of 'equation' + else if ( domelem.attribute( "type" ) == "line" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + oc = filtersConstructTextObject( m, parents[0], "equation", *ret, false ); + } + else if ( domelem.attribute( "type" ) == "circle" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + oc = filtersConstructTextObject( m, parents[0], "simply-cartesian-equation", *ret, false ); + } + else + { + notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, " + "which Kig does not currently support." ).arg( domelem.tagName() ).arg( + domelem.attribute( "type" ) ) ); + return false; + } +#ifdef DRGEO_DEBUG + kdDebug() << "+++++++++ oc:" << oc << endl; +#endif + } + else if ( domelem.tagName() == "angle" ) + { + if ( domelem.attribute( "type" ) == "3pts" ) + { + if ( parents.size() != 3 ) KIG_FILTER_PARSE_ERROR; + oc = new ObjectTypeCalcer( HalfAngleType::instance(), parents ); + } + else + { + notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, " + "which Kig does not currently support." ).arg( domelem.tagName() ).arg( + domelem.attribute( "type" ) ) ); + return false; + } +#ifdef DRGEO_DEBUG + kdDebug() << "+++++++++ oc:" << oc << endl; +#endif + } + else if ( domelem.tagName() == "script" ) + { + QString xs; + QString ys; + QString text; + for ( QDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() ) + { + QDomElement ce = c.toElement(); + if ( ce.isNull() ) continue; + else if ( ce.tagName() == "x" ) + xs = ce.text(); + else if ( ce.tagName() == "y" ) + ys = ce.text(); + else if ( ce.tagName() == "code" ) + text = ce.text(); + } + bool ok; + bool ok2; + double x = xs.toDouble( &ok ); + double y = ys.toDouble( &ok2 ); + if ( ! ( ok && ok2 ) ) + KIG_FILTER_PARSE_ERROR; + // since Kig doesn't support Guile scripts, it will write script's text + // in a label, so the user can freely see the code and make whatever + // he/she wants + // possible idea: construct a new script object with the parents of Guile + // one and the Guile code inserted commented... depends on a better + // handling of arguments in scripts? + if ( domelem.attribute( "type" ) == "nitems" ) + oc = fact->labelCalcer( text, Coordinate( x, y ), false, std::vector<ObjectCalcer*>(), *ret ); + else + { + notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, " + "which Kig does not currently support." ).arg( domelem.tagName() ).arg( + domelem.attribute( "type" ) ) ); + return false; + } + } + else if ( domelem.tagName() == "locus" ) + { + if ( domelem.attribute( "type" ) == "None" ) + oc = fact->locusCalcer( parents[0], parents[1] ); + else + { + notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, " + "which Kig does not currently support." ).arg( domelem.tagName() ).arg( + domelem.attribute( "type" ) ) ); + return false; + } +#ifdef DRGEO_DEBUG + kdDebug() << "+++++++++ oc:" << oc << endl; +#endif + } + else if ( ( domelem.tagName() == "boundingBox" ) || + ( domelem.tagName() == "customUI" ) ) + { + // ignoring these elements, since they are not useful to us... + nignored++; + } + else + { +#ifdef DRGEO_DEBUG + kdDebug() << ">>>>>>>>> UNKNOWN OBJECT" << endl; +#endif + notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, " + "which Kig does not currently support." ).arg( domelem.tagName() ).arg( + domelem.attribute( "type" ) ) ); + return false; + } + curid++; + if ( oc == 0 ) + continue; + +// reading color + QColor co( domelem.attribute( "color" ) ); + if ( ! co.isValid() ) + if ( domelem.attribute( "color" ) == "Bordeaux" ) + co.setRgb( 145, 0, 0 ); + else + co = Qt::blue; +// reading width and style +// Dashed -> the little one +// Normal -> the medium +// Thick -> the biggest one + int w = -1; + Qt::PenStyle s = Qt::SolidLine; + if ( domelem.tagName() == "point" ) + { + if ( domelem.attribute( "thickness" ) == "Normal" ) + w = 7; + else if ( domelem.attribute( "thickness" ) == "Thick" ) + w = 9; + } + else + { + if ( domelem.attribute( "thickness" ) == "Dashed" ) + s = Qt::DotLine; + if ( domelem.attribute( "thickness" ) == "Thick" ) + w = 2; + } + QString ps = domelem.attribute( "style" ); + int pointstyle = ObjectDrawer::pointStyleFromString( ps ); +// show this object? + bool show = ( ( domelem.attribute( "masked" ) != "True" ) && + ( domelem.attribute( "masked" ) != "Alway" ) ); +// costructing the ObjectDrawer* + ObjectDrawer* d = new ObjectDrawer( co, w, show, s, pointstyle ); +// reading object name + QString strname = domelem.attribute( "name" ); + ObjectConstCalcer* name = new ObjectConstCalcer( new StringImp( strname ) ); + +// creating the ObjectHolder* + ObjectHolder* o = new ObjectHolder( oc, d, name ); + holders.push_back( o ); +// calc() +#ifdef DRGEO_DEBUG + kdDebug() << ">>>>>>>>> calc" << endl; +#endif + holders[curid-1-nignored]->calc( *ret ); + + if ( domelem.tagName() == "point" ) + { + if ( !strname.isEmpty() ) + { + std::vector<ObjectCalcer*> args2; + args2.push_back( o->nameCalcer() ); + oc2 = fact->attachedLabelCalcer( QString::fromLatin1( "%1" ), oc, + static_cast<const PointImp*>( oc->imp() )->coordinate(), + false, args2, *ret ); + co = Qt::black; + } + } + else if ( domelem.tagName() == "angle" ) + { + oc2 = filtersConstructTextObject( + static_cast<const PointImp*>( holders[curid-1-nignored]->calcer()->parents()[1]->imp() )->coordinate(), + holders[curid-1-nignored]->calcer(), "angle-degrees", *ret, false ); + } + + oc = 0; + + if ( oc2 != 0 ) + { + oc2->calc( *ret ); + ObjectDrawer* d2 = new ObjectDrawer( co ); + ObjectHolder* o2 = new ObjectHolder( oc2, d2 ); + holders2.push_back( o2 ); + oc2 = 0; + } + } + + ret->addObjects( holders ); + ret->addObjects( holders2 ); + ret->setGrid( grid ); + ret->setAxes( grid ); + return ret; +} + +KigFilterDrgeo* KigFilterDrgeo::instance() +{ + static KigFilterDrgeo f; + return &f; +} diff --git a/kig/filters/drgeo-filter.h b/kig/filters/drgeo-filter.h new file mode 100644 index 00000000..7485fd5b --- /dev/null +++ b/kig/filters/drgeo-filter.h @@ -0,0 +1,46 @@ +// Copyright (C) 2004 Pino Toscano <[email protected]> +// Copyright (C) 2004 Dominique Devriese <[email protected]> + +// 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_FILTERS_DRGEO_FILTER_H +#define KIG_FILTERS_DRGEO_FILTER_H + +#include "filter.h" + +class QDomNode; +class KigDocument; +class QString; + +/** + * This is an import filter for the GNOME geometry program DrGeo. + */ +class KigFilterDrgeo + : public KigFilter +{ +protected: + KigFilterDrgeo(); + ~KigFilterDrgeo(); +public: + static KigFilterDrgeo* instance(); + + bool supportMime( const QString& mime ); + KigDocument* load( const QString& file ); +private: + KigDocument* importFigure( QDomNode f, const QString& file, const bool grid ); +}; + +#endif diff --git a/kig/filters/exporter.cc b/kig/filters/exporter.cc new file mode 100644 index 00000000..c2ece44e --- /dev/null +++ b/kig/filters/exporter.cc @@ -0,0 +1,624 @@ +// Copyright (C) 2003 Dominique Devriese <[email protected]> + +// 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 "exporter.h" + +#include "imageexporteroptions.h" +#include "latexexporter.h" +#include "svgexporter.h" + +#include "../kig/kig_document.h" +#include "../kig/kig_part.h" +#include "../kig/kig_view.h" +#include "../misc/common.h" +#include "../misc/kigfiledialog.h" +#include "../misc/kigpainter.h" +#include "../objects/circle_imp.h" +#include "../objects/line_imp.h" +#include "../objects/object_drawer.h" +#include "../objects/object_holder.h" +#include "../objects/object_imp.h" +#include "../objects/other_imp.h" +#include "../objects/point_imp.h" +#include "../objects/text_imp.h" + +#include <qcheckbox.h> +#include <qcolor.h> +#include <qfile.h> +#include <qiconset.h> +#include <qtextstream.h> + +#include <kaction.h> +#include <kiconloader.h> +#include <kimageio.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <knuminput.h> + +#include <map> + +// we need this for storing colors in a std::map.. +static bool operator<( const QColor& a, const QColor& b ) +{ + return a.rgb() < b.rgb(); +} + +class ExporterAction + : public KAction +{ + KigExporter* mexp; + const KigPart* mdoc; + KigWidget* mw; +public: + ExporterAction( const KigPart* doc, KigWidget* w, + KActionCollection* parent, KigExporter* exp ); + void slotActivated(); +}; + +ExporterAction::ExporterAction( const KigPart* doc, KigWidget* w, + KActionCollection* parent, KigExporter* exp ) + : KAction( exp->menuEntryName(), KShortcut(), 0, 0, parent ), + mexp( exp ), mdoc( doc ), mw( w ) +{ + QString iconstr = exp->menuIcon(); + if ( iconstr.isEmpty() ) + return; + KIconLoader* l = doc->instance()->iconLoader(); + QPixmap icon = l->loadIcon( iconstr, KIcon::Small, 16, KIcon::DefaultState, 0L, true ); + if ( !icon.isNull() ) + setIconSet( QIconSet( icon ) ); +} + +void ExporterAction::slotActivated() +{ + mexp->run( *mdoc, *mw ); +} + +KigExporter::~KigExporter() +{ +} + +ImageExporter::~ImageExporter() +{ +} + +QString ImageExporter::exportToStatement() const +{ + return i18n( "&Export to image" ); +} + +QString ImageExporter::menuEntryName() const +{ + return i18n( "&Image..." ); +} + +QString ImageExporter::menuIcon() const +{ + return "image"; +} + +void ImageExporter::run( const KigPart& doc, KigWidget& w ) +{ + static bool kimageioRegistered = false; + if ( ! kimageioRegistered ) + { + KImageIO::registerFormats(); + kimageioRegistered = true; + } + + KigFileDialog* kfd = new KigFileDialog( + QString::null, KImageIO::pattern( KImageIO::Writing ), + i18n( "Export as Image" ), &w ); + kfd->setOptionCaption( i18n( "Image Options" ) ); + ImageExporterOptions* opts = new ImageExporterOptions( 0L, w.size() ); + kfd->setOptionsWidget( opts ); + opts->WidthInput->setValue( w.size().width() ); + opts->HeightInput->setValue( w.size().height() ); + opts->showGridCheckBox->setChecked( doc.document().grid() ); + opts->showAxesCheckBox->setChecked( doc.document().axes() ); + if ( !kfd->exec() ) + return; + + QString filename = kfd->selectedFile(); + bool showgrid = opts->showGridCheckBox->isOn(); + bool showaxes = opts->showAxesCheckBox->isOn(); + int width = opts->WidthInput->value(); + int height = opts->HeightInput->value(); + + delete opts; + delete kfd; + + QString type = KImageIO::type( filename ); + if ( type.isNull() ) + { + KMessageBox::sorry( &w, i18n( "Sorry, this file format is not supported." ) ); + return; + }; + + kdDebug() << k_funcinfo << type << endl; + + QFile file( filename ); + if ( ! file.open( IO_WriteOnly ) ) + { + KMessageBox::sorry( &w, + i18n( "The file \"%1\" could not be opened. Please check if the file permissions are set correctly." ) + .arg( filename ) ); + return; + }; + + QPixmap img( QSize( width, height ) ); + img.fill( Qt::white ); + KigPainter p( ScreenInfo( w.screenInfo().shownRect(), img.rect() ), &img, doc.document() ); + p.setWholeWinOverlay(); + p.drawGrid( doc.document().coordinateSystem(), showgrid, showaxes ); + // FIXME: show the selections ? + p.drawObjects( doc.document().objects(), false ); + if ( ! img.save( filename, type.latin1() ) ) + { + KMessageBox::error( &w, i18n( "Sorry, something went wrong while saving to image \"%1\"" ).arg( filename ) ); + } + +} + +KigExportManager::KigExportManager() +{ + mexporters.push_back( new ImageExporter ); + // working on this one ;) + mexporters.push_back( new XFigExporter ); + mexporters.push_back( new LatexExporter ); + mexporters.push_back( new SVGExporter ); +} + +KigExportManager::~KigExportManager() +{ + for ( uint i = 0; i < mexporters.size(); ++i ) + delete mexporters[i]; +} + +void KigExportManager::addMenuAction( const KigPart* doc, KigWidget* w, + KActionCollection* coll ) +{ + KActionMenu* m = + new KActionMenu( i18n( "&Export To" ), coll, "file_export" ); + for ( uint i = 0; i < mexporters.size(); ++i ) + m->insert( new ExporterAction( doc, w, coll, mexporters[i] ) ); +} + +KigExportManager* KigExportManager::instance() +{ + static KigExportManager m; + return &m; +} + +XFigExporter::~XFigExporter() +{ +} + +QString XFigExporter::exportToStatement() const +{ + return i18n( "Export to &XFig file" ); +} + + +QString XFigExporter::menuEntryName() const +{ + return i18n( "&XFig File..." ); +} + +QString XFigExporter::menuIcon() const +{ + return "kig_xfig"; +} + +class XFigExportImpVisitor + : public ObjectImpVisitor +{ + QTextStream& mstream; + ObjectHolder* mcurobj; + const KigWidget& mw; + Rect msr; + std::map<QColor, int> mcolormap; + int mnextcolorid; + int mcurcolorid; + + QPoint convertCoord( const Coordinate& c ) + { + Coordinate ret = ( c - msr.bottomLeft() ); + ret.y = msr.height() - ret.y; +// kdDebug() << "msr: " << msr << endl +// << "ret: " << ret << endl +// << "c: " << c << endl; + ret *= 9450; + ret /= msr.width(); + return ret.toQPoint(); + } + + void emitLine( const Coordinate& a, const Coordinate& b, int width, bool vector = false ); +public: + void visit( ObjectHolder* obj ); + void mapColor( const ObjectDrawer* obj ); + + XFigExportImpVisitor( QTextStream& s, const KigWidget& w ) + : mstream( s ), mw( w ), msr( mw.showingRect() ), + mnextcolorid( 32 ) + { + // predefined colors in XFig.. + mcolormap[Qt::black] = 0; + mcolormap[Qt::blue] = 1; + mcolormap[Qt::green] = 2; + mcolormap[Qt::cyan] = 3; + mcolormap[Qt::red] = 4; + mcolormap[Qt::magenta] = 5; + mcolormap[Qt::yellow] = 6; + mcolormap[Qt::white] = 7; + } + void visit( const LineImp* imp ); + void visit( const PointImp* imp ); + void visit( const TextImp* imp ); + void visit( const AngleImp* imp ); + void visit( const VectorImp* imp ); + void visit( const LocusImp* imp ); + void visit( const CircleImp* imp ); + void visit( const ConicImp* imp ); + void visit( const CubicImp* imp ); + void visit( const SegmentImp* imp ); + void visit( const RayImp* imp ); + void visit( const ArcImp* imp ); +}; + +void XFigExportImpVisitor::mapColor( const ObjectDrawer* obj ) +{ + if ( ! obj->shown() ) return; + QColor color = obj->color(); + if ( mcolormap.find( color ) == mcolormap.end() ) + { + int newcolorid = mnextcolorid++; + mstream << "0 " + << newcolorid << " " + << color.name() << "\n"; + mcolormap[color] = newcolorid; + } +} + +void XFigExportImpVisitor::visit( ObjectHolder* obj ) +{ + if ( ! obj->drawer()->shown() ) return; + assert( mcolormap.find( obj->drawer()->color() ) != mcolormap.end() ); + mcurcolorid = mcolormap[ obj->drawer()->color() ]; + mcurobj = obj; + obj->imp()->visit( this ); +} + +void XFigExportImpVisitor::visit( const LineImp* imp ) +{ + Coordinate a = imp->data().a; + Coordinate b = imp->data().b; + calcBorderPoints( a, b, msr ); + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + + if ( a != b ) + emitLine( a, b, width ); +} + +void XFigExportImpVisitor::emitLine( const Coordinate& a, const Coordinate& b, int width, bool vector ) +{ + mstream << "2 "; // polyline type; + mstream << "1 "; // polyline subtype; + mstream << "0 "; // line_style: Solid + mstream << width << " "; // thickness: *1/80 inch + mstream << mcurcolorid << " "; // pen_color: default + mstream << "7 "; // fill_color: white + mstream << "50 "; // depth: 50 + mstream << "-1 "; // pen_style: unused by XFig + mstream << "-1 "; // area_fill: no fill + mstream << "0.000 "; // style_val: the distance between dots and + // dashes in case of dotted or dashed lines.. + mstream << "0 "; // join_style: Miter + mstream << "0 "; // cap_style: Butt + mstream << "-1 "; // radius in case of an arc-box, but we're a + // polyline, so nothing here.. + if ( ! vector ) + mstream << "0 "; // forward arrow: no + else + mstream << "1 "; // forward arrow: yes + mstream << "0 "; // backward arrow: no + mstream << "2"; // a two points polyline.. + + mstream << "\n\t "; + + if ( vector ) + { + // first the arrow line in case of a vector.. + mstream << "1 " // arrow_type: closed triangle + << "1 " // arrow_style: filled with pen color.. + << "1.00 " // arrow_thickness: 1 + << "195.00 " // arrow_width + << "165.00 " // arrow_height + << "\n\t"; + } + QPoint ca = convertCoord( a ); + QPoint cb = convertCoord( b ); + + mstream << ca.x() << " " << ca.y() << " " << cb.x() << " " << cb.y() << "\n"; +} + +void XFigExportImpVisitor::visit( const PointImp* imp ) +{ + const QPoint center = convertCoord( imp->coordinate() ); + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 5; + width *= 10; + + mstream << "1 " // Ellipse type + << "3 " // circle defined by radius subtype + << "0 "; // line_style: Solid + mstream << "1 " << " " // thickness: *1/80 inch + << mcurcolorid << " " // pen_color: default + << mcurcolorid << " " // fill_color: black + << "50 " // depth: 50 + << "-1 " // pen_style: unused by XFig + << "20 " // area_fill: full saturation of the fill color + << "0.000 " // style_val: the distance between dots and + // dashes in case of dotted or dashed lines.. + << "1 " // direction: always 1 + << "0.0000 " // angle: the radius of the x-axis: 0 + << center.x() << " " << center.y() << " " // the center.. + << width << " " << width << " " // radius_x and radius_y + << center.x() << " " // start_x and start_y, appear + << center.y() << " " // unused.. + << center.x() + width << " " // end_x and end_y, + << center.y() << "\n"; // appear unused too... +} + +void XFigExportImpVisitor::visit( const TextImp* imp ) +{ + QString text = imp->text(); + QPoint coord = convertCoord( imp->surroundingRect().bottomLeft() ); + + mstream << "4 " // text type + << "0 " // subtype: left justfied + << mcurcolorid << " " // color: black + << "50 " // depth: 50 + << "-1 " // pen style: unused + << "0 " // font: default + << "11 " // font-size: 11 + << "0 " // angle + << "0 " // font-flags: all the defaults.. + << "500 500 " // height, width: large enough.. + << coord.x() << " " // x, y + << coord.y() << " " + << text.ascii() << "\\001" // text, terminated by \001 + << "\n"; +} + +void XFigExportImpVisitor::visit( const AngleImp* ) +{ +} + +void XFigExportImpVisitor::visit( const VectorImp* imp ) +{ + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + emitLine( imp->a(), imp->b(), width, true ); +} + +void XFigExportImpVisitor::visit( const LocusImp* ) +{ + +} + +void XFigExportImpVisitor::visit( const CircleImp* imp ) +{ + const QPoint center = convertCoord( imp->center() ); + const int radius = + ( convertCoord( imp->center() + Coordinate( imp->radius(), 0 ) ) - center ).x(); + + mstream << "1 " // Ellipse type + << "3 " // circle defined by radius subtype + << "0 "; // line_style: Solid + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + mstream << width << " " // thickness: *1/80 inch + << mcurcolorid << " " // pen_color: default + << "7 " // fill_color: white + << "50 " // depth: 50 + << "-1 " // pen_style: unused by XFig + << "-1 " // area_fill: no fill + << "0.000 " // style_val: the distance between dots and + // dashes in case of dotted or dashed lines.. + << "1 " // direction: always 1 + << "0.0000 " // angle: the radius of the x-axis: 0 + << center.x() << " " << center.y() << " " // the center.. + << radius << " " << radius << " " // radius_x and radius_y + << center.x() << " " // start_x and start_y, appear + << center.y() << " " // unused.. + << center.x() + radius << " " // end_x and end_y, + << center.y() << "\n"; // appear unused too... +} + +void XFigExportImpVisitor::visit( const ConicImp* imp ) +{ + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + if ( imp->conicType() == 1 ) + { + // an ellipse, this is good, cause this allows us to export to a + // real ellipse type.. + const ConicPolarData data = imp->polarData(); + + // gather some necessary data.. + // the angle of the x axis.. + double anglex = atan2( data.esintheta0, data.ecostheta0 ); + // the exentricity + double e = hypot( data.esintheta0, data.ecostheta0 ); + // the x radius is easy to find.. + double radiusx = data.pdimen / ( 1 - e * e ); + // the y radius is a bit harder: we first find the distance from + // the focus point to the mid point of the two focuses, this is: + double d = -e * data.pdimen / ( 1 - e * e ); + // the distance from the first focus to the intersection of the + // second axis with the conic equals radiusx: + double r = radiusx; + double radiusy = sqrt( r*r - d*d ); + + Coordinate center = data.focus1 - Coordinate( cos( anglex ), sin( anglex ) ).normalize( d ); + const QPoint qcenter = convertCoord( center ); + const int radius_x = ( convertCoord( center + Coordinate( radiusx, 0 ) ) - + convertCoord( center ) ).x(); + const int radius_y = ( convertCoord( center + Coordinate( radiusy, 0 ) ) - + convertCoord( center ) ).x(); + const QPoint qpoint2 = convertCoord( center + Coordinate( -sin( anglex ), cos( anglex ) ) * radiusy ); + + mstream << "1 " // ellipse type + << "1 " // subtype: ellipse defined by readii + << "0 " // line_style: Solid + << width << " " // thickness + << mcurcolorid << " " // pen_color: black + << "7 " // fill_color: white + << "50 " // depth: 50 + << "-1 " // pan_style: not used + << "-1 " // area_fill: no fill + << "0.000 " // style_val: not used + << "1 " // direction: always 1 + << anglex << " " // angle of the main axis + << qcenter.x() << " " // center + << qcenter.y() << " " + << radius_x << " " // radiuses + << radius_y << " " + << qcenter.x() << " " // start point + << qcenter.y() << " " + << qpoint2.x() << " " // end point + << qpoint2.y() << " "; + } + else return; +} + +void XFigExportImpVisitor::visit( const CubicImp* ) +{ +} + +void XFigExportImpVisitor::visit( const SegmentImp* imp ) +{ + Coordinate a = imp->data().a; + Coordinate b = imp->data().b; + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + + emitLine( a, b, width ); +} + +void XFigExportImpVisitor::visit( const RayImp* imp ) +{ + Coordinate a = imp->data().a; + Coordinate b = imp->data().b; + calcRayBorderPoints( a, b, msr ); + + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + + emitLine( a, b, width ); +} + +void XFigExportImpVisitor::visit( const ArcImp* imp ) +{ + const Coordinate center = imp->center(); + const double radius = imp->radius(); + const double startangle = imp->startAngle(); + const double endangle = startangle + imp->angle(); + const double middleangle = ( startangle + endangle ) / 2; + const Coordinate ad = Coordinate( cos( startangle ), sin( startangle ) ).normalize( radius ); + const Coordinate bd = Coordinate( cos( middleangle ), sin( middleangle ) ).normalize( radius ); + const Coordinate cd = Coordinate( cos( endangle ), sin( endangle ) ).normalize( radius ); + const QPoint a = convertCoord( center + ad ); + const QPoint b = convertCoord( center + bd ); + const QPoint c = convertCoord( center + cd ); + const QPoint cent = convertCoord( center ); + + mstream << "5 " // Ellipse type + << "1 " // subtype: open ended arc + << "0 "; // line_style: Solid + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + mstream << width << " " // thickness: *1/80 inch + << mcurcolorid << " " // pen_color: default + << "7 " // fill_color: white + << "50 " // depth: 50 + << "-1 " // pen_style: unused by XFig + << "-1 " // area_fill: no fill + << "0.000 " // style_val: the distance between dots and + // dashes in case of dotted or dashed lines.. + << "0 "; // cap_style: Butt.. + // 0 is clockwise, 1 is counterclockwise . + int direction = imp->angle() > 0 ? 1 : 0; + // direction next + mstream << direction << " " // direction.. + << "0 " // forward_arrow: no + << "0 " // backward_arrow: no + << cent.x() << " " << cent.y() << " " // the center.. + << a.x() << " " << a.y() << " " // x1, y1 + << b.x() << " " << b.y() << " " // x2, y2 + << c.x() << " " << c.y() << " " // x3, y3 + << "\n"; +} + +void XFigExporter::run( const KigPart& doc, KigWidget& w ) +{ + KigFileDialog* kfd = new KigFileDialog( + ":document", i18n( "*.fig|XFig Documents (*.fig)" ), + i18n( "Export as XFig File" ), &w ); + if ( !kfd->exec() ) + return; + + QString file_name = kfd->selectedFile(); + + delete kfd; + + QFile file( file_name ); + if ( ! file.open( IO_WriteOnly ) ) + { + KMessageBox::sorry( &w, i18n( "The file \"%1\" could not be opened. Please " + "check if the file permissions are set correctly." ) + .arg( file_name ) ); + return; + }; + QTextStream stream( &file ); + stream << "#FIG 3.2\n"; + stream << "Landscape\n"; + stream << "Center\n"; + stream << "Metric\n"; + stream << "A4\n"; + stream << "100.00\n"; + stream << "Single\n"; + stream << "-2\n"; + stream << "1200 2\n"; + + std::vector<ObjectHolder*> os = doc.document().objects(); + XFigExportImpVisitor visitor( stream, w ); + + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); + i != os.end(); ++i ) + { + visitor.mapColor( ( *i )->drawer() ); + }; + + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); + i != os.end(); ++i ) + { + visitor.visit( *i ); + }; +} diff --git a/kig/filters/exporter.h b/kig/filters/exporter.h new file mode 100644 index 00000000..4fc74453 --- /dev/null +++ b/kig/filters/exporter.h @@ -0,0 +1,102 @@ +// Copyright (C) 2003 Dominique Devriese <[email protected]> + +// 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_FILTERS_EXPORTER_H +#define KIG_FILTERS_EXPORTER_H + +#include <vector> + +class QString; +class KigDocument; +class KigPart; +class KigWidget; +class KActionCollection; + +class KigExporter; + +class KigExportManager +{ + std::vector<KigExporter*> mexporters; + KigExportManager(); + ~KigExportManager(); +public: + static KigExportManager* instance(); + void addMenuAction( const KigPart* doc, KigWidget* w, + KActionCollection* coll ); +}; + +/** + * Base class for a Kig exporter. + * + * Subclass it and implement its methods to have it working. + */ +class KigExporter +{ +public: + virtual ~KigExporter(); + + /** + * Returns a statement like i18n( "Export to image" ) + */ + virtual QString exportToStatement() const = 0; + /** + * Returns a string like i18n( "Image..." ) + */ + virtual QString menuEntryName() const = 0; + /** + * Returns a string with the name of the icon + */ + virtual QString menuIcon() const = 0; + + /** + * Do what you need to do. It's up to the individual exporters to + * ask the user for which file to export to etc., because they can + * do a much better job at that.. + */ + virtual void run( const KigPart& doc, KigWidget& w ) = 0; +}; + +/** + * This exporter takes care of the "Export to Image" stuff.. + */ +class ImageExporter + : public KigExporter +{ +public: + ~ImageExporter(); + QString exportToStatement() const; + QString menuEntryName() const; + QString menuIcon() const; + void run( const KigPart& doc, KigWidget& w ); +}; + +/** + * Guess what this one does ;) + * It exports to the XFig file format, as documented in the file + * FORMAT3.2 in the XFig source distribution. + */ +class XFigExporter + : public KigExporter +{ +public: + ~XFigExporter(); + QString exportToStatement() const; + QString menuEntryName() const; + QString menuIcon() const; + void run( const KigPart& doc, KigWidget& w ); +}; +#endif diff --git a/kig/filters/filter.cc b/kig/filters/filter.cc new file mode 100644 index 00000000..70290e8a --- /dev/null +++ b/kig/filters/filter.cc @@ -0,0 +1,114 @@ +/** + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese <[email protected]> + + 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 "filter.h" + +#include "kgeo-filter.h" +#include "cabri-filter.h" +#include "native-filter.h" +#include "kseg-filter.h" +#include "drgeo-filter.h" + +#include <kmessagebox.h> +#include <klocale.h> + +KigFilters* KigFilters::sThis; + +KigFilter* KigFilters::find(const QString& mime) +{ + for (vect::iterator i = mFilters.begin(); i != mFilters.end(); ++i) + { + if ((*i)->supportMime(mime)) return *i; + }; + return 0; +} + +KigFilters::KigFilters() +{ + mFilters.push_back( KigFilterKGeo::instance() ); + mFilters.push_back( KigFilterKSeg::instance() ); + mFilters.push_back( KigFilterCabri::instance() ); + mFilters.push_back( KigFilterNative::instance() ); + mFilters.push_back( KigFilterDrgeo::instance() ); +} + +KigFilters* KigFilters::instance() +{ + return sThis ? sThis : ( sThis = new KigFilters() ); +} + +KigFilter::KigFilter() +{ +} + +KigFilter::~KigFilter() +{ +} + +bool KigFilter::supportMime( const QString& ) +{ + return false; +} + +void KigFilter::fileNotFound( const QString& file ) const +{ + KMessageBox::sorry( 0, + i18n( "The file \"%1\" could not be opened. " + "This probably means that it does not " + "exist, or that it cannot be opened due to " + "its permissions" ).arg( file ) ); +} + +void KigFilter::parseError( const QString& file, const QString& explanation ) const +{ + const QString text = + i18n( "An error was encountered while parsing the file \"%1\". It " + "cannot be opened." ).arg( file ); + const QString title = i18n( "Parse Error" ); + + if ( explanation.isNull() ) + KMessageBox::sorry( 0, text, title ); + else + KMessageBox::detailedSorry( 0, text, explanation, title ); +} + +void KigFilter::notSupported( const QString& file, const QString& explanation ) const +{ + KMessageBox::detailedSorry( 0, + i18n( "Kig cannot open the file \"%1\"." ).arg( file ), + explanation, i18n( "Not Supported" ) ); +} + +void KigFilter::warning( const QString& explanation ) const +{ + KMessageBox::information( 0, explanation ); +} + +bool KigFilters::save( const KigDocument& data, const QString& tofile ) +{ + return KigFilterNative::instance()->save( data, tofile ); +} + +/* +bool KigFilters::save( const KigDocument& data, QTextStream& stream ) +{ + return KigFilterNative::instance()->save( data, stream ); +} +*/ diff --git a/kig/filters/filter.h b/kig/filters/filter.h new file mode 100644 index 00000000..f5d8b0f9 --- /dev/null +++ b/kig/filters/filter.h @@ -0,0 +1,96 @@ +// This file is part of Kig, a KDE program for Interactive Geometry... +// Copyright (C) 2002 Dominique Devriese <[email protected]> + +// 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 FILTER_H +#define FILTER_H + +#include <qstring.h> + +#include <vector> + +class KigFilter; +class ScreenInfo; +class KigDocument; + +/** + * This singleton class handles all the input filters. + */ +class KigFilters +{ +public: + static KigFilters* instance(); + KigFilter* find (const QString& mime); + +// bool save ( const KigDocument& data, QTextStream& stream ); + /** + * saving is always done with the native filter. We don't support + * output filters.. + */ + bool save ( const KigDocument& data, const QString& outfile ); +protected: + KigFilters(); + static KigFilters* sThis; + typedef std::vector<KigFilter*> vect; + vect mFilters; +}; + +// KigFilter::load functions should use this macro to conveniently +// return a very useful parse error in a filter's load function.. +#define KIG_FILTER_PARSE_ERROR \ + { \ + QString locs = i18n( "An error was encountered at " \ + "line %1 in file %2." ) \ + .arg( __LINE__ ).arg( __FILE__ ); \ + parseError( file, locs ); \ + return 0; \ + } + +/** + * This is the base class for an input filter. + * + * All the needed work to add a new input filter to Kig is + * subclassing this class and implement supportMime() and load(). + */ +class KigFilter +{ +protected: + // shows errors to the user.. + void fileNotFound( const QString& file ) const; + void parseError( const QString& file, const QString& explanation = QString::null ) const; + void notSupported( const QString& file, const QString& explanation ) const; + void warning( const QString& explanation ) const; +public: + KigFilter(); + virtual ~KigFilter(); + + /** + * can the filter handle the mimetype \p mime ? + */ + virtual bool supportMime ( const QString& mime ); + + /** + * load file \p fromfile and build a KigDocument from it.. If this + * function returns 0, that means that an error occurred while + * loading ( implementations of this function are responsible for + * showing an error message themselves, using the above error + * functions ). If this functions returns non-0, the caller owns + * the returned KigDocument ( that was allocated with "new" ). + */ + virtual KigDocument* load ( const QString& fromfile ) = 0; +}; +#endif diff --git a/kig/filters/filters-common.cc b/kig/filters/filters-common.cc new file mode 100644 index 00000000..d25c2e14 --- /dev/null +++ b/kig/filters/filters-common.cc @@ -0,0 +1,39 @@ +// Copyright (C) 2004 Dominique Devriese <[email protected]> + +// 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 "filters-common.h" + +#include <vector> + +#include <qcstring.h> +#include <qstring.h> + +#include "../objects/object_calcer.h" +#include "../objects/object_factory.h" + +ObjectTypeCalcer* filtersConstructTextObject( + const Coordinate& c, ObjectCalcer* o, + const QCString& arg, const KigDocument& doc, bool needframe ) +{ + const ObjectFactory* fact = ObjectFactory::instance(); + ObjectCalcer* propo = fact->propertyObjectCalcer( o, arg ); + propo->calc( doc ); + std::vector<ObjectCalcer*> args; + args.push_back( propo ); + return fact->labelCalcer( QString::fromLatin1( "%1" ), c, needframe, + args, doc ); +} diff --git a/kig/filters/filters-common.h b/kig/filters/filters-common.h new file mode 100644 index 00000000..c46facc4 --- /dev/null +++ b/kig/filters/filters-common.h @@ -0,0 +1,30 @@ +// Copyright (C) 2004 Dominique Devriese <[email protected]> + +// 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. + +class ObjectTypeCalcer; +class Coordinate; +class ObjectCalcer; +class QCString; +class KigDocument; + +/** + * constructs a text object with text "%1", location \p c, and variable + * parts given by the argument \p arg of obj \p o. + */ +ObjectTypeCalcer* filtersConstructTextObject( + const Coordinate& c, ObjectCalcer* o, + const QCString& arg, const KigDocument& doc, bool needframe ); diff --git a/kig/filters/imageexporteroptions.cc b/kig/filters/imageexporteroptions.cc new file mode 100644 index 00000000..cb996926 --- /dev/null +++ b/kig/filters/imageexporteroptions.cc @@ -0,0 +1,57 @@ +// Copyright (C) 2002 Dominique Devriese <[email protected]> + +// 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 "imageexporteroptions.h" +#include "imageexporteroptions.moc" + +#include <qcheckbox.h> +#include <qsize.h> + +#include <knuminput.h> + +ImageExporterOptions::ImageExporterOptions( QWidget* parent, const QSize& s ) + : ImageExporterOptionsBase( parent, "imageexporteroptions" ), msize( s ), + minternallysettingstuff( false ) +{ + keepAspectRatio->setChecked( true ); + connect( WidthInput, SIGNAL( valueChanged( int ) ), this, SLOT( slotWidthChanged( int ) ) ); + connect( HeightInput, SIGNAL( valueChanged( int ) ), this, SLOT( slotHeightChanged( int ) ) ); +} + +ImageExporterOptions::~ImageExporterOptions() +{ +} + +void ImageExporterOptions::slotWidthChanged( int w ) +{ + if ( ! minternallysettingstuff && keepAspectRatio->isOn() ) + { + minternallysettingstuff = true; + HeightInput->setValue( w * msize.height() / msize.width() ); + minternallysettingstuff = false; + }; +} + +void ImageExporterOptions::slotHeightChanged( int h ) +{ + if ( ! minternallysettingstuff && keepAspectRatio->isOn() ) + { + minternallysettingstuff = true; + WidthInput->setValue( h * msize.width() / msize.height() ); + minternallysettingstuff = false; + }; +} diff --git a/kig/filters/imageexporteroptions.h b/kig/filters/imageexporteroptions.h new file mode 100644 index 00000000..1ef6a855 --- /dev/null +++ b/kig/filters/imageexporteroptions.h @@ -0,0 +1,45 @@ +// Copyright (C) 2002 Dominique Devriese <[email protected]> + +// 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_FILTERS_IMAGEEXPORTEROPTIONS_H +#define KIG_FILTERS_IMAGEEXPORTEROPTIONS_H + +#include "imageexporteroptionsbase.h" + +class QSize; + +class ImageExporterOptions + : public ImageExporterOptionsBase +{ + Q_OBJECT + + QSize msize; + + // this is set by slotWidthChanged() when they set the other input + // widget's value, to avoid reacting to internal changes to the + // value like to user changes... + bool minternallysettingstuff; +public: + ImageExporterOptions( QWidget* parent, const QSize& s ); + ~ImageExporterOptions(); + +protected slots: + void slotWidthChanged( int ); + void slotHeightChanged( int ); +}; + +#endif diff --git a/kig/filters/imageexporteroptionsbase.ui b/kig/filters/imageexporteroptionsbase.ui new file mode 100644 index 00000000..03145dec --- /dev/null +++ b/kig/filters/imageexporteroptionsbase.ui @@ -0,0 +1,152 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>ImageExporterOptionsBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>ImageExporterOptionsBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>250</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Resolution</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout2_2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>WidthLabel_2</cstring> + </property> + <property name="text"> + <string>Width:</string> + </property> + </widget> + <widget class="KIntNumInput"> + <property name="name"> + <cstring>WidthInput</cstring> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="suffix"> + <string> pixels</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout3_2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>HeightLabel_2</cstring> + </property> + <property name="text"> + <string>Height:</string> + </property> + </widget> + <widget class="KIntNumInput"> + <property name="name"> + <cstring>HeightInput</cstring> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="suffix"> + <string> pixels</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>keepAspectRatio</cstring> + </property> + <property name="text"> + <string>&Keep aspect ratio</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Options</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>showGridCheckBox</cstring> + </property> + <property name="text"> + <string>Show grid</string> + </property> + </widget> + <widget class="QCheckBox" row="0" column="1"> + <property name="name"> + <cstring>showAxesCheckBox</cstring> + </property> + <property name="text"> + <string>Show axes</string> + </property> + </widget> + </grid> + </widget> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/kig/filters/kgeo-filter.cc b/kig/filters/kgeo-filter.cc new file mode 100644 index 00000000..da26457d --- /dev/null +++ b/kig/filters/kgeo-filter.cc @@ -0,0 +1,374 @@ +/** + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese <[email protected]> + + 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 "kgeo-filter.h" + +#include "kgeo-resource.h" +#include "filters-common.h" + +#include "../kig/kig_part.h" +#include "../kig/kig_document.h" +#include "../objects/angle_type.h" +#include "../objects/bogus_imp.h" +#include "../objects/circle_imp.h" +#include "../objects/circle_type.h" +#include "../objects/intersection_types.h" +#include "../objects/line_type.h" +#include "../objects/object_calcer.h" +#include "../objects/object_drawer.h" +#include "../objects/object_factory.h" +#include "../objects/object_holder.h" +#include "../objects/other_type.h" +#include "../objects/point_imp.h" +#include "../objects/point_type.h" +#include "../objects/text_type.h" +#include "../objects/transform_types.h" +#include "../objects/vector_type.h" + +#include <ksimpleconfig.h> + +#include <algorithm> +#include <functional> + +bool KigFilterKGeo::supportMime( const QString& mime ) +{ + return mime == "application/x-kgeo"; +} + +KigDocument* KigFilterKGeo::load( const QString& sFrom ) +{ + // kgeo uses a KSimpleConfig to save its contents... + KSimpleConfig config ( sFrom ); + + loadMetrics ( &config ); + return loadObjects ( sFrom, &config ); +} + +void KigFilterKGeo::loadMetrics(KSimpleConfig* c ) +{ + c->setGroup("Main"); + xMax = c->readNumEntry("XMax", 16); + yMax = c->readNumEntry("YMax", 11); + grid = c->readBoolEntry( "Grid", true ); + axes = c->readBoolEntry( "Axes", true ); + // the rest is not relevant to us (yet ?)... +} + +struct KGeoHierarchyElement +{ + int id; + std::vector<int> parents; +}; + +static void visitElem( std::vector<KGeoHierarchyElement>& ret, + const std::vector<KGeoHierarchyElement>& elems, + std::vector<bool>& seen, + int i ) +{ + if ( !seen[i] ) + { + for ( uint j = 0; j < elems[i].parents.size(); ++j ) + visitElem( ret, elems, seen, elems[i].parents[j] ); + ret.push_back( elems[i] ); + seen[i] = true; + }; +} + +static std::vector<KGeoHierarchyElement> sortElems( const std::vector<KGeoHierarchyElement> elems ) +{ + std::vector<KGeoHierarchyElement> ret; + std::vector<bool> seenElems( elems.size(), false ); + for ( uint i = 0; i < elems.size(); ++i ) + visitElem( ret, elems, seenElems, i ); + return ret; +} + +KigDocument* KigFilterKGeo::loadObjects( const QString& file, KSimpleConfig* c ) +{ + KigDocument* ret = new KigDocument(); + + using namespace std; + + QString group; + bool ok = true; + c->setGroup("Main"); + int number = c->readNumEntry ("Number"); + + // first we determine the parent relationships, and sort the + // elements in an order that we can be sure all of an object's + // parents will have been handled before it is handled itself.. + // ( aka topological sort of the parent relations graph.. + std::vector<KGeoHierarchyElement> elems; + elems.reserve( number ); + + for ( int i = 0; i < number; ++i ) + { + KGeoHierarchyElement elem; + elem.id = i; + group.setNum( i + 1 ); + group.prepend( "Object " ); + c->setGroup( group ); + QStrList parents; + c->readListEntry( "Parents", parents ); + elems.push_back( elem ); + for ( const char* parent = parents.first(); parent; parent = parents.next() ) + { + int parentIndex = QString::fromLatin1( parent ).toInt( &ok ); + if ( ! ok ) KIG_FILTER_PARSE_ERROR; + if ( parentIndex != 0 ) + elems[i].parents.push_back( parentIndex - 1 ); + }; + }; + + std::vector<KGeoHierarchyElement> sortedElems = sortElems( elems ); + std::vector<ObjectHolder*> os; + os.resize( number, 0 ); + const ObjectFactory* factory = ObjectFactory::instance(); + + // now we iterate over the elems again in the newly determined + // order.. + for ( uint i = 0; i < sortedElems.size(); ++i ) + { + const KGeoHierarchyElement& e = sortedElems[i]; + int id = e.id; + group.setNum( id + 1 ); + group.prepend( "Object " ); + c->setGroup( group ); + int objID = c->readNumEntry( "Geo" ); + + std::vector<ObjectCalcer*> parents; + for ( uint j = 0; j < e.parents.size(); ++j ) + { + int parentid = e.parents[j]; + parents.push_back( os[parentid]->calcer() ); + }; + + ObjectCalcer* o = 0; + switch (objID) + { + case ID_point: + { + // fetch the coordinates... + QString strX = c->readEntry("QPointX"); + QString strY = c->readEntry("QPointY"); + double x = strX.toDouble(&ok); + if (!ok) KIG_FILTER_PARSE_ERROR; + double y = strY.toDouble(&ok); + if (!ok) KIG_FILTER_PARSE_ERROR; + Coordinate m( x, y ); + uint nparents = parents.size(); + if ( nparents == 0 ) + o = factory->fixedPointCalcer( m ); + else if ( nparents == 1 ) + o = factory->constrainedPointCalcer( parents[0], m, *ret ); + else + KIG_FILTER_PARSE_ERROR; + break; + } + case ID_segment: + { + o = new ObjectTypeCalcer( SegmentABType::instance(), parents ); + break; + } + case ID_circle: + { + o = new ObjectTypeCalcer( CircleBCPType::instance(), parents ); + break; + } + case ID_line: + { + o = new ObjectTypeCalcer( LineABType::instance(), parents ); + break; + } + case ID_bisection: + { + // if this is the bisection of two points, first build a segment + // between them.. + if ( parents.size() == 2 ) + { + ObjectTypeCalcer* seg = new ObjectTypeCalcer( SegmentABType::instance(), parents ); + parents.clear(); + parents.push_back( seg ); + } + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + o = factory->propertyObjectCalcer( parents[0], "mid-point" ); + break; + }; + case ID_perpendicular: + { + o = new ObjectTypeCalcer( LinePerpendLPType::instance(), parents ); + break; + } + case ID_parallel: + { + o = new ObjectTypeCalcer( LineParallelLPType::instance(), parents ); + break; + } + case ID_vector: + { + o = new ObjectTypeCalcer( VectorType::instance(), parents ); + break; + } + case ID_ray: + { + o = new ObjectTypeCalcer( RayABType::instance(), parents ); + break; + } + case ID_move: + { + o = new ObjectTypeCalcer( TranslatedType::instance(), parents ); + break; + } + case ID_mirrorPoint: + { + o = new ObjectTypeCalcer( PointReflectionType::instance(), parents ); + break; + } + case ID_pointOfConc: + { + o = new ObjectTypeCalcer( LineLineIntersectionType::instance(), parents ); + break; + } + case ID_text: + { + bool frame = c->readBoolEntry( "Frame" ); + double x = c->readDoubleNumEntry( "TextRectCenterX" ); + double y = c->readDoubleNumEntry( "TextRectCenterY" ); + QString text = c->readEntry( "TextRectEntry" ); + double height = c->readNumEntry( "TextRectHeight" ); + double width = c->readNumEntry( "TextRectWidth" ); + // we don't want the center, but the top left.. + x -= width / 80; + y -= height / 80; + o = factory->labelCalcer( + text, Coordinate( x, y ), frame, std::vector<ObjectCalcer*>(), *ret ); + break; + } + case ID_fixedCircle: + { + double r = c->readDoubleNumEntry( "Radius" ); + parents.push_back( new ObjectConstCalcer( new DoubleImp( r ) ) ); + o = new ObjectTypeCalcer( CircleBPRType::instance(), parents ); + break; + } + case ID_angle: + { + if ( parents.size() == 3 ) + { + ObjectTypeCalcer* ao = new ObjectTypeCalcer( AngleType::instance(), parents ); + ao->calc( *ret ); + parents.clear(); + parents.push_back( ao ); + }; + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + ObjectCalcer* angle = parents[0]; + parents.clear(); + const Coordinate c = + static_cast<const PointImp*>( angle->parents()[1]->imp() )->coordinate(); + o = filtersConstructTextObject( c, angle, "angle-degrees", *ret, true ); + break; + } + case ID_distance: + { + if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR; + ObjectTypeCalcer* segment = new ObjectTypeCalcer( SegmentABType::instance(), parents ); + segment->calc( *ret ); + Coordinate m = ( static_cast<const PointImp*>( parents[0]->imp() )->coordinate() + + static_cast<const PointImp*>( parents[1]->imp() )->coordinate() ) / 2; + o = filtersConstructTextObject( m, segment, "length", *ret, true ); + break; + } + case ID_arc: + { + o = new ObjectTypeCalcer( AngleType::instance(), parents ); + break; + } + case ID_area: + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + const CircleImp* circle = static_cast<const CircleImp*>( parents[0]->imp() ); + const Coordinate c = circle->center() + Coordinate( circle->radius(), 0 ); + o = filtersConstructTextObject( c, parents[0], "surface", *ret, true ); + break; + } + case ID_slope: + { + // if parents contains a segment, line, vector or whatever, we + // take its parents cause we want points.. + if ( parents.size() == 1 ) parents = parents[0]->parents(); + if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR; + const Coordinate c = ( + static_cast<const PointImp*>( parents[0]->imp() )->coordinate() + + static_cast<const PointImp*>( parents[1]->imp() )->coordinate() ) / 2; + ObjectTypeCalcer* line = new ObjectTypeCalcer( LineABType::instance(), parents ); + line->calc( *ret ); + o = filtersConstructTextObject( c, line, "slope", *ret, true ); + break; + } + case ID_circumference: + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + const CircleImp* c = static_cast<const CircleImp*>( parents[0]->imp() ); + const Coordinate m = c->center() + Coordinate( c->radius(), 0 ); + o = filtersConstructTextObject( m, parents[0], "circumference", *ret, true ); + break; + } + case ID_rotation: + { + // in kig, the rotated object should be last.. + ObjectCalcer* t = parents[2]; + parents[2] = parents[0]; + parents[0] = t; + o = new ObjectTypeCalcer( RotationType::instance(), parents ); + break; + } + default: + KIG_FILTER_PARSE_ERROR; + }; + + // set the color... + QColor co = c->readColorEntry( "Color" ); + if( !co.isValid() ) + co = Qt::blue; + ObjectDrawer* d = new ObjectDrawer( co ); + + os[i] = new ObjectHolder( o, d ); + os[i]->calc( *ret ); + }; // for loop (creating KGeoHierarchyElements.. + + ret->addObjects( os ); + ret->setGrid( grid ); + ret->setAxes( axes ); + return ret; +} + +KigFilterKGeo::KigFilterKGeo() +{ +} + +KigFilterKGeo::~KigFilterKGeo() +{ +} + +KigFilterKGeo* KigFilterKGeo::instance() +{ + static KigFilterKGeo f; + return &f; +} diff --git a/kig/filters/kgeo-filter.h b/kig/filters/kgeo-filter.h new file mode 100644 index 00000000..1a2ff83d --- /dev/null +++ b/kig/filters/kgeo-filter.h @@ -0,0 +1,55 @@ +// This file is part of Kig, a KDE program for Interactive Geometry... +// Copyright (C) 2002 Dominique Devriese <[email protected]> + +// 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_FILTERS_KGEO_FILTER_H +#define KIG_FILTERS_KGEO_FILTER_H + +#include "filter.h" + +class KSimpleConfig; + +/** + * This is an import filter for files generated by the program KGeo, + * which was an interactive geometry program in kdeedu. Kig is + * supposed to be its successor, and this import filter is part of my + * attempt to achieve that :) + * + * Status: a significant part of KGeo's format is supported, not all + * yet, though.. + */ +class KigFilterKGeo + : public KigFilter +{ +public: + static KigFilterKGeo* instance(); + bool supportMime ( const QString& mime ); + KigDocument* load ( const QString& from ); +protected: + KigFilterKGeo(); + ~KigFilterKGeo(); + + void loadMetrics ( KSimpleConfig* ); + KigDocument* loadObjects ( const QString& file, KSimpleConfig* ); + + int xMax; + int yMax; + bool grid; + bool axes; +}; + +#endif diff --git a/kig/filters/kgeo-resource.h b/kig/filters/kgeo-resource.h new file mode 100644 index 00000000..2a272ed0 --- /dev/null +++ b/kig/filters/kgeo-resource.h @@ -0,0 +1,204 @@ +/** + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese <[email protected]> + + 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 +**/ + + +/// note: this code comes from KGeo by Marc Bartsch.. + + +/*************************************************************************** + resource.h - description + ------------------- + begin : Die Okt 3 09:00:59 CEST 2000 + copyright : (C) 2000 by Marc Bartsch + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef RESOURCE_H +#define RESOURCE_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <iostream> +#include <qstring.h> +#include <klocale.h> + +/////////////////////////////////////////////////////////////////// +// resource.h -- contains macros used for commands + + +/////////////////////////////////////////////////////////////////// +// COMMAND VALUES FOR MENUBAR AND TOOLBAR ENTRIES + + +/////////////////////////////////////////////////////////////////// +// File-menu entries +#define ID_FILE_NEW_WINDOW 10010 +#define ID_FILE_NEW 10020 +#define ID_FILE_OPEN 10030 +#define ID_FILE_OPEN_RECENT 10040 +#define ID_FILE_CLOSE 10050 + +#define ID_FILE_SAVE 10060 +#define ID_FILE_SAVE_AS 10070 + +#define ID_FILE_PRINT 10080 + +#define ID_FILE_QUIT 10090 + +/////////////////////////////////////////////////////////////////// +// Edit-menu entries +#define ID_EDIT_COPY 11010 +#define ID_EDIT_CUT 11020 +#define ID_EDIT_PASTE 11030 +// domi: disabled, breaks --enable-final, and is not used anyway. +//#define ID_EDIT_PREFERENCES 11040 +#define ID_EDIT_FULLSCREEN 11050 + +/////////////////////////////////////////////////////////////////// +// View-menu entries +#define ID_VIEW_TOOLBAR 12010 +#define ID_VIEW_STATUSBAR 12020 +#define ID_VIEW_FULLSCREEN 12030 + +/////////////////////////////////////////////////////////////////// +// Help-menu entries +#define ID_HELP_CONTENTS 1002 + +/////////////////////////////////////////////////////////////////// +// General application values +#define ID_STATUS_MSG 1001 + +#define IDS_STATUS_DEFAULT "Ready." + +#define ID_infinite -1 + +#define ID_point 1 +#define ID_pointxy 14 +#define ID_pointOnLine 15 +#define ID_pointOfConc 7 +#define ID_bisection 5 +#define ID_mirrorPoint 9 + +#define ID_segment 2 +#define ID_circle 3 +#define ID_line 4 +#define ID_fixedCircle 6 +#define ID_arc 8 +#define ID_eraser 10 +#define ID_attacher 11 +#define ID_tracer 12 +#define ID_triangle 13 +#define ID_colorizer 16 +#define ID_thicker 17 +#define ID_geoPoint 18 +#define ID_geoTool 19 +#define ID_geoObject 20 +#define ID_geoMeasure 21 +#define ID_distance 22 +#define ID_angle 23 +#define ID_area 24 +#define ID_slope 25 +#define ID_circumference 26 +#define ID_vector 27 +#define ID_geoLine 28 +#define ID_ray 29 +#define ID_parallel 30 +#define ID_perpendicular 31 +#define ID_move 32 +#define ID_rotation 33 +#define ID_text 34 + +#define ID_buttonFileNew 100 +#define ID_buttonKiosk 101 + +#define ID_buttonPoint 110 +#define ID_buttonPointxy 111 +#define ID_buttonPointOnLine 112 +#define ID_buttonPointOfConc 113 +#define ID_buttonBisection 114 +#define ID_buttonMirrorPoint 115 +#define ID_buttonMove 116 +#define ID_buttonRotation 117 + +#define ID_buttonSegment 120 +#define ID_buttonLine 121 +#define ID_buttonVector 122 +#define ID_buttonRay 123 +#define ID_buttonParallel 124 +#define ID_buttonPerpendicular 125 +#define ID_buttonTriangle 126 + +#define ID_buttonBaseCircle 130 +#define ID_buttonCircle 131 +#define ID_buttonArc 132 + +#define ID_buttonDistance 140 +#define ID_buttonAngle 141 +#define ID_buttonArea 142 +#define ID_buttonSlope 143 +#define ID_buttonCircumference 144 + +#define ID_buttonBlack 150 +#define ID_buttonDarkGray 151 +#define ID_buttonLightGray 152 +#define ID_buttonWhite 153 +#define ID_buttonBlue 154 +#define ID_buttonRed 155 +#define ID_buttonGreen 156 + +#define ID_buttonThinLine 160 +#define ID_buttonMiddleLine 161 +#define ID_buttonThickLine 162 + +#define ID_buttonEraser 170 +#define ID_buttonAttacher 171 +#define ID_buttonTracer 172 +#define ID_buttonText 173 +#define ID_buttonMoveGrid 174 +#define ID_buttonPointer 175 +#define ID_buttonDrawColor 176 +#define ID_buttonSizer 177 + +#define ID_drawingModeNoMode 0 +#define ID_drawingModeMovingGrid 1 +#define ID_drawingModeMovingObjects 2 +#define ID_drawingModeConstructing 3 + +#define MinimumPointSize 3 + +#define Str_AppName "KGeo" + + +#define ID_overlayRectSize 24 + +#define PI 3.1415926535 + +#endif // RESOURCE_H diff --git a/kig/filters/kseg-defs.h b/kig/filters/kseg-defs.h new file mode 100644 index 00000000..ad90fa1a --- /dev/null +++ b/kig/filters/kseg-defs.h @@ -0,0 +1,301 @@ +// Copyright (C) 2003 Dominique Devriese <[email protected]> + +// 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. + +// this is a collection of definitions we need from KSeg. It includes +// code from defs.H and G_drawstyle.H. Thanks to Ilya Baran for +// making KSeg GPL, so there are no license probs or whatever.. + +/* + * KSeg + * Copyright (C) 1999-2003 Ilya Baran + * + * 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, Cambridge, MA 02110-1301, USA. + * + * Send comments and/or bug reports to: + */ + + +#ifndef DEFS_H +#define DEFS_H + +#include <stdio.h> +#include <stdlib.h> +#include <qglobal.h> + +using namespace std; + +#define DRAW_MAX 5000 // maximum coordinate. assumes you have a screen resolution less than this. + +#define BIG (1e+37) +#define SMALL (1e-10) + +inline int ROUND(double x) { return ((int)(x + 0.5)); } +inline int SIGN(double x) { return (x < 0) ? -1 : 1; } +inline int INTRAND(int a, int b) { return QMIN(a, b) + rand() % abs(a - b); } +#define SQR(x) ((x) * (x)) +#define CUBE(x) ((x) * (x) * (x)) +#define QUAD(x) (((x) * (x)) * ((x) * (x))) + +enum G_Type +{ + G_POINT = 1, + G_SEGMENT = 2, + G_RAY = 4, + G_LINE = 8, + G_CIRCLE = 16, + G_ARC = 32, + G_POLYGON = 64, + G_CIRCLEINTERIOR = 128, + G_ARCSECTOR = 256, + G_ARCSEGMENT = 512, + //non-primitive geometric types now: + G_LOCUS = 1024, + G_MEASURE = 2048, + G_CALCULATE = 4096, + G_ANNOTATION = 8192, + //fake type for scripting: + G_LOOP = 16384, + //compound types now: + G_STRAIGHT = G_SEGMENT | G_LINE | G_RAY, + G_CURVE = G_STRAIGHT | G_ARC | G_CIRCLE, + G_FILLED = G_POLYGON | G_CIRCLEINTERIOR | G_ARCSECTOR | G_ARCSEGMENT, + G_GEOMETRIC = G_POINT | G_CURVE | G_FILLED | G_LOCUS, + G_VALUE = G_MEASURE | G_CALCULATE, + G_TEXT = G_VALUE | G_ANNOTATION, + G_ANY = G_GEOMETRIC | G_TEXT | G_LOOP +}; + +enum G_AnyType +{ + G_TRANSLATED, + G_ROTATED, + G_SCALED, + G_REFLECTED +}; + +#define IS_TRANSFORM(x) ((x) == G_TRANSLATED || (x) == G_ROTATED || (x) == G_SCALED || (x) == G_REFLECTED) + +enum G_PointType +{ + G_FREE_POINT = G_REFLECTED + 1, + G_CONSTRAINED_POINT, + G_INTERSECTION_POINT, + G_INTERSECTION2_POINT, + G_MID_POINT +}; + +enum G_SegmentType +{ + G_ENDPOINTS_SEGMENT = G_REFLECTED + 1 +}; + +enum G_RayType +{ + G_TWOPOINTS_RAY = G_REFLECTED + 1, + G_BISECTOR_RAY +}; + +enum G_LineType +{ + G_TWOPOINTS_LINE = G_REFLECTED + 1, + G_PARALLEL_LINE, + G_PERPENDICULAR_LINE +}; + +enum G_CircleType +{ + G_CENTERPOINT_CIRCLE = G_REFLECTED + 1, + G_CENTERRADIUS_CIRCLE +}; + +enum G_ArcType +{ + G_THREEPOINTS_ARC = G_REFLECTED + 1 +}; + +enum G_FilledType +{ + G_DEFAULT_FILLED = G_REFLECTED + 1 +}; + +enum G_LocusType +{ + G_OBJECT_LOCUS = G_REFLECTED + 1 +}; + +enum G_MeasureType +{ + G_DISTANCE_MEASURE, + G_LENGTH_MEASURE, + G_RADIUS_MEASURE, + G_ANGLE_MEASURE, + G_RATIO_MEASURE, + G_SLOPE_MEASURE, + G_AREA_MEASURE +}; + +enum G_CalculateType +{ + G_REGULAR_CALCULATE +}; + + +enum MenuIDs +{ + ID_NEW_SEGMENT = 1, + ID_NEW_MIDPOINT, + ID_NEW_LINE, + ID_NEW_PERPENDICULAR, + ID_NEW_RAY, + ID_NEW_BISECTOR, + ID_NEW_CIRCLE, + ID_NEW_INTERSECTION, + ID_NEW_ARC, + ID_NEW_LOCUS, + ID_NEW_ARCSECTOR, + ID_NEW_ARCSEGMENT, + ID_NEW_CIRCLEINTERIOR, + ID_NEW_POLYGON, + + ID_EDIT_UNDO, + ID_EDIT_REDO, + ID_EDIT_DELETE, + ID_EDIT_TOGGLELABELS, + ID_EDIT_SHOWLABELS, + ID_EDIT_HIDELABELS, + ID_EDIT_CHANGELABEL, + ID_EDIT_HIDE, + ID_EDIT_SHOWHIDDEN, + ID_EDIT_COLOR, + ID_EDIT_POINTSTYLE, + ID_EDIT_LINESTYLE, + ID_EDIT_FONT, + ID_EDIT_CHANGE_NUMBER_OF_SAMPLES, + ID_EDIT_PREFERENCES, + + ID_EDIT_COLOR_BLACK, + ID_EDIT_COLOR_GRAY, + ID_EDIT_COLOR_RED, + ID_EDIT_COLOR_GREEN, + ID_EDIT_COLOR_BLUE, + ID_EDIT_COLOR_YELLOW, + ID_EDIT_COLOR_PURPLE, + ID_EDIT_COLOR_CYAN, + ID_EDIT_COLOR_OTHER, + + ID_EDIT_POINTSTYLE_LARGECIRCLE, + ID_EDIT_POINTSTYLE_MEDIUMCIRCLE, + ID_EDIT_POINTSTYLE_SMALLCIRCLE, + + ID_EDIT_LINESTYLE_SOLID, + ID_EDIT_LINESTYLE_DASHED, + ID_EDIT_LINESTYLE_DOTTED, + ID_EDIT_LINESTYLE_THIN, + ID_EDIT_LINESTYLE_NORMAL, + ID_EDIT_LINESTYLE_THICK, + + ID_EDIT_FONT_10, + ID_EDIT_FONT_12, + ID_EDIT_FONT_14, + ID_EDIT_FONT_20, + ID_EDIT_FONT_30, + ID_EDIT_FONT_FONT, + + ID_MEASURE_DISTANCE, + ID_MEASURE_LENGTH, + ID_MEASURE_RADIUS, + ID_MEASURE_ANGLE, + ID_MEASURE_RATIO, + ID_MEASURE_SLOPE, + ID_MEASURE_AREA, + ID_MEASURE_CALCULATE, + + ID_TRANSFORM_CHOOSE_VECTOR, + ID_TRANSFORM_CHOOSE_MIRROR, + ID_TRANSFORM_CHOOSE_CENTER, + ID_TRANSFORM_CHOOSE_RATIO, + ID_TRANSFORM_CHOOSE_ANGLE, + ID_TRANSFORM_CLEAR_CHOSEN, + ID_TRANSFORM_TRANSLATE, + ID_TRANSFORM_ROTATE, + ID_TRANSFORM_REFLECT, + ID_TRANSFORM_SCALE, + + ID_CONSTRUCTION_MAKE_NORMAL, + ID_CONSTRUCTION_MAKE_GIVEN, + ID_CONSTRUCTION_MAKE_FINAL, + ID_CONSTRUCTION_MAKE_INITIAL, + ID_CONSTRUCTION_RECURSE, + + ID_PLAY_QUICKPLAY, + + ID_QUICKPLAY_SET_DIRECTORY, + + ID_FILE_RECENTLIST_START //should be the last entry +}; + +#endif //DEFS_H + + +/* + * KSeg + * Copyright (C) 1999-2003 Ilya Baran + * + * 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, Cambridge, MA 02110-1301, USA. + * + * Send comments and/or bug reports to: + */ + + +#ifndef G_DRAWSTYLE_H +#define G_DRAWSTYLE_H + +enum PointStyle +{ + ANY = 0, + SMALL_CIRCLE, + MEDIUM_CIRCLE, + LARGE_CIRCLE +}; + +#endif //G_DRAWSTYLE_H diff --git a/kig/filters/kseg-filter-status.txt b/kig/filters/kseg-filter-status.txt new file mode 100644 index 00000000..eb896726 --- /dev/null +++ b/kig/filters/kseg-filter-status.txt @@ -0,0 +1,41 @@ +KSeg filter status +================== + +Objects imported +---------------- + +Points ok +Rays ok +Vectors ok +Lines ok +Circles ok +Angles ok +Arcs ok +Locuses some +Transformations most +Intersections most +Polygons ok +Labels ok + +Colors ok +Visibility ok +Styles ok +Grid ok + +Objects not imported +-------------------- + +Transformations scaling (with ratio as formula) (*) +Intersections arc-circle(*) +Filled circles (*) +Arc sectors (*) +Arc segments (*) +Formulas (*) + +(*) objects which currently are not implemented in Kig + +Known problems +-------------- + +* Some locuses may crash the filter. +* Label text should be correctly encoded. diff --git a/kig/filters/kseg-filter.cc b/kig/filters/kseg-filter.cc new file mode 100644 index 00000000..f2ba901b --- /dev/null +++ b/kig/filters/kseg-filter.cc @@ -0,0 +1,679 @@ +// Copyright (C) 2003 Dominique Devriese <[email protected]> + +// 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 "kseg-filter.h" + +#include "kseg-defs.h" + +#include "../kig/kig_document.h" +#include "../kig/kig_part.h" +#include "../misc/coordinate.h" +#include "../objects/angle_type.h" +#include "../objects/arc_type.h" +#include "../objects/bogus_imp.h" +#include "../objects/circle_type.h" +#include "../objects/conic_imp.h" +#include "../objects/conic_types.h" +#include "../objects/intersection_types.h" +#include "../objects/line_imp.h" +#include "../objects/line_type.h" +#include "../objects/object_calcer.h" +#include "../objects/object_drawer.h" +#include "../objects/object_factory.h" +#include "../objects/object_holder.h" +#include "../objects/other_imp.h" +#include "../objects/other_type.h" +#include "../objects/point_imp.h" +#include "../objects/point_type.h" +#include "../objects/polygon_type.h" +#include "../objects/transform_types.h" +#include "../objects/vector_type.h" + +#include <qfont.h> +#include <qpen.h> +#include <qbrush.h> +#include <qfile.h> +#include <qdatastream.h> +#include <qbuffer.h> + +#include <klocale.h> + +KigFilterKSeg::KigFilterKSeg() +{ +} + +KigFilterKSeg::~KigFilterKSeg() +{ +} + +bool KigFilterKSeg::supportMime( const QString& mime ) +{ + return mime == "application/x-kseg"; +} + +struct drawstyle +{ + Q_INT8 pointstyle; + QFont font; + QPen pen; + QBrush brush; +}; + +static Coordinate readKSegCoordinate( QDataStream& stream ) +{ + // read the coord.. + float inx, iny; + stream >> inx >> iny; + // KSeg uses a coordinate system, where the topleft is (0,0), and + // the bottom right is the widget coordinate in the window: if the + // KSeg window had a width of 600 pixels and a height of 600, then + // the bottom right will be at (600,600). We assume a window of + // such a height here, and transform it into Kig Coordinates. This + // function is quite similar to ScreenInfo::fromScreen, and it's + // basically a simple modification of that code to floats.. + + // invert the y-axis: 0 is at the bottom ! + Coordinate t( inx, 600 - iny ); + t *= 14; + t /= 600; + return t + Coordinate( -7, -7 ); +} + +static ObjectTypeCalcer* intersectionPoint( const std::vector<ObjectCalcer*>& parents, int which ) +{ + if ( parents.size() != 2 ) return 0; + int nlines = 0; + int nconics = 0; + int narcs = 0; + for ( int i = 0; i < 2; ++i ) + { + if ( parents[i]->imp()->inherits( AbstractLineImp::stype() ) ) ++nlines; + else if ( parents[i]->imp()->inherits( ConicImp::stype() ) ) ++nconics; + else if ( parents[i]->imp()->inherits( ArcImp::stype() ) ) ++narcs; + else return 0; + }; + if ( nlines == 2 ) + return which == -1 ? new ObjectTypeCalcer( LineLineIntersectionType::instance(), parents ) : 0; + else if ( nlines == 1 && nconics == 1 ) + { + std::vector<ObjectCalcer*> intparents( parents ); + intparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) ); + return new ObjectTypeCalcer( ConicLineIntersectionType::instance(), intparents ); + } + else if ( nlines == 0 && nconics == 2 ) + { + std::vector<ObjectCalcer*> rparents( parents ); + rparents.push_back( new ObjectConstCalcer( new IntImp( 1 ) ) ); + rparents.push_back( new ObjectConstCalcer( new IntImp( 1 ) ) ); + rparents.push_back( new ObjectTypeCalcer( ConicRadicalType::instance(), rparents ) ); + std::vector<ObjectCalcer*> iparents; + iparents.push_back( parents[0] ); + iparents.push_back( rparents.back() ); + iparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) ); + return new ObjectTypeCalcer( ConicLineIntersectionType::instance(), iparents ); + } + else if ( nlines == 1 && narcs == 1 ) + { + std::vector<ObjectCalcer*> intparents( parents ); + intparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) ); + return new ObjectTypeCalcer( ArcLineIntersectionType::instance(), intparents ); + } + else return 0; +} + +ObjectCalcer* KigFilterKSeg::transformObject( const QString& file, KigDocument& kigdoc, + std::vector<ObjectCalcer*>& parents, + int subtype, bool& ok ) +{ + ok = true; + ObjectCalcer* retobj = 0; + switch( subtype ) + { + case G_TRANSLATED: + { + std::vector<ObjectCalcer*> vectorparents( parents.begin() + 1, parents.end() ); + ObjectTypeCalcer* vector = new ObjectTypeCalcer( VectorType::instance(), vectorparents ); + vector->calc( kigdoc ); + + std::vector<ObjectCalcer*> transparents; + transparents.push_back( parents[0] ); + transparents.push_back( vector ); + retobj = new ObjectTypeCalcer( TranslatedType::instance(), transparents ); + break; + } + case G_ROTATED: + { + std::vector<ObjectCalcer*> angleparents( parents.begin() + 2, parents.end() ); + ObjectTypeCalcer* angle = new ObjectTypeCalcer( AngleType::instance(), angleparents ); + angle->calc( kigdoc ); + + std::vector<ObjectCalcer*> rotparents; + rotparents.push_back( parents[0] ); + rotparents.push_back( parents[1] ); + rotparents.push_back( angle ); + retobj = new ObjectTypeCalcer( RotationType::instance(), rotparents ); + break; + } + case G_SCALED: + { + if ( parents.size() == 4 ) + { + retobj = new ObjectTypeCalcer( ScalingOverCenter2Type::instance(), parents ); + } + else + { + // TODO + notSupported( file, i18n( "This KSeg document uses a scaling " + "transformation, which Kig currently " + "cannot import." ) ); + ok = false; + return 0; + } + break; + } + case G_REFLECTED: + { + std::vector<ObjectCalcer*> mirparents( parents.begin(), parents.end() ); + retobj = new ObjectTypeCalcer( LineReflectionType::instance(), mirparents ); + break; + } + } + + return retobj; +} + +KigDocument* KigFilterKSeg::load( const QString& file ) +{ + QFile ffile( file ); + if ( ! ffile.open( IO_ReadOnly ) ) + { + fileNotFound( file ); + return false; + }; + + KigDocument* retdoc = new KigDocument(); + + QDataStream fstream( &ffile ); + + QString versionstring; + fstream >> versionstring; + if ( !versionstring.startsWith( "KSeg Document Version " ) ) + KIG_FILTER_PARSE_ERROR; + + QByteArray array; + fstream >> array; + QBuffer buf( array ); + buf.open( IO_ReadOnly ); + QDataStream stream( &buf ); + + stream.setVersion( 3 ); + + // G_drawstyles: + short numstyles; + stream >> numstyles; + std::vector<drawstyle> drawstyles( numstyles ); + for ( short i = 0; i < numstyles; ++i ) + { + stream >> drawstyles[i].pointstyle; + stream >> drawstyles[i].font; + stream >> drawstyles[i].pen; + stream >> drawstyles[i].brush; + }; + + std::vector<ObjectHolder*> ret; + std::vector<ObjectHolder*> ret2; + + // G_refs + unsigned int count; + stream >> count; + + ret.resize( count, 0 ); + const ObjectFactory* fact = ObjectFactory::instance(); + + // KSeg topologically sorts the objects before saving, that means we + // can read the entire file in one iteration.. + for ( uint i = 0; i < count; ++i ) + { + short styleid; + stream >> styleid; + short nparents; + stream >> nparents; + std::vector<ObjectCalcer*> parents( nparents, 0 ); + for ( short j = 0; j < nparents; ++j ) + { + int parent; + stream >> parent; + parents[j] = ret[parent]->calcer(); + }; + + // read the object.. + short info; + stream >> info; + int type = 1 << (info & 31); + info >>= 5; + int descendtype = (info & 15); + info >>= 4; + bool visible = info & 1; + bool labelVisible = info & 2; + bool given = info & 4; + bool final = info & 8; + + // avoid g++ warnings about unused vars.. + // this doesn't really do anything.. + (void) given; + (void) final; + + drawstyle style = drawstyles[styleid]; + + if ( type == G_LOOP ) continue; + // read the label.. + QString labeltext; + stream >> labeltext; + Coordinate relcoord = readKSegCoordinate( stream ); + // shut up gcc + (void) relcoord; + if ( type & G_CURVE ) + { + Coordinate relcurvecoord = readKSegCoordinate( stream ); + // shut up gcc + (void) relcurvecoord; + }; + + // now load the object data.. + ObjectHolder* object = 0; + ObjectCalcer* o = 0; + bool ok = true; + + QColor color = style.pen.color(); + int width = style.pen.width(); + +/* + kdDebug() << "type: " << type << endl + << "descendtype: " << descendtype << endl + << "label: " << labeltext << endl; +//*/ + + switch ( type ) + { + case G_POINT: + { + switch( descendtype ) + { + case G_TRANSLATED: + case G_ROTATED: + case G_SCALED: + case G_REFLECTED: + { + o = transformObject( file, *retdoc, parents, descendtype, ok ); + break; + } + case G_FREE_POINT: + { + // fixed point + if ( nparents != 0 ) KIG_FILTER_PARSE_ERROR; + Coordinate c = readKSegCoordinate( stream ); + o = fact->fixedPointCalcer( c ); + break; + } + case G_CONSTRAINED_POINT: + { + // constrained point + double p; + stream >> p; + if ( nparents != 1 ) KIG_FILTER_PARSE_ERROR; + ObjectCalcer* parent = parents[0]; + assert( parent ); + o = fact->constrainedPointCalcer( parent, p ); + break; + } + case G_INTERSECTION_POINT: + { + // KSeg has somewhat weird intersection objects.. + // for all objects G_INTERSECTION_POINT gets the + // first intersection of its parents, G_INTERSECTION2_POINT + // represents the second, if present. + o = intersectionPoint( parents, -1 ); + if ( ! o ) KIG_FILTER_PARSE_ERROR; + break; + } + case G_INTERSECTION2_POINT: + { + o = intersectionPoint( parents, 1 ); + if ( ! o ) KIG_FILTER_PARSE_ERROR; + break; + } + case G_MID_POINT: + { + // midpoint of a segment.. + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + if ( !parents[0]->imp()->inherits( SegmentImp::stype() ) ) + KIG_FILTER_PARSE_ERROR; + int index = parents[0]->imp()->propertiesInternalNames().findIndex( "mid-point" ); + assert( index != -1 ); + o = new ObjectPropertyCalcer( parents[0], index ); + break; + } + default: + KIG_FILTER_PARSE_ERROR; + }; + width = style.pointstyle == SMALL_CIRCLE ? 2 : style.pointstyle == MEDIUM_CIRCLE ? 3 : 5; + color = style.brush.color(); + break; + }; + case G_SEGMENT: + { + switch( descendtype ) + { + case G_TRANSLATED: + case G_ROTATED: + case G_SCALED: + case G_REFLECTED: + { + o = transformObject( file, *retdoc, parents, descendtype, ok ); + break; + } + case G_ENDPOINTS_SEGMENT: + { + if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR; + o = new ObjectTypeCalcer( SegmentABType::instance(), parents ); + break; + } + default: + KIG_FILTER_PARSE_ERROR; + } + break; + }; + case G_RAY: + { + switch( descendtype ) + { + case G_TRANSLATED: + case G_ROTATED: + case G_SCALED: + case G_REFLECTED: + { + o = transformObject( file, *retdoc, parents, descendtype, ok ); + break; + } + case G_TWOPOINTS_RAY: + { + if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR; + o = new ObjectTypeCalcer( RayABType::instance(), parents ); + break; + } + case G_BISECTOR_RAY: + { + ObjectTypeCalcer* angle = new ObjectTypeCalcer( HalfAngleType::instance(), parents ); + angle->calc( *retdoc ); + o = fact->propertyObjectCalcer( angle, "angle-bisector" ); + break; + } + default: + KIG_FILTER_PARSE_ERROR; + }; + break; + }; + case G_LINE: + { + switch( descendtype ) + { + case G_TRANSLATED: + case G_ROTATED: + case G_SCALED: + case G_REFLECTED: + { + o = transformObject( file, *retdoc, parents, descendtype, ok ); + break; + } + case G_TWOPOINTS_LINE: + { + if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR; + o = new ObjectTypeCalcer( LineABType::instance(), parents ); + break; + } + case G_PARALLEL_LINE: + { + if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR; + o = new ObjectTypeCalcer( LineParallelLPType::instance(), parents ); + break; + } + case G_PERPENDICULAR_LINE: + { + if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR; + o = new ObjectTypeCalcer( LinePerpendLPType::instance(), parents ); + break; + } + default: + KIG_FILTER_PARSE_ERROR; + }; + break; + }; + case G_CIRCLE: + { + switch( descendtype ) + { + case G_TRANSLATED: + case G_ROTATED: + case G_SCALED: + case G_REFLECTED: + { + o = transformObject( file, *retdoc, parents, descendtype, ok ); + break; + } + case G_CENTERPOINT_CIRCLE: + { + if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR; + o = new ObjectTypeCalcer( CircleBCPType::instance(), parents ); + break; + } + case G_CENTERRADIUS_CIRCLE: + { + ObjectCalcer* point; + ObjectCalcer* segment; + if ( parents[0]->imp()->inherits( PointImp::stype() ) ) + { + point = parents[0]; + segment = parents[1]; + } + else + { + point = parents[1]; + segment = parents[0]; + }; + int index = segment->imp()->propertiesInternalNames().findIndex( "length" ); + if ( index == -1 ) KIG_FILTER_PARSE_ERROR; + ObjectPropertyCalcer* length = new ObjectPropertyCalcer( segment, index ); + length->calc( *retdoc ); + std::vector<ObjectCalcer*> cparents; + cparents.push_back( point ); + cparents.push_back( length ); + o = new ObjectTypeCalcer( CircleBPRType::instance(), cparents ); + break; + } + default: + KIG_FILTER_PARSE_ERROR; + }; + break; + }; + case G_ARC: + { + switch( descendtype ) + { + case G_TRANSLATED: + case G_ROTATED: + case G_SCALED: + case G_REFLECTED: + { + o = transformObject( file, *retdoc, parents, descendtype, ok ); + break; + } + case G_THREEPOINTS_ARC: + { + if ( nparents != 3 ) KIG_FILTER_PARSE_ERROR; + o = new ObjectTypeCalcer( ArcBTPType::instance(), parents ); + break; + } + default: + KIG_FILTER_PARSE_ERROR; + } + break; + }; + case G_POLYGON: + { + switch( descendtype ) + { + case G_TRANSLATED: + case G_ROTATED: + case G_SCALED: + case G_REFLECTED: + { + o = transformObject( file, *retdoc, parents, descendtype, ok ); + break; + } + default: + { + if ( nparents < 3 ) KIG_FILTER_PARSE_ERROR; + o = new ObjectTypeCalcer( PolygonBNPType::instance(), parents ); + } + } +// default: +// KIG_FILTER_PARSE_ERROR; + break; + }; + case G_CIRCLEINTERIOR: + { + notSupported( file, i18n( "This KSeg file contains a filled circle, " + "which Kig does not currently support." ) ); + return false; + }; + case G_ARCSECTOR: + { + notSupported( file, i18n( "This KSeg file contains an arc sector, " + "which Kig does not currently support." ) ); + return false; + }; + case G_ARCSEGMENT: + { + notSupported( file, i18n( "This KSeg file contains an arc segment, " + "which Kig does not currently support." ) ); + return false; + }; + case G_LOCUS: + { + switch( descendtype ) + { + case G_TRANSLATED: + case G_ROTATED: + case G_SCALED: + case G_REFLECTED: + { + o = transformObject( file, *retdoc, parents, descendtype, ok ); + break; + } + case G_OBJECT_LOCUS: + { + if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR; + o = fact->locusCalcer( parents[0], parents[1] ); + break; + } + default: + KIG_FILTER_PARSE_ERROR; + } + break; + }; + case G_MEASURE: + KIG_FILTER_PARSE_ERROR; + case G_CALCULATE: + KIG_FILTER_PARSE_ERROR; + case G_ANNOTATION: + KIG_FILTER_PARSE_ERROR; + case G_LOOP: + KIG_FILTER_PARSE_ERROR; + default: + KIG_FILTER_PARSE_ERROR; + + } + + // checking if the object was correctly created + if ( ! o ) + { + if ( ok ) + KIG_FILTER_PARSE_ERROR + else + return 0; + } + + ObjectDrawer* d = new ObjectDrawer( color, width, visible, style.pen.style() ); + if ( !labeltext.isEmpty() ) + { + ObjectConstCalcer* name = new ObjectConstCalcer( new StringImp( labeltext ) ); + object = new ObjectHolder( o, d, name ); + } + else + { + object = new ObjectHolder( o, d ); + } + + assert( object ); + ret[i] = object; + object->calc( *retdoc ); + if ( !labeltext.isEmpty() && labelVisible ) + { + std::vector<ObjectCalcer*> args2; + args2.push_back( object->nameCalcer() ); + ObjectCalcer* oc2 = fact->attachedLabelCalcer( + QString::fromLatin1( "%1" ), object->calcer(), + static_cast<const PointImp*>( object->imp() )->coordinate(), + false, args2, *retdoc ); + oc2->calc( *retdoc ); + ObjectDrawer* d2 = new ObjectDrawer( style.pen.color() ); + ObjectHolder* o2 = new ObjectHolder( oc2, d2 ); + ret2.push_back( o2 ); + } + }; + + // selection groups ( we ignore them, but we pretend to read them + // out anyway, so we can find what comes after them.. ) + int selgroupcount; + stream >> selgroupcount; + for ( int i = 0; i < selgroupcount; ++i ) + { + QString name; + stream >> name; + int size; + stream >> size; + for ( int i = 0; i < size; ++i ) + { + short object; + stream >> object; + (void) object; + }; + }; + + // no more data in the file.. + retdoc->addObjects( ret ); + retdoc->addObjects( ret2 ); + retdoc->setAxes( false ); + retdoc->setGrid( false ); + return retdoc; +} + +KigFilterKSeg* KigFilterKSeg::instance() +{ + static KigFilterKSeg f; + return &f; +} diff --git a/kig/filters/kseg-filter.h b/kig/filters/kseg-filter.h new file mode 100644 index 00000000..af475a7a --- /dev/null +++ b/kig/filters/kseg-filter.h @@ -0,0 +1,42 @@ +// Copyright (C) 2003 Dominique Devriese <[email protected]> + +// 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_FILTERS_KSEG_FILTER_H +#define KIG_FILTERS_KSEG_FILTER_H + +#include "filter.h" + +class ObjectCalcer; + +class KigFilterKSeg + : public KigFilter +{ + KigFilterKSeg(); + ~KigFilterKSeg(); + + ObjectCalcer* transformObject( const QString& file, KigDocument& kigdoc, + std::vector<ObjectCalcer*>& parents, + int subtype, bool& ok ); + +public: + static KigFilterKSeg* instance(); + + bool supportMime ( const QString& mime ); + KigDocument* load ( const QString& fromfile ); +}; + +#endif diff --git a/kig/filters/latexexporter.cc b/kig/filters/latexexporter.cc new file mode 100644 index 00000000..955ac148 --- /dev/null +++ b/kig/filters/latexexporter.cc @@ -0,0 +1,608 @@ +// Copyright (C) 2004 Pino Toscano <[email protected]> + +// 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 <config.h> + +#include "latexexporter.h" + +#include "latexexporteroptions.h" + +#include "../kig/kig_document.h" +#include "../kig/kig_part.h" +#include "../kig/kig_view.h" +#include "../misc/common.h" +#include "../misc/goniometry.h" +#include "../misc/kigfiledialog.h" +#include "../misc/rect.h" +#include "../objects/circle_imp.h" +#include "../objects/cubic_imp.h" +#include "../objects/curve_imp.h" +#include "../objects/line_imp.h" +#include "../objects/locus_imp.h" +#include "../objects/object_drawer.h" +#include "../objects/object_holder.h" +#include "../objects/object_imp.h" +#include "../objects/other_imp.h" +#include "../objects/point_imp.h" +#include "../objects/polygon_imp.h" +#include "../objects/text_imp.h" + +#include <math.h> +#include <algorithm> + +#include <qcheckbox.h> +#include <qcolor.h> +#include <qfile.h> +#include <qtextstream.h> + +#include <klocale.h> +#include <kmessagebox.h> + +#ifdef HAVE_TRUNC +#define KDE_TRUNC(a) trunc(a) +#else +#define KDE_TRUNC(a) rint(a) +#endif + +struct ColorMap { + QColor color; + QString name; +}; + +LatexExporter::~LatexExporter() +{ +} + +QString LatexExporter::exportToStatement() const +{ + return i18n( "Export to &Latex..." ); +} + +QString LatexExporter::menuEntryName() const +{ + return i18n( "&Latex..." ); +} + +QString LatexExporter::menuIcon() const +{ + // TODO + return "tex"; +} + +class LatexExportImpVisitor + : public ObjectImpVisitor +{ + QTextStream& mstream; + ObjectHolder* mcurobj; + const KigWidget& mw; + Rect msr; + std::vector<ColorMap> mcolors; + QString mcurcolorid; +public: + void visit( ObjectHolder* obj ); + void mapColor( QColor color ); + + LatexExportImpVisitor( QTextStream& s, const KigWidget& w ) + : mstream( s ), mw( w ), msr( mw.showingRect() ) + { + } + void visit( const LineImp* imp ); + void visit( const PointImp* imp ); + void visit( const TextImp* imp ); + void visit( const AngleImp* imp ); + void visit( const VectorImp* imp ); + void visit( const LocusImp* imp ); + void visit( const CircleImp* imp ); + void visit( const ConicImp* imp ); + void visit( const CubicImp* imp ); + void visit( const SegmentImp* imp ); + void visit( const RayImp* imp ); + void visit( const ArcImp* imp ); + void visit( const PolygonImp* imp ); + + double unit; + +private: + /** + * Converts Kig coords to pstrick coord system and sends them to stream + * using the format: (xcoord,ycoord) + */ + void emitCoord( const Coordinate& c ); + /** + * Draws a line (segment) or a vector if vector is true. + */ + void emitLine( const Coordinate& a, const Coordinate& b, const int width, + const Qt::PenStyle s, bool vector = false ); + /** + * Sends a new line character ( \n ) to stream. + */ + void newLine(); + /** + * Searches if a color is already mapped into mcolors, and returns its + * index or -1 if not found. + */ + int findColor( QColor c ); + /** + * Use to convert a dimension "on the screen" to a dimension wrt. + * Kig coordinate system. + */ + double dimRealToCoord( int dim ); + /** + * Converts a pen style into latex style string. + */ + QString writeStyle( Qt::PenStyle style ); + /** + * Plots a generic curve though its points calc'ed with getPoint. + */ + void plotGenericCurve( const CurveImp* imp ); +}; + +void LatexExportImpVisitor::emitCoord( const Coordinate& c ) +{ + mstream << "(" << c.x - msr.left() << "," << c.y - msr.bottom() << ")"; +} + +void LatexExportImpVisitor::emitLine( const Coordinate& a, const Coordinate& b, + const int width, const Qt::PenStyle s, + bool vector ) +{ + mstream << "\\psline[linecolor=" << mcurcolorid << ",linewidth=" << width / 100.0 + << "," << writeStyle( s ); + if ( vector ) + mstream << ",arrowscale=3,arrowinset=1.3"; + mstream << "]"; + if ( vector ) + mstream << "{->}"; + emitCoord( a ); + emitCoord( b ); + newLine(); +} + +void LatexExportImpVisitor::newLine() +{ + mstream << "\n"; +} + +int LatexExportImpVisitor::findColor( QColor c ) +{ + for ( uint i = 0; i < mcolors.size(); ++i ) + { + if ( c == mcolors[i].color ) + return i; + } + return -1; +} + +void LatexExportImpVisitor::mapColor( QColor color ) +{ + if ( findColor( color ) == -1 ) + { + ColorMap newcolor; + newcolor.color = color; + QString tmpname = color.name(); + tmpname.replace( "#", "" ); + newcolor.name = tmpname; + mcolors.push_back( newcolor ); + mstream << "\\newrgbcolor{" << tmpname << "}{" + << color.red() / 255.0 << " " << color.green() / 255.0 << " " + << color.blue() / 255.0 << "}\n"; + } +} + +double LatexExportImpVisitor::dimRealToCoord( int dim ) +{ + QRect qr( 0, 0, dim, dim ); + Rect r = mw.screenInfo().fromScreen( qr ); + return fabs( r.width() ); +} + +QString LatexExportImpVisitor::writeStyle( Qt::PenStyle style ) +{ + QString ret( "linestyle=" ); + if ( style == Qt::DashLine ) + ret += "dashed"; + else if ( style == Qt::DotLine ) + ret += "dotted,dotsep=2pt"; + else + ret += "solid"; + return ret; +} + +void LatexExportImpVisitor::plotGenericCurve( const CurveImp* imp ) +{ + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + + QString prefix = QString( "\\pscurve[linecolor=%1,linewidth=%2,%3]" ) + .arg( mcurcolorid ) + .arg( width / 100.0 ) + .arg( writeStyle( mcurobj->drawer()->style() ) ); + + std::vector< std::vector< Coordinate > > coordlist; + coordlist.push_back( std::vector< Coordinate >() ); + uint curid = 0; + + Coordinate c; + Coordinate prev = Coordinate::invalidCoord(); + for ( double i = 0.0; i <= 1.0; i += 0.005 ) + { + c = imp->getPoint( i, mw.document() ); + if ( !c.valid() ) + { + if ( coordlist[curid].size() > 0 ) + { + coordlist.push_back( std::vector< Coordinate >() ); + ++curid; + prev = Coordinate::invalidCoord(); + } + continue; + } + if ( ! ( ( fabs( c.x ) <= 1000 ) && ( fabs( c.y ) <= 1000 ) ) ) + continue; + // if there's too much distance between this coordinate and the previous + // one, then it's another piece of curve not joined with the rest + if ( prev.valid() && ( c.distance( prev ) > 4.0 ) ) + { + coordlist.push_back( std::vector< Coordinate >() ); + ++curid; + } + coordlist[curid].push_back( c ); + prev = c; + } + // special case for ellipse + if ( const ConicImp* conic = dynamic_cast< const ConicImp* >( imp ) ) + { + // if ellipse, close its path + if ( conic->conicType() == 1 && coordlist.size() == 1 && coordlist[0].size() > 1 ) + { + coordlist[0].push_back( coordlist[0][0] ); + } + } + for ( uint i = 0; i < coordlist.size(); ++i ) + { + uint s = coordlist[i].size(); + // there's no point in draw curves empty or with only one point + if ( s <= 1 ) + continue; + + mstream << prefix; + for ( uint j = 0; j < s; ++j ) + emitCoord( coordlist[i][j] ); + newLine(); + } +} + +void LatexExportImpVisitor::visit( ObjectHolder* obj ) +{ + if ( ! obj->drawer()->shown() ) + return; + const int id = findColor( obj->drawer()->color() ); + if ( id == -1 ) + return; + mcurcolorid = mcolors[id].name; + mcurobj = obj; + obj->imp()->visit( this ); +} + +void LatexExportImpVisitor::visit( const LineImp* imp ) +{ + Coordinate a = imp->data().a; + Coordinate b = imp->data().b; + calcBorderPoints( a, b, msr ); + + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + + emitLine( a, b, width, mcurobj->drawer()->style() ); +} + +void LatexExportImpVisitor::visit( const PointImp* imp ) +{ + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 5; + width /= 5; + + mstream << "\\psdots[linecolor=" << mcurcolorid + << ",dotscale=" << width << ",dotstyle="; + const int ps = mcurobj->drawer()->pointStyle(); + QString pss( "*,fillstyle=solid,fillcolor=" + mcurcolorid ); + if ( ps == 1 ) + pss = "o,fillstyle=none"; + else if ( ps == 2 ) + pss = "square*,fillstyle=solid,fillcolor=" + mcurcolorid; + else if ( ps == 3 ) + pss = "square,fillstyle=none"; + else if ( ps == 4 ) + pss = "+,dotangle=45"; + mstream << pss << "]"; + emitCoord( imp->coordinate() ); + newLine(); +} + +void LatexExportImpVisitor::visit( const TextImp* imp ) +{ + // FIXME: support multiline texts... + mstream << "\\rput[tl]"; + emitCoord( imp->coordinate() ); + newLine(); + mstream << "{"; + newLine(); + if ( imp->hasFrame() ) + { + mstream << " \\psframebox[linecolor=c5c2c5,linewidth=0.01" + << ",fillstyle=solid,fillcolor=ffffde]" + << "{" << imp->text() << "}"; + } + else + { + mstream << imp->text(); + } + newLine(); + mstream << "}"; + newLine(); +} + +void LatexExportImpVisitor::visit( const AngleImp* imp ) +{ + const Coordinate center = imp->point(); + const double radius = dimRealToCoord( 50 ) * unit; + double startangle = imp->startAngle(); + double endangle = startangle + imp->angle(); +// if ( startangle > M_PI ) +// startangle -= 2 * M_PI; + startangle = Goniometry::convert( startangle, Goniometry::Rad, Goniometry::Deg ); +// if ( endangle > 2 * M_PI ) +// endangle -= 2 * M_PI; + endangle = Goniometry::convert( endangle, Goniometry::Rad, Goniometry::Deg ); + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + + mstream << "\\psarc[linecolor=" << mcurcolorid << ",linewidth=" << width / 100.0 + << "," << writeStyle( mcurobj->drawer()->style() ) << ",arrowscale=3,arrowinset=0]{->}"; + emitCoord( center ); + mstream << "{" << radius << "}{" << startangle << "}{" << endangle << "}"; + newLine(); +} + +void LatexExportImpVisitor::visit( const VectorImp* imp ) +{ + Coordinate a = imp->data().a; + Coordinate b = imp->data().b; + + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + + emitLine( a, b, width, mcurobj->drawer()->style(), true ); +} + +void LatexExportImpVisitor::visit( const LocusImp* imp ) +{ + plotGenericCurve( imp ); +} + +void LatexExportImpVisitor::visit( const CircleImp* imp ) +{ + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + + mstream << "\\pscircle[linecolor=" << mcurcolorid << ",linewidth=" << width / 100.0 + << "," << writeStyle( mcurobj->drawer()->style() ) << "]"; + emitCoord( imp->center() ); + mstream << "{" << imp->radius() * unit << "}"; + newLine(); +} + +void LatexExportImpVisitor::visit( const ConicImp* imp ) +{ + plotGenericCurve( imp ); +} + +void LatexExportImpVisitor::visit( const CubicImp* ) +{ + // FIXME: cubic are not drawn correctly with plotGenericCurve +// plotGenericCurve( imp ); +} + +void LatexExportImpVisitor::visit( const SegmentImp* imp ) +{ + Coordinate a = imp->data().a; + Coordinate b = imp->data().b; + + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + + emitLine( a, b, width, mcurobj->drawer()->style() ); +} + +void LatexExportImpVisitor::visit( const RayImp* imp ) +{ + Coordinate a = imp->data().a; + Coordinate b = imp->data().b; + calcRayBorderPoints( a, b, msr ); + + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + + emitLine( a, b, width, mcurobj->drawer()->style() ); +} + +void LatexExportImpVisitor::visit( const ArcImp* imp ) +{ + const Coordinate center = imp->center(); + const double radius = imp->radius() * unit; + double startangle = imp->startAngle(); + double endangle = startangle + imp->angle(); +// if ( startangle > M_PI ) +// startangle -= 2 * M_PI; + startangle = Goniometry::convert( startangle, Goniometry::Rad, Goniometry::Deg ); +// if ( endangle > M_PI ) +// endangle -= 2 * M_PI; + endangle = Goniometry::convert( endangle, Goniometry::Rad, Goniometry::Deg ); + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + + mstream << "\\psarc[linecolor=" << mcurcolorid << ",linewidth=" << width / 100.0 + << "," << writeStyle( mcurobj->drawer()->style() ) << "]"; + emitCoord( center ); + mstream << "{" << radius << "}{" << startangle << "}{" << endangle << "}"; + newLine(); +} + +void LatexExportImpVisitor::visit( const PolygonImp* imp ) +{ + int width = mcurobj->drawer()->width(); + if ( width == -1 ) width = 1; + + mstream << "\\pspolygon[linecolor=" << mcurcolorid << ",linewidth=0" + << "," << writeStyle( mcurobj->drawer()->style() ) + << ",hatchcolor=" << mcurcolorid << ",hatchwidth=0.5pt,hatchsep=0.5pt" + << ",fillcolor=" << mcurcolorid << ",fillstyle=crosshatch]"; + + std::vector<Coordinate> pts = imp->points(); + for ( uint i = 0; i < pts.size(); i++ ) + { + emitCoord( pts[i] ); + } + newLine(); +} + +void LatexExporter::run( const KigPart& doc, KigWidget& w ) +{ + KigFileDialog* kfd = new KigFileDialog( + QString::null, i18n( "*.tex|Latex Documents (*.tex)" ), + i18n( "Export as Latex" ), &w ); + kfd->setOptionCaption( i18n( "Latex Options" ) ); + LatexExporterOptions* opts = new LatexExporterOptions( 0L ); + kfd->setOptionsWidget( opts ); + opts->showGridCheckBox->setChecked( doc.document().grid() ); + opts->showAxesCheckBox->setChecked( doc.document().axes() ); + opts->showExtraFrameCheckBox->setChecked( false ); + if ( !kfd->exec() ) + return; + + QString file_name = kfd->selectedFile(); + bool showgrid = opts->showGridCheckBox->isOn(); + bool showaxes = opts->showAxesCheckBox->isOn(); + bool showframe = opts->showExtraFrameCheckBox->isOn(); + + delete opts; + delete kfd; + + QFile file( file_name ); + if ( ! file.open( IO_WriteOnly ) ) + { + KMessageBox::sorry( &w, i18n( "The file \"%1\" could not be opened. Please " + "check if the file permissions are set correctly." ) + .arg( file_name ) ); + return; + }; + + QTextStream stream( &file ); + stream << "\\documentclass[a4paper]{minimal}\n"; +// stream << "\\usepackage[latin1]{inputenc}\n"; + stream << "\\usepackage{pstricks}\n"; + stream << "\\usepackage{pst-plot}\n"; + stream << "\\author{Kig " << KIGVERSION << "}\n"; + stream << "\\begin{document}\n"; + + const double bottom = w.showingRect().bottom(); + const double left = w.showingRect().left(); + const double height = w.showingRect().height(); + const double width = w.showingRect().width(); + +/* + // TODO: calculating aspect ratio... + if ( 297 / 210 >= height / width ) + { + + } +*/ + const double tmpwidth = 15.0; + const double xunit = tmpwidth / width; + const double yunit = xunit; + + stream << "\\begin{pspicture*}(0,0)(" << tmpwidth << "," << yunit * height << ")\n"; + stream << "\\psset{xunit=" << xunit << "}\n"; + stream << "\\psset{yunit=" << yunit << "}\n"; + + std::vector<ObjectHolder*> os = doc.document().objects(); + LatexExportImpVisitor visitor( stream, w ); + visitor.unit = xunit; + + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); + i != os.end(); ++i ) + { + if ( ! ( *i )->shown() ) continue; + visitor.mapColor( ( *i )->drawer()->color() ); + }; + visitor.mapColor( QColor( 255, 255, 222 ) ); // ffffde - text label background + visitor.mapColor( QColor( 197, 194, 197 ) ); // c5c2c5 - text label border line + visitor.mapColor( QColor( 160, 160, 164 ) ); // a0a0a4 - axes color + visitor.mapColor( QColor( 192, 192, 192 ) ); // c0c0c0 - grid color + + // extra frame + if ( showframe ) + { + stream << "\\psframe[linecolor=black,linewidth=0.02]" + << "(0,0)" + << "(" << width << "," << height << ")" + << "\n"; + } + + // grid + if ( showgrid ) + { + // vertical lines... + double startingpoint = - left - 1 + static_cast<int>( KDE_TRUNC( left ) ); + for ( double i = startingpoint; i < width; ++i ) + { + stream << "\\psline[linecolor=c0c0c0,linewidth=0.01,linestyle=dashed]" + << "(" << i << ",0)" + << "(" << i << "," << height << ")" + << "\n"; + } + + // horizontal lines... + startingpoint = - bottom - 1 + static_cast<int>( KDE_TRUNC( bottom ) ); + for ( double i = startingpoint; i < height; ++i ) + { + stream << "\\psline[linecolor=c0c0c0,linewidth=0.01,linestyle=dashed]" + << "(0," << i << ")" + << "(" << width << "," << i << ")" + << "\n"; + } + } + + // axes + if ( showaxes ) + { + stream << "\\psaxes[linecolor=a0a0a4,linewidth=0.03,ticks=none,arrowinset=0]{->}" + << "(" << -left << "," << -bottom << ")" + << "(0,0)" + << "(" << width << "," << height << ")" + << "\n"; + } + + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); + i != os.end(); ++i ) + { + visitor.visit( *i ); + }; + + stream << "\\end{pspicture*}\n"; + stream << "\\end{document}\n"; +} diff --git a/kig/filters/latexexporter.h b/kig/filters/latexexporter.h new file mode 100644 index 00000000..32638de1 --- /dev/null +++ b/kig/filters/latexexporter.h @@ -0,0 +1,41 @@ +// Copyright (C) 2004 Pino Toscano <[email protected]> + +// 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_FILTERS_LATEXEXPORTER_H +#define KIG_FILTERS_LATEXEXPORTER_H + +#include "exporter.h" + +class QString; +class KigPart; +class KigWidget; + +/** + * Export to LaTex. + */ +class LatexExporter + : public KigExporter +{ +public: + ~LatexExporter(); + QString exportToStatement() const; + QString menuEntryName() const; + QString menuIcon() const; + void run( const KigPart& doc, KigWidget& w ); +}; + +#endif diff --git a/kig/filters/latexexporteroptions.ui b/kig/filters/latexexporteroptions.ui new file mode 100644 index 00000000..d2e60c5b --- /dev/null +++ b/kig/filters/latexexporteroptions.ui @@ -0,0 +1,69 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>LatexExporterOptions</class> +<widget class="QWidget"> + <property name="name"> + <cstring>LatexExporterOptions</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>450</width> + <height>150</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Options</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>showGridCheckBox</cstring> + </property> + <property name="text"> + <string>Show grid</string> + </property> + </widget> + <widget class="QCheckBox" row="0" column="1"> + <property name="name"> + <cstring>showAxesCheckBox</cstring> + </property> + <property name="text"> + <string>Show axes</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>showExtraFrameCheckBox</cstring> + </property> + <property name="text"> + <string>Show extra frame</string> + </property> + </widget> + </grid> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> +</includehints> +</UI> diff --git a/kig/filters/native-filter.cc b/kig/filters/native-filter.cc new file mode 100644 index 00000000..6cecf09b --- /dev/null +++ b/kig/filters/native-filter.cc @@ -0,0 +1,747 @@ +// Copyright (C) 2003 Dominique Devriese <[email protected]> + +// 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 "native-filter.h" + +#include "../kig/kig_part.h" +#include "../kig/kig_document.h" +#include "../objects/bogus_imp.h" +#include "../objects/object_type.h" +#include "../objects/object_imp.h" +#include "../objects/object_calcer.h" +#include "../objects/object_drawer.h" +#include "../objects/object_holder.h" +#include "../objects/object_type_factory.h" +#include "../objects/object_imp_factory.h" +#include "../misc/calcpaths.h" +#include "../misc/coordinate_system.h" + +#include "config.h" + +#include <qdom.h> +#include <qfile.h> +#include <qregexp.h> + +#include <karchive.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <ktar.h> + +#include <stdio.h> + +#include <vector> +#include <algorithm> +#include <map> + +struct HierElem +{ + int id; + std::vector<int> parents; + QDomElement el; +}; + +static void extendVect( std::vector<HierElem>& vect, uint size ) +{ + if ( size > vect.size() ) + { + int osize = vect.size(); + vect.resize( size ); + for ( uint i = osize; i < size; ++i ) + vect[i].id = i+1; + }; +} + +static void visitElem( std::vector<HierElem>& ret, + const std::vector<HierElem>& elems, + std::vector<bool>& seen, + int i ) +{ + if ( !seen[i] ) + { + for ( uint j = 0; j < elems[i].parents.size(); ++j ) + visitElem( ret, elems, seen, elems[i].parents[j] - 1); + ret.push_back( elems[i] ); + seen[i] = true; + }; +} + +static std::vector<HierElem> sortElems( const std::vector<HierElem> elems ) +{ + std::vector<HierElem> ret; + std::vector<bool> seenElems( elems.size(), false ); + for ( uint i = 0; i < elems.size(); ++i ) + visitElem( ret, elems, seenElems, i ); + return ret; +} + +KigFilterNative::KigFilterNative() +{ +} + +KigFilterNative::~KigFilterNative() +{ +} + +bool KigFilterNative::supportMime( const QString& mime ) +{ + return mime == "application/x-kig"; +} + +KigDocument* KigFilterNative::load( const QString& file ) +{ + QFile ffile( file ); + if ( ! ffile.open( IO_ReadOnly ) ) + { + fileNotFound( file ); + return 0; + }; + + QFile kigdoc( file ); +#ifndef KIG_NO_COMPRESSED_FILES + bool iscompressed = false; + if ( !file.endsWith( ".kig", false ) ) + { + // the file is compressed, so we have to decompress it and fetch the + // kig file inside it... + iscompressed = true; + + QString tempdir = KGlobal::dirs()->saveLocation( "tmp" ); + if ( tempdir.isEmpty() ) + KIG_FILTER_PARSE_ERROR; + + QString tempname = file.section( '/', -1 ); + if ( file.endsWith( ".kigz", false ) ) + { + tempname.remove( QRegExp( "\\.[Kk][Ii][Gg][Zz]$" ) ); + } + else + KIG_FILTER_PARSE_ERROR; + // reading compressed file + KTar* ark = new KTar( file, "application/x-gzip" ); + ark->open( IO_ReadOnly ); + const KArchiveDirectory* dir = ark->directory(); +// assert( dir ); + QStringList entries = dir->entries(); + QStringList kigfiles = entries.grep( QRegExp( "\\.kig$" ) ); + if ( kigfiles.count() != 1 ) + // I throw a generic parse error here, but I should warn the user that + // this kig archive file doesn't contain one kig file (it contains no + // kig files or more than one). + KIG_FILTER_PARSE_ERROR; + const KArchiveEntry* kigz = dir->entry( kigfiles[0] ); + if ( !kigz->isFile() ) + KIG_FILTER_PARSE_ERROR; + dynamic_cast<const KArchiveFile*>( kigz )->copyTo( tempdir ); + kdDebug() << "extracted file: " << tempdir + kigz->name() << endl + << "exists: " << QFile::exists( tempdir + kigz->name() ) << endl; + + kigdoc.setName( tempdir + kigz->name() ); + } +#endif + + if ( !kigdoc.open( IO_ReadOnly ) ) + KIG_FILTER_PARSE_ERROR; + + QDomDocument doc( "KigDocument" ); + if ( !doc.setContent( &kigdoc ) ) + KIG_FILTER_PARSE_ERROR; + kigdoc.close(); + +#ifndef KIG_NO_COMPRESSED_FILES + // removing temp file + if ( iscompressed ) + kigdoc.remove(); +#endif + + QDomElement main = doc.documentElement(); + + QString version = main.attribute( "CompatibilityVersion" ); + if ( version.isEmpty() ) version = main.attribute( "Version" ); + if ( version.isEmpty() ) version = main.attribute( "version" ); + if ( version.isEmpty() ) + KIG_FILTER_PARSE_ERROR; + + // matches 0.1, 0.2.0, 153.128.99 etc. + QRegExp versionre( "(\\d+)\\.(\\d+)(\\.(\\d+))?" ); + if ( ! versionre.exactMatch( version ) ) + KIG_FILTER_PARSE_ERROR; + bool ok = true; + int major = versionre.cap( 1 ).toInt( &ok ); + bool ok2 = true; + int minor = versionre.cap( 2 ).toInt( &ok2 ); + if ( ! ok || ! ok2 ) + KIG_FILTER_PARSE_ERROR; + + // int minorminor = versionre.cap( 4 ).toInt( &ok ); + + // we only support 0.[0-7] and 1.0.* + if ( major > 0 || minor > 9 ) + { + notSupported( file, i18n( "This file was created by Kig version \"%1\", " + "which this version cannot open." ).arg( version ) ); + return false; + } + else if ( major == 0 && minor <= 3 ) + { + notSupported( file, i18n( "This file was created by Kig version \"%1\".\n" + "Support for older Kig formats (pre-0.4) has been " + "removed from Kig.\n" + "You can try to open this file with an older Kig " + "version (0.4 to 0.6),\n" + "and then save it again, which will save it in the " + "new format." ).arg( version ) ); + return false; + } + else if ( major == 0 && minor <= 6 ) + return load04( file, main ); + else + return load07( file, main ); +} + +KigDocument* KigFilterNative::load04( const QString& file, const QDomElement& docelem ) +{ + bool ok = true; + + KigDocument* ret = new KigDocument(); + + for ( QDomNode n = docelem.firstChild(); ! n.isNull(); n = n.nextSibling() ) + { + QDomElement e = n.toElement(); + if ( e.isNull() ) continue; + if ( e.tagName() == "CoordinateSystem" ) + { + const QCString type = e.text().latin1(); + CoordinateSystem* s = CoordinateSystemFactory::build( type ); + if ( ! s ) + { + warning( i18n( "This Kig file has a coordinate system " + "that this Kig version does not support.\n" + "A standard coordinate system will be used " + "instead." ) ); + } + else ret->setCoordinateSystem( s ); + } + else if ( e.tagName() == "Objects" ) + { + std::vector<ObjectCalcer*> retcalcers; + std::vector<ObjectHolder*> retholders; + + // first pass: do a topological sort of the objects, to support + // randomly ordered files... + std::vector<HierElem> elems; + QDomElement objectselem = e; + for ( QDomNode o = objectselem.firstChild(); ! o.isNull(); o = o.nextSibling() ) + { + e = o.toElement(); + if ( e.isNull() ) continue; + uint id; + if ( e.tagName() == "Data" || e.tagName() == "Property" || e.tagName() == "Object" ) + { + // fetch the id + QString tmp = e.attribute("id"); + id = tmp.toInt(&ok); + if ( !ok ) KIG_FILTER_PARSE_ERROR; + + extendVect( elems, id ); + elems[id-1].el = e; + } + else continue; + + for ( QDomNode p = e.firstChild(); !p.isNull(); p = p.nextSibling() ) + { + QDomElement f = p.toElement(); + if ( f.isNull() ) continue; + if ( f.tagName() == "Parent" ) + { + QString tmp = f.attribute( "id" ); + uint pid = tmp.toInt( &ok ); + if ( ! ok ) KIG_FILTER_PARSE_ERROR; + + extendVect( elems, id ); + elems[id-1].parents.push_back( pid ); + } + } + }; + + for ( uint i = 0; i < elems.size(); ++i ) + if ( elems[i].el.isNull() ) + KIG_FILTER_PARSE_ERROR; + elems = sortElems( elems ); + + retcalcers.resize( elems.size(), 0 ); + + for ( std::vector<HierElem>::iterator i = elems.begin(); + i != elems.end(); ++i ) + { + QDomElement e = i->el; + bool internal = e.attribute( "internal" ) == "true" ? true : false; + ObjectCalcer* o = 0; + if ( e.tagName() == "Data" ) + { + QString tmp = e.attribute( "type" ); + if ( tmp.isNull() ) + KIG_FILTER_PARSE_ERROR; + QString error; + ObjectImp* imp = ObjectImpFactory::instance()->deserialize( tmp, e, error ); + if ( ( !imp ) && !error.isEmpty() ) + { + parseError( file, error ); + return false; + } + o = new ObjectConstCalcer( imp ); + } + else if ( e.tagName() == "Property" ) + { + QCString propname; + for ( QDomElement ec = e.firstChild().toElement(); !ec.isNull(); + ec = ec.nextSibling().toElement() ) + { + if ( ec.tagName() == "Property" ) + propname = ec.text().latin1(); + }; + + if ( i->parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + ObjectCalcer* parent = retcalcers[i->parents[0] -1]; + QCStringList propnames = parent->imp()->propertiesInternalNames(); + int propid = propnames.findIndex( propname ); + if ( propid == -1 ) + KIG_FILTER_PARSE_ERROR; + + o = new ObjectPropertyCalcer( parent, propid ); + } + else if ( e.tagName() == "Object" ) + { + QString tmp = e.attribute( "type" ); + if ( tmp.isNull() ) + KIG_FILTER_PARSE_ERROR; + + const ObjectType* type = + ObjectTypeFactory::instance()->find( tmp.latin1() ); + if ( !type ) + { + notSupported( file, 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( tmp ) ); + return false; + }; + + std::vector<ObjectCalcer*> parents; + for ( std::vector<int>::iterator j = i->parents.begin(); + j != i->parents.end(); ++j ) + parents.push_back( retcalcers[*j - 1] ); + + o = new ObjectTypeCalcer( type, parents ); + } + else continue; + + o->calc( *ret ); + retcalcers[i->id - 1] = o; + + if ( ! internal ) + { + QString tmp = e.attribute( "color" ); + QColor color( tmp ); + if ( !color.isValid() ) + KIG_FILTER_PARSE_ERROR; + + tmp = e.attribute( "shown" ); + bool shown = !( tmp == "false" || tmp == "no" ); + + tmp = e.attribute( "width" ); + int width = tmp.toInt( &ok ); + if ( ! ok ) width = -1; + + ObjectDrawer* d = new ObjectDrawer( color, width, shown ); + retholders.push_back( new ObjectHolder( o, d ) ); + } + } + ret->addObjects( retholders ); + } + else continue; // be forward-compatible.. + }; + + return ret; +} + +KigFilterNative* KigFilterNative::instance() +{ + static KigFilterNative f; + return &f; +} + +KigDocument* KigFilterNative::load07( const QString& file, const QDomElement& docelem ) +{ + KigDocument* ret = new KigDocument(); + + bool ok = true; + std::vector<ObjectCalcer::shared_ptr> calcers; + std::vector<ObjectHolder*> holders; + + QString t = docelem.attribute( "grid" ); + bool tmphide = ( t == "false" ) || ( t == "no" ) || ( t == "0" ); + ret->setGrid( !tmphide ); + t = docelem.attribute( "axes" ); + tmphide = ( t == "false" ) || ( t == "no" ) || ( t == "0" ); + ret->setAxes( !tmphide ); + + for ( QDomElement subsectionelement = docelem.firstChild().toElement(); ! subsectionelement.isNull(); + subsectionelement = subsectionelement.nextSibling().toElement() ) + { + if ( subsectionelement.tagName() == "CoordinateSystem" ) + { + QString tmptype = subsectionelement.text(); + // compatibility code - to support Invisible coord system... + if ( tmptype == "Invisible" ) + { + tmptype = "Euclidean"; + ret->setGrid( false ); + ret->setAxes( false ); + } + const QCString type = tmptype.latin1(); + CoordinateSystem* s = CoordinateSystemFactory::build( type ); + if ( ! s ) + { + warning( i18n( "This Kig file has a coordinate system " + "that this Kig version does not support.\n" + "A standard coordinate system will be used " + "instead." ) ); + } + else ret->setCoordinateSystem( s ); + } + else if ( subsectionelement.tagName() == "Hierarchy" ) + { + for ( QDomElement e = subsectionelement.firstChild().toElement(); ! e.isNull(); + e = e.nextSibling().toElement() ) + { + QString tmp = e.attribute( "id" ); + uint id = tmp.toInt( &ok ); + if ( id <= 0 ) KIG_FILTER_PARSE_ERROR; + + std::vector<ObjectCalcer*> parents; + for ( QDomElement parentel = e.firstChild().toElement(); ! parentel.isNull(); + parentel = parentel.nextSibling().toElement() ) + { + if ( parentel.tagName() != "Parent" ) continue; + QString tmp = parentel.attribute( "id" ); + uint parentid = tmp.toInt( &ok ); + if ( ! ok ) KIG_FILTER_PARSE_ERROR; + if ( parentid == 0 || parentid > calcers.size() ) KIG_FILTER_PARSE_ERROR; + ObjectCalcer* parent = calcers[parentid - 1].get(); + if ( ! parent ) KIG_FILTER_PARSE_ERROR; + parents.push_back( parent ); + } + + ObjectCalcer* o = 0; + + if ( e.tagName() == "Data" ) + { + if ( !parents.empty() ) KIG_FILTER_PARSE_ERROR; + QString tmp = e.attribute( "type" ); + QString error; + ObjectImp* imp = ObjectImpFactory::instance()->deserialize( tmp, e, error ); + if ( ( !imp ) && !error.isEmpty() ) + { + parseError( file, error ); + return false; + } + o = new ObjectConstCalcer( imp ); + } + else if ( e.tagName() == "Property" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + QCString propname = e.attribute( "which" ).latin1(); + + ObjectCalcer* parent = parents[0]; + int propid = parent->imp()->propertiesInternalNames().findIndex( propname ); + if ( propid == -1 ) KIG_FILTER_PARSE_ERROR; + + o = new ObjectPropertyCalcer( parent, propid ); + } + else if ( e.tagName() == "Object" ) + { + QString tmp = e.attribute( "type" ); + const ObjectType* type = + ObjectTypeFactory::instance()->find( tmp.latin1() ); + if ( ! type ) + { + notSupported( file, 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( tmp ) ); + return false; + } + + // mp: (I take the responsibility for this!) explanation: the usual ObjectTypeCalcer + // constructor also "sortArgs" the parents. I believe that this *must not* be done + // when loading from a saved kig file for the following reasons: + // 1. the arguments should already be in their intended order, since the file was + // saved from a working hierarchy; furthermore we actually want to restore the original + // hierarchy, not really to also fix possible problems with the original hierarchy; + // 2. calling sortArgs could have undesirable side effects in particular situations, + // since kig actually allow an ObjectType to produce different type of ObjectImp's + // it may happen that the parents of an object do not satisfy the requirements + // enforced by sortArgs (while moving around the free objects) but still be + // perfectly valid + o = new ObjectTypeCalcer( type, parents, false ); + } + else KIG_FILTER_PARSE_ERROR; + + o->calc( *ret ); + calcers.resize( id, 0 ); + calcers[id-1] = o; + } + } + else if ( subsectionelement.tagName() == "View" ) + { + for ( QDomElement e = subsectionelement.firstChild().toElement(); ! e.isNull(); + e = e.nextSibling().toElement() ) + { + if ( e.tagName() != "Draw" ) KIG_FILTER_PARSE_ERROR; + + QString tmp = e.attribute( "object" ); + uint id = tmp.toInt( &ok ); + if ( !ok ) KIG_FILTER_PARSE_ERROR; + if ( id <= 0 || id > calcers.size() ) + KIG_FILTER_PARSE_ERROR; + ObjectCalcer* calcer = calcers[id-1].get(); + + tmp = e.attribute( "color" ); + QColor color( tmp ); + if ( !color.isValid() ) + KIG_FILTER_PARSE_ERROR; + + tmp = e.attribute( "shown" ); + bool shown = !( tmp == "false" || tmp == "no" ); + + tmp = e.attribute( "width" ); + int width = tmp.toInt( &ok ); + if ( ! ok ) width = -1; + + tmp = e.attribute( "style" ); + Qt::PenStyle style = ObjectDrawer::styleFromString( tmp ); + + tmp = e.attribute( "point-style" ); + int pointstyle = ObjectDrawer::pointStyleFromString( tmp ); + + ObjectConstCalcer* namecalcer = 0; + tmp = e.attribute( "namecalcer" ); + if ( tmp != "none" && !tmp.isEmpty() ) + { + int ncid = tmp.toInt( &ok ); + if ( !ok ) KIG_FILTER_PARSE_ERROR; + if ( ncid <= 0 || ncid > calcers.size() ) + KIG_FILTER_PARSE_ERROR; + if ( ! dynamic_cast<ObjectConstCalcer*>( calcers[ncid-1].get() ) ) + KIG_FILTER_PARSE_ERROR; + namecalcer = static_cast<ObjectConstCalcer*>( calcers[ncid-1].get() ); + } + + ObjectDrawer* drawer = new ObjectDrawer( color, width, shown, style, pointstyle ); + holders.push_back( new ObjectHolder( calcer, drawer, namecalcer ) ); + } + } + } + + ret->addObjects( holders ); + return ret; +} + +bool KigFilterNative::save07( const KigDocument& kdoc, QTextStream& stream ) +{ + QDomDocument doc( "KigDocument" ); + + QDomElement docelem = doc.createElement( "KigDocument" ); + docelem.setAttribute( "Version", KIGVERSION ); + docelem.setAttribute( "CompatibilityVersion", "0.7.0" ); + docelem.setAttribute( "grid", kdoc.grid() ); + docelem.setAttribute( "axes", kdoc.axes() ); + + QDomElement cselem = doc.createElement( "CoordinateSystem" ); + cselem.appendChild( doc.createTextNode( kdoc.coordinateSystem().type() ) ); + docelem.appendChild( cselem ); + + std::vector<ObjectHolder*> holders = kdoc.objects(); + std::vector<ObjectCalcer*> calcers = getAllParents( getAllCalcers( holders ) ); + calcers = calcPath( calcers ); + + QDomElement hierelem = doc.createElement( "Hierarchy" ); + std::map<const ObjectCalcer*, int> idmap; + for ( std::vector<ObjectCalcer*>::const_iterator i = calcers.begin(); + i != calcers.end(); ++i ) + idmap[*i] = ( i - calcers.begin() ) + 1; + int id = 1; + + for ( std::vector<ObjectCalcer*>::const_iterator i = calcers.begin(); i != calcers.end(); ++i ) + { + QDomElement objectelem; + if ( dynamic_cast<ObjectConstCalcer*>( *i ) ) + { + objectelem = doc.createElement( "Data" ); + QString ser = + ObjectImpFactory::instance()->serialize( *(*i)->imp(), objectelem, doc ); + objectelem.setAttribute( "type", ser ); + } + else if ( dynamic_cast<const ObjectPropertyCalcer*>( *i ) ) + { + const ObjectPropertyCalcer* o = static_cast<const ObjectPropertyCalcer*>( *i ); + objectelem = doc.createElement( "Property" ); + + QCString propname = o->parent()->imp()->propertiesInternalNames()[o->propId()]; + objectelem.setAttribute( "which", propname ); + } + else if ( dynamic_cast<const ObjectTypeCalcer*>( *i ) ) + { + const ObjectTypeCalcer* o = static_cast<const ObjectTypeCalcer*>( *i ); + objectelem = doc.createElement( "Object" ); + objectelem.setAttribute( "type", o->type()->fullName() ); + } + else assert( false ); + + const std::vector<ObjectCalcer*> parents = ( *i )->parents(); + for ( std::vector<ObjectCalcer*>::const_iterator i = parents.begin(); i != parents.end(); ++i ) + { + std::map<const ObjectCalcer*,int>::const_iterator idp = idmap.find( *i ); + assert( idp != idmap.end() ); + int pid = idp->second; + QDomElement pel = doc.createElement( "Parent" ); + pel.setAttribute( "id", pid ); + objectelem.appendChild( pel ); + } + + objectelem.setAttribute( "id", id++ ); + hierelem.appendChild( objectelem ); + } + docelem.appendChild( hierelem ); + + QDomElement windowelem = doc.createElement( "View" ); + for ( std::vector<ObjectHolder*>::iterator i = holders.begin(); i != holders.end(); ++i ) + { + std::map<const ObjectCalcer*,int>::const_iterator idp = idmap.find( ( *i )->calcer() ); + assert( idp != idmap.end() ); + int id = idp->second; + + const ObjectDrawer* d = ( *i )->drawer(); + QDomElement drawelem = doc.createElement( "Draw" ); + drawelem.setAttribute( "object", id ); + drawelem.setAttribute( "color", d->color().name() ); + drawelem.setAttribute( "shown", QString::fromLatin1( d->shown() ? "true" : "false" ) ); + drawelem.setAttribute( "width", QString::number( d->width() ) ); + drawelem.setAttribute( "style", d->styleToString() ); + drawelem.setAttribute( "point-style", d->pointStyleToString() ); + + ObjectCalcer* namecalcer = ( *i )->nameCalcer(); + if ( namecalcer ) + { + std::map<const ObjectCalcer*,int>::const_iterator ncp = idmap.find( namecalcer ); + assert( ncp != idmap.end() ); + int ncid = ncp->second; + drawelem.setAttribute( "namecalcer", ncid ); + } + else + { + drawelem.setAttribute( "namecalcer", "none" ); + } + + windowelem.appendChild( drawelem ); + }; + docelem.appendChild( windowelem ); + + doc.appendChild( docelem ); + stream << doc.toString(); + return true; +} + +bool KigFilterNative::save( const KigDocument& data, const QString& file ) +{ + return save07( data, file ); +} + +bool KigFilterNative::save07( const KigDocument& data, const QString& outfile ) +{ + // we have an empty outfile, so we have to print all to stdout + if ( outfile.isEmpty() ) + { + QTextStream stdoutstream( stdout, IO_WriteOnly ); + return save07( data, stdoutstream ); + } +#ifndef KIG_NO_COMPRESSED_FILES + if ( !outfile.endsWith( ".kig", false ) ) + { + // the user wants to save a compressed file, so we have to save our kig + // file to a temp file and then compress it... + + QString tempdir = KGlobal::dirs()->saveLocation( "tmp" ); + if ( tempdir.isEmpty() ) + return false; + + QString tempname = outfile.section( '/', -1 ); + if ( outfile.endsWith( ".kigz", false ) ) + tempname.remove( QRegExp( "\\.[Kk][Ii][Gg][Zz]$" ) ); + else + return false; + + QString tmpfile = tempdir + tempname + ".kig"; + QFile ftmpfile( tmpfile ); + if ( !ftmpfile.open( IO_WriteOnly ) ) + return false; + QTextStream stream( &ftmpfile ); + if ( !save07( data, stream ) ) + return false; + ftmpfile.close(); + + kdDebug() << "tmp saved file: " << tmpfile << endl; + + // creating the archive and adding our file + KTar* ark = new KTar( outfile, "application/x-gzip" ); + ark->open( IO_WriteOnly ); + ark->addLocalFile( tmpfile, tempname + ".kig" ); + ark->close(); + + // finally, removing temp file + QFile::remove( tmpfile ); + + return true; + } + else + { +#endif + QFile file( outfile ); + if ( ! file.open( IO_WriteOnly ) ) + { + fileNotFound( outfile ); + return false; + } + QTextStream stream( &file ); + return save07( data, stream ); +#ifndef KIG_NO_COMPRESSED_FILES + } + + // we should never reach this point... + return false; +#endif +} + +/* +bool KigFilterNative::save( const KigDocument& data, QTextStream& stream ) +{ + return save07( data, stream ); +} +*/ diff --git a/kig/filters/native-filter.h b/kig/filters/native-filter.h new file mode 100644 index 00000000..12778f35 --- /dev/null +++ b/kig/filters/native-filter.h @@ -0,0 +1,66 @@ +// Copyright (C) 2003 Dominique Devriese <[email protected]> + +// 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_FILTERS_NATIVE_FILTER_H +#define KIG_FILTERS_NATIVE_FILTER_H + +#include "filter.h" + +class QDomElement; +class KigDocument; +class QTextStream; +class QString; + +/** + * Kig's native format. Between versions 0.3.1 and 0.4, there was a + * change in the file format. This filter no longer supports pre-0.4 + * formats, it did up until Kig 0.6. + */ +class KigFilterNative + : public KigFilter +{ +private: + /** + * this is the load function for the Kig format that is used, + * starting at Kig 0.4 + */ + KigDocument* load04( const QString& file, const QDomElement& doc ); + /** + * this is the load function for the Kig format that is used + * starting at Kig 0.7 + */ + KigDocument* load07( const QString& file, const QDomElement& doc ); + + /** + * save in the Kig format that is used starting at Kig 0.7 + */ + bool save07( const KigDocument& data, const QString& outfile ); + bool save07( const KigDocument& data, QTextStream& file ); + + KigFilterNative(); + ~KigFilterNative(); +public: + static KigFilterNative* instance(); + + bool supportMime( const QString& mime ); + KigDocument* load( const QString& file ); + + bool save( const KigDocument& data, const QString& file ); +// bool save( const KigDocument& data, QTextStream& stream ); +}; + +#endif diff --git a/kig/filters/svgexporter.cc b/kig/filters/svgexporter.cc new file mode 100644 index 00000000..6e945de2 --- /dev/null +++ b/kig/filters/svgexporter.cc @@ -0,0 +1,111 @@ +// Copyright (C) 2004 Pino Toscano <[email protected]> + +// 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 "svgexporter.h" + +#include "svgexporteroptions.h" + +#include "../kig/kig_document.h" +#include "../kig/kig_part.h" +#include "../kig/kig_view.h" +#include "../misc/common.h" +#include "../misc/kigfiledialog.h" +#include "../misc/kigpainter.h" + +#include <qcheckbox.h> +#include <qfile.h> +#include <qpicture.h> +#include <qrect.h> + +#include <klocale.h> +#include <kmessagebox.h> + +#include <map> + +SVGExporter::~SVGExporter() +{ +} + +QString SVGExporter::exportToStatement() const +{ + return i18n( "&Export to SVG..." ); +} + +QString SVGExporter::menuEntryName() const +{ + return i18n( "&SVG..." ); +} + +QString SVGExporter::menuIcon() const +{ + // TODO + return "vectorgfx"; +} + +void SVGExporter::run( const KigPart& part, KigWidget& w ) +{ + KigFileDialog* kfd = new KigFileDialog( + QString::null, i18n( "*.svg|Scalable Vector Graphics (*.svg)" ), + i18n( "Export as SVG" ), &w ); + kfd->setOptionCaption( i18n( "SVG Options" ) ); + SVGExporterOptions* opts = new SVGExporterOptions( 0L ); + kfd->setOptionsWidget( opts ); + opts->showGridCheckBox->setChecked( part.document().grid() ); + opts->showAxesCheckBox->setChecked( part.document().axes() ); + if ( !kfd->exec() ) + return; + + QString file_name = kfd->selectedFile(); + bool showgrid = opts->showGridCheckBox->isOn(); + bool showaxes = opts->showAxesCheckBox->isOn(); + + delete opts; + delete kfd; + + QFile file( file_name ); + if ( ! file.open( IO_WriteOnly ) ) + { + KMessageBox::sorry( &w, i18n( "The file \"%1\" could not be opened. Please " + "check if the file permissions are set correctly." ) + .arg( file_name ) ); + return; + }; + + QRect viewrect( w.screenInfo().viewRect() ); + QRect r( 0, 0, viewrect.width(), viewrect.height() ); + + QPicture pic; + pic.setBoundingRect( r ); + KigPainter* p = new KigPainter( ScreenInfo( w.screenInfo().shownRect(), viewrect ), + &pic, part.document() ); +// p->setWholeWinOverlay(); +// p->setBrushColor( Qt::white ); +// p->setBrushStyle( Qt::SolidPattern ); +// p->drawRect( r ); +// p->setBrushStyle( Qt::NoBrush ); +// p->setWholeWinOverlay(); + p->drawGrid( part.document().coordinateSystem(), showgrid, showaxes ); + p->drawObjects( part.document().objects(), false ); + + delete p; + + if ( !pic.save( file_name, "SVG" ) ) + { + KMessageBox::error( &w, i18n( "Sorry, something went wrong while saving to SVG file \"%1\"" ).arg( file_name ) ); + } + +} diff --git a/kig/filters/svgexporter.h b/kig/filters/svgexporter.h new file mode 100644 index 00000000..17193673 --- /dev/null +++ b/kig/filters/svgexporter.h @@ -0,0 +1,41 @@ +// Copyright (C) 2004 Pino Toscano <[email protected]> + +// 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_FILTERS_SVGEXPORTER_H +#define KIG_FILTERS_SVGEXPORTER_H + +#include "exporter.h" + +class QString; +class KigPart; +class KigWidget; + +/** + * Export to Scalable Vector Graphics (SVG) + */ +class SVGExporter + : public KigExporter +{ +public: + ~SVGExporter(); + QString exportToStatement() const; + QString menuEntryName() const; + QString menuIcon() const; + void run( const KigPart& part, KigWidget& w ); +}; + +#endif diff --git a/kig/filters/svgexporteroptions.ui b/kig/filters/svgexporteroptions.ui new file mode 100644 index 00000000..2de679cb --- /dev/null +++ b/kig/filters/svgexporteroptions.ui @@ -0,0 +1,61 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>SVGExporterOptions</class> +<widget class="QWidget"> + <property name="name"> + <cstring>SVGExporterOptions</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>440</width> + <height>200</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Options</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>showGridCheckBox</cstring> + </property> + <property name="text"> + <string>Show grid</string> + </property> + </widget> + <widget class="QCheckBox" row="0" column="1"> + <property name="name"> + <cstring>showAxesCheckBox</cstring> + </property> + <property name="text"> + <string>Show axes</string> + </property> + </widget> + </grid> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> +</includehints> +</UI> diff --git a/kig/filters/tests/circleBCP.FIG b/kig/filters/tests/circleBCP.FIG new file mode 100644 index 00000000..aeaa9689 --- /dev/null +++ b/kig/filters/tests/circleBCP.FIG @@ -0,0 +1,24 @@ +FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.89479166666667 0.291041666666667
+
+4: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -1.61395833333333 2.43416666666667
+
+5: Cir, 0, CN:2, VN:2
+Bl, W, t, DS:1 1, GT:0, V, nSt
+Const: 3 4
+
diff --git a/kig/filters/tests/constrainedPoint.FIG b/kig/filters/tests/constrainedPoint.FIG new file mode 100644 index 00000000..ac086421 --- /dev/null +++ b/kig/filters/tests/constrainedPoint.FIG @@ -0,0 +1,24 @@ +FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.18583333333333 1.11125
+
+4: Line, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 3, Val: 0.958665525176453 0.284535429846892
+
+5: Pt/, 0, CN:1, VN:3
+R, W, t, DS:1 1, GT:1, V, nSt
+Const: 4, Val: -2.80458333333333 1.81801369863014
+
diff --git a/kig/filters/tests/cubiclineintersect.kig b/kig/filters/tests/cubiclineintersect.kig new file mode 100644 index 00000000..a157f611 --- /dev/null +++ b/kig/filters/tests/cubiclineintersect.kig @@ -0,0 +1,105 @@ +<!DOCTYPE KigDocument> +<KigDocument Version="0.6.0" > + <CoordinateSystem>Euclidean</CoordinateSystem> + <Objects> + <Data internal="true" type="double" id="1" >-5.63522</Data> + <Data internal="true" type="double" id="2" >1.0566</Data> + <Data internal="true" type="double" id="3" >-1.49686</Data> + <Data internal="true" type="double" id="4" >2.33333</Data> + <Data internal="true" type="double" id="5" >-1.14465</Data> + <Data internal="true" type="double" id="6" >-0.220126</Data> + <Data internal="true" type="double" id="7" >-4.66667</Data> + <Data internal="true" type="double" id="8" >-1.14465</Data> + <Data internal="true" type="double" id="9" >-8.1927</Data> + <Data internal="true" type="double" id="10" >-2.01515</Data> + <Data internal="true" type="double" id="11" >-8.36478</Data> + <Data internal="true" type="double" id="12" >1.36478</Data> + <Data internal="true" type="double" id="13" >-7.48428</Data> + <Data internal="true" type="double" id="14" >2.64151</Data> + <Data internal="true" type="double" id="15" >-4.88679</Data> + <Data internal="true" type="double" id="16" >3.12579</Data> + <Data internal="true" type="double" id="17" >-3.03774</Data> + <Data internal="true" type="double" id="18" >1.49686</Data> + <Data internal="true" type="double" id="19" >-6.25157</Data> + <Data internal="true" type="double" id="20" >3.91824</Data> + <Data internal="true" type="double" id="21" >-2.06918</Data> + <Data internal="true" type="double" id="22" >-3.47799</Data> + <Data internal="true" type="int" id="23" >1</Data> + <Data internal="true" type="int" id="24" >2</Data> + <Data internal="true" type="int" id="25" >3</Data> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="26" color="#0000ff" > + <Parent id="1" /> + <Parent id="2" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="27" color="#0000ff" > + <Parent id="3" /> + <Parent id="4" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="28" color="#0000ff" > + <Parent id="5" /> + <Parent id="6" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="29" color="#0000ff" > + <Parent id="7" /> + <Parent id="8" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="30" color="#0000ff" > + <Parent id="9" /> + <Parent id="10" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="31" color="#0000ff" > + <Parent id="11" /> + <Parent id="12" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="32" color="#0000ff" > + <Parent id="13" /> + <Parent id="14" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="33" color="#0000ff" > + <Parent id="15" /> + <Parent id="16" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="34" color="#0000ff" > + <Parent id="17" /> + <Parent id="18" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="35" color="#0000ff" > + <Parent id="19" /> + <Parent id="20" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="36" color="#0000ff" > + <Parent id="21" /> + <Parent id="22" /> + </Object> + <Object width="-1" internal="false" shown="true" type="CubicB9P" id="37" color="#0000ff" > + <Parent id="26" /> + <Parent id="27" /> + <Parent id="28" /> + <Parent id="29" /> + <Parent id="30" /> + <Parent id="31" /> + <Parent id="32" /> + <Parent id="33" /> + <Parent id="34" /> + </Object> + <Object width="-1" internal="false" shown="true" type="LineAB" id="38" color="#0000ff" > + <Parent id="35" /> + <Parent id="36" /> + </Object> + <Object width="-1" internal="false" shown="true" type="LineCubicIntersection" id="39" color="#0000ff" > + <Parent id="37" /> + <Parent id="38" /> + <Parent id="23" /> + </Object> + <Object width="-1" internal="false" shown="true" type="LineCubicIntersection" id="40" color="#0000ff" > + <Parent id="37" /> + <Parent id="38" /> + <Parent id="24" /> + </Object> + <Object width="-1" internal="false" shown="true" type="LineCubicIntersection" id="41" color="#0000ff" > + <Parent id="37" /> + <Parent id="38" /> + <Parent id="25" /> + </Object> + </Objects> +</KigDocument> diff --git a/kig/filters/tests/intersectandasymptotestest.kig b/kig/filters/tests/intersectandasymptotestest.kig new file mode 100644 index 00000000..d521e241 --- /dev/null +++ b/kig/filters/tests/intersectandasymptotestest.kig @@ -0,0 +1,111 @@ +<!DOCTYPE KigDocument> +<KigDocument Version="0.6.0" > + <CoordinateSystem>Euclidean</CoordinateSystem> + <Objects> + <Data internal="true" type="double" id="1" >-6.73585</Data> + <Data internal="true" type="double" id="2" >-1.0566</Data> + <Data internal="true" type="double" id="3" >-2.92721</Data> + <Data internal="true" type="double" id="4" >2.22373</Data> + <Data internal="true" type="double" id="5" >-5.45912</Data> + <Data internal="true" type="double" id="6" >4.40252</Data> + <Data internal="true" type="double" id="7" >-6.16352</Data> + <Data internal="true" type="double" id="8" >2.11321</Data> + <Data internal="true" type="int" id="9" >-1</Data> + <Data internal="true" type="int" id="10" >1</Data> + <Data internal="true" type="double" id="11" >-12.1069</Data> + <Data internal="true" type="double" id="12" >1.0566</Data> + <Data internal="true" type="double" id="13" >2.50943</Data> + <Data internal="true" type="double" id="14" >-1.10063</Data> + <Data internal="true" type="int" id="15" >1</Data> + <Data internal="true" type="int" id="16" >-1</Data> + <Data internal="true" type="double" id="17" >1.84906</Data> + <Data internal="true" type="double" id="18" >1.45283</Data> + <Data internal="true" type="double" id="19" >7.04403</Data> + <Data internal="true" type="double" id="20" >1.49686</Data> + <Data internal="true" type="double" id="21" >6.42767</Data> + <Data internal="true" type="double" id="22" >-0.440252</Data> + <Data internal="true" type="int" id="23" >1</Data> + <Data internal="true" type="int" id="24" >-1</Data> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="25" color="#0000ff" > + <Parent id="1" /> + <Parent id="2" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="26" color="#0000ff" > + <Parent id="3" /> + <Parent id="4" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="27" color="#0000ff" > + <Parent id="5" /> + <Parent id="6" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="28" color="#0000ff" > + <Parent id="7" /> + <Parent id="8" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="29" color="#0000ff" > + <Parent id="11" /> + <Parent id="12" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="30" color="#0000ff" > + <Parent id="13" /> + <Parent id="14" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="31" color="#0000ff" > + <Parent id="17" /> + <Parent id="18" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="32" color="#0000ff" > + <Parent id="19" /> + <Parent id="20" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="33" color="#0000ff" > + <Parent id="21" /> + <Parent id="22" /> + </Object> + <Object width="-1" internal="false" shown="true" type="CircleBCP" id="34" color="#0000ff" > + <Parent id="25" /> + <Parent id="26" /> + </Object> + <Object width="-1" internal="false" shown="true" type="SegmentAB" id="35" color="#0000ff" > + <Parent id="27" /> + <Parent id="28" /> + </Object> + <Object width="-1" internal="false" shown="true" type="LineAB" id="36" color="#0000ff" > + <Parent id="29" /> + <Parent id="30" /> + </Object> + <Object width="-1" internal="false" shown="true" type="HyperbolaBFFP" id="37" color="#0000ff" > + <Parent id="31" /> + <Parent id="32" /> + <Parent id="33" /> + </Object> + <Object width="-1" internal="false" shown="true" type="ConicLineIntersection" id="38" color="#0000ff" > + <Parent id="34" /> + <Parent id="35" /> + <Parent id="9" /> + </Object> + <Object width="-1" internal="false" shown="true" type="ConicLineIntersection" id="39" color="#0000ff" > + <Parent id="34" /> + <Parent id="35" /> + <Parent id="10" /> + </Object> + <Object width="-1" internal="false" shown="true" type="ConicLineIntersection" id="40" color="#0000ff" > + <Parent id="34" /> + <Parent id="36" /> + <Parent id="15" /> + </Object> + <Object width="-1" internal="false" shown="true" type="ConicLineIntersection" id="41" color="#0000ff" > + <Parent id="34" /> + <Parent id="36" /> + <Parent id="16" /> + </Object> + <Object width="-1" internal="false" shown="true" type="ConicAsymptote" id="42" color="#0000ff" > + <Parent id="37" /> + <Parent id="23" /> + </Object> + <Object width="-1" internal="false" shown="true" type="ConicAsymptote" id="43" color="#0000ff" > + <Parent id="37" /> + <Parent id="24" /> + </Object> + </Objects> +</KigDocument> diff --git a/kig/filters/tests/intersection-test.seg b/kig/filters/tests/intersection-test.seg Binary files differnew file mode 100644 index 00000000..44d69b70 --- /dev/null +++ b/kig/filters/tests/intersection-test.seg diff --git a/kig/filters/tests/invisibleLine.FIG b/kig/filters/tests/invisibleLine.FIG new file mode 100644 index 00000000..5eeb6ae3 --- /dev/null +++ b/kig/filters/tests/invisibleLine.FIG @@ -0,0 +1,32 @@ +FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.159375 -0.608541666666667
+
+4: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -2.91041666666667 3.54541666666667
+
+5: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 2.19604166666667 0.79375
+
+6: Line, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, I, nSt
+Const: 5 3
+
+7: Perp, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 4 6
+
diff --git a/kig/filters/tests/lineBTP.FIG b/kig/filters/tests/lineBTP.FIG new file mode 100644 index 00000000..7926b787 --- /dev/null +++ b/kig/filters/tests/lineBTP.FIG @@ -0,0 +1,24 @@ +FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.318125 2.16958333333333
+
+4: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -1.29645833333333 3.01625
+
+5: Line, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 3 4
+
diff --git a/kig/filters/tests/linebyonepoint.FIG b/kig/filters/tests/linebyonepoint.FIG new file mode 100644 index 00000000..4cdac84e --- /dev/null +++ b/kig/filters/tests/linebyonepoint.FIG @@ -0,0 +1,20 @@ +FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.683125 1.93145833333333
+
+4: Line, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 3, Val: 0.972745500001038 0.231875380814201
+
diff --git a/kig/filters/tests/locus.fgeo b/kig/filters/tests/locus.fgeo new file mode 100644 index 00000000..a914068c --- /dev/null +++ b/kig/filters/tests/locus.fgeo @@ -0,0 +1,2 @@ +<?xml version="1.0"?> +<drgenius><drgeo name="Figuur 1" scale="30.000000" origin_x="0.000000" origin_y="0.000000" grid="False"><point id="8293DE0" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>-1.666666</x><y>3.216667</y></point><point id="8306C70" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>-2.766667</x><y>0.550000</y></point><circle id="8307268" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name=""><parent ref="8293DE0"/><parent ref="8306C70"/></circle><point id="8309098" type="On_curve" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><value>0.080691</value><parent ref="8307268"/></point><point id="830A920" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>3.000000</x><y>3.016667</y></point><line id="8172970" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name=""><parent ref="8309098"/><parent ref="830A920"/></line><point id="8339730" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>2.866667</x><y>-0.750000</y></point><line id="833AD18" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name=""><parent ref="8309098"/><parent ref="8339730"/></line><point id="8338A50" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>2.600000</x><y>3.816667</y></point><line id="833BBB8" type="perpendicular" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name=""><parent ref="8338A50"/><parent ref="833AD18"/></line><point id="8342478" type="Intersection" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name="" extra="0"><parent ref="8172970"/><parent ref="833BBB8"/></point><locus id="8345D60" type="None" color="Black" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><parent ref="8309098"/><parent ref="8342478"/></locus></drgeo></drgenius> diff --git a/kig/filters/tests/lotsOfObjects.FIG b/kig/filters/tests/lotsOfObjects.FIG new file mode 100644 index 00000000..67b24164 --- /dev/null +++ b/kig/filters/tests/lotsOfObjects.FIG @@ -0,0 +1,148 @@ +FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -6.72041666666667 3.94229166666667
+
+4: Line, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 3, Val: -0.0202661071897195 -0.999794621359494
+
+5: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 0.582083333333333 2.35479166666667
+
+6: Line, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 5 3
+
+7: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.78895833333333 -0.661458333333333
+
+8: Seg, 0, CN:2, VN:0
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 5 7
+
+9: Ray, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 7, Val: 0.965226371919943 -0.261415475728318
+
+10: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -2.19604166666667 -2.56645833333333
+
+11: Ray, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 7 10
+
+12: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:0, V, nSt
+Val: -0.687916666666667 -0.820208333333333
+
+13: Vec, 0, CN:2, VN:0
+P, W, t, DS:1 1, GT:0, V, nSt
+Const: 10 12
+
+14: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 3.75708333333333 -0.661458333333333
+
+15: Cir, 0, CN:1, VN:2
+Bl, W, t, DS:1 1, GT:0, V, nSt
+Const: 14, Val: 2.32351774734393
+
+16: Cir, 0, CN:2, VN:2
+Bl, W, t, DS:1 1, GT:0, V, nSt
+Const: 14 5
+
+17: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.70958333333333 2.19604166666667
+
+18: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -6.19125 1.00541666666667
+
+19: Arc, 0, CN:3, VN:4
+R, W, t, DS:1 1, GT:0, V, nSt
+Const: 7 17 18
+
+20: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -2.96333333333333 3.78354166666667
+
+21: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -0.0264583333333333 4.1275
+
+22: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 1.95791666666667 2.69875
+
+23: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 0.0264583333333333 0.582083333333333
+
+24: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.25979166666667 1.08479166666667
+
+25: Con, 1, CN:5, VN:6
+Bl, W, t, DS:1 1, GT:0, V, nSt
+Const: 20 21 22 23 24
+
+26: Perp, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 14 11
+
+27: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.37104166666667 -2.56645833333333
+
+28: Par, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 27 11
+
+29: Mid, 0, CN:1, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Const: 13
+
+30: Mid, 0, CN:1, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Const: 8
+
+31: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.97958333333333 3.254375
+
+32: Mid, 0, CN:2, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Const: 31 18
+
+33: PBiss, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 8
+
+34: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.55083333333333 -2.460625
+
+35: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -3.889375 -1.71979166666667
+
+36: PBiss, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 34 35
+
diff --git a/kig/filters/tests/python-script.kig b/kig/filters/tests/python-script.kig new file mode 100644 index 00000000..edac8b48 --- /dev/null +++ b/kig/filters/tests/python-script.kig @@ -0,0 +1,29 @@ +<!DOCTYPE KigDocument> +<KigDocument Version="0.5.1" > + <CoordinateSystem>Euclidean</CoordinateSystem> + <Objects> + <Data internal="true" type="double" id="1" >-3.93514</Data> + <Data internal="true" type="double" id="2" >2.97568</Data> + <Data internal="true" type="double" id="3" >-2.03636</Data> + <Data internal="true" type="double" id="4" >1.57224</Data> + <Data internal="true" type="string" id="5" >def calc( arg1, arg2 ): + return Point( ( arg1.coordinate() + arg2.coordinate() ) / 2 ) +</Data> + <Object width="-1" internal="false" shown="true" type="FixedPoint" id="6" color="#0000ff" > + <Parent id="1" /> + <Parent id="2" /> + </Object> + <Object width="-1" internal="false" shown="true" type="FixedPoint" id="7" color="#0000ff" > + <Parent id="3" /> + <Parent id="4" /> + </Object> + <Object width="-1" internal="true" shown="true" type="PythonCompileType" id="8" color="#0000ff" > + <Parent id="5" /> + </Object> + <Object width="-1" internal="false" shown="true" type="PythonExecuteType" id="9" color="#0000ff" > + <Parent id="8" /> + <Parent id="6" /> + <Parent id="7" /> + </Object> + </Objects> +</KigDocument> diff --git a/kig/filters/tests/radicallinestest.kig b/kig/filters/tests/radicallinestest.kig new file mode 100644 index 00000000..82b1e564 --- /dev/null +++ b/kig/filters/tests/radicallinestest.kig @@ -0,0 +1,85 @@ +<!DOCTYPE KigDocument> +<KigDocument Version="0.6.0" > + <CoordinateSystem>Euclidean</CoordinateSystem> + <Objects> + <Data internal="true" type="double" id="1" >-3.43396</Data> + <Data internal="true" type="double" id="2" >1.54088</Data> + <Data internal="true" type="double" id="3" >-1.10063</Data> + <Data internal="true" type="double" id="4" >2.01216</Data> + <Data internal="true" type="double" id="5" >-0.0880503</Data> + <Data internal="true" type="double" id="6" >-0.748428</Data> + <Data internal="true" type="double" id="7" >-2.28931</Data> + <Data internal="true" type="double" id="8" >0.968553</Data> + <Data internal="true" type="double" id="9" >-0.836478</Data> + <Data internal="true" type="double" id="10" >4.35849</Data> + <Data internal="true" type="int" id="11" >1</Data> + <Data internal="true" type="int" id="12" >1</Data> + <Data internal="true" type="int" id="13" >-1</Data> + <Data internal="true" type="int" id="14" >1</Data> + <Data internal="true" type="double" id="15" >5.50314</Data> + <Data internal="true" type="double" id="16" >-0.0440252</Data> + <Data internal="true" type="double" id="17" >1.01258</Data> + <Data internal="true" type="double" id="18" >1.80503</Data> + <Data internal="true" type="int" id="19" >1</Data> + <Data internal="true" type="int" id="20" >1</Data> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="21" color="#0000ff" > + <Parent id="1" /> + <Parent id="2" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="22" color="#0000ff" > + <Parent id="3" /> + <Parent id="4" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="23" color="#0000ff" > + <Parent id="5" /> + <Parent id="6" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="24" color="#0000ff" > + <Parent id="7" /> + <Parent id="8" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="25" color="#0000ff" > + <Parent id="9" /> + <Parent id="10" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="26" color="#0000ff" > + <Parent id="15" /> + <Parent id="16" /> + </Object> + <Object width="5" internal="false" shown="true" type="FixedPoint" id="27" color="#0000ff" > + <Parent id="17" /> + <Parent id="18" /> + </Object> + <Object width="-1" internal="false" shown="true" type="CircleBCP" id="28" color="#0000ff" > + <Parent id="21" /> + <Parent id="22" /> + </Object> + <Object width="-1" internal="false" shown="true" type="CircleBTP" id="29" color="#0000ff" > + <Parent id="23" /> + <Parent id="24" /> + <Parent id="25" /> + </Object> + <Object width="-1" internal="false" shown="true" type="CircleBCP" id="30" color="#0000ff" > + <Parent id="26" /> + <Parent id="27" /> + </Object> + <Object width="-1" internal="false" shown="true" type="ConicRadical" id="31" color="#0000ff" > + <Parent id="28" /> + <Parent id="29" /> + <Parent id="11" /> + <Parent id="12" /> + </Object> + <Object width="-1" internal="false" shown="true" type="ConicRadical" id="32" color="#0000ff" > + <Parent id="28" /> + <Parent id="29" /> + <Parent id="13" /> + <Parent id="14" /> + </Object> + <Object width="-1" internal="false" shown="true" type="ConicRadical" id="33" color="#0000ff" > + <Parent id="29" /> + <Parent id="30" /> + <Parent id="19" /> + <Parent id="20" /> + </Object> + </Objects> +</KigDocument> diff --git a/kig/filters/tests/stylestest.kig b/kig/filters/tests/stylestest.kig new file mode 100644 index 00000000..f9a91951 --- /dev/null +++ b/kig/filters/tests/stylestest.kig @@ -0,0 +1,27 @@ +<!DOCTYPE KigDocument> +<KigDocument Version="0.7.1" > + <CoordinateSystem>Euclidean</CoordinateSystem> + <Hierarchy> + <Data type="double" id="1" >-3.41511</Data> + <Data type="double" id="2" >-0.798177</Data> + <Data type="double" id="3" >2.53813</Data> + <Data type="double" id="4" >3.67781</Data> + <Object type="FixedPoint" id="5" > + <Parent id="1" /> + <Parent id="3" /> + </Object> + <Object type="FixedPoint" id="6" > + <Parent id="4" /> + <Parent id="2" /> + </Object> + <Object type="LineAB" id="7" > + <Parent id="5" /> + <Parent id="6" /> + </Object> + </Hierarchy> + <View> + <Draw width="-1" point-style="Round" style="DashLine" shown="true" color="#0000ff" object="7" /> + <Draw width="-1" point-style="Cross" style="SolidLine" shown="true" color="#0000ff" object="5" /> + <Draw width="-1" point-style="RectangularEmpty" style="SolidLine" shown="true" color="#0000ff" object="6" /> + </View> +</KigDocument> diff --git a/kig/filters/tests/test.kgeo b/kig/filters/tests/test.kgeo new file mode 100644 index 00000000..e0edaa9d --- /dev/null +++ b/kig/filters/tests/test.kgeo @@ -0,0 +1,145 @@ +[Colors] +Background=255,255,255 +Draw=0,0,0 + +[Main] +Axes=true +Grid=true +Number=17 +Numbers=true +Scaling=false +Version=KGeo 1.0.2 +XMax=11 +YMax=7 + +[Object 1] +Color=0,0,0 +Geo=1 +Parents= +Position=1 +QPointX=-3.4 +QPointY=1.3 +Size=3 + +[Object 10] +Color=0,0,0 +Geo=31 +Parents=8,9 +Size=1 + +[Object 11] +Color=0,0,0 +Geo=27 +Parents=5,7 +Size=1 + +[Object 12] +Color=0,0,0 +Geo=29 +Parents=9,5 +Size=1 + +[Object 13] +Color=0,0,0 +Geo=1 +Parents= +Position=1 +QPointX=3.8 +QPointY=-1.7 +Size=3 + +[Object 14] +Color=0,0,0 +Geo=32 +Parents=13,11 +Position=1 +QPointX=-0.2 +QPointY=-0.3 +Size=3 + +[Object 15] +Color=0,0,0 +Geo=1 +Parents= +Position=1 +QPointX=-7.4 +QPointY=7.8 +Size=3 + +[Object 16] +Color=0,0,0 +Geo=1 +Parents= +Position=1 +QPointX=-7.4 +QPointY=6.4 +Size=3 + +[Object 17] +Color=0,0,0 +Geo=9 +Parents=15,16 +Position=1 +QPointX=-7.4 +QPointY=5 +Size=3 + +[Object 2] +Color=0,0,0 +Geo=1 +Parents= +Position=1 +QPointX=-3.4 +QPointY=2.4 +Size=3 + +[Object 3] +Color=0,0,0 +Geo=3 +Parents=1,2 +Size=1 + +[Object 4] +Color=0,0,0 +Geo=4 +Parents=1,2 +Size=1 + +[Object 5] +Color=0,0,0 +Geo=1 +Parents= +Position=1 +QPointX=1.5 +QPointY=3.6 +Size=3 + +[Object 6] +Color=0,0,0 +Geo=2 +Parents=1,5 +Size=1 + +[Object 7] +Color=0,0,0 +Geo=1 +Parents= +Position=1 +QPointX=-2.5 +QPointY=5 +Size=3 + +[Object 8] +Color=0,0,0 +Geo=30 +Parents=6,7 +Size=1 + +[Object 9] +Color=0,0,0 +Geo=1 +Parents= +Position=1 +QPointX=-5.1 +QPointY=-4.1 +Size=3 diff --git a/kig/filters/tests/test.seg b/kig/filters/tests/test.seg Binary files differnew file mode 100644 index 00000000..d51c281d --- /dev/null +++ b/kig/filters/tests/test.seg diff --git a/kig/filters/tests/testalotofeverything.kig b/kig/filters/tests/testalotofeverything.kig new file mode 100644 index 00000000..1e7a5fcb --- /dev/null +++ b/kig/filters/tests/testalotofeverything.kig @@ -0,0 +1,174 @@ +<!DOCTYPE KigDocument> +<KigDocument Version="0.7.1" > + <CoordinateSystem>Euclidean</CoordinateSystem> + <Hierarchy> + <Data type="double" id="1" >4.20683</Data> + <Data type="double" id="2" >-1.93144</Data> + <Data type="double" id="3" >0.661451</Data> + <Data type="double" id="4" >-2.91039</Data> + <Data type="double" id="5" >0.694042</Data> + <Data type="double" id="6" >-2.38123</Data> + <Data type="double" id="7" >-2.27539</Data> + <Data type="double" id="8" >3.2808</Data> + <Data type="double" id="9" >-0.8202</Data> + <Data type="double" id="10" >0.24161</Data> + <Data type="double" id="11" >2.0671</Data> + <Data type="double" id="12" >5.39744</Data> + <Data type="double" id="13" >2.17293</Data> + <Data type="double" id="14" >5.39744</Data> + <Data type="double" id="15" >-1.66686</Data> + <Data type="double" id="16" >-0.0760034</Data> + <Data type="double" id="17" >3.09559</Data> + <Data type="double" id="18" >0.434012</Data> + <Data type="int" id="19" >1</Data> + <Data type="double" id="20" >-3.91579</Data> + <Data type="double" id="21" >6.42931</Data> + <Data type="double" id="22" >4.73936</Data> + <Data type="string" id="23" >%1</Data> + <Data type="double" id="24" >-1.34936</Data> + <Data type="point" id="25" > + <x>4.55079</x> + <y>3.67767</y> + </Data> + <Data type="double" id="26" >-1.76794</Data> + <Data type="hierarchy" id="27" > + <input requirement="point" id="1" /> + <input requirement="point" id="2" /> + <input requirement="double" id="3" /> + <intermediate action="calc" type="LineAB" id="4" > + <arg>1</arg> + <arg>2</arg> + </intermediate> + <result action="calc" type="ConstrainedPoint" id="5" > + <arg>3</arg> + <arg>4</arg> + </result> + </Data> + <Data type="double" id="28" >1.93481</Data> + <Data type="string" id="29" >def calc( arg1 ): + return Point( arg1.coordinate() + Coordinate( 1,.8))</Data> + <Object type="FixedPoint" id="30" > + <Parent id="3" /> + <Parent id="2" /> + </Object> + <Object type="FixedPoint" id="31" > + <Parent id="7" /> + <Parent id="9" /> + </Object> + <Object type="FixedPoint" id="32" > + <Parent id="15" /> + <Parent id="6" /> + </Object> + <Object type="FixedPoint" id="33" > + <Parent id="12" /> + <Parent id="16" /> + </Object> + <Object type="FixedPoint" id="34" > + <Parent id="17" /> + <Parent id="8" /> + </Object> + <Object type="FixedPoint" id="35" > + <Parent id="20" /> + <Parent id="11" /> + </Object> + <Object type="FixedPoint" id="36" > + <Parent id="1" /> + <Parent id="21" /> + </Object> + <Object type="FixedPoint" id="37" > + <Parent id="4" /> + <Parent id="22" /> + </Object> + <Object type="FixedPoint" id="38" > + <Parent id="24" /> + <Parent id="13" /> + </Object> + <Object type="FixedPoint" id="39" > + <Parent id="26" /> + <Parent id="18" /> + </Object> + <Object type="FixedPoint" id="40" > + <Parent id="14" /> + <Parent id="28" /> + </Object> + <Object type="PythonCompileType" id="41" > + <Parent id="29" /> + </Object> + <Object type="Vector" id="42" > + <Parent id="36" /> + <Parent id="34" /> + </Object> + <Object type="Vector" id="43" > + <Parent id="35" /> + <Parent id="38" /> + </Object> + <Object type="CircleBCP" id="44" > + <Parent id="33" /> + <Parent id="40" /> + </Object> + <Object type="PythonExecuteType" id="45" > + <Parent id="41" /> + <Parent id="37" /> + </Object> + <Object type="LineByVector" id="46" > + <Parent id="43" /> + <Parent id="37" /> + </Object> + <Object type="VectorEquality" id="47" > + <Parent id="43" /> + <Parent id="42" /> + </Object> + <Object type="ConstrainedPoint" id="48" > + <Parent id="10" /> + <Parent id="44" /> + </Object> + <Object type="Locus" id="49" > + <Parent id="27" /> + <Parent id="44" /> + <Parent id="39" /> + <Parent id="5" /> + </Object> + <Property which="test-result" id="50" > + <Parent id="47" /> + </Property> + <Object type="LineAB" id="51" > + <Parent id="48" /> + <Parent id="39" /> + </Object> + <Object type="Similitude" id="52" > + <Parent id="49" /> + <Parent id="31" /> + <Parent id="32" /> + <Parent id="30" /> + </Object> + <Object type="Label" id="53" > + <Parent id="19" /> + <Parent id="25" /> + <Parent id="23" /> + <Parent id="50" /> + </Object> + </Hierarchy> + <View> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="35" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="39" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="48" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="51" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="53" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="30" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="43" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="31" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="38" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="40" /> + <Draw width="5" point-style="Round" style="SolidLine" shown="true" color="#ffff00" object="52" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="42" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="34" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="32" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="33" /> + <Draw width="7" point-style="Round" style="DotLine" shown="true" color="#a0a0a4" object="49" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="36" /> + <Draw width="7" point-style="Round" style="DashDotDotLine" shown="true" color="#00ff00" object="46" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="44" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="37" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="45" /> + </View> +</KigDocument> diff --git a/kig/filters/tests/testlocuswithinvalidpoints.kig b/kig/filters/tests/testlocuswithinvalidpoints.kig new file mode 100644 index 00000000..6bb3f57d --- /dev/null +++ b/kig/filters/tests/testlocuswithinvalidpoints.kig @@ -0,0 +1,177 @@ +<!DOCTYPE KigDocument> +<KigDocument Version="0.7.1" > + <CoordinateSystem>Euclidean</CoordinateSystem> + <Hierarchy> + <Data type="int" id="1" >0</Data> + <Data type="hierarchy" id="2" > + <input requirement="point" id="1" /> + <input requirement="double" id="2" /> + <input requirement="circle" id="3" /> + <input requirement="int" id="4" /> + <intermediate action="calc" type="CircleBPR" id="5" > + <arg>1</arg> + <arg>2</arg> + </intermediate> + <intermediate action="calc" type="CircleCircleIntersection" id="6" > + <arg>3</arg> + <arg>5</arg> + <arg>4</arg> + </intermediate> + <intermediate action="calc" type="SegmentAB" id="7" > + <arg>6</arg> + <arg>1</arg> + </intermediate> + <result action="fetch-property" property="mid-point" id="8" > + <arg>7</arg> + </result> + </Data> + <Data type="double" id="3" >-1.40273</Data> + <Data type="double" id="4" >-0.608162</Data> + <Data type="int" id="5" >1</Data> + <Data type="int" id="6" >0</Data> + <Data type="double" id="7" >1.74813</Data> + <Data type="double" id="8" >-8.26962</Data> + <Data type="double" id="9" >-2.18736</Data> + <Data type="double" id="10" >-9.17811</Data> + <Data type="double" id="11" >-8.44019</Data> + <Data type="double" id="12" >-9.66304</Data> + <Data type="string" id="13" >Q</Data> + <Data type="double" id="14" >3.24779</Data> + <Data type="double" id="15" >-0.401053</Data> + <Data type="double" id="16" >3.41264</Data> + <Data type="double" id="17" >-0.327406</Data> + <Data type="double" id="18" >2.46458</Data> + <Data type="double" id="19" >-9.94648</Data> + <Data type="string" id="20" >P</Data> + <Data type="double" id="21" >-0.816147</Data> + <Data type="int" id="22" >-1</Data> + <Data type="double" id="23" >-5.54805</Data> + <Data type="double" id="24" >0.177996</Data> + <Object type="FixedPoint" id="25" > + <Parent id="8" /> + <Parent id="7" /> + </Object> + <Object type="FixedPoint" id="26" > + <Parent id="12" /> + <Parent id="14" /> + </Object> + <Object type="FixedPoint" id="27" > + <Parent id="10" /> + <Parent id="15" /> + </Object> + <Object type="FixedPoint" id="28" > + <Parent id="11" /> + <Parent id="16" /> + </Object> + <Object type="FixedPoint" id="29" > + <Parent id="4" /> + <Parent id="18" /> + </Object> + <Object type="FixedPoint" id="30" > + <Parent id="19" /> + <Parent id="9" /> + </Object> + <Object type="FixedPoint" id="31" > + <Parent id="17" /> + <Parent id="21" /> + </Object> + <Object type="FixedPoint" id="32" > + <Parent id="23" /> + <Parent id="3" /> + </Object> + <Object type="SegmentAB" id="33" > + <Parent id="27" /> + <Parent id="25" /> + </Object> + <Object type="SegmentAB" id="34" > + <Parent id="26" /> + <Parent id="28" /> + </Object> + <Object type="SegmentAB" id="35" > + <Parent id="30" /> + <Parent id="32" /> + </Object> + <Property which="length" id="36" > + <Parent id="33" /> + </Property> + <Property which="length" id="37" > + <Parent id="34" /> + </Property> + <Property which="length" id="38" > + <Parent id="35" /> + </Property> + <Object type="CircleBPR" id="39" > + <Parent id="29" /> + <Parent id="36" /> + </Object> + <Object type="CircleBPR" id="40" > + <Parent id="31" /> + <Parent id="37" /> + </Object> + <Object type="ConstrainedPoint" id="41" > + <Parent id="24" /> + <Parent id="40" /> + </Object> + <Object type="Locus" id="42" > + <Parent id="2" /> + <Parent id="40" /> + <Parent id="38" /> + <Parent id="39" /> + <Parent id="5" /> + </Object> + <Object type="CircleBPR" id="43" > + <Parent id="41" /> + <Parent id="38" /> + </Object> + <Object type="Label" id="44" > + <Parent id="1" /> + <Parent id="41" /> + <Parent id="20" /> + </Object> + <Object type="CircleCircleIntersection" id="45" > + <Parent id="39" /> + <Parent id="43" /> + <Parent id="22" /> + </Object> + <Object type="CircleCircleIntersection" id="46" > + <Parent id="39" /> + <Parent id="43" /> + <Parent id="5" /> + </Object> + <Object type="SegmentAB" id="47" > + <Parent id="46" /> + <Parent id="41" /> + </Object> + <Property which="mid-point" id="48" > + <Parent id="47" /> + </Property> + <Object type="Label" id="49" > + <Parent id="6" /> + <Parent id="48" /> + <Parent id="13" /> + </Object> + </Hierarchy> + <View> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="44" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="26" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="42" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="43" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="33" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="30" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="46" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="49" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="41" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="31" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="27" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="35" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="28" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="40" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="32" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="39" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="45" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="25" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="29" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="48" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="34" /> + </View> +</KigDocument> diff --git a/kig/filters/tests/testnames.kig b/kig/filters/tests/testnames.kig new file mode 100644 index 00000000..3fd10730 --- /dev/null +++ b/kig/filters/tests/testnames.kig @@ -0,0 +1,62 @@ +<!DOCTYPE KigDocument> +<KigDocument Version="0.7.1" > + <CoordinateSystem>Euclidean</CoordinateSystem> + <Hierarchy> + <Data type="int" id="1" >0</Data> + <Data type="double" id="2" >1.3131</Data> + <Data type="string" id="3" >%1</Data> + <Data type="double" id="4" >-4.04756</Data> + <Data type="double" id="5" >4.22311</Data> + <Data type="double" id="6" >0.661366</Data> + <Data type="int" id="7" >0</Data> + <Data type="double" id="8" >0.55381</Data> + <Data type="string" id="9" >%1</Data> + <Data type="string" id="10" >ab</Data> + <Data type="int" id="11" >0</Data> + <Data type="string" id="12" >%1</Data> + <Data type="string" id="13" >a</Data> + <Data type="string" id="14" >b</Data> + <Object type="FixedPoint" id="15" > + <Parent id="4" /> + <Parent id="2" /> + </Object> + <Object type="FixedPoint" id="16" > + <Parent id="6" /> + <Parent id="5" /> + </Object> + <Object type="Label" id="17" > + <Parent id="11" /> + <Parent id="15" /> + <Parent id="12" /> + <Parent id="14" /> + </Object> + <Object type="SegmentAB" id="18" > + <Parent id="15" /> + <Parent id="16" /> + </Object> + <Object type="Label" id="19" > + <Parent id="1" /> + <Parent id="16" /> + <Parent id="3" /> + <Parent id="13" /> + </Object> + <Object type="ConstrainedPoint" id="20" > + <Parent id="8" /> + <Parent id="18" /> + </Object> + <Object type="Label" id="21" > + <Parent id="7" /> + <Parent id="20" /> + <Parent id="9" /> + <Parent id="10" /> + </Object> + </Hierarchy> + <View> + <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="19" /> + <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="21" /> + <Draw width="-1" point-style="Round" namecalcer="10" style="SolidLine" shown="true" color="#0000ff" object="18" /> + <Draw width="-1" point-style="Round" namecalcer="13" style="SolidLine" shown="true" color="#0000ff" object="16" /> + <Draw width="-1" point-style="Round" namecalcer="14" style="SolidLine" shown="true" color="#0000ff" object="15" /> + <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="17" /> + </View> +</KigDocument> diff --git a/kig/filters/tests/testtest.kig b/kig/filters/tests/testtest.kig new file mode 100644 index 00000000..b232d227 --- /dev/null +++ b/kig/filters/tests/testtest.kig @@ -0,0 +1,66 @@ +<!DOCTYPE KigDocument> +<KigDocument Version="0.7.1" > + <CoordinateSystem>Euclidean</CoordinateSystem> + <Hierarchy> + <Data type="point" id="1" > + <x>0.446592</x> + <y>0.0161959</y> + </Data> + <Data type="double" id="2" >0.278897</Data> + <Data type="double" id="3" >-0.288971</Data> + <Data type="double" id="4" >0.278897</Data> + <Data type="double" id="5" >-2.2855</Data> + <Data type="double" id="6" >-2.92606</Data> + <Data type="double" id="7" >-3.91425</Data> + <Data type="double" id="8" >2.27542</Data> + <Data type="int" id="9" >1</Data> + <Data type="double" id="10" >0.157621</Data> + <Data type="string" id="11" >%1</Data> + <Object type="FixedPoint" id="12" > + <Parent id="3" /> + <Parent id="4" /> + </Object> + <Object type="FixedPoint" id="13" > + <Parent id="5" /> + <Parent id="6" /> + </Object> + <Object type="FixedPoint" id="14" > + <Parent id="7" /> + <Parent id="2" /> + </Object> + <Object type="FixedPoint" id="15" > + <Parent id="10" /> + <Parent id="8" /> + </Object> + <Object type="LineAB" id="16" > + <Parent id="12" /> + <Parent id="13" /> + </Object> + <Object type="SegmentAB" id="17" > + <Parent id="15" /> + <Parent id="14" /> + </Object> + <Object type="AreOrthogonal" id="18" > + <Parent id="16" /> + <Parent id="17" /> + </Object> + <Property which="test-result" id="19" > + <Parent id="18" /> + </Property> + <Object type="Label" id="20" > + <Parent id="9" /> + <Parent id="1" /> + <Parent id="11" /> + <Parent id="19" /> + </Object> + </Hierarchy> + <View> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="14" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="12" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="16" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="13" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="20" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="15" /> + <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="17" /> + </View> +</KigDocument> diff --git a/kig/filters/tests/transform-test.seg b/kig/filters/tests/transform-test.seg Binary files differnew file mode 100644 index 00000000..e2dc7219 --- /dev/null +++ b/kig/filters/tests/transform-test.seg diff --git a/kig/filters/tests/transformlocustest.kig b/kig/filters/tests/transformlocustest.kig new file mode 100644 index 00000000..f9c8500c --- /dev/null +++ b/kig/filters/tests/transformlocustest.kig @@ -0,0 +1,82 @@ +<!DOCTYPE KigDocument> +<KigDocument Version="0.4.0" > + <CoordinateSystem>Euclidean</CoordinateSystem> + <Objects> + <Data type="double" id="1" >-4.86</Data> + <Data type="double" id="2" >0</Data> + <Data type="double" id="3" >-6.93</Data> + <Data type="double" id="4" >0.42</Data> + <Data type="double" id="5" >0.346818</Data> + <Data type="double" id="6" >0.12</Data> + <Data type="double" id="7" >4.14</Data> + <Data type="double" id="8" >0.698969</Data> + <Data type="hierarchy" id="9" > + <input requirement="point" id="1" /> + <input requirement="point" id="2" /> + <input requirement="double" id="3" /> + <intermediate action="calc" type="LineAB" id="4" > + <arg>1</arg> + <arg>2</arg> + </intermediate> + <result action="calc" type="ConstrainedPoint" id="5" > + <arg>3</arg> + <arg>4</arg> + </result> + </Data> + <Data type="double" id="10" >0.15</Data> + <Data type="double" id="11" >0</Data> + <Data type="double" id="12" >3.63</Data> + <Data type="double" id="13" >-0.12</Data> + <Object width="-1" shown="true" type="FixedPoint" id="14" color="#0000ff" > + <Parent id="1" /> + <Parent id="2" /> + </Object> + <Object width="-1" shown="true" type="FixedPoint" id="15" color="#0000ff" > + <Parent id="3" /> + <Parent id="4" /> + </Object> + <Object width="-1" shown="true" type="FixedPoint" id="16" color="#0000ff" > + <Parent id="6" /> + <Parent id="7" /> + </Object> + <Object width="-1" shown="true" type="FixedPoint" id="17" color="#0000ff" > + <Parent id="10" /> + <Parent id="11" /> + </Object> + <Object width="-1" shown="true" type="FixedPoint" id="18" color="#0000ff" > + <Parent id="12" /> + <Parent id="13" /> + </Object> + <Object width="-1" shown="true" type="CircleBCP" id="19" color="#0000ff" > + <Parent id="14" /> + <Parent id="15" /> + </Object> + <Object width="-1" shown="true" type="SegmentAB" id="20" color="#0000ff" > + <Parent id="17" /> + <Parent id="18" /> + </Object> + <Object width="-1" shown="true" type="ConstrainedPoint" id="21" color="#0000ff" > + <Parent id="5" /> + <Parent id="19" /> + </Object> + <Object width="-1" shown="true" type="Locus" id="22" color="#0000ff" > + <Parent id="19" /> + <Parent id="9" /> + <Parent id="16" /> + <Parent id="8" /> + </Object> + <Object width="-1" shown="true" type="LineAB" id="23" color="#0000ff" > + <Parent id="21" /> + <Parent id="16" /> + </Object> + <Object width="-1" shown="true" type="ConstrainedPoint" id="24" color="#0000ff" > + <Parent id="8" /> + <Parent id="23" /> + </Object> + <Object width="-1" shown="true" type="ScalingOverLine" id="25" color="#0000ff" > + <Parent id="22" /> + <Parent id="23" /> + <Parent id="20" /> + </Object> + </Objects> +</KigDocument> |