File indexing completed on 2024-06-16 04:17:59

0001 /*
0002  *  SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #include "kis_liquify_paint_helper.h"
0007 
0008 #include <QElapsedTimer>
0009 #include <QPainterPath>
0010 
0011 #include "kis_algebra_2d.h"
0012 #include "KoPointerEvent.h"
0013 #include <brushengine/kis_paint_information.h>
0014 #include "kis_painting_information_builder.h"
0015 #include "kis_liquify_transform_worker.h"
0016 #include <brushengine/kis_paintop_utils.h>
0017 #include "kis_coordinates_converter.h"
0018 #include "kis_liquify_paintop.h"
0019 #include "kis_liquify_properties.h"
0020 
0021 struct KisLiquifyPaintHelper::Private
0022 {
0023     Private(const KisCoordinatesConverter *_converter)
0024         : converter(_converter),
0025           infoBuilder(new KisConverterPaintingInformationBuilder(converter)),
0026           hasPaintedAtLeastOnce(false)
0027     {
0028     }
0029 
0030     KisPaintInformation previousPaintInfo;
0031 
0032     QScopedPointer<KisLiquifyPaintop> paintOp;
0033     KisDistanceInformation currentDistance;
0034     const KisCoordinatesConverter *converter;
0035     QScopedPointer<KisPaintingInformationBuilder> infoBuilder;
0036 
0037     QElapsedTimer strokeTime;
0038 
0039     bool hasPaintedAtLeastOnce;
0040 
0041     KisDistanceInformation previousDistanceInfo;
0042     KisPaintOpUtils::PositionHistory lastOutlinePos;
0043     void updatePreviousPaintInfo(const KisPaintInformation &info);
0044 };
0045 
0046 
0047 KisLiquifyPaintHelper::KisLiquifyPaintHelper(const KisCoordinatesConverter *converter)
0048     : m_d(new Private(converter))
0049 {
0050 }
0051 
0052 KisLiquifyPaintHelper::~KisLiquifyPaintHelper()
0053 {
0054 }
0055 
0056 void KisLiquifyPaintHelper::Private::updatePreviousPaintInfo(const KisPaintInformation &info)
0057 {
0058     QPointF prevPos = lastOutlinePos.pushThroughHistory(info.pos(), converter->effectiveZoom());
0059     qreal angle = KisAlgebra2D::directionBetweenPoints(prevPos, info.pos(), 0);
0060 
0061     previousDistanceInfo =
0062         KisDistanceInformation(prevPos, angle);
0063 
0064     previousPaintInfo = info;
0065 }
0066 
0067 QPainterPath KisLiquifyPaintHelper::brushOutline(const KisLiquifyProperties &props)
0068 {
0069     KisPaintInformation::DistanceInformationRegistrar registrar =
0070         m_d->previousPaintInfo.registerDistanceInformation(&m_d->previousDistanceInfo);
0071 
0072     return KisLiquifyPaintop::brushOutline(props, m_d->previousPaintInfo);
0073 }
0074 
0075 void KisLiquifyPaintHelper::configurePaintOp(const KisLiquifyProperties &props,
0076                                              KisLiquifyTransformWorker *worker)
0077 {
0078     m_d->paintOp.reset(new KisLiquifyPaintop(props, worker));
0079 }
0080 
0081 void KisLiquifyPaintHelper::startPaint(KoPointerEvent *event, const KoCanvasResourceProvider *manager)
0082 {
0083     KIS_ASSERT_RECOVER_RETURN(m_d->paintOp);
0084 
0085     m_d->strokeTime.start();
0086     KisPaintInformation pi =
0087         m_d->infoBuilder->startStroke(event, m_d->strokeTime.elapsed(), manager);
0088 
0089     m_d->updatePreviousPaintInfo(pi);
0090     m_d->hasPaintedAtLeastOnce = false;
0091 }
0092 
0093 void KisLiquifyPaintHelper::continuePaint(KoPointerEvent *event)
0094 {
0095     KIS_ASSERT_RECOVER_RETURN(m_d->paintOp);
0096 
0097     KisPaintInformation pi =
0098         m_d->infoBuilder->continueStroke(event, m_d->strokeTime.elapsed());
0099 
0100     KisPaintOpUtils::paintLine(*m_d->paintOp.data(),
0101                                m_d->previousPaintInfo,
0102                                pi,
0103                                &m_d->currentDistance,
0104                                false, false);
0105 
0106     m_d->updatePreviousPaintInfo(pi);
0107     m_d->hasPaintedAtLeastOnce = true;
0108 }
0109 
0110 bool KisLiquifyPaintHelper::endPaint(KoPointerEvent *event)
0111 {
0112     KIS_ASSERT_RECOVER(m_d->paintOp) { return false; }
0113 
0114     if (!m_d->hasPaintedAtLeastOnce) {
0115         KisPaintInformation pi =
0116             m_d->infoBuilder->continueStroke(event, m_d->strokeTime.elapsed());
0117 
0118         pi.paintAt(*m_d->paintOp.data(), &m_d->previousDistanceInfo);
0119     }
0120 
0121     m_d->paintOp.reset();
0122 
0123     return !m_d->hasPaintedAtLeastOnce;
0124 }
0125 
0126 void KisLiquifyPaintHelper::hoverPaint(KoPointerEvent *event)
0127 {
0128     QPointF imagePoint = m_d->converter->documentToImage(event->pos());
0129     KisPaintInformation pi = m_d->infoBuilder->hover(imagePoint, event, m_d->paintOp);
0130 
0131     m_d->updatePreviousPaintInfo(pi);
0132 }