Skip to content
Snippets Groups Projects
RotateOp.cpp 5.11 KiB
Newer Older
/*
 * Copyright 2011-2012 INSA Rennes
 *
 * This file is part of ImageINSA.
 * ImageINSA is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ImageINSA is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ImageINSA.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <QDialogButtonBox>
#include <QFormLayout>
#include <QDialog>
#include <QSpinBox>
#include <QCheckBox>

#include <cmath>

#include "RotateOp.h"
#include "../Tools.h"

using namespace std;
using namespace imagein;

RotateOp::RotateOp() : Operation(qApp->translate("Operations", "Rotation").toStdString())
Sacha Percot-Tétu's avatar
Sacha Percot-Tétu committed
bool RotateOp::needCurrentImg() const {
    return true;
}

struct Point {
    int x;
    int y;
    Point(int x_=0, int y_=0) : x(x_), y(y_) {}
};

inline Point rotatePoint(Point toRotate, Point rotatePoint, double sin, double cos)
{
    Point returnval;
    returnval.x = ((double) (toRotate.x - rotatePoint.x)) * cos + ((double) (toRotate.y - rotatePoint.y)) * sin  + rotatePoint.x;
    returnval.y = ((double) (toRotate.y - rotatePoint.y)) * cos - ((double) (toRotate.x - rotatePoint.x))* sin + rotatePoint.y;
    return returnval;
}

void RotateOp::operator()(const Image* img, const map<const Image*, string>& imgList) {

    QString imgName(imgList.find(img)->second.c_str());
    QDialog* dialog = new QDialog();
    dialog->setWindowTitle(qApp->translate("Rotation", "Rotating %1").arg(imgName));
    dialog->setMinimumWidth(180);
    QFormLayout* layout = new QFormLayout();
    dialog->setLayout(layout);


    layout->setSizeConstraint(QLayout::SetFixedSize);

    QDoubleSpinBox* angleSpinBox = new QDoubleSpinBox(dialog);
    QCheckBox* expandBox = new QCheckBox(qApp->translate("Rotation", "Expand image"), dialog);
    QSpinBox* valueSpinBox = new QSpinBox(dialog);

    angleSpinBox->setRange(-180, 180);
    angleSpinBox->setWrapping(true);
    angleSpinBox->setSingleStep(45);
    valueSpinBox->setRange(0, 255);
    valueSpinBox->setValue(0);

    layout->insertRow(0, qApp->translate("Rotation", "Rotation angle : "), angleSpinBox);
    layout->insertRow(1, expandBox);
    layout->insertRow(2, qApp->translate("Rotation", "Fill value : "), valueSpinBox);

    QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, Qt::Horizontal, dialog);
    layout->insertRow(3, buttonBox);
    QObject::connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
    QObject::connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));

    QDialog::DialogCode code = static_cast<QDialog::DialogCode>(dialog->exec());

    if(code!=QDialog::Accepted) return;

    double angle = angleSpinBox->value() * acos(0)/90;
    Image::depth_t fillValue = valueSpinBox->value();

    int Width = img->getWidth();
    int Height= img->getHeight();
    int nWidth=Width, nHeight=Height;

    double cos_angle = cos(angle);
    if(fabs(cos_angle)< 1e-10) cos_angle = 0;
    double cos_neg_ang = cos( -angle );
    if( fabs(cos_neg_ang) < 1e-10 ) cos_neg_ang = 0;

    double sin_angle = sin(angle);
    if( fabs(sin_angle) < 1e-10 ) sin_angle = 0;
    double sin_neg_ang = sin( -angle );
    if( fabs(sin_neg_ang) < 1e-10 ) sin_neg_ang = 0;

    // Calculate the size of the new bitmap
    Point rotation_point;
    rotation_point.x = img->getWidth()/2;
    rotation_point.y = img->getHeight()/2;
    Point p1 = rotatePoint(Point(0,0), rotation_point, sin_angle, cos_angle);
    Point p2 = rotatePoint(Point(img->getWidth()-1,0), rotation_point,  sin_angle, cos_angle);
    Point p3 = rotatePoint(Point(0,img->getHeight()-1), rotation_point, sin_angle, cos_angle);
    Point p4 = rotatePoint(Point(img->getWidth()-1,img->getHeight()-1), rotation_point, sin_angle, cos_angle);

    int min_x = min(min(p1.x,p2.x),min(p3.x,p4.x));
    int max_x = max(max(p1.x,p2.x),max(p3.x,p4.x));
    int min_y = min(min(p1.y,p2.y),min(p3.y,p4.y));
    int max_y = max(max(p1.y,p2.y),max(p3.y,p4.y));

    if(expandBox->isChecked()) {
        nWidth = abs(max_x-min_x)+1;
        nHeight= abs(max_y-min_y)+1;
    }

    Image *resImg = new Image(nWidth, nHeight, img->getNbChannels(), fillValue);

    Point source_point;
    for(unsigned int c = 0; c < resImg->getNbChannels(); ++c){
        for(unsigned int i = 0; i<resImg->getWidth(); i++){
            for(unsigned int j = 0; j<resImg->getHeight(); j++){
            
                source_point = rotatePoint(Point(i,j), rotation_point, sin_neg_ang, cos_neg_ang );
                try {
                    resImg->setPixel(i,j, c,img->getPixel(source_point.x,source_point.y,c));
	            catch(std::out_of_range){}
    QString name = qApp->translate("Rotation", "rotated %1").arg(angleSpinBox->value());
    this->outImage(resImg, name.toStdString());