Movable spline path.

--HG--
branch : feature
This commit is contained in:
Roman Telezhynskyi 2016-03-05 23:06:54 +02:00
parent 2b3c13eb1d
commit f53fe379c6
6 changed files with 126 additions and 95 deletions

View file

@ -28,6 +28,8 @@
#include "vsplinepoint.h" #include "vsplinepoint.h"
#include "vsplinepoint_p.h" #include "vsplinepoint_p.h"
#include "../qmuparser/qmutokenparser.h"
#include <QDebug> #include <QDebug>
#include <QLineF> #include <QLineF>
@ -322,3 +324,10 @@ void VSplinePoint::SetLength2(const qreal &value, const QString &length2F)
d->length2 = value; d->length2 = value;
d->length2F = length2F; d->length2F = length2F;
} }
//---------------------------------------------------------------------------------------------------------------------
bool VSplinePoint::IsMovable() const
{
return qmu::QmuTokenParser::IsSingle(d->angle1F) && qmu::QmuTokenParser::IsSingle(d->angle2F) &&
qmu::QmuTokenParser::IsSingle(d->length1F) && qmu::QmuTokenParser::IsSingle(d->length2F);
}

View file

@ -98,6 +98,8 @@ public:
qreal Length2() const; qreal Length2() const;
QString Length2Formula() const; QString Length2Formula() const;
void SetLength2(const qreal &value, const QString &length2F); void SetLength2(const qreal &value, const QString &length2F);
bool IsMovable() const;
protected: protected:
QSharedDataPointer<VSplinePointData> d; QSharedDataPointer<VSplinePointData> d;
}; };

View file

@ -336,12 +336,7 @@ void VToolSpline::mousePressEvent(QGraphicsSceneMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick) if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
{ {
const auto spline = VAbstractTool::data.GeometricObject<VSpline>(id); if (IsMovable())
if (qmu::QmuTokenParser::IsSingle(spline->GetStartAngleFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetEndAngleFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetC1LengthFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetC2LengthFormula()))
{ {
SetOverrideCursor(cursorArrowCloseHand, 1, 1); SetOverrideCursor(cursorArrowCloseHand, 1, 1);
oldPosition = event->scenePos(); oldPosition = event->scenePos();
@ -359,12 +354,7 @@ void VToolSpline::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick) if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
{ {
const auto spline = VAbstractTool::data.GeometricObject<VSpline>(id); if (IsMovable())
if (qmu::QmuTokenParser::IsSingle(spline->GetStartAngleFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetEndAngleFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetC1LengthFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetC2LengthFormula()))
{ {
//Disable cursor-arrow-closehand //Disable cursor-arrow-closehand
RestoreOverrideCursor(cursorArrowCloseHand); RestoreOverrideCursor(cursorArrowCloseHand);
@ -377,12 +367,7 @@ void VToolSpline::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VToolSpline::mouseMoveEvent(QGraphicsSceneMouseEvent *event) void VToolSpline::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{ {
const auto spline = VAbstractTool::data.GeometricObject<VSpline>(id); if (IsMovable())
if (qmu::QmuTokenParser::IsSingle(spline->GetStartAngleFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetEndAngleFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetC1LengthFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetC2LengthFormula()))
{ {
// Don't need check if left mouse button was pressed. According to the Qt documentation "If you do receive this // 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 // event, you can be certain that this item also received a mouse press event, and that this item is the current
@ -392,6 +377,7 @@ void VToolSpline::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
// "weight" describes how the influence of the drag should be distributed // "weight" describes how the influence of the drag should be distributed
// among the handles; 0 = front handle only, 1 = back handle only. // among the handles; 0 = front handle only, 1 = back handle only.
const auto spline = VAbstractTool::data.GeometricObject<VSpline>(id);
const qreal t = spline->ParamT(oldPosition); const qreal t = spline->ParamT(oldPosition);
if (qFloor(t) == -1) if (qFloor(t) == -1)
@ -460,12 +446,7 @@ void VToolSpline::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{ {
if (flags() & QGraphicsItem::ItemIsMovable) if (flags() & QGraphicsItem::ItemIsMovable)
{ {
const auto spline = VAbstractTool::data.GeometricObject<VSpline>(id); if (IsMovable())
if (qmu::QmuTokenParser::IsSingle(spline->GetStartAngleFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetEndAngleFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetC1LengthFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetC2LengthFormula()))
{ {
SetOverrideCursor(cursorArrowOpenHand, 1, 1); SetOverrideCursor(cursorArrowOpenHand, 1, 1);
} }
@ -479,12 +460,7 @@ void VToolSpline::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{ {
if (flags() & QGraphicsItem::ItemIsMovable) if (flags() & QGraphicsItem::ItemIsMovable)
{ {
const auto spline = VAbstractTool::data.GeometricObject<VSpline>(id); if (IsMovable())
if (qmu::QmuTokenParser::IsSingle(spline->GetStartAngleFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetEndAngleFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetC1LengthFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetC2LengthFormula()))
{ {
//Disable cursor-arrow-openhand //Disable cursor-arrow-openhand
RestoreOverrideCursor(cursorArrowOpenHand); RestoreOverrideCursor(cursorArrowOpenHand);
@ -515,6 +491,17 @@ void VToolSpline::SetVisualization()
} }
} }
//---------------------------------------------------------------------------------------------------------------------
bool VToolSpline::IsMovable() const
{
const auto spline = VAbstractTool::data.GeometricObject<VSpline>(id);
return qmu::QmuTokenParser::IsSingle(spline->GetStartAngleFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetEndAngleFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetC1LengthFormula()) &&
qmu::QmuTokenParser::IsSingle(spline->GetC2LengthFormula());
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
/** /**
* @brief RefreshGeometry refresh item on scene. * @brief RefreshGeometry refresh item on scene.

View file

@ -80,6 +80,7 @@ private:
Q_DISABLE_COPY(VToolSpline) Q_DISABLE_COPY(VToolSpline)
QPointF oldPosition; QPointF oldPosition;
bool IsMovable() const;
void RefreshGeometry (); void RefreshGeometry ();
void SetSplineAttributes(QDomElement &domElement, const VSpline &spl); void SetSplineAttributes(QDomElement &domElement, const VSpline &spl);
}; };

View file

@ -53,7 +53,9 @@ const QString VToolSplinePath::OldToolType = QStringLiteral("path");
*/ */
VToolSplinePath::VToolSplinePath(VAbstractPattern *doc, VContainer *data, quint32 id, const QString &color, VToolSplinePath::VToolSplinePath(VAbstractPattern *doc, VContainer *data, quint32 id, const QString &color,
const Source &typeCreation, QGraphicsItem *parent) const Source &typeCreation, QGraphicsItem *parent)
:VAbstractSpline(doc, data, id, parent), oldPosition() : VAbstractSpline(doc, data, id, parent),
oldPosition(),
splIndex(-1)
{ {
sceneType = SceneObject::SplinePath; sceneType = SceneObject::SplinePath;
lineColor = color; lineColor = color;
@ -256,7 +258,7 @@ void VToolSplinePath::UpdateControlPoints(const VSpline &spl, VSplinePath &splPa
{ {
VSplinePoint p = splPath.GetSplinePoint(indexSpline, SplinePointPosition::FirstPoint); VSplinePoint p = splPath.GetSplinePoint(indexSpline, SplinePointPosition::FirstPoint);
p.SetAngle2(spl.GetStartAngle(), spl.GetStartAngleFormula()); p.SetAngle2(spl.GetStartAngle(), spl.GetStartAngleFormula());
p.SetLength2(spl.GetC2Length(), spl.GetC2LengthFormula()); p.SetLength2(spl.GetC1Length(), spl.GetC1LengthFormula());
splPath.UpdatePoint(indexSpline, SplinePointPosition::FirstPoint, p); splPath.UpdatePoint(indexSpline, SplinePointPosition::FirstPoint, p);
p = splPath.GetSplinePoint(indexSpline, SplinePointPosition::LastPoint); p = splPath.GetSplinePoint(indexSpline, SplinePointPosition::LastPoint);
@ -442,9 +444,14 @@ void VToolSplinePath::mousePressEvent(QGraphicsSceneMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick) if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
{ {
SetOverrideCursor(cursorArrowCloseHand, 1, 1);
oldPosition = event->scenePos(); oldPosition = event->scenePos();
event->accept(); const auto splPath = VAbstractTool::data.GeometricObject<VSplinePath>(id);
splIndex = splPath->Segment(oldPosition);
if (IsMovable(splIndex))
{
SetOverrideCursor(cursorArrowCloseHand, 1, 1);
event->accept();
}
} }
} }
VAbstractSpline::mousePressEvent(event); VAbstractSpline::mousePressEvent(event);
@ -457,6 +464,7 @@ void VToolSplinePath::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick) if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
{ {
oldPosition = event->scenePos();
//Disable cursor-arrow-closehand //Disable cursor-arrow-closehand
RestoreOverrideCursor(cursorArrowCloseHand); RestoreOverrideCursor(cursorArrowCloseHand);
} }
@ -467,84 +475,82 @@ void VToolSplinePath::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VToolSplinePath::mouseMoveEvent(QGraphicsSceneMouseEvent *event) void VToolSplinePath::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{ {
// Don't need check if left mouse button was pressed. According to the Qt documentation "If you do receive this // Don't need to 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 // event, you can be certain that this item also received a mouse press event, and that this item is the current
// mouse grabber.". // mouse grabber.".
VSplinePath oldSplPath = *VAbstractTool::data.GeometricObject<VSplinePath>(id); if (IsMovable(splIndex))
VSplinePath newSplPath = oldSplPath;
int indexSpline = oldSplPath.Segment(oldPosition);
if (indexSpline == -1)
{ {
return; VSplinePath oldSplPath = *VAbstractTool::data.GeometricObject<VSplinePath>(id);
} VSplinePath newSplPath = oldSplPath;
VSpline spline = newSplPath.GetSpline(indexSpline); VSpline spline = newSplPath.GetSpline(splIndex);
const qreal t = spline.ParamT(oldPosition); const qreal t = spline.ParamT(oldPosition);
if (qFloor(t) == -1) if (qFloor(t) == -1)
{ {
return; return;
} }
// Magic Bezier Drag Equations follow! // Magic Bezier Drag Equations follow!
// "weight" describes how the influence of the drag should be distributed // "weight" describes how the influence of the drag should be distributed
// among the handles; 0 = front handle only, 1 = back handle only. // among the handles; 0 = front handle only, 1 = back handle only.
double weight; double weight;
if (t <= 1.0 / 6.0) if (t <= 1.0 / 6.0)
{ {
weight = 0; weight = 0;
} }
else if (t <= 0.5) else if (t <= 0.5)
{ {
weight = (pow((6 * t - 1) / 2.0, 3)) / 2; weight = (pow((6 * t - 1) / 2.0, 3)) / 2;
} }
else if (t <= 5.0 / 6.0) else if (t <= 5.0 / 6.0)
{ {
weight = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5; weight = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5;
} }
else else
{ {
weight = 1; weight = 1;
} }
const QPointF delta = event->scenePos() - oldPosition; const QPointF delta = event->scenePos() - oldPosition;
const QPointF offset0 = ((1-weight)/(3*t*(1-t)*(1-t))) * delta; const QPointF offset0 = ((1-weight)/(3*t*(1-t)*(1-t))) * delta;
const QPointF offset1 = (weight/(3*t*t*(1-t))) * delta; const QPointF offset1 = (weight/(3*t*t*(1-t))) * delta;
const QPointF p2 = spline.GetP2() + offset0; const QPointF p2 = spline.GetP2() + offset0;
const QPointF p3 = spline.GetP3() + offset1; const QPointF p3 = spline.GetP3() + offset1;
oldPosition = event->scenePos(); // Now mouse here oldPosition = event->scenePos(); // Now mouse here
const VSpline spl = VSpline(spline.GetP1(), p2, p3, spline.GetP4()); const VSpline spl = VSpline(spline.GetP1(), p2, p3, spline.GetP4());
UpdateControlPoints(spl, newSplPath, indexSpline); UpdateControlPoints(spl, newSplPath, splIndex);
MoveSplinePath *moveSplPath = new MoveSplinePath(doc, oldSplPath, newSplPath, id, this->scene()); MoveSplinePath *moveSplPath = new MoveSplinePath(doc, oldSplPath, newSplPath, id, this->scene());
connect(moveSplPath, &VUndoCommand::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree); connect(moveSplPath, &VUndoCommand::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
qApp->getUndoStack()->push(moveSplPath); qApp->getUndoStack()->push(moveSplPath);
// Each time we move something we call recalculation scene rect. In some cases this can cause moving // Each time we move something we call recalculation scene rect. In some cases this can cause moving
// objects positions. And this cause infinite redrawing. That's why we wait the finish of saving the last move. // objects positions. And this cause infinite redrawing. That's why we wait the finish of saving the last move.
static bool changeFinished = true; static bool changeFinished = true;
if (changeFinished) if (changeFinished)
{ {
changeFinished = false; changeFinished = false;
const QList<QGraphicsView *> viewList = scene()->views(); const QList<QGraphicsView *> viewList = scene()->views();
if (not viewList.isEmpty()) if (not viewList.isEmpty())
{
if (QGraphicsView *view = viewList.at(0))
{ {
VMainGraphicsScene *currentScene = qobject_cast<VMainGraphicsScene *>(scene()); if (QGraphicsView *view = viewList.at(0))
SCASSERT(currentScene); {
const QPointF cursorPosition = currentScene->getScenePos(); VMainGraphicsScene *currentScene = qobject_cast<VMainGraphicsScene *>(scene());
view->ensureVisible(QRectF(cursorPosition.x()-5, cursorPosition.y()-5, 10, 10)); SCASSERT(currentScene);
const QPointF cursorPosition = currentScene->getScenePos();
view->ensureVisible(QRectF(cursorPosition.x()-5, cursorPosition.y()-5, 10, 10));
}
} }
} changeFinished = true;
changeFinished = true; }
} }
} }
@ -553,7 +559,13 @@ void VToolSplinePath::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{ {
if (flags() & QGraphicsItem::ItemIsMovable) if (flags() & QGraphicsItem::ItemIsMovable)
{ {
SetOverrideCursor(cursorArrowOpenHand, 1, 1); oldPosition = event->scenePos();
const auto splPath = VAbstractTool::data.GeometricObject<VSplinePath>(id);
splIndex = splPath->Segment(oldPosition);
if (IsMovable(splIndex))
{
SetOverrideCursor(cursorArrowOpenHand, 1, 1);
}
} }
VAbstractSpline::hoverEnterEvent(event); VAbstractSpline::hoverEnterEvent(event);
@ -564,6 +576,7 @@ void VToolSplinePath::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{ {
if (flags() & QGraphicsItem::ItemIsMovable) if (flags() & QGraphicsItem::ItemIsMovable)
{ {
oldPosition = event->scenePos();
//Disable cursor-arrow-openhand //Disable cursor-arrow-openhand
RestoreOverrideCursor(cursorArrowOpenHand); RestoreOverrideCursor(cursorArrowOpenHand);
} }
@ -586,6 +599,23 @@ void VToolSplinePath::SetVisualization()
} }
} }
//---------------------------------------------------------------------------------------------------------------------
bool VToolSplinePath::IsMovable(int index) const
{
const auto splPath = VAbstractTool::data.GeometricObject<VSplinePath>(id);
//index == -1 - can delete, but decided to left
if (index == -1 || index < 1 || index > splPath->Count())
{
return false;
}
const VSplinePoint p1 = splPath->GetSplinePoint(index, SplinePointPosition::FirstPoint);
const VSplinePoint p2 = splPath->GetSplinePoint(index, SplinePointPosition::LastPoint);
return p1.IsMovable() && p2.IsMovable();
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
/** /**
* @brief RefreshGeometry refresh item on scene. * @brief RefreshGeometry refresh item on scene.

View file

@ -101,7 +101,9 @@ protected:
virtual void SetVisualization() Q_DECL_OVERRIDE; virtual void SetVisualization() Q_DECL_OVERRIDE;
private: private:
QPointF oldPosition; QPointF oldPosition;
int splIndex;
bool IsMovable(int index) const;
void RefreshGeometry(); void RefreshGeometry();
static void AddPathPoint(VAbstractPattern *doc, QDomElement &domElement, const VSplinePoint &splPoint); static void AddPathPoint(VAbstractPattern *doc, QDomElement &domElement, const VSplinePoint &splPoint);
void UpdateControlPoints(const VSpline &spl, VSplinePath &splPath, const qint32 &indexSpline) const; void UpdateControlPoints(const VSpline &spl, VSplinePath &splPath, const qint32 &indexSpline) const;