Krita Source Code Documentation
Loading...
Searching...
No Matches
krita_utils.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2011 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "krita_utils.h"
8
9#include <QtCore/qmath.h>
10
11#include <QRect>
12#include <QRegion>
13#include <QPainterPath>
14#include <QPolygonF>
15#include <QPen>
16#include <QPainter>
17
18#include "kis_algebra_2d.h"
19
21
22#include "kis_image.h"
23#include "kis_image_config.h"
24#include "kis_debug.h"
25#include "kis_node.h"
28
29#include <KisRenderedDab.h>
30
31
32namespace KritaUtils
33{
34
36 {
37 KisImageConfig cfg(true);
38 return QSize(cfg.updatePatchWidth(),
39 cfg.updatePatchHeight());
40 }
41
42 QVector<QRect> splitRectIntoPatches(const QRect &rc, const QSize &patchSize)
43 {
44 using namespace KisAlgebra2D;
45
46
47 QVector<QRect> patches;
48
49 const qint32 firstCol = divideFloor(rc.x(), patchSize.width());
50 const qint32 firstRow = divideFloor(rc.y(), patchSize.height());
51
52 // TODO: check if -1 is needed here
53 const qint32 lastCol = divideFloor(rc.x() + rc.width(), patchSize.width());
54 const qint32 lastRow = divideFloor(rc.y() + rc.height(), patchSize.height());
55
56 for(qint32 i = firstRow; i <= lastRow; i++) {
57 for(qint32 j = firstCol; j <= lastCol; j++) {
58 QRect maxPatchRect(j * patchSize.width(), i * patchSize.height(),
59 patchSize.width(), patchSize.height());
60 QRect patchRect = rc & maxPatchRect;
61
62 if (!patchRect.isEmpty()) {
63 patches.append(patchRect);
64 }
65 }
66 }
67
68 return patches;
69 }
70
71 QVector<QRect> splitRectIntoPatchesTight(const QRect &rc, const QSize &patchSize)
72 {
73 QVector<QRect> patches;
74
75 for (qint32 y = rc.y(); y < rc.y() + rc.height(); y += patchSize.height()) {
76 for (qint32 x = rc.x(); x < rc.x() + rc.width(); x += patchSize.width()) {
77 patches << QRect(x, y,
78 qMin(rc.x() + rc.width() - x, patchSize.width()),
79 qMin(rc.y() + rc.height() - y, patchSize.height()));
80 }
81 }
82
83 return patches;
84 }
85
86 QVector<QRect> splitRegionIntoPatches(const KisRegion &region, const QSize &patchSize)
87 {
88 QVector<QRect> patches;
89
90 Q_FOREACH (const QRect rect, region.rects()) {
91 patches << KritaUtils::splitRectIntoPatches(rect, patchSize);
92 }
93
94 return patches;
95 }
96
97 bool checkInTriangle(const QRectF &rect,
98 const QPolygonF &triangle)
99 {
100 return triangle.intersected(rect).boundingRect().isValid();
101 }
102
103
104 KisRegion splitTriangles(const QPointF &center,
105 const QVector<QPointF> &points)
106 {
107
108 Q_ASSERT(points.size());
109 Q_ASSERT(!(points.size() & 1));
110
111 QVector<QPolygonF> triangles;
112 QRect totalRect;
113
114 for (int i = 0; i < points.size(); i += 2) {
115 QPolygonF triangle;
116 triangle << center;
117 triangle << points[i];
118 triangle << points[i+1];
119
120 totalRect |= triangle.boundingRect().toAlignedRect();
121 triangles << triangle;
122 }
123
124
125 const int step = 64;
126 const int right = totalRect.x() + totalRect.width();
127 const int bottom = totalRect.y() + totalRect.height();
128
129 QVector<QRect> dirtyRects;
130
131 for (int y = totalRect.y(); y < bottom;) {
132 int nextY = qMin((y + step) & ~(step-1), bottom);
133
134 for (int x = totalRect.x(); x < right;) {
135 int nextX = qMin((x + step) & ~(step-1), right);
136
137 QRect rect(x, y, nextX - x, nextY - y);
138
139 Q_FOREACH (const QPolygonF &triangle, triangles) {
140 if(checkInTriangle(rect, triangle)) {
141 dirtyRects << rect;
142 break;
143 }
144 }
145
146 x = nextX;
147 }
148 y = nextY;
149 }
150 return KisRegion(std::move(dirtyRects));
151 }
152
153 KisRegion splitPath(const QPainterPath &path)
154 {
155 QVector<QRect> dirtyRects;
156 QRect totalRect = path.boundingRect().toAlignedRect();
157
158 // adjust the rect for antialiasing to work
159 totalRect = totalRect.adjusted(-1,-1,1,1);
160
161 const int step = 64;
162 const int right = totalRect.x() + totalRect.width();
163 const int bottom = totalRect.y() + totalRect.height();
164
165 for (int y = totalRect.y(); y < bottom;) {
166 int nextY = qMin((y + step) & ~(step-1), bottom);
167
168 for (int x = totalRect.x(); x < right;) {
169 int nextX = qMin((x + step) & ~(step-1), right);
170
171 QRect rect(x, y, nextX - x, nextY - y);
172
173 if(path.intersects(rect)) {
174 dirtyRects << rect;
175 }
176
177 x = nextX;
178 }
179 y = nextY;
180 }
181
182 return KisRegion(std::move(dirtyRects));
183 }
184
185 QString KRITAIMAGE_EXPORT prettyFormatReal(qreal value)
186 {
187 return QLocale().toString(value, 'f', 1);
188 }
189
190 qreal KRITAIMAGE_EXPORT maxDimensionPortion(const QRectF &bounds, qreal portion, qreal minValue)
191 {
192 qreal maxDimension = qMax(bounds.width(), bounds.height());
193 return qMax(portion * maxDimension, minValue);
194 }
195
196 bool tryMergePoints(QPainterPath &path,
197 const QPointF &startPoint,
198 const QPointF &endPoint,
199 qreal &distance,
200 qreal distanceThreshold,
201 bool lastSegment)
202 {
203 qreal length = (endPoint - startPoint).manhattanLength();
204
205 if (lastSegment || length > distanceThreshold) {
206 if (lastSegment) {
207 qreal wrappedLength =
208 (endPoint - QPointF(path.elementAt(0))).manhattanLength();
209
210 if (length < distanceThreshold ||
211 wrappedLength < distanceThreshold) {
212
213 return true;
214 }
215 }
216
217 distance = 0;
218 return false;
219 }
220
221 distance += length;
222
223 if (distance > distanceThreshold) {
224 path.lineTo(endPoint);
225 distance = 0;
226 }
227
228 return true;
229 }
230
231 QPainterPath trySimplifyPath(const QPainterPath &path, qreal lengthThreshold)
232 {
233 QPainterPath newPath;
234 QPointF startPoint;
235 qreal distance = 0;
236
237 int count = path.elementCount();
238 for (int i = 0; i < count; i++) {
239 QPainterPath::Element e = path.elementAt(i);
240 QPointF endPoint = QPointF(e.x, e.y);
241
242 switch (e.type) {
243 case QPainterPath::MoveToElement:
244 newPath.moveTo(endPoint);
245 break;
246 case QPainterPath::LineToElement:
247 if (!tryMergePoints(newPath, startPoint, endPoint,
248 distance, lengthThreshold, i == count - 1)) {
249
250 newPath.lineTo(endPoint);
251 }
252 break;
253 case QPainterPath::CurveToElement: {
254 Q_ASSERT(i + 2 < count);
255
256 if (!tryMergePoints(newPath, startPoint, endPoint,
257 distance, lengthThreshold, i == count - 1)) {
258
259 e = path.elementAt(i + 1);
260 Q_ASSERT(e.type == QPainterPath::CurveToDataElement);
261 QPointF ctrl1 = QPointF(e.x, e.y);
262 e = path.elementAt(i + 2);
263 Q_ASSERT(e.type == QPainterPath::CurveToDataElement);
264 QPointF ctrl2 = QPointF(e.x, e.y);
265 newPath.cubicTo(ctrl1, ctrl2, endPoint);
266 }
267
268 i += 2;
269 }
270 default:
271 ;
272 }
273 startPoint = endPoint;
274 }
275
276 return newPath;
277 }
278
279 QList<QPainterPath> splitDisjointPaths(const QPainterPath &path)
280 {
281 QList<QPainterPath> resultList;
282 QList<QPolygonF> inputPolygons = path.toSubpathPolygons();
283
284 Q_FOREACH (const QPolygonF &poly, inputPolygons) {
285 QPainterPath testPath;
286 testPath.addPolygon(poly);
287
288 if (resultList.isEmpty()) {
289 resultList.append(testPath);
290 continue;
291 }
292
293 QPainterPath mergedPath = testPath;
294
295 for (auto it = resultList.begin(); it != resultList.end(); /*noop*/) {
296 if (it->intersects(testPath)) {
297 mergedPath.addPath(*it);
298 it = resultList.erase(it);
299 } else {
300 ++it;
301 }
302 }
303
304 resultList.append(mergedPath);
305 }
306
307 return resultList;
308 }
309
310 quint8 mergeOpacityU8(quint8 opacity, quint8 parentOpacity)
311 {
312 if (parentOpacity != OPACITY_OPAQUE_U8) {
313 opacity = (int(opacity) * parentOpacity) / OPACITY_OPAQUE_U8;
314 }
315 return opacity;
316 }
317
318 qreal mergeOpacityF(qreal opacity, qreal parentOpacity)
319 {
320 if (!qFuzzyCompare(parentOpacity, OPACITY_OPAQUE_F)) {
321 opacity *= parentOpacity;
322 }
323 return opacity;
324 }
325
326 QBitArray mergeChannelFlags(const QBitArray &childFlags, const QBitArray &parentFlags)
327 {
328 QBitArray flags = childFlags;
329
330 if (!flags.isEmpty() &&
331 !parentFlags.isEmpty() &&
332 flags.size() == parentFlags.size()) {
333
334 flags &= parentFlags;
335
336 } else if (!parentFlags.isEmpty()) {
337 flags = parentFlags;
338 }
339
340 return flags;
341 }
342
343 bool compareChannelFlags(QBitArray f1, QBitArray f2)
344 {
345 if (f1.isNull() && f2.isNull()) return true;
346
347 if (f1.isNull()) {
348 f1.fill(true, f2.size());
349 }
350
351 if (f2.isNull()) {
352 f2.fill(true, f1.size());
353 }
354
355 return f1 == f2;
356 }
357
358 QString KRITAIMAGE_EXPORT toLocalizedOnOff(bool value) {
359 return value ? i18n("on") : i18n("off");
360 }
361
363 {
364 KisNodeSP newNode = node->nextSibling();
365
366 if (!newNode) {
367 newNode = node->prevSibling();
368 }
369
370 if (!newNode) {
371 newNode = node->parent();
372 }
373
374 return newNode;
375 }
376
377 void renderExactRect(QPainter *p, const QRect &rc)
378 {
379 p->drawRect(rc.adjusted(0,0,-1,-1));
380 }
381
382 void renderExactRect(QPainter *p, const QRect &rc, const QPen &pen)
383 {
384 QPen oldPen = p->pen();
385 p->setPen(pen);
386 renderExactRect(p, rc);
387 p->setPen(oldPen);
388 }
389
390 QImage convertQImageToGrayA(const QImage &image)
391 {
392 QImage dstImage(image.size(), QImage::Format_ARGB32);
393
394 // TODO: if someone feel bored, a more optimized version of this would be welcome
395 const QSize size = image.size();
396 for(int y = 0; y < size.height(); ++y) {
397 for(int x = 0; x < size.width(); ++x) {
398 const QRgb pixel = image.pixel(x,y);
399 const int gray = qGray(pixel);
400 dstImage.setPixel(x, y, qRgba(gray, gray, gray, qAlpha(pixel)));
401 }
402 }
403
404 return dstImage;
405 }
406
407 void applyToAlpha8Device(KisPaintDeviceSP dev, const QRect &rc, std::function<void(quint8)> func) {
408 KisSequentialConstIterator dstIt(dev, rc);
409 while (dstIt.nextPixel()) {
410 const quint8 *dstPtr = dstIt.rawDataConst();
411 func(*dstPtr);
412 }
413 }
414
415 void filterAlpha8Device(KisPaintDeviceSP dev, const QRect &rc, std::function<quint8(quint8)> func) {
416 KisSequentialIterator dstIt(dev, rc);
417 while (dstIt.nextPixel()) {
418 quint8 *dstPtr = dstIt.rawData();
419 *dstPtr = func(*dstPtr);
420 }
421 }
422
423 qreal estimatePortionOfTransparentPixels(KisPaintDeviceSP dev, const QRect &rect, qreal samplePortion) {
424 const KoColorSpace *cs = dev->colorSpace();
425
426 const qreal linearPortion = std::sqrt(samplePortion);
427 const qreal ratio = qreal(rect.width()) / rect.height();
428 const int xStep = qMax(1, qRound(1.0 / linearPortion * ratio));
429 const int yStep = qMax(1, qRound(1.0 / linearPortion / ratio));
430
431 int numTransparentPixels = 0;
432 int numPixels = 0;
433
435 for (int y = rect.y(); y <= rect.bottom(); y += yStep) {
436 for (int x = rect.x(); x <= rect.right(); x += xStep) {
437 it->moveTo(x, y);
438 const quint8 alpha = cs->opacityU8(it->rawDataConst());
439
440 if (alpha != OPACITY_OPAQUE_U8) {
441 numTransparentPixels++;
442 }
443
444 numPixels++;
445 }
446 }
447
448 if (numPixels == 0) {
449 return 0; // avoid dividing by 0
450 }
451 return qreal(numTransparentPixels) / numPixels;
452 }
453
454 void mirrorDab(Qt::Orientation dir, const QPoint &center, KisRenderedDab *dab, bool skipMirrorPixels)
455 {
456 const QRect rc = dab->realBounds();
457
458 if (dir == Qt::Horizontal) {
459 const int mirrorX = -((rc.x() + rc.width()) - center.x()) + center.x();
460
461 if (!skipMirrorPixels) {
462 dab->device->mirror(true, false);
463 }
464 dab->offset.rx() = mirrorX;
465 } else /* if (dir == Qt::Vertical) */ {
466 const int mirrorY = -((rc.y() + rc.height()) - center.y()) + center.y();
467
468 if (!skipMirrorPixels) {
469 dab->device->mirror(false, true);
470 }
471 dab->offset.ry() = mirrorY;
472 }
473 }
474
475 void mirrorDab(Qt::Orientation dir, const QPointF &center, KisRenderedDab *dab, bool skipMirrorPixels)
476 {
477 const QRect rc = dab->realBounds();
478
479 if (dir == Qt::Horizontal) {
480 const int mirrorX = -((rc.x() + rc.width()) - center.x()) + center.x();
481
482 if (!skipMirrorPixels) {
483 dab->device->mirror(true, false);
484 }
485 dab->offset.rx() = mirrorX;
486 } else /* if (dir == Qt::Vertical) */ {
487 const int mirrorY = -((rc.y() + rc.height()) - center.y()) + center.y();
488
489 if (!skipMirrorPixels) {
490 dab->device->mirror(false, true);
491 }
492 dab->offset.ry() = mirrorY;
493 }
494 }
495
496 void mirrorRect(Qt::Orientation dir, const QPoint &center, QRect *rc)
497 {
498 if (dir == Qt::Horizontal) {
499 const int mirrorX = -((rc->x() + rc->width()) - center.x()) + center.x();
500 rc->moveLeft(mirrorX);
501 } else /* if (dir == Qt::Vertical) */ {
502 const int mirrorY = -((rc->y() + rc->height()) - center.y()) + center.y();
503 rc->moveTop(mirrorY);
504 }
505 }
506
507 void mirrorRect(Qt::Orientation dir, const QPointF &center, QRect *rc)
508 {
509 if (dir == Qt::Horizontal) {
510 const int mirrorX = -((rc->x() + rc->width()) - center.x()) + center.x();
511 rc->moveLeft(mirrorX);
512 } else /* if (dir == Qt::Vertical) */ {
513 const int mirrorY = -((rc->y() + rc->height()) - center.y()) + center.y();
514 rc->moveTop(mirrorY);
515 }
516 }
517
518 void mirrorPoint(Qt::Orientation dir, const QPoint &center, QPointF *pt)
519 {
520 if (dir == Qt::Horizontal) {
521 pt->rx() = -(pt->x() - qreal(center.x())) + center.x();
522 } else /* if (dir == Qt::Vertical) */ {
523 pt->ry() = -(pt->y() - qreal(center.y())) + center.y();
524 }
525 }
526
527 void mirrorPoint(Qt::Orientation dir, const QPointF &center, QPointF *pt)
528 {
529 if (dir == Qt::Horizontal) {
530 pt->rx() = -(pt->x() - qreal(center.x())) + center.x();
531 } else /* if (dir == Qt::Vertical) */ {
532 pt->ry() = -(pt->y() - qreal(center.y())) + center.y();
533 }
534 }
535
537 {
538 return QTransform::fromScale(image->xRes(), image->yRes());
539 }
540
541 QPainterPath tryCloseTornSubpathsAfterIntersection(QPainterPath path)
542 {
543 path.setFillRule(Qt::WindingFill);
544 QList<QPolygonF> polys = path.toSubpathPolygons();
545
546 path = QPainterPath();
547 path.setFillRule(Qt::WindingFill);
548 Q_FOREACH (QPolygonF poly, polys) {
549 ENTER_FUNCTION() << ppVar(poly.isClosed());
550 if (!poly.isClosed()) {
551 poly.append(poly.first());
552 }
553 path.addPolygon(poly);
554 }
555 return path;
556 }
557
558 void thresholdOpacity(KisPaintDeviceSP device, const QRect &rect, ThresholdMode mode)
559 {
560 const KoColorSpace *cs = device->colorSpace();
561
562 if (mode == ThresholdCeil) {
563 KisSequentialIterator it(device, rect);
564 while (it.nextPixel()) {
565 if (cs->opacityU8(it.rawDataConst()) > 0) {
566 cs->setOpacity(it.rawData(), quint8(255), 1);
567 }
568 }
569 } else if (mode == ThresholdFloor) {
570 KisSequentialIterator it(device, rect);
571 while (it.nextPixel()) {
572 if (cs->opacityU8(it.rawDataConst()) < 255) {
573 cs->setOpacity(it.rawData(), quint8(0), 1);
574 }
575 }
576 } else if (mode == ThresholdMaxOut) {
577 KisSequentialIterator it(device, rect);
578 int numConseqPixels = it.nConseqPixels();
579 while (it.nextPixels(numConseqPixels)) {
580 numConseqPixels = it.nConseqPixels();
581 cs->setOpacity(it.rawData(), quint8(255), numConseqPixels);
582 }
583 }
584 }
585
587 {
588 if (mode == ThresholdCeil) {
589 filterAlpha8Device(device, rect,
590 [] (quint8 value) {
591 return value > 0 ? 255 : value;
592 });
593 } else if (mode == ThresholdFloor) {
594 filterAlpha8Device(device, rect,
595 [] (quint8 value) {
596 return value < 255 ? 0 : value;
597 });
598 } else if (mode == ThresholdMaxOut) {
599 device->fill(rect, KoColor(Qt::white, device->colorSpace()));
600 }
601 }
602
603 QVector<QPoint> rasterizeHLine(const QPoint &startPoint, const QPoint &endPoint)
604 {
605 QVector<QPoint> points;
606 rasterizeHLine(startPoint, endPoint, [&points](const QPoint &point) { points.append(point); });
607 return points;
608 }
609
610 QVector<QPoint> rasterizeVLine(const QPoint &startPoint, const QPoint &endPoint)
611 {
612 QVector<QPoint> points;
613 rasterizeVLine(startPoint, endPoint, [&points](const QPoint &point) { points.append(point); });
614 return points;
615 }
616
617 QVector<QPoint> rasterizeLineDDA(const QPoint &startPoint, const QPoint &endPoint)
618 {
619 QVector<QPoint> points;
620 rasterizeLineDDA(startPoint, endPoint, [&points](const QPoint &point) { points.append(point); });
621 return points;
622 }
623
625 {
626 QVector<QPoint> points;
627 rasterizePolylineDDA(polylinePoints, [&points](const QPoint &point) { points.append(point); });
628 return points;
629 }
630
632 {
633 QVector<QPoint> points;
634 rasterizePolygonDDA(polygonPoints, [&points](const QPoint &point) { points.append(point); });
635 return points;
636 }
637
638}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
float value(const T *src, size_t ch)
const Params2D p
const qreal OPACITY_OPAQUE_F
const quint8 OPACITY_OPAQUE_U8
qreal distance(const QPointF &p1, const QPointF &p2)
virtual const quint8 * rawDataConst() const =0
void mirror(bool horizontal, bool vertical)
int updatePatchWidth() const
int updatePatchHeight() const
double xRes() const
double yRes() const
KisRandomConstAccessorSP createRandomConstAccessorNG() const
void fill(const QRect &rc, const KoColor &color)
const KoColorSpace * colorSpace() const
virtual void moveTo(qint32 x, qint32 y)=0
QVector< QRect > rects() const
ALWAYS_INLINE quint8 * rawData()
ALWAYS_INLINE const quint8 * rawDataConst() const
virtual void setOpacity(quint8 *pixels, quint8 alpha, qint32 nPixels) const =0
virtual quint8 opacityU8(const quint8 *pixel) const =0
static bool qFuzzyCompare(half p1, half p2)
unsigned int QRgb
#define bounds(x, a, b)
#define ENTER_FUNCTION()
Definition kis_debug.h:178
#define ppVar(var)
Definition kis_debug.h:155
qreal KRITAIMAGE_EXPORT maxDimensionPortion(const QRectF &bounds, qreal portion, qreal minValue)
QVector< QRect > splitRectIntoPatches(const QRect &rc, const QSize &patchSize)
quint8 mergeOpacityU8(quint8 opacity, quint8 parentOpacity)
void filterAlpha8Device(KisPaintDeviceSP dev, const QRect &rc, std::function< quint8(quint8)> func)
QPainterPath trySimplifyPath(const QPainterPath &path, qreal lengthThreshold)
bool compareChannelFlags(QBitArray f1, QBitArray f2)
QString KRITAIMAGE_EXPORT toLocalizedOnOff(bool value)
void thresholdOpacity(KisPaintDeviceSP device, const QRect &rect, ThresholdMode mode)
QVector< QPoint > rasterizeLineDDA(const QPoint &startPoint, const QPoint &endPoint)
QString KRITAIMAGE_EXPORT prettyFormatReal(qreal value)
KisRegion splitPath(const QPainterPath &path)
QVector< QPoint > rasterizePolygonDDA(const QVector< QPoint > &polygonPoints)
QTransform pathShapeBooleanSpaceWorkaround(KisImageSP image)
KisNodeSP nearestNodeAfterRemoval(KisNodeSP node)
qreal mergeOpacityF(qreal opacity, qreal parentOpacity)
QImage convertQImageToGrayA(const QImage &image)
QPainterPath tryCloseTornSubpathsAfterIntersection(QPainterPath path)
QVector< QRect > splitRegionIntoPatches(const KisRegion &region, const QSize &patchSize)
qreal estimatePortionOfTransparentPixels(KisPaintDeviceSP dev, const QRect &rect, qreal samplePortion)
void mirrorDab(Qt::Orientation dir, const QPoint &center, KisRenderedDab *dab, bool skipMirrorPixels)
bool checkInTriangle(const QRectF &rect, const QPolygonF &triangle)
QList< QPainterPath > splitDisjointPaths(const QPainterPath &path)
void applyToAlpha8Device(KisPaintDeviceSP dev, const QRect &rc, std::function< void(quint8)> func)
QBitArray mergeChannelFlags(const QBitArray &childFlags, const QBitArray &parentFlags)
QVector< QPoint > rasterizeVLine(const QPoint &startPoint, const QPoint &endPoint)
KisRegion splitTriangles(const QPointF &center, const QVector< QPointF > &points)
QVector< QRect > splitRectIntoPatchesTight(const QRect &rc, const QSize &patchSize)
void thresholdOpacityAlpha8(KisPaintDeviceSP device, const QRect &rect, ThresholdMode mode)
bool tryMergePoints(QPainterPath &path, const QPointF &startPoint, const QPointF &endPoint, qreal &distance, qreal distanceThreshold, bool lastSegment)
void mirrorPoint(Qt::Orientation dir, const QPoint &center, QPointF *pt)
QSize optimalPatchSize()
void mirrorRect(Qt::Orientation dir, const QPoint &center, QRect *rc)
void renderExactRect(QPainter *p, const QRect &rc)
QVector< QPoint > rasterizeHLine(const QPoint &startPoint, const QPoint &endPoint)
QVector< QPoint > rasterizePolylineDDA(const QVector< QPoint > &polylinePoints)
KisNodeSP prevSibling() const
Definition kis_node.cpp:402
KisNodeWSP parent
Definition kis_node.cpp:86
KisNodeSP nextSibling() const
Definition kis_node.cpp:408
KisFixedPaintDeviceSP device
QRect realBounds() const