File indexing completed on 2024-12-22 04:14:23
0001 /* 0002 * SPDX-FileCopyrightText: 2008 Cyrille Berger <cberger@cberger.net> 0003 * SPDX-FileCopyrightText: 2010 Geoffry Song <goffrie@gmail.com> 0004 * SPDX-FileCopyrightText: 2017 Scott Petrovic <scottpetrovic@gmail.com> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "EllipseAssistant.h" 0010 0011 #include <klocalizedstring.h> 0012 #include "kis_debug.h" 0013 #include <QPainter> 0014 #include <QPainterPath> 0015 #include <QLinearGradient> 0016 #include <QTransform> 0017 0018 #include <kis_canvas2.h> 0019 #include <kis_coordinates_converter.h> 0020 #include "kis_algebra_2d.h" 0021 0022 #include <math.h> 0023 0024 EllipseAssistant::EllipseAssistant() 0025 : KisPaintingAssistant("ellipse", i18n("Ellipse assistant")) 0026 { 0027 } 0028 0029 EllipseAssistant::EllipseAssistant(const EllipseAssistant &rhs, QMap<KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP> &handleMap) 0030 : KisPaintingAssistant(rhs, handleMap) 0031 , e(rhs.e) 0032 { 0033 } 0034 0035 KisPaintingAssistantSP EllipseAssistant::clone(QMap<KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP> &handleMap) const 0036 { 0037 return KisPaintingAssistantSP(new EllipseAssistant(*this, handleMap)); 0038 } 0039 0040 QPointF EllipseAssistant::project(const QPointF& pt) const 0041 { 0042 Q_ASSERT(isAssistantComplete()); 0043 e.set(*handles()[0], *handles()[1], *handles()[2]); 0044 return e.project(pt); 0045 } 0046 0047 QPointF EllipseAssistant::adjustPosition(const QPointF& pt, const QPointF& /*strokeBegin*/, const bool /*snapToAny*/, qreal /*moveThresholdPt*/) 0048 { 0049 return project(pt); 0050 0051 } 0052 0053 void EllipseAssistant::adjustLine(QPointF &point, QPointF &strokeBegin) 0054 { 0055 const QPointF p1 = point; 0056 const QPointF p2 = strokeBegin; 0057 0058 Q_ASSERT(isAssistantComplete()); 0059 e.set(*handles()[0], *handles()[1], *handles()[2]); 0060 0061 QPointF p3 = e.project(p1); 0062 QPointF p4 = e.project(p2); 0063 point = p3; 0064 strokeBegin = p4; 0065 } 0066 0067 void EllipseAssistant::drawAssistant(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter* converter, bool cached, KisCanvas2* canvas, bool assistantVisible, bool previewVisible) 0068 { 0069 gc.save(); 0070 gc.resetTransform(); 0071 QPoint mousePos; 0072 0073 if (canvas){ 0074 //simplest, cheapest way to get the mouse-position// 0075 mousePos= canvas->canvasWidget()->mapFromGlobal(QCursor::pos()); 0076 } 0077 else { 0078 //...of course, you need to have access to a canvas-widget for that.// 0079 mousePos = QCursor::pos();//this'll give an offset// 0080 dbgFile<<"canvas does not exist in the ellipse assistant, you may have passed arguments incorrectly:"<<canvas; 0081 } 0082 0083 QTransform initialTransform = converter->documentToWidgetTransform(); 0084 0085 if (isSnappingActive() && boundingRect().contains(initialTransform.inverted().map(mousePos), false) && previewVisible==true){ 0086 0087 if (isAssistantComplete()){ 0088 if (e.set(*handles()[0], *handles()[1], *handles()[2])) { 0089 // valid ellipse 0090 gc.setTransform(initialTransform); 0091 gc.setTransform(e.getInverse(), true); 0092 QPainterPath path; 0093 //path.moveTo(QPointF(-e.semiMajor(), 0)); path.lineTo(QPointF(e.semiMajor(), 0)); 0094 //path.moveTo(QPointF(0, -e.semiMinor())); path.lineTo(QPointF(0, e.semiMinor())); 0095 // Draw the ellipse 0096 path.addEllipse(QPointF(0, 0), e.semiMajor(), e.semiMinor()); 0097 drawPreview(gc, path); 0098 } 0099 } 0100 } 0101 gc.restore(); 0102 KisPaintingAssistant::drawAssistant(gc, updateRect, converter, cached, canvas, assistantVisible, previewVisible); 0103 0104 } 0105 0106 0107 void EllipseAssistant::drawCache(QPainter& gc, const KisCoordinatesConverter *converter, bool assistantVisible) 0108 { 0109 0110 if (assistantVisible == false || handles().size() < 2){ 0111 return; 0112 } 0113 0114 QTransform initialTransform = converter->documentToWidgetTransform(); 0115 0116 if (handles().size() == 2) { 0117 // just draw the axis 0118 gc.setTransform(initialTransform); 0119 QPainterPath path; 0120 path.moveTo(*handles()[0]); 0121 path.lineTo(*handles()[1]); 0122 drawPath(gc, path, isSnappingActive()); 0123 return; 0124 } 0125 if (e.set(*handles()[0], *handles()[1], *handles()[2])) { 0126 // valid ellipse 0127 0128 gc.setTransform(initialTransform); 0129 gc.setTransform(e.getInverse(), true); 0130 QPainterPath path; 0131 path.moveTo(QPointF(-e.semiMajor(), 0)); path.lineTo(QPointF(e.semiMajor(), 0)); 0132 path.moveTo(QPointF(0, -e.semiMinor())); path.lineTo(QPointF(0, e.semiMinor())); 0133 // Draw the ellipse 0134 path.addEllipse(QPointF(0, 0), e.semiMajor(), e.semiMinor()); 0135 drawPath(gc, path, isSnappingActive()); 0136 } 0137 } 0138 0139 QRect EllipseAssistant::boundingRect() const 0140 { 0141 if (!isAssistantComplete()) { 0142 return KisPaintingAssistant::boundingRect(); 0143 } 0144 0145 if (e.set(*handles()[0], *handles()[1], *handles()[2])) { 0146 return e.boundingRect().adjusted(-2, -2, 2, 2).toAlignedRect(); 0147 } else { 0148 return QRect(); 0149 } 0150 } 0151 0152 QPointF EllipseAssistant::getDefaultEditorPosition() const 0153 { 0154 return (*handles()[0] + *handles()[1]) * 0.5; 0155 } 0156 0157 bool EllipseAssistant::isAssistantComplete() const 0158 { 0159 return handles().size() >= 3; 0160 } 0161 0162 void EllipseAssistant::transform(const QTransform &transform) 0163 { 0164 e.set(*handles()[0], *handles()[1], *handles()[2]); 0165 0166 QPointF newAxes; 0167 QTransform newTransform; 0168 0169 std::tie(newAxes, newTransform) = KisAlgebra2D::transformEllipse(QPointF(e.semiMajor(), e.semiMinor()), e.getInverse() * transform); 0170 0171 const QPointF p1 = newTransform.map(QPointF(newAxes.x(), 0)); 0172 const QPointF p2 = newTransform.map(QPointF(-newAxes.x(), 0)); 0173 const QPointF p3 = newTransform.map(QPointF(0, newAxes.y())); 0174 0175 *handles()[0] = p1; 0176 *handles()[1] = p2; 0177 *handles()[2] = p3; 0178 0179 uncache(); 0180 } 0181 0182 EllipseAssistantFactory::EllipseAssistantFactory() 0183 { 0184 } 0185 0186 EllipseAssistantFactory::~EllipseAssistantFactory() 0187 { 0188 } 0189 0190 QString EllipseAssistantFactory::id() const 0191 { 0192 return "ellipse"; 0193 } 0194 0195 QString EllipseAssistantFactory::name() const 0196 { 0197 return i18n("Ellipse"); 0198 } 0199 0200 KisPaintingAssistant* EllipseAssistantFactory::createPaintingAssistant() const 0201 { 0202 return new EllipseAssistant; 0203 }