Krita Source Code Documentation
Loading...
Searching...
No Matches
TwoPointAssistant Class Reference

#include <TwoPointAssistant.h>

+ Inheritance diagram for TwoPointAssistant:

Public Types

enum  TwoPointHandle {
  FirstHandle , SecondHandle , VerticalHandle , LocalFirstHandle ,
  LocalSecondHandle
}
 

Public Member Functions

void adjustLine (QPointF &point, QPointF &strokeBegin) override
 
QPointF adjustPosition (const QPointF &point, const QPointF &strokeBegin, const bool snapToAny, qreal moveThresholdPt) override
 
bool canBeLocal () const override
 canBeLocal
 
KisPaintingAssistantSP clone (QMap< KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP > &handleMap) const override
 
void endStroke () override
 
QPointF getDefaultEditorPosition () const override
 
double gridDensity ()
 
bool isAssistantComplete () const override
 
bool loadCustomXml (QXmlStreamReader *xml) override
 
QTransform localTransform (QPointF vp_a, QPointF vp_b, QPointF pt_c, qreal *size)
 
int numHandles () const override
 
void saveCustomXml (QXmlStreamWriter *xml) override
 
void setGridDensity (double density)
 
void setUseVertical (bool value)
 
 TwoPointAssistant ()
 
bool useVertical ()
 
- Public Member Functions inherited from KisPaintingAssistant
void addHandle (KisPaintingAssistantHandleSP handle, HandleType type)
 
bool areTwoPointsClose (const QPointF &pointOne, const QPointF &pointTwo)
 
QColor assistantCustomColor ()
 
KisPaintingAssistantHandleSP bottomLeft ()
 
const KisPaintingAssistantHandleSP bottomLeft () const
 
KisPaintingAssistantHandleSP bottomMiddle ()
 
const KisPaintingAssistantHandleSP bottomMiddle () const
 
KisPaintingAssistantHandleSP bottomRight ()
 
const KisPaintingAssistantHandleSP bottomRight () const
 
KisPaintingAssistantHandleSP closestCornerHandleFromPoint (QPointF point)
 
void copySharedData (KisPaintingAssistantSP assistant)
 
void drawError (QPainter &painter, const QPainterPath &path, const KoColorDisplayRendererInterface *displayRenderInterface)
 
void drawPath (QPainter &painter, const QPainterPath &path, const KoColorDisplayRendererInterface *displayRenderInterface, bool drawActive=true)
 
void drawPreview (QPainter &painter, const QPainterPath &path, const KoColorDisplayRendererInterface *displayRenderInterface)
 
void drawX (QPainter &painter, const QPointF &pt, const KoColorDisplayRendererInterface *displayRenderInterface)
 
QPointF editorWidgetOffset ()
 
QColor effectiveAssistantColor () const
 
void findPerspectiveAssistantHandleLocation ()
 
virtual QPointF getEditorPosition () const
 
QList< KisPaintingAssistantHandleSPhandles ()
 
const QList< KisPaintingAssistantHandleSP > & handles () const
 
const QString & id () const
 
bool isDuplicating ()
 isDuplicating
 
bool isLocal () const
 isLocal
 
bool isLocked ()
 isLocked
 
bool isSnappingActive () const
 
 KisPaintingAssistant (const QString &id, const QString &name)
 
KisPaintingAssistantHandleSP leftMiddle ()
 
const KisPaintingAssistantHandleSP leftMiddle () const
 
void loadXml (KoStore *store, QMap< int, KisPaintingAssistantHandleSP > &handleMap, QString path)
 
const QString & name () const
 
KisPaintingAssistantHandleSP oppHandleOne ()
 
void replaceHandle (KisPaintingAssistantHandleSP _handle, KisPaintingAssistantHandleSP _with)
 
KisPaintingAssistantHandleSP rightMiddle ()
 
const KisPaintingAssistantHandleSP rightMiddle () const
 
QByteArray saveXml (QMap< KisPaintingAssistantHandleSP, int > &handleMap)
 
void saveXmlList (QDomDocument &doc, QDomElement &assistantsElement, int count)
 
virtual void setAdjustedBrushPosition (const QPointF position)
 
void setAssistantCustomColor (QColor color)
 
void setAssistantGlobalColorCache (const QColor &color)
 
void setDecorationThickness (int thickness)
 
void setDuplicating (bool value)
 setDuplicating
 
void setEditorWidgetOffset (QPointF offset)
 
virtual void setFollowBrushPosition (bool follow)
 
void setLocal (bool value)
 setLocal
 
void setLocked (bool value)
 setLocked
 
void setSnappingActive (bool set)
 
void setUseCustomColor (bool useCustomColor)
 
QList< KisPaintingAssistantHandleSPsideHandles ()
 
const QList< KisPaintingAssistantHandleSP > & sideHandles () const
 
KisPaintingAssistantHandleSP topLeft ()
 
const KisPaintingAssistantHandleSP topLeft () const
 
KisPaintingAssistantHandleSP topMiddle ()
 
const KisPaintingAssistantHandleSP topMiddle () const
 
KisPaintingAssistantHandleSP topRight ()
 
const KisPaintingAssistantHandleSP topRight () const
 
virtual void transform (const QTransform &transform)
 
void uncache ()
 
bool useCustomColor ()
 
QPointF viewportConstrainedEditorPosition (const KisCoordinatesConverter *converter, const QSize editorSize)
 
virtual ~KisPaintingAssistant ()
 

Protected Member Functions

void drawAssistant (QPainter &gc, const QRectF &updateRect, const KisCoordinatesConverter *converter, const KoColorDisplayRendererInterface *displayRenderInterface, bool cached=true, KisCanvas2 *canvas=nullptr, bool assistantVisible=true, bool previewVisible=true) override
 
void drawCache (QPainter &gc, const KisCoordinatesConverter *converter, const KoColorDisplayRendererInterface *displayRenderInterface, bool assistantVisible=true) override
 performance layer where the graphics can be drawn from a cache instead of generated every render update
 
KisPaintingAssistantHandleSP firstLocalHandle () const override
 firstLocalHandle Note: this doesn't guarantee it will be the topleft corner! For that, use getLocalRect().topLeft() The only purpose of those functions to exist is to be able to put getLocalRect() function in the KisPaintingAssistant instead of reimplementing it in every specific assistant.
 
KisPaintingAssistantHandleSP secondLocalHandle () const override
 secondLocalHandle Note: this doesn't guarantee it will be the bottomRight corner! For that, use getLocalRect().bottomRight() (and remember that for QRect bottomRight() works differently than for QRectF, so don't convert to QRect before accessing the corner)
 
- Protected Member Functions inherited from KisPaintingAssistant
virtual QRect boundingRect () const
 
QPointF effectiveBrushPosition (const KisCoordinatesConverter *converter, KisCanvas2 *canvas) const
 Query the effective brush position to be used for preview lines. This is intended to be used for painting the dynamic preview lines for assistants that feature them. Affected by setAdjustedBrushPosition() and setFollowBrushPosition().
 
QRectF getLocalRect () const
 getLocalRect The function deals with local handles not being topLeft and bottomRight gracefully and returns a correct rectangle. Thanks to that the user can place handles in a "wrong" order or move them around but the local rectangle will still be correct.
 
void initHandles (QList< KisPaintingAssistantHandleSP > _handles)
 
 KisPaintingAssistant (const KisPaintingAssistant &rhs, QMap< KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP > &handleMap)
 
QPointF pixelToView (const QPoint pixelCoords) const
 

Private Member Functions

QPointF project (const QPointF &pt, const QPointF &strokeBegin, const bool snapToAny, qreal moveThreshold)
 
 TwoPointAssistant (const TwoPointAssistant &rhs, QMap< KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP > &handleMap)
 

Private Attributes

KisCanvas2m_canvas {nullptr}
 
double m_gridDensity {1.0}
 
int m_lastUsedPoint {-1}
 
QLineF m_snapLine
 
bool m_useVertical {true}
 

Additional Inherited Members

- Static Public Member Functions inherited from KisPaintingAssistant
static QList< KisPaintingAssistantSPcloneAssistantList (const QList< KisPaintingAssistantSP > &list)
 
static double norm2 (const QPointF &p)
 
- Protected Attributes inherited from KisPaintingAssistant
QList< KisPaintingAssistantHandleSPm_handles
 
bool m_hasBeenInsideLocalRect {false}
 

Detailed Description

Definition at line 17 of file TwoPointAssistant.h.

Member Enumeration Documentation

◆ TwoPointHandle

Enumerator
FirstHandle 
SecondHandle 
VerticalHandle 
LocalFirstHandle 
LocalSecondHandle 

Definition at line 21 of file TwoPointAssistant.h.

Constructor & Destructor Documentation

◆ TwoPointAssistant() [1/2]

TwoPointAssistant::TwoPointAssistant ( )

Definition at line 27 of file TwoPointAssistant.cc.

28 : KisPaintingAssistant("two point", i18n("Two point assistant"))
29{
30}
KisPaintingAssistant(const QString &id, const QString &name)

◆ TwoPointAssistant() [2/2]

TwoPointAssistant::TwoPointAssistant ( const TwoPointAssistant & rhs,
QMap< KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP > & handleMap )
explicitprivate

Member Function Documentation

◆ adjustLine()

void TwoPointAssistant::adjustLine ( QPointF & point,
QPointF & strokeBegin )
overridevirtual

Implements KisPaintingAssistant.

Definition at line 146 of file TwoPointAssistant.cc.

147{
148 QPointF p = project(point, strokeBegin, true, 0.0);
149 point = p;
150}
const Params2D p
QPointF project(const QPointF &pt, const QPointF &strokeBegin, const bool snapToAny, qreal moveThreshold)

References p, and project().

◆ adjustPosition()

QPointF TwoPointAssistant::adjustPosition ( const QPointF & point,
const QPointF & strokeBegin,
const bool snapToAny,
qreal moveThresholdPt )
overridevirtual

Adjust the position given in parameter.

Parameters
pointthe coordinates in point in the document reference
strokeBeginthe coordinates of the beginning of the stroke
snapToAnybecause now assistants can be composited out of multiple inside assistants. snapToAny true means that you can use any of the inside assistant, while it being false means you should use the last used one. The logic determining when it happens (first stroke etc.) is in the decoration, so those two options are enough.
moveThresholdPtthe threshold for the "move" of the cursor measured in pt (usually equals to 2px in screen coordinates converted to pt)

Implements KisPaintingAssistant.

Definition at line 141 of file TwoPointAssistant.cc.

142{
143 return project(pt, strokeBegin, snapToAny, moveThresholdPt);
144}

References project().

◆ canBeLocal()

bool TwoPointAssistant::canBeLocal ( ) const
overridevirtual

canBeLocal

Returns
if the assistant can be potentially a "local assistant" (limited to rectangular area) or not

Reimplemented from KisPaintingAssistant.

Definition at line 484 of file TwoPointAssistant.cc.

485{
486 return true;
487}

◆ clone()

KisPaintingAssistantSP TwoPointAssistant::clone ( QMap< KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP > & handleMap) const
overridevirtual

Implements KisPaintingAssistant.

Definition at line 42 of file TwoPointAssistant.cc.

43{
44 return KisPaintingAssistantSP(new TwoPointAssistant(*this, handleMap));
45}
QSharedPointer< KisPaintingAssistant > KisPaintingAssistantSP
Definition kis_types.h:189

References TwoPointAssistant().

◆ drawAssistant()

void TwoPointAssistant::drawAssistant ( QPainter & gc,
const QRectF & updateRect,
const KisCoordinatesConverter * converter,
const KoColorDisplayRendererInterface * displayRenderInterface,
bool cached = true,
KisCanvas2 * canvas = nullptr,
bool assistantVisible = true,
bool previewVisible = true )
overrideprotectedvirtual

Reimplemented from KisPaintingAssistant.

Definition at line 152 of file TwoPointAssistant.cc.

153{
154 Q_UNUSED(updateRect);
155 Q_UNUSED(cached);
156 gc.save();
157 gc.resetTransform();
158
159 const QColor canvasAssistantColor = displayRenderInterface->convertColorToDisplayColorSpace(KoColor(effectiveAssistantColor(), KoColorSpaceRegistry::instance()->rgb8()));
160
161 const QTransform initialTransform = converter->documentToWidgetTransform();
162 bool isEditing = false;
163 bool showLocal = isLocal() && handles().size() == 5;
164
165 if (canvas) {
166 isEditing = canvas->paintingAssistantsDecoration()->isEditingAssistants();
167 }
168
169 if (isEditing) {
170 Q_FOREACH (const QPointF* handle, handles()) {
171 QPointF h = initialTransform.map(*handle);
172 QRectF ellipse = QRectF(QPointF(h.x() -15, h.y() -15), QSizeF(30, 30));
173
174 QPainterPath pathCenter;
175 pathCenter.addEllipse(ellipse);
176 drawPath(gc, pathCenter, displayRenderInterface, isSnappingActive());
177
178 // Draw circle to represent center of vision
179 if (handles().length() == 3 && handle == handles()[2]) {
180 const QLineF horizon = QLineF(*handles()[0],*handles()[1]);
181 QLineF normal = horizon.normalVector();
182 normal.translate(*handles()[2]-normal.p1());
183 QPointF cov = horizon.center();
184 normal.intersects(horizon,&cov);
185 const QPointF center = initialTransform.map(cov);
186 QRectF center_ellipse = QRectF(QPointF(center.x() -15, center.y() -15), QSizeF(30, 30));
187 QPainterPath pathCenter;
188 pathCenter.addEllipse(center_ellipse);
189 drawPath(gc, pathCenter, displayRenderInterface, isSnappingActive());
190 }
191 }
192
193 if (handles().size() <= 2) {
194 QPainterPath path;
195 int tempDensity = m_gridDensity * 10; // the vanishing point density seems visibly more dense, hence let's make it less dense
196 QRect viewport = gc.viewport();
197
198 for (int i = 0; i < handles().size(); i++) {
199 const QPointF p = initialTransform.map(*handles()[i]);
200 for (int currentAngle=0; currentAngle <= 180; currentAngle = currentAngle + tempDensity) {
201
202 // determine the correct angle based on the iteration
203 float xPos = cos(currentAngle * M_PI / 180);
204 float yPos = sin(currentAngle * M_PI / 180);
205 float length = 100;
206 QPointF unit = QPointF(length*xPos, length*yPos);
207
208 // find point
209 QLineF snapLine = QLineF(p, p + unit);
210 if (KisAlgebra2D::intersectLineRect(snapLine, viewport, false)) {
211 // make a line from VP center to edge of canvas with that angle
212
213 path.moveTo(snapLine.p1());
214 path.lineTo(snapLine.p2());
215 }
216
217 QLineF snapLine2 = QLineF(p, p - unit);
218 if (KisAlgebra2D::intersectLineRect(snapLine2, viewport, false)) {
219 // make a line from VP center to edge of canvas with that angle
220
221 path.moveTo(snapLine2.p1());
222 path.lineTo(snapLine2.p2());
223 }
224
225
226 }
227
228 drawPreview(gc, path, displayRenderInterface);//and we draw the preview.
229
230 }
231 }
232
233 }
234
235 if (handles().size() >= 2) {
236 QPointF mousePos = effectiveBrushPosition(converter, canvas);
237 const QPointF p1 = *handles()[0];
238 const QPointF p2 = *handles()[1];
239 const QRect viewport= gc.viewport();
240
241 const QPolygonF localPoly = (isLocal() && handles().size() == 5) ? initialTransform.map(QPolygonF(getLocalRect())) : QPolygonF();
242 const QPolygonF viewportAndLocalPoly = !localPoly.isEmpty() ? QPolygonF(QRectF(viewport)).intersected(localPoly) : QRectF(viewport);
243
244
245 QPainterPath path;
246 QPainterPath previewPath; // part of the preview, instead of the assistant itself
247
248 // draw the horizon
249 if (assistantVisible == true || isEditing == true) {
250 QLineF horizonLine = initialTransform.map(QLineF(p1,p2));
251 KisAlgebra2D::cropLineToConvexPolygon(horizonLine, viewportAndLocalPoly, true, true);
252 path.moveTo(horizonLine.p1());
253 path.lineTo(horizonLine.p2());
254 }
255
256 // draw the VP-->mousePos lines
257 if (isEditing == false && previewVisible == true && isSnappingActive() == true) {
258 // draw the line vp <-> mouse even outside of the local rectangle
259 // but only if the mouse pos is inside the rectangle
260 QLineF snapMouse1 = QLineF(initialTransform.map(p1), mousePos);
261 QLineF snapMouse2 = QLineF(initialTransform.map(p2), mousePos);
262 KisAlgebra2D::cropLineToConvexPolygon(snapMouse1, viewportAndLocalPoly, false, true);
263 KisAlgebra2D::cropLineToConvexPolygon(snapMouse2, viewportAndLocalPoly, false, true);
264 previewPath.moveTo(snapMouse1.p1());
265 previewPath.lineTo(snapMouse1.p2());
266 previewPath.moveTo(snapMouse2.p1());
267 previewPath.lineTo(snapMouse2.p2());
268 }
269
270 // draw the side handle bars
271 if (isEditing == true && !sideHandles().isEmpty()) {
272 path.moveTo(initialTransform.map(p1));
273 path.lineTo(initialTransform.map(*sideHandles()[0]));
274 path.lineTo(initialTransform.map(*sideHandles()[1]));
275 path.moveTo(initialTransform.map(p2));
276 path.lineTo(initialTransform.map(*sideHandles()[2]));
277 path.lineTo(initialTransform.map(*sideHandles()[3]));
278 path.moveTo(initialTransform.map(p1));
279 path.lineTo(initialTransform.map(*sideHandles()[4]));
280 path.lineTo(initialTransform.map(*sideHandles()[5]));
281 path.moveTo(initialTransform.map(p2));
282 path.lineTo(initialTransform.map(*sideHandles()[6]));
283 path.lineTo(initialTransform.map(*sideHandles()[7]));
284 }
285
286 // draw the local rectangle
287 if (showLocal && assistantVisible) {
288 QPointF p1 = *handles()[(int)LocalFirstHandle];
289 QPointF p3 = *handles()[(int)LocalSecondHandle];
290 QPointF p2 = QPointF(p1.x(), p3.y());
291 QPointF p4 = QPointF(p3.x(), p1.y());
292
293 path.moveTo(initialTransform.map(p1));
294
295 path.lineTo(initialTransform.map(p2));
296 path.lineTo(initialTransform.map(p3));
297 path.lineTo(initialTransform.map(p4));
298 path.lineTo(initialTransform.map(p1));
299 }
300
301
302 drawPreview(gc,previewPath, displayRenderInterface);
303 drawPath(gc, path, displayRenderInterface, isSnappingActive());
304
305 if (handles().size() >= 3 && isSnappingActive()) {
306 path = QPainterPath(); // clear
307 const QPointF p3 = *handles()[2];
308
309 qreal size = 0;
310 const QTransform t = localTransform(p1,p2,p3,&size);
311 const QTransform inv = t.inverted();
312 const QPointF vp_a = t.map(p1);
313 const QPointF vp_b = t.map(p2);
314
315 if ((vp_a.x() < 0 && vp_b.x() > 0) ||
316 (vp_a.x() > 0 && vp_b.x() < 0)) {
317 if (m_useVertical) {
318 // Draw vertical line, but only if the center is between both VPs
319 QLineF vertical = initialTransform.map(inv.map(QLineF::fromPolar(1,90)));
320 if (!isEditing) vertical.translate(mousePos - vertical.p1());
321 KisAlgebra2D::cropLineToConvexPolygon(vertical, viewportAndLocalPoly, true, true);
322 if (previewVisible) {
323 path.moveTo(vertical.p1());
324 path.lineTo(vertical.p2());
325 }
326
327 if (assistantVisible) {
328 // Display a notch to represent the center of vision
329 path.moveTo(initialTransform.map(inv.map(QPointF(0,vp_a.y()-10))));
330 path.lineTo(initialTransform.map(inv.map(QPointF(0,vp_a.y()+10))));
331 }
332 drawPreview(gc,path, displayRenderInterface);
333 path = QPainterPath(); // clear
334 }
335 }
336
337 const QPointF upper = QPointF(0,vp_a.y() + size);
338 const QPointF lower = QPointF(0,vp_a.y() - size);
339
340 // Set up the fading effect for the grid lines
341 // Needed so the grid density doesn't look distracting
342 QColor color = canvasAssistantColor;
343 QGradient fade = QLinearGradient(initialTransform.map(inv.map(upper)),
344 initialTransform.map(inv.map(lower)));
345 color.setAlphaF(0);
346 fade.setColorAt(0.4, canvasAssistantColor);
347 fade.setColorAt(0.5, color);
348 fade.setColorAt(0.6, canvasAssistantColor);
349 const QPen pen = gc.pen();
350 const QBrush new_brush = QBrush(fade);
351 int width = 1;
352 const QPen new_pen = QPen(new_brush, width, pen.style());
353 gc.setPen(new_pen);
354
355 const QList<QPointF> station_points = {upper, lower};
356 const QList<QPointF> vanishing_points = {vp_a, vp_b};
357
358 // Draw grid lines above and below the horizon
359 Q_FOREACH (const QPointF sp, station_points) {
360
361 // Draw grid lines towards each vanishing point
362 Q_FOREACH (const QPointF vp, vanishing_points) {
363
364 // Interval between each grid line, uses grid density specified by user
365 const qreal initial_angle = QLineF(sp, vp).angle();
366 const qreal interval = size*m_gridDensity / cos((initial_angle - 90) * M_PI/180);
367 const QPointF translation = QPointF(interval, 0);
368
369 // Draw grid lines originating from both the left and right of the central vertical line
370 Q_FOREACH (const int dir, QList<int>({-1, 1})) {
371
372 // Limit at 300 grid lines per direction, reasonable even for m_gridDensity=0.1;
373 for (int i = 0; i <= 300; i++) {
374 const QLineF gridline = QLineF(sp + translation * i * dir, vp);
375
376 // Don't bother drawing lines that are nearly parallel to horizon
377 const qreal angle = gridline.angle();
378 if (angle < 0.25 || angle > 359.75 || (angle < 180.25 && angle > 179.75)) {
379 break;
380 }
381
382 QLineF drawn_gridline = initialTransform.map(inv.map(gridline));
383 KisAlgebra2D::cropLineToConvexPolygon(drawn_gridline, viewportAndLocalPoly, true, false);
384
385 if (assistantVisible || isEditing == true) {
386 path.moveTo(drawn_gridline.p2());
387 path.lineTo(drawn_gridline.p1());
388 }
389 }
390 }
391 }
392 }
393 gc.drawPath(path);
394 }
395 }
396
397 gc.restore();
398 //KisPaintingAssistant::drawAssistant(gc, updateRect, converter, cached, canvas, assistantVisible, previewVisible);
399}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
QPointF p2
QPointF p3
QPointF p1
KisPaintingAssistantsDecorationSP paintingAssistantsDecoration() const
QPointF effectiveBrushPosition(const KisCoordinatesConverter *converter, KisCanvas2 *canvas) const
Query the effective brush position to be used for preview lines. This is intended to be used for pain...
void drawPreview(QPainter &painter, const QPainterPath &path, const KoColorDisplayRendererInterface *displayRenderInterface)
void drawPath(QPainter &painter, const QPainterPath &path, const KoColorDisplayRendererInterface *displayRenderInterface, bool drawActive=true)
QRectF getLocalRect() const
getLocalRect The function deals with local handles not being topLeft and bottomRight gracefully and r...
const QList< KisPaintingAssistantHandleSP > & sideHandles() const
const QList< KisPaintingAssistantHandleSP > & handles() const
virtual QColor convertColorToDisplayColorSpace(const KoColor color) const =0
convertColorToDisplayColorSpace
QTransform localTransform(QPointF vp_a, QPointF vp_b, QPointF pt_c, qreal *size)
#define M_PI
Definition kis_global.h:111
void cropLineToConvexPolygon(QLineF &line, const QPolygonF polygon, bool extendFirst, bool extendSecond)
bool intersectLineRect(QLineF &line, const QRect rect, bool extend)
int size(const Forest< T > &forest)
Definition KisForest.h:1232
static KoColorSpaceRegistry * instance()

References KoColorDisplayRendererInterface::convertColorToDisplayColorSpace(), KisAlgebra2D::cropLineToConvexPolygon(), KisCoordinatesConverter::documentToWidgetTransform(), KisPaintingAssistant::drawPath(), KisPaintingAssistant::drawPreview(), KisPaintingAssistant::effectiveAssistantColor(), KisPaintingAssistant::effectiveBrushPosition(), KisPaintingAssistant::getLocalRect(), KisPaintingAssistant::handles(), KoColorSpaceRegistry::instance(), KisAlgebra2D::intersectLineRect(), KisPaintingAssistantsDecoration::isEditingAssistants(), KisPaintingAssistant::isLocal(), KisPaintingAssistant::isSnappingActive(), length(), LocalFirstHandle, LocalSecondHandle, localTransform(), m_gridDensity, M_PI, m_useVertical, p, p1, p2, p3, KisCanvas2::paintingAssistantsDecoration(), and KisPaintingAssistant::sideHandles().

◆ drawCache()

void TwoPointAssistant::drawCache ( QPainter & gc,
const KisCoordinatesConverter * converter,
const KoColorDisplayRendererInterface * displayRenderInterface,
bool assistantVisible = true )
overrideprotectedvirtual

performance layer where the graphics can be drawn from a cache instead of generated every render update

Implements KisPaintingAssistant.

Definition at line 401 of file TwoPointAssistant.cc.

402{
403 Q_UNUSED(gc);
404 Q_UNUSED(converter);
405 Q_UNUSED(assistantVisible);
406 Q_UNUSED(displayRenderInterface);
407 if (!m_canvas || !isAssistantComplete()) {
408 return;
409 }
410
411 if (assistantVisible == false || m_canvas->paintingAssistantsDecoration()->isEditingAssistants()) {
412 return;
413 }
414}
bool isAssistantComplete() const override

References isAssistantComplete(), KisPaintingAssistantsDecoration::isEditingAssistants(), m_canvas, and KisCanvas2::paintingAssistantsDecoration().

◆ endStroke()

void TwoPointAssistant::endStroke ( )
overridevirtual

Reimplemented from KisPaintingAssistant.

Definition at line 134 of file TwoPointAssistant.cc.

135{
136 m_snapLine = QLineF();
137 m_lastUsedPoint = -1;
139}

References KisPaintingAssistant::endStroke(), m_lastUsedPoint, and m_snapLine.

◆ firstLocalHandle()

KisPaintingAssistantHandleSP TwoPointAssistant::firstLocalHandle ( ) const
overrideprotectedvirtual

firstLocalHandle Note: this doesn't guarantee it will be the topleft corner! For that, use getLocalRect().topLeft() The only purpose of those functions to exist is to be able to put getLocalRect() function in the KisPaintingAssistant instead of reimplementing it in every specific assistant.

Returns
the first handle of the rectangle of the limited area

Reimplemented from KisPaintingAssistant.

Definition at line 416 of file TwoPointAssistant.cc.

417{
418 if (handles().size() > LocalFirstHandle) {
419 return handles().at(LocalFirstHandle);
420 } else {
421 return nullptr;
422 }
423}

References KisPaintingAssistant::handles(), and LocalFirstHandle.

◆ getDefaultEditorPosition()

QPointF TwoPointAssistant::getDefaultEditorPosition ( ) const
overridevirtual

Implements KisPaintingAssistant.

Definition at line 434 of file TwoPointAssistant.cc.

435{
436 int centerOfVisionHandle = 2;
437 if (handles().size() > centerOfVisionHandle) {
438 return *handles().at(centerOfVisionHandle);
439 } else if (handles().size() > 0) {
441 return *handles().at(0);
442 } else {
443 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(false, QPointF(0, 0));
444 return QPointF(0, 0);
445 }
446}
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129

References KisPaintingAssistant::handles(), and KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE.

◆ gridDensity()

double TwoPointAssistant::gridDensity ( )

Definition at line 463 of file TwoPointAssistant.cc.

464{
465 return m_gridDensity;
466}

References m_gridDensity.

◆ isAssistantComplete()

bool TwoPointAssistant::isAssistantComplete ( ) const
overridevirtual

determines if the assistant has enough handles to be considered created new assistants get in a "creation" phase where they are currently being made on the canvas it will return false if we are in the middle of creating the assistant.

Reimplemented from KisPaintingAssistant.

Definition at line 479 of file TwoPointAssistant.cc.

480{
481 return handles().size() >= numHandles();
482}
int numHandles() const override

References KisPaintingAssistant::handles(), and numHandles().

◆ loadCustomXml()

bool TwoPointAssistant::loadCustomXml ( QXmlStreamReader * xml)
overridevirtual

Reimplemented from KisPaintingAssistant.

Definition at line 503 of file TwoPointAssistant.cc.

504{
505 if (xml && xml->name() == "gridDensity") {
506 this->setGridDensity((float)KisDomUtils::toDouble(xml->attributes().value("value").toString()));
507 }
508 if (xml && xml->name() == "useVertical") {
509 this->setUseVertical((bool)KisDomUtils::toInt(xml->attributes().value("value").toString()));
510 }
511 if (xml && xml->name() == "isLocal") {
512 this->setLocal((bool)KisDomUtils::toInt(xml->attributes().value("value").toString()));
513 }
514 return true;
515}
void setLocal(bool value)
setLocal
void setGridDensity(double density)
void setUseVertical(bool value)
double toDouble(const QString &str, bool *ok=nullptr)
int toInt(const QString &str, bool *ok=nullptr)

References setGridDensity(), KisPaintingAssistant::setLocal(), setUseVertical(), KisDomUtils::toDouble(), and KisDomUtils::toInt().

◆ localTransform()

QTransform TwoPointAssistant::localTransform ( QPointF vp_a,
QPointF vp_b,
QPointF pt_c,
qreal * size )

Definition at line 468 of file TwoPointAssistant.cc.

469{
470 QTransform t = QTransform();
471 t.rotate(QLineF(vp_a, vp_b).angle());
472 t.translate(-pt_c.x(),-pt_c.y());
473 const QLineF horizon = QLineF(t.map(vp_a), QPointF(t.map(vp_b).x(),t.map(vp_a).y()));
474 *size = sqrt(pow(horizon.length()/2.0,2) - pow(abs(horizon.center().x()),2));
475
476 return t;
477}
Point abs(const Point &pt)

◆ numHandles()

int TwoPointAssistant::numHandles ( ) const
inlineoverridevirtual

Implements KisPaintingAssistant.

Definition at line 37 of file TwoPointAssistant.h.

37{ return isLocal() ? 5 : 3; }

References KisPaintingAssistant::isLocal().

◆ project()

QPointF TwoPointAssistant::project ( const QPointF & pt,
const QPointF & strokeBegin,
const bool snapToAny,
qreal moveThreshold )
private

Definition at line 47 of file TwoPointAssistant.cc.

48{
49 Q_ASSERT(isAssistantComplete());
50
51 QPointF best_pt = point;
52 double best_dist = DBL_MAX;
53 QList<int> possibleHandles;
54
55 // must be above or equal to 0;
56 // if useVertical, then last used point must be below 3, because 2 means vertical
57 // and it's the last possible point here (sanity check)
58 // if !useVertical, then it must be below 2, because 2 means vertical
59 bool isLastUsedPointCorrectNow = m_lastUsedPoint >= 0 && (m_useVertical ? m_lastUsedPoint < 3 : m_lastUsedPoint < 2);
60
61 if (isLocal() && handles().size() == 5) {
62 // here we can just return since we don't want to do anything
63 // so we're returning a NaN
64 // but only if we don't have a point/axes it was already using
65
66 QRectF rect = getLocalRect();
67 bool insideLocalRect = rect.contains(point);
68 if (!insideLocalRect && (!isLastUsedPointCorrectNow || !m_hasBeenInsideLocalRect)) {
69 return QPointF(qQNaN(), qQNaN());
70 } else if (insideLocalRect) {
72 }
73 }
74
75 if (!isLastUsedPointCorrectNow && KisAlgebra2D::norm(point - strokeBegin) < moveThreshold) {
76 return strokeBegin;
77 }
78
79 if (!snapToAny && isLastUsedPointCorrectNow) {
80 possibleHandles = QList<int>({m_lastUsedPoint});
81 } else {
82 if (m_useVertical) {
83 possibleHandles = QList<int>({0, 1, 2});
84 } else {
85 possibleHandles = QList<int>({0, 1});
86 }
87 }
88
89 Q_FOREACH (int vpIndex, possibleHandles) {
90 QPointF vp = *handles()[vpIndex];
91 double dist = 0;
92 QPointF pt = QPointF();
93 QLineF snapLine = QLineF();
94
95 // TODO: Would be a good idea to generalize this whole routine
96 // in KisAlgebra2d, as it's all lifted from the vanishing
97 // point assistant and parallel ruler assistant, and by
98 // extension the perspective assistant...
99 qreal dx = point.x() - strokeBegin.x();
100 qreal dy = point.y() - strokeBegin.y();
101
102 if (vp != *handles()[2]) {
103 snapLine = QLineF(vp, strokeBegin);
104 } else {
105 QLineF vertical = QLineF(*handles()[0],*handles()[1]).normalVector();
106 snapLine = QLineF(vertical.p1(), vertical.p2());
107 QPointF translation = (vertical.p1()-strokeBegin)*-1.0;
108 snapLine = snapLine.translated(translation);
109 }
110
111 dx = snapLine.dx();
112 dy = snapLine.dy();
113
114 const qreal dx2 = dx * dx;
115 const qreal dy2 = dy * dy;
116 const qreal invsqrlen = 1.0 / (dx2 + dy2);
117
118 pt = QPointF(dx2 * point.x() + dy2 * snapLine.x1() + dx * dy * (point.y() - snapLine.y1()),
119 dx2 * snapLine.y1() + dy2 * point.y() + dx * dy * (point.x() - snapLine.x1()));
120
121 pt *= invsqrlen;
122 dist = qAbs(pt.x() - point.x()) + qAbs(pt.y() - point.y());
123
124 if (dist < best_dist) {
125 best_pt = pt;
126 best_dist = dist;
127 m_lastUsedPoint = vpIndex;
128 }
129 }
130
131 return best_pt;
132}
qreal norm(const T &a)

References KisPaintingAssistant::getLocalRect(), KisPaintingAssistant::handles(), isAssistantComplete(), KisPaintingAssistant::isLocal(), KisPaintingAssistant::m_hasBeenInsideLocalRect, m_lastUsedPoint, m_useVertical, and KisAlgebra2D::norm().

◆ saveCustomXml()

void TwoPointAssistant::saveCustomXml ( QXmlStreamWriter * xml)
overridevirtual

Reimplemented from KisPaintingAssistant.

Definition at line 489 of file TwoPointAssistant.cc.

490{
491 xml->writeStartElement("gridDensity");
492 xml->writeAttribute("value", KisDomUtils::toString( this->gridDensity()));
493 xml->writeEndElement();
494 xml->writeStartElement("useVertical");
495 xml->writeAttribute("value", KisDomUtils::toString( (int)this->useVertical()));
496 xml->writeEndElement();
497 xml->writeStartElement("isLocal");
498 xml->writeAttribute("value", KisDomUtils::toString( (int)this->isLocal()));
499 xml->writeEndElement();
500
501}
QString toString(const QString &value)

References gridDensity(), KisPaintingAssistant::isLocal(), KisDomUtils::toString(), and useVertical().

◆ secondLocalHandle()

KisPaintingAssistantHandleSP TwoPointAssistant::secondLocalHandle ( ) const
overrideprotectedvirtual

secondLocalHandle Note: this doesn't guarantee it will be the bottomRight corner! For that, use getLocalRect().bottomRight() (and remember that for QRect bottomRight() works differently than for QRectF, so don't convert to QRect before accessing the corner)

Returns

Reimplemented from KisPaintingAssistant.

Definition at line 425 of file TwoPointAssistant.cc.

426{
427 if (handles().size() > LocalSecondHandle) {
428 return handles().at(LocalSecondHandle);
429 } else {
430 return nullptr;
431 }
432}

References KisPaintingAssistant::handles(), and LocalSecondHandle.

◆ setGridDensity()

void TwoPointAssistant::setGridDensity ( double density)

Definition at line 448 of file TwoPointAssistant.cc.

449{
450 m_gridDensity = density;
451}

References m_gridDensity.

◆ setUseVertical()

void TwoPointAssistant::setUseVertical ( bool value)

Definition at line 458 of file TwoPointAssistant.cc.

459{
461}
float value(const T *src, size_t ch)

References m_useVertical, and value().

◆ useVertical()

bool TwoPointAssistant::useVertical ( )

Definition at line 453 of file TwoPointAssistant.cc.

454{
455 return m_useVertical;
456}

References m_useVertical.

Member Data Documentation

◆ m_canvas

KisCanvas2* TwoPointAssistant::m_canvas {nullptr}
private

Definition at line 76 of file TwoPointAssistant.h.

76{nullptr};

◆ m_gridDensity

double TwoPointAssistant::m_gridDensity {1.0}
private

Definition at line 79 of file TwoPointAssistant.h.

79{1.0};

◆ m_lastUsedPoint

int TwoPointAssistant::m_lastUsedPoint {-1}
private

Definition at line 82 of file TwoPointAssistant.h.

82{-1}; // last used vanishing point

◆ m_snapLine

QLineF TwoPointAssistant::m_snapLine
private

Definition at line 78 of file TwoPointAssistant.h.

◆ m_useVertical

bool TwoPointAssistant::m_useVertical {true}
private

Definition at line 80 of file TwoPointAssistant.h.

80{true};

The documentation for this class was generated from the following files: