18 #include "beziercurve.h"
22 #include <QXmlStreamWriter>
23 #include <QDomElement>
25 #include <QPainterPath>
27 #include "pencilerror.h"
30 BezierCurve::BezierCurve()
34 BezierCurve::BezierCurve(
const QList<QPointF>& pointList,
bool smooth)
37 for (
int i = 0; i < pointList.
size(); i++)
41 createCurve(pointList, pressureList, smooth);
47 int n = pointList.
size();
53 for (
int i=0; i<n; i++) { markList.
append(
false); }
56 BezierCurve::simplify(tol, pointList, 0, n-1, markList);
60 for(
int i=0; i<n; i++)
62 if (markList.
at(i) ==
true)
64 simplifiedPointList.
append(pointList.
at(i));
65 if (pressureList.
size() > i)
69 qreal currentPressure = pressureList.
at(i);
70 if (currentPressure < 0.1) {
71 currentPressure = 0.1;
73 simplifiedPressureList.
append(currentPressure);
77 simplifiedPressureList.
append(0.5);
83 createCurve(simplifiedPointList, simplifiedPressureList, smooth);
91 xmlStream.
writeAttribute(
"variableWidth", variableWidth ?
"true" :
"false" );
93 xmlStream.
writeAttribute(
"invisible", invisible ?
"true" :
"false" );
100 int errorLocation = -1;
101 for (
int i = 0; i < c1.
size() ; i++ )
111 if ( errorLocation < 0 && xmlStream.
hasError() )
119 if ( xmlStream.
hasError() && errorLocation >= 0 )
122 debugInfo <<
"BezierCurve::createDomElement";
123 debugInfo <<
QString(
"width = %1").
arg(width);
124 debugInfo <<
QString(
"variableWidth = %1").
arg(
"variableWidth");
125 debugInfo <<
QString(
"feather = %1").
arg(feather);
126 debugInfo <<
QString(
"invisible = %1").
arg(invisible);
127 debugInfo <<
QString(
"filled = %1").
arg(mFilled);
128 debugInfo <<
QString(
"colorNumber = %1").
arg(colorNumber);
129 debugInfo <<
QString(
"originX = %1").
arg(origin.
x());
130 debugInfo <<
QString(
"originY = %1").
arg(origin.
y());
131 debugInfo <<
QString(
"originPressure = %1").
arg(pressure.
at(0));
132 debugInfo <<
QString(
"- segmentTag[%1] has failed to write").
arg(errorLocation);
133 debugInfo <<
QString(
" c1x = %1").
arg(c1.
at(errorLocation).
x());
134 debugInfo <<
QString(
" c1y = %1").
arg(c1.
at(errorLocation).
y());
135 debugInfo <<
QString(
" c2x = %1").
arg(c2.
at(errorLocation).
x());
136 debugInfo <<
QString(
" c2y = %1").
arg(c2.
at(errorLocation).
y());
137 debugInfo <<
QString(
" vx = %1").
arg(vertex.
at(errorLocation).
x());
138 debugInfo <<
QString(
" vy = %1").
arg(vertex.
at(errorLocation).
y());
139 debugInfo <<
QString(
" pressure = %1").
arg(pressure.
at(errorLocation + 1));
141 return Status(Status::FAIL, debugInfo);
147 void BezierCurve::loadDomElement(
const QDomElement& element)
150 variableWidth = (element.
attribute(
"variableWidth") ==
"1") || (element.
attribute(
"variableWidth") ==
"true");
152 invisible = (element.
attribute(
"invisible") ==
"1") || (element.
attribute(
"invisible") ==
"true");
153 mFilled = (element.
attribute(
"filled") ==
"1") || (element.
attribute(
"filled") ==
"true");
154 if (width == 0) invisible =
true;
162 while (!segmentTag.
isNull())
165 if (!segmentElement.
isNull())
167 if (segmentElement.
tagName() ==
"segment")
173 appendCubic(c1Point, c2Point, vertexPoint, pressureValue);
181 void BezierCurve::setOrigin(
const QPointF& point)
186 void BezierCurve::setOrigin(
const QPointF& point,
const qreal& pressureValue,
const bool& trueOrFalse)
189 pressure[0] = pressureValue;
190 selected[0] = trueOrFalse;
193 void BezierCurve::setC1(
int i,
const QPointF& point)
195 if ( i >= 0 || i < c1.
size() )
201 qDebug() <<
"BezierCurve::setC1! index out of bounds:" << i;
205 void BezierCurve::setC2(
int i,
const QPointF& point)
207 if ( i >= 0 || i < c2.
size() )
213 qDebug() <<
"BezierCurve::setC2! index out of bounds:" << i;
217 void BezierCurve::setVertex(
int i,
const QPointF& point)
223 else if (i >= 0 && i < vertex.
size())
229 qDebug() <<
"BezierCurve::setVertex! index out of bounds:" << i;
233 void BezierCurve::setLastVertex(
const QPointF& point)
235 if (vertex.
size() > 0)
237 vertex[vertex.
size()-1] = point;
241 qDebug() <<
"BezierCurve::setLastVertex! curve has less than 2 vertices";
246 void BezierCurve::setWidth(qreal desiredWidth)
248 width = desiredWidth;
251 void BezierCurve::setFeather(qreal desiredFeather)
253 feather = desiredFeather;
256 void BezierCurve::setVariableWidth(
bool YesOrNo)
258 variableWidth = YesOrNo;
261 void BezierCurve::setInvisibility(
bool YesOrNo)
266 void BezierCurve::setSelected(
int i,
bool YesOrNo)
268 selected[i+1] = YesOrNo;
285 if (isSelected(-1)) { transformedCurve.setOrigin(transformation.
map(origin)); }
286 for(
int i=0; i< vertex.
size(); i++)
288 if (isSelected(i-1)) { transformedCurve.setC1(i, transformation.
map(c1.
at(i))); }
291 transformedCurve.setC2(i, transformation.
map(c2.
at(i)));
292 transformedCurve.setVertex(i, transformation.
map(vertex.
at(i)));
312 return transformedCurve;
315 void BezierCurve::transform(
QTransform transformation)
317 if (isSelected(-1)) setOrigin( transformation.
map(origin) );
318 for(
int i=0; i< vertex.
size(); i++)
320 if (isSelected(i-1)) c1[i] = transformation.
map(c1.
at(i));
323 c2[i] = transformation.
map(c2.
at(i));
324 vertex[i] = transformation.
map(vertex.
at(i));
330 void BezierCurve::appendCubic(
const QPointF& c1Point,
const QPointF& c2Point,
const QPointF& vertexPoint, qreal pressureValue)
334 vertex.
append(vertexPoint);
335 pressure.
append(pressureValue);
339 void BezierCurve::addPoint(
int position,
const QPointF point)
341 if ( position > -1 && position < getVertexSize() )
343 QPointF v1 = getVertex(position-1);
344 QPointF v2 = getVertex(position);
348 c1[position] = point + 0.2*(v2-v1);
349 c2[position] = v2 + (c2o-v2)*(0.5);
351 c1.
insert(position, v1 + (c1o-v1)*(0.5) );
352 c2.
insert(position, point - 0.2*(v2-v1));
353 vertex.
insert(position, point);
354 pressure.
insert(position, getPressure(position));
355 selected.
insert(position, isSelected(position) && isSelected(position-1));
361 qDebug() <<
"Error BezierCurve::addPoint(int, QPointF)";
365 void BezierCurve::addPoint(
int position,
const qreal fraction)
370 if ( position > -1 && position < getVertexSize() )
372 QPointF vA = getVertex(position-1);
373 QPointF vB = getVertex(position);
376 QPointF c12 = (1-fraction)*c1o + fraction*c2o;
377 QPointF cA1 = (1-fraction)*vA + fraction*c1o;
378 QPointF cB2 = (1-fraction)*c2o + fraction*vB;
379 QPointF cA2 = (1-fraction)*cA1 + fraction*c12;
380 QPointF cB1 = (1-fraction)*c12 + fraction*cB2;
381 QPointF vM = (1-fraction)*cA2 + fraction*cB1;
383 setC1(position, cB1);
384 setC2(position, cB2);
388 vertex.
insert(position, vM);
389 pressure.
insert(position, getPressure(position));
390 selected.
insert(position, isSelected(position) && isSelected(position-1));
396 qDebug() <<
"Error BezierCurve::addPoint(int, qreal)";
400 void BezierCurve::removeVertex(
int i)
402 int n = vertex.
size();
407 origin = vertex.
at(0);
432 void BezierCurve::drawPath(
QPainter& painter,
Object*
object,
QTransform transformation,
bool simplified,
bool showThinLines )
434 QColor color =
object->getColor(colorNumber).color;
437 if (isPartlySelected()) { myCurve = (transformed(transformation)); }
438 else { myCurve = *
this; }
440 if ( variableWidth && !simplified && !invisible)
444 painter.
drawPath(myCurve.getStrokedPath());
448 qreal renderedWidth = width;
454 renderedWidth = fabs(renderedWidth);
488 color =
QColor(100,150,255);
491 lineWidth = fabs(lineWidth);
493 if (isSelected()) painter.
drawPath(myCurve.getSimplePath());
496 for(
int i=-1; i< vertex.
size(); i++)
521 for(
int i=0; i<vertex.
size(); i++)
533 for(
int i=0; i<vertex.
size(); i++)
542 return getStrokedPath( width );
547 return getStrokedPath(width,
true);
551 QPainterPath BezierCurve::getStrokedPath(qreal width,
bool usePressure)
554 QPointF tangentVec, normalVec, normalVec2, normalVec2_1, normalVec2_2;
555 qreal width2 = width;
556 int n = vertex.
size();
559 normalVec =
QPointF(-(c1.
at(0) - origin).y(), (c1.
at(0) - origin).x());
560 normalise(normalVec);
561 if (usePressure) width2 = width * 0.5 * pressure.
at(0);
562 if (n==1 && width2 == 0.0) width2 = 0.15 * width;
563 path.
moveTo(origin + width2*normalVec);
564 for(
int i=0; i<n; i++)
568 normalVec2 =
QPointF(-(vertex.
at(i) - c2.
at(i)).y(), (vertex.
at(i) - c2.
at(i)).x());
572 normalVec2_1 =
QPointF(-(vertex.
at(i) - c2.
at(i)).y(), (vertex.
at(i) - c2.
at(i)).x());
573 normalise(normalVec2_1);
574 normalVec2_2 =
QPointF(-(c1.
at(i+1) - vertex.
at(i)).y(), (c1.
at(i+1) - vertex.
at(i)).x());
575 normalise(normalVec2_2);
576 normalVec2 = normalVec2_1 + normalVec2_2;
578 normalise(normalVec2);
579 if (usePressure) width2 = width * 0.5 * pressure.
at(i);
580 if (n==1 && width2 == 0.0) width2 = 0.15 * width;
582 path.
cubicTo(c1.
at(i) + width2*normalVec, c2.
at(i) + width2*normalVec2, vertex.
at(i) + width2*normalVec2);
585 normalVec = normalVec2;
587 if (usePressure) width2 = width * 0.5 * pressure.
at(n-1);
588 if (n==1 && width2 == 0.0) width2 = 0.15 * width;
591 tangentVec = (vertex.
at(n-1)-c2.
at(n-1));
592 normalise(tangentVec);
593 path.
cubicTo(vertex.
at(n-1) + width2*(normalVec+1.8*tangentVec), vertex.
at(n-1) + width2*(-normalVec+1.8*tangentVec), vertex.
at(n-1) - width2*normalVec);
595 for(
int i=n-2; i>=0; i--)
597 normalVec2_1 =
QPointF((vertex.
at(i) - c1.
at(i+1)).y(), -(vertex.
at(i) - c1.
at(i+1)).x());
598 normalise(normalVec2_1);
599 normalVec2_2 =
QPointF((c2.
at(i) - vertex.
at(i)).y(), -(c2.
at(i) - vertex.
at(i)).x());
600 normalise(normalVec2_2);
601 normalVec2 = normalVec2_1 + normalVec2_2;
602 normalise(normalVec2);
603 if (usePressure) width2 = width * 0.5 * pressure.
at(i);
604 if (n==1 && width2 == 0.0) width2 = 0.15 * width;
605 path.
cubicTo(c2.
at(i+1) - width2*normalVec, c1.
at(i+1) - width2*normalVec2, vertex.
at(i) - width2*normalVec2);
606 normalVec = normalVec2;
608 normalVec2 =
QPointF((origin - c1.
at(0)).y(), -(origin - c1.
at(0)).x());
609 normalise(normalVec2);
610 if (usePressure) width2 = width * 0.5 * pressure.
at(0);
611 if (n==1 && width2 == 0.0) width2 = 0.15 * width;
612 path.
cubicTo(c2.
at(0) - width2*normalVec, c1.
at(0) - width2*normalVec2, origin - width2*normalVec2);
614 tangentVec = (origin-c1.
at(0));
615 normalise(tangentVec);
616 path.
cubicTo(origin + width2*(-normalVec+1.8*tangentVec), origin + width2*(normalVec+1.8*tangentVec), origin + width2*normalVec);
622 QRectF BezierCurve::getBoundingRect()
630 int n = pointList.
size();
639 setOrigin( pointList.
at(0) );
641 pressure.
append(pressureList.
at(0));
648 pressure.
append(pressureList.
at(p));
661 void BezierCurve::smoothCurve()
663 QPointF c1, c2, c2old, tangentVec, normalVec;
664 int n = vertex.
size();
666 for(
int p=0; p<n-1; p++)
669 QPointF Dprev = getVertex(p-1);
670 QPointF Dnext = getVertex(p+1);
671 qreal L1 = mLength(D-Dprev);
672 qreal L2 = mLength(D-Dnext);
674 tangentVec = 0.4*(Dnext - Dprev);
675 normalVec =
QPointF(-tangentVec.
y(), tangentVec.
x())/eLength(tangentVec);
676 if ( ((D-Dprev).x()*(D-Dnext).x()+(D-Dprev).y()*(D-Dnext).y())/(1.0*L1*L2) < 0 )
679 c1 = D - tangentVec*(L1+0.0)/(L1+L2);
680 c2 = D + tangentVec*(L2+0.0)/(L1+L2);
685 c1 = 0.6*D + 0.4*Dprev;
686 c2 = 0.6*D + 0.4*Dnext;
691 c2old = 0.5*(vertex.
at(0)+c1);
701 this->c1[n-1] = c2old;
702 this->c2[n-1] = 0.5*(c2old+vertex.
at(n-1));
719 for (
int i = j + 1; i < k - 1; i++)
723 double Vijx = Vij.
x();
724 double Vijy = Vij.
y();
725 double Vjkx = Vjk.
x();
726 double Vjky = Vjk.
y();
727 double dv = (Vjkx * Vjkx + Vjky * Vjky);
730 dv = sqrt( Vijx*Vijx+Vijy*Vijy - pow(Vijx*Vjkx+Vijy*Vjky,2)/dv );
749 simplify(tol, inputList, j, maxi, markList);
750 simplify(tol, inputList, maxi, k, markList);
756 qreal BezierCurve::eLength(
const QPointF point)
758 qreal result = sqrt( point.
x()*point.
x() + point.
y()*point.
y() );
763 qreal BezierCurve::mLength(
const QPointF point)
765 qreal result = qAbs(point.
x()) + qAbs(point.
y());
766 if (result == 0.0) result = 1.0;
770 void BezierCurve::normalise(
QPointF& point)
772 qreal length = eLength(point);
775 point = point/length;
784 Q = curve.getVertex(i-1);
785 qreal distMin = eLength(Q-P);
788 for(
int k=1; k<=nSteps; k++)
790 qreal s = (k+0.0)/nSteps;
791 Q = curve.getPointOnCubic(i, s);
792 qreal dist = eLength(Q-P);
804 QPointF BezierCurve::getPointOnCubic(
int i, qreal t)
806 return (1.0-t)*(1.0-t)*(1.0-t)*getVertex(i-1)
807 + 3*t*(1.0-t)*(1.0-t)*getC1(i)
808 + 3*t*t*(1.0-t)*getC2(i)
809 + t*t*t*getVertex(i);
813 bool BezierCurve::intersects(
QPointF point, qreal distance)
816 if ( getStrokedPath(distance,
false).contains(point) )
824 bool BezierCurve::intersects(
QRectF rectangle)
827 if ( getSimplePath().controlPointRect().intersects(rectangle))
829 for(
int i=0; i<vertex.
size(); i++)
831 if ( rectangle.
contains( getVertex(i) ) )
return true;
846 P1 = curve1.getVertex(i1-1);
847 Q1 = curve1.getVertex(i1);
848 P2 = curve2.getVertex(i2-1);
849 Q2 = curve2.getVertex(i2);
861 QPointF* cubicIntersection = &intersectionPoint;
870 P1 = curve1.getVertex(i1-1);
871 for(
int i=1; i<=nSteps; i++)
873 qreal s = (i+0.0)/nSteps;
874 Q1 = curve1.getPointOnCubic(i1, s);
875 P2 = curve2.getVertex(i2-1);
876 for(
int j=1; j<=nSteps; j++)
878 qreal t = (j+0.0)/nSteps;
879 Q2 = curve2.getPointOnCubic(i2, t);
884 QPointF intersectionPoint = *cubicIntersection;
885 if (intersectionPoint != curve1.getVertex(i1-1) && intersectionPoint != curve1.getVertex(i1))
887 qreal fraction1 = eLength(intersectionPoint-Q1)/(0.0+eLength(Q1-P1));
888 qreal fraction2 = eLength(intersectionPoint-Q2)/(0.0+eLength(Q2-P2));
889 qreal t1 = (i - fraction1)/nSteps;
890 qreal t2 = (j - fraction2)/nSteps;
892 intersection.point = intersectionPoint;
893 intersection.t1 = t1;
894 intersection.t2 = t2;
895 intersections.
append( intersection );
QRectF boundingRect() const const
QString attribute(const QString &name, const QString &defValue) const const
bool hasError() const const
const T & at(int i) const const
bool contains(const QRectF &rectangle) const const
void cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &endPoint)
void moveTo(const QPointF &point)
bool intersects(const QRectF &rectangle) const const
double toDouble(bool *ok) const const
QDomNode nextSibling() const const
QDomElement toElement() const const
QString number(int n, int base)
void append(const T &value)
QLineF::IntersectType intersect(const QLineF &line, QPointF *intersectionPoint) const const
void setFillRule(Qt::FillRule fillRule)
void setPen(const QColor &color)
void lineTo(const QPointF &endPoint)
int toInt(bool *ok, int base) const const
void setBrush(const QBrush &brush)
void setTopLeft(const QPointF &position)
bool isNull() const const
void writeAttribute(const QString &qualifiedName, const QString &value)
QDomNode firstChild() const const
void drawPath(const QPainterPath &path)
void insert(int i, const T &value)
float toFloat(bool *ok) const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
void setFilled(bool yesOrNo)
BezierCurve::setFilled.
QString tagName() const const
void setBottomRight(const QPointF &position)
void writeEmptyElement(const QString &qualifiedName)
void writeStartElement(const QString &qualifiedName)
void replace(int i, const T &value)