Pencil2D Animation
Download Community News Docs Contribute
  • Overview
  • Articles
  • Code
  •  
  • Class List
  • Class Index
  • Class Hierarchy
  • Class Members
  • File List
Loading...
Searching...
No Matches
  • core_lib
  • src
  • graphics
  • vector
vectorimage.cpp
1/*
2
3Pencil2D - Traditional Animation Software
4Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5Copyright (C) 2012-2020 Matthew Chiawen Chang
6
7This program is free software; you can redistribute it and/or
8modify it under the terms of the GNU General Public License
9as published by the Free Software Foundation; version 2 of the License.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16*/
17#include "vectorimage.h"
18
19#include <cmath>
20#include <QImage>
21#include <QFile>
22#include <QFileInfo>
23#include <QDebug>
24#include <QXmlStreamWriter>
25#include "object.h"
26#include "util.h"
27
28
29VectorImage::VectorImage()
30{
31 deselectAll();
32}
33
34VectorImage::VectorImage(const VectorImage& v2) : KeyFrame(v2)
35{
36 deselectAll();
37 mCurves = v2.mCurves;
38 mArea = v2.mArea;
39 mOpacity = v2.mOpacity;
40}
41
42VectorImage::~VectorImage()
43{
44}
45
46VectorImage& VectorImage::operator=(const VectorImage& a) {
47
48 if (this == &a)
49 {
50 return *this; // a self-assignment
51 }
52
53 deselectAll();
54 KeyFrame::operator=(a);
55 mCurves = a.mCurves;
56 mArea = a.mArea;
57 mOpacity = a.mOpacity;
58 modification();
59 return *this;
60}
61
62VectorImage* VectorImage::clone() const
63{
64 VectorImage* v = new VectorImage(*this);
65 v->setFileName(""); // don't link to the file of the source vector image
66 return v;
67}
68
73bool VectorImage::read(QString filePath)
74{
75 QFileInfo fileInfo(filePath);
76 if (fileInfo.isDir())
77 {
78 return false;
79 }
80
81 QFile file(filePath);
82 if (!file.open(QFile::ReadOnly))
83 {
84 return false;
85 }
86
87 QDomDocument doc;
88 if (!doc.setContent(&file)) return false; // this is not a XML file
89 QDomDocumentType type = doc.doctype();
90 if (type.name() != "PencilVectorImage") return false; // this is not a Pencil document
91
92 QDomElement element = doc.documentElement();
93 if (element.tagName() == "image")
94 {
95 if (element.attribute("type") == "vector")
96 {
97 loadDomElement(element);
98 }
99 }
100
101 setFileName(filePath);
102 setModified(false);
103 return true;
104}
105
112Status VectorImage::write(QString filePath, QString format)
113{
114 DebugDetails debugInfo;
115 debugInfo << "VectorImage::write";
116 debugInfo << QString("filePath = ").append(filePath);
117 debugInfo << QString("format = ").append(format);
118
119 QFile file(filePath);
120 bool result = file.open(QIODevice::WriteOnly);
121 if (!result)
122 {
123 qDebug() << "VectorImage - Cannot write file" << filePath << file.error();
124 debugInfo << ("file.error() = " + file.errorString());
125 return Status(Status::FAIL, debugInfo);
126 }
127
128 if (format != "VEC")
129 {
130 debugInfo << "Unrecognized format";
131 return Status(Status::FAIL, debugInfo);
132 }
133
134 QXmlStreamWriter xmlStream(&file);
135 xmlStream.setAutoFormatting(true);
136 xmlStream.writeStartDocument();
137 xmlStream.writeDTD("<!DOCTYPE PencilVectorImage>");
138
139 xmlStream.writeStartElement("image");
140 xmlStream.writeAttribute("type", "vector");
141
142 Status st = createDomElement(xmlStream);
143 if (!st.ok())
144 {
145 debugInfo.collect(st.details());
146 debugInfo << "- xml creation failed";
147 return Status(Status::FAIL, debugInfo);
148 }
149 xmlStream.writeEndElement(); // Close image element
150 xmlStream.writeEndDocument();
151
152 setFileName(filePath);
153 return Status::OK;
154}
155
161Status VectorImage::createDomElement(QXmlStreamWriter& xmlStream)
162{
163 DebugDetails debugInfo;
164 debugInfo << "VectorImage::createDomElement";
165
166 for (int i = 0; i < mCurves.size(); i++)
167 {
168 Status st = mCurves[i].createDomElement(xmlStream);
169 if (!st.ok())
170 {
171 debugInfo.collect(st.details());
172 debugInfo << QString("- m_curves[%1] failed to write").arg(i);
173 return Status(Status::FAIL, debugInfo);
174 }
175 }
176 for (int i = 0; i < mArea.size(); i++)
177 {
178 Status st = mArea[i].createDomElement(xmlStream);
179 if (!st.ok())
180 {
181 debugInfo.collect(st.details());
182 debugInfo << QString("- area[%1] failed to write").arg(i);
183 return Status(Status::FAIL, debugInfo);
184 }
185 }
186 return Status::OK;
187}
188
193void VectorImage::loadDomElement(QDomElement element)
194{
195 QDomNode atomTag = element.firstChild(); // an atom in a vector picture is a curve or an area
196 while (!atomTag.isNull())
197 {
198 QDomElement atomElement = atomTag.toElement();
199 if (!atomElement.isNull())
200 {
201 if (atomElement.tagName() == "curve")
202 {
203 BezierCurve newCurve;
204 newCurve.loadDomElement(atomElement);
205 mCurves.append(newCurve);
206 }
207 if (atomElement.tagName() == "area")
208 {
209 BezierArea newArea;
210 newArea.loadDomElement(atomElement);
211 addArea(newArea);
212 }
213 }
214 atomTag = atomTag.nextSibling();
215 }
216 clean();
217}
218
219BezierCurve& VectorImage::curve(int i)
220{
221 return mCurves[i];
222}
223
230void VectorImage::addPoint(int curveNumber, int vertexNumber, qreal fraction)
231{
232 mCurves[curveNumber].addPoint(vertexNumber, fraction);
233 // updates the bezierAreas
234 for (int j = 0; j < mArea.size(); j++)
235 {
236 // shift the references of all the points beyond the new point
237 for (int k = 0; k < mArea.at(j).mVertex.size(); k++)
238 {
239 if (mArea[j].getVertexRef(k).curveNumber == curveNumber)
240 {
241 if (mArea[j].getVertexRef(k).vertexNumber >= vertexNumber)
242 {
243 mArea[j].mVertex[k].vertexNumber++;
244 }
245 }
246 }
247 // insert the new point in the area if necessary
248 for (int k = 1; k < mArea.at(j).mVertex.size(); k++)
249 {
250 if (VertexRef(curveNumber, vertexNumber + 1) == mArea.at(j).mVertex.at(k)) // area[j].vertex[k] == VertexRef(curveNumber, vertexNumber+1)
251 {
252 if (VertexRef(curveNumber, vertexNumber - 1) == mArea.at(j).mVertex.at(k - 1))
253 {
254 mArea[j].mVertex.insert(k, VertexRef(curveNumber, vertexNumber));
255 }
256 }
257 if (VertexRef(curveNumber, vertexNumber - 1) == mArea.at(j).mVertex.at(k))
258 {
259 if (VertexRef(curveNumber, vertexNumber + 1) == mArea.at(j).mVertex.at(k - 1))
260 {
261 mArea[j].mVertex.insert(k, VertexRef(curveNumber, vertexNumber));
262 }
263 }
264 }
265 }
266 modification();
267}
268
273void VectorImage::removeCurveAt(int i)
274{
275 // first change the curve numbers in the areas
276 for (int j = 0; j < mArea.size(); j++)
277 {
278 for (int k = 0; k < mArea.at(j).mVertex.size(); k++)
279 {
280 if (mArea.at(j).mVertex[k].curveNumber > i) { mArea[j].mVertex[k].curveNumber--; }
281 }
282 }
283 // then remove curve
284 mCurves.removeAt(i);
285 modification();
286}
287
295void VectorImage::insertCurve(int position, BezierCurve& newCurve, qreal factor, bool interacts)
296{
297 if (newCurve.getVertexSize() < 1) // security - a new curve should have a least 2 vertices
298 return;
299
300 // Does the curve interact with others or with itself?
301 if (interacts)
302 {
303 // tolerance for taking the intersection as an existing vertex on a curve
304 qreal tol = qMax(newCurve.getWidth() / factor, 3.0 / factor);
305 //qDebug() << "tolerance" << tol;
306
307 checkCurveExtremity(newCurve, tol);
308 checkCurveIntersections(newCurve, tol);
309 }
310
311
312 // Append or insert the curve in the list
313 if (position < 0 || position > mCurves.size() - 1)
314 {
315 mCurves.append(newCurve);
316 }
317 else
318 {
319 // If it's an insert we have to shift the curve numbers in the areas
320 for (int i = 0; i < mArea.size(); i++)
321 {
322 for (int j = 0; j < mArea.at(i).mVertex.size(); j++)
323 {
324 if (mArea.at(i).mVertex[j].curveNumber >= position) {
325 mArea[i].mVertex[j].curveNumber++;
326 }
327 }
328 }
329 mCurves.insert(position, newCurve);
330 }
331 updateImageSize(newCurve);
332 modification();
333}
334
341void VectorImage::addCurve(BezierCurve& newCurve, qreal factor, bool interacts)
342{
343 insertCurve(-1, newCurve, factor, interacts);
344}
345
351void VectorImage::checkCurveExtremity(BezierCurve& newCurve, qreal tolerance)
352{
353 // finds if the new curve is closed
354 QPointF P = newCurve.getVertex(-1);
355 QPointF Q = newCurve.getVertex(newCurve.getVertexSize() - 1);
356 if (BezierCurve::eLength(P - Q) < tolerance)
357 {
358 newCurve.setVertex(newCurve.getVertexSize() - 1, P);
359 }
360
361 // finds if the first or last point of the new curve is close to other curves
362 for (int i = 0; i < mCurves.size(); i++) // for each other curve
363 {
364 for (int j = 0; j < mCurves.at(i).getVertexSize(); j++) // for each cubic section of the other curve
365 {
366 QPointF P = newCurve.getVertex(-1);
367 QPointF Q = newCurve.getVertex(newCurve.getVertexSize() - 1);
368 QPointF P1 = mCurves.at(i).getVertex(j - 1);
369 QPointF P2 = mCurves.at(i).getVertex(j);
370 qreal tol3 = 2.0*sqrt(0.25*((P1 - P2).x()*(P1 - P2).x() + (P1 - P2).y()*(P1 - P2).y()) + tolerance*tolerance);
371 qreal dist1 = BezierCurve::eLength(P - P1);
372 qreal dist2 = BezierCurve::eLength(P - P2);
373 if (dist1 <= 0.2*tolerance)
374 {
375 newCurve.setVertex(-1, P1); //qDebug() << "--b " << P1;
376 }
377 else
378 {
379 if (dist2 <= 0.2*tolerance)
380 {
381 newCurve.setVertex(-1, P2); //qDebug() << "--c " << P2;
382 }
383 else
384 {
385 if (dist1 + dist2 <= 3 * tol3) // preselection, to speed up
386 {
387 QPointF nearestPoint = P;
388 qreal t = -1.0;
389 qreal distance = BezierCurve::findDistance(mCurves[i], j, P, nearestPoint, t);
390 if (distance < tolerance)
391 {
392 newCurve.setOrigin(nearestPoint); //qDebug() << "--d " << nearestPoint;
393 addPoint(i, j, t);
394 }
395 }
396 }
397 }
398
399 dist1 = BezierCurve::eLength(Q - P1);
400 dist2 = BezierCurve::eLength(Q - P2);
401 if (dist1 <= 0.2*tolerance)
402 {
403 newCurve.setLastVertex(P1); //qDebug() << "--e " << P1;
404 }
405 else
406 {
407 if (dist2 <= 0.2*tolerance)
408 {
409 newCurve.setLastVertex(P2); //qDebug() << "--f " << P2;
410 }
411 else
412 {
413 if (dist1 + dist2 <= 3 * tol3) // pre-selection, to speed up
414 {
415 QPointF nearestPoint = Q;
416 qreal t = -1.0;
417 qreal distance = BezierCurve::findDistance(mCurves[i], j, Q, nearestPoint, t);
418 if (distance < tolerance)
419 {
420 newCurve.setLastVertex(nearestPoint); //qDebug() << "--g " << nearestPoint;
421 addPoint(i, j, t);
422 }
423 }
424 }
425 //qDebug() << "Modif last";
426 }
427 }
428 }
429 modification();
430}
431
437void VectorImage::checkCurveIntersections(BezierCurve& newCurve, qreal tolerance)
438{
439 // finds if the new curve intersects itself
440 for (int k = 0; k < newCurve.getVertexSize(); k++) // for each cubic section of the new curve
441 {
442 for (int j = k + 1; j < newCurve.getVertexSize(); j++) // for each other cubic section of the new curve
443 {
444 QList<Intersection> intersections;
445 bool intersection = BezierCurve::findIntersection(newCurve, k, newCurve, j, intersections);
446 if (intersection)
447 {
448 //qDebug() << "INTERSECTION" << intersectionPoint << t1 << t2;
449 //newCurve.addPoint(k, intersectionPoint);
450 newCurve.addPoint(k, intersections[0].t1); //qDebug() << "--a " << newCurve.getVertex(k) << newCurve.getVertex(k+1);
451 k++;
452 j++;
453 //newCurve.addPoint(j, intersectionPoint);
454 newCurve.addPoint(j, intersections[0].t2); //qDebug() << "--a " << newCurve.getVertex(j) << newCurve.getVertex(j+1);
455 j++;
456 }
457 }
458 }
459
460 // finds if the new curve interesects other curves
461 for (int k = 0; k < newCurve.getVertexSize(); k++) // for each cubic section of the new curve
462 {
463 //if (k==0) L1 = QLineF(P1 + 1.5*tol*(P1-Q1)/BezierCurve::eLength(P1-Q1), Q1); // we extend slightly the line for the near point
464 //if (k==newCurve.getVertexSize()-1) L1 = QLineF(P1, Q1- 1.5*tol*(P1-Q1)/BezierCurve::eLength(P1-Q1)); // we extend slightly the line for the last point
465 //QPointF extension1 = 1.5*tol*(P1-Q1)/BezierCurve::eLength(P1-Q1);
466 //L1 = QLineF(P1 + extension1, Q1 - extension1);
467 for (int i = 0; i < mCurves.size(); i++) // for each other curve // TO DO: should only loop on "nearby" curves instead of all
468 {
469 // ---- finds if the first or last point of the other curve is close to the current cubic section of the new curve
470 QPointF P = mCurves.at(i).getVertex(-1);
471 QPointF Q = mCurves.at(i).getVertex(mCurves.at(i).getVertexSize() - 1);
472 QPointF P1 = newCurve.getVertex(k - 1);
473 QPointF P2 = newCurve.getVertex(k);
474 qreal tol3 = 2.0*sqrt(0.25*((P1 - P2).x()*(P1 - P2).x() + (P1 - P2).y()*(P1 - P2).y()) + tolerance*tolerance);
475 qreal dist1 = BezierCurve::eLength(P - P1);
476 qreal dist2 = BezierCurve::eLength(P - P2);
477
478 if (dist1 < 0.2*tolerance)
479 {
480 mCurves[i].setVertex(-1, P1); // memo: curve.at(i) is just a copy which can be read, curve[i] is a reference which can be modified
481 }
482 else
483 {
484 if (dist2 < 0.2*tolerance)
485 {
486 mCurves[i].setVertex(-1, P2);
487 }
488 else
489 {
490 if (dist1 + dist2 < 3 * tol3)
491 {
492 // TO DO: find a better intersection point
493 QPointF nearestPoint = P;
494 qreal t = -1.0;
495 qreal distance = BezierCurve::findDistance(newCurve, k, P, nearestPoint, t);
496 //qDebug() << "OK1" << t;
497 if (distance < tolerance)
498 {
499 P = nearestPoint;
500 //m_curves[i].setOrigin(P);
501 //newCurve.addPoint(k, P); //qDebug() << "--i " << P;
502 }
503 }
504 }
505 //qDebug() << "Modif first";
506 }
507 dist1 = BezierCurve::eLength(Q - P1);
508 dist2 = BezierCurve::eLength(Q - P2);
509 if (dist1 < 0.2*tolerance)
510 {
511 mCurves[i].setVertex(mCurves.at(i).getVertexSize() - 1, P1);
512 }
513 else
514 {
515 if (dist2 < 0.2*tolerance)
516 {
517 mCurves[i].setVertex(mCurves.at(i).getVertexSize() - 1, P2);
518 }
519 else
520 {
521 if (dist1 + dist2 < 3 * tol3)
522 {
523 // TO DO: find a better intersection point
524 QPointF nearestPoint = Q;
525 qreal t = -1.0;
526 qreal distance = BezierCurve::findDistance(newCurve, k, Q, nearestPoint, t);
527 //qDebug() << "OK2" << t;
528 if (distance < tolerance)
529 {
530 Q = nearestPoint;
531 //m_curves[i].setLastVertex(Q);
532 //newCurve.addPoint(k, Q); //qDebug() << "--j " << Q;
533 }
534 }
535 }
536 //qDebug() << "Modif first";
537 }
538
539 // ---- finds if any cubic section of the other curve intersects the current cubic section of the new curve
540 for (int j = 0; j < mCurves.at(i).getVertexSize(); j++) // for each cubic section of the other curve
541 {
542 QList<Intersection> intersections;
543 bool intersection = BezierCurve::findIntersection(newCurve, k, mCurves.at(i), j, intersections);
544 if (intersection)
545 {
546 //qDebug() << "Found " << intersections.size() << " intersections";
547 QPointF intersectionPoint = intersections[0].point;
548 qreal t1 = intersections[0].t1;
549 qreal t2 = intersections[0].t2;
550 if (BezierCurve::eLength(intersectionPoint - newCurve.getVertex(k - 1)) <= 0.1*tolerance) // the first point is close to the intersection
551 {
552 newCurve.setVertex(k - 1, intersectionPoint); //qDebug() << "--k " << intersectionPoint;
553 //qDebug() << "--------- recal " << k-1 << intersectionPoint;
554 }
555 else
556 {
557 if (BezierCurve::eLength(intersectionPoint - newCurve.getVertex(k)) <= 0.1*tolerance) // the second point is close to the intersection
558 {
559 newCurve.setVertex(k, intersectionPoint); //qDebug() << "--l " << intersectionPoint;
560 //qDebug() << "-------- recal " << k << intersectionPoint;
561 }
562 else // none of the point is close to the intersection -> we add a new point
563 {
564 //newCurve.addPoint(k, intersectionPoint);
565 newCurve.addPoint(k, t1); //qDebug() << "--m " << newCurve.getVertex(k);
566 //qDebug() << "----- add " << k << newCurve.getVertex(k);
567 //k++;
568 }
569 }
570 if (BezierCurve::eLength(intersectionPoint - mCurves.at(i).getVertex(j - 1)) <= 0.1*tolerance) // the first point is close to the intersection
571 {
572 mCurves[i].setVertex(j - 1, intersectionPoint); //qDebug() << "--n " << intersectionPoint;
573 //qDebug() << "-------- recal2 " << j-1 << intersectionPoint;
574 }
575 else
576 {
577 if (BezierCurve::eLength(intersectionPoint - mCurves.at(i).getVertex(j)) <= 0.1*tolerance) // the second point is close to the intersection
578 {
579 mCurves[i].setVertex(j, intersectionPoint); //qDebug() << "--o " << intersectionPoint;
580 //qDebug() << "-------- recal2 " << j << intersectionPoint;
581 }
582 else // none of the point is close to the intersection -> we add a new point
583 {
584 addPoint(i, j, t2);
585 //qDebug() << "----- add2 " << j << curve[i].getVertex(j);
586 //j++;
587 }
588 }
589 }
590 }
591 }
592 }
593}
594
595void VectorImage::select(QRectF rectangle)
596{
597 for (int i = 0; i < mCurves.size(); i++)
598 {
599 bool bSelected = mCurves[i].intersects(rectangle);
600 setSelected(i, bSelected);
601 }
602
603 for (int i = 0; i < mArea.size(); i++)
604 {
605 bool b = rectangle.contains(mArea[i].mPath.boundingRect());
606 setAreaSelected(i, b);
607 }
608 modification();
609}
610
616void VectorImage::setSelected(int curveNumber, bool YesOrNo)
617{
618 if (mCurves.isEmpty()) return;
619
620 mCurves[curveNumber].setSelected(YesOrNo);
621
622 if (YesOrNo)
623 mSelectionRect |= mCurves[curveNumber].getBoundingRect();
624 modification();
625}
626
633void VectorImage::setSelected(int curveNumber, int vertexNumber, bool YesOrNo)
634{
635 if (mCurves.isEmpty()) return;
636 mCurves[curveNumber].setSelected(vertexNumber, YesOrNo);
637 QPointF vertex = getVertex(curveNumber, vertexNumber);
638 if (YesOrNo) mSelectionRect |= QRectF(vertex.x(), vertex.y(), 0.0, 0.0);
639
640 modification();
641}
642
648void VectorImage::setSelected(VertexRef vertexRef, bool YesOrNo)
649{
650 setSelected(vertexRef.curveNumber, vertexRef.vertexNumber, YesOrNo);
651}
652
658void VectorImage::setSelected(QList<int> curveList, bool YesOrNo)
659{
660 for (int i = 0; i < curveList.size(); i++)
661 {
662 setSelected(curveList.at(i), YesOrNo);
663 }
664}
665
671void VectorImage::setSelected(QList<VertexRef> vertexList, bool YesOrNo)
672{
673 for (int i = 0; i < vertexList.size(); i++)
674 {
675 setSelected(vertexList.at(i), YesOrNo);
676 }
677}
678
684void VectorImage::setAreaSelected(int areaNumber, bool YesOrNo)
685{
686 mArea[areaNumber].setSelected(YesOrNo);
687 if (YesOrNo) mSelectionRect |= mArea[areaNumber].mPath.boundingRect();
688 modification();
689}
690
696bool VectorImage::isAreaSelected(int areaNumber)
697{
698 return mArea[areaNumber].isSelected();
699}
700
705bool VectorImage::isPathFilled()
706{
707 bool filled = false;
708 QList<int> curveNumbers = getSelectedCurveNumbers();
709 for (int curveNum : curveNumbers)
710 {
711 //qDebug() << mCurves[curveNum].isFilled();
712 if (mCurves[curveNum].isSelected())
713 {
714 // FIXME: something wrong here.
715 filled = mCurves[curveNum].isFilled();
716 }
717 }
718 return filled;
719}
720
726bool VectorImage::isSelected(int curveNumber)
727{
728 return mCurves[curveNumber].isSelected();
729}
730
737bool VectorImage::isSelected(int curveNumber, int vertexNumber)
738{
739 return mCurves[curveNumber].isSelected(vertexNumber);
740}
741
747bool VectorImage::isSelected(VertexRef vertexRef)
748{
749 return isSelected(vertexRef.curveNumber, vertexRef.vertexNumber);
750}
751
757bool VectorImage::isSelected(QList<int> curveList)
758{
759 bool result = true;
760 for (int i = 0; i < curveList.size(); i++)
761 {
762 result &= isSelected(curveList.at(i));
763 }
764 return result;
765}
766
772bool VectorImage::isSelected(QList<VertexRef> vertexList)
773{
774 bool result = true;
775 for (int i = 0; i < vertexList.size(); i++)
776 {
777 result &= isSelected(vertexList.at(i));
778 }
779 return result;
780}
781
786int VectorImage::getFirstSelectedCurve()
787{
788 int result = -1;
789 for (int i = 0; i < mCurves.size() && result == -1; i++)
790 {
791 if (isSelected(i)) result = i;
792 }
793 return result;
794}
795
800int VectorImage::getFirstSelectedArea()
801{
802 int result = -1;
803 for (int i = 0; i < mArea.size() && result == -1; i++)
804 {
805 if (isAreaSelected(i)) result = i;
806 }
807 return result;
808}
809
813void VectorImage::selectAll()
814{
815 for (int i = 0; i < mCurves.size(); i++)
816 {
817 setSelected(i, true);
818 }
819 mSelectionTransformation.reset();
820}
821
826bool VectorImage::isAnyCurveSelected()
827{
828 if (mCurves.isEmpty()) return false;
829 for (int curve = 0; curve < mCurves.size(); curve++)
830 {
831 if (mCurves[curve].isSelected()) return true;
832 }
833 return false;
834}
835
839void VectorImage::deselectAll()
840{
841 if (mCurves.empty()) return;
842 for (int i = 0; i < mCurves.size(); i++)
843 {
844 mCurves[i].setSelected(false);
845 }
846 for (int i = 0; i < mArea.size(); i++)
847 {
848 mArea[i].setSelected(false);
849 }
850 mSelectionRect = QRectF(0, 0, 0, 0);
851 mSelectionTransformation.reset();
852 modification();
853}
854
859void VectorImage::setSelectionRect(QRectF rectangle)
860{
861 mSelectionRect = rectangle;
862 select(rectangle);
863}
864
865QRectF VectorImage::getBoundsOfTransformedCurves() const
866{
867 QRectF bounds;
868 for (int i = 0; i < mCurves.size(); i++)
869 {
870 BezierCurve curve;
871 if (mCurves.at(i).isPartlySelected())
872 {
873 curve = mCurves[i].transformed(mSelectionTransformation);
874 bounds |= curve.getBoundingRect();
875 }
876 }
877 return bounds;
878}
879
883void VectorImage::calculateSelectionRect()
884{
885 mSelectionRect = QRectF(0, 0, 0, 0);
886 for (int i = 0; i < mCurves.size(); i++)
887 {
888 if (mCurves.at(i).isPartlySelected())
889 mSelectionRect |= mCurves[i].getBoundingRect();
890 }
891}
892
897void VectorImage::setSelectionTransformation(QTransform transform)
898{
899 mSelectionTransformation = transform;
900 modification();
901}
902
906void VectorImage::deleteSelection()
907{
908 // ---- deletes areas
909 for (int i = 0; i < mArea.size(); i++)
910 {
911 if (mArea[i].isSelected())
912 {
913 mArea.removeAt(i);
914 i--;
915 }
916 }
917 // ---- deletes curves
918 for (int i = 0; i < mCurves.size(); i++)
919 {
920 if (mCurves[i].isSelected())
921 {
922 // eliminates areas which are associated to this curve
923 for (int j = 0; j < mArea.size(); j++)
924 {
925 bool toBeDeleted = false;
926 for (int k = 0; k < mArea.at(j).mVertex.size(); k++)
927 {
928 if (mArea.at(j).mVertex[k].curveNumber == i) { toBeDeleted = true; }
929 if (mArea.at(j).mVertex[k].curveNumber > i)
930 {
931 mArea[j].mVertex[k].curveNumber = mArea[j].mVertex[k].curveNumber - 1;
932 }
933 }
934 if (toBeDeleted)
935 {
936 mArea.removeAt(j);
937 j--;
938 }
939 }
940 mCurves.removeAt(i);
941 i--;
942 }
943 }
944 modification();
945}
946
952void VectorImage::removeVertex(int curve, int vertex)
953{
954 // first eliminates areas which are associated to this point
955 for (int j = 0; j < mArea.size(); j++)
956 {
957 bool toBeDeleted = false;
958 for (int k = 0; k < mArea.at(j).mVertex.size(); k++)
959 {
960 if (mArea.at(j).mVertex[k].curveNumber == curve && mArea.at(j).mVertex[k].vertexNumber == vertex) { toBeDeleted = true; }
961 //if (area.at(j).vertex[k].curveNumber > i) { area[j].vertex[k].curveNumber = area[j].vertex[k].curveNumber - 1; }
962 }
963 if (toBeDeleted)
964 {
965 mArea.removeAt(j);
966 j--;
967 }
968 }
969 // then eliminates the point
970 if (mCurves[curve].getVertexSize() > 1)
971 {
972 // second possibility: we split the curve into two parts:
973 if (vertex == -1 || vertex == getCurveSize(curve) - 1) // we just remove the first or last point
974 {
975 mCurves[curve].removeVertex(vertex);
976 vertex--;
977 // we also need to update the areas
978 for (int j = 0; j < mArea.size(); j++)
979 {
980 for (int k = 0; k < mArea.at(j).mVertex.size(); k++)
981 {
982 if (mArea.at(j).mVertex[k].curveNumber == curve && mArea.at(j).mVertex[k].vertexNumber > vertex) { mArea[j].mVertex[k].vertexNumber--; }
983 }
984 }
985 }
986 else
987 {
988 int n = getCurveSize(curve);
989 BezierCurve newCurve = mCurves.at(curve); // duplicate curve
990 for (int p = vertex; p < n; p++) // removes the end of of the curve i (after m, included) -> left part
991 {
992 mCurves[curve].removeVertex(getCurveSize(curve) - 1);
993 }
994 for (int p = -1; p <= vertex; p++) // removes the beginning of the new curve (before m, included) -> right part
995 {
996 newCurve.removeVertex(-1);
997 }
998 //if (newCurve.getVertexSize() > 0) curve.insert(i+1, newCurve);
999 if (newCurve.getVertexSize() > 0) mCurves.append(newCurve); // insert the right part if it has more than one point
1000 // we also need to update the areas
1001 for (int j = 0; j < mArea.size(); j++)
1002 {
1003 for (int k = 0; k < mArea.at(j).mVertex.size(); k++)
1004 {
1005 if (mArea.at(j).mVertex[k].curveNumber == curve && mArea.at(j).mVertex[k].vertexNumber > vertex)
1006 {
1007 mArea[j].mVertex[k].curveNumber = mCurves.size() - 1;
1008 mArea[j].mVertex[k].vertexNumber = mArea[j].mVertex[k].vertexNumber - vertex - 1;
1009 }
1010 }
1011 }
1012
1013 if (getCurveSize(curve) < 1) // the left part has less than two points so we remove it
1014 {
1015 removeCurveAt(curve);
1016 curve--;
1017 }
1018 }
1019 }
1020 else // there are just two points left, so we remove the whole curve
1021 {
1022 removeCurveAt(curve);
1023 curve--;
1024 }
1025}
1026
1030void VectorImage::deleteSelectedPoints()
1031{
1032 for (int i = 0; i < mCurves.size(); i++)
1033 {
1034 for (int m = -1; m < getCurveSize(i); m++)
1035 {
1036 if (mCurves.at(i).isSelected(m)) // point m of curve i is selected
1037 {
1038 removeVertex(i, m);
1039 }
1040 }
1041 }
1042 modification();
1043}
1044
1049void VectorImage::paste(VectorImage& vectorImage)
1050{
1051 mSelectionRect = QRect(0, 0, 0, 0);
1052 int n = mCurves.size();
1053 QList<int> selectedCurves;
1054
1055 bool hasSelection = getFirstSelectedCurve() < -1;
1056
1057 for (int i = 0; i < vectorImage.mCurves.size(); i++)
1058 {
1059 // If nothing is selected, paste everything
1060 if (!hasSelection || vectorImage.mCurves.at(i).isSelected())
1061 {
1062 mCurves.append(vectorImage.mCurves.at(i));
1063 selectedCurves << i;
1064 mSelectionRect |= vectorImage.mCurves[i].getBoundingRect();
1065 }
1066 }
1067 for (int i = 0; i < vectorImage.mArea.size(); i++)
1068 {
1069 BezierArea newArea = vectorImage.mArea.at(i);
1070 bool ok = true;
1071 for (int j = 0; j < newArea.mVertex.size(); j++)
1072 {
1073 int curveNumber = newArea.mVertex.at(j).curveNumber;
1074 int vertexNumber = newArea.mVertex.at(j).vertexNumber;
1075
1076 // If nothing is selected, paste everything
1077 //
1078 if (!hasSelection || vectorImage.mCurves.at(curveNumber).isSelected())
1079 {
1080 newArea.mVertex[j] = VertexRef(selectedCurves.indexOf(curveNumber) + n, vertexNumber);
1081 }
1082 else
1083 {
1084 ok = false;
1085 }
1086 }
1087 if (ok) mArea.append(newArea);
1088 }
1089 modification();
1090}
1091
1097int VectorImage::getColorNumber(QPointF point)
1098{
1099 int result = -1;
1100 int areaNumber = getLastAreaNumber(point);
1101 if (areaNumber != -1)
1102 {
1103 result = mArea[areaNumber].mColorNumber;
1104 }
1105 return result;
1106}
1112int VectorImage::getCurvesColor(int curve)
1113{
1114 int result = -1;
1115 if (curve > -1)
1116 {
1117 result = mCurves[curve].getColorNumber();
1118 }
1119 return result;
1120}
1121
1122bool VectorImage::isCurveVisible(int curve)
1123{
1124 if (curve > -1 && curve < mCurves.length())
1125 {
1126 return !mCurves[curve].isInvisible();
1127 }
1128 return false;
1129}
1130
1136bool VectorImage::usesColor(int index)
1137{
1138 for (int i = 0; i < mArea.size(); i++)
1139 {
1140 if (mArea[i].mColorNumber == index) return true;
1141 }
1142 for (int i = 0; i < mCurves.size(); i++)
1143 {
1144 if (mCurves[i].getColorNumber() == index) return true;
1145 }
1146 return false;
1147}
1148
1153void VectorImage::removeColor(int index)
1154{
1155 for (int i = 0; i < mArea.size(); i++)
1156 {
1157 int colorNumber = mArea[i].getColorNumber();
1158 if (colorNumber >= index && colorNumber > 0) {
1159 mArea[i].decreaseColorNumber();
1160 }
1161 }
1162 for (int i = 0; i < mCurves.size(); i++)
1163 {
1164 int colorNumber = mCurves[i].getColorNumber();
1165 if (colorNumber >= index && colorNumber > 0) {
1166 mCurves[i].decreaseColorNumber();
1167 }
1168 }
1169}
1170
1171void VectorImage::moveColor(int start, int end)
1172{
1173 for(int i=0; i< mArea.size(); i++)
1174 {
1175 if (mArea[i].getColorNumber() == start) mArea[i].setColorNumber(end);
1176 }
1177 for(int i=0; i< mCurves.size(); i++)
1178 {
1179 if (mCurves[i].getColorNumber() == start) mCurves[i].setColorNumber(end);
1180 }
1181}
1182
1191void VectorImage::paintImage(QPainter& painter,
1192 const Object& object,
1193 bool simplified,
1194 bool showThinCurves,
1195 bool antialiasing)
1196{
1197 painter.save();
1198 painter.setRenderHint(QPainter::Antialiasing, antialiasing);
1199
1200 painter.setClipping(false);
1201 QTransform painterMatrix = painter.transform();
1202
1203 QRect mappedViewRect = QRect(0, 0, painter.device()->width(), painter.device()->height());
1204 painterMatrix.inverted().mapRect(mappedViewRect);
1205
1206 // --- draw filled areas ----
1207 if (!simplified)
1208 {
1209 for (int i = 0; i < mArea.size(); i++)
1210 {
1211 updateArea(mArea[i]); // to do: if selected
1212
1213 // --- fill areas ---- //
1214 QColor color = object.getColor(mArea[i].mColorNumber).color;
1215
1216 painter.save();
1217 painter.setWorldMatrixEnabled(false);
1218
1219 if (mArea[i].isSelected())
1220 {
1221 painter.setBrush(QBrush(qPremultiply(color.rgba()), Qt::Dense2Pattern));
1222 }
1223 else
1224 {
1225 painter.setPen(QPen(QBrush(color), 1, Qt::NoPen, Qt::RoundCap, Qt::RoundJoin));
1226 painter.setBrush(QBrush(color, Qt::SolidPattern));
1227 }
1228
1229 painter.drawPath(painter.transform().map(mArea[i].mPath));
1230 painter.restore();
1231 painter.setWorldMatrixEnabled(true);
1232 painter.setRenderHint(QPainter::Antialiasing, antialiasing);
1233 painter.setClipping(false);
1234 }
1235 }
1236
1237 // ---- draw curves ----
1238 for (BezierCurve curve : mCurves)
1239 {
1240 curve.drawPath(painter, object, mSelectionTransformation, simplified, showThinCurves);
1241 painter.setClipping(false);
1242 }
1243 painter.restore();
1244}
1245
1249void VectorImage::clear()
1250{
1251 while (mCurves.size() > 0) { mCurves.removeAt(0); }
1252 while (mArea.size() > 0) { mArea.removeAt(0); }
1253 modification();
1254}
1255
1259void VectorImage::clean()
1260{
1261 for (int i = 0; i < mCurves.size(); i++)
1262 {
1263 if (mCurves.at(i).getVertexSize() == 0)
1264 {
1265 mCurves.removeAt(i);
1266 i--;
1267 }
1268 }
1269}
1270
1274void VectorImage::applySelectionTransformation()
1275{
1276 applySelectionTransformation(mSelectionTransformation);
1277}
1278
1283void VectorImage::applySelectionTransformation(QTransform transf)
1284{
1285 for (int i = 0; i < mCurves.size(); i++)
1286 {
1287 if (mCurves.at(i).isPartlySelected())
1288 {
1289 mCurves[i].transform(transf);
1290 }
1291 }
1292 calculateSelectionRect();
1293 mSelectionTransformation.reset();
1294 modification();
1295}
1296
1302void VectorImage::applyColorToSelectedCurve(int colorNumber)
1303{
1304 for (int i = 0; i < mCurves.size(); i++)
1305 {
1306 if (mCurves.at(i).isSelected()) mCurves[i].setColorNumber(colorNumber);
1307 }
1308 modification();
1309}
1310
1315void VectorImage::applyColorToSelectedArea(int colorNumber)
1316{
1317 for (int i = 0; i < mArea.size(); i++)
1318 {
1319 if (mArea.at(i).isSelected()) mArea[i].setColorNumber(colorNumber);
1320 }
1321 modification();
1322}
1323
1328void VectorImage::applyWidthToSelection(qreal width)
1329{
1330 for (int i = 0; i < mCurves.size(); i++)
1331 {
1332 if (mCurves.at(i).isSelected()) mCurves[i].setWidth(width);
1333 }
1334 modification();
1335}
1336
1341void VectorImage::applyFeatherToSelection(qreal feather)
1342{
1343 for (int i = 0; i < mCurves.size(); i++)
1344 {
1345 if (mCurves.at(i).isSelected()) mCurves[i].setFeather(feather);
1346 }
1347 modification();
1348}
1349
1354void VectorImage::applyOpacityToSelection(qreal opacity)
1355{
1356 Q_UNUSED(opacity);
1357 for (int i = 0; i < mCurves.size(); i++)
1358 {
1359 //if ( curve.at(i).isSelected()) curve[i].setOpacity(width);
1360 }
1361 modification();
1362}
1363
1368void VectorImage::applyInvisibilityToSelection(bool YesOrNo)
1369{
1370 for (int i = 0; i < mCurves.size(); i++)
1371 {
1372 if (mCurves.at(i).isSelected()) mCurves[i].setInvisibility(YesOrNo);
1373 }
1374 modification();
1375}
1376
1381void VectorImage::applyVariableWidthToSelection(bool YesOrNo)
1382{
1383 for (int i = 0; i < mCurves.size(); i++)
1384 {
1385 if (mCurves.at(i).isSelected()) {
1386 mCurves[i].setVariableWidth(YesOrNo);
1387 }
1388 }
1389 modification();
1390}
1391
1398QList<int> VectorImage::getCurvesCloseTo(QPointF P1, qreal maxDistance)
1399{
1400 QList<int> result;
1401 for (int j = 0; j < mCurves.size(); j++)
1402 {
1403 BezierCurve myCurve;
1404 if (mCurves[j].isPartlySelected())
1405 {
1406 myCurve = mCurves[j].transformed(mSelectionTransformation);
1407 }
1408 else
1409 {
1410 myCurve = mCurves[j];
1411 }
1412 if (myCurve.intersects(P1, maxDistance))
1413 {
1414 result.append(j);
1415 // store stroke for later use.
1416 mGetStrokedPath = myCurve.getStrokedPath(1.0, true);
1417 }
1418 }
1419 return result;
1420}
1421
1429VertexRef VectorImage::getClosestVertexTo(const BezierCurve& curve, int curveNum, QPointF thePoint)
1430{
1431 VertexRef result;
1432 result = VertexRef(-1, -1); // result = [-1, -1]
1433
1434 // distance of the closest point
1435 QPointF P2 = getVertex(0, 0);
1436 qreal minDistance = thePoint.dotProduct(QPointF(thePoint - P2), QPointF(thePoint - P2));
1437
1438 for (int vertexPoint = -1; vertexPoint < curve.getVertexSize(); vertexPoint++)
1439 {
1440 P2 = curve.getVertex(vertexPoint);
1441 qreal distance = thePoint.dotProduct(QPointF(thePoint - P2), QPointF(thePoint - P2));
1442
1443 if (distance < minDistance)
1444 {
1445 minDistance = distance;
1446 result = VertexRef(curveNum, vertexPoint);
1447 }
1448 }
1449 return result;
1450}
1451
1458QList<VertexRef> VectorImage::getVerticesCloseTo(QPointF P1, qreal maxDistance)
1459{
1460 QList<VertexRef> result;
1461
1462 // Square maxDistance rather than taking the square root for each distance
1463 maxDistance *= maxDistance;
1464
1465 for (int curve = 0; curve < mCurves.size(); curve++)
1466 {
1467 for (int vertex = -1; vertex < mCurves.at(curve).getVertexSize(); vertex++)
1468 {
1469 QPointF P2 = getVertex(curve, vertex);
1470 qreal distance = P1.dotProduct(QPointF(P1 - P2), QPointF(P1 - P2));
1471 if (distance < maxDistance)
1472 {
1473 result.append(VertexRef(curve, vertex));
1474 }
1475 }
1476 }
1477 return result;
1478}
1479
1487QList<VertexRef> VectorImage::getVerticesCloseTo(QPointF P1, qreal maxDistance, QList<VertexRef>* listOfPoints)
1488{
1489 QList<VertexRef> result;
1490 for (int j = 0; j < listOfPoints->size(); j++)
1491 {
1492 QPointF P2 = getVertex(listOfPoints->at(j));
1493 qreal distance = P1.dotProduct(QPointF(P1 - P2), QPointF(P1 - P2));
1494 if (distance < maxDistance)
1495 {
1496 result.append(listOfPoints->at(j));
1497 }
1498 }
1499 return result;
1500}
1501
1508QList<VertexRef> VectorImage::getVerticesCloseTo(VertexRef P1ref, qreal maxDistance)
1509{
1510 return getVerticesCloseTo(getVertex(P1ref), maxDistance);
1511}
1512
1520QList<VertexRef> VectorImage::getVerticesCloseTo(VertexRef P1ref, qreal maxDistance, QList<VertexRef>* listOfPoints)
1521{
1522 return getVerticesCloseTo(getVertex(P1ref), maxDistance, listOfPoints);
1523}
1524
1532QList<VertexRef> VectorImage::getAndRemoveVerticesCloseTo(QPointF P1, qreal maxDistance, QList<VertexRef>* listOfPoints)
1533{
1534 QList<VertexRef> result;
1535 for (int j = 0; j < listOfPoints->size(); j++)
1536 {
1537 QPointF P2 = getVertex(listOfPoints->at(j));
1538 qreal distance = P1.dotProduct(QPointF(P1 - P2), QPointF(P1 - P2));
1539 if (distance < maxDistance)
1540 {
1541 result.append(listOfPoints->at(j));
1542 listOfPoints->removeAt(j);
1543 }
1544 }
1545 return result;
1546}
1547
1555QList<VertexRef> VectorImage::getAndRemoveVerticesCloseTo(VertexRef P1Ref, qreal maxDistance, QList<VertexRef>* listOfPoints)
1556{
1557 return getAndRemoveVerticesCloseTo(getVertex(P1Ref), maxDistance, listOfPoints);
1558}
1559
1566QPointF VectorImage::getVertex(int curveNumber, int vertexNumber)
1567{
1568 QPointF result = QPointF(0, 0);
1569 if (curveNumber > -1 && curveNumber < mCurves.size())
1570 {
1571 BezierCurve myCurve = mCurves.at(curveNumber);
1572 if (myCurve.isPartlySelected())
1573 {
1574 myCurve = myCurve.transformed(mSelectionTransformation);
1575 }
1576
1577 if (vertexNumber > -2 && vertexNumber < myCurve.getVertexSize())
1578 {
1579 result = myCurve.getVertex(vertexNumber);
1580 }
1581 }
1582 return result;
1583}
1584
1590QPointF VectorImage::getVertex(VertexRef vertexRef)
1591{
1592 return getVertex(vertexRef.curveNumber, vertexRef.vertexNumber);
1593}
1594
1601QPointF VectorImage::getC1(int curveNumber, int vertexNumber)
1602{
1603 QPointF result = QPointF(0, 0);
1604 if (curveNumber > -1 && curveNumber < mCurves.size())
1605 {
1606 BezierCurve myCurve = mCurves.at(curveNumber);
1607 if (myCurve.isPartlySelected()) myCurve = myCurve.transformed(mSelectionTransformation);
1608 if (vertexNumber > -1 && vertexNumber < myCurve.getVertexSize())
1609 {
1610 result = myCurve.getC1(vertexNumber);
1611 }
1612 }
1613 return result;
1614}
1615
1621QPointF VectorImage::getC1(VertexRef vertexRef)
1622{
1623 return getC1(vertexRef.curveNumber, vertexRef.vertexNumber);
1624}
1625
1632QPointF VectorImage::getC2(int curveNumber, int vertexNumber)
1633{
1634 QPointF result = QPointF(0, 0);
1635 if (curveNumber > -1 && curveNumber < mCurves.size())
1636 {
1637 BezierCurve myCurve = mCurves.at(curveNumber);
1638 if (myCurve.isPartlySelected()) myCurve = myCurve.transformed(mSelectionTransformation);
1639 if (vertexNumber > -1 && vertexNumber < myCurve.getVertexSize())
1640 {
1641 result = myCurve.getC2(vertexNumber);
1642 }
1643 }
1644 return result;
1645}
1646
1652QPointF VectorImage::getC2(VertexRef vertexRef)
1653{
1654 return getC2(vertexRef.curveNumber, vertexRef.vertexNumber);
1655}
1656
1662QList<VertexRef> VectorImage::getCurveVertices(int curveNumber)
1663{
1664 QList<VertexRef> result;
1665
1666 if (curveNumber > -1 && curveNumber < mCurves.size())
1667 {
1668 BezierCurve myCurve = mCurves[curveNumber];
1669
1670 for (int k = -1; k < myCurve.getVertexSize(); k++)
1671 {
1672 VertexRef vertexRef = VertexRef(curveNumber, k);
1673 result.append(vertexRef);
1674 }
1675 }
1676
1677 return result;
1678}
1679
1684QList<VertexRef> VectorImage::getAllVertices()
1685{
1686 QList<VertexRef> result;
1687 for (int j = 0; j < mCurves.size(); j++)
1688 {
1689 for (int k = -1; k < mCurves.at(j).getVertexSize(); k++)
1690 {
1691 VertexRef vertexRef = VertexRef(j, k);
1692 result.append(vertexRef);
1693 }
1694 }
1695 // Add Area vertices
1696 return result;
1697}
1698
1704int VectorImage::getCurveSize(int curveNumber)
1705{
1706 if (curveNumber > -1 && curveNumber < mCurves.size())
1707 {
1708 return mCurves.at(curveNumber).getVertexSize();
1709 }
1710 else
1711 {
1712 return -1;
1713 }
1714}
1715
1720QList<BezierCurve> VectorImage::getSelectedCurves()
1721{
1722 QList<BezierCurve> curves;
1723 for (int curve = 0; curve < mCurves.size(); curve++)
1724 {
1725 if (mCurves[curve].isSelected())
1726 {
1727 curves.append(mCurves[curve]);
1728 }
1729 }
1730 return curves;
1731}
1732
1737QList<int> VectorImage::getSelectedCurveNumbers()
1738{
1739 QList<int> result;
1740 for (int curve = 0; curve < mCurves.size(); curve++)
1741 {
1742 if (mCurves[curve].isSelected())
1743 {
1744 result.append(curve);
1745 }
1746 }
1747 return result;
1748}
1749
1754int VectorImage::getNumOfCurvesSelected()
1755{
1756 int count = 0;
1757 for (int curve = 0; curve < mCurves.size(); curve++)
1758 {
1759 if (mCurves[curve].isSelected())
1760 {
1761 count++;
1762 }
1763 }
1764 return count;
1765}
1766
1772BezierArea VectorImage::getSelectedArea(QPointF currentPoint)
1773{
1774 for (int i = 0; i < mArea.size(); i++)
1775 {
1776 if (mArea[i].mPath.controlPointRect().contains(currentPoint))
1777 {
1778 return mArea[i];
1779 }
1780 }
1781 return BezierArea();
1782}
1783
1789void VectorImage::fillSelectedPath(int color)
1790{
1791 QList<VertexRef> vertexPath;
1792 QList<int> curveNumbers = getSelectedCurveNumbers();
1793 QList<BezierCurve> curves = getSelectedCurves();
1794 QList<VertexRef> vertexList;
1795 VertexRef vertex;
1796 for (int curve = 0; curve < getNumOfCurvesSelected(); curve++)
1797 {
1798 vertexList = getCurveVertices(curveNumbers[curve]);
1799 for (int i = 0; i < vertexList.size(); i++)
1800 {
1801 QPointF point = getVertex(vertexList[i]);
1802 vertex = getClosestVertexTo(curves[curve], curveNumbers[curve], point);
1803
1804 if (vertex.curveNumber != -1 && !vertexPath.contains(vertex))
1805 {
1806 vertexPath.append(vertex);
1807 }
1808 }
1809
1810 BezierArea bezierArea(vertexPath, color);
1811 addArea(bezierArea);
1812
1813 // set selected curves as filled
1814 mCurves[curveNumbers[curve]].setFilled(true);
1815
1816 // clear path for next area
1817 vertexPath.clear();
1818 }
1819
1820 modification();
1821}
1822
1829void VectorImage::fillContour(QList<QPointF> contourPath, int color)
1830{
1831 QList<VertexRef> vertexPath;
1832 VertexRef vertex;
1833
1834 BezierCurve lastCurve = getLastCurve();
1835 int lastCurveNum = getLastCurveNumber();
1836
1837 for (QPointF point : contourPath) {
1838 vertex = getClosestVertexTo(lastCurve, lastCurveNum, point);
1839
1840 if (vertex.curveNumber != -1 && !vertexPath.contains(vertex)) {
1841 vertexPath.append(vertex);
1842 }
1843 }
1844
1845 BezierArea bezierArea(vertexPath, color);
1846
1847 addArea(bezierArea);
1848 modification();
1849}
1850
1851//QList<QPointF> VectorImage::getfillContourPoints(QPoint point)
1852//{
1853// // We get the contour points from a bitmap version of the vector layer as it is much faster to process
1854// QImage* image = new QImage( mSize, QImage::Format_ARGB32_Premultiplied );
1855// image->fill(Qt::white);
1856// QPainter painter( image );
1857
1858// // Adapt the QWidget view coordinates to the QImage coordinates
1859// QTransform translate;
1860// translate.translate( mSize.width() / 2.f , mSize.height() / 2.f );
1861// painter.setTransform( translate );
1862// paintImage( painter, true, true, false );
1863
1864// QList<QPoint> queue; // queue all the pixels of the filled area (as they are found)
1865// QList<QPointF> contourPoints; // refs of points near the contour pixels
1866
1867// qreal maxWidth = mSize.width();
1868// qreal maxHeight = mSize.height();
1869
1870// // To keep track of the highest y contour point to make sure it is on the main contour and not inside.
1871// int highestY = point.y();
1872
1873// // Convert point to image coordinates as the image doesn't have the same coordinates origin as the
1874// // QWidget view
1875// QPointF startPoint((maxWidth / 2) + point.x(), (maxHeight / 2) + point.y());
1876// queue.append( startPoint.toPoint() );
1877
1878// // Check the color of the clicked point
1879// QRgb colorFrom = image->pixel(startPoint.x(), startPoint.y());
1880// QRgb colorTo = Qt::green;
1881
1882// QPoint currentPoint;
1883
1884// int leftX, rightX;
1885// bool foundLeftBound, foundRightBound;
1886
1887// // ----- flood fill and remember the contour pixels -> contourPixels
1888// // ----- from the standard flood fill algorithm
1889// // ----- http://en.wikipedia.org/wiki/Flood_fill
1890// while ( queue.size() > 0 ) {
1891
1892// // Get the first point in the queue and remove it afterwards
1893// currentPoint = queue.at(0);
1894// queue.removeAt(0);
1895
1896// // Inspect a line from edge to edge
1897// if (image->pixel(currentPoint.x(), currentPoint.y()) == colorFrom) {
1898// leftX = currentPoint.x();
1899// rightX = currentPoint.x();
1900
1901// foundLeftBound = false;
1902// foundRightBound = false;
1903
1904// while (!foundLeftBound) {
1905// leftX--;
1906
1907// // Are we getting to the end of the document ?
1908// if ( leftX < 1) {
1909// qWarning() << " Out of bound left ";
1910// QList<QPointF> emptylist;
1911// return emptylist;
1912// }
1913
1914// QPoint leftPoint = QPoint(leftX, currentPoint.y());
1915
1916// // Are we getting to a curve ?
1917// if ( image->pixel(leftPoint.x(), leftPoint.y()) != colorFrom &&
1918// image->pixel(leftPoint.x(), leftPoint.y()) != colorTo ) {
1919
1920// foundLeftBound = true;
1921
1922// // Convert point to view coordinates
1923// QPointF contourPoint( leftPoint.x() - (maxWidth / 2), leftPoint.y() - (maxHeight / 2));
1924
1925// // Check if the left bound is just a line crossing the main shape
1926// bool foundFillAfter = false;
1927// int increment = 1;
1928
1929// while (leftPoint.x() - increment > 0 && increment < 3 && !foundFillAfter) {
1930// QPoint pointAfter = QPoint(leftPoint.x() - increment, leftPoint.y());
1931
1932// if (image->pixel(pointAfter.x(), pointAfter.y()) == colorTo) {
1933// foundFillAfter = true;
1934// }
1935
1936// increment++;
1937// }
1938
1939// // If the bound is not a contour, we must ignore it
1940// if (foundFillAfter) {
1941
1942// // If the bound is not a contour, we must ignore it
1943// contourPoints.removeOne(contourPoint);
1944// } else {
1945// contourPoints.append(contourPoint);
1946// }
1947// }
1948// }
1949
1950// while (!foundRightBound) {
1951// rightX++;
1952
1953// // Are we getting to the end of the document ?
1954// if ( rightX > maxWidth - 1 ) {
1955// qWarning() << " Out of bound right ";
1956// QList<QPointF> emptylist;
1957// return emptylist;
1958// }
1959
1960// QPoint rightPoint = QPoint(rightX, currentPoint.y());
1961
1962// // Are we getting to a curve ?
1963// if ( image->pixel(rightPoint.x(), rightPoint.y()) != colorFrom &&
1964// image->pixel(rightPoint.x(), rightPoint.y()) != colorTo) {
1965
1966// foundRightBound = true;
1967
1968// // Convert point to view coordinates
1969// QPointF contourPoint( rightPoint.x() - (maxWidth / 2), rightPoint.y() - (maxHeight / 2));
1970
1971// // Check if the left bound is just a line crossing the main shape
1972// bool foundFillAfter = false;
1973// int increment = 1;
1974
1975// while (rightPoint.x() + increment < maxWidth && increment < 3 && !foundFillAfter) {
1976// QPoint pointAfter = QPoint(rightPoint.x() + increment, rightPoint.y());
1977
1978// if (image->pixel(pointAfter.x(), pointAfter.y()) == colorTo) {
1979// foundFillAfter = true;
1980// }
1981
1982// increment++;
1983// }
1984
1985// if (foundFillAfter) {
1986
1987// // If the bound is not a contour, we must ignore it
1988// contourPoints.removeOne(contourPoint);
1989// } else {
1990// contourPoints.append(contourPoint);
1991// }
1992// }
1993// }
1994
1995// int lineY = currentPoint.y();
1996// int topY = lineY - 1;
1997// int bottomY = lineY + 1;
1998
1999// if ( topY < 1 || bottomY > maxHeight - 1 ) {
2000// qWarning() << " Out of bound top / bottom ";
2001// QList<QPointF> emptylist;
2002// return emptylist;
2003// }
2004
2005// for (int x = leftX + 1; x < rightX; x++) {
2006
2007// // The current line point is checked (Colored)
2008// QPoint linePoint = QPoint(x, lineY);
2009// image->setPixel(linePoint.x(), linePoint.y(), colorTo);
2010
2011// QPoint topPoint = QPoint(x, topY);
2012
2013// if ( image->pixel(topPoint.x(), topPoint.y()) != colorFrom &&
2014// image->pixel(topPoint.x(), topPoint.y()) != colorTo) {
2015
2016// // Convert point to view coordinates
2017// QPointF contourPoint( topPoint.x() - (maxWidth / 2), topPoint.y() - (maxHeight / 2));
2018
2019// // Check if the left bound is just a line crossing the main shape
2020// bool foundFillAfter = false;
2021// int increment = 1;
2022
2023// while (topPoint.y() - increment > 0 && increment < 3 && !foundFillAfter) {
2024// QPoint pointAfter = QPoint(topPoint.x(), topPoint.y() - increment);
2025
2026// if (image->pixel(pointAfter.x(), pointAfter.y()) == colorTo) {
2027// foundFillAfter = true;
2028// }
2029// increment ++;
2030// }
2031
2032
2033// if (foundFillAfter) {
2034
2035// // If the bound is not a contour, we must ignore it
2036// contourPoints.removeOne(contourPoint);
2037// } else {
2038// contourPoints.append(contourPoint);
2039// }
2040// } else {
2041// queue.append(topPoint);
2042// }
2043
2044// QPoint bottomPoint = QPoint(x, bottomY);
2045
2046// if ( image->pixel(bottomPoint.x(), bottomPoint.y()) != colorFrom &&
2047// image->pixel(bottomPoint.x(), bottomPoint.y()) != colorTo ) {
2048
2049// QPointF contourPoint( bottomPoint.x() - (maxWidth / 2), bottomPoint.y() - (maxHeight / 2));
2050
2051// // Check if the left bound is just a line crossing the main shape
2052// bool foundFillAfter = false;
2053// int increment = 1;
2054
2055// while (bottomPoint.y() + increment < maxHeight && increment < 3 && !foundFillAfter) {
2056// QPoint pointAfter = QPoint(bottomPoint.x(), bottomPoint.y() + increment);
2057
2058// if (image->pixel(pointAfter.x(), pointAfter.y()) == colorTo) {
2059// foundFillAfter = true;
2060// }
2061
2062// increment++;
2063// }
2064
2065// if (foundFillAfter) {
2066
2067// // If the bound is not a contour, we must ignore it
2068// contourPoints.removeOne(contourPoint);
2069// }
2070// else {
2071
2072// // Keep track of the highest Y position (lowest point) at the beginning of the list
2073// // so that we can parse the list from a point that is a real extremity.
2074// // of the area.
2075// if (highestY < bottomY) {
2076
2077// highestY = bottomY;
2078// contourPoints.insert(0, contourPoint);
2079// } else {
2080// contourPoints.append(contourPoint);
2081// }
2082// }
2083
2084// } else {
2085// queue.append(bottomPoint);
2086// }
2087// }
2088// }
2089// }
2090// return contourPoints;
2091//}
2092
2093//void VectorImage::fill(QPointF point, int color, float tolerance)
2094//{
2095// // Check if we clicked on a curve. In that case, we change its color.
2096// QList<int> closestCurves = getCurvesCloseTo( point, tolerance );
2097
2098// if (closestCurves.size() > 0) // the user click on one or more curves
2099// {
2100// // For each clicked curves, we change the color if requiered
2101// for (int i = 0; i < closestCurves.size(); i++) {
2102// int curveNumber = closestCurves[i];
2103// m_curves[curveNumber].setColorNumber(color);
2104// }
2105
2106// return;
2107// }
2108
2109// // Check if we clicked on an area of the same color.
2110// // We don't want to create another area.
2111// int areaNum = getLastAreaNumber(point);
2112// if (areaNum > -1 && area[areaNum].mColorNumber == color) {
2113// return;
2114// }
2115
2116// // Get the contour points
2117// QList<QPointF> contourPoints = getfillContourPoints(point.toPoint());
2118
2119// // Make a path from the external contour points.
2120// // Put the points in the right order.
2121// QList<QPointF> mainContourPath;
2122// QPointF currentPoint;
2123
2124// if (contourPoints.size() > 0) {
2125// currentPoint = QPointF(contourPoints[0].x(), contourPoints[0].y());
2126// mainContourPath.append(currentPoint);
2127// contourPoints.removeAt(0);
2128// }
2129
2130// bool completedPath = false;
2131// bool foundError = (contourPoints.size() < 1 && !completedPath);
2132
2133// int maxDelta = 2;
2134// int minDelta = -2;
2135
2136// while (!completedPath && !foundError) {
2137
2138// bool foundNextPoint = false;
2139
2140// int i = 0;
2141// while (i < contourPoints.size() && !foundNextPoint) {
2142// QPointF point = contourPoints.at(i);
2143
2144// if (mainContourPath.contains(point)) {
2145// contourPoints.removeAt(i);
2146// }
2147// else {
2148// qreal deltaX = currentPoint.x() - point.x();
2149// qreal deltaY = currentPoint.y() - point.y();
2150
2151// if ( (deltaX < maxDelta && deltaX > minDelta) &&
2152// (deltaY < maxDelta && deltaY > minDelta)) {
2153
2154// currentPoint = QPointF(point.x(), point.y());
2155// mainContourPath.append(currentPoint);
2156// contourPoints.removeAt(i);
2157
2158// foundNextPoint = true;
2159
2160// maxDelta = 2;
2161// minDelta = -2;
2162// }
2163// i++;
2164// }
2165// }
2166
2167// // Check if we have looped
2168// if (!foundNextPoint) {
2169
2170// qreal deltaX = currentPoint.x() - mainContourPath[0].x();
2171// qreal deltaY = currentPoint.y() - mainContourPath[0].y();
2172
2173// if ( (deltaX < maxDelta && deltaX > minDelta) &&
2174// (deltaY < maxDelta && deltaY > minDelta)) {
2175// completedPath = true;
2176// foundNextPoint = true;
2177// }
2178// else if (maxDelta == 2){
2179// // Check if we can find the point after
2180// //
2181// maxDelta = 3;
2182// minDelta = -3;
2183// foundNextPoint = true;
2184// }
2185// else {
2186// qWarning() << " couldn't find next point after " << currentPoint.x() << ", " << currentPoint.y();
2187// }
2188// }
2189// else if (contourPoints.size() < 1) {
2190// // If we found the next point and we have no more points, it means, we have the end of the path
2191// completedPath = true;
2192// foundNextPoint = true;
2193// }
2194
2195// foundError = ( (contourPoints.size() < 1 && !completedPath) || !foundNextPoint );
2196// }
2197
2198// // Add exclude paths
2199
2200// // Fill the path if we have one.
2201// if (completedPath) {
2202// fillSelectedPath(mainContourPath, color);
2203// }
2204// else {
2205// // Check if we clicked on an area in this position and as we couldn't create one,
2206// // we update this one. It may be an area drawn from a stroke path.
2207// int areaNum = getLastAreaNumber(point);
2208// if (areaNum > -1) {
2209
2210// int clickedColorNum = area[areaNum].getColorNumber();
2211
2212// if (clickedColorNum != color) {
2213// area[areaNum].setColorNumber(color);
2214// }
2215// }
2216// }
2217//}
2218
2223void VectorImage::addArea(BezierArea bezierArea)
2224{
2225 updateArea(bezierArea);
2226 mArea.append(bezierArea);
2227 modification();
2228}
2229
2235int VectorImage::getFirstAreaNumber(QPointF point)
2236{
2237 int result = -1;
2238 for (int i = 0; i < mArea.size() && result == -1; i++)
2239 {
2240 if (mArea[i].mPath.controlPointRect().contains(point))
2241 {
2242 if (mArea[i].mPath.contains(point))
2243 {
2244 result = i;
2245 }
2246 }
2247 }
2248 return result;
2249}
2250
2256int VectorImage::getLastAreaNumber(QPointF point)
2257{
2258 return getLastAreaNumber(point, mArea.size() - 1);
2259}
2264int VectorImage::getLastCurveNumber()
2265{
2266 return !mCurves.isEmpty() ? mCurves.size() - 1 : 0;
2267}
2268
2273BezierCurve VectorImage::getLastCurve()
2274{
2275 return !mCurves.isEmpty() ? mCurves[mCurves.size() - 1] : BezierCurve();
2276}
2277
2284int VectorImage::getLastAreaNumber(QPointF point, int maxAreaNumber)
2285{
2286 int result = -1;
2287 for (int i = maxAreaNumber; i > -1 && result == -1; i--)
2288 {
2289 if (mArea[i].mPath.controlPointRect().contains(point))
2290 {
2291 if (mArea[i].mPath.contains(point))
2292 {
2293 result = i;
2294 }
2295 }
2296 }
2297 return result;
2298}
2299
2305void VectorImage::removeArea(QPointF point)
2306{
2307 int areaNumber = getLastAreaNumber(point);
2308 if (areaNumber != -1)
2309 {
2310 mArea.removeAt(areaNumber);
2311 }
2312 modification();
2313}
2314
2321void VectorImage::removeAreaInCurve(int curve, int areaNumber)
2322{
2323 QPointF areaPoint = getVertex(curve, areaNumber);
2324 removeArea(areaPoint);
2325}
2326
2331void VectorImage::updateArea(BezierArea& bezierArea)
2332{
2333 QPainterPath newPath;
2334 for (int i = 0; i < bezierArea.mVertex.size(); i++)
2335 {
2336 QPointF myPoint = getVertex(bezierArea.mVertex[i]);
2337 QPointF myC1;
2338 QPointF myC2;
2339
2340 if (i == 0)
2341 {
2342 newPath.moveTo(myPoint);
2343 }
2344 else
2345 {
2346 if (bezierArea.mVertex[i - 1].curveNumber == bezierArea.mVertex[i].curveNumber) // the two points are on the same curve
2347 {
2348 if (bezierArea.mVertex[i - 1].vertexNumber < bezierArea.mVertex[i].vertexNumber) // the points follow the curve progression
2349 {
2350 myC1 = getC1(bezierArea.mVertex[i]);
2351 myC2 = getC2(bezierArea.mVertex[i]);
2352 }
2353 else
2354 {
2355 myC1 = getC2(bezierArea.mVertex[i - 1]);
2356 myC2 = getC1(bezierArea.mVertex[i - 1]);
2357 }
2358 newPath.cubicTo(myC1, myC2, myPoint);
2359 }
2360 else // the two points are not the same curve
2361 {
2362 if (bezierArea.mVertex[i].vertexNumber == -1) // the current point is the first point in the new curve
2363 {
2364 newPath.lineTo(myPoint);
2365 }
2366 else
2367 {
2368 newPath.lineTo(myPoint);
2369 }
2370 }
2371 }
2372 }
2373 newPath.closeSubpath();
2374 bezierArea.mPath = newPath;
2375 bezierArea.mPath.setFillRule(Qt::WindingFill);
2376}
2377
2384qreal VectorImage::getDistance(VertexRef r1, VertexRef r2)
2385{
2386 return BezierCurve::eLength(getVertex(r1) - getVertex(r2));
2387}
2388
2393void VectorImage::updateImageSize(BezierCurve& updatedCurve) {
2394
2395 // Set the current width of the document based on the extremity of the drawing.
2396 //
2397 // It calculates the size of the document in a way that the center point from
2398 // the view (0, 0) is always the center point of the document.
2399 //
2400 // It adds a point to the 4 sides of the document size in order
2401 // make sure that any curve, any vertex stays within the document.
2402 //
2403
2404 QRectF rect = updatedCurve.getBoundingRect();
2405
2406 QPoint topLeft = rect.topLeft().toPoint();
2407 QPoint bottomRight = rect.bottomRight().toPoint();
2408
2409 int widthFromLeft = ((topLeft.x() * -1) * 2) + 2;
2410
2411 if (widthFromLeft > mSize.width())
2412 {
2413 mSize.setWidth(widthFromLeft);
2414 }
2415
2416 int widthFromRight = (bottomRight.x() * 2) + 2;
2417
2418 if (widthFromRight > mSize.width())
2419 {
2420 mSize.setWidth(widthFromRight);
2421 }
2422
2423 int heightFromTop = ((topLeft.y() * -1) * 2) + 2;
2424
2425 if (heightFromTop > mSize.height())
2426 {
2427 mSize.setHeight(heightFromTop);
2428 }
2429
2430 int heightFromBottom = (bottomRight.y() * 2) + 2;
2431
2432 if (heightFromBottom > mSize.height())
2433 {
2434 mSize.setHeight(heightFromBottom);
2435 }
2436}
BezierArea
Definition: bezierarea.h:31
BezierCurve
Definition: beziercurve.h:34
DebugDetails
Definition: pencilerror.h:25
KeyFrame
Definition: keyframe.h:30
Object
Definition: object.h:42
Status
Definition: pencilerror.h:40
VectorImage
Definition: vectorimage.h:32
VectorImage::applyInvisibilityToSelection
void applyInvisibilityToSelection(bool YesOrNo)
VectorImage::applyInvisibilityToSelection.
Definition: vectorimage.cpp:1368
VectorImage::applyColorToSelectedArea
void applyColorToSelectedArea(int colorNumber)
VectorImage::applyColorToSelectedArea.
Definition: vectorimage.cpp:1315
VectorImage::addArea
void addArea(BezierArea bezierArea)
VectorImage::addArea.
Definition: vectorimage.cpp:2223
VectorImage::getClosestVertexTo
VertexRef getClosestVertexTo(const BezierCurve &curve, int curveNum, QPointF thisPoint)
VectorImage::getClosestVertexTo.
Definition: vectorimage.cpp:1429
VectorImage::getDistance
qreal getDistance(VertexRef r1, VertexRef r2)
VectorImage::getDistance.
Definition: vectorimage.cpp:2384
VectorImage::applyFeatherToSelection
void applyFeatherToSelection(qreal feather)
VectorImage::applyFeatherToSelection.
Definition: vectorimage.cpp:1341
VectorImage::getLastCurve
BezierCurve getLastCurve()
VectorImage::getLastCurve.
Definition: vectorimage.cpp:2273
VectorImage::updateArea
void updateArea(BezierArea &bezierArea)
VectorImage::updateArea.
Definition: vectorimage.cpp:2331
VectorImage::fillSelectedPath
void fillSelectedPath(int color)
VectorImage::fillSelectedPath.
Definition: vectorimage.cpp:1789
VectorImage::createDomElement
Status createDomElement(QXmlStreamWriter &doc)
VectorImage::createDomElement.
Definition: vectorimage.cpp:161
VectorImage::getCurveVertices
QList< VertexRef > getCurveVertices(int curveNumber)
VectorImage::getCurveVertices.
Definition: vectorimage.cpp:1662
VectorImage::removeArea
void removeArea(QPointF point)
VectorImage::removeArea.
Definition: vectorimage.cpp:2305
VectorImage::deselectAll
void deselectAll()
VectorImage::deselectAll.
Definition: vectorimage.cpp:839
VectorImage::loadDomElement
void loadDomElement(QDomElement element)
VectorImage::loadDomElement.
Definition: vectorimage.cpp:193
VectorImage::getNumOfCurvesSelected
int getNumOfCurvesSelected()
VectorImage::numOfCurvesSelected.
Definition: vectorimage.cpp:1754
VectorImage::isAreaSelected
bool isAreaSelected(int areaNumber)
VectorImage::isAreaSelected.
Definition: vectorimage.cpp:696
VectorImage::paste
void paste(VectorImage &)
VectorImage::paste.
Definition: vectorimage.cpp:1049
VectorImage::getSelectedCurveNumbers
QList< int > getSelectedCurveNumbers()
VectorImage::getSelectedCurveNumber.
Definition: vectorimage.cpp:1737
VectorImage::applyVariableWidthToSelection
void applyVariableWidthToSelection(bool YesOrNo)
VectorImage::applyVariableWidthToSelection.
Definition: vectorimage.cpp:1381
VectorImage::removeCurveAt
void removeCurveAt(int i)
VectorImage::removeCurveAt.
Definition: vectorimage.cpp:273
VectorImage::setSelected
void setSelected(int curveNumber, bool YesOrNo)
VectorImage::setSelected.
Definition: vectorimage.cpp:616
VectorImage::paintImage
void paintImage(QPainter &painter, const Object &object, bool simplified, bool showThinCurves, bool antialiasing)
VectorImage::paintImage.
Definition: vectorimage.cpp:1191
VectorImage::calculateSelectionRect
void calculateSelectionRect()
VectorImage::calculateSelectionRect.
Definition: vectorimage.cpp:883
VectorImage::getLastCurveNumber
int getLastCurveNumber()
VectorImage::getLastCurveNumber.
Definition: vectorimage.cpp:2264
VectorImage::removeAreaInCurve
void removeAreaInCurve(int curve, int areaNumber)
VectorImage::removeAreaInCurve.
Definition: vectorimage.cpp:2321
VectorImage::isPathFilled
bool isPathFilled()
VectorImage::isPathFilled.
Definition: vectorimage.cpp:705
VectorImage::applyColorToSelectedCurve
void applyColorToSelectedCurve(int colorNumber)
VectorImage::applyColorToSelectedCurve.
Definition: vectorimage.cpp:1302
VectorImage::getSelectedArea
BezierArea getSelectedArea(QPointF currentPoint)
VectorImage::getSelectedArea.
Definition: vectorimage.cpp:1772
VectorImage::usesColor
bool usesColor(int index)
VectorImage::usesColor.
Definition: vectorimage.cpp:1136
VectorImage::addCurve
void addCurve(BezierCurve &newCurve, qreal factor, bool interacts=true)
VectorImage::addCurve.
Definition: vectorimage.cpp:341
VectorImage::getC1
QPointF getC1(int curveNumber, int vertexNumber)
VectorImage::getC1.
Definition: vectorimage.cpp:1601
VectorImage::addPoint
void addPoint(int curveNumber, int vertexNumber, qreal fraction)
VectorImage::addPoint.
Definition: vectorimage.cpp:230
VectorImage::getAllVertices
QList< VertexRef > getAllVertices()
VectorImage::getAllVertices.
Definition: vectorimage.cpp:1684
VectorImage::getColorNumber
int getColorNumber(QPointF point)
VectorImage::getColorNumber.
Definition: vectorimage.cpp:1097
VectorImage::removeVertex
void removeVertex(int curve, int vertex)
VectorImage::removeVertex.
Definition: vectorimage.cpp:952
VectorImage::removeColor
void removeColor(int index)
VectorImage::removeColor.
Definition: vectorimage.cpp:1153
VectorImage::read
bool read(QString filePath)
VectorImage::read.
Definition: vectorimage.cpp:73
VectorImage::fillContour
void fillContour(QList< QPointF > contourPath, int color)
VectorImage::fillContour.
Definition: vectorimage.cpp:1829
VectorImage::checkCurveExtremity
void checkCurveExtremity(BezierCurve &newCurve, qreal tolerance)
VectorImage::checkCurveExtremity.
Definition: vectorimage.cpp:351
VectorImage::write
Status write(QString filePath, QString format)
VectorImage::write.
Definition: vectorimage.cpp:112
VectorImage::applyWidthToSelection
void applyWidthToSelection(qreal width)
VectorImage::applyWidthToSelection.
Definition: vectorimage.cpp:1328
VectorImage::getLastAreaNumber
int getLastAreaNumber(QPointF point)
VectorImage::getLastAreaNumber.
Definition: vectorimage.cpp:2256
VectorImage::getFirstSelectedArea
int getFirstSelectedArea()
VectorImage::getFirstSelectedArea.
Definition: vectorimage.cpp:800
VectorImage::selectAll
void selectAll()
VectorImage::selectAll.
Definition: vectorimage.cpp:813
VectorImage::getAndRemoveVerticesCloseTo
QList< VertexRef > getAndRemoveVerticesCloseTo(QPointF thisPoint, qreal maxDistance, QList< VertexRef > *listOfPoints)
VectorImage::getAndRemoveVerticesCloseTo.
Definition: vectorimage.cpp:1532
VectorImage::getCurvesColor
int getCurvesColor(int curve)
VectorImage::getCurvesColor.
Definition: vectorimage.cpp:1112
VectorImage::getC2
QPointF getC2(int curveNumber, int vertexNumber)
VectorImage::getC2.
Definition: vectorimage.cpp:1632
VectorImage::getSelectedCurves
QList< BezierCurve > getSelectedCurves()
VectorImage::getSelectedCurve.
Definition: vectorimage.cpp:1720
VectorImage::applyOpacityToSelection
void applyOpacityToSelection(qreal opacity)
VectorImage::applyOpacityToSelection.
Definition: vectorimage.cpp:1354
VectorImage::getFirstSelectedCurve
int getFirstSelectedCurve()
VectorImage::getFirstSelectedCurve.
Definition: vectorimage.cpp:786
VectorImage::checkCurveIntersections
void checkCurveIntersections(BezierCurve &newCurve, qreal tolerance)
VectorImage::checkCurveIntersections.
Definition: vectorimage.cpp:437
VectorImage::getVertex
QPointF getVertex(int curveNumber, int vertexNumber)
VectorImage::getVertex.
Definition: vectorimage.cpp:1566
VectorImage::clear
void clear()
VectorImage::clear.
Definition: vectorimage.cpp:1249
VectorImage::deleteSelectedPoints
void deleteSelectedPoints()
VectorImage::deleteSelectedPoints.
Definition: vectorimage.cpp:1030
VectorImage::clean
void clean()
VectorImage::clean.
Definition: vectorimage.cpp:1259
VectorImage::setAreaSelected
void setAreaSelected(int areaNumber, bool YesOrNo)
VectorImage::setAreaSelected.
Definition: vectorimage.cpp:684
VectorImage::insertCurve
void insertCurve(int position, BezierCurve &newCurve, qreal factor, bool interacts)
VectorImage::insertCurve.
Definition: vectorimage.cpp:295
VectorImage::applySelectionTransformation
void applySelectionTransformation()
VectorImage::applySelectionTransformation.
Definition: vectorimage.cpp:1274
VectorImage::setSelectionTransformation
void setSelectionTransformation(QTransform transform)
VectorImage::setSelectionTransformation.
Definition: vectorimage.cpp:897
VectorImage::setSelectionRect
void setSelectionRect(QRectF rectange)
VectorImage::setSelectionRect.
Definition: vectorimage.cpp:859
VectorImage::getFirstAreaNumber
int getFirstAreaNumber(QPointF point)
VectorImage::getFirstAreaNumber.
Definition: vectorimage.cpp:2235
VectorImage::getVerticesCloseTo
QList< VertexRef > getVerticesCloseTo(QPointF thisPoint, qreal maxDistance)
VectorImage::getVerticesCloseTo.
Definition: vectorimage.cpp:1458
VectorImage::isAnyCurveSelected
bool isAnyCurveSelected()
VectorImage::isAnyCurveSelected.
Definition: vectorimage.cpp:826
VectorImage::isSelected
bool isSelected(int curveNumber)
VectorImage::isSelected.
Definition: vectorimage.cpp:726
VectorImage::getCurvesCloseTo
QList< int > getCurvesCloseTo(QPointF thisPoint, qreal maxDistance)
VectorImage::getCurvesCloseTo.
Definition: vectorimage.cpp:1398
VectorImage::updateImageSize
void updateImageSize(BezierCurve &updatedCurve)
VectorImage::updateImageSize.
Definition: vectorimage.cpp:2393
VectorImage::getCurveSize
int getCurveSize(int curveNumber)
VectorImage::getCurveSize.
Definition: vectorimage.cpp:1704
VectorImage::deleteSelection
void deleteSelection()
VectorImage::deleteSelection.
Definition: vectorimage.cpp:906
VertexRef
Definition: vertexref.h:22
QBrush
QColor
QColor::rgba
QRgb rgba() const const
QDomDocument
QDomDocument::doctype
QDomDocumentType doctype() const const
QDomDocument::documentElement
QDomElement documentElement() const const
QDomDocument::setContent
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
QDomDocumentType
QDomDocumentType::name
QString name() const const
QDomElement
QDomElement::attribute
QString attribute(const QString &name, const QString &defValue) const const
QDomElement::tagName
QString tagName() const const
QDomNode
QDomNode::firstChild
QDomNode firstChild() const const
QDomNode::isNull
bool isNull() const const
QDomNode::nextSibling
QDomNode nextSibling() const const
QDomNode::toElement
QDomElement toElement() const const
QFile
QFile::open
virtual bool open(QIODevice::OpenMode mode) override
QFileDevice::error
QFileDevice::FileError error() const const
QFileInfo
QFileInfo::isDir
bool isDir() const const
QIODevice::ReadOnly
ReadOnly
QIODevice::errorString
QString errorString() const const
QList
QList::append
void append(const T &value)
QList::at
const T & at(int i) const const
QList::clear
void clear()
QList::contains
bool contains(const T &value) const const
QList::empty
bool empty() const const
QList::indexOf
int indexOf(const T &value, int from) const const
QList::insert
void insert(int i, const T &value)
QList::isEmpty
bool isEmpty() const const
QList::length
int length() const const
QList::removeAt
void removeAt(int i)
QList::size
int size() const const
QPaintDevice::height
int height() const const
QPaintDevice::width
int width() const const
QPainter
QPainter::Antialiasing
Antialiasing
QPainter::device
QPaintDevice * device() const const
QPainter::drawPath
void drawPath(const QPainterPath &path)
QPainter::restore
void restore()
QPainter::save
void save()
QPainter::setBrush
void setBrush(const QBrush &brush)
QPainter::setClipping
void setClipping(bool enable)
QPainter::setPen
void setPen(const QColor &color)
QPainter::setRenderHint
void setRenderHint(QPainter::RenderHint hint, bool on)
QPainter::setWorldMatrixEnabled
void setWorldMatrixEnabled(bool enable)
QPainter::transform
const QTransform & transform() const const
QPainterPath
QPainterPath::closeSubpath
void closeSubpath()
QPainterPath::cubicTo
void cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &endPoint)
QPainterPath::lineTo
void lineTo(const QPointF &endPoint)
QPainterPath::moveTo
void moveTo(const QPointF &point)
QPainterPath::setFillRule
void setFillRule(Qt::FillRule fillRule)
QPen
QPoint
QPoint::x
int x() const const
QPoint::y
int y() const const
QPointF
QPointF::dotProduct
qreal dotProduct(const QPointF &p1, const QPointF &p2)
QPointF::toPoint
QPoint toPoint() const const
QPointF::x
qreal x() const const
QPointF::y
qreal y() const const
QRect
QRectF
QRectF::bottomRight
QPointF bottomRight() const const
QRectF::contains
bool contains(const QRectF &rectangle) const const
QRectF::topLeft
QPointF topLeft() const const
QSize::height
int height() const const
QSize::setHeight
void setHeight(int height)
QSize::setWidth
void setWidth(int width)
QSize::width
int width() const const
QString
QString::append
QString & append(QChar ch)
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
Qt::Dense2Pattern
Dense2Pattern
Qt::WindingFill
WindingFill
Qt::RoundCap
RoundCap
Qt::RoundJoin
RoundJoin
Qt::NoPen
NoPen
QTransform
QTransform::inverted
QTransform inverted(bool *invertible) const const
QTransform::map
QPoint map(const QPoint &point) const const
QTransform::mapRect
QRect mapRect(const QRect &rectangle) const const
QTransform::reset
void reset()
QXmlStreamWriter
QXmlStreamWriter::setAutoFormatting
void setAutoFormatting(bool enable)
QXmlStreamWriter::writeAttribute
void writeAttribute(const QString &qualifiedName, const QString &value)
QXmlStreamWriter::writeDTD
void writeDTD(const QString &dtd)
QXmlStreamWriter::writeEndDocument
void writeEndDocument()
QXmlStreamWriter::writeEndElement
void writeEndElement()
QXmlStreamWriter::writeStartDocument
void writeStartDocument()
QXmlStreamWriter::writeStartElement
void writeStartElement(const QString &qualifiedName)
Generated on Thu May 8 2025 04:47:53 for Pencil2D by doxygen 1.9.6 based on revision 4513250b1d5b1a3676ec0e67b06b7a885ceaae39