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