From kde-commits Fri Dec 31 23:27:34 2010 From: Geoffry Song Date: Fri, 31 Dec 2010 23:27:34 +0000 To: kde-commits Subject: [Calligra] a9be43f: implement perspective value calculation Message-Id: <20101231232734.28C4AA6092 () git ! kde ! org> X-MARC-Message: https://marc.info/?l=kde-commits&m=129383809716693 A krita/ui/kis_abstract_perspective_grid.h [License: UNKNOWN] commit a9be43f3a1d52b80bfa461a9c851c22064d215c7 Author: Geoffry Song Date: Wed Dec 29 21:50:06 2010 -0500 implement perspective value calculation diff --git a/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.cc b/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.cc index 0442ded..95d1106 100644 --- a/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.cc +++ b/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.cc @@ -28,8 +28,8 @@ #include "kis_coordinates_converter.h" #include - #include +#include PerspectiveAssistant::PerspectiveAssistant() : KisPaintingAssistant("perspective", i18n("Perspective assistant")) @@ -104,6 +104,51 @@ void PerspectiveAssistant::endStroke() snapLine = QLineF(); } +bool PerspectiveAssistant::contains(const QPointF& pt) const +{ + QPolygonF poly; + if (!quad(poly)) return false; + return poly.containsPoint(pt, Qt::OddEvenFill); +} + +inline qreal lengthSquared(const QPointF& vector) +{ + return vector.x() * vector.x() + vector.y() * vector.y(); +} + +inline qreal distanceSquared(const QTransform& transform, QPointF pt, QPointF orig) +{ + const qreal epsilon = 1e-5, epsilonSquared = epsilon * epsilon; + qreal xSizeSquared = lengthSquared(transform.map(pt + QPointF(epsilon, 0.0)) - orig) / epsilonSquared; + qreal ySizeSquared = lengthSquared(transform.map(pt + QPointF(0.0, epsilon)) - orig) / epsilonSquared; + xSizeSquared /= lengthSquared(transform.map(QPointF(0.0, pt.y())) - transform.map(QPointF(1.0, pt.y()))); + ySizeSquared /= lengthSquared(transform.map(QPointF(pt.x(), 0.0)) - transform.map(QPointF(pt.x(), 1.0))); + return xSizeSquared + ySizeSquared; +} + +qreal PerspectiveAssistant::distance(const QPointF& pt) const +{ + QPolygonF poly; + if (!quad(poly)) return 1.0; + QTransform transform; + if (!QTransform::squareToQuad(poly, transform)) return 1.0; + bool invertible; + QTransform inverse = transform.inverted(&invertible); + if (!invertible) return 1.0; + if (inverse.m13() * pt.x() + inverse.m23() * pt.y() + inverse.m33() == 0.0) { + // point at infinity + return 0.0; + } + QPointF realPoint = inverse.map(pt); + const qreal corners[4] = { + distanceSquared(transform, QPointF(0.0, 0.0), transform.map(QPointF(0.0, 0.0))), + distanceSquared(transform, QPointF(0.0, 1.0), transform.map(QPointF(0.0, 1.0))), + distanceSquared(transform, QPointF(1.0, 0.0), transform.map(QPointF(1.0, 0.0))), + distanceSquared(transform, QPointF(1.0, 1.0), transform.map(QPointF(1.0, 1.0)))}; + const qreal max = std::max(std::max(corners[0], corners[1]), std::max(corners[2], corners[3])); + return sqrt(distanceSquared(transform, realPoint, pt) / max); +} + // draw a vanishing point marker inline void drawX(QPainter& gc, const QPointF& pt) { diff --git a/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.h b/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.h index 4048f0d..19fea0e 100644 --- a/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.h +++ b/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.h @@ -19,12 +19,13 @@ #ifndef _PERSPECTIVE_ASSISTANT_H_ #define _PERSPECTIVE_ASSISTANT_H_ +#include "kis_abstract_perspective_grid.h" #include "kis_painting_assistant.h" #include #include #include -class PerspectiveAssistant : public KisPaintingAssistant +class PerspectiveAssistant : public KisPaintingAssistant, public KisAbstractPerspectiveGrid { public: PerspectiveAssistant(); @@ -33,6 +34,9 @@ public: void drawAssistant(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter *converter); virtual QPointF buttonPosition() const; virtual int numHandles() const { return 4; } + + virtual bool contains(const QPointF& point) const; + virtual qreal distance(const QPointF& point) const; private: QPointF project(const QPointF& pt, const QPointF& strokeBegin); // creates the convex hull, returns false if it's not a quadrilateral diff --git a/krita/ui/kis_abstract_perspective_grid.h b/krita/ui/kis_abstract_perspective_grid.h new file mode 100644 index 0000000..864b482 --- /dev/null +++ b/krita/ui/kis_abstract_perspective_grid.h @@ -0,0 +1,38 @@ +/* + * This file is part of Krita + * + * Copyright (c) 2010 Geoffry Song + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_ABSTRACT_PERSPECTIVE_GRID_H +#define KIS_ABSTRACT_PERSPECTIVE_GRID_H + +#include + +class KisAbstractPerspectiveGrid +{ +public: + virtual bool contains(const QPointF& pt) const = 0; + /** + * Returns the reciprocal of the distance from the given point + * to the 'observer', in the range [0, 1] where 0 = inifinite + * distance and 1 = closest. + */ + virtual qreal distance(const QPointF& pt) const = 0; +}; + +#endif diff --git a/krita/ui/tool/kis_tool_freehand.cc b/krita/ui/tool/kis_tool_freehand.cc index 702c6dc..2359aea 100644 --- a/krita/ui/tool/kis_tool_freehand.cc +++ b/krita/ui/tool/kis_tool_freehand.cc @@ -48,6 +48,7 @@ // Krita/ui +#include "kis_abstract_perspective_grid.h" #include "kis_config.h" #include #include "canvas/kis_canvas2.h" @@ -141,10 +142,19 @@ void KisToolFreehand::mousePressEvent(KoPointerEvent *e) * FIXME: we need some better way to implement modifiers * for a paintop level */ + QPointF pos = adjustPosition(e->point, e->point); + qreal perspective = 1.0; + foreach (const KisPaintingAssistant* assistant, static_cast(canvas())->view()->paintingAssistantManager()->assistants()) { + const KisAbstractPerspectiveGrid* perspectiveGrid = dynamic_cast(assistant); + if (!perspectiveGrid) continue; + if (!perspectiveGrid->contains(pos)) continue; + perspective = perspectiveGrid->distance(pos); + break; + } bool ignoreEvent = currentPaintOpPreset()->settings()->mousePressEvent(KisPaintInformation(convertToPixelCoord(e->point), pressureToCurve(e->pressure()), e->xTilt(), e->yTilt(), KisVector2D::Zero(), - e->rotation(), e->tangentialPressure(), 1.0, m_strokeTimeMeasure.elapsed()),e->modifiers()); + e->rotation(), e->tangentialPressure(), perspective, m_strokeTimeMeasure.elapsed()),e->modifiers()); if (!ignoreEvent){ e->accept(); return; @@ -168,7 +178,7 @@ void KisToolFreehand::mousePressEvent(KoPointerEvent *e) m_previousPaintInformation = KisPaintInformation(convertToPixelCoord(adjustPosition(e->point, e->point)), pressureToCurve(e->pressure()), e->xTilt(), e->yTilt(), KisVector2D::Zero(), - e->rotation(), e->tangentialPressure(), 1.0, m_strokeTimeMeasure.elapsed()); + e->rotation(), e->tangentialPressure(), perspective, m_strokeTimeMeasure.elapsed()); m_strokeBegin = e->point; e->accept(); @@ -212,13 +222,23 @@ void KisToolFreehand::mouseMoveEvent(KoPointerEvent *e) /** * Actual painting */ - QPointF pos = convertToPixelCoord(adjustPosition(e->point, m_strokeBegin)); + QPointF adjusted = adjustPosition(e->point, m_strokeBegin); + QPointF pos = convertToPixelCoord(adjusted); QPointF dragVec = pos - m_previousPaintInformation.pos(); + qreal perspective = 1.0; + foreach (const KisPaintingAssistant* assistant, static_cast(canvas())->view()->paintingAssistantManager()->assistants()) { + const KisAbstractPerspectiveGrid* perspectiveGrid = dynamic_cast(assistant); + if (!perspectiveGrid) continue; + if (!perspectiveGrid->contains(adjusted)) continue; + perspective = perspectiveGrid->distance(adjusted); + break; + } + KisPaintInformation info = KisPaintInformation(pos, pressureToCurve(e->pressure()), e->xTilt(), e->yTilt(), toKisVector2D(dragVec), - e->rotation(), e->tangentialPressure(), 1.0, + e->rotation(), e->tangentialPressure(), perspective, m_strokeTimeMeasure.elapsed()); if (m_smooth) {