File indexing completed on 2024-05-26 04:32:04
0001 /* 0002 * SPDX-FileCopyrightText: 2008 Cyrille Berger <cberger@cberger.net> 0003 * SPDX-FileCopyrightText: 2010 Geoffry Song <goffrie@gmail.com> 0004 * SPDX-FileCopyrightText: 2014 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com> 0005 * SPDX-FileCopyrightText: 2017 Scott Petrovic <scottpetrovic@gmail.com> 0006 * 0007 * SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "FisheyePointAssistant.h" 0011 0012 #include "kis_debug.h" 0013 #include <klocalizedstring.h> 0014 0015 #include <QPainter> 0016 #include <QPainterPath> 0017 #include <QLinearGradient> 0018 #include <QTransform> 0019 0020 #include <kis_canvas2.h> 0021 #include <kis_coordinates_converter.h> 0022 #include <kis_algebra_2d.h> 0023 0024 #include <math.h> 0025 #include <limits> 0026 0027 FisheyePointAssistant::FisheyePointAssistant() 0028 : KisPaintingAssistant("fisheye-point", i18n("Fish Eye Point assistant")) 0029 { 0030 } 0031 0032 FisheyePointAssistant::FisheyePointAssistant(const FisheyePointAssistant &rhs, QMap<KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP> &handleMap) 0033 : KisPaintingAssistant(rhs, handleMap) 0034 , e(rhs.e) 0035 , extraE(rhs.extraE) 0036 { 0037 } 0038 0039 KisPaintingAssistantSP FisheyePointAssistant::clone(QMap<KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP> &handleMap) const 0040 { 0041 return KisPaintingAssistantSP(new FisheyePointAssistant(*this, handleMap)); 0042 } 0043 0044 QPointF FisheyePointAssistant::project(const QPointF& pt, const QPointF& strokeBegin) 0045 { 0046 const static QPointF nullPoint(std::numeric_limits<qreal>::quiet_NaN(), std::numeric_limits<qreal>::quiet_NaN()); 0047 Q_ASSERT(isAssistantComplete()); 0048 e.set(*handles()[0], *handles()[1], *handles()[2]); 0049 0050 //set the extrapolation ellipse. 0051 if (e.set(*handles()[0], *handles()[1], *handles()[2])){ 0052 QLineF radius(*handles()[1], *handles()[0]); 0053 radius.setAngle(fmod(radius.angle()+180.0,360.0)); 0054 QLineF radius2(*handles()[0], *handles()[1]); 0055 radius2.setAngle(fmod(radius2.angle()+180.0,360.0)); 0056 if ( extraE.set(*handles()[0], *handles()[1],strokeBegin ) ) { 0057 return extraE.project(pt); 0058 } else if (extraE.set(radius.p1(), radius.p2(),strokeBegin)) { 0059 return extraE.project(pt); 0060 } else if (extraE.set(radius2.p1(), radius2.p2(),strokeBegin)){ 0061 return extraE.project(pt); 0062 } 0063 } 0064 0065 return nullPoint; 0066 0067 } 0068 0069 QPointF FisheyePointAssistant::adjustPosition(const QPointF& pt, const QPointF& strokeBegin, const bool /*snapToAny*/, qreal /*moveThresholdPt*/) 0070 { 0071 return project(pt, strokeBegin); 0072 } 0073 0074 void FisheyePointAssistant::adjustLine(QPointF &point, QPointF &strokeBegin) 0075 { 0076 point = QPointF(); 0077 strokeBegin = QPointF(); 0078 } 0079 0080 void FisheyePointAssistant::drawAssistant(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter* converter, bool cached, KisCanvas2* canvas, bool assistantVisible, bool previewVisible) 0081 { 0082 gc.save(); 0083 gc.resetTransform(); 0084 0085 if (isSnappingActive() && previewVisible == true ) { 0086 0087 if (isAssistantComplete()){ 0088 0089 QTransform initialTransform = converter->documentToWidgetTransform(); 0090 0091 if (e.set(*handles()[0], *handles()[1], *handles()[2])) { 0092 QPointF mousePos = effectiveBrushPosition(converter, canvas); 0093 if (extraE.set(*handles()[0], *handles()[1], initialTransform.inverted().map(mousePos))){ 0094 gc.setTransform(initialTransform); 0095 gc.setTransform(e.getInverse(), true); 0096 QPainterPath path; 0097 // Draw the ellipse 0098 path.addEllipse(QPointF(0, 0), extraE.semiMajor(), extraE.semiMinor()); 0099 drawPreview(gc, path); 0100 } 0101 QLineF radius(*handles()[1], *handles()[0]); 0102 radius.setAngle(fmod(radius.angle()+180.0,360.0)); 0103 if (extraE.set(radius.p1(), radius.p2(), initialTransform.inverted().map(mousePos))){ 0104 gc.setTransform(initialTransform); 0105 gc.setTransform(extraE.getInverse(), true); 0106 QPainterPath path; 0107 // Draw the ellipse 0108 path.addEllipse(QPointF(0, 0), extraE.semiMajor(), extraE.semiMinor()); 0109 drawPreview(gc, path); 0110 } 0111 QLineF radius2(*handles()[0], *handles()[1]); 0112 radius2.setAngle(fmod(radius2.angle()+180.0,360.0)); 0113 if (extraE.set(radius2.p1(), radius2.p2(), initialTransform.inverted().map(mousePos))){ 0114 gc.setTransform(initialTransform); 0115 gc.setTransform(extraE.getInverse(), true); 0116 QPainterPath path; 0117 // Draw the ellipse 0118 path.addEllipse(QPointF(0, 0), extraE.semiMajor(), extraE.semiMinor()); 0119 drawPreview(gc, path); 0120 } 0121 0122 } 0123 } 0124 } 0125 gc.restore(); 0126 0127 KisPaintingAssistant::drawAssistant(gc, updateRect, converter, cached, canvas, assistantVisible, previewVisible); 0128 0129 } 0130 0131 void FisheyePointAssistant::drawCache(QPainter& gc, const KisCoordinatesConverter *converter, bool assistantVisible) 0132 { 0133 if (assistantVisible == false){ 0134 return; 0135 } 0136 0137 QTransform initialTransform = converter->documentToWidgetTransform(); 0138 0139 if (handles().size() == 2) { 0140 // just draw the axis 0141 gc.setTransform(initialTransform); 0142 QPainterPath path; 0143 path.moveTo(*handles()[0]); 0144 path.lineTo(*handles()[1]); 0145 drawPath(gc, path, isSnappingActive()); 0146 return; 0147 } 0148 if (e.set(*handles()[0], *handles()[1], *handles()[2])) { 0149 // valid ellipse 0150 0151 gc.setTransform(initialTransform); 0152 gc.setTransform(e.getInverse(), true); 0153 QPainterPath path; 0154 //path.moveTo(QPointF(-e.semiMajor(), -e.semiMinor())); path.lineTo(QPointF(e.semiMajor(), -e.semiMinor())); 0155 path.moveTo(QPointF(-e.semiMajor(), -e.semiMinor())); path.lineTo(QPointF(-e.semiMajor(), e.semiMinor())); 0156 //path.moveTo(QPointF(-e.semiMajor(), e.semiMinor())); path.lineTo(QPointF(e.semiMajor(), e.semiMinor())); 0157 path.moveTo(QPointF(e.semiMajor(), -e.semiMinor())); path.lineTo(QPointF(e.semiMajor(), e.semiMinor())); 0158 path.moveTo(QPointF(-(e.semiMajor()*3), -e.semiMinor())); path.lineTo(QPointF(-(e.semiMajor()*3), e.semiMinor())); 0159 path.moveTo(QPointF((e.semiMajor()*3), -e.semiMinor())); path.lineTo(QPointF((e.semiMajor()*3), e.semiMinor())); 0160 path.moveTo(QPointF(-e.semiMajor(), 0)); path.lineTo(QPointF(e.semiMajor(), 0)); 0161 //path.moveTo(QPointF(0, -e.semiMinor())); path.lineTo(QPointF(0, e.semiMinor())); 0162 // Draw the ellipse 0163 path.addEllipse(QPointF(0, 0), e.semiMajor(), e.semiMinor()); 0164 drawPath(gc, path, isSnappingActive()); 0165 } 0166 0167 } 0168 0169 QRect FisheyePointAssistant::boundingRect() const 0170 { 0171 if (!isAssistantComplete()) { 0172 return KisPaintingAssistant::boundingRect(); 0173 } 0174 0175 if (e.set(*handles()[0], *handles()[1], *handles()[2])) { 0176 return e.boundingRect().adjusted(-(e.semiMajor()*2), -2, (e.semiMajor()*2), 2).toAlignedRect(); 0177 } else { 0178 return QRect(); 0179 } 0180 } 0181 0182 QPointF FisheyePointAssistant::getDefaultEditorPosition() const 0183 { 0184 return (*handles()[0] + *handles()[1]) * 0.5; 0185 } 0186 0187 bool FisheyePointAssistant::isAssistantComplete() const 0188 { 0189 return handles().size() >= 3; 0190 } 0191 0192 0193 FisheyePointAssistantFactory::FisheyePointAssistantFactory() 0194 { 0195 } 0196 0197 FisheyePointAssistantFactory::~FisheyePointAssistantFactory() 0198 { 0199 } 0200 0201 QString FisheyePointAssistantFactory::id() const 0202 { 0203 return "fisheye-point"; 0204 } 0205 0206 QString FisheyePointAssistantFactory::name() const 0207 { 0208 return i18n("Fish Eye Point"); 0209 } 0210 0211 KisPaintingAssistant* FisheyePointAssistantFactory::createPaintingAssistant() const 0212 { 0213 return new FisheyePointAssistant; 0214 }