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;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
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
|
||||
static QVector<QPointF> SplinePoints(const QPointF &p1, const QPointF &p4, qreal angle1, qreal angle2, qreal kAsm1,
|
||||
qreal kAsm2, qreal kCurve);
|
||||
qreal ParamT(const QPointF &pBt) const;
|
||||
protected:
|
||||
static QVector<QPointF> GetPoints (const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4 );
|
||||
private:
|
||||
|
@ -80,6 +81,10 @@ private:
|
|||
qint16 level, QVector<qreal> &px, QVector<qreal> &py);
|
||||
static qreal CalcSqDistance ( qreal x1, qreal y1, qreal x2, qreal y2);
|
||||
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
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "../../dialogs/tools/dialogspline.h"
|
||||
#include "../../undocommands/movespline.h"
|
||||
#include "../../visualization/vistoolspline.h"
|
||||
#include <QtMath>
|
||||
|
||||
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,
|
||||
QGraphicsItem *parent)
|
||||
:VAbstractSpline(doc, data, id, parent)
|
||||
:VAbstractSpline(doc, data, id, parent), oldPosition()
|
||||
{
|
||||
sceneType = SceneObject::Spline;
|
||||
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->setFlag(QGraphicsItem::ItemIsSelectable, true);
|
||||
this->setFlag(QGraphicsItem::ItemIsFocusable, true);
|
||||
this->setFlag(QGraphicsItem::ItemIsMovable, true);
|
||||
//this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
this->setAcceptHoverEvents(true);
|
||||
this->setPath(ToolPath());
|
||||
|
||||
|
@ -355,6 +358,71 @@ void VToolSpline::SaveOptions(QDomElement &tag, QSharedPointer<VGObject> &obj)
|
|||
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.
|
||||
|
|
|
@ -63,9 +63,12 @@ protected:
|
|||
virtual void RemoveReferens();
|
||||
virtual void SaveDialog(QDomElement &domElement);
|
||||
virtual void SaveOptions(QDomElement &tag, QSharedPointer<VGObject> &obj);
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent * event);
|
||||
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event);
|
||||
private:
|
||||
Q_DISABLE_COPY(VToolSpline)
|
||||
void RefreshGeometry ();
|
||||
QPointF oldPosition;
|
||||
};
|
||||
|
||||
#endif // VTOOLSPLINE_H
|
||||
|
|
Loading…
Reference in New Issue
Block a user