|
- /*
- * Copyright (c) 2004 Michael Thaler <michael.thaler@physik.tu-muenchen.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- #include <math.h>
- #include <tqapplication.h>
- #include <tqwmatrix.h>
- #include <tqrect.h>
-
- #include <kdebug.h>
- #include <tdelocale.h>
-
- #include "kis_paint_device.h"
- #include "kis_rotate_visitor.h"
- #include "kis_progress_display_interface.h"
- #include "kis_iterators_pixel.h"
- #include "kis_selection.h"
- #include "kis_painter.h"
-
- void KisRotateVisitor::rotate(double angle, bool rotateAboutImageCentre, KisProgressDisplayInterface *progress)
- {
- KisPoint centreOfRotation;
-
- if (rotateAboutImageCentre) {
- centreOfRotation = KisPoint(m_dev->image()->width() / 2.0, m_dev->image()->height() / 2.0);
- } else {
- TQRect r = m_dev->exactBounds();
- centreOfRotation = KisPoint(r.x() + (r.width() / 2.0), r.y() + (r.height() / 2.0));
- }
-
- m_progress = progress;
-
- KisPaintDeviceSP rotated = rotate(m_dev, angle, centreOfRotation);
-
- if (!m_dev->hasSelection()) {
- // Clear everything
- m_dev->clear();
- } else {
- // Clear selected pixels
- m_dev->clearSelection();
- }
-
- KisPainter p(m_dev);
- TQRect r = rotated->extent();
-
- // OVER ipv COPY
- p.bitBlt(r.x(), r.y(), COMPOSITE_OVER, rotated, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height());
- p.end();
- }
-
- void KisRotateVisitor::shear(double angleX, double angleY, KisProgressDisplayInterface *progress)
- {
- const double pi=3.1415926535897932385;
- double thetaX = angleX * pi / 180;
- double shearX = tan(thetaX);
- double thetaY = angleY * pi / 180;
- double shearY = tan(thetaY);
-
- TQRect r = m_dev->exactBounds();
-
- const int xShearSteps = r.height();
- const int yShearSteps = r.width();
-
- m_progress = progress;
- initProgress(xShearSteps + yShearSteps);
-
-
- KisPaintDeviceSP sheared;
-
- if (m_dev->hasSelection()) {
- sheared = new KisPaintDevice(m_dev->colorSpace(), "sheared");
- KisPainter p1(sheared);
- p1.bltSelection(r.x(), r.y(), COMPOSITE_OVER, m_dev, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height());
- p1.end();
- sheared = xShear(sheared, shearX);
- }
- else {
- sheared = xShear(m_dev, shearX);
- }
-
- sheared = yShear(sheared, shearY);
-
- if (!m_dev->hasSelection()) {
- m_dev->clear();
- } else {
- // Clear selected pixels
- m_dev->clearSelection();
- }
-
- KisPainter p2(m_dev);
- r = sheared->extent();
-
- p2.bitBlt(r.x(), r.y(), COMPOSITE_OVER, sheared, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height());
- p2.end();
-
- setProgressDone();
- }
-
- KisPaintDeviceSP KisRotateVisitor::rotateRight90(KisPaintDeviceSP src)
- {
- KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotateright90");
- dst->setX(src->getX());
- dst->setY(src->getY());
-
- TQ_INT32 pixelSize = src->pixelSize();
- TQRect r = src->exactBounds();
- TQ_INT32 x = 0;
-
- for (TQ_INT32 y = r.bottom(); y >= r.top(); --y) {
- KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), false);
- KisVLineIterator vit = dst->createVLineIterator(-y, r.x(), r.width(), true);
-
- while (!hit.isDone()) {
- if (hit.isSelected()) {
- memcpy(vit.rawData(), hit.rawData(), pixelSize);
- }
- ++hit;
- ++vit;
- }
- ++x;
- incrementProgress();
- }
-
- return dst;
- }
-
- KisPaintDeviceSP KisRotateVisitor::rotateLeft90(KisPaintDeviceSP src)
- {
- KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotateleft90");
-
- TQ_INT32 pixelSize = src->pixelSize();
- TQRect r = src->exactBounds();
- TQ_INT32 x = 0;
-
- for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) {
- // Read the horizontal line from back to front, write onto the vertical column
- KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), false);
- KisVLineIterator vit = dst->createVLineIterator(y, -r.x() - r.width(), r.width(), true);
-
- hit += r.width() - 1;
- while (!vit.isDone()) {
- if (hit.isSelected()) {
- memcpy(vit.rawData(), hit.rawData(), pixelSize);
- }
- --hit;
- ++vit;
- }
- ++x;
- incrementProgress();
- }
-
- return dst;
- }
-
- KisPaintDeviceSP KisRotateVisitor::rotate180(KisPaintDeviceSP src)
- {
- KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotate180");
- dst->setX(src->getX());
- dst->setY(src->getY());
-
- TQ_INT32 pixelSize = src->pixelSize();
- TQRect r = src->exactBounds();
-
- for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) {
- KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width(), false);
- KisHLineIterator dstIt = dst->createHLineIterator( -r.x() - r.width(), -y, r.width(), true);
-
- srcIt += r.width() - 1;
- while (!dstIt.isDone()) {
- if (srcIt.isSelected()) {
- memcpy(dstIt.rawData(), srcIt.rawData(), pixelSize);
- }
- --srcIt;
- ++dstIt;
- }
- incrementProgress();
- }
-
- return dst;
- }
-
- KisPaintDeviceSP KisRotateVisitor::rotate(KisPaintDeviceSP src, double angle, KisPoint centreOfRotation)
- {
- const double pi = 3.1415926535897932385;
-
- if (angle >= 315 && angle < 360) {
- angle = angle - 360;
- } else if (angle > -360 && angle < -45) {
- angle = angle + 360;
- }
-
- TQRect r = src->exactBounds();
-
- const int xShearSteps = r.height();
- const int yShearSteps = r.width();
- const int fixedRotateSteps = r.height();
-
- KisPaintDeviceSP dst;
-
- if (angle == 90) {
- initProgress(fixedRotateSteps);
- dst = rotateRight90(src);
- } else if (angle == 180) {
- initProgress(fixedRotateSteps);
- dst = rotate180(src);
- } else if (angle == 270) {
- initProgress(fixedRotateSteps);
- dst = rotateLeft90(src);
- } else {
- double theta;
-
- if (angle >= -45 && angle < 45) {
-
- theta = angle * pi / 180;
- dst = src;
- initProgress(yShearSteps + (2 * xShearSteps));
- }
- else if (angle >= 45 && angle < 135) {
-
- initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps));
- dst = rotateRight90(src);
- theta = (angle - 90) * pi / 180;
- }
- else if (angle >= 135 && angle < 225) {
-
- initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps));
- dst = rotate180(src);
- theta = (angle - 180) * pi / 180;
-
- } else {
-
- initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps));
- dst = rotateLeft90(src);
- theta = (angle - 270) * pi / 180;
- }
-
- double shearX = tan(theta / 2);
- double shearY = sin(theta);
-
- //first perform a shear along the x-axis by tan(theta/2)
- dst = xShear(dst, shearX);
- //next perform a shear along the y-axis by sin(theta)
- dst = yShear(dst, shearY);
- //again perform a shear along the x-axis by tan(theta/2)
- dst = xShear(dst, shearX);
- }
-
- double sinAngle = sin(angle * pi / 180);
- double cosAngle = cos(angle * pi / 180);
-
- KisPoint rotatedCentreOfRotation(
- centreOfRotation.x() * cosAngle - centreOfRotation.y() * sinAngle,
- centreOfRotation.x() * sinAngle + centreOfRotation.y() * cosAngle);
-
- dst->setX((TQ_INT32)(dst->getX() + centreOfRotation.x() - rotatedCentreOfRotation.x()));
- dst->setY((TQ_INT32)(dst->getY() + centreOfRotation.y() - rotatedCentreOfRotation.y()));
-
- setProgressDone();
-
- return dst;
- }
-
- KisPaintDeviceSP KisRotateVisitor::xShear(KisPaintDeviceSP src, double shearX)
- {
- KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "xShear");
- dst->setX(src->getX());
- dst->setY(src->getY());
-
- TQRect r = src->exactBounds();
-
- double displacement;
- TQ_INT32 displacementInt;
- double weight;
-
- for (TQ_INT32 y = r.top(); y <= r.bottom(); y++) {
-
- //calculate displacement
- displacement = -y * shearX;
-
- displacementInt = (TQ_INT32)(floor(displacement));
- weight = displacement - displacementInt;
-
- TQ_UINT8 pixelWeights[2];
-
- pixelWeights[0] = static_cast<TQ_UINT8>(weight * 255 + 0.5);
- pixelWeights[1] = 255 - pixelWeights[0];
-
- KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width() + 1, false);
- KisHLineIteratorPixel leftSrcIt = src->createHLineIterator(r.x() - 1, y, r.width() + 1, false);
- KisHLineIteratorPixel dstIt = dst->createHLineIterator(r.x() + displacementInt, y, r.width() + 1, true);
-
- while (!srcIt.isDone()) {
-
- const TQ_UINT8 *pixelPtrs[2];
-
- pixelPtrs[0] = leftSrcIt.rawData();
- pixelPtrs[1] = srcIt.rawData();
-
- src->colorSpace()->mixColors(pixelPtrs, pixelWeights, 2, dstIt.rawData());
-
- ++srcIt;
- ++leftSrcIt;
- ++dstIt;
- }
- incrementProgress();
- }
-
- return dst;
- }
-
- KisPaintDeviceSP KisRotateVisitor::yShear(KisPaintDeviceSP src, double shearY)
- {
- KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "yShear");
- dst->setX(src->getX());
- dst->setY(src->getY());
-
- TQRect r = src->exactBounds();
-
- double displacement;
- TQ_INT32 displacementInt;
- double weight;
-
- for (TQ_INT32 x = r.left(); x <= r.right(); x++) {
-
- //calculate displacement
- displacement = x * shearY;
-
- displacementInt = (TQ_INT32)(floor(displacement));
- weight = displacement - displacementInt;
-
- TQ_UINT8 pixelWeights[2];
-
- pixelWeights[0] = static_cast<TQ_UINT8>(weight * 255 + 0.5);
- pixelWeights[1] = 255 - pixelWeights[0];
-
- KisVLineIteratorPixel srcIt = src->createVLineIterator(x, r.y(), r.height() + 1, false);
- KisVLineIteratorPixel leftSrcIt = src->createVLineIterator(x, r.y() - 1, r.height() + 1, false);
- KisVLineIteratorPixel dstIt = dst->createVLineIterator(x, r.y() + displacementInt, r.height() + 1, true);
-
- while (!srcIt.isDone()) {
-
- const TQ_UINT8 *pixelPtrs[2];
-
- pixelPtrs[0] = leftSrcIt.rawData();
- pixelPtrs[1] = srcIt.rawData();
-
- src->colorSpace()->mixColors(pixelPtrs, pixelWeights, 2, dstIt.rawData());
-
- ++srcIt;
- ++leftSrcIt;
- ++dstIt;
- }
- incrementProgress();
- }
-
- return dst;
- }
-
- void KisRotateVisitor::initProgress(TQ_INT32 totalSteps)
- {
- if (!m_progress) return;
-
- m_progressTotalSteps = totalSteps;
- m_progressStep = 0;
- m_lastProgressPerCent = 0;
-
-
- m_progress->setSubject(this, true, false);
- emit notifyProgress(0);
-
- }
-
- void KisRotateVisitor::incrementProgress()
- {
- if (!m_progress) return;
-
- m_progressStep++;
- TQ_INT32 progressPerCent = (m_progressStep * 100) / m_progressTotalSteps;
-
- if (progressPerCent != m_lastProgressPerCent) {
- m_lastProgressPerCent = progressPerCent;
- emit notifyProgress(progressPerCent);
- }
- }
-
- void KisRotateVisitor::setProgressDone()
- {
- if (!m_progress) return;
-
- emit notifyProgressDone();
- }
-
|