/***********************************************************************************
 *                                                                                 *
 * Voreen - The Volume Rendering Engine                                            *
 *                                                                                 *
 * Copyright (C) 2005-2013 University of Muenster, Germany.                        *
 * Visualization and Computer Graphics Group <http://viscg.uni-muenster.de>        *
 * For a list of authors please refer to the file "CREDITS.txt".                   *
 *                                                                                 *
 * This file is part of the Voreen software package. Voreen is free software:      *
 * you can redistribute it and/or modify it under the terms of the GNU General     *
 * Public License version 2 as published by the Free Software Foundation.          *
 *                                                                                 *
 * Voreen 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 in the file   *
 * "LICENSE.txt" along with this file. If not, see <http://www.gnu.org/licenses/>. *
 *                                                                                 *
 * For non-commercial academic use see the license exception specified in the file *
 * "LICENSE-academic.txt". To get information about commercial licensing please    *
 * contact the authors.                                                            *
 *                                                                                 *
 ***********************************************************************************/

#include "plotlibrarylatex.h"

#include "plotlibrarylatexrender.h"
#include "../../datastructures/plotrow.h"

#include "voreen/core/voreenapplication.h"
#include "voreen/core/version.h"

#include "tgt/tgt_math.h"
#include "tgt/spline.h"
#include "tgt/matrix.h"
#include "tgt/vector.h"

#include <string>
#include <sstream>
#include <fstream>
#include <iostream>

#include <iomanip>

namespace voreen {

const std::string PlotLibraryLatex::loggerCat_("voreen.plotting.PlotLibraryLatex");

PlotLibraryLatex::PlotLibraryLatex()
    : PlotLibraryFileBase()
    , plotLabelGroup_(&labelFont_, 5, tgt::Bounds(), tgt::Color(1, 1, 1, 0.75))
    , lineLabelGroup_(&labelFont_, 6, tgt::Bounds())
    , xAxisLabelGroup_(&labelFont_, 10, tgt::Bounds())
    , axisLabelGroup_(&labelFont_, 6)
    , latexColor_(0.f,0.f,0.f,1.f)
    , textureNumber_(0)
    , renderVector_()
{
    labelFont_.setSize(8);
    domain_[0] = Interval<plot_t>(0, 1, false, false);
    domain_[1] = Interval<plot_t>(0, 1, false, false);
    domain_[2] = Interval<plot_t>(0, 1, false, false);
    logarithmicAxisFlags_[0] = false;
    logarithmicAxisFlags_[1] = false;
    logarithmicAxisFlags_[2] = false;
    minimumScaleStep_[0] = 40;
    minimumScaleStep_[1] = 40;
    minimumScaleStep_[2] = 40;
}

PlotLibraryLatex::~PlotLibraryLatex() {
    for (size_t i = 0; i < renderVector_.size(); ++i)
        delete renderVector_[i];
    renderVector_.clear();
}

void PlotLibraryLatex::beforeRender() {
    latexOutput_.str("");
    latexOutput_.clear();
    latexColor_ = drawingColor_;
    latexOutput_ << "%LaTeX with PSTricks extensions\n"
        << "%%Creator: http://www.voreen.org " << VoreenVersion::getVersion() << "\n"
        << "%%copyright: " << VoreenVersion::getCopyright() << "\n"
        << "%%Please note this file requires PSTricks extensions\n"
        << "\\documentclass{article}\n"
        << "\\usepackage[utf8]{inputenc}\n"
        << "\\pagestyle{empty}\n"
        << "\\usepackage{pstricks}\n"
        << "\\usepackage{pstricks-add}\n"
        << "\\usepackage{pst-all}\n"
        << "\\usepackage{color}\n"
        << "\\usepackage{multido}\n"
        << "\\usepackage{geometry}\n"
        << "\\geometry{a2paper,left=10mm,right=10mm, top=1cm, bottom=2cm}\n"
        << "\\begin{document}\n"
        << "\\psset{xunit=.75pt,yunit=.75pt,runit=.75pt}\n"
        << "\\begin{pspicture}(" << windowSize_.x << "," << windowSize_.y << ")\n";
    if (viewPortClipping_) {
        latexOutput_ << "\\psclip{\\psframe[strokeopacity=0](-1,-1)(" << windowSize_.x+1
        << "," << windowSize_.y+1 << ")}\n";
    }
    std::vector< PlotLibraryFileBase::Projection_Coordinates > points;
    tgt::Vector3<plot_t> coor = tgt::Vector3<plot_t>(0,0,0);
    points.push_back(Projection_Coordinates(coor,coor,coor));
    coor = tgt::Vector3<plot_t>(windowSize_.x,0,0);
    points.push_back(Projection_Coordinates(coor,coor,coor));
    coor = tgt::Vector3<plot_t>(windowSize_.x,windowSize_.y,0);
    points.push_back(Projection_Coordinates(coor,coor,coor));
    coor = tgt::Vector3<plot_t>(0,windowSize_.y,0);
    points.push_back(Projection_Coordinates(coor,coor,coor));
    PlotLibraryLatexRenderPolygon polygon = PlotLibraryLatexRenderPolygon(points,tgt::Color(0,0,0,0),tgt::Color(1,1,0.995,0.005),0,1,0,PlotEntitySettings::FILLNONE);
    latexOutput_ << polygon.render();
}
namespace {
    struct PlotLibraryLatexSorter {
        bool operator() (PlotLibraryLatexRender* a, PlotLibraryLatexRender* b) const {
            return a->avgValue(PlotLibraryFileBase::PROJECTION,PlotLibrary::Z_AXIS) > b->avgValue(PlotLibraryFileBase::PROJECTION,PlotLibrary::Z_AXIS);
        };
    } PlotLibraryLatexSorter;
};

void PlotLibraryLatex::afterRender() {
    if (dimension_ == THREE) {
        PlotLibraryLatexRenderLine* line;
        PlotLibraryLatexRenderPolygon* polygon;
        std::vector< tgt::Vector3<plot_t> > linePoints, polygonpoints, trianglePoints;
        std::vector< PlotLibraryFileBase::Projection_Coordinates > linecutPoints;
        tgt::Vector3<plot_t> result = tgt::Vector3<plot_t>();
        std::vector< PlotLibraryLatexRender* >::iterator svgit;
        std::vector< PlotLibraryLatexRender* > newLines, cutLines;
        svgit = renderVector_.begin();
        while (svgit < renderVector_.end()) {
            line = dynamic_cast<PlotLibraryLatexRenderLine*>(*svgit);
            if (line != 0) {
                linePoints = line->getPoints(PlotLibraryFileBase::ORIGIN);
                for (size_t j = 0; j < renderVector_.size(); ++j) {
                    polygon = dynamic_cast<PlotLibraryLatexRenderPolygon*>(renderVector_[j]);
                    if (polygon != 0) {
                        polygonpoints = polygon->getPoints(PlotLibraryFileBase::ORIGIN);
                        trianglePoints.clear();
                        if (polygonpoints.size() == 3) {
                            trianglePoints = polygonpoints;
                            if (intersect_Triangle_Ray(linePoints,trianglePoints,&result) == 1)
                                linecutPoints.push_back(projection_neu(result));
                        }
                        else if (polygonpoints.size() == 4) {
                            trianglePoints.push_back(polygonpoints[0]);
                            trianglePoints.push_back(polygonpoints[1]);
                            trianglePoints.push_back(polygonpoints[2]);
                            if (intersect_Triangle_Ray(linePoints,trianglePoints,&result) == 1)
                                linecutPoints.push_back(projection_neu(result));
                            else {
                                trianglePoints.clear();
                                trianglePoints.push_back(polygonpoints[0]);
                                trianglePoints.push_back(polygonpoints[2]);
                                trianglePoints.push_back(polygonpoints[3]);
                                if (intersect_Triangle_Ray(linePoints,trianglePoints,&result) == 1)
                                    linecutPoints.push_back(projection_neu(result));
                            }
                        }
                    }

                }
                if (linecutPoints.size() > 0) {
                    linecutPoints.push_back(line->getPoints()[0]);
                    linecutPoints.push_back(line->getPoints()[1]);
                    std::stable_sort(linecutPoints.begin(),linecutPoints.end(),PlotLibraryPointSorter);
                    cutLines = line->generateLines(linecutPoints);
                    for (size_t i = 0; i < cutLines.size(); ++i) {
                        newLines.push_back(cutLines[i]);
                    }
                    cutLines.clear();
                    delete line;
                    line = 0;
                    svgit = renderVector_.erase(svgit);
                    linecutPoints.clear();
                }
                else
                    ++svgit;
            }
            else
                ++svgit;
        }
        for (size_t i = 0; i < newLines.size(); ++i) {
            renderVector_.push_back(newLines[i]);
        }
        std::stable_sort(renderVector_.begin(),renderVector_.end(),PlotLibraryLatexSorter);
    }
    for (size_t i = 0; i < renderVector_.size(); ++i){
        if (renderVector_[i]->getClippingNumber() == 1) {
            latexOutput_ << "\\psclip{\\psframe[strokeopacity=0]("
                << marginLeft_ << "," << marginBottom_
                << ")(" << windowSize_.x - marginRight_ << ","
                << windowSize_.y - marginTop_ << ")}\n"
                << renderVector_[i]->render()
                << "\\endpsclip\n";
        }
        else if (renderVector_[i]->getClippingNumber() == 2) {
            latexOutput_ << "\\psclip{\\psframe[strokeopacity=0](" << marginLeft_ - maxGlyphSize_/2.0
                << "," << marginBottom_  - maxGlyphSize_/2.0
                << ")(" << windowSize_.x - marginRight_ + maxGlyphSize_ << ","
                << windowSize_.y - marginTop_ + maxGlyphSize_ << ")}\n"
                << renderVector_[i]->render()
                << "\\endpsclip\n";
        }
        else
            latexOutput_ << renderVector_[i]->render();
    }
    if (viewPortClipping_)
        latexOutput_ << "\\endpsclip\n";
    latexOutput_ << "\\end{pspicture}\n\\end{document}";
    std::ofstream latexfile (outputFile_.c_str(),std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    latexfile << latexOutput_.str();
    latexfile.close();
}

bool PlotLibraryLatex::setRenderStatus() {
    if (usePlotPickingManager_)
        return false;
    // helper domains
    invertedmodelviewMatrix_ = tgt::Matrix4<plot_t>::zero;
    plot_t xl = domain_[X_AXIS].getLeft(); plot_t xr = domain_[X_AXIS].getRight();
    plot_t yl = domain_[Y_AXIS].getLeft(); plot_t yr = domain_[Y_AXIS].getRight();
    plot_t zl = domain_[Z_AXIS].getLeft(); plot_t zr = domain_[Z_AXIS].getRight();
    clippingPlanes_.clear();
    renewPlotToViewportScale();
    // for 2D plots setup orthographic projection using margins
    if (dimension_ == TWO || dimension_ == FAKETHREE) {
        //check, if the canvas is big enough
        if (marginLeft_+marginRight_>=windowSize_.x || marginTop_+marginBottom_>=windowSize_.y)
            return false;
        left_ = xl-static_cast<double>(marginLeft_)/plotToViewportScale_.x;
        right_ = xr+static_cast<double>(marginRight_)/plotToViewportScale_.x;
        bottom_ = yl-static_cast<double>(marginBottom_)/plotToViewportScale_.y;
        top_ = yr+static_cast<double>(marginTop_)/plotToViewportScale_.y;
        near_ = zl-1;
        far_ = zr+1;
        projectionsMatrix_ = plOrtho(left_,right_,bottom_,top_,near_,far_);

        modelviewMatrix_ = tgt::Matrix4<plot_t>::createIdentity();
        if (dimension_ == TWO) {
            //set up clipping planes
            tgt::dvec2 leftBottom = convertViewportToPlotCoordinates(tgt::ivec2(marginLeft_,marginBottom_));
            tgt::dvec2 rightTop = convertViewportToPlotCoordinates(tgt::ivec2(windowSize_.x-marginRight_,windowSize_.y-marginTop_));
            clippingPlanes_.push_back(tgt::Vector4<plot_t>(1.0, 0.0, 0.0, -leftBottom.x));
            clippingPlanes_.push_back(tgt::Vector4<plot_t>(-1.0, 0.0, 0.0, rightTop.x));
            clippingPlanes_.push_back(tgt::Vector4<plot_t>(0.0, 1.0, 0.0, -leftBottom.y));
            clippingPlanes_.push_back(tgt::Vector4<plot_t>(0.0, -1.0, 0.0, rightTop.y));
        }
        else { //dimension_ == FAKETHREE
            tgt::Matrix4<plot_t> m = tgt::Matrix4<plot_t>(1,0,0,0,0,1,0,0,-shear_.x*static_cast<double>(xr-xl),
                -shear_.y*static_cast<double>(yr-yl),1,0,0,0,0,1);
            //translation to the center
            ////rescaling
            ////shearing for fake 3d effect
            modelviewMatrix_ = tgt::Matrix4<plot_t>::createTranslation(tgt::Vector3<plot_t>((xl+xr)/2,(yl+yr)/2,(zl+zr)/2))
                * tgt::transpose(m)
                * tgt::Matrix4<plot_t>::createScale(tgt::Vector3<plot_t>(1/(1+shear_.x*static_cast<double>(zr-zl)),1/(1+shear_.y*static_cast<double>(zr-zl)),1))
                * tgt::Matrix4<plot_t>::createTranslation(tgt::Vector3<plot_t>(-(xl+xr)/2,-(yl+yr)/2,-(zl+zr)/2));
        }
    }
    // for 3D plot setup projection using the camera
    else if (dimension_ == THREE) {
        //if (lightingFlag_ == true && usePlotPickingManager_ == false) {
        //}
        modelviewMatrix_ = camera_.getViewMatrix();
        ////plot into [-0.5,0.5]^3
        modelviewMatrix_ = modelviewMatrix_
            * tgt::Matrix4<plot_t>::createTranslation(tgt::Vector3<plot_t>(-0.5,-0.5,-0.5))
            * tgt::Matrix4<plot_t>::createScale(tgt::Vector3<plot_t>(1/domain_[0].size(),1/domain_[1].size(),1/domain_[2].size()))
            * tgt::Matrix4<plot_t>::createTranslation(tgt::Vector3<plot_t>(-domain_[0].getLeft(),-domain_[1].getLeft(),-domain_[2].getLeft()));
        if (orthographicCameraFlag_) {
            left_ = -0.9;
            right_ = 0.9;
            bottom_ = -0.9;
            top_ = 0.9;
            near_ = -2;
            far_ = 10;
            projectionsMatrix_ = plOrtho(left_,right_,bottom_,top_,near_,far_);
        }
        else {
            float aspectRatio = 1.0f; //TODO?
            projectionsMatrix_ = camera_.getProjectionMatrix(aspectRatio);
            camera_.updateFrustum();
            left_ = camera_.getFrustLeft();
            right_ = camera_.getFrustRight();
            bottom_ = camera_.getFrustBottom();
            top_ = camera_.getFrustTop();
            near_ = camera_.getNearDist();
            far_ = camera_.getFarDist();
        }
        clippingPlanes_.push_back(tgt::Vector4<plot_t>(1.0, 0.0, 0.0, -domain_[X_AXIS].getLeft()));
        clippingPlanes_.push_back(tgt::Vector4<plot_t>(-1.0, 0.0, 0.0, domain_[X_AXIS].getRight()));
        clippingPlanes_.push_back(tgt::Vector4<plot_t>(0.0, 1.0, 0.0, -domain_[Y_AXIS].getLeft()));
        clippingPlanes_.push_back(tgt::Vector4<plot_t>(0.0, -1.0, 0.0, domain_[Y_AXIS].getRight()));
        clippingPlanes_.push_back(tgt::Vector4<plot_t>(0.0, 0.0, 1.0, -domain_[Z_AXIS].getLeft()));
        clippingPlanes_.push_back(tgt::Vector4<plot_t>(0.0, 0.0, -1.0, domain_[Z_AXIS].getRight()));

        // we need to calculate which are the outer edges (used for selection and
        // labeling the axes)
        calculateSelectionEdges();
    }
    latexColor_ = drawingColor_;
    textureNumber_ = 0;
    modelviewMatrix_.invert(invertedmodelviewMatrix_);

    return true;
}

void PlotLibraryLatex::renderLine(const PlotData& data, int indexX, int indexY) {
    if (usePlotPickingManager_)
        return;
    //row iterator
    std::vector<PlotRowValue>::const_iterator it = data.getRowsBegin();
    // check if only values or only tags in given cells
    bool tagsInX = (data.getColumnType(indexX) == PlotBase::STRING);
    bool lineIsHighlighted = data.isHighlighted(tgt::ivec2(-1,indexY));
    PlotLibraryFileBase::Projection_Coordinates point1, point2;
    int i = 0;
    double x = 0.0; double y = 0.0; //they are set in the loop
    //go to the first row with non null entries
    while (it->getCellAt(indexX).isNull() || it->getCellAt(indexY).isNull()) {
        ++it; ++i;
    }
    if (it == data.getRowsEnd() || it == --data.getRowsEnd())
        return;

    // draw the line
    double oldX = tagsInX ? i : it->getValueAt(indexX);
    double oldY = it->getValueAt(indexY);
    if (lineIsHighlighted)
        latexColor_ = highlightColor_;
    else
        latexColor_ = drawingColor_;
    for (++it, ++i; it != data.getRowsEnd(); ++it, ++i) {
        //we ignore rows with null entries
        if (it->getCellAt(indexX).isNull() || it->getCellAt(indexY).isNull()) {
            continue;
        }
        x = tagsInX ? i : it->getValueAt(indexX);
        y = it->getValueAt(indexY);
        point1 = convertPlotCoordinatesToViewport3Projection(oldX,oldY,0);
        point2 = convertPlotCoordinatesToViewport3Projection(x,y,0);
        latexLine(point1,point2,latexColor_,1,lineWidth_,lineStyle_);

        //if x is out of the interval, we leave the loop
        if (x>= domain_[X_AXIS].getRight())
            break;
        oldX = x;
        oldY = y;
    }

    // render the points
    for (it = data.getRowsBegin(), i = 0; it != data.getRowsEnd(); ++it, ++i) {
        //we ignore rows with null entries
        if (it->getCellAt(indexX).isNull() || it->getCellAt(indexY).isNull()) {
            continue;
        }
        x = tagsInX ? i : it->getValueAt(indexX);
        y = it->getValueAt(indexY);
        if (it->getCellAt(indexY).isHighlighted())
            latexColor_ = highlightColor_;
        else
            latexColor_ = drawingColor_;
        point2 = convertPlotCoordinatesToViewport3Projection(x,y,0);
        latexCircle(point2,maxGlyphSize_/2,latexColor_,latexColor_,2,1);
    }
}

void PlotLibraryLatex::renderSpline(const PlotData& data, int indexX, int indexY) {
    if (usePlotPickingManager_)
        return;
    std::vector<PlotRowValue>::const_iterator it = data.getRowsBegin(); // row iterator
    tgt::Spline spline;
    std::vector< PlotLibraryFileBase::Projection_Coordinates > points;
    // check if only values or only tags in given cells
    bool tagsInX = (data.getColumnType(indexX) == PlotBase::STRING);
    bool lineIsHighlighted = data.isHighlighted(tgt::ivec2(-1,indexY));
    int i = 0;
    //go to the first row with non null entrys
    while (it->getCellAt(indexX).isNull() || it->getCellAt(indexY).isNull()) {
        ++it; ++i;
    }
    if (it == data.getRowsEnd())
        return;

    // add the control points
    double x = tagsInX ? i : it->getValueAt(indexX);
    double y = it->getValueAt(indexY);
    spline.addControlPoint(tgt::dvec3(x,y,0));
    for (; it != data.getRowsEnd(); ++it, ++i) {
        //we ignore rows with null entries
        if (it->getCellAt(indexX).isNull() || it->getCellAt(indexY).isNull()) {
            continue;
        }
        x = tagsInX ? i : it->getValueAt(indexX);
        y = it->getValueAt(indexY);
        spline.addControlPoint(tgt::dvec3(x,y,0));
    }
    spline.addControlPoint(tgt::dvec3(x,y,0));

    //render spline, possibly with log coordinates
    GLfloat step = 1.f /spline.getStepCount();
    if (lineIsHighlighted)
        latexColor_ = highlightColor_;
    else
        latexColor_ = drawingColor_;
    for (GLfloat p = 0.f; p < 1.f; p+=step) {
        x = spline.getPoint(p).x;
        y = spline.getPoint(p).y;
        points.push_back(convertPlotCoordinatesToViewport3Projection(x,y,0));
        if (x >= domain_[X_AXIS].getRight())
            break;
    }
    latexPolyline(points,latexColor_,latexColor_,1,lineWidth_,PlotEntitySettings::FILLNONE,lineStyle_);

    // render the points
    for (it = data.getRowsBegin(), i = 0; it != data.getRowsEnd(); ++it, ++i) {
        //we ignore rows with null entries
        if (it->getCellAt(indexX).isNull() || it->getCellAt(indexY).isNull()) {
            continue;
        }
        x = tagsInX ? i : it->getValueAt(indexX);
        y = it->getValueAt(indexY);
        if (it->getCellAt(indexY).isHighlighted())
            latexColor_ = highlightColor_;
        else
            latexColor_ = drawingColor_;
        latexCircle(convertPlotCoordinatesToViewport3Projection(x,y,0),maxGlyphSize_/2,latexColor_,latexColor_,2);
    }
}

void PlotLibraryLatex::renderErrorline(const PlotData& data, int indexX, int indexY, int indexError) {
    if (usePlotPickingManager_)
        return;
    std::vector<PlotRowValue>::const_iterator it = data.getRowsBegin();
    std::vector< PlotLibraryFileBase::Projection_Coordinates > points;
    // check if only values or only tags in given cells
    bool tagsInX = (data.getColumnType(indexX) == PlotBase::STRING);

    int i = 0;
    //go to the first row with non null entrys
    while (it->getCellAt(indexX).isNull() || it->getCellAt(indexY).isNull()) {
        ++it; ++i;
    }
    if (it == data.getRowsEnd())
        return;

    double x             = tagsInX ? i : it->getValueAt(indexX);
    double errorTop      = it->getValueAt(indexY) + std::abs(it->getValueAt(indexError));
    double errorBottom   = it->getValueAt(indexY) - std::abs(it->getValueAt(indexError));
    double oldX, oldErrorTop, oldErrorBottom;
    latexColor_ = fillColor_;
    // draw the errorline
    ++i;
    for (it = (++it); it != data.getRowsEnd(); ++it, ++i) {
        if (it->getCellAt(indexX).isNull() || it->getCellAt(indexY).isNull())
            continue;
        if (i > 1) {
            points.clear();
            points.push_back(convertPlotCoordinatesToViewport3Projection(oldX,oldErrorTop,0));
            points.push_back(convertPlotCoordinatesToViewport3Projection(x,errorTop,0));
            points.push_back(convertPlotCoordinatesToViewport3Projection(x,errorBottom,0));
            points.push_back(convertPlotCoordinatesToViewport3Projection(oldX,oldErrorBottom,0));
            latexPolygon(points,latexColor_,latexColor_,1,0);
        }
        oldX = x;
        oldErrorTop = errorTop;
        oldErrorBottom = errorBottom;
        x = tagsInX ? i : it->getValueAt(indexX);
        errorTop = it->getValueAt(indexY) + std::abs(it->getValueAt(indexError));
        errorBottom = it->getValueAt(indexY) - std::abs(it->getValueAt(indexError));
    }
    points.clear();
    points.push_back(convertPlotCoordinatesToViewport3Projection(oldX,oldErrorTop,0));
    points.push_back(convertPlotCoordinatesToViewport3Projection(x,errorTop,0));
    points.push_back(convertPlotCoordinatesToViewport3Projection(x,errorBottom,0));
    points.push_back(convertPlotCoordinatesToViewport3Projection(oldX,oldErrorBottom,0));
    latexPolygon(points,latexColor_,latexColor_,1,0);
}

void PlotLibraryLatex::renderErrorspline(const PlotData& data, int indexX, int indexY, int indexError) {
    if (usePlotPickingManager_)
        return;
    std::vector<PlotRowValue>::const_iterator it = data.getRowsBegin();
    tgt::Spline splineTop, splineBottom;
    std::vector< PlotLibraryFileBase::Projection_Coordinates > points;

    // check if only values or only tags in given cells
    bool tagsInX = (data.getColumnType(indexX) == PlotBase::STRING);
    latexColor_ = fillColor_;
    int i = 0;
    //go to the first row with non null entrys
    while (it->getCellAt(indexX).isNull() || it->getCellAt(indexY).isNull()) {
        ++it; ++i;
    }
    if (it == data.getRowsEnd())
        return;

    //fill the splines

    double x             = tagsInX ? i : it->getValueAt(indexX);
    double errorTop      = it->getValueAt(indexY) + std::abs(it->getValueAt(indexError));
    double errorBottom   = it->getValueAt(indexY) - std::abs(it->getValueAt(indexError));
    splineTop.addControlPoint(tgt::dvec3(x,errorTop,0));
    splineBottom.addControlPoint(tgt::dvec3(x,errorBottom,0));
    for (; it != data.getRowsEnd(); ++it, ++i) {
        if (it->getCellAt(indexX).isNull() || it->getCellAt(indexY).isNull())
            continue;

        x = tagsInX ? i : it->getValueAt(indexX);
        if (it->getCellAt(indexError).isNull()){
            errorTop = it->getValueAt(indexY);
            errorBottom = it->getValueAt(indexY);
        } else {
            errorTop = it->getValueAt(indexY) + std::abs(it->getValueAt(indexError));
            errorBottom = it->getValueAt(indexY) - std::abs(it->getValueAt(indexError));
        }
        splineTop.addControlPoint(tgt::dvec3(x,errorTop,0));
        splineBottom.addControlPoint(tgt::dvec3(x,errorBottom,0));
    }
    splineTop.addControlPoint(tgt::dvec3(x,errorTop,0));
    splineBottom.addControlPoint(tgt::dvec3(x,errorBottom,0));

    //draw the thick spline
    GLfloat step = 1.f /splineTop.getStepCount();
    for (GLfloat p = 0.f; p < 1.f-step; p+=step) {
        points.clear();
        points.push_back(convertPlotCoordinatesToViewport3Projection(splineTop.getPoint(p)));
        points.push_back(convertPlotCoordinatesToViewport3Projection(splineBottom.getPoint(p)));
        points.push_back(convertPlotCoordinatesToViewport3Projection(splineBottom.getPoint(p+step)));
        points.push_back(convertPlotCoordinatesToViewport3Projection(splineTop.getPoint(p+step)));
        latexPolygon(points,latexColor_,latexColor_,1,0);
    }
}

void PlotLibraryLatex::renderErrorbars(const PlotData& data, int indexX, int indexY, int indexError) {
    if (usePlotPickingManager_)
        return;
    PlotLibraryFileBase::Projection_Coordinates p11;
    PlotLibraryFileBase::Projection_Coordinates p12;
    PlotLibraryFileBase::Projection_Coordinates p21;
    PlotLibraryFileBase::Projection_Coordinates p22;
    PlotLibraryFileBase::Projection_Coordinates p31;
    PlotLibraryFileBase::Projection_Coordinates p32;
    std::vector<PlotRowValue>::const_iterator it;
    // check if only values or only tags in given cells
    bool tagsInX = (data.getColumnType(indexX) == PlotBase::STRING);

    float radius = static_cast<float>(domain_[X_AXIS].size()/(4.f*data.getRowsCount()));
    //float aspectRatio = static_cast<float>(windowSize_.x)/static_cast<float>(windowSize_.y)*
    //    static_cast<float>(domain_[Y_AXIS].size() / domain_[X_AXIS].size());

    int i = 0;
    // draw the errorbars
    for (it = data.getRowsBegin(); it != data.getRowsEnd(); ++it, ++i) {
        if (it->getCellAt(indexX).isNull() || it->getCellAt(indexY).isNull() || it->getCellAt(indexError).isNull()) {
            continue;
        }
        double x = tagsInX ? i : it->getValueAt(indexX);
        if (!domain_[X_AXIS].contains(x))
            continue;

        if (it->getCellAt(indexError).isHighlighted())
            latexColor_ = highlightColor_;
        else
            latexColor_ = drawingColor_;

        double y = it->getValueAt(indexY);
        double yTop = it->getValueAt(indexY) + it->getValueAt(indexError);
        double yBottom = it->getValueAt(indexY) - it->getValueAt(indexError);
        x = logarithmicAxisFlags_[X_AXIS] ? convertToLogCoordinates(x, X_AXIS) : x;
        y = logarithmicAxisFlags_[Y_AXIS] ? convertToLogCoordinates(y, Y_AXIS) : y;
        yTop = logarithmicAxisFlags_[Y_AXIS] ? convertToLogCoordinates(yTop, Y_AXIS) : yTop;
        yBottom = logarithmicAxisFlags_[Y_AXIS] ? convertToLogCoordinates(yBottom, Y_AXIS) : yBottom;
        p11 = projection_neu(x,yBottom,0);
        p12 = projection_neu(x,yTop,0);
        latexLine(p11,p12,latexColor_,1,lineWidth_);
        p21 = projection_neu(x-radius,yTop,0);
        p22 = projection_neu(x+radius,yTop,0);
        latexLine(p21,p22,latexColor_,0,lineWidth_);
        p31 = projection_neu(x-radius,yBottom,0);
        p32 = projection_neu(x+radius,yBottom,0);
        latexLine(p31,p32,latexColor_,0,lineWidth_);
        //tgt::Ellipse midpoint(tgt::dvec3(x, y, domain_[2].getLeft()), radius/2,
        //                      (radius*aspectRatio)/2, tgt::dvec3(0, 0, 1), tgt::dvec3(1, 0, 0 ), 32);
        //midpoint.render();
        latexEllipse(projection_neu(x,y,0),(p22.afterProjection_.x-p21.afterProjection_.x)*radius,(p22.afterProjection_.x-p21.afterProjection_.x)*radius,latexColor_,latexColor_,0,3,PlotEntitySettings::FILLNONE);
    }
}

void PlotLibraryLatex::renderCandlesticks(const PlotData& data, int indexX, int stickTop,
                                     int stickBottom, int candleTop, int candleBottom) {
    if (usePlotPickingManager_)
        return;
    std::vector<PlotRowValue>::const_iterator it;

    // check if only values or only tags in given cells
    bool tagsInX = (data.getColumnType(indexX) == PlotBase::STRING);
    std::vector< PlotLibraryFileBase::Projection_Coordinates > points;

    float width = static_cast<float>(domain_[X_AXIS].size()/(4.f*data.getRowsCount()));

    // draw the candlestick
    int i=0;
    double yStickTop     = 0.0;
    double yStickBottom  = 0.0;
    double yCandleTop    = 0.0;
    double yCandleBottom = 0.0;

    for (it = data.getRowsBegin(); it != data.getRowsEnd(); ++it, ++i) {
        if (it->getCellAt(indexX).isNull() || it->getCellAt(stickTop).isNull() || it->getCellAt(stickBottom).isNull()
            || it->getCellAt(candleTop).isNull() || it->getCellAt(candleBottom).isNull()) {
            continue;
        }
        double x = tagsInX ? i : it->getValueAt(indexX);
        yStickTop     = it->getValueAt(stickTop);
        yStickBottom  = it->getValueAt(stickBottom);
        yCandleTop    = it->getValueAt(candleTop);
        yCandleBottom = it->getValueAt(candleBottom);

        // we divide the stick and the candle in top and bottom half
        // draw stick
        if (it->getCellAt(stickTop).isHighlighted())
            latexColor_ = highlightColor_;
        else
            latexColor_ = drawingColor_;
        latexLine(convertPlotCoordinatesToViewport3Projection(x,yStickTop,0),convertPlotCoordinatesToViewport3Projection(x,(yStickTop+yStickBottom)/2.0,0),latexColor_,1,lineWidth_);
        if (it->getCellAt(stickBottom).isHighlighted())
            latexColor_ = highlightColor_;
        else
            latexColor_ = drawingColor_;
        latexLine(convertPlotCoordinatesToViewport3Projection(x,(yStickTop+yStickBottom)/2.0,0),convertPlotCoordinatesToViewport3Projection(x,yStickBottom,0),latexColor_,1,lineWidth_);
        //draw candle
        if (it->getCellAt(candleTop).isHighlighted())
            latexColor_ = highlightColor_;
        else
            latexColor_ = fillColor_;
        points.clear();
        points.push_back(convertPlotCoordinatesToViewport3Projection(x-width,yCandleTop,0));
        points.push_back(convertPlotCoordinatesToViewport3Projection(x-width,(yCandleBottom+yCandleTop)/2.0,0));
        points.push_back(convertPlotCoordinatesToViewport3Projection(x+width,(yCandleBottom+yCandleTop)/2.0,0));
        points.push_back(convertPlotCoordinatesToViewport3Projection(x+width,yCandleTop,0));
        latexPolygon(points,latexColor_,latexColor_,1,lineWidth_);
        if (it->getCellAt(candleBottom).isHighlighted())
            latexColor_ = highlightColor_;
        else
            latexColor_ = fillColor_;
        points.clear();
        points.push_back(convertPlotCoordinatesToViewport3Projection(x-width,(yCandleBottom+yCandleTop)/2.0,0));
        points.push_back(convertPlotCoordinatesToViewport3Projection(x-width,yCandleBottom,0));
        points.push_back(convertPlotCoordinatesToViewport3Projection(x+width,yCandleBottom,0));
        points.push_back(convertPlotCoordinatesToViewport3Projection(x+width,(yCandleBottom+yCandleTop)/2.0,0));
        latexPolygon(points,latexColor_,latexColor_,1,lineWidth_);
    }
}

void PlotLibraryLatex::renderSurface(const PlotData& data, const std::vector<int>& triangleVertexIndices, bool wire,
                                int indexX, int indexY, int indexZ, int indexCM, bool wireonly)  {
    if (usePlotPickingManager_ || !wire)
        return;
    // security check: if count of edge indices is not a multiple of 3 abort
    if (triangleVertexIndices.size() % 3 != 0)
        return;

    Interval<plot_t> colInterval(0, 0);

    if ( indexCM != -1 ) {
        colInterval = data.getInterval(indexCM);
        if (colInterval.size() == 0)
            indexCM = -1;
    }
    if ( indexCM == -1)
        latexColor_ = drawingColor_;

    // draw the triangles
    std::set<int> renderedHighlights; // we want to render each plot label // highlight only once
    PlotLibraryFileBase::Projection_Coordinates p1;
    PlotLibraryFileBase::Projection_Coordinates p2;
    PlotLibraryFileBase::Projection_Coordinates p3;
    PlotLibraryFileBase::Projection_Coordinates p4;
    std::vector< PlotLibraryFileBase::Projection_Coordinates > points;
    for (std::vector<int>::const_iterator it = triangleVertexIndices.begin(); it < triangleVertexIndices.end(); it += 3) {
        points.clear();
        latexColor_ = drawingColor_;
        for (int i=0; i<3; ++i) {
            const PlotRowValue& row = data.getRow(*(it+i));

            if (indexCM != -1 ) {
                float c = static_cast<float>((row.getValueAt(indexCM) - colInterval.getLeft()) / colInterval.size());
                latexColor_ = colorMap_.getColorAtPosition(c);
            }
            p1 = convertPlotCoordinatesToViewport3Projection(row.getValueAt(indexX), row.getValueAt(indexY), row.getValueAt(indexZ));
            if (!wire && row.getCellAt(indexZ).isHighlighted()) {
                points.push_back(p1);
            }
            else
                points.push_back(p1);
        }
        if (wireonly)
            latexPolygon(points,latexColor_,lineColor_,0,lineWidth_,PlotEntitySettings::FILLNONE);
        else
            latexPolygon(points,latexColor_,lineColor_,0,lineWidth_);
    }
}

void PlotLibraryLatex::renderHeightmap(const voreen::PlotData& data, const std::vector< std::list< tgt::dvec2 > >& voronoiRegions,
                                  bool wire, int indexZ, int indexCM, bool wireonly) {
    if (usePlotPickingManager_ || !wire)
        return;
    Interval<plot_t> colInterval(0, 0);
    plot_t yMin = data.getInterval(2).getLeft();
    PlotLibraryFileBase::Projection_Coordinates point1;
    PlotLibraryFileBase::Projection_Coordinates point2;
    PlotLibraryFileBase::Projection_Coordinates point3;
    PlotLibraryFileBase::Projection_Coordinates point4;
    std::vector< PlotLibraryFileBase::Projection_Coordinates > points;

    if ( indexCM != -1 ) {
        colInterval = data.getInterval(indexCM);
        if (colInterval.size() == 0)
            indexCM = -1;
    }

    int row = 0;
    std::vector< std::list< tgt::dvec2 > >::const_iterator rit = voronoiRegions.begin();
    std::vector<PlotRowValue>::const_iterator pit = data.getRowsBegin();
    for (; rit < voronoiRegions.end(); ++rit, ++pit, ++row){
        if (rit->empty())
            continue;

        if (!wire && pit->getCellAt(indexZ).isHighlighted())
            latexColor_ = highlightColor_;
        else if (indexCM != -1 ) {
            float c = static_cast<float>((pit->getValueAt(indexCM) - colInterval.getLeft()) / colInterval.size());
            latexColor_ = colorMap_.getColorAtPosition(c);
        }
        else {
            latexColor_ = drawingColor_;
        }

        plot_t height = pit->getValueAt(indexZ);
        //clip it:
        if (height > domain_[Z_AXIS].getRight())
            height = domain_[Z_AXIS].getRight();
        if (yMin < domain_[Z_AXIS].getLeft())
            yMin = domain_[Z_AXIS].getLeft();
        if (height > yMin) {
            // render the sides of the pillar
            int i = 0;
            for (std::list< tgt::dvec2 >::const_iterator eit = rit->begin(); eit != rit->end(); ++eit) {
                if (i == 0) {
                    point3 = convertPlotCoordinatesToViewport3Projection(eit->x, eit->y, height);
                    point4 = convertPlotCoordinatesToViewport3Projection(eit->x, eit->y, yMin);
                }
                else {
                    point2 = point3;
                    point1 = point4;
                    point3 = convertPlotCoordinatesToViewport3Projection(eit->x, eit->y, height);
                    point4 = convertPlotCoordinatesToViewport3Projection(eit->x, eit->y, yMin);
                    points.clear();
                    points.push_back(point1);
                    points.push_back(point2);
                    points.push_back(point3);
                    points.push_back(point4);
                    if (wireonly)
                        latexPolygon(points,latexColor_,lineColor_,0,lineWidth_,PlotEntitySettings::FILLNONE);
                    else
                        latexPolygon(points,latexColor_,lineColor_,0,lineWidth_);
                }
                ++i;
            }
            point1 = point4;
            point4 = convertPlotCoordinatesToViewport3Projection(rit->begin()->x, rit->begin()->y, yMin);
            point2 = point3;
            point3 = convertPlotCoordinatesToViewport3Projection(rit->begin()->x, rit->begin()->y, height);
            points.clear();
            points.push_back(point1);
            points.push_back(point2);
            points.push_back(point3);
            points.push_back(point4);
            if (wireonly)
                latexPolygon(points,latexColor_,lineColor_,0,lineWidth_,PlotEntitySettings::FILLNONE);
            else
                latexPolygon(points,latexColor_,lineColor_,0,lineWidth_);
            points.clear();
            for (std::list< tgt::dvec2 >::const_iterator eit = rit->begin(); eit != rit->end(); ++eit) {
                point1 = convertPlotCoordinatesToViewport3Projection(eit->x, eit->y, height);
                points.push_back(point1);
            }
            if (wireonly)
                latexPolygon(points,latexColor_,lineColor_,0,lineWidth_,PlotEntitySettings::FILLNONE);
            else
                latexPolygon(points,latexColor_,lineColor_,0,lineWidth_);
            points.clear();
            for (std::list< tgt::dvec2 >::const_iterator eit = rit->begin(); eit != rit->end(); ++eit) {
                point1 = convertPlotCoordinatesToViewport3Projection(eit->x, eit->y, yMin);
                points.push_back(point1);
            }
            if (wireonly)
                latexPolygon(points,latexColor_,lineColor_,0,lineWidth_,PlotEntitySettings::FILLNONE);
            else
                latexPolygon(points,latexColor_,lineColor_,0,lineWidth_);
        }
    }
}

void PlotLibraryLatex::renderBars(const PlotData& data, std::vector<int> indicesY) {
    if (usePlotPickingManager_)
        return;
    std::vector<PlotRowValue>::const_iterator rowIt = data.getRowsBegin();
    //stores y values and indices of a merged bar group, the indices are used to get the right color
    std::vector<std::pair<plot_t, tgt::Color> > mergedBars;
    //stores last y value, used for stacked bars
    plot_t lastY;
    //rowcounter
    plot_t row = 0;
    for (; rowIt < data.getRowsEnd(); ++rowIt) {
        lastY = 0;
        mergedBars.clear();
        // we do not use the iterator because we also iterate through the colormap
        for (size_t i = 0; i < indicesY.size(); ++i) {
            if (rowIt->getCellAt(indicesY.at(i)).isHighlighted())
                latexColor_ = highlightColor_;
            else
                latexColor_ = colorMap_.getColorAtIndex(static_cast<int>(i));
            if (barMode_ == STACKED) {
                if (rowIt->getCellAt(indicesY.at(i)).isNull() )
                    continue;
                plot_t newY = lastY+rowIt->getValueAt(indicesY.at(i));
                //negative stacked bars do not make any sense and are ignored
                if (newY < lastY)
                    continue;
                renderSingleBar(row-barWidth_/2.0,row+barWidth_/2.0, lastY, newY, latexColor_);
                lastY = newY;
            }
            else if (barMode_ == GROUPED) {
                if (rowIt->getCellAt(indicesY.at(i)).isNull())
                    continue;
                double singleBarWidth = barWidth_/(1.0*static_cast<double>(indicesY.size()));
                renderSingleBar(row-barWidth_/2.0+static_cast<double>(i)*singleBarWidth,
                    row-barWidth_/2.0+static_cast<double>(i+1)*singleBarWidth, 0, rowIt->getValueAt(indicesY.at(i)), latexColor_);
            }

            else { // MERGED
                // we can't skip null entries, so we set them 0
                if (rowIt->getCellAt(indicesY.at(i)).isNull())
                    mergedBars.push_back(std::pair<plot_t, tgt::Color>(0, latexColor_));
                // push the y value and the color index
                mergedBars.push_back(std::pair<plot_t, tgt::Color>(rowIt->getValueAt(indicesY.at(i)), latexColor_));
            }
        }
        if (barMode_ == MERGED) {
            // the values are stored in bars, but not yet drawn
            std::sort(mergedBars.begin(), mergedBars.end(), mergedBarSorter);
            std::vector<std::pair<plot_t, tgt::Color> >::const_iterator it;
            std::vector<std::pair<plot_t, tgt::Color> >::const_iterator lastit;
            double squeeze = 1.0;
            for (it = mergedBars.begin(); it < mergedBars.end(); ++it) {
                //glColor4fv(it->second.elem);
                latexColor_ = it->second;
                if (it == mergedBars.begin()) {
                    renderSingleBar(row-barWidth_/2.0,row+barWidth_/2.0, 0, it->first, it->second, squeeze);
                }
                else
                    renderSingleBar(row-barWidth_/2.0,row+barWidth_/2.0, lastit->first, it->first, it->second, squeeze);
                squeeze = squeezeFactor_*squeeze;
                lastit = it;
            }
        }
        ++row;
    }
}

void PlotLibraryLatex::renderNodeGraph(const PlotData& nodeData, const PlotData& connectionData, int indexX, int indexY, int indexDx, int indexDy) {
    if (usePlotPickingManager_)
        return;
    std::vector<PlotRowValue>::const_iterator it;

    // render nodes
    plot_t glyphSize = (maxGlyphSize_ + minGlyphSize_)/2;
    int i = 0;
    for (it = nodeData.getRowsBegin(); it != nodeData.getRowsEnd(); ++it, ++i) {
        // render node
        latexColor_ = drawingColor_;
        renderGlyph(it->getValueAt(indexX), it->getValueAt(indexY), 0, glyphSize);

        // render force vector
        latexLine(convertPlotCoordinatesToViewport3Projection(it->getValueAt(indexX),it->getValueAt(indexY),0),
            convertPlotCoordinatesToViewport3Projection(it->getValueAt(indexX) + it->getValueAt(indexDx),
            it->getValueAt(indexY) + it->getValueAt(indexDy),0),
            fillColor_,1,lineWidth_);

        // render node label
        std::stringstream ss;
        ss << i;
        renderLabel(tgt::dvec3(it->getValueAt(indexX), it->getValueAt(indexY), 0), SmartLabel::CENTERED, ss.str(), false, 0);
    }

    std::vector<PlotCellValue> tester;
    tester.push_back(PlotCellValue(0));
    std::vector<PlotRowValue>::const_iterator firstIt, secondIt;

    // render connections
    for (it = connectionData.getRowsBegin(); it != connectionData.getRowsEnd(); ++it) {
        tester[0].setValue(static_cast<int>(it->getValueAt(0)));
        firstIt = nodeData.lower_bound(tester);

        tester[0].setValue(static_cast<int>(it->getValueAt(1)));
        secondIt = nodeData.lower_bound(tester);

        if (firstIt != nodeData.getRowsEnd() && secondIt != nodeData.getRowsEnd()) {
            latexLine(convertPlotCoordinatesToViewport3Projection(firstIt->getValueAt(indexX),firstIt->getValueAt(indexY),0),
                convertPlotCoordinatesToViewport3Projection(secondIt->getValueAt(indexX),secondIt->getValueAt(indexY),0),
                drawingColor_,1,lineWidth_);
        }
    }
}

void PlotLibraryLatex::renderColorMapLegend(const PlotData& data, int column, int number) {
    tgt::Color c1, c2;
    std::stringstream ss;
    // ColorMaps with less than 2 colors may not exist
    if (colorMap_.getColorCount() < 2)
        return;

    Interval<plot_t>   interval = data.getInterval(column);
    const std::string& label    = data.getColumnLabel(column);

    // render legend
    int colorcount      = colorMap_.getColorCount();
    const double width  = 96;
    const double height = 16;
    const double xslide = 8;
    const double xStart = windowSize_.x - width - xslide;
    const double yStart = windowSize_.y - xslide - (number*32) - height;
    double stepWidth    = width / (colorcount - 1);

    // color map
    for (int i = 0; i < colorcount-1; ++i) {
        c1 = colorMap_.getColorAtIndex(i);
        c2 = colorMap_.getColorAtIndex(i+1);
        tgt::Vector3<plot_t> point = tgt::Vector3<plot_t>(xStart + (i*stepWidth),yStart,0);
        latexRect(PlotLibraryFileBase::Projection_Coordinates(point,point,point),stepWidth,height,c1,c2);
    }

    latexColor_ = drawingColor_;
    std::vector< PlotLibraryFileBase::Projection_Coordinates > points;
    tgt::Vector3<plot_t> coor;
    coor = tgt::Vector3<plot_t>(xStart,yStart,0);
    points.push_back(PlotLibraryFileBase::Projection_Coordinates(coor,coor,coor));
    coor = tgt::Vector3<plot_t>(xStart,yStart + height,0);
    points.push_back(PlotLibraryFileBase::Projection_Coordinates(coor,coor,coor));
    coor = tgt::Vector3<plot_t>(xStart + width,yStart + height,0);
    points.push_back(PlotLibraryFileBase::Projection_Coordinates(coor,coor,coor));
    coor = tgt::Vector3<plot_t>(xStart + width,yStart,0);
    points.push_back(PlotLibraryFileBase::Projection_Coordinates(coor,coor,coor));
    coor = tgt::Vector3<plot_t>(xStart,yStart,0);
    points.push_back(PlotLibraryFileBase::Projection_Coordinates(coor,coor,coor));
    latexPolygon(points,latexColor_,latexColor_,0,lineWidth_,PlotEntitySettings::FILLNONE);

    // labels
    tgt::dvec3 position = tgt::dvec3(xStart, yStart + (height/2),0);
    SmartLabelGroupBaseLatex::renderSingleLabel(&labelFont_, label,fontSize_,SmartLabel::MIDDLERIGHT, 4,position);
    latexText(position,label,&labelFont_,fontSize_,fontColor_,SmartLabel::MIDDLERIGHT);

    ss.str("");
    ss.clear();
    ss << std::setprecision(4) << interval.getLeft();
    position = tgt::dvec3(xStart, yStart, 0);
    SmartLabelGroupBaseLatex::renderSingleLabel(&labelFont_, ss.str(),fontSize_, SmartLabel::BOTTOMCENTERED, 4,position);
    latexText(position,ss.str(),&labelFont_,fontSize_,fontColor_,SmartLabel::BOTTOMCENTERED);

    ss.str("");
    ss.clear();
    ss << std::setprecision(4) << interval.getRight();
    position = tgt::dvec3(xStart + width, yStart, 0);
    SmartLabelGroupBaseLatex::renderSingleLabel(&labelFont_, ss.str(),fontSize_, SmartLabel::BOTTOMRIGHT,4,position);
    latexText(position,ss.str(),&labelFont_,fontSize_,fontColor_,SmartLabel::BOTTOMRIGHT);

}

void PlotLibraryLatex::renderScatter(const PlotData& data, int indexX, int indexY, int indexZ, int indexCM, int indexSize) {
    if (usePlotPickingManager_)
        return;
    Interval<plot_t> colInterval(0, 0);
    if ( indexCM != -1 ) {
        colInterval = data.getInterval(indexCM);
        if (colInterval.size() == 0)
            indexCM = -1;
    }
    plot_t x, y, z;
    plot_t size = maxGlyphSize_;
    // if there is size data, we interpolate it to [minGlyphSize_,maxGlyphSize_]
    Interval<plot_t> sizeInterval(0, 0);
    if ( indexSize != -1 ) {
        sizeInterval = data.getInterval(indexSize);
        //we can only use an interval with positive size
        if (sizeInterval.size() == 0)
            indexSize = -1;
    }
    tgt::Color textureColor = tgt::Color(0,0,0,0);
    if (texture_ != 0) {
        GLfloat* textureBuffer = (GLfloat*)(texture_->downloadTextureToBuffer(GL_RGBA,GL_FLOAT));
        std::vector< int > colorvector;
        tgt::Color colorvalue;
        colorvector.resize(255*255*255);
        int r,g,b;
        for (size_t i = 0; i < texture_->getArraySize(); ++i) {
            colorvalue = tgt::Color(textureBuffer[4*i],textureBuffer[4*i+1],textureBuffer[4*i+2],textureBuffer[4*i+3]);
            r = static_cast<int>(tgt::round(colorvalue.r*255));
            g = static_cast<int>(tgt::round(colorvalue.r*255));
            b = static_cast<int>(tgt::round(colorvalue.r*255));
            colorvector[r*255*255+g*255+b] += 1;
        }
        size_t max = 0;
        for (size_t i = 0; i < colorvector.size(); ++i) {
            if (colorvector[i] > colorvector[max])
                max = i;
        }
        textureColor = tgt::Color(static_cast<float>(max%255)/255.f,static_cast<float>((max/255)%255)/255.f,
            static_cast<float>((max/(255*255))%255)/255.f,1);
    }


    //row iterator
    int i = 0;
    std::vector<PlotRowValue>::const_iterator it = data.getRowsBegin();

    for (; it != data.getRowsEnd(); ++it, ++i) {
        //we ignore rows with null entries
        if (it->getCellAt(indexX).isNull() || it->getCellAt(indexY).isNull()) {
            continue;
        }
        x = it->getValueAt(indexX); y = it->getValueAt(indexY); z = (indexZ == -1 ? 0 : it->getValueAt(indexZ));
        //check if the point is inside the domains
        if (domain_[X_AXIS].contains(x) && domain_[Y_AXIS].contains(y) && (dimension_ == TWO || domain_[Z_AXIS].contains(z))) {
            // set color
            if (texture_ != 0)
                latexColor_ = textureColor;
            else if ((indexZ != -1 && it->getCellAt(indexZ).isHighlighted())
                    || (indexZ == -1 && it->getCellAt(indexY).isHighlighted()))
                latexColor_ = highlightColor_;
            else if (indexCM != -1 ) {
                float c = static_cast<float>((it->getValueAt(indexCM) - colInterval.getLeft()) / colInterval.size());
                latexColor_ = colorMap_.getColorAtPosition(c);
            }
            else
                latexColor_ = drawingColor_;
            // set size
            if (indexSize != -1 ) {
                size = minGlyphSize_ + (maxGlyphSize_ - minGlyphSize_) *
                            (it->getValueAt(indexSize) - sizeInterval.getLeft()) / sizeInterval.size();
            }
            renderGlyph(x, y, z, size);
        }
    }
}

void PlotLibraryLatex::renderAxes() {
    // axes

     latexColor_ = drawingColor_;

    plot_t xl = domain_[0].getLeft();    plot_t xr = domain_[0].getRight();
    plot_t yl = domain_[1].getLeft();    plot_t yr = domain_[1].getRight();
    plot_t zl = domain_[2].getLeft();    plot_t zr = domain_[2].getRight();

    PlotLibraryFileBase::Projection_Coordinates p1;
    PlotLibraryFileBase::Projection_Coordinates p2;
    PlotLibraryFileBase::Projection_Coordinates p3;
    PlotLibraryFileBase::Projection_Coordinates p4;
    PlotLibraryFileBase::Projection_Coordinates p5;
    PlotLibraryFileBase::Projection_Coordinates p6;
    std::vector< PlotLibraryFileBase::Projection_Coordinates > points;

    if (! centerAxesFlag_) {
        p1 = projection_neu(xl, yr, zl);
        p2 = projection_neu(xl, yl, zl);
        p3 = projection_neu(xr, yl, zl);
        latexLine(p1,p2,latexColor_,0,axesWidth_);
        latexLine(p2,p3,latexColor_,0,axesWidth_);
    }

    if (dimension_ == TWO) {
    //draw arrows with viewport coordinates
        int arrowSize = 5; // in pixel

        tgt::Vector3<plot_t> p11 = tgt::Vector3<plot_t>(windowSize_.x-marginRight_,marginBottom_,0);
        tgt::Vector3<plot_t> p12 = tgt::Vector3<plot_t>(windowSize_.x-marginRight_+4*arrowSize,marginBottom_,0);
        p1 = PlotLibraryFileBase::Projection_Coordinates(p11,p11,p11);
        p2 = PlotLibraryFileBase::Projection_Coordinates(p12,p12,p12);
        latexLine(p1,p2,latexColor_,0,axesWidth_);

        p11 = tgt::Vector3<plot_t>(windowSize_.x-marginRight_+2*arrowSize,marginBottom_+arrowSize,0);
        p12 = tgt::Vector3<plot_t>(windowSize_.x-marginRight_+4*arrowSize,marginBottom_,0);
        p1 = PlotLibraryFileBase::Projection_Coordinates(p11,p11,p11);
        p2 = PlotLibraryFileBase::Projection_Coordinates(p12,p12,p12);
        latexLine(p1,p2,latexColor_,0,axesWidth_);

        p11 = tgt::Vector3<plot_t>(windowSize_.x-marginRight_+2*arrowSize,marginBottom_-arrowSize,0);
        p12 = tgt::Vector3<plot_t>(windowSize_.x-marginRight_+4*arrowSize,marginBottom_,0);
        p1 = PlotLibraryFileBase::Projection_Coordinates(p11,p11,p11);
        p2 = PlotLibraryFileBase::Projection_Coordinates(p12,p12,p12);
        latexLine(p1,p2,latexColor_,0,axesWidth_);

        p11 = tgt::Vector3<plot_t>(marginLeft_,windowSize_.y-marginTop_,0);
        p12 = tgt::Vector3<plot_t>(marginLeft_,windowSize_.y-marginTop_+4*arrowSize,0);
        p1 = PlotLibraryFileBase::Projection_Coordinates(p11,p11,p11);
        p2 = PlotLibraryFileBase::Projection_Coordinates(p12,p12,p12);
        latexLine(p1,p2,latexColor_,0,axesWidth_);

        p11 = tgt::Vector3<plot_t>(marginLeft_ + arrowSize,windowSize_.y-marginTop_+2*arrowSize,0);
        p12 = tgt::Vector3<plot_t>(marginLeft_,windowSize_.y-marginTop_+4*arrowSize,0);
        p1 = PlotLibraryFileBase::Projection_Coordinates(p11,p11,p11);
        p2 = PlotLibraryFileBase::Projection_Coordinates(p12,p12,p12);
        latexLine(p1,p2,latexColor_,0,axesWidth_);

        p11 = tgt::Vector3<plot_t>(marginLeft_ - arrowSize,windowSize_.y-marginTop_+2*arrowSize,0);
        p12 = tgt::Vector3<plot_t>(marginLeft_,windowSize_.y-marginTop_+4*arrowSize,0);
        p1 = PlotLibraryFileBase::Projection_Coordinates(p11,p11,p11);
        p2 = PlotLibraryFileBase::Projection_Coordinates(p12,p12,p12);
        latexLine(p1,p2,latexColor_,0,axesWidth_);

    }
    else if (dimension_ == THREE) {
    //draw cube mesh
        p1 = projection_neu(xr, yl, zl);
        p2 = projection_neu(xr, yr, zl);
        p3 = projection_neu(xl, yr, zl);
        p4 = projection_neu(xl, yr, zr);
        p5 = projection_neu(xr, yr, zr);
        p6 = projection_neu(xr, yr, zl);
        latexLine(p1,p2,latexColor_,0,axesWidth_);
        latexLine(p2,p3,latexColor_,0,axesWidth_);
        latexLine(p3,p4,latexColor_,0,axesWidth_);
        latexLine(p4,p5,latexColor_,0,axesWidth_);
        latexLine(p5,p6,latexColor_,0,axesWidth_);
        latexLine(p6,p1,latexColor_,0,axesWidth_);

        p1 = projection_neu(xr, yl, zl);
        p2 = projection_neu(xr, yl, zr);
        p3 = projection_neu(xl, yl, zr);
        p4 = projection_neu(xl, yl, zl);
        latexLine(p1,p2,latexColor_,0,axesWidth_);
        latexLine(p2,p3,latexColor_,0,axesWidth_);
        latexLine(p3,p4,latexColor_,0,axesWidth_);
        latexLine(p4,p1,latexColor_,0,axesWidth_);

        p1 = projection_neu(xr, yl, zr);
        p2 = projection_neu(xr, yr, zr);
        latexLine(p1,p2,latexColor_,0,axesWidth_);

        p1 = projection_neu(xl, yl, zr);
        p2 = projection_neu(xl, yr, zr);
        latexLine(p1,p2,latexColor_,0,axesWidth_);
    }
    else if (dimension_ == FAKETHREE) {
        //draw back
        p1 = projection_neu(xl, yr, zl);
        p2 = projection_neu(xl, yl, zl);
        p3 = projection_neu(xr, yl, zl);
        p4 = projection_neu(xr, yr, zl);
        points.clear();
        points.push_back(p1);
        points.push_back(p2);
        points.push_back(p3);
        points.push_back(p4);
        latexPolygon(points,latexColor_,latexColor_,0,axesWidth_,PlotEntitySettings::FILLNONE);

        //draw bottom
        p1 = projection_neu(xl, yl, zl);
        p2 = projection_neu(xl, yl, zr);
        latexLine(p1,p2,latexColor_,0,axesWidth_);

        p1 = projection_neu(xr, yl, zr);
        p2 = projection_neu(xr, yl, zl);
        latexLine(p1,p2,latexColor_,0,axesWidth_);

        //draw left
        p1 = projection_neu(xl, yr, zr);
        p2 = projection_neu(xl, yl, zr);
        p3 = projection_neu(xl, yl, zl);
        p4 = projection_neu(xl, yr, zl);
        points.clear();
        points.push_back(p1);
        points.push_back(p2);
        points.push_back(p3);
        points.push_back(p4);
        latexPolygon(points,latexColor_,latexColor_,0,axesWidth_,PlotEntitySettings::FILLNONE);

        //draw zero
        p1 = projection_neu(xl, 0, zl);
        p2 = projection_neu(xl, 0, zr);
        latexLine(p1,p2,latexColor_,0,axesWidth_);

        p1 = projection_neu(xr, 0, zr);
        p2 = projection_neu(xr, 0, zl);
        latexLine(p1,p2,latexColor_,0,axesWidth_);

        //the front is always above the plot
        p1 = projection_neu(xl, 0, zr);
        p2 = projection_neu(xr, 0, zr);
        latexLine(p1,p2,latexColor_,0,axesWidth_);

        p1 = projection_neu(xl, yl, zr);
        p2 = projection_neu(xr, yl, zr);
        latexLine(p1,p2,latexColor_,0,axesWidth_);
    }
}

void PlotLibraryLatex::renderAxisScales(Axis axis, bool helperLines, const std::string& label, plot_t offset) {
    tgt::dvec2 step = updateScaleSteps(axis);
    latexColor_ = drawingColor_;
    plot_t xl = domain_[0].getLeft();    plot_t xr = domain_[0].getRight();
    plot_t yl = domain_[1].getLeft();    plot_t yr = domain_[1].getRight();
    plot_t zl = domain_[2].getLeft();    plot_t zr = domain_[2].getRight();

    std::stringstream stream;
    if (step.x < 1) {
        int precision = static_cast<int>(ceil(log10(1.0/step.x)));
        stream << std::fixed << std::setprecision(precision);
    }

    if (dimension_ == TWO || dimension_ == FAKETHREE) {
        xAxisLabelGroup_.reset();
        xAxisLabelGroup_.setBounds(getBoundsBelowPlot());
        // if respective scaleStep is e.g. 50 and interval begin e.g. 27.43, we want to have labels like
        // 50, 100, 150, ... instead of 27.43, 77.43, 127.43, ...
        // So we do some smart rounding:
        plot_t start = domain_[axis].getLeft();
        start = ceil(start / step.x) * step.x;

        for (plot_t i = start; i <= domain_[axis].getRight(); i += step.x) {
            plot_t pos = i;//(logarithmicAxisFlags_[axis] ? convertFromLogCoordinates(i, axis) : i);
            stream.str("");
            stream.clear();
            stream << round(pos + offset, step.y);
            if (axis == X_AXIS) {
                xAxisLabelGroup_.addLabel(stream.str(),
                                          convertPlotCoordinatesToViewport3(tgt::dvec3(i, yl, zr)),
                                          fontColor_, fontSize_, SmartLabel::TOPCENTERED);
                if (helperLines && dimension_ == TWO) {
                    PlotLibraryFileBase::Projection_Coordinates p1 = convertPlotCoordinatesToViewport3Projection(i, yl,0);
                    PlotLibraryFileBase::Projection_Coordinates p2 = convertPlotCoordinatesToViewport3Projection(i, yr,0);
                    latexLine(p1,p2,latexColor_,0,axesWidth_/2.f);
                }
            }
            else if (axis == Y_AXIS) {
                renderLabel(tgt::dvec3(xl, i, zr), SmartLabel::MIDDLERIGHT, stream.str());
                if (helperLines) {
                    PlotLibraryFileBase::Projection_Coordinates p2 = convertPlotCoordinatesToViewport3Projection(xl, i, zl);
                    PlotLibraryFileBase::Projection_Coordinates p3 = convertPlotCoordinatesToViewport3Projection(xr, i, zl);
                    if (dimension_ == FAKETHREE) {
                        PlotLibraryFileBase::Projection_Coordinates p1 = convertPlotCoordinatesToViewport3Projection(xl, i, zr);
                        latexLine(p1,p2,latexColor_,0,axesWidth_/2.f);
                    }
                    latexLine(p2,p3,latexColor_,0,axesWidth_/2.f);
                }
            }
        }
        renderSmartLabelGroup(&xAxisLabelGroup_);
    }
    else if (dimension_ == THREE) {
        // If we are inside the plot cube (or really close to it) we do not want to
        // render scales because it looks ugly it doesn't make any sense.
        if (!orthographicCameraFlag_ && tgt::distance(camera_.getPosition(), tgt::vec3(0,0,0)) < 1)
            return;

        axisLabelGroup_.reset();

        // avoid expensive copying by using iterators
        std::vector<SelectionEdge>::const_iterator minEdge = selectionEdgesX_.begin();
        std::vector<SelectionEdge>::const_iterator endEdge = selectionEdgesX_.end();
        if (axis == X_AXIS) {
            if (selectionEdgesX_.empty())
                return;
        }
        else if (axis == Y_AXIS) {
            if (selectionEdgesY_.empty())
                return;
            minEdge = selectionEdgesY_.begin();
            endEdge = selectionEdgesY_.end();
        }
        else if (axis == Z_AXIS) {
            if (selectionEdgesZ_.empty())
                return;
            minEdge = selectionEdgesZ_.begin();
            endEdge = selectionEdgesZ_.end();
        }

        // find edge with maximum length
        double length = tgt::length(minEdge->endVertex_ - minEdge->startVertex_);

        if (! orthographicCameraFlag_) {
            for (std::vector<SelectionEdge>::const_iterator it = ++minEdge; it < endEdge; ++it) {
                double val = tgt::length(it->endVertex_ - it->startVertex_);
                if (val > length) {
                    minEdge = it;
                    length = val;
                }
            }
        }

        // determine on which side the cube our axis is and with that the label alignment
        tgt::dvec2 edgeDirection = minEdge->endVertex_ - minEdge->startVertex_;
        tgt::dvec2 center(windowSize_.x/2, windowSize_.y/2);
        tgt::dvec2 ray((minEdge->startVertex_ + 0.5*edgeDirection) - center);
        ray = 1.0/tgt::length(ray) * ray;
        double angle = atan2(ray.y, ray.x);

        SmartLabel::Alignment align = SmartLabel::MIDDLELEFT;
        if (angle > tgt::PI/8 && angle <= 3.0*tgt::PI/8)
            align = SmartLabel::TOPLEFT;
        else if (angle > 3.0*tgt::PI/8 && angle <= 5.0*tgt::PI/8)
            align = SmartLabel::TOPCENTERED;
        else if (angle > 5.0*tgt::PI/8 && angle <= 7.0*tgt::PI/8)
            align = SmartLabel::TOPRIGHT;
        else if (angle < -7.0*tgt::PI/8 || angle > 7.0*tgt::PI/8)
            align = SmartLabel::MIDDLERIGHT;

        if (angle < -tgt::PI/8 && angle >= -3.0*tgt::PI/8)
            align = SmartLabel::BOTTOMLEFT;
        else if (angle < -3.0*tgt::PI/8 && angle >= -5.0*tgt::PI/8)
            align = SmartLabel::BOTTOMCENTERED;
        else if (angle < -5.0*tgt::PI/8 && angle >= -7.0*tgt::PI/8)
            align = SmartLabel::BOTTOMRIGHT;

        // render axis label first:
        if (label != "") {
            axisLabelGroup_.addLabel(label, minEdge->startVertex_ + (0.5 * edgeDirection) + (32.0 * ray), fontColor_, fontSize_, align);
        }

        // now render scales:
        // if respective scaleStep is e.g. 50 and interval begin e.g. 27.43, we want to have labels like
        // 50, 100, 150, ... instead of 27.43, 77.43, 127.43, ...
        // So we do some smart rounding:
        plot_t start = domain_[axis].getLeft();
        start = ceil(start / step.x) * step.x;
        plot_t domainSize = domain_[axis].size();

        for (plot_t i = start; i  <= domain_[axis].getRight(); i += step.x) {
            stream.str("");
            stream.clear();
            stream << round(i, step.y);
            if (minEdge->ascOrientation_)
                axisLabelGroup_.addLabel(stream.str(),
                        minEdge->startVertex_ + ((i - domain_[axis].getLeft())/domainSize)*edgeDirection,
                        fontColor_, fontSize_, align);
            else
                axisLabelGroup_.addLabel(stream.str(),
                        minEdge->endVertex_ - ((i - domain_[axis].getLeft())/domainSize)*edgeDirection,
                        fontColor_, fontSize_, align);

        }
        renderSmartLabelGroup(&axisLabelGroup_);

        // render helper lines
        if (helperLines) {
            PlotLibraryFileBase::Projection_Coordinates p1;
            PlotLibraryFileBase::Projection_Coordinates p2;
            PlotLibraryFileBase::Projection_Coordinates p3;
            PlotLibraryFileBase::Projection_Coordinates p4;
            std::vector< PlotLibraryFileBase::Projection_Coordinates > points;
            tgt::dvec2 xEdgeDirection;
            tgt::dvec2 yEdgeDirection;
            tgt::dvec2 zEdgeDirection;
            bool base, top, back, front, left, right;
            if (orthographicCameraFlag_) {
                xEdgeDirection = selectionEdgesX_.begin()->endVertex_ - selectionEdgesX_.begin()->startVertex_;
                yEdgeDirection = selectionEdgesY_.begin()->endVertex_ - selectionEdgesY_.begin()->startVertex_;
                //zEdgeDirection = selectionEdgesZ_.begin()->endVertex_ - selectionEdgesZ_.begin()->startVertex_;
                base = ((xEdgeDirection.x > 0.0  && xEdgeDirection.y > 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x > 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x < 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y > 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == false)));
                top = (!base);
                back = ((xEdgeDirection.x > 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x > 0.0  && xEdgeDirection.y > 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0  && xEdgeDirection.y > 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesY_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesY_.begin()->ascOrientation_ == true)));
                front = (!back);
                left = ((xEdgeDirection.x > 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x < 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x < 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x > 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesY_.begin()->ascOrientation_ == true)));
                right = (!left);
            }
            else {
                if (selectionEdgesX_.size() > 0)
                    xEdgeDirection = selectionEdgesX_.begin()->endVertex_ - selectionEdgesX_.begin()->startVertex_;
                if (selectionEdgesY_.size() > 0)
                    yEdgeDirection = selectionEdgesY_.begin()->endVertex_ - selectionEdgesY_.begin()->startVertex_;
                if (selectionEdgesZ_.size() > 0)
                    zEdgeDirection = selectionEdgesZ_.begin()->endVertex_ - selectionEdgesZ_.begin()->startVertex_;
                base = ((xEdgeDirection.x > 0.0  && xEdgeDirection.y > 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x > 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x < 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y > 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y < 0.0  && yEdgeDirection.x < 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x < 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y > 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y > 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x < 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (yEdgeDirection.x < 0.0 && yEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesY_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)) ||
                    (yEdgeDirection.x < 0.0 && yEdgeDirection.y > 0.0  && zEdgeDirection.x < 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesY_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (yEdgeDirection.x > 0.0 && yEdgeDirection.y > 0.0  && zEdgeDirection.x < 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesY_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)));
                top = ((xEdgeDirection.x > 0.0 && xEdgeDirection.y > 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false) && selectionEdgesY_.size() == 0) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x < 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x < 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y > 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x > 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)) ||
                    (yEdgeDirection.x < 0.0 && yEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesY_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)));
                back = ((xEdgeDirection.x > 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x > 0.0  && xEdgeDirection.y > 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0  && xEdgeDirection.y > 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesY_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y > 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x < 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x < 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y > 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (yEdgeDirection.x < 0.0 && yEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesY_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)));
                front = ((xEdgeDirection.x < 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)) ||
                    (yEdgeDirection.x < 0.0 && yEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesY_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)));
                left = ((xEdgeDirection.x > 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x < 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x < 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x > 0.0  && xEdgeDirection.y < 0.0  && yEdgeDirection.x > 0.0  && yEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesY_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y > 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x < 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x < 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y > 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)) ||
                    (yEdgeDirection.x < 0.0 && yEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesY_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)));
                right = ((xEdgeDirection.x > 0.0 && xEdgeDirection.y > 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x < 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false) && selectionEdgesY_.size() == 0) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x < 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y > 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == true) && (selectionEdgesZ_.begin()->ascOrientation_ == false)) ||
                    (xEdgeDirection.x < 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y < 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)) ||
                    (xEdgeDirection.x > 0.0 && xEdgeDirection.y < 0.0  && zEdgeDirection.x > 0.0  && zEdgeDirection.y > 0.0 && (selectionEdgesX_.begin()->ascOrientation_ == false) && (selectionEdgesZ_.begin()->ascOrientation_ == true)));
            }
            if (axis == X_AXIS) {
                for (plot_t i = start + step.x ; i <= domain_[axis].getRight(); i += step.x) {
                    if (base) {
                        p1 = projection_neu(i - step.x, yl, zl);
                        p2 = projection_neu(i, yl, zl);
                        p3 = projection_neu(i, yr, zl);
                        p4 = projection_neu(i - step.x, yr, zl);
                        latexLine(p1,p2,latexColor_,0,lineWidth_);
                        latexLine(p2,p3,latexColor_,0,lineWidth_);
                        latexLine(p3,p4,latexColor_,0,lineWidth_);
                        latexLine(p4,p1,latexColor_,0,lineWidth_);
                    }
                    if (top) {
                        p1 = projection_neu(i, yl, zr);
                        p2 = projection_neu(i - step.x, yl, zr);
                        p3 = projection_neu(i - step.x, yr, zr);
                        p4 = projection_neu(i, yr, zr);
                        latexLine(p1,p2,latexColor_,0,lineWidth_);
                        latexLine(p2,p3,latexColor_,0,lineWidth_);
                        latexLine(p3,p4,latexColor_,0,lineWidth_);
                        latexLine(p4,p1,latexColor_,0,lineWidth_);
                    }
                    if (front) {
                        p1 = projection_neu(i - step.x, yl, zl);
                        p2 = projection_neu(i - step.x, yl, zr);
                        p3 = projection_neu(i, yl, zr);
                        p4 = projection_neu(i, yl, zl);
                        latexLine(p1,p2,latexColor_,0,lineWidth_);
                        latexLine(p2,p3,latexColor_,0,lineWidth_);
                        latexLine(p3,p4,latexColor_,0,lineWidth_);
                        latexLine(p4,p1,latexColor_,0,lineWidth_);
                    }
                    if (back) {
                        p1 = projection_neu(i, yr, zl);
                        p2 = projection_neu(i, yr, zr);
                        p3 = projection_neu(i - step.x, yr, zr);
                        p4 = projection_neu(i - step.x, yr, zl);
                        latexLine(p1,p2,latexColor_,0,lineWidth_);
                        latexLine(p2,p3,latexColor_,0,lineWidth_);
                        latexLine(p3,p4,latexColor_,0,lineWidth_);
                        latexLine(p4,p1,latexColor_,0,lineWidth_);
                    }
                }
            }
            else if (axis == Y_AXIS) {
                for (plot_t i = start + step.x ; i <= domain_[axis].getRight(); i += step.x) {
                    if (base) {
                        p1 = projection_neu(xr, i - step.x, zl);
                        p2 = projection_neu(xr, i, zl);
                        p3 = projection_neu(xl, i, zl);
                        p4 = projection_neu(xl, i - step.x, zl);
                        latexLine(p1,p2,latexColor_,0,lineWidth_);
                        latexLine(p2,p3,latexColor_,0,lineWidth_);
                        latexLine(p3,p4,latexColor_,0,lineWidth_);
                        latexLine(p4,p1,latexColor_,0,lineWidth_);
                    }
                    if (top) {
                        p1 = projection_neu(xr, i, zr);
                        p2 = projection_neu(xr, i - step.x, zr);
                        p3 = projection_neu(xl, i - step.x, zr);
                        p4 = projection_neu(xl, i, zr);
                        latexLine(p1,p2,latexColor_,0,lineWidth_);
                        latexLine(p2,p3,latexColor_,0,lineWidth_);
                        latexLine(p3,p4,latexColor_,0,lineWidth_);
                        latexLine(p4,p1,latexColor_,0,lineWidth_);
                    }
                    if (left) {
                        p1 = projection_neu(xl, i - step.x, zr);
                        p2 = projection_neu(xl, i - step.x, zl);
                        p3 = projection_neu(xl, i, zl);
                        p4 = projection_neu(xl, i, zr);
                        latexLine(p1,p2,latexColor_,0,lineWidth_);
                        latexLine(p2,p3,latexColor_,0,lineWidth_);
                        latexLine(p3,p4,latexColor_,0,lineWidth_);
                        latexLine(p4,p1,latexColor_,0,lineWidth_);
                    }
                    if (right) {
                        p1 = projection_neu(xr, i, zr);
                        p2 = projection_neu(xr, i,  zl);
                        p3 = projection_neu(xr ,i - step.x, zl);
                        p4 = projection_neu(xr, i - step.x, zr);
                        latexLine(p1,p2,latexColor_,0,lineWidth_);
                        latexLine(p2,p3,latexColor_,0,lineWidth_);
                        latexLine(p3,p4,latexColor_,0,lineWidth_);
                        latexLine(p4,p1,latexColor_,0,lineWidth_);
                    }
                }
            }
            else if (axis == Z_AXIS) {
                for (plot_t i = start + step.x ; i <= domain_[axis].getRight(); i += step.x) {
                    if (back) {
                        p1 = projection_neu(xr, yr, i - step.x);
                        p2 = projection_neu(xr, yr, i);
                        p3 = projection_neu(xl, yr, i);
                        p4 = projection_neu(xl, yr, i - step.x);
                        latexLine(p1,p2,latexColor_,0,lineWidth_);
                        latexLine(p2,p3,latexColor_,0,lineWidth_);
                        latexLine(p3,p4,latexColor_,0,lineWidth_);
                        latexLine(p4,p1,latexColor_,0,lineWidth_);
                    }
                    if (front) {
                        p1 = projection_neu(xr, yl, i);
                        p2 = projection_neu(xr, yl, i - step.x);
                        p3 = projection_neu(xl, yl, i - step.x);
                        p4 = projection_neu(xl, yl, i);
                        latexLine(p1,p2,latexColor_,0,lineWidth_);
                        latexLine(p2,p3,latexColor_,0,lineWidth_);
                        latexLine(p3,p4,latexColor_,0,lineWidth_);
                        latexLine(p4,p1,latexColor_,0,lineWidth_);
                    }
                    if (left) {
                        p1 = projection_neu(xl, yl, i - step.x);
                        p2 = projection_neu(xl, yr, i - step.x);
                        p3 = projection_neu(xl, yr, i);
                        p4 = projection_neu(xl, yl, i);
                        latexLine(p1,p2,latexColor_,0,lineWidth_);
                        latexLine(p2,p3,latexColor_,0,lineWidth_);
                        latexLine(p3,p4,latexColor_,0,lineWidth_);
                        latexLine(p4,p1,latexColor_,0,lineWidth_);
                    }
                    if (right) {
                        p1 = projection_neu(xr, yl, i);
                        p2 = projection_neu(xr, yr, i);
                        p3 = projection_neu(xr, yr, i - step.x);
                        p4 = projection_neu(xr, yl,i - step.x);
                        latexLine(p1,p2,latexColor_,0,lineWidth_);
                        latexLine(p2,p3,latexColor_,0,lineWidth_);
                        latexLine(p3,p4,latexColor_,0,lineWidth_);
                        latexLine(p4,p1,latexColor_,0,lineWidth_);
                    }
                }
            }
        }
    }
}

void PlotLibraryLatex::renderAxisLabelScales(const PlotData& data, int indexLabel, bool helperLines) {
    std::string label;
    xAxisLabelGroup_.reset();
    xAxisLabelGroup_.setBounds(getBoundsBelowPlot());
    std::vector<PlotRowValue>::const_iterator it = data.getRowsBegin();
    plot_t x = 0;
    std::vector< PlotLibraryFileBase::Projection_Coordinates > points;
    for (;it!=data.getRowsEnd();++it) {
        if (!domain_[X_AXIS].contains(x) || it->getCellAt(indexLabel).isNull()){
            x += 1;
            continue;
        }
        if (data.getColumnType(indexLabel) == PlotBase::STRING)
            label = it->getTagAt(indexLabel);
        else {
            std::ostringstream stream;
            stream << it->getValueAt(indexLabel);
            label = stream.str();
        }
        xAxisLabelGroup_.addLabel(label,
                                  convertPlotCoordinatesToViewport3(tgt::dvec3(x, domain_[1].getLeft(), domain_[2].getRight())),
                                  fontColor_, fontSize_, SmartLabel::TOPCENTERED);
        if (helperLines && dimension_ == TWO) {
            points.clear();
            points.push_back(convertPlotCoordinatesToViewport3Projection(x,domain_[1].getLeft(),0));
            points.push_back(convertPlotCoordinatesToViewport3Projection(x,domain_[1].getRight(),0));
            latexLine(points.at(0),points.at(1),drawingColor_,0,axesWidth_/2.f);
        }
        x += 1;
    }
    renderSmartLabelGroup(&xAxisLabelGroup_);
}

void PlotLibraryLatex::renderLabel(tgt::vec3 pos, const SmartLabel::Alignment align, const std::string& text,
                              bool viewCoordinates, int padding) {
    if (!viewCoordinates)
        pos = convertPlotCoordinatesToViewport3(pos);

    tgt::Matrix4<plot_t> oldpjm = projectionsMatrix_;
    tgt::Matrix4<plot_t> oldmdlv = modelviewMatrix_;
    projectionsMatrix_ = plOrtho(0.0, windowSize_.x, 0.0, windowSize_.y, -1.0, 1.0);
    modelviewMatrix_ = tgt::Matrix4<plot_t>::createIdentity();

    tgt::dvec3 position = pos;
    SmartLabelGroupBaseLatex::renderSingleLabel(&labelFont_,  text,fontSize_, align, static_cast<double>(padding), position);
    latexText(position,text,&labelFont_,fontSize_,fontColor_,align);

    projectionsMatrix_ = oldpjm;
    modelviewMatrix_ = oldmdlv;
}

void PlotLibraryLatex::renderLabel(tgt::dvec2 pos, const SmartLabel::Alignment align, const std::string& text, int padding) {
    tgt::Matrix4<plot_t> oldpjm = projectionsMatrix_;
    tgt::Matrix4<plot_t> oldmdlv = modelviewMatrix_;
    projectionsMatrix_ = plOrtho(0.0, windowSize_.x, 0.0, windowSize_.y, -1.0, 1.0);
    modelviewMatrix_ = tgt::Matrix4<plot_t>::createIdentity();

    tgt::dvec3 position = tgt::dvec3(pos,0.0);
    SmartLabelGroupBaseLatex::renderSingleLabel(&labelFont_, text, fontSize_, align,static_cast<double>(padding), position);
    latexText(position,text,&labelFont_,fontSize_,fontColor_,align);

    projectionsMatrix_ = oldpjm;
    modelviewMatrix_ = oldmdlv;
}

void PlotLibraryLatex::addPlotLabel(std::string text, tgt::vec3 position, tgt::Color color,
                               int size, SmartLabel::Alignment align) {
    plotLabelGroup_.addLabel(text, position, color, size, align);
}

void PlotLibraryLatex::addLineLabel(std::string text, tgt::vec3 position, tgt::Color color,
                               int size, SmartLabel::Alignment align) {
    lineLabelGroup_.addLabel(text, position, color, size, align);
}

//
// helper functions
//

void PlotLibraryLatex::resetLineLabels() {
    lineLabelGroup_.reset();
    lineLabelGroup_.setBounds(getBoundsRightOfPlot());
}

void PlotLibraryLatex::renderLineLabels() {
    renderSmartLabelGroup(&lineLabelGroup_);
}

void PlotLibraryLatex::resetPlotLabels() {
    plotLabelGroup_.reset();
    plotLabelGroup_.setBounds(getBoundsPlot());
}

void PlotLibraryLatex::renderPlotLabels() {
    renderSmartLabelGroup(&plotLabelGroup_);
}

void PlotLibraryLatex::renderSmartLabelGroup(SmartLabelGroupBase* smg) {
    smg->performLayout();

    tgt::Matrix4<plot_t> oldpjm = projectionsMatrix_;
    tgt::Matrix4<plot_t> oldmdlv = modelviewMatrix_;
    projectionsMatrix_ = plOrtho(0.0, windowSize_.x, 0.0, windowSize_.y, -1.0, 1.0);
    modelviewMatrix_ = tgt::Matrix4<plot_t>::createIdentity();

    smg->render();
    if (dynamic_cast<SmartLabelGroupLatexNoLayoutWithBackground*>(smg) != 0) {
        SmartLabelGroupLatexNoLayoutWithBackground* slglabel = static_cast<SmartLabelGroupLatexNoLayoutWithBackground*>(smg);
        std::vector< std::vector< tgt::Vector3<double> > > polygonpoints = slglabel->getPolygonPoints();
        std::vector<SmartLabel> slabelvector = slglabel->getLabels();
        std::vector< tgt::Vector3<double> > points;
        std::vector< PlotLibraryFileBase::Projection_Coordinates > projPoints;
        points.resize(4);
        projPoints.resize(4);
        for (size_t i = 0; i < polygonpoints.size(); ++i) {
            for (int k = 0; k < 4; ++k) {
                points[k] = polygonpoints.at(i).at(k);
                projPoints[k] = PlotLibraryFileBase::Projection_Coordinates(points[k],points[k],points[k]);
            }
            latexPolygon(projPoints,slglabel->getBackgroundColor(),lineColor_,-1);
            latexTextArea(tgt::Vector3<double>(points[0].x,points[0].y+(points[2].y-points[0].y),points[0].z),points[1].x-points[0].x,
                points[2].y-points[0].y,slabelvector[i].text_,
                slglabel->getFont(),slabelvector[i].size_,slabelvector[i].color_);
        }
    }
    else {
        SmartLabelGroupBaseLatex* slgb = dynamic_cast<SmartLabelGroupBaseLatex*>(smg);
        if (slgb != 0) {
            std::vector<SmartLabel> slabelvector = slgb->getLabels();
            tgt::Font* font = slgb->getFont();
            tgt::dvec3 pos;
            for (size_t i = 0; i < slabelvector.size(); ++i) {
                SmartLabel label = slabelvector.at(i);
                pos = label.position_;
                latexText(pos,label.text_,font,label.size_,label.color_,label.align_);
            }
        }
    }

    projectionsMatrix_ = oldpjm;
    modelviewMatrix_ = oldmdlv;
}

void PlotLibraryLatex::resetRenderStatus() {
    lineWidth_ = 1;
}

void PlotLibraryLatex::renderGlyph(plot_t x, plot_t y, plot_t z, plot_t size) {
    if (usePlotPickingManager_)
        return;
    PlotLibraryFileBase::Projection_Coordinates point = projection_neu(x,y,z);
    tgt::Vector3<plot_t> hpoint = point.afterProjection_;

    std::vector< PlotLibraryFileBase::Projection_Coordinates > points;
    if (glyphStyle_ == PlotEntitySettings::POINT) {
        latexCircle(point,size/2,latexColor_,latexColor_,0);
        return;
    }
    if (dimension_ == TWO){
        if (glyphStyle_ == PlotEntitySettings::CIRCLE){
            if (texture_ == 0) {
                latexCircle(point,size/2,latexColor_,latexColor_,0);
            }
            else
                latexCircle(point,size/2,latexColor_,latexColor_,0,0,PlotEntitySettings::TEXTURE);
        }
        else if (glyphStyle_ == PlotEntitySettings::TRIANGLE){
            points.clear();
            tgt::Vector3<plot_t> coor = tgt::Vector3<plot_t>(hpoint.x,hpoint.y + size/2,0);
            points.push_back(PlotLibraryFileBase::Projection_Coordinates(coor,coor,coor));
            coor = tgt::Vector3<plot_t>(hpoint.x - size/3,hpoint.y - size/3,0);
            points.push_back(PlotLibraryFileBase::Projection_Coordinates(coor,coor,coor));
            coor = tgt::Vector3<plot_t>(hpoint.x + size/3,hpoint.y - size/3,0);
            points.push_back(PlotLibraryFileBase::Projection_Coordinates(coor,coor,coor));
            if (texture_ == 0) {
                latexPolygon(points,latexColor_,latexColor_,0);
            }
            else
                latexPolygon(points,latexColor_,latexColor_,0,0,PlotEntitySettings::TEXTURE);
        }
        else if (glyphStyle_ == PlotEntitySettings::QUAD){
            points.clear();
            tgt::Vector3<plot_t> coor = tgt::Vector3<plot_t>(hpoint.x-size/2,hpoint.y - size/2,0);
            points.push_back(PlotLibraryFileBase::Projection_Coordinates(coor,coor,coor));
            coor = tgt::Vector3<plot_t>(hpoint.x+size/2,hpoint.y - size/2,0);
            points.push_back(PlotLibraryFileBase::Projection_Coordinates(coor,coor,coor));
            coor = tgt::Vector3<plot_t>(hpoint.x+size/2,hpoint.y + size/2,0);
            points.push_back(PlotLibraryFileBase::Projection_Coordinates(coor,coor,coor));
            coor = tgt::Vector3<plot_t>(hpoint.x+size/2,hpoint.y + size/2,0);
            points.push_back(PlotLibraryFileBase::Projection_Coordinates(coor,coor,coor));
            if (texture_ == 0) {
                latexPolygon(points,latexColor_,latexColor_,0);
            }
            else
                latexPolygon(points,latexColor_,latexColor_,0,0,PlotEntitySettings::TEXTURE);
        }
    }
    else if (dimension_ == THREE){
        if (glyphStyle_ == PlotEntitySettings::CIRCLE){
            if (texture_ == 0) {
                latexSphere(tgt::Vector3<plot_t>(x,y,z),size,latexColor_,tgt::Color(1,1,1,0.01f),20,0,1);
            }
            else
                latexSphere(tgt::Vector3<plot_t>(x,y,z),size,latexColor_,tgt::Color(1,1,1,0.01f),20,0,1,PlotEntitySettings::TEXTURE);
        }
        else if (glyphStyle_ == PlotEntitySettings::TRIANGLE){
            if (texture_ == 0) {
                latexTriangle3D(tgt::Vector3<plot_t>(x,y,z),size,size,latexColor_,tgt::Color(1,1,1,0.01f),0,1);
            }
            else
                latexTriangle3D(tgt::Vector3<plot_t>(x,y,z),size,size,latexColor_,tgt::Color(1,1,1,0.01f),0,1,PlotEntitySettings::TEXTURE);
        }
        else if (glyphStyle_ == PlotEntitySettings::QUAD){
            if (texture_ == 0) {
                latexQuad(tgt::Vector3<plot_t>(x,y,z),size,size,size,latexColor_,tgt::Color(1,1,1,0.01f),0,1);
            }
            else
                latexQuad(tgt::Vector3<plot_t>(x,y,z),size,size,size,latexColor_,tgt::Color(1,1,1,0.01f),0,1,PlotEntitySettings::TEXTURE);
        }
    }
}

void PlotLibraryLatex::renderSingleBar(plot_t left, plot_t right, plot_t bottom, plot_t top, tgt::Color c, plot_t squeeze) {
    if (usePlotPickingManager_)
        return;
    PlotLibraryFileBase::Projection_Coordinates p1;
    PlotLibraryFileBase::Projection_Coordinates p2;
    PlotLibraryFileBase::Projection_Coordinates p3;
    PlotLibraryFileBase::Projection_Coordinates p4;

    plot_t back = domain_[Z_AXIS].getLeft();
    plot_t front = domain_[Z_AXIS].getRight();
    //squeeze
    left = (left+squeeze*left+right-squeeze*right)/2.0;
    right = (left-squeeze*left+right+squeeze*right)/2.0;
    back = (back+squeeze*back+front-squeeze*front)/2.0;
    front = (back-squeeze*back+front+squeeze*front)/2.0;
    tgt::Color color;
    std::vector< PlotLibraryFileBase::Projection_Coordinates > points;
    points.resize(4);
    lineColor_ = tgt::Color(0.2f*c.r, 0.2f*c.g, 0.2f*c.b, 1.0f);

    //bottom
    color = tgt::Color(0.9f*c.r, 0.9f*c.g, 0.9f*c.b, 1.0f);
    p1 = convertPlotCoordinatesToViewport3Projection(left,bottom,front);
    p2 = convertPlotCoordinatesToViewport3Projection(left,bottom,back);
    p3 = convertPlotCoordinatesToViewport3Projection(right,bottom,back);
    p4 = convertPlotCoordinatesToViewport3Projection(right,bottom,front);
    points[0] = p1;
    points[1] = p2;
    points[2] = p3;
    points[3] = p4;
    latexPolygon(points,color,lineColor_,0,lineWidth_);

    //back
    color = tgt::Color(0.8f*c.r, 0.8f*c.g, 0.8f*c.b, 1.0f);
    p1 = convertPlotCoordinatesToViewport3Projection(right,bottom,back);
    p2 = convertPlotCoordinatesToViewport3Projection(right,top,back);
    p3 = convertPlotCoordinatesToViewport3Projection(left,top,back);
    p4 = convertPlotCoordinatesToViewport3Projection(left,bottom,back);
    points[0] = p1;
    points[1] = p2;
    points[2] = p3;
    points[3] = p4;
    latexPolygon(points,color,lineColor_,0,lineWidth_);

    //left
    color = tgt::Color(c.r, c.g, c.b, 1.0f);
    p1 = convertPlotCoordinatesToViewport3Projection(left,bottom,front);
    p2 = convertPlotCoordinatesToViewport3Projection(left,top,front);
    p3 = convertPlotCoordinatesToViewport3Projection(left,top,back);
    p4 = convertPlotCoordinatesToViewport3Projection(left,bottom,back);
    points[0] = p1;
    points[1] = p2;
    points[2] = p3;
    points[3] = p4;
    latexPolygon(points,color,lineColor_,0,lineWidth_);

    //right
    color = tgt::Color(0.8f*c.r, 0.8f*c.g, 0.8f*c.b, 1.0f);
    p1 = convertPlotCoordinatesToViewport3Projection(right,bottom,front);
    p2 = convertPlotCoordinatesToViewport3Projection(right,top,front);
    p3 = convertPlotCoordinatesToViewport3Projection(right,top,back);
    p4 = convertPlotCoordinatesToViewport3Projection(right,bottom,back);
    points[0] = p1;
    points[1] = p2;
    points[2] = p3;
    points[3] = p4;
    latexPolygon(points,color,lineColor_,0,lineWidth_);

    //top
    color = tgt::Color(0.9f*c.r, 0.9f*c.g, 0.9f*c.b, 1.0f);
    p1 = convertPlotCoordinatesToViewport3Projection(left,top,front);
    p2 = convertPlotCoordinatesToViewport3Projection(left,top,back);
    p3 = convertPlotCoordinatesToViewport3Projection(right,top,back);
    p4 = convertPlotCoordinatesToViewport3Projection(right,top,front);
    points[0] = p1;
    points[1] = p2;
    points[2] = p3;
    points[3] = p4;
    latexPolygon(points,color,lineColor_,0,lineWidth_);

    //front
    color = tgt::Color(c.r, c.g, c.b, 1.0f);
    p1 = convertPlotCoordinatesToViewport3Projection(left,bottom,front);
    p2 = convertPlotCoordinatesToViewport3Projection(left,top,front);
    p3 = convertPlotCoordinatesToViewport3Projection(right,top,front);
    p4 = convertPlotCoordinatesToViewport3Projection(right,bottom,front);
    points[0] = p1;
    points[1] = p2;
    points[2] = p3;
    points[3] = p4;
    latexPolygon(points,color,lineColor_,0,lineWidth_);
}

void PlotLibraryLatex::latexCircle(const PlotLibraryFileBase::Projection_Coordinates& point, plot_t radius, tgt::Color fillColor, tgt::Color borderColor, int clipping_number, double lineWidth, PlotEntitySettings::PolygonFillStyle fillStyle, PlotEntitySettings::LineStyle lineStyle) {
    if (clipping_number == 0 || inClippRegion(point.afterModelview_))
        renderVector_.push_back(new PlotLibraryLatexRenderCircle(point,radius,fillColor,borderColor,clipping_number,lineWidth,textureNumber_,fillStyle,lineStyle));
}

void PlotLibraryLatex::latexLine(const PlotLibraryFileBase::Projection_Coordinates& startPoint, const PlotLibraryFileBase::Projection_Coordinates& endPoint, tgt::Color lineColor, int clipping_number, double lineWidth, PlotEntitySettings::LineStyle lineStyle) {
    if (clipping_number == 0 || inClippRegion(startPoint.afterModelview_) || inClippRegion(endPoint.afterModelview_))
        renderVector_.push_back(new PlotLibraryLatexRenderLine(startPoint,endPoint,lineColor,clipping_number,lineWidth,lineStyle));
}

void PlotLibraryLatex::latexPolygon(const std::vector< PlotLibraryFileBase::Projection_Coordinates >& points, tgt::Color fillColor, tgt::Color lineColor, int clipping_number, double lineWidth, PlotEntitySettings::PolygonFillStyle fillStyle, PlotEntitySettings::LineStyle lineStyle) {
    if (clipping_number == 0 || inClippRegion(points))
        renderVector_.push_back(new PlotLibraryLatexRenderPolygon(points,fillColor,lineColor,clipping_number,lineWidth,textureNumber_,fillStyle,lineStyle));
}

void PlotLibraryLatex::latexPolyline(const std::vector< PlotLibraryFileBase::Projection_Coordinates >& points, tgt::Color fillColor, tgt::Color lineColor, int clipping_number, double lineWidth, PlotEntitySettings::PolygonFillStyle fillStyle, PlotEntitySettings::LineStyle lineStyle) {
    if (clipping_number == 0 || inClippRegion(points))
        renderVector_.push_back(new PlotLibraryLatexRenderPolyline(points,fillColor,lineColor,clipping_number,lineWidth,textureNumber_,fillStyle,lineStyle));
}

void PlotLibraryLatex::latexEllipse(const PlotLibraryFileBase::Projection_Coordinates& mpoint, double xradius, double yradius, tgt::Color fillColor, tgt::Color lineColor, int clipping_number, double lineWidth, PlotEntitySettings::PolygonFillStyle fillStyle, PlotEntitySettings::LineStyle lineStyle) {
    if (clipping_number == 0 || inClippRegion(mpoint.afterModelview_))
        renderVector_.push_back(new PlotLibraryLatexRenderEllipse(mpoint,xradius,yradius,fillColor,lineColor,clipping_number,lineWidth,textureNumber_,fillStyle,lineStyle));
}

void PlotLibraryLatex::latexRect(const PlotLibraryFileBase::Projection_Coordinates& startPoint, double stepWidth, double height, tgt::Color startColor, tgt::Color endColor) {
    renderVector_.push_back(new PlotLibraryLatexRenderRect(startPoint,stepWidth,height,startColor,endColor));
}

void PlotLibraryLatex::latexText(const tgt::Vector3<plot_t>& point, const std::string& text,  tgt::Font* /*font*/, double size, tgt::Color textColor, const SmartLabel::Alignment align) {
    if (text.size() > 0) {
        std::stringstream latexText;
        std::stringstream controlledText;
        latexText << "\\newrgbcolor{tcolor}{" << PlotLibraryLatexRender::latexColor(textColor) << "}\n";
        latexText << "\\rput";
        switch (align) {
            case SmartLabel::TOPLEFT:
                latexText << "[lt]";
                break;
            case SmartLabel::TOPCENTERED:
                latexText << "[t]";
                break;
            case SmartLabel::TOPRIGHT:
                latexText << "[rt]";
                break;
            case SmartLabel::MIDDLELEFT:
                latexText << "[lB]";
                break;
            case SmartLabel::CENTERED:
                latexText << "[B]";
                break;
            case SmartLabel::MIDDLERIGHT:
                latexText << "[rB]";
                break;
            case SmartLabel::BOTTOMLEFT:
                latexText << "[lb]";
                break;
            case SmartLabel::BOTTOMCENTERED:
                latexText << "[b]";
                break;
            case SmartLabel::BOTTOMRIGHT:
                latexText << "[rb]";
                break;
        }
        for (size_t i = 0; i < text.size(); ++i) {
            switch (text.at(i)) {
                case '^' : controlledText << "\\^{}";
                    break;
                case '$' : controlledText << "\\$";
                    break;
                case '&' : controlledText << "\\&";
                    break;
                case '%' : controlledText << "\\%";
                    break;
                case '{' : controlledText << "\\{";
                    break;
                case '}' : controlledText << "\\}";
                    break;
                case '\\' : controlledText << "\\textbackslash";
                    break;
            default:
                controlledText << text.at(i);
            }
        }
        latexText << "(" << point.x << "," << point.y << "){\\fontsize{"<< size*0.85 <<"}{"<< size*0.85 <<"}\\selectfont\\textcolor{tcolor}{" << controlledText.str() << "}}\n";
        renderVector_.push_back(new PlotLibraryLatexRenderText(point,latexText.str()));
    }
}

void PlotLibraryLatex::latexTextArea(const tgt::Vector3<plot_t>& point, double /*width*/, double height, const std::string& text,  tgt::Font* font, double size, tgt::Color textColor) {
    std::vector<std::string > copytext;
    copytext.resize(1);
    int j =0;
    for (size_t i = 0; i < text.size(); ++i) {
        switch (text.at(i)) {
            case 'y':
            case 'z':
                ++j; copytext.push_back("");
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            case '.':
            case ':':
            case ' ':
            case 'x':
                copytext[j] += text.at(i);
                break;
        }
    }
    for (size_t i = 0; i < copytext.size(); ++i) {
        latexText(tgt::Vector3<plot_t>(point.x+3,point.y-(i+0.76)*height/copytext.size(),point.z),copytext[i],font,size,textColor,SmartLabel::MIDDLELEFT);
    }
}

void PlotLibraryLatex::latexSphere(const tgt::Vector3<plot_t>& mpoint, double radius, tgt::Color fillColor, tgt::Color lineColor, int sections, int clipping_number, double lineWidth, PlotEntitySettings::PolygonFillStyle fillStyle, PlotEntitySettings::LineStyle lineStyle) {
    PlotLibraryFileBase::Projection_Coordinates point = convertPlotCoordinatesToViewport3Projection(mpoint);
    if (inClippRegion(point.afterModelview_)) {
        double xscale = domain_[X_AXIS].size()/static_cast<double>(2*windowSize_.x);
        double yscale = domain_[Y_AXIS].size()/static_cast<double>(2*windowSize_.y);
        double zscale = domain_[Z_AXIS].size()/1000.0;
        double a = 2*tgt::PI / static_cast<double>(sections);
        double theta, phi;
        std::vector< PlotLibraryFileBase::Projection_Coordinates > points;
        points.resize(4);
        float fakt = 0;
        for (int k = 0; k < sections; ++k) {
            for (int l = 0; l < sections/2.0; ++l) {
                theta = l*a;
                phi = k*a;
                PlotLibraryFileBase::Projection_Coordinates point1 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(std::sin(theta)*std::cos(phi)*radius*xscale+mpoint.x,std::sin(theta)*std::sin(phi)*radius*yscale+mpoint.y,std::cos(theta)*radius*zscale+mpoint.z));
                PlotLibraryFileBase::Projection_Coordinates point2 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(std::sin(theta)*std::cos(phi+a)*radius*xscale+mpoint.x,std::sin(theta)*std::sin(phi+a)*radius*yscale+mpoint.y,std::cos(theta)*radius*zscale+mpoint.z));
                PlotLibraryFileBase::Projection_Coordinates point3 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(std::sin(theta+a)*std::cos(phi+a)*radius*xscale+mpoint.x,std::sin(theta+a)*std::sin(phi+a)*radius*yscale+mpoint.y,std::cos(theta+a)*radius*zscale+mpoint.z));
                PlotLibraryFileBase::Projection_Coordinates point4 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(std::sin(theta+a)*std::cos(phi)*radius*xscale+mpoint.x,std::sin(theta+a)*std::sin(phi)*radius*yscale+mpoint.y,std::cos(theta+a)*radius*zscale+mpoint.z));
                points[0] = point1;
                points[1] = point2;
                points[2] = point3;
                points[3] = point4;
                fakt = static_cast<float>(0.4 + (0.6*std::cos(theta)+ 1)/2.0);
                latexPolygon(points,tgt::Color(fillColor.r*fakt,fillColor.g*fakt,fillColor.b*fakt,fillColor.a),lineColor,clipping_number,lineWidth,fillStyle,lineStyle);
            }
        }
    }
}

void PlotLibraryLatex::latexQuad(const tgt::Vector3<plot_t>& mpoint, double xsize, double ysize, double zsize, tgt::Color fillColor, tgt::Color lineColor, int clipping_number, double lineWidth,PlotEntitySettings::PolygonFillStyle fillStyle, PlotEntitySettings::LineStyle lineStyle) {
    PlotLibraryFileBase::Projection_Coordinates point = convertPlotCoordinatesToViewport3Projection(mpoint);
    if (inClippRegion(point.afterModelview_)) {
        double xscale = domain_[X_AXIS].size()/static_cast<double>(2*windowSize_.x);
        double yscale = domain_[Y_AXIS].size()/static_cast<double>(2*windowSize_.y);
        double zscale = domain_[Z_AXIS].size()/1000.0;
        PlotLibraryFileBase::Projection_Coordinates point1 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(mpoint.x - xsize*xscale,mpoint.y - ysize*yscale,mpoint.z - zsize*zscale));
        PlotLibraryFileBase::Projection_Coordinates point2 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(mpoint.x + xsize*xscale,mpoint.y - ysize*yscale,mpoint.z - zsize*zscale));
        PlotLibraryFileBase::Projection_Coordinates point3 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(mpoint.x + xsize*xscale,mpoint.y + ysize*yscale,mpoint.z - zsize*zscale));
        PlotLibraryFileBase::Projection_Coordinates point4 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(mpoint.x - xsize*xscale,mpoint.y + ysize*yscale,mpoint.z - zsize*zscale));
        PlotLibraryFileBase::Projection_Coordinates point5 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(mpoint.x - xsize*xscale,mpoint.y - ysize*yscale,mpoint.z + zsize*zscale));
        PlotLibraryFileBase::Projection_Coordinates point6 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(mpoint.x + xsize*xscale,mpoint.y - ysize*yscale,mpoint.z + zsize*zscale));
        PlotLibraryFileBase::Projection_Coordinates point7 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(mpoint.x + xsize*xscale,mpoint.y + ysize*yscale,mpoint.z + zsize*zscale));
        PlotLibraryFileBase::Projection_Coordinates point8 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(mpoint.x - xsize*xscale,mpoint.y + ysize*yscale,mpoint.z + zsize*zscale));
        std::vector< std::vector< PlotLibraryFileBase::Projection_Coordinates > > pointsvector;
        std::vector< PlotLibraryFileBase::Projection_Coordinates > points;
        std::vector<int> sortvector;
        std::vector<tgt::Color> fillcolorvector;
        sortvector.resize(6);
        points.resize(4);
        //Front
        points[0] = point5;
        points[1] = point6;
        points[2] = point7;
        points[3] = point8;
        pointsvector.push_back(points);
        fillcolorvector.push_back(fillColor);
        //Back
        points[0] = point1;
        points[1] = point2;
        points[2] = point3;
        points[3] = point4;
        pointsvector.push_back(points);
        fillcolorvector.push_back(tgt::Color(fillColor.r*0.8f,fillColor.g*0.8f,fillColor.b*0.8f,fillColor.a));
        //left
        points[0] = point1;
        points[1] = point4;
        points[2] = point8;
        points[3] = point5;
        pointsvector.push_back(points);
        fillcolorvector.push_back(tgt::Color(fillColor.r*0.7f,fillColor.g*0.7f,fillColor.b*0.7f,fillColor.a));
        //right
        points[0] = point2;
        points[1] = point3;
        points[2] = point7;
        points[3] = point6;
        pointsvector.push_back(points);
        fillcolorvector.push_back(tgt::Color(fillColor.r*0.8f,fillColor.g*0.8f,fillColor.b*0.8f,fillColor.a));
        //top
        points[0] = point3;
        points[1] = point4;
        points[2] = point8;
        points[3] = point7;
        pointsvector.push_back(points);
        fillcolorvector.push_back(tgt::Color(fillColor.r*0.9f,fillColor.g*0.9f,fillColor.b*0.9f,fillColor.a));
        //down
        points[0] = point1;
        points[1] = point2;
        points[2] = point6;
        points[3] = point5;
        pointsvector.push_back(points);
        fillcolorvector.push_back(tgt::Color(fillColor.r*0.9f,fillColor.g*0.9f,fillColor.b*0.9f,fillColor.a));

        for (size_t i = 0; i < fillcolorvector.size(); ++i) {
            latexPolygon(pointsvector[i],fillcolorvector[i],lineColor,clipping_number,lineWidth,fillStyle,lineStyle);
        }
    }
}

void PlotLibraryLatex::latexTriangle3D(const tgt::Vector3<plot_t>& mpoint, double height, double weight, tgt::Color fillColor, tgt::Color lineColor, int clipping_number, double lineWidth, PlotEntitySettings::PolygonFillStyle fillStyle, PlotEntitySettings::LineStyle lineStyle) {
    PlotLibraryFileBase::Projection_Coordinates point = convertPlotCoordinatesToViewport3Projection(mpoint);
    if (inClippRegion(point.afterModelview_)) {
        double xscale = domain_[X_AXIS].size()/static_cast<double>(2*windowSize_.x);
        double yscale = domain_[Y_AXIS].size()/static_cast<double>(2*windowSize_.y);
        double zscale = domain_[Z_AXIS].size()/1000.0;
        PlotLibraryFileBase::Projection_Coordinates point1 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(mpoint.x - weight*xscale/2.0,mpoint.y - weight*yscale/2.0,mpoint.z - height*zscale/2.0));
        PlotLibraryFileBase::Projection_Coordinates point2 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(mpoint.x + weight*xscale/2.0,mpoint.y - weight*yscale/2.0,mpoint.z - height*zscale/2.0));
        PlotLibraryFileBase::Projection_Coordinates point3 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(mpoint.x,mpoint.y + weight*yscale/2.0,mpoint.z - height*zscale/2.0));
        PlotLibraryFileBase::Projection_Coordinates point4 = convertPlotCoordinatesToViewport3Projection(tgt::Vector3<plot_t>(mpoint.x,mpoint.y,mpoint.z + height*zscale*3.0/2.0));
        std::vector< std::vector< PlotLibraryFileBase::Projection_Coordinates > > pointsvector;
        std::vector< PlotLibraryFileBase::Projection_Coordinates > points;
        std::vector< std::pair<double, int> > sortvector;
        std::vector<double> deepvector;
        points.resize(3);
        points[0] = point1;
        points[1] = point2;
        points[2] = point3;
        pointsvector.push_back(points);
        deepvector.push_back((point1.afterProjection_.z + point2.afterProjection_.z + point3.afterProjection_.z)/3);

        points[0] = point1;
        points[1] = point2;
        points[2] = point4;
        pointsvector.push_back(points);
        deepvector.push_back((point1.afterProjection_.z + point2.afterProjection_.z + point4.afterProjection_.z)/3);

        points[0] = point1;
        points[1] = point3;
        points[2] = point4;
        pointsvector.push_back(points);
        deepvector.push_back((point1.afterProjection_.z + point3.afterProjection_.z + point4.afterProjection_.z)/3);

        points[0] = point2;
        points[1] = point3;
        points[2] = point4;
        pointsvector.push_back(points);
        deepvector.push_back((point4.afterProjection_.z + point2.afterProjection_.z + point3.afterProjection_.z)/3);

        std::vector< std::pair<double, int> >::iterator it;
        bool stop;
        std::pair<double, int> item;
        for (size_t i = 0; i < deepvector.size(); ++i) {
            stop = false;
            if (sortvector.size() == 0) {
                sortvector.push_back(std::pair<double, int>(deepvector[i], static_cast<int>(i)));
            }
            else {
                for (it = sortvector.begin(); it < sortvector.end(); ++it) {
                    if (it->first <= deepvector[i]) {
                        item = std::pair<double, int>(deepvector[i], static_cast<int>(i));
                        sortvector.insert(it,item);
                        stop = true;
                        break;
                    }
                }
                if (!stop) {
                    sortvector.push_back(std::pair<double, int>(deepvector[i], static_cast<int>(i)));
                }
            }
        }

        //float fakt;
        for(size_t i = 0; i < sortvector.size(); ++i) {
            //fakt = 0.6f*(i+1)/sortvector.size() + 0.4f;
            latexPolygon(pointsvector[sortvector[i].second],fillColor,lineColor,clipping_number,lineWidth,fillStyle,lineStyle);
        }
    }
}

} // namespace
