Now spline can move by mouse.
--HG-- branch : feature
This commit is contained in:
parent
fb8dca8452
commit
254d9b7b7a
|
@ -744,3 +744,134 @@ void VSpline::SetKcurve(qreal factor)
|
||||||
d->kCurve = factor;
|
d->kCurve = factor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
int VSpline::Sign(long double ld) const
|
||||||
|
{
|
||||||
|
if(qAbs(ld)<0.00000000001)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (ld>0) ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* @brief Cubic Cubic equation solution. Real coefficients case.
|
||||||
|
*
|
||||||
|
* This method use method Vieta-Cardano for eval cubic equations.
|
||||||
|
* Cubic equation write in form x3+a*x2+b*x+c=0.
|
||||||
|
*
|
||||||
|
* Output:
|
||||||
|
* 3 real roots -> then x is filled with them;
|
||||||
|
* 1 real + 2 complex -> x[0] is real, x[1] is real part of complex roots, x[2] - non-negative imaginary part.
|
||||||
|
*
|
||||||
|
* @param x solution array (size 3).
|
||||||
|
* @param a coefficient
|
||||||
|
* @param b coefficient
|
||||||
|
* @param c coefficient
|
||||||
|
* @return 3 - 3 real roots;
|
||||||
|
* 1 - 1 real root + 2 complex;
|
||||||
|
* 2 - 1 real root + complex roots imaginary part is zero (i.e. 2 real roots).
|
||||||
|
*/
|
||||||
|
qint32 VSpline::Cubic(QVector<qreal> &x, qreal a, qreal b, qreal c) const
|
||||||
|
{
|
||||||
|
//To find cubic equation roots in the case of real coefficients, calculated at the beginning
|
||||||
|
const qreal q = (pow(a, 2) - 3*b)/9.;
|
||||||
|
const qreal r = (2*pow(a, 3) - 9*a*b + 27.*c)/54.;
|
||||||
|
if (pow(r, 2) < pow(q, 3))
|
||||||
|
{ // equation has three real roots, use formula Vieta
|
||||||
|
const qreal t = acos(r/sqrt(pow(q, 3)))/3.;
|
||||||
|
x.insert(0, -2.*sqrt(q)*cos(t)-a/3);
|
||||||
|
x.insert(1, -2.*sqrt(q)*cos(t + (2*M_2PI/3.)) - a/3.);
|
||||||
|
x.insert(2, -2.*sqrt(q)*cos(t - (2*M_2PI/3.)) - a/3.);
|
||||||
|
return(3);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // 1 real root + 2 complex
|
||||||
|
//Formula Cardano
|
||||||
|
const qreal aa = -Sign(r)*pow(fabs(r)+sqrt(pow(r, 2)-pow(q, 3)), 1./3.);
|
||||||
|
const qreal bb = Sign(aa) == 0 ? 0 : q/aa;
|
||||||
|
|
||||||
|
x.insert(0, aa+bb-a/3.); // Real root
|
||||||
|
x.insert(1, (-0.5)*(aa+bb)-a/3.); //Complex root
|
||||||
|
x.insert(2, (sqrt(3.)*0.5)*fabs(aa-bb)); // Complex root
|
||||||
|
if (qFuzzyCompare(x.at(2) + 1, 0. + 1))
|
||||||
|
{
|
||||||
|
return(2);
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
QVector<qreal> VSpline::CalcT (qreal curveCoord1, qreal curveCoord2, qreal curveCoord3,
|
||||||
|
qreal curveCoord4, qreal pointCoord) const
|
||||||
|
{
|
||||||
|
const qreal a = -curveCoord1 + 3*curveCoord2 - 3*curveCoord3 + curveCoord4;
|
||||||
|
const qreal b = 3*curveCoord1 - 6*curveCoord2 + 3*curveCoord3;
|
||||||
|
const qreal c = -3*curveCoord1 + 3*curveCoord2;
|
||||||
|
const qreal d = -pointCoord + curveCoord1;
|
||||||
|
|
||||||
|
QVector<qreal> t = QVector<qreal>(3, -1);
|
||||||
|
Cubic(t, b/a, c/a, d/a);
|
||||||
|
|
||||||
|
QVector<qreal> retT;
|
||||||
|
for (int i=0; i < t.size(); ++i)
|
||||||
|
{
|
||||||
|
if ( t.at(i) >= 0 && t.at(i) <= 1 )
|
||||||
|
{
|
||||||
|
retT.append(t.at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* @brief VSpline::ParamT calculate t coeffient that reprezent point on curve.
|
||||||
|
*
|
||||||
|
* Each point that belongs to Cubic Bézier curve can be shown by coefficient in interval [0; 1].
|
||||||
|
*
|
||||||
|
* @param pBt point on curve
|
||||||
|
* @return t coeffient that reprezent this point on curve. Return -1 if point doesn't belongs to curve.
|
||||||
|
*/
|
||||||
|
qreal VSpline::ParamT (const QPointF &pBt) const
|
||||||
|
{
|
||||||
|
QVector<qreal> ts;
|
||||||
|
// Calculate t coefficient for each axis
|
||||||
|
ts += CalcT (GetP1().toQPointF().x(), d->p2.x(), d->p3.x(), GetP4().toQPointF().x(), pBt.x());
|
||||||
|
ts += CalcT (GetP1().toQPointF().y(), d->p2.y(), d->p3.y(), GetP4().toQPointF().y(), pBt.y());
|
||||||
|
|
||||||
|
if(ts.isEmpty())
|
||||||
|
{
|
||||||
|
return -1; // We don't have candidates
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal tx = -1;
|
||||||
|
qreal eps = 3; // Error calculation
|
||||||
|
|
||||||
|
// In morst case we will have 6 result in interval [0; 1].
|
||||||
|
// Here we try find closest to our point.
|
||||||
|
for (int i=0; i< ts.size(); ++i)
|
||||||
|
{
|
||||||
|
const qreal t = ts.at(i);
|
||||||
|
const QPointF p0 = GetP1().toQPointF();
|
||||||
|
const QPointF p1 = d->p2;
|
||||||
|
const QPointF p2 = d->p3;
|
||||||
|
const QPointF p3 = GetP4().toQPointF();
|
||||||
|
//The explicit form of the Cubic Bézier curve
|
||||||
|
const qreal pointX = pow(1-t, 3)*p0.x() + 3*pow(1-t, 2)*t*p1.x() + 3*(1-t)*pow(t, 2)*p2.x() + pow(t, 3)*p3.x();
|
||||||
|
const qreal pointY = pow(1-t, 3)*p0.y() + 3*pow(1-t, 2)*t*p1.y() + 3*(1-t)*pow(t, 2)*p2.y() + pow(t, 3)*p3.y();
|
||||||
|
|
||||||
|
const QLineF line(pBt, QPointF(pointX, pointY));
|
||||||
|
if (line.length() <= eps)
|
||||||
|
{
|
||||||
|
tx = t;
|
||||||
|
eps = line.length(); //Next point should be even closest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ public:
|
||||||
// cppcheck-suppress unusedFunction
|
// cppcheck-suppress unusedFunction
|
||||||
static QVector<QPointF> SplinePoints(const QPointF &p1, const QPointF &p4, qreal angle1, qreal angle2, qreal kAsm1,
|
static QVector<QPointF> SplinePoints(const QPointF &p1, const QPointF &p4, qreal angle1, qreal angle2, qreal kAsm1,
|
||||||
qreal kAsm2, qreal kCurve);
|
qreal kAsm2, qreal kCurve);
|
||||||
|
qreal ParamT(const QPointF &pBt) const;
|
||||||
protected:
|
protected:
|
||||||
static QVector<QPointF> GetPoints (const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4 );
|
static QVector<QPointF> GetPoints (const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4 );
|
||||||
private:
|
private:
|
||||||
|
@ -80,6 +81,10 @@ private:
|
||||||
qint16 level, QVector<qreal> &px, QVector<qreal> &py);
|
qint16 level, QVector<qreal> &px, QVector<qreal> &py);
|
||||||
static qreal CalcSqDistance ( qreal x1, qreal y1, qreal x2, qreal y2);
|
static qreal CalcSqDistance ( qreal x1, qreal y1, qreal x2, qreal y2);
|
||||||
void CreateName();
|
void CreateName();
|
||||||
|
QVector<qreal> CalcT(qreal curveCoord1, qreal curveCoord2, qreal curveCoord3, qreal curveCoord4,
|
||||||
|
qreal pointCoord) const;
|
||||||
|
qint32 Cubic(QVector<qreal> &x, qreal a, qreal b, qreal c) const;
|
||||||
|
int Sign(long double ld) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VSPLINE_H
|
#endif // VSPLINE_H
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "../../dialogs/tools/dialogspline.h"
|
#include "../../dialogs/tools/dialogspline.h"
|
||||||
#include "../../undocommands/movespline.h"
|
#include "../../undocommands/movespline.h"
|
||||||
#include "../../visualization/vistoolspline.h"
|
#include "../../visualization/vistoolspline.h"
|
||||||
|
#include <QtMath>
|
||||||
|
|
||||||
const QString VToolSpline::ToolType = QStringLiteral("simple");
|
const QString VToolSpline::ToolType = QStringLiteral("simple");
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ const QString VToolSpline::ToolType = QStringLiteral("simple");
|
||||||
*/
|
*/
|
||||||
VToolSpline::VToolSpline(VPattern *doc, VContainer *data, quint32 id, const QString color, const Source &typeCreation,
|
VToolSpline::VToolSpline(VPattern *doc, VContainer *data, quint32 id, const QString color, const Source &typeCreation,
|
||||||
QGraphicsItem *parent)
|
QGraphicsItem *parent)
|
||||||
:VAbstractSpline(doc, data, id, parent)
|
:VAbstractSpline(doc, data, id, parent), oldPosition()
|
||||||
{
|
{
|
||||||
sceneType = SceneObject::Spline;
|
sceneType = SceneObject::Spline;
|
||||||
lineColor = color;
|
lineColor = color;
|
||||||
|
@ -53,6 +54,8 @@ VToolSpline::VToolSpline(VPattern *doc, VContainer *data, quint32 id, const QStr
|
||||||
this->setPen(QPen(Qt::black, qApp->toPixel(qApp->widthHairLine())/factor));
|
this->setPen(QPen(Qt::black, qApp->toPixel(qApp->widthHairLine())/factor));
|
||||||
this->setFlag(QGraphicsItem::ItemIsSelectable, true);
|
this->setFlag(QGraphicsItem::ItemIsSelectable, true);
|
||||||
this->setFlag(QGraphicsItem::ItemIsFocusable, true);
|
this->setFlag(QGraphicsItem::ItemIsFocusable, true);
|
||||||
|
this->setFlag(QGraphicsItem::ItemIsMovable, true);
|
||||||
|
//this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||||
this->setAcceptHoverEvents(true);
|
this->setAcceptHoverEvents(true);
|
||||||
this->setPath(ToolPath());
|
this->setPath(ToolPath());
|
||||||
|
|
||||||
|
@ -355,6 +358,71 @@ void VToolSpline::SaveOptions(QDomElement &tag, QSharedPointer<VGObject> &obj)
|
||||||
doc->SetAttribute(tag, AttrColor, lineColor);
|
doc->SetAttribute(tag, AttrColor, lineColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void VToolSpline::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
oldPosition = event->scenePos();
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
VAbstractSpline::mousePressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void VToolSpline::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
// Don't need check if left mouse button was pressed. According to the Qt documentation "If you do receive this
|
||||||
|
// event, you can be certain that this item also received a mouse press event, and that this item is the current
|
||||||
|
// mouse grabber.".
|
||||||
|
|
||||||
|
// Magic Bezier Drag Equations follow!
|
||||||
|
// "weight" describes how the influence of the drag should be distributed
|
||||||
|
// among the handles; 0 = front handle only, 1 = back handle only.
|
||||||
|
|
||||||
|
const QSharedPointer<VSpline> spline = VAbstractTool::data.GeometricObject<VSpline>(id);
|
||||||
|
const qreal t = spline->ParamT(oldPosition);
|
||||||
|
|
||||||
|
if (qFloor(t) == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double weight;
|
||||||
|
if (t <= 1.0 / 6.0)
|
||||||
|
{
|
||||||
|
weight = 0;
|
||||||
|
}
|
||||||
|
else if (t <= 0.5)
|
||||||
|
{
|
||||||
|
weight = (pow((6 * t - 1) / 2.0, 3)) / 2;
|
||||||
|
}
|
||||||
|
else if (t <= 5.0 / 6.0)
|
||||||
|
{
|
||||||
|
weight = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
weight = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPointF delta = event->scenePos() - oldPosition;
|
||||||
|
const QPointF offset0 = ((1-weight)/(3*t*(1-t)*(1-t))) * delta;
|
||||||
|
const QPointF offset1 = (weight/(3*t*t*(1-t))) * delta;
|
||||||
|
|
||||||
|
const QPointF p2 = spline->GetP2() + offset0;
|
||||||
|
const QPointF p3 = spline->GetP3() + offset1;
|
||||||
|
|
||||||
|
oldPosition = event->scenePos(); // Now mouse here
|
||||||
|
|
||||||
|
VSpline spl = VSpline(spline->GetP1(), p2, p3, spline->GetP4(), spline->GetKcurve());
|
||||||
|
|
||||||
|
MoveSpline *moveSpl = new MoveSpline(doc, spline.data(), spl, id, this->scene());
|
||||||
|
connect(moveSpl, &MoveSpline::NeedLiteParsing, doc, &VPattern::LiteParseTree);
|
||||||
|
qApp->getUndoStack()->push(moveSpl);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* @brief RefreshGeometry refresh item on scene.
|
* @brief RefreshGeometry refresh item on scene.
|
||||||
|
|
|
@ -63,9 +63,12 @@ protected:
|
||||||
virtual void RemoveReferens();
|
virtual void RemoveReferens();
|
||||||
virtual void SaveDialog(QDomElement &domElement);
|
virtual void SaveDialog(QDomElement &domElement);
|
||||||
virtual void SaveOptions(QDomElement &tag, QSharedPointer<VGObject> &obj);
|
virtual void SaveOptions(QDomElement &tag, QSharedPointer<VGObject> &obj);
|
||||||
|
virtual void mousePressEvent(QGraphicsSceneMouseEvent * event);
|
||||||
|
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event);
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(VToolSpline)
|
Q_DISABLE_COPY(VToolSpline)
|
||||||
void RefreshGeometry ();
|
void RefreshGeometry ();
|
||||||
|
QPointF oldPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VTOOLSPLINE_H
|
#endif // VTOOLSPLINE_H
|
||||||
|
|
Loading…
Reference in New Issue
Block a user