00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <math.h>
00019 #include <qapplication.h>
00020 #include <qwmatrix.h>
00021 #include <qrect.h>
00022
00023 #include <kdebug.h>
00024 #include <klocale.h>
00025
00026 #include "kis_paint_device.h"
00027 #include "kis_rotate_visitor.h"
00028 #include "kis_progress_display_interface.h"
00029 #include "kis_iterators_pixel.h"
00030 #include "kis_selection.h"
00031 #include "kis_painter.h"
00032
00033 void KisRotateVisitor::rotate(double angle, bool rotateAboutImageCentre, KisProgressDisplayInterface *progress)
00034 {
00035 KisPoint centreOfRotation;
00036
00037 if (rotateAboutImageCentre) {
00038 centreOfRotation = KisPoint(m_dev->image()->width() / 2.0, m_dev->image()->height() / 2.0);
00039 } else {
00040 QRect r = m_dev->exactBounds();
00041 centreOfRotation = KisPoint(r.x() + (r.width() / 2.0), r.y() + (r.height() / 2.0));
00042 }
00043
00044 m_progress = progress;
00045
00046 KisPaintDeviceSP rotated = rotate(m_dev, angle, centreOfRotation);
00047
00048 if (!m_dev->hasSelection()) {
00049
00050 m_dev->clear();
00051 } else {
00052
00053 m_dev->clearSelection();
00054 }
00055
00056 KisPainter p(m_dev);
00057 QRect r = rotated->extent();
00058
00059
00060 p.bitBlt(r.x(), r.y(), COMPOSITE_OVER, rotated, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height());
00061 p.end();
00062 }
00063
00064 void KisRotateVisitor::shear(double angleX, double angleY, KisProgressDisplayInterface *progress)
00065 {
00066 const double pi=3.1415926535897932385;
00067 double thetaX = angleX * pi / 180;
00068 double shearX = tan(thetaX);
00069 double thetaY = angleY * pi / 180;
00070 double shearY = tan(thetaY);
00071
00072 QRect r = m_dev->exactBounds();
00073
00074 const int xShearSteps = r.height();
00075 const int yShearSteps = r.width();
00076
00077 m_progress = progress;
00078 initProgress(xShearSteps + yShearSteps);
00079
00080
00081 KisPaintDeviceSP sheared;
00082
00083 if (m_dev->hasSelection()) {
00084 sheared = new KisPaintDevice(m_dev->colorSpace(), "sheared");
00085 KisPainter p1(sheared);
00086 p1.bltSelection(r.x(), r.y(), COMPOSITE_OVER, m_dev, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height());
00087 p1.end();
00088 sheared = xShear(sheared, shearX);
00089 }
00090 else {
00091 sheared = xShear(m_dev, shearX);
00092 }
00093
00094 sheared = yShear(sheared, shearY);
00095
00096 if (!m_dev->hasSelection()) {
00097 m_dev->clear();
00098 } else {
00099
00100 m_dev->clearSelection();
00101 }
00102
00103 KisPainter p2(m_dev);
00104 r = sheared->extent();
00105
00106 p2.bitBlt(r.x(), r.y(), COMPOSITE_OVER, sheared, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height());
00107 p2.end();
00108
00109 setProgressDone();
00110 }
00111
00112 KisPaintDeviceSP KisRotateVisitor::rotateRight90(KisPaintDeviceSP src)
00113 {
00114 KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotateright90");
00115 dst->setX(src->getX());
00116 dst->setY(src->getY());
00117
00118 Q_INT32 pixelSize = src->pixelSize();
00119 QRect r = src->exactBounds();
00120 Q_INT32 x = 0;
00121
00122 for (Q_INT32 y = r.bottom(); y >= r.top(); --y) {
00123 KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), false);
00124 KisVLineIterator vit = dst->createVLineIterator(-y, r.x(), r.width(), true);
00125
00126 while (!hit.isDone()) {
00127 if (hit.isSelected()) {
00128 memcpy(vit.rawData(), hit.rawData(), pixelSize);
00129 }
00130 ++hit;
00131 ++vit;
00132 }
00133 ++x;
00134 incrementProgress();
00135 }
00136
00137 return dst;
00138 }
00139
00140 KisPaintDeviceSP KisRotateVisitor::rotateLeft90(KisPaintDeviceSP src)
00141 {
00142 KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotateleft90");
00143
00144 Q_INT32 pixelSize = src->pixelSize();
00145 QRect r = src->exactBounds();
00146 Q_INT32 x = 0;
00147
00148 for (Q_INT32 y = r.top(); y <= r.bottom(); ++y) {
00149
00150 KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), false);
00151 KisVLineIterator vit = dst->createVLineIterator(y, -r.x() - r.width(), r.width(), true);
00152
00153 hit += r.width() - 1;
00154 while (!vit.isDone()) {
00155 if (hit.isSelected()) {
00156 memcpy(vit.rawData(), hit.rawData(), pixelSize);
00157 }
00158 --hit;
00159 ++vit;
00160 }
00161 ++x;
00162 incrementProgress();
00163 }
00164
00165 return dst;
00166 }
00167
00168 KisPaintDeviceSP KisRotateVisitor::rotate180(KisPaintDeviceSP src)
00169 {
00170 KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotate180");
00171 dst->setX(src->getX());
00172 dst->setY(src->getY());
00173
00174 Q_INT32 pixelSize = src->pixelSize();
00175 QRect r = src->exactBounds();
00176
00177 for (Q_INT32 y = r.top(); y <= r.bottom(); ++y) {
00178 KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width(), false);
00179 KisHLineIterator dstIt = dst->createHLineIterator( -r.x() - r.width(), -y, r.width(), true);
00180
00181 srcIt += r.width() - 1;
00182 while (!dstIt.isDone()) {
00183 if (srcIt.isSelected()) {
00184 memcpy(dstIt.rawData(), srcIt.rawData(), pixelSize);
00185 }
00186 --srcIt;
00187 ++dstIt;
00188 }
00189 incrementProgress();
00190 }
00191
00192 return dst;
00193 }
00194
00195 KisPaintDeviceSP KisRotateVisitor::rotate(KisPaintDeviceSP src, double angle, KisPoint centreOfRotation)
00196 {
00197 const double pi = 3.1415926535897932385;
00198
00199 if (angle >= 315 && angle < 360) {
00200 angle = angle - 360;
00201 } else if (angle > -360 && angle < -45) {
00202 angle = angle + 360;
00203 }
00204
00205 QRect r = src->exactBounds();
00206
00207 const int xShearSteps = r.height();
00208 const int yShearSteps = r.width();
00209 const int fixedRotateSteps = r.height();
00210
00211 KisPaintDeviceSP dst;
00212
00213 if (angle == 90) {
00214 initProgress(fixedRotateSteps);
00215 dst = rotateRight90(src);
00216 } else if (angle == 180) {
00217 initProgress(fixedRotateSteps);
00218 dst = rotate180(src);
00219 } else if (angle == 270) {
00220 initProgress(fixedRotateSteps);
00221 dst = rotateLeft90(src);
00222 } else {
00223 double theta;
00224
00225 if (angle >= -45 && angle < 45) {
00226
00227 theta = angle * pi / 180;
00228 dst = src;
00229 initProgress(yShearSteps + (2 * xShearSteps));
00230 }
00231 else if (angle >= 45 && angle < 135) {
00232
00233 initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps));
00234 dst = rotateRight90(src);
00235 theta = (angle - 90) * pi / 180;
00236 }
00237 else if (angle >= 135 && angle < 225) {
00238
00239 initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps));
00240 dst = rotate180(src);
00241 theta = (angle - 180) * pi / 180;
00242
00243 } else {
00244
00245 initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps));
00246 dst = rotateLeft90(src);
00247 theta = (angle - 270) * pi / 180;
00248 }
00249
00250 double shearX = tan(theta / 2);
00251 double shearY = sin(theta);
00252
00253
00254 dst = xShear(dst, shearX);
00255
00256 dst = yShear(dst, shearY);
00257
00258 dst = xShear(dst, shearX);
00259 }
00260
00261 double sinAngle = sin(angle * pi / 180);
00262 double cosAngle = cos(angle * pi / 180);
00263
00264 KisPoint rotatedCentreOfRotation(
00265 centreOfRotation.x() * cosAngle - centreOfRotation.y() * sinAngle,
00266 centreOfRotation.x() * sinAngle + centreOfRotation.y() * cosAngle);
00267
00268 dst->setX((Q_INT32)(dst->getX() + centreOfRotation.x() - rotatedCentreOfRotation.x()));
00269 dst->setY((Q_INT32)(dst->getY() + centreOfRotation.y() - rotatedCentreOfRotation.y()));
00270
00271 setProgressDone();
00272
00273 return dst;
00274 }
00275
00276 KisPaintDeviceSP KisRotateVisitor::xShear(KisPaintDeviceSP src, double shearX)
00277 {
00278 KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "xShear");
00279 dst->setX(src->getX());
00280 dst->setY(src->getY());
00281
00282 QRect r = src->exactBounds();
00283
00284 double displacement;
00285 Q_INT32 displacementInt;
00286 double weight;
00287
00288 for (Q_INT32 y = r.top(); y <= r.bottom(); y++) {
00289
00290
00291 displacement = -y * shearX;
00292
00293 displacementInt = (Q_INT32)(floor(displacement));
00294 weight = displacement - displacementInt;
00295
00296 Q_UINT8 pixelWeights[2];
00297
00298 pixelWeights[0] = static_cast<Q_UINT8>(weight * 255 + 0.5);
00299 pixelWeights[1] = 255 - pixelWeights[0];
00300
00301 KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width() + 1, false);
00302 KisHLineIteratorPixel leftSrcIt = src->createHLineIterator(r.x() - 1, y, r.width() + 1, false);
00303 KisHLineIteratorPixel dstIt = dst->createHLineIterator(r.x() + displacementInt, y, r.width() + 1, true);
00304
00305 while (!srcIt.isDone()) {
00306
00307 const Q_UINT8 *pixelPtrs[2];
00308
00309 pixelPtrs[0] = leftSrcIt.rawData();
00310 pixelPtrs[1] = srcIt.rawData();
00311
00312 src->colorSpace()->mixColors(pixelPtrs, pixelWeights, 2, dstIt.rawData());
00313
00314 ++srcIt;
00315 ++leftSrcIt;
00316 ++dstIt;
00317 }
00318 incrementProgress();
00319 }
00320
00321 return dst;
00322 }
00323
00324 KisPaintDeviceSP KisRotateVisitor::yShear(KisPaintDeviceSP src, double shearY)
00325 {
00326 KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "yShear");
00327 dst->setX(src->getX());
00328 dst->setY(src->getY());
00329
00330 QRect r = src->exactBounds();
00331
00332 double displacement;
00333 Q_INT32 displacementInt;
00334 double weight;
00335
00336 for (Q_INT32 x = r.left(); x <= r.right(); x++) {
00337
00338
00339 displacement = x * shearY;
00340
00341 displacementInt = (Q_INT32)(floor(displacement));
00342 weight = displacement - displacementInt;
00343
00344 Q_UINT8 pixelWeights[2];
00345
00346 pixelWeights[0] = static_cast<Q_UINT8>(weight * 255 + 0.5);
00347 pixelWeights[1] = 255 - pixelWeights[0];
00348
00349 KisVLineIteratorPixel srcIt = src->createVLineIterator(x, r.y(), r.height() + 1, false);
00350 KisVLineIteratorPixel leftSrcIt = src->createVLineIterator(x, r.y() - 1, r.height() + 1, false);
00351 KisVLineIteratorPixel dstIt = dst->createVLineIterator(x, r.y() + displacementInt, r.height() + 1, true);
00352
00353 while (!srcIt.isDone()) {
00354
00355 const Q_UINT8 *pixelPtrs[2];
00356
00357 pixelPtrs[0] = leftSrcIt.rawData();
00358 pixelPtrs[1] = srcIt.rawData();
00359
00360 src->colorSpace()->mixColors(pixelPtrs, pixelWeights, 2, dstIt.rawData());
00361
00362 ++srcIt;
00363 ++leftSrcIt;
00364 ++dstIt;
00365 }
00366 incrementProgress();
00367 }
00368
00369 return dst;
00370 }
00371
00372 void KisRotateVisitor::initProgress(Q_INT32 totalSteps)
00373 {
00374 if (!m_progress) return;
00375
00376 m_progressTotalSteps = totalSteps;
00377 m_progressStep = 0;
00378 m_lastProgressPerCent = 0;
00379
00380
00381 m_progress->setSubject(this, true, false);
00382 emit notifyProgress(0);
00383
00384 }
00385
00386 void KisRotateVisitor::incrementProgress()
00387 {
00388 if (!m_progress) return;
00389
00390 m_progressStep++;
00391 Q_INT32 progressPerCent = (m_progressStep * 100) / m_progressTotalSteps;
00392
00393 if (progressPerCent != m_lastProgressPerCent) {
00394 m_lastProgressPerCent = progressPerCent;
00395 emit notifyProgress(progressPerCent);
00396 }
00397 }
00398
00399 void KisRotateVisitor::setProgressDone()
00400 {
00401 if (!m_progress) return;
00402
00403 emit notifyProgressDone();
00404 }
00405
00406