chalk

kis_rotate_visitor.cpp
1/*
2 * Copyright (c) 2004 Michael Thaler <michael.thaler@physik.tu-muenchen.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18#include <math.h>
19#include <tqapplication.h>
20#include <tqwmatrix.h>
21#include <tqrect.h>
22
23#include <kdebug.h>
24#include <tdelocale.h>
25
26#include "kis_paint_device.h"
27#include "kis_rotate_visitor.h"
28#include "kis_progress_display_interface.h"
29#include "kis_iterators_pixel.h"
30#include "kis_selection.h"
31#include "kis_painter.h"
32
33void KisRotateVisitor::rotate(double angle, bool rotateAboutImageCentre, KisProgressDisplayInterface *progress)
34{
35 KisPoint centreOfRotation;
36
37 if (rotateAboutImageCentre) {
38 centreOfRotation = KisPoint(m_dev->image()->width() / 2.0, m_dev->image()->height() / 2.0);
39 } else {
40 TQRect r = m_dev->exactBounds();
41 centreOfRotation = KisPoint(r.x() + (r.width() / 2.0), r.y() + (r.height() / 2.0));
42 }
43
44 m_progress = progress;
45
46 KisPaintDeviceSP rotated = rotate(m_dev, angle, centreOfRotation);
47
48 if (!m_dev->hasSelection()) {
49 // Clear everything
50 m_dev->clear();
51 } else {
52 // Clear selected pixels
53 m_dev->clearSelection();
54 }
55
56 KisPainter p(m_dev);
57 TQRect r = rotated->extent();
58
59 // OVER ipv COPY
60 p.bitBlt(r.x(), r.y(), COMPOSITE_OVER, rotated, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height());
61 p.end();
62}
63
64void KisRotateVisitor::shear(double angleX, double angleY, KisProgressDisplayInterface *progress)
65{
66 const double pi=3.1415926535897932385;
67 double thetaX = angleX * pi / 180;
68 double shearX = tan(thetaX);
69 double thetaY = angleY * pi / 180;
70 double shearY = tan(thetaY);
71
72 TQRect r = m_dev->exactBounds();
73
74 const int xShearSteps = r.height();
75 const int yShearSteps = r.width();
76
77 m_progress = progress;
78 initProgress(xShearSteps + yShearSteps);
79
80
81 KisPaintDeviceSP sheared;
82
83 if (m_dev->hasSelection()) {
84 sheared = new KisPaintDevice(m_dev->colorSpace(), "sheared");
85 KisPainter p1(sheared);
86 p1.bltSelection(r.x(), r.y(), COMPOSITE_OVER, m_dev, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height());
87 p1.end();
88 sheared = xShear(sheared, shearX);
89 }
90 else {
91 sheared = xShear(m_dev, shearX);
92 }
93
94 sheared = yShear(sheared, shearY);
95
96 if (!m_dev->hasSelection()) {
97 m_dev->clear();
98 } else {
99 // Clear selected pixels
100 m_dev->clearSelection();
101 }
102
103 KisPainter p2(m_dev);
104 r = sheared->extent();
105
106 p2.bitBlt(r.x(), r.y(), COMPOSITE_OVER, sheared, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height());
107 p2.end();
108
109 setProgressDone();
110}
111
112KisPaintDeviceSP KisRotateVisitor::rotateRight90(KisPaintDeviceSP src)
113{
114 KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotateright90");
115 dst->setX(src->getX());
116 dst->setY(src->getY());
117
118 TQ_INT32 pixelSize = src->pixelSize();
119 TQRect r = src->exactBounds();
120 TQ_INT32 x = 0;
121
122 for (TQ_INT32 y = r.bottom(); y >= r.top(); --y) {
123 KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), false);
124 KisVLineIterator vit = dst->createVLineIterator(-y, r.x(), r.width(), true);
125
126 while (!hit.isDone()) {
127 if (hit.isSelected()) {
128 memcpy(vit.rawData(), hit.rawData(), pixelSize);
129 }
130 ++hit;
131 ++vit;
132 }
133 ++x;
134 incrementProgress();
135 }
136
137 return dst;
138}
139
140KisPaintDeviceSP KisRotateVisitor::rotateLeft90(KisPaintDeviceSP src)
141{
142 KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotateleft90");
143
144 TQ_INT32 pixelSize = src->pixelSize();
145 TQRect r = src->exactBounds();
146 TQ_INT32 x = 0;
147
148 for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) {
149 // Read the horizontal line from back to front, write onto the vertical column
150 KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), false);
151 KisVLineIterator vit = dst->createVLineIterator(y, -r.x() - r.width(), r.width(), true);
152
153 hit += r.width() - 1;
154 while (!vit.isDone()) {
155 if (hit.isSelected()) {
156 memcpy(vit.rawData(), hit.rawData(), pixelSize);
157 }
158 --hit;
159 ++vit;
160 }
161 ++x;
162 incrementProgress();
163 }
164
165 return dst;
166}
167
168KisPaintDeviceSP KisRotateVisitor::rotate180(KisPaintDeviceSP src)
169{
170 KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotate180");
171 dst->setX(src->getX());
172 dst->setY(src->getY());
173
174 TQ_INT32 pixelSize = src->pixelSize();
175 TQRect r = src->exactBounds();
176
177 for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) {
178 KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width(), false);
179 KisHLineIterator dstIt = dst->createHLineIterator( -r.x() - r.width(), -y, r.width(), true);
180
181 srcIt += r.width() - 1;
182 while (!dstIt.isDone()) {
183 if (srcIt.isSelected()) {
184 memcpy(dstIt.rawData(), srcIt.rawData(), pixelSize);
185 }
186 --srcIt;
187 ++dstIt;
188 }
189 incrementProgress();
190 }
191
192 return dst;
193}
194
195KisPaintDeviceSP KisRotateVisitor::rotate(KisPaintDeviceSP src, double angle, KisPoint centreOfRotation)
196{
197 const double pi = 3.1415926535897932385;
198
199 if (angle >= 315 && angle < 360) {
200 angle = angle - 360;
201 } else if (angle > -360 && angle < -45) {
202 angle = angle + 360;
203 }
204
205 TQRect r = src->exactBounds();
206
207 const int xShearSteps = r.height();
208 const int yShearSteps = r.width();
209 const int fixedRotateSteps = r.height();
210
211 KisPaintDeviceSP dst;
212
213 if (angle == 90) {
214 initProgress(fixedRotateSteps);
215 dst = rotateRight90(src);
216 } else if (angle == 180) {
217 initProgress(fixedRotateSteps);
218 dst = rotate180(src);
219 } else if (angle == 270) {
220 initProgress(fixedRotateSteps);
221 dst = rotateLeft90(src);
222 } else {
223 double theta;
224
225 if (angle >= -45 && angle < 45) {
226
227 theta = angle * pi / 180;
228 dst = src;
229 initProgress(yShearSteps + (2 * xShearSteps));
230 }
231 else if (angle >= 45 && angle < 135) {
232
233 initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps));
234 dst = rotateRight90(src);
235 theta = (angle - 90) * pi / 180;
236 }
237 else if (angle >= 135 && angle < 225) {
238
239 initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps));
240 dst = rotate180(src);
241 theta = (angle - 180) * pi / 180;
242
243 } else {
244
245 initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps));
246 dst = rotateLeft90(src);
247 theta = (angle - 270) * pi / 180;
248 }
249
250 double shearX = tan(theta / 2);
251 double shearY = sin(theta);
252
253 //first perform a shear along the x-axis by tan(theta/2)
254 dst = xShear(dst, shearX);
255 //next perform a shear along the y-axis by sin(theta)
256 dst = yShear(dst, shearY);
257 //again perform a shear along the x-axis by tan(theta/2)
258 dst = xShear(dst, shearX);
259 }
260
261 double sinAngle = sin(angle * pi / 180);
262 double cosAngle = cos(angle * pi / 180);
263
264 KisPoint rotatedCentreOfRotation(
265 centreOfRotation.x() * cosAngle - centreOfRotation.y() * sinAngle,
266 centreOfRotation.x() * sinAngle + centreOfRotation.y() * cosAngle);
267
268 dst->setX((TQ_INT32)(dst->getX() + centreOfRotation.x() - rotatedCentreOfRotation.x()));
269 dst->setY((TQ_INT32)(dst->getY() + centreOfRotation.y() - rotatedCentreOfRotation.y()));
270
271 setProgressDone();
272
273 return dst;
274}
275
276KisPaintDeviceSP KisRotateVisitor::xShear(KisPaintDeviceSP src, double shearX)
277{
278 KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "xShear");
279 dst->setX(src->getX());
280 dst->setY(src->getY());
281
282 TQRect r = src->exactBounds();
283
284 double displacement;
285 TQ_INT32 displacementInt;
286 double weight;
287
288 for (TQ_INT32 y = r.top(); y <= r.bottom(); y++) {
289
290 //calculate displacement
291 displacement = -y * shearX;
292
293 displacementInt = (TQ_INT32)(floor(displacement));
294 weight = displacement - displacementInt;
295
296 TQ_UINT8 pixelWeights[2];
297
298 pixelWeights[0] = static_cast<TQ_UINT8>(weight * 255 + 0.5);
299 pixelWeights[1] = 255 - pixelWeights[0];
300
301 KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width() + 1, false);
302 KisHLineIteratorPixel leftSrcIt = src->createHLineIterator(r.x() - 1, y, r.width() + 1, false);
303 KisHLineIteratorPixel dstIt = dst->createHLineIterator(r.x() + displacementInt, y, r.width() + 1, true);
304
305 while (!srcIt.isDone()) {
306
307 const TQ_UINT8 *pixelPtrs[2];
308
309 pixelPtrs[0] = leftSrcIt.rawData();
310 pixelPtrs[1] = srcIt.rawData();
311
312 src->colorSpace()->mixColors(pixelPtrs, pixelWeights, 2, dstIt.rawData());
313
314 ++srcIt;
315 ++leftSrcIt;
316 ++dstIt;
317 }
318 incrementProgress();
319 }
320
321 return dst;
322}
323
324KisPaintDeviceSP KisRotateVisitor::yShear(KisPaintDeviceSP src, double shearY)
325{
326 KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "yShear");
327 dst->setX(src->getX());
328 dst->setY(src->getY());
329
330 TQRect r = src->exactBounds();
331
332 double displacement;
333 TQ_INT32 displacementInt;
334 double weight;
335
336 for (TQ_INT32 x = r.left(); x <= r.right(); x++) {
337
338 //calculate displacement
339 displacement = x * shearY;
340
341 displacementInt = (TQ_INT32)(floor(displacement));
342 weight = displacement - displacementInt;
343
344 TQ_UINT8 pixelWeights[2];
345
346 pixelWeights[0] = static_cast<TQ_UINT8>(weight * 255 + 0.5);
347 pixelWeights[1] = 255 - pixelWeights[0];
348
349 KisVLineIteratorPixel srcIt = src->createVLineIterator(x, r.y(), r.height() + 1, false);
350 KisVLineIteratorPixel leftSrcIt = src->createVLineIterator(x, r.y() - 1, r.height() + 1, false);
351 KisVLineIteratorPixel dstIt = dst->createVLineIterator(x, r.y() + displacementInt, r.height() + 1, true);
352
353 while (!srcIt.isDone()) {
354
355 const TQ_UINT8 *pixelPtrs[2];
356
357 pixelPtrs[0] = leftSrcIt.rawData();
358 pixelPtrs[1] = srcIt.rawData();
359
360 src->colorSpace()->mixColors(pixelPtrs, pixelWeights, 2, dstIt.rawData());
361
362 ++srcIt;
363 ++leftSrcIt;
364 ++dstIt;
365 }
366 incrementProgress();
367 }
368
369 return dst;
370}
371
372void KisRotateVisitor::initProgress(TQ_INT32 totalSteps)
373{
374 if (!m_progress) return;
375
376 m_progressTotalSteps = totalSteps;
377 m_progressStep = 0;
378 m_lastProgressPerCent = 0;
379
380
381 m_progress->setSubject(this, true, false);
382 emit notifyProgress(0);
383
384}
385
386void KisRotateVisitor::incrementProgress()
387{
388 if (!m_progress) return;
389
390 m_progressStep++;
391 TQ_INT32 progressPerCent = (m_progressStep * 100) / m_progressTotalSteps;
392
393 if (progressPerCent != m_lastProgressPerCent) {
394 m_lastProgressPerCent = progressPerCent;
395 emit notifyProgress(progressPerCent);
396 }
397}
398
399void KisRotateVisitor::setProgressDone()
400{
401 if (!m_progress) return;
402
403 emit notifyProgressDone();
404}
405
406
The pixel iterators are high level iterarators.
A paint device contains the actual pixel data and offers methods to read and write pixels.
KisPainter contains the graphics primitives necessary to draw on a KisPaintDevice.
Definition kis_painter.h:56
A double-based point class that can return it's coordinates approximated to integers.
Definition kis_point.h:28