Example #1
0
void KisToolLineHelper::addPoint(KoPointerEvent *event, const QPointF &overridePos)
{
    if (!m_d->enabled) return;

    KisPaintInformation pi =
            m_d->infoBuilder->continueStroke(event, elapsedStrokeTime());

    if (!m_d->useSensors) {
        pi = KisPaintInformation(pi.pos());
    }

    if (!overridePos.isNull()) {
        pi.setPos(overridePos);
    }

    if (m_d->linePoints.size() > 1) {
        const QPointF startPos = m_d->linePoints.first().pos();
        const QPointF endPos = pi.pos();
        const qreal maxDistance = kisDistance(startPos, endPos);
        const QPointF unit = (endPos - startPos) / maxDistance;

        QVector<KisPaintInformation>::iterator it = m_d->linePoints.begin();
        ++it;
        while (it != m_d->linePoints.end()) {
            qreal dist = kisDistance(startPos, it->pos());
            if (dist < maxDistance) {
                QPointF pos = startPos + unit * dist;
                it->setPos(pos);
                ++it;
            } else {
                it = m_d->linePoints.erase(it);
            }
        }
    }

    m_d->linePoints.append(pi);
}
void KisFreeTransformStrategy::continuePrimaryAction(const QPointF &mousePos, bool specialModifierActive)
{
    switch (m_d->function) {
    case MOVE: {
        QPointF diff = mousePos - m_d->clickPos;

        if (specialModifierActive) {

            KisTransformUtils::MatricesPack m(m_d->clickArgs);
            QTransform t = m.S * m.projectedP;
            QPointF originalDiff = t.inverted().map(diff);

            if (qAbs(originalDiff.x()) >= qAbs(originalDiff.y())) {
                originalDiff.setY(0);
            } else {
                originalDiff.setX(0);
            }

            diff = t.map(originalDiff);

        }

        m_d->currentArgs.setTransformedCenter(m_d->clickArgs.transformedCenter() + diff);

        break;
    }
    case ROTATE:
    {
        KisTransformUtils::MatricesPack clickM(m_d->clickArgs);
        QTransform clickT = clickM.finalTransform();

        QPointF rotationCenter = m_d->clickArgs.originalCenter() + m_d->clickArgs.rotationCenterOffset();
        QPointF clickMouseImagePos = clickT.inverted().map(m_d->clickPos) - rotationCenter;
        QPointF mouseImagePos = clickT.inverted().map(mousePos) - rotationCenter;

        qreal a1 = atan2(clickMouseImagePos.y(), clickMouseImagePos.x());
        qreal a2 = atan2(mouseImagePos.y(), mouseImagePos.x());

        double theta = -a1 + a2;

        m_d->currentArgs.setAZ(normalizeAngle(m_d->clickArgs.aZ() + theta));

        KisTransformUtils::MatricesPack m(m_d->currentArgs);
        QTransform t = m.finalTransform();
        QPointF newRotationCenter = t.map(m_d->currentArgs.originalCenter() + m_d->currentArgs.rotationCenterOffset());
        QPointF oldRotationCenter = clickT.map(m_d->clickArgs.originalCenter() + m_d->clickArgs.rotationCenterOffset());

        m_d->currentArgs.setTransformedCenter(m_d->currentArgs.transformedCenter() + oldRotationCenter - newRotationCenter);
    }
    break;
    case PERSPECTIVE:
    {
        QPointF diff = mousePos - m_d->clickPos;
        double thetaX = - diff.y() * M_PI / m_d->transaction.originalHalfHeight() / 2 / fabs(m_d->currentArgs.scaleY());
        m_d->currentArgs.setAX(normalizeAngle(m_d->clickArgs.aX() + thetaX));

        qreal sign = qAbs(m_d->currentArgs.aX() - M_PI) < M_PI / 2 ? -1.0 : 1.0;
        double thetaY = sign * diff.x() * M_PI / m_d->transaction.originalHalfWidth() / 2 / fabs(m_d->currentArgs.scaleX());
        m_d->currentArgs.setAY(normalizeAngle(m_d->clickArgs.aY() + thetaY));

        KisTransformUtils::MatricesPack m(m_d->currentArgs);
        QTransform t = m.finalTransform();
        QPointF newRotationCenter = t.map(m_d->currentArgs.originalCenter() + m_d->currentArgs.rotationCenterOffset());

        KisTransformUtils::MatricesPack clickM(m_d->clickArgs);
        QTransform clickT = clickM.finalTransform();
        QPointF oldRotationCenter = clickT.map(m_d->clickArgs.originalCenter() + m_d->clickArgs.rotationCenterOffset());

        m_d->currentArgs.setTransformedCenter(m_d->currentArgs.transformedCenter() + oldRotationCenter - newRotationCenter);
    }
    break;
    case TOPSCALE:
    case BOTTOMSCALE: {
        QPointF staticPoint;
        QPointF movingPoint;
        qreal extraSign;

        if (m_d->function == TOPSCALE) {

            staticPoint = m_d->transaction.originalMiddleBottom();
            movingPoint = m_d->transaction.originalMiddleTop();
            extraSign = -1.0;
        } else {
            staticPoint = m_d->transaction.originalMiddleTop();
            movingPoint = m_d->transaction.originalMiddleBottom();
            extraSign = 1.0;
        }

        QPointF mouseImagePos = m_d->transform.inverted().map(mousePos);

        qreal sign = mouseImagePos.y() <= staticPoint.y() ? -extraSign : extraSign;
        m_d->currentArgs.setScaleY(sign * m_d->currentArgs.scaleY());

        QPointF staticPointInView = m_d->transform.map(staticPoint);

        qreal dist = kisDistance(staticPointInView, mousePos);

        GSL::ScaleResult1D result =
            GSL::calculateScaleY(m_d->currentArgs,
                                 staticPoint,
                                 staticPointInView,
                                 movingPoint,
                                 dist);

        if (specialModifierActive ||  m_d->currentArgs.keepAspectRatio()) {
            qreal aspectRatio = m_d->clickArgs.scaleX() / m_d->clickArgs.scaleY();
            m_d->currentArgs.setScaleX(aspectRatio * result.scale);
        }

        m_d->currentArgs.setScaleY(result.scale);
        m_d->currentArgs.setTransformedCenter(result.transformedCenter);
        break;
    }

    case LEFTSCALE:
    case RIGHTSCALE: {
        QPointF staticPoint;
        QPointF movingPoint;
        qreal extraSign;

        if (m_d->function == LEFTSCALE) {

            staticPoint = m_d->transaction.originalMiddleRight();
            movingPoint = m_d->transaction.originalMiddleLeft();
            extraSign = -1.0;
        } else {
            staticPoint = m_d->transaction.originalMiddleLeft();
            movingPoint = m_d->transaction.originalMiddleRight();
            extraSign = 1.0;
        }

        QPointF mouseImagePos = m_d->transform.inverted().map(mousePos);

        qreal sign = mouseImagePos.x() <= staticPoint.x() ? -extraSign : extraSign;
        m_d->currentArgs.setScaleX(sign * m_d->currentArgs.scaleX());

        QPointF staticPointInView = m_d->transform.map(staticPoint);

        qreal dist = kisDistance(staticPointInView, mousePos);

        GSL::ScaleResult1D result =
            GSL::calculateScaleX(m_d->currentArgs,
                                 staticPoint,
                                 staticPointInView,
                                 movingPoint,
                                 dist);

        if (specialModifierActive  ||  m_d->currentArgs.keepAspectRatio()) {
            qreal aspectRatio = m_d->clickArgs.scaleY() / m_d->clickArgs.scaleX();
            m_d->currentArgs.setScaleY(aspectRatio * result.scale);
        }

        m_d->currentArgs.setScaleX(result.scale);
        m_d->currentArgs.setTransformedCenter(result.transformedCenter);
        break;
    }
    case TOPRIGHTSCALE:
    case BOTTOMRIGHTSCALE:
    case TOPLEFTSCALE:
    case BOTTOMLEFTSCALE: {
        QPointF staticPoint;
        QPointF movingPoint;

        if (m_d->function == TOPRIGHTSCALE) {
            staticPoint = m_d->transaction.originalBottomLeft();
            movingPoint = m_d->transaction.originalTopRight();
        } else if (m_d->function == BOTTOMRIGHTSCALE) {
            staticPoint = m_d->transaction.originalTopLeft();
            movingPoint = m_d->transaction.originalBottomRight();
        } else if (m_d->function == TOPLEFTSCALE) {
            staticPoint = m_d->transaction.originalBottomRight();
            movingPoint = m_d->transaction.originalTopLeft();
        } else {
            staticPoint = m_d->transaction.originalTopRight();
            movingPoint = m_d->transaction.originalBottomLeft();
        }

        QPointF staticPointInView = m_d->transform.map(staticPoint);
        QPointF movingPointInView = mousePos;

        if (specialModifierActive  ||  m_d->currentArgs.keepAspectRatio()) {
            KisTransformUtils::MatricesPack m(m_d->clickArgs);
            QTransform t = m.finalTransform();

            QPointF refDiff = t.map(movingPoint) - staticPointInView;
            QPointF realDiff = mousePos - staticPointInView;
            realDiff = kisProjectOnVector(refDiff, realDiff);

            movingPointInView = staticPointInView + realDiff;
        }

        GSL::ScaleResult2D result =
            GSL::calculateScale2D(m_d->currentArgs,
                                  staticPoint,
                                  staticPointInView,
                                  movingPoint,
                                  movingPointInView);

        m_d->currentArgs.setScaleX(result.scaleX);
        m_d->currentArgs.setScaleY(result.scaleY);
        m_d->currentArgs.setTransformedCenter(result.transformedCenter);
        break;
    }
    case MOVECENTER: {
        QPointF pt = m_d->transform.inverted().map(mousePos);
        pt = KisTransformUtils::clipInRect(pt, m_d->transaction.originalRect());

        QPointF newRotationCenterOffset = pt - m_d->currentArgs.originalCenter();

        if (specialModifierActive) {
            if (qAbs(newRotationCenterOffset.x()) > qAbs(newRotationCenterOffset.y())) {
                newRotationCenterOffset.ry() = 0;
            } else {
                newRotationCenterOffset.rx() = 0;
            }
        }

        m_d->currentArgs.setRotationCenterOffset(newRotationCenterOffset);
        emit requestResetRotationCenterButtons();
    }
        break;
    case TOPSHEAR:
    case BOTTOMSHEAR: {
        KisTransformUtils::MatricesPack m(m_d->clickArgs);

        QTransform backwardT = (m.S * m.projectedP).inverted();
        QPointF diff = backwardT.map(mousePos - m_d->clickPos);

        qreal sign = m_d->function == BOTTOMSHEAR ? 1.0 : -1.0;

        // get the dx pixels corresponding to the current shearX factor
        qreal dx = sign * m_d->clickArgs.shearX() * m_d->clickArgs.scaleY() * m_d->transaction.originalHalfHeight(); // get the dx pixels corresponding to the current shearX factor
        dx += diff.x();

        // calculate the new shearX factor
        m_d->currentArgs.setShearX(sign * dx / m_d->currentArgs.scaleY() / m_d->transaction.originalHalfHeight()); // calculate the new shearX factor
        break;
    }

    case LEFTSHEAR:
    case RIGHTSHEAR: {
        KisTransformUtils::MatricesPack m(m_d->clickArgs);

        QTransform backwardT = (m.S * m.projectedP).inverted();
        QPointF diff = backwardT.map(mousePos - m_d->clickPos);

        qreal sign = m_d->function == RIGHTSHEAR ? 1.0 : -1.0;

        // get the dx pixels corresponding to the current shearX factor
        qreal dy = sign *  m_d->clickArgs.shearY() * m_d->clickArgs.scaleX() * m_d->transaction.originalHalfWidth();
        dy += diff.y();

        // calculate the new shearY factor
        m_d->currentArgs.setShearY(sign * dy / m_d->clickArgs.scaleX() / m_d->transaction.originalHalfWidth());
        break;
    }
    }

    m_d->recalculateTransformations();
}