diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2 (patch) | |
tree | d3bb9f5d25a2dc09ca81adecf39621d871534297 /kig/filters/latexexporter.cc | |
download | tdeedu-ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2.tar.gz tdeedu-ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdeedu@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kig/filters/latexexporter.cc')
-rw-r--r-- | kig/filters/latexexporter.cc | 608 |
1 files changed, 608 insertions, 0 deletions
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 <toscano.pino@tiscali.it> + +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#include <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"; +} |