13#include <QPainterPath>
92 inline QPointF
imageToThumb(
const QPointF &pt,
bool useFlakeOptimization);
103 m_d(new
Private(this, converter, currentArgs, transaction))
105 connect(&
m_d->recalculateSignalCompressor, SIGNAL(timeout()),
106 SLOT(recalculateTransformations()));
115 Q_UNUSED(shiftModifierActive);
116 Q_UNUSED(altModifierActive);
120 bool cursorOverPoint =
false;
121 m_d->pointIndexUnderCursor = -1;
127 for (
int i = 0; i < points.size(); ++i) {
131 cursorOverPoint =
true;
132 m_d->pointIndexUnderCursor = i;
136 if (cursorOverPoint) {
137 m_d->mode = perspectiveModifierActive &&
138 !
m_d->currentArgs.isEditingTransformPoints() ?
141 }
else if (!
m_d->currentArgs.isEditingTransformPoints()) {
142 QPolygonF polygon(
m_d->currentArgs.transfPoints());
143 bool insidePolygon = polygon.boundingRect().contains(mousePos);
182 bool drawTransfPoints)
185 m_d->drawOrigPoints = drawOrigPoints;
186 m_d->drawTransfPoints = drawTransfPoints;
191 m_d->closeOnStartPointClick =
value;
196 m_d->clipOriginalPointsPosition =
value;
200 m_d->transformType = type;
206 bool isEditingPoints)
208 Q_UNUSED(isEditingPoints);
217 const int numPoints = origPoints.size();
219 for (
int i = 0; i < numPoints; ++i) {
220 gc.setPen(outlinePen);
221 gc.drawLine(transfPoints[i], origPoints[i]);
223 gc.drawLine(transfPoints[i], origPoints[i]);
233 gc.setOpacity(
m_d->transaction.basePreviewOpacity());
234 gc.setTransform(
m_d->paintingTransform,
true);
235 gc.drawImage(
m_d->paintingOffset,
m_d->transformedImage);
241 gc.setTransform(
m_d->handlesTransform,
true);
243 if (
m_d->drawConnectionLines) {
247 m_d->currentArgs.origPoints(),
248 m_d->currentArgs.transfPoints(),
249 m_d->currentArgs.isEditingTransformPoints());
254 mainPen.setCosmetic(
true);
256 QPen outlinePen(
palette.white);
257 outlinePen.setCosmetic(
true);
262 const int numPoints =
m_d->currentArgs.origPoints().size();
268 qreal dstIn = 8 / handlesExtraScale;
269 qreal dstOut = 10 / handlesExtraScale;
270 qreal srcIn = 6 / handlesExtraScale;
271 qreal srcOut = 6 / handlesExtraScale;
273 QRectF handleRect1(-0.5 * dstIn, -0.5 * dstIn, dstIn, dstIn);
274 QRectF handleRect2(-0.5 * dstOut, -0.5 * dstOut, dstOut, dstOut);
276 if (
m_d->drawTransfPoints) {
279 for (
int i = 0; i < numPoints; ++i) {
280 gc.setPen(outlinePen);
281 gc.drawEllipse(handleRect2.translated(
m_d->currentArgs.transfPoints()[i]));
283 gc.drawEllipse(handleRect1.translated(
m_d->currentArgs.transfPoints()[i]));
289 QBrush selectionBrush = selectedPoints.size() > 1 ? Qt::red : Qt::black;
291 QBrush oldBrush = gc.brush();
292 gc.setBrush(selectionBrush);
293 Q_FOREACH (
const QPointF *pt, selectedPoints) {
294 gc.drawEllipse(handleRect1.translated(*pt));
296 gc.setBrush(oldBrush);
300 if (
m_d->drawOrigPoints) {
302 inLine.moveTo(-0.5 * srcIn, 0);
303 inLine.lineTo( 0.5 * srcIn, 0);
304 inLine.moveTo( 0, -0.5 * srcIn);
305 inLine.lineTo( 0, 0.5 * srcIn);
307 QPainterPath outLine;
308 outLine.moveTo(-0.5 * srcOut, -0.5 * srcOut);
309 outLine.lineTo( 0.5 * srcOut, -0.5 * srcOut);
310 outLine.lineTo( 0.5 * srcOut, 0.5 * srcOut);
311 outLine.lineTo(-0.5 * srcOut, 0.5 * srcOut);
312 outLine.lineTo(-0.5 * srcOut, -0.5 * srcOut);
316 for (
int i = 0; i < numPoints; ++i) {
317 gc.setPen(outlinePen);
318 gc.drawPath(outLine.translated(
m_d->currentArgs.origPoints()[i]));
320 gc.drawPath(inLine.translated(
m_d->currentArgs.origPoints()[i]));
327 if (
m_d->currentArgs.warpCalculation() == KisWarpTransformWorker::WarpCalculation::GRID &&
332 const int numPoints =
m_d->currentArgs.origPoints().size();
335 int rowsInWarp = sqrt(
m_d->currentArgs.origPoints().size());
342 for (
int i = 0; i < numPoints; i++) {
343 if (i != 0 && i % rowsInWarp == rowsInWarp -1) {
351 for (
int i = 0; i < numPoints; i++) {
353 if ( (numPoints - i - 1) < rowsInWarp ) {
356 handlePainter.
drawConnectionLine(
m_d->currentArgs.transfPoints()[i],
m_d->currentArgs.transfPoints()[i+rowsInWarp] );
367 if (
m_d->lastNumPoints !=
m_d->currentArgs.transfPoints().size()) {
368 m_d->pointsInAction.clear();
371 m_d->recalculateTransformations();
376 const bool isEditingPoints =
m_d->currentArgs.isEditingTransformPoints();
387 }
else if (isEditingPoints) {
388 QPointF newPos =
m_d->clipOriginalPointsPosition ?
392 m_d->currentArgs.refOriginalPoints().append(newPos);
393 m_d->currentArgs.refTransformedPoints().append(newPos);
396 m_d->pointIndexUnderCursor =
m_d->currentArgs.origPoints().size() - 1;
398 m_d->recalculateSignalCompressor.start();
404 m_d->pointPosOnClick =
405 m_d->currentArgs.transfPoints()[
m_d->pointIndexUnderCursor];
406 m_d->pointWasDragged =
false;
408 m_d->pointsInAction.clear();
409 m_d->pointsInAction <<
m_d->pointIndexUnderCursor;
410 m_d->lastNumPoints =
m_d->currentArgs.transfPoints().size();
413 std::find(
m_d->pointsInAction.begin(),
414 m_d->pointsInAction.end(),
415 m_d->pointIndexUnderCursor);
417 if (it !=
m_d->pointsInAction.end()) {
418 m_d->pointsInAction.erase(it);
420 m_d->pointsInAction <<
m_d->pointIndexUnderCursor;
423 m_d->lastNumPoints =
m_d->currentArgs.transfPoints().size();
426 m_d->lastMousePos = pt;
438 selectedPoints << &points[index];
444 for (; it != end; ++it) {
445 selectedPoints << &(*it);
450 *center = boundingRect.center();
451 return selectedPoints;
456 Q_UNUSED(shiftModifierActive);
457 Q_UNUSED(altModifierActive);
464 m_d->pointIndexUnderCursor >= 0 &&
465 m_d->pointsInAction.size() == 1) ||
467 m_d->pointIndexUnderCursor >= 0));
470 if (
m_d->currentArgs.isEditingTransformPoints()) {
471 QPointF newPos =
m_d->clipOriginalPointsPosition ?
474 m_d->currentArgs.origPoint(
m_d->pointIndexUnderCursor) = newPos;
475 m_d->currentArgs.transfPoint(
m_d->pointIndexUnderCursor) = newPos;
477 m_d->currentArgs.transfPoint(
m_d->pointIndexUnderCursor) = pt;
484 m_d->currentArgs.transfPoint(
m_d->pointIndexUnderCursor),
485 m_d->pointPosOnClick);
487 if (dist > handleRadiusSq) {
488 m_d->pointWasDragged =
true;
494 QPointF diff = pt -
m_d->lastMousePos;
498 for (; it != end; ++it) {
505 QPointF oldDirection =
m_d->lastMousePos - center;
506 QPointF newDirection = pt - center;
510 R.rotateRadians(rotateAngle);
513 QTransform::fromTranslate(-center.x(), -center.y()) *
515 QTransform::fromTranslate(center.x(), center.y());
519 for (; it != end; ++it) {
526 QPolygonF polygon(
m_d->currentArgs.origPoints());
527 QSizeF maxSize = polygon.boundingRect().size();
528 qreal maxDimension = qMax(maxSize.width(), maxSize.height());
530 qreal scale = 1.0 - (pt -
m_d->lastMousePos).y() / maxDimension;
533 QTransform::fromTranslate(-center.x(), -center.y()) *
534 QTransform::fromScale(scale, scale) *
535 QTransform::fromTranslate(center.x(), center.y());
539 for (; it != end; ++it) {
544 m_d->lastMousePos = pt;
545 m_d->recalculateSignalCompressor.start();
551 return currentArgs.isEditingTransformPoints() &&
552 closeOnStartPointClick &&
553 pointIndexUnderCursor == 0 &&
554 currentArgs.origPoints().size() > 2 &&
560 return m_d->shouldCloseTheCage() ||
561 m_d->currentArgs.isEditingTransformPoints();
566 if (
m_d->shouldCloseTheCage()) {
567 m_d->currentArgs.setEditingTransformPoints(
false);
575 return useFlakeOptimization ? converter->imageToDocument(converter->documentToFlake((pt))) : q->thumbToImageTransform().inverted().map(pt);
582 QTransform resultThumbTransform = q->thumbToImageTransform() * scaleTransform;
584 bool useFlakeOptimization = scale < 1.0 &&
590 for (
int i = 0; i < currentArgs.numPoints(); ++i) {
591 thumbOrigPoints[i] = imageToThumb(currentArgs.origPoints()[i], useFlakeOptimization);
592 thumbTransfPoints[i] = imageToThumb(currentArgs.transfPoints()[i], useFlakeOptimization);
595 paintingOffset = transaction.originalTopLeft();
597 if (!q->originalImage().isNull() && !currentArgs.isEditingTransformPoints()) {
598 QPointF origTLInFlake = imageToThumb(transaction.originalTopLeft(), useFlakeOptimization);
600 if (useFlakeOptimization) {
601 transformedImage = q->originalImage().transformed(resultThumbTransform);
602 paintingTransform = QTransform();
604 transformedImage = q->originalImage();
605 paintingTransform = resultThumbTransform;
609 transformedImage = q->calculateTransformedImage(currentArgs,
616 transformedImage = q->originalImage();
617 paintingOffset = imageToThumb(transaction.originalTopLeft(),
false);
618 paintingTransform = resultThumbTransform;
621 handlesTransform = scaleTransform;
622 Q_EMIT q->requestCanvasUpdate();
623 Q_EMIT q->requestImageRecalculation();
627 const QImage &srcImage,
630 const QPointF &srcOffset,
635 origPoints, transfPoints,
638 srcOffset, dstOffset);
641#include "moc_kis_warp_transform_strategy.cpp"
float value(const T *src, size_t ch)
Eigen::Matrix< double, 4, 2 > R
static QCursor crossCursor()
static QCursor rotateCursor()
static QCursor moveCursor()
static QCursor arrowCursor()
static QCursor pointingHandCursor()
static QCursor sizeVerCursor()
The KisHandlePainterHelper class is a special helper for painting handles around objects....
void drawConnectionLine(const QLineF &line)
void setHandleStyle(const KisHandleStyle &style)
static KisHandleStyle & primarySelection(KisHandlePalette palette=KisHandlePalette())
virtual KisHandlePalette handlePaletteForDisplayColorSpace() const =0
handlePaletteForDisplayColorSpace
#define KIS_ASSERT_RECOVER_RETURN(cond)
qreal kisSquareDistance(const QPointF &pt1, const QPointF &pt2)
void accumulateBounds(const Point &pt, Rect *bounds)
qreal angleBetweenVectors(const QPointF &v1, const QPointF &v2)
void initAntsPen(QPen *antsPen, QPen *outlinePen, int antLength, int antSpace, QColor black, QColor white)
rgba palette[MAX_PALETTE]