aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmldesigner/components/pathtool/cubicsegment.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/qmldesigner/components/pathtool/cubicsegment.cpp')
-rw-r--r--src/plugins/qmldesigner/components/pathtool/cubicsegment.cpp367
1 files changed, 367 insertions, 0 deletions
diff --git a/src/plugins/qmldesigner/components/pathtool/cubicsegment.cpp b/src/plugins/qmldesigner/components/pathtool/cubicsegment.cpp
new file mode 100644
index 0000000000..0005514339
--- /dev/null
+++ b/src/plugins/qmldesigner/components/pathtool/cubicsegment.cpp
@@ -0,0 +1,367 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "cubicsegment.h"
+
+#include <qmath.h>
+#include <QtDebug>
+
+
+namespace QmlDesigner {
+
+CubicSegment::CubicSegment() = default;
+
+CubicSegment CubicSegment::create()
+{
+ CubicSegment cubicSegment;
+ cubicSegment.d = new CubicSegmentData;
+
+ return cubicSegment;
+}
+
+void CubicSegment::setModelNode(const ModelNode &modelNode)
+{
+ d->modelNode = modelNode;
+}
+
+ModelNode CubicSegment::modelNode() const
+{
+ return d->modelNode;
+}
+
+void CubicSegment::setFirstControlPoint(const ControlPoint &firstControlPoint)
+{
+ d->firstControllPoint = firstControlPoint;
+}
+
+void CubicSegment::setFirstControlPoint(double x, double y)
+{
+ d->firstControllPoint.setX(x);
+ d->firstControllPoint.setY(y);
+}
+
+void CubicSegment::setFirstControlPoint(const QPointF &coordiante)
+{
+ d->firstControllPoint.setCoordinate(coordiante);
+}
+
+void CubicSegment::setSecondControlPoint(const ControlPoint &secondControlPoint)
+{
+ d->secondControllPoint = secondControlPoint;
+ d->secondControllPoint.setPathElementModelNode(d->modelNode);
+ d->secondControllPoint.setPointType(FirstControlPoint);
+}
+
+void CubicSegment::setSecondControlPoint(double x, double y)
+{
+ d->secondControllPoint.setX(x);
+ d->secondControllPoint.setY(y);
+ d->secondControllPoint.setPathElementModelNode(d->modelNode);
+ d->secondControllPoint.setPointType(FirstControlPoint);
+}
+
+void CubicSegment::setSecondControlPoint(const QPointF &coordiante)
+{
+ d->secondControllPoint.setCoordinate(coordiante);
+ d->secondControllPoint.setPathElementModelNode(d->modelNode);
+ d->secondControllPoint.setPointType(FirstControlPoint);
+}
+
+void CubicSegment::setThirdControlPoint(const ControlPoint &thirdControlPoint)
+{
+ d->thirdControllPoint = thirdControlPoint;
+ d->thirdControllPoint.setPathElementModelNode(d->modelNode);
+ d->thirdControllPoint.setPointType(SecondControlPoint);
+}
+
+void CubicSegment::setThirdControlPoint(double x, double y)
+{
+ d->thirdControllPoint.setX(x);
+ d->thirdControllPoint.setY(y);
+ d->thirdControllPoint.setPathElementModelNode(d->modelNode);
+ d->thirdControllPoint.setPointType(SecondControlPoint);
+}
+
+void CubicSegment::setThirdControlPoint(const QPointF &coordiante)
+{
+ d->thirdControllPoint.setCoordinate(coordiante);
+ d->thirdControllPoint.setPathElementModelNode(d->modelNode);
+ d->thirdControllPoint.setPointType(SecondControlPoint);
+}
+
+void CubicSegment::setFourthControlPoint(const ControlPoint &fourthControlPoint)
+{
+ d->fourthControllPoint = fourthControlPoint;
+ d->fourthControllPoint.setPathElementModelNode(d->modelNode);
+ d->fourthControllPoint.setPointType(EndPoint);
+}
+
+void CubicSegment::setFourthControlPoint(double x, double y)
+{
+ d->fourthControllPoint.setX(x);
+ d->fourthControllPoint.setY(y);
+ d->fourthControllPoint.setPathElementModelNode(d->modelNode);
+ d->fourthControllPoint.setPointType(EndPoint);
+}
+
+void CubicSegment::setFourthControlPoint(const QPointF &coordiante)
+{
+ d->fourthControllPoint.setCoordinate(coordiante);
+ d->fourthControllPoint.setPathElementModelNode(d->modelNode);
+ d->fourthControllPoint.setPointType(EndPoint);
+}
+
+void CubicSegment::setAttributes(const QMap<QString, QVariant> &attributes)
+{
+ d->attributes = attributes;
+}
+
+void CubicSegment::setPercent(double percent)
+{
+ d->percent = percent;
+}
+
+ControlPoint CubicSegment::firstControlPoint() const
+{
+ return d->firstControllPoint;
+}
+
+ControlPoint CubicSegment::secondControlPoint() const
+{
+ return d->secondControllPoint;
+}
+
+ControlPoint CubicSegment::thirdControlPoint() const
+{
+ return d->thirdControllPoint;
+}
+
+ControlPoint CubicSegment::fourthControlPoint() const
+{
+ return d->fourthControllPoint;
+}
+
+const QMap<QString, QVariant> CubicSegment::attributes() const
+{
+ return d->attributes;
+}
+
+double CubicSegment::percent() const
+{
+ return d->percent;
+}
+
+QList<ControlPoint> CubicSegment::controlPoints() const
+{
+ QList<ControlPoint> controlPointList;
+
+ controlPointList.reserve(4);
+
+ controlPointList.append(firstControlPoint());
+ controlPointList.append(secondControlPoint());
+ controlPointList.append(thirdControlPoint());
+ controlPointList.append(fourthControlPoint());
+
+ return controlPointList;
+}
+
+double CubicSegment::firstControlX() const
+{
+ return firstControlPoint().coordinate().x();
+}
+
+double CubicSegment::firstControlY() const
+{
+ return firstControlPoint().coordinate().y();
+}
+
+double CubicSegment::secondControlX() const
+{
+ return secondControlPoint().coordinate().x();
+}
+
+double CubicSegment::secondControlY() const
+{
+ return secondControlPoint().coordinate().y();
+}
+
+double CubicSegment::thirdControlX() const
+{
+ return thirdControlPoint().coordinate().x();
+}
+
+double CubicSegment::thirdControlY() const
+{
+ return thirdControlPoint().coordinate().y();
+}
+
+double CubicSegment::fourthControlX() const
+{
+ return fourthControlPoint().coordinate().x();
+}
+
+double CubicSegment::fourthControlY() const
+{
+ return fourthControlPoint().coordinate().y();
+}
+
+double CubicSegment::quadraticControlX() const
+{
+ return -0.25 * firstControlX() + 0.75 * secondControlX() + 0.75 * thirdControlX() - 0.25 * fourthControlX();
+}
+
+double CubicSegment::quadraticControlY() const
+{
+ return -0.25 * firstControlY() + 0.75 * secondControlY() + 0.75 * thirdControlY() - 0.25 * fourthControlY();
+}
+
+bool CubicSegment::isValid() const
+{
+ return d.data();
+}
+
+bool CubicSegment::canBeConvertedToLine() const
+{
+ return canBeConvertedToQuad()
+ && qFuzzyIsNull(((3. * d->firstControllPoint.coordinate())
+ - (6. * d->secondControllPoint.coordinate())
+ + (3. * d->thirdControllPoint.coordinate())).manhattanLength());;
+}
+
+bool CubicSegment::canBeConvertedToQuad() const
+{
+ return qFuzzyIsNull(((3. * d->secondControllPoint.coordinate())
+ - (3 * d->thirdControllPoint.coordinate())
+ + d->fourthControllPoint.coordinate()
+ - d->firstControllPoint.coordinate()).manhattanLength());
+}
+
+QPointF CubicSegment::sample(double t) const
+{
+ return qPow(1.-t, 3.) * firstControlPoint().coordinate()
+ + 3 * qPow(1.-t, 2.) * t * secondControlPoint().coordinate()
+ + 3 * qPow(t, 2.) * (1. - t) * thirdControlPoint().coordinate()
+ + qPow(t, 3.) * fourthControlPoint().coordinate();
+}
+
+double CubicSegment::minimumDistance(const QPointF &pickPoint, double &tReturnValue) const
+{
+ double actualMinimumDistance = 10000000.;
+ for (double t = 0.0; t <= 1.0; t += 0.1) {
+ QPointF samplePoint = sample(t);
+ QPointF distanceVector = pickPoint - samplePoint;
+ if (distanceVector.manhattanLength() < actualMinimumDistance) {
+ actualMinimumDistance = distanceVector.manhattanLength();
+ tReturnValue = t;
+ }
+ }
+
+ return actualMinimumDistance;
+}
+
+static QPointF interpolatedPoint(double t, const QPointF &firstPoint, const QPointF &secondPoint)
+{
+ return (secondPoint - firstPoint) * t + firstPoint;
+}
+
+QPair<CubicSegment, CubicSegment> CubicSegment::split(double t)
+{
+ // first pass
+ QPointF secondPointFirstSegment = interpolatedPoint(t, firstControlPoint().coordinate(), secondControlPoint().coordinate());
+ QPointF firstIntermediatPoint = interpolatedPoint(t, secondControlPoint().coordinate(), thirdControlPoint().coordinate());
+ QPointF thirdPointSecondSegment = interpolatedPoint(t, thirdControlPoint().coordinate(), fourthControlPoint().coordinate());
+
+ // second pass
+ QPointF thirdPointFirstSegment = interpolatedPoint(t, secondPointFirstSegment, firstIntermediatPoint);
+ QPointF secondPointSecondSegment = interpolatedPoint(t, firstIntermediatPoint, thirdPointSecondSegment);
+
+ // third pass
+ QPointF midPoint = interpolatedPoint(t, thirdPointFirstSegment, secondPointSecondSegment);
+ ControlPoint midControlPoint(midPoint);
+
+
+ CubicSegment firstCubicSegment = CubicSegment::create();
+ firstCubicSegment.setFirstControlPoint(firstControlPoint().coordinate());
+ firstCubicSegment.setSecondControlPoint(secondPointFirstSegment);
+ firstCubicSegment.setThirdControlPoint(thirdPointFirstSegment);
+ firstCubicSegment.setFourthControlPoint(midControlPoint);
+
+ CubicSegment secondCubicSegment = CubicSegment::create();
+ secondCubicSegment.setFirstControlPoint(midControlPoint);
+ secondCubicSegment.setSecondControlPoint(secondPointSecondSegment);
+ secondCubicSegment.setThirdControlPoint(thirdPointSecondSegment);
+ secondCubicSegment.setFourthControlPoint(fourthControlPoint().coordinate());
+
+ qDebug() << firstCubicSegment << secondCubicSegment;
+
+ return {firstCubicSegment, secondCubicSegment};
+}
+
+void CubicSegment::makeStraightLine()
+{
+ QPointF lineVector = fourthControlPoint().coordinate() - firstControlPoint().coordinate();
+ QPointF newSecondControlPoint = firstControlPoint().coordinate() + (lineVector * 0.3);
+ QPointF newThirdControlPoint = fourthControlPoint().coordinate() - (lineVector * 0.3);
+ setSecondControlPoint(newSecondControlPoint);
+ setThirdControlPoint(newThirdControlPoint);
+}
+
+void CubicSegment::updateModelNode()
+{
+ firstControlPoint().updateModelNode();
+ secondControlPoint().updateModelNode();
+ thirdControlPoint().updateModelNode();
+ fourthControlPoint().updateModelNode();
+}
+
+CubicSegmentData::CubicSegmentData()
+ : firstControllPoint(0., 0.),
+ secondControllPoint(0., 0.),
+ thirdControllPoint(0., 0.),
+ fourthControllPoint(0., 0.),
+ percent(-1.0)
+{
+}
+
+bool operator ==(const CubicSegment& firstCubicSegment, const CubicSegment& secondCubicSegment)
+{
+ return firstCubicSegment.d.data() == secondCubicSegment.d.data();
+}
+
+QDebug operator<<(QDebug debug, const CubicSegment &cubicSegment)
+{
+ if (cubicSegment.isValid()) {
+ debug.nospace() << "CubicSegment("
+ << cubicSegment.firstControlPoint() << ", "
+ << cubicSegment.secondControlPoint() << ", "
+ << cubicSegment.thirdControlPoint() << ", "
+ << cubicSegment.fourthControlPoint() << ')';
+ } else {
+ debug.nospace() << "CubicSegment(invalid)";
+ }
+
+ return debug.space();
+}
+} // namespace QmlDesigner