diff --git a/src/libs/ifc/ifcdef.h b/src/libs/ifc/ifcdef.h index 8553e8d15..7cd02e838 100644 --- a/src/libs/ifc/ifcdef.h +++ b/src/libs/ifc/ifcdef.h @@ -147,6 +147,7 @@ extern const QString ColorYellow; // Hacks for avoiding the linker error "undefined reference to" #define SPL_ "Spl_" #define ARC_ "Arc_" +#define EARC_ "ElArc_" extern const QString line_; extern const QString angleLine_; diff --git a/src/libs/vgeometry/varc.cpp b/src/libs/vgeometry/varc.cpp index f15de23a2..10ef8393a 100644 --- a/src/libs/vgeometry/varc.cpp +++ b/src/libs/vgeometry/varc.cpp @@ -283,7 +283,7 @@ QPointF VArc::CutArc(const qreal &length, VArc &arc1, VArc &arc2) const len = length; } - qreal n = (len*180)/(M_PI*d->radius); + qreal n = (len*180)/(M_PI*d->radius); // n - is angle in degrees QLineF line(GetCenter().toQPointF(), GetP1()); line.setAngle(line.angle()+n); @@ -354,7 +354,7 @@ void VArc::FindF2(qreal length) startAngle.setAngle(d->f1 + arcAngle);// We use QLineF just because it is easy way correct angle value d->f2 = startAngle.angle(); - d->formulaF2 = QString("%1").arg(d->f2); + d->formulaF2 = QString().number(d->f2); } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/libs/vgeometry/varc_p.h b/src/libs/vgeometry/varc_p.h index b11f1399c..70c3b6393 100644 --- a/src/libs/vgeometry/varc_p.h +++ b/src/libs/vgeometry/varc_p.h @@ -31,6 +31,7 @@ #include #include "vgeometrydef.h" +#include "../vmisc/vabstractapplication.h" #include "vpointf.h" #ifdef Q_CC_GNU @@ -54,18 +55,20 @@ public: {} VArcData(VPointF center, qreal radius, qreal f1, qreal f2) - : f1(f1), formulaF1(QString("%1").arg(f1)), f2(f2), formulaF2(QString("%1").arg(f2)), radius(radius), - formulaRadius(QString("%1").arg(radius)), center(center), isFlipped(false), formulaLength() + : f1(f1), formulaF1(QString().number(f1)), + f2(f2), formulaF2(QString().number(f2)), + radius(radius), formulaRadius(QString().number(qApp->fromPixel(radius))), + center(center), isFlipped(false), formulaLength() {} - VArcData (QString formulaLength, VPointF center, qreal radius, QString formulaRadius, qreal f1, QString formulaF1 ) + VArcData (QString formulaLength, VPointF center, qreal radius, QString formulaRadius, qreal f1, QString formulaF1) : f1(f1), formulaF1(formulaF1), f2(0), formulaF2("0"), radius(radius), formulaRadius(formulaRadius), center(center), isFlipped(false), formulaLength(formulaLength) {} VArcData(VPointF center, qreal radius, qreal f1) - : f1(f1), formulaF1(QString("%1").arg(f1)), f2(0), formulaF2("0"), radius(radius), - formulaRadius(QString("%1").arg(radius)), center(center), isFlipped(false), formulaLength() + : f1(f1), formulaF1(QString().number(f1)), f2(0), formulaF2("0"), radius(radius), + formulaRadius(QString().number(qApp->fromPixel(radius))), center(center), isFlipped(false), formulaLength() {} VArcData(const VArcData &arc) diff --git a/src/libs/vgeometry/vellipticalarc.cpp b/src/libs/vgeometry/vellipticalarc.cpp new file mode 100644 index 000000000..9a3e8a946 --- /dev/null +++ b/src/libs/vgeometry/vellipticalarc.cpp @@ -0,0 +1,592 @@ +/************************************************************************ + ** + ** @file vellipticalarc.cpp + ** @author Valentina Zhuravska + ** @date February 1, 2016 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2013-2015 Valentina project + ** All Rights Reserved. + ** + ** Valentina is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#include "vellipticalarc.h" +#include "vellipticalarc_p.h" +#include "vspline.h" +#include "../ifc/ifcdef.h" +#include +#include +#include + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief VEllipticalArc default constructor. + */ +VEllipticalArc::VEllipticalArc() + :VAbstractCurve(GOType::EllipticalArc), d (new VEllipticalArcData) +{} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief VEllipticalArc constructor. + * @param center center point. + * @param radius1 arc major radius. + * @param radius2 arc minor radius. + * @param f1 start angle (degree). + * @param f2 end angle (degree). + */ +VEllipticalArc::VEllipticalArc (VPointF center, qreal radius1, qreal radius2, + QString formulaRadius1, QString formulaRadius2, qreal f1, QString formulaF1, qreal f2, + QString formulaF2, qreal rotationAngle, quint32 idObject, Draw mode) + : VAbstractCurve(GOType::EllipticalArc, idObject, mode), + d (new VEllipticalArcData(center, radius1, radius2, formulaRadius1, formulaRadius2, + f1, formulaF1, f2, formulaF2, rotationAngle)) +{ + CreateName(); +} + +//--------------------------------------------------------------------------------------------------------------------- +VEllipticalArc::VEllipticalArc(VPointF center, qreal radius1, qreal radius2, qreal f1, qreal f2, qreal rotationAngle) + : VAbstractCurve(GOType::EllipticalArc, NULL_ID, Draw::Calculation), + d (new VEllipticalArcData(center, radius1, radius2, f1, f2, rotationAngle)) +{ + CreateName(); +} + +//--------------------------------------------------------------------------------------------------------------------- +VEllipticalArc::VEllipticalArc(qreal length, QString formulaLength, VPointF center, qreal radius1, qreal radius2, + QString formulaRadius1, QString formulaRadius2, qreal f1, QString formulaF1, qreal rotationAngle, + quint32 idObject, Draw mode) + : VAbstractCurve(GOType::EllipticalArc, idObject, mode), + d (new VEllipticalArcData(formulaLength, center, radius1, radius2, formulaRadius1, formulaRadius2, + f1, formulaF1, rotationAngle)) +{ + CreateName(); + FindF2(length); +} + +//--------------------------------------------------------------------------------------------------------------------- +VEllipticalArc::VEllipticalArc(qreal length, VPointF center, qreal radius1, qreal radius2, qreal f1, + qreal rotationAngle) + : VAbstractCurve(GOType::EllipticalArc, NULL_ID, Draw::Calculation), + d (new VEllipticalArcData(center, radius1, radius2, f1, rotationAngle)) +{ + CreateName(); + FindF2(length); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief VEllipticalArc copy constructor + * @param arc arc + */ +VEllipticalArc::VEllipticalArc(const VEllipticalArc &arc) + : VAbstractCurve(arc), d (arc.d) +{} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief operator = assignment operator + * @param arc arc + * @return arc + */ +VEllipticalArc &VEllipticalArc::operator =(const VEllipticalArc &arc) +{ + if ( &arc == this ) + { + return *this; + } + VAbstractCurve::operator=(arc); + d = arc.d; + return *this; +} + +//--------------------------------------------------------------------------------------------------------------------- +VEllipticalArc::~VEllipticalArc() +{} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetLength return arc length. + * @return length. + */ +qreal VEllipticalArc::GetLength() const +{ + qreal length = 0; + QPainterPath elArc; + QVector points = GetPoints(); + elArc.moveTo(points.at(0)); + for (qint32 i = 1; i < points.count(); ++i) + { + elArc.lineTo(points.at(i)); + } + length = elArc.length(); + + if (d->isFlipped) + { + length = length * -1; + } + + return length; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetP1 return point associated with start angle. + * @return point. + */ +QPointF VEllipticalArc::GetP1() const +{ + return GetPoint(d->f1); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetP2 return point associated with end angle. + * @return point. + */ +QPointF VEllipticalArc::GetP2 () const +{ + return GetPoint(d->f2); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetPoint return point associated with angle. + * @return point. + */ +QPointF VEllipticalArc::GetPoint (qreal angle) const +{ + if (angle > 360 || angle < 0) + {// Filter incorect value of angle + QLineF dummy(0,0, 100, 0); + dummy.setAngle(angle); + angle = dummy.angle(); + } + + // p - point without rotation + qreal x = qAbs((d->radius1 * d->radius2)/ + (qSqrt(d->radius2*d->radius2+d->radius1*d->radius1*qTan(M_PI*angle/180)*qTan(M_PI*angle/180)))); + qreal y = qAbs(qTan(M_PI*angle/180) * x); + + if (angle > 90 && angle <= 180) + { + x = -x; + } + else if (angle > 180 && angle < 270) + { + x = -x; + y = -y; + } + else if (angle > 270) + { + y = -y; + } + else if (angle == 90) + { + x = 0; + y = d->radius2; + } + else if (angle == 270) + { + x = 0; + y = -d->radius2; + } + QPointF p ( GetCenter().x () + x, GetCenter().y () + y); + // rotation of point + QLineF line(GetCenter().toQPointF(), p); + line.setAngle(line.angle() + GetRotationAngle()); + + return line.p2(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief AngleArc calculate arc angle. + * @return angle in degree. + */ +qreal VEllipticalArc::AngleArc() const +{ + if ((qFuzzyIsNull(d->f1) && qFuzzyCompare(d->f2, 360)) || + (qFuzzyCompare(d->f1, 360) && qFuzzyIsNull(d->f2))) + { + return 360; + } + QLineF l1(0, 0, 100, 100); + l1.setAngle(d->f1); + QLineF l2(0, 0, 100, 100); + l2.setAngle(d->f2); + + qreal ang = l1.angleTo(l2); + + if (d->isFlipped) + { + ang = 360 - ang; + } + + return ang; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetAngles return list of angles needed for drawing arc. + * @return list of angles + */ +QVector VEllipticalArc::GetAngles() const +{ + QVector sectionAngle; + qreal angle = AngleArc(); + + if (qFuzzyIsNull(angle)) + {// Return the array that includes one angle + sectionAngle.append(d->f1); + return sectionAngle; + } + + if (angle > 360 || angle < 0) + {// Filter incorect value of angle + QLineF dummy(0,0, 100, 0); + dummy.setAngle(angle); + angle = dummy.angle(); + } + + const qreal angleInterpolation = 45; //degree + const int sections = qFloor(angle / angleInterpolation); + for (int i = 0; i < sections; ++i) + { + sectionAngle.append(angleInterpolation); + } + + const qreal tail = angle - sections * angleInterpolation; + if (tail > 0) + { + sectionAngle.append(tail); + } + return sectionAngle; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetPoints return list of points needed for drawing arc. + * @return list of points + */ +QVector VEllipticalArc::GetPoints() const +{ + QVector points; + QVector sectionAngle = GetAngles(); + + qreal currentAngle; + d->isFlipped ? currentAngle = GetEndAngle() : currentAngle = GetStartAngle(); + for (int i = 0; i < sectionAngle.size(); ++i) + { + QPointF startPoint = GetPoint(currentAngle); + QPointF ellipsePoint2 = GetPoint(currentAngle + sectionAngle.at(i)/3); + QPointF ellipsePoint3 = GetPoint(currentAngle + 2*sectionAngle.at(i)/3); + QPointF lastPoint = GetPoint(currentAngle + sectionAngle.at(i)); + // four points that are on ellipse + + QPointF bezierPoint1 = ( -5*startPoint + 18*ellipsePoint2 -9*ellipsePoint3 + 2*lastPoint )/6; + QPointF bezierPoint2 = ( 2*startPoint - 9*ellipsePoint2 + 18*ellipsePoint3 - 5*lastPoint )/6; + + VSpline spl(VPointF(startPoint), bezierPoint1, bezierPoint2, VPointF(lastPoint), 1.0); + + QVector splPoints = spl.GetPoints(); + + if (not splPoints.isEmpty() && i != sectionAngle.size() - 1) + { + splPoints.removeLast(); + } + points << splPoints; + currentAngle += sectionAngle.at(i); + } + return points; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief CutArc cut arc into two arcs. + * @param length length first arc. + * @param arc1 first arc. + * @param arc2 second arc. + * @return point cutting + */ +QPointF VEllipticalArc::CutArc(const qreal &length, VEllipticalArc &arc1, VEllipticalArc &arc2) const +{ + //Always need return two arcs, so we must correct wrong length. + qreal len = 0; + if (length < this->GetLength()*0.02) + { + len = this->GetLength()*0.02; + } + else if ( length > this->GetLength()*0.98) + { + len = this->GetLength()*0.98; + } + else + { + len = length; + } + + // the first arc has given length and startAngle just like in the origin arc + arc1 = VEllipticalArc (len, QString().setNum(length), d->center, d->radius1, d->radius2, + d->formulaRadius1, d->formulaRadius2, d->f1, d->formulaF1, d->rotationAngle, + getIdObject(), getMode()); + // the second arc has startAngle just like endAngle of the first arc + // and it has endAngle just like endAngle of the origin arc + arc2 = VEllipticalArc (d->center, d->radius1, d->radius2, d->formulaRadius1, d->formulaRadius2, + arc1.GetEndAngle(), arc1.GetFormulaF2(), d->f2, d->formulaF2, d->rotationAngle, + getIdObject(), getMode()); + return arc1.GetP1(); +} + + +//--------------------------------------------------------------------------------------------------------------------- +QPointF VEllipticalArc::CutArc(const qreal &length) const +{ + VEllipticalArc arc1; + VEllipticalArc arc2; + return this->CutArc(length, arc1, arc2); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief setId keep id arc in data. + * @param id id arc in data. + */ +void VEllipticalArc::setId(const quint32 &id) +{ + VAbstractCurve::setId(id); + CreateName(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VEllipticalArc::CreateName() +{ + QString name = EARC_ + QString("%1").arg(this->GetCenter().name()); + + if (VAbstractCurve::id() != NULL_ID) + { + name += QString("_%1").arg(VAbstractCurve::id()); + } + + if (GetDuplicate() > 0) + { + name += QString("_%1").arg(GetDuplicate()); + } + + setName(name); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VEllipticalArc::FindF2(qreal length) +{ + qreal gap = 180; + if (length < 0) + { + d->isFlipped = true; + gap = -gap; + } + while (length > MaxLength()) + { + length = length - MaxLength(); + } + + // We need to calculate the second angle + // first approximation of angle between start and end angles + + qreal endAngle = GetStartAngle() + gap; + d->f2 = endAngle; // we need to set the end anngle, because we want to use GetLength() + + qreal lenBez = GetLength(); // first approximation of length + + qreal eps = 0.001 * qAbs(length); + + while (qAbs(lenBez - length) > eps) + { + gap = gap/2; + if (lenBez > length) + { // we selected too big end angle + endAngle = endAngle - qAbs(gap); + } + else + { // we selected too little end angle + endAngle = endAngle + qAbs(gap); + } + // we need to set d->f2, because we use it when we calculate GetLength + d->f2 = endAngle; + lenBez = GetLength(); + } + d->formulaF2 = QString().number(d->f2); + d->formulaLength = QString().number(qApp->fromPixel(lenBez)); +} + +//--------------------------------------------------------------------------------------------------------------------- +qreal VEllipticalArc::MaxLength() const +{ + const qreal h = ((d->radius1-d->radius2)*(d->radius1-d->radius2))/((d->radius1+d->radius2)*(d->radius1+d->radius2)); + const qreal ellipseLength = M_PI*(d->radius1+d->radius2)*(1+3*h/(10+qSqrt(4-3*h))); + return ellipseLength; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetF1 return start angle. + * @return angle in degree. + */ +QString VEllipticalArc::GetFormulaF1() const +{ + return d->formulaF1; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VEllipticalArc::SetFormulaF1(const QString &formula, qreal value) +{ + d->formulaF1 = formula; + d->f1 = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetF1 return formula for start angle. + * @return string with formula. + */ +qreal VEllipticalArc::GetStartAngle() const +{ + return d->f1; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetF2 return end angle. + * @return angle in degree. + */ +QString VEllipticalArc::GetFormulaF2() const +{ + return d->formulaF2; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VEllipticalArc::SetFormulaF2(const QString &formula, qreal value) +{ + d->formulaF2 = formula; + d->f2 = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetF2 return formula for end angle. + * @return string with formula. + */ +qreal VEllipticalArc::GetEndAngle() const +{ + return d->f2; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetRadius return arc major radius. + * @return radius. + */ +QString VEllipticalArc::GetFormulaRadius1() const +{ + return d->formulaRadius1; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetRadius return arc minor radius. + * @return radius. + */ +QString VEllipticalArc::GetFormulaRadius2() const +{ + return d->formulaRadius2; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetRotationAngle return rotation angle. + * @return rotationAngle. + */ +qreal VEllipticalArc::GetRotationAngle() const +{ + return d->rotationAngle; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VEllipticalArc::SetFormulaRadius1(const QString &formula, qreal value) +{ + d->formulaRadius1 = formula; + d->radius1 = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VEllipticalArc::SetFormulaRadius2(const QString &formula, qreal value) +{ + d->formulaRadius2 = formula; + d->radius2 = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetRadius return formula for major radius. + * @return string with formula. + */ +qreal VEllipticalArc::GetRadius1() const +{ + return d->radius1; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetRadius return formula for minor radius. + * @return string with formula. + */ +qreal VEllipticalArc::GetRadius2() const +{ + return d->radius2; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief GetCenter return center point. + * @return center point. + */ +VPointF VEllipticalArc::GetCenter() const +{ + return d->center; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VEllipticalArc::SetCenter(const VPointF &value) +{ + d->center = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +QString VEllipticalArc::GetFormulaLength() const +{ + return d->formulaLength; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VEllipticalArc::SetFormulaLength(const QString &formula, qreal value) +{ + d->formulaLength = formula; + FindF2(value); +} diff --git a/src/libs/vgeometry/vellipticalarc.h b/src/libs/vgeometry/vellipticalarc.h new file mode 100644 index 000000000..44a3f2cd1 --- /dev/null +++ b/src/libs/vgeometry/vellipticalarc.h @@ -0,0 +1,107 @@ +/************************************************************************ + ** + ** @file vellipticalarc.h + ** @author Valentina Zhuravska + ** @date February 1, 2016 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2013-2015 Valentina project + ** All Rights Reserved. + ** + ** Valentina is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#ifndef VELLIPTICALARC_H +#define VELLIPTICALARC_H + +#include "vabstractcurve.h" +#include "vpointf.h" +#include + +class VEllipticalArcData; + +class VEllipticalArc : public VAbstractCurve +{ + Q_DECLARE_TR_FUNCTIONS(VEllipticalArc) +public: + VEllipticalArc(); + VEllipticalArc (VPointF center, qreal radius1, qreal radius2, QString formulaRadius1, QString formulaRadius2, + qreal f1, QString formulaF1, qreal f2, QString formulaF2, qreal rotationAngle, + quint32 idObject = 0, Draw mode = Draw::Calculation); + + VEllipticalArc (VPointF center, qreal radius1, qreal radius2, qreal f1, qreal f2, qreal rotationAngle); + + VEllipticalArc (qreal length, QString formulaLength, VPointF center, qreal radius1, qreal radius2, + QString formulaRadius1, QString formulaRadius2, qreal f1, QString formulaF1, + qreal rotationAngle, quint32 idObject = 0, Draw mode = Draw::Calculation); + + VEllipticalArc (qreal length, VPointF center, qreal radius1, qreal radius2, qreal f1, qreal rotationAngle); + + VEllipticalArc(const VEllipticalArc &arc); + + VEllipticalArc& operator= (const VEllipticalArc &arc); + + virtual ~VEllipticalArc() Q_DECL_OVERRIDE; + + QString GetFormulaF1 () const; + void SetFormulaF1 (const QString &formula, qreal value); + virtual qreal GetStartAngle () const Q_DECL_OVERRIDE; + + QString GetFormulaF2 () const; + void SetFormulaF2 (const QString &formula, qreal value); + virtual qreal GetEndAngle () const Q_DECL_OVERRIDE; + + qreal GetRotationAngle() const; + + QString GetFormulaRadius1 () const; + void SetFormulaRadius1 (const QString &formula, qreal value); + qreal GetRadius1 () const; + + QString GetFormulaRadius2 () const; + void SetFormulaRadius2 (const QString &formula, qreal value); + qreal GetRadius2 () const; + + VPointF GetCenter () const; + void SetCenter (const VPointF &value); + + QString GetFormulaLength () const; + void SetFormulaLength (const QString &formula, qreal value); + qreal GetLength () const; + + QPointF GetP1() const; + QPointF GetP2 () const; + + qreal AngleArc() const; + QVector GetAngles () const; + QVector GetPoints () const; + QPointF CutArc (const qreal &length, VEllipticalArc &arc1, VEllipticalArc &arc2) const; + QPointF CutArc (const qreal &length) const; + virtual void setId(const quint32 &id) Q_DECL_OVERRIDE; +protected: + virtual void CreateName() Q_DECL_OVERRIDE; +private: + QSharedDataPointer d; + void FindF2(qreal length); + + qreal MaxLength() const; + QPointF GetPoint (qreal angle) const; +}; + +Q_DECLARE_TYPEINFO(VEllipticalArc, Q_MOVABLE_TYPE); + +#endif // VELLIPTICALARC_H diff --git a/src/libs/vgeometry/vellipticalarc_p.h b/src/libs/vgeometry/vellipticalarc_p.h new file mode 100644 index 000000000..d1515ece0 --- /dev/null +++ b/src/libs/vgeometry/vellipticalarc_p.h @@ -0,0 +1,90 @@ +#ifndef VELLIPTICALARC_P +#define VELLIPTICALARC_P + +#include +#include "../vmisc/vabstractapplication.h" +#include "vpointf.h" + +class VEllipticalArcData : public QSharedData +{ +public: + + VEllipticalArcData () + : f1(0), f2(0), formulaF1(QString()), formulaF2(QString()), + radius1(0), radius2(0), formulaRadius1(QString()), formulaRadius2(QString()), + center(VPointF()), isFlipped(false), formulaLength(), rotationAngle(0) + {} + + VEllipticalArcData (VPointF center, qreal radius1, qreal radius2, QString formulaRadius1, QString formulaRadius2, + qreal f1, QString formulaF1, qreal f2, QString formulaF2, qreal rotationAngle) + : f1(f1), f2(f2), formulaF1(formulaF1), formulaF2(formulaF2), + radius1(radius1), radius2(radius2), formulaRadius1(formulaRadius1), formulaRadius2(formulaRadius2), + center(center), isFlipped(false), formulaLength(), rotationAngle(rotationAngle) + {} + + VEllipticalArcData(VPointF center, qreal radius1, qreal radius2, qreal f1, qreal f2, qreal rotationAngle) + : f1(f1), f2(f2), formulaF1(QString().number(f1)), + formulaF2(QString().number(f2)), radius1(radius1), radius2(radius2), + formulaRadius1(QString().number(qApp->fromPixel(radius1))), + formulaRadius2(QString().number(qApp->fromPixel(radius2))), + center(center), isFlipped(false), formulaLength(), rotationAngle(rotationAngle) + {} + + VEllipticalArcData (QString formulaLength, VPointF center, qreal radius1, qreal radius2, + QString formulaRadius1, QString formulaRadius2, qreal f1, QString formulaF1, + qreal rotationAngle) + : f1(f1), f2(0), formulaF1(formulaF1), formulaF2("0"), radius1(radius1),radius2(radius2), + formulaRadius1(formulaRadius1), formulaRadius2(formulaRadius2), + center(center), isFlipped(false), formulaLength(formulaLength), rotationAngle(rotationAngle) + {} + + VEllipticalArcData(VPointF center, qreal radius1, qreal radius2, qreal f1, qreal rotationAngle) + : f1(f1), f2(0), formulaF1(QString().number(f1)), formulaF2("0"), + radius1(radius1), radius2(radius2), + formulaRadius1(QString().number(qApp->fromPixel(radius1))), + formulaRadius2(QString().number(qApp->fromPixel(radius2))), + center(center), isFlipped(false), formulaLength(), rotationAngle(rotationAngle) + {} + + VEllipticalArcData(const VEllipticalArcData &arc) + : QSharedData(arc), f1(arc.f1), f2(arc.f2), formulaF1(arc.formulaF1), formulaF2(arc.formulaF2), + radius1(arc.radius1), radius2(arc.radius2), + formulaRadius1(arc.formulaRadius1), formulaRadius2(arc.formulaRadius2), + center(arc.center), isFlipped(arc.isFlipped), formulaLength(arc.formulaLength), + rotationAngle(arc.rotationAngle) + {} + + virtual ~VEllipticalArcData(); + + /** @brief f1 start angle in degree. */ + qreal f1; + /** @brief f2 end angle in degree. */ + qreal f2; + /** @brief formulaF1 formula for start angle. */ + QString formulaF1; + /** @brief formulaF2 formula for end angle. */ + QString formulaF2; + /** @brief radius1 elliptical arc major radius. */ + qreal radius1; + /** @brief radius2 elliptical arc minor radius. */ + qreal radius2; + /** @brief formulaRadius1 formula for elliptical arc major radius. */ + QString formulaRadius1; + /** @brief formulaRadius2 formula for elliptical arc minor radius. */ + QString formulaRadius2; + /** @brief center center point of arc. */ + VPointF center; + bool isFlipped; + QString formulaLength; + /** @brief rotationAngle in degree. */ + qreal rotationAngle; + +private: + VEllipticalArcData &operator=(const VEllipticalArcData &) Q_DECL_EQ_DELETE; +}; + +VEllipticalArcData::~VEllipticalArcData() +{} + +#endif // VELLIPTICALARC_P + diff --git a/src/libs/vgeometry/vgeometry.pri b/src/libs/vgeometry/vgeometry.pri index d195e20c9..1c80d0ed3 100644 --- a/src/libs/vgeometry/vgeometry.pri +++ b/src/libs/vgeometry/vgeometry.pri @@ -8,7 +8,8 @@ SOURCES += \ $$PWD/vpointf.cpp \ $$PWD/vspline.cpp \ $$PWD/vsplinepath.cpp \ - $$PWD/vsplinepoint.cpp + $$PWD/vsplinepoint.cpp \ + $$PWD/vellipticalarc.cpp win32-msvc*:SOURCES += $$PWD/stable.cpp @@ -28,4 +29,6 @@ HEADERS += \ $$PWD/vsplinepoint.h \ $$PWD/vsplinepoint_p.h \ $$PWD/vgeometrydef.h \ + $$PWD/vellipticalarc.h \ + $$PWD/vellipticalarc_p.h \ $$PWD/vabstractcurve_p.h diff --git a/src/libs/vgeometry/vgeometry.pro b/src/libs/vgeometry/vgeometry.pro index 61861480f..327e1d802 100644 --- a/src/libs/vgeometry/vgeometry.pro +++ b/src/libs/vgeometry/vgeometry.pro @@ -7,6 +7,8 @@ # File with common stuff for whole project include(../../../common.pri) +QT += widgets + # Name of library TARGET = vgeometry diff --git a/src/libs/vgeometry/vgeometrydef.h b/src/libs/vgeometry/vgeometrydef.h index b69e68c7d..9c8840e72 100644 --- a/src/libs/vgeometry/vgeometrydef.h +++ b/src/libs/vgeometry/vgeometrydef.h @@ -32,7 +32,7 @@ #include enum class Draw : char { Calculation, Modeling, Layout }; -enum class GOType : char { Point, Arc, Spline, SplinePath, Unknown }; +enum class GOType : char { Point, Arc, EllipticalArc, Spline, SplinePath, Unknown }; enum class SplinePointPosition : char { FirstPoint, LastPoint }; #endif // VGEOMETRYDEF_H diff --git a/src/test/ValentinaTest/ValentinaTest.pro b/src/test/ValentinaTest/ValentinaTest.pro index cba46d81f..52a187aa9 100644 --- a/src/test/ValentinaTest/ValentinaTest.pro +++ b/src/test/ValentinaTest/ValentinaTest.pro @@ -54,7 +54,8 @@ SOURCES += \ tst_vcommandline.cpp \ tst_tstranslation.cpp \ tst_vdetail.cpp \ - tst_findpoint.cpp + tst_findpoint.cpp \ + tst_vellipticalarc.cpp HEADERS += \ tst_vposter.h \ @@ -76,7 +77,8 @@ HEADERS += \ tst_vcommandline.h \ tst_tstranslation.h \ tst_vdetail.h \ - tst_findpoint.h + tst_findpoint.h \ + tst_vellipticalarc.h # Set using ccache. Function enable_ccache() defined in common.pri. $$enable_ccache() diff --git a/src/test/ValentinaTest/abstracttest.h b/src/test/ValentinaTest/abstracttest.h index 1932c7347..750e8a153 100644 --- a/src/test/ValentinaTest/abstracttest.h +++ b/src/test/ValentinaTest/abstracttest.h @@ -46,7 +46,7 @@ class AbstractTest : public QObject { Q_OBJECT public: - explicit AbstractTest(QObject *parent = 0); + explicit AbstractTest(QObject *parent = nullptr); protected: void Comparison(const QVector &ekv, const QVector &ekvOrig) const; diff --git a/src/test/ValentinaTest/qttestmainlambda.cpp b/src/test/ValentinaTest/qttestmainlambda.cpp index bad3060f0..b1a4f4e1d 100644 --- a/src/test/ValentinaTest/qttestmainlambda.cpp +++ b/src/test/ValentinaTest/qttestmainlambda.cpp @@ -34,6 +34,7 @@ #include "tst_nameregexp.h" #include "tst_vlayoutdetail.h" #include "tst_varc.h" +#include "tst_vellipticalarc.h" #include "tst_measurementregexp.h" #include "tst_tapecommandline.h" #include "tst_valentinacommandline.h" @@ -68,6 +69,7 @@ int main(int argc, char** argv) ASSERT_TEST(new TST_NameRegExp()); ASSERT_TEST(new TST_VLayoutDetail()); ASSERT_TEST(new TST_VArc()); + ASSERT_TEST(new TST_VEllipticalArc()); ASSERT_TEST(new TST_MeasurementRegExp()); ASSERT_TEST(new TST_TapeCommandLine()); ASSERT_TEST(new TST_ValentinaCommandLine()); diff --git a/src/test/ValentinaTest/tst_measurementregexp.h b/src/test/ValentinaTest/tst_measurementregexp.h index f9004585e..322a6e9d9 100644 --- a/src/test/ValentinaTest/tst_measurementregexp.h +++ b/src/test/ValentinaTest/tst_measurementregexp.h @@ -40,7 +40,7 @@ class TST_MeasurementRegExp : public AbstractTest { Q_OBJECT public: - explicit TST_MeasurementRegExp(QObject *parent = 0); + explicit TST_MeasurementRegExp(QObject *parent = nullptr); virtual ~TST_MeasurementRegExp() Q_DECL_OVERRIDE; private slots: diff --git a/src/test/ValentinaTest/tst_nameregexp.h b/src/test/ValentinaTest/tst_nameregexp.h index fc20cc349..12e863bea 100644 --- a/src/test/ValentinaTest/tst_nameregexp.h +++ b/src/test/ValentinaTest/tst_nameregexp.h @@ -35,7 +35,7 @@ class TST_NameRegExp : public QObject { Q_OBJECT public: - explicit TST_NameRegExp(QObject *parent = 0); + explicit TST_NameRegExp(QObject *parent = nullptr); signals: diff --git a/src/test/ValentinaTest/tst_qmutokenparser.h b/src/test/ValentinaTest/tst_qmutokenparser.h index 1431594d3..22930d27d 100644 --- a/src/test/ValentinaTest/tst_qmutokenparser.h +++ b/src/test/ValentinaTest/tst_qmutokenparser.h @@ -36,7 +36,7 @@ class TST_QmuTokenParser : public QObject Q_OBJECT public: Q_DISABLE_COPY(TST_QmuTokenParser) - explicit TST_QmuTokenParser(QObject *parent = 0); + explicit TST_QmuTokenParser(QObject *parent = nullptr); private slots: void IsSingle_data(); diff --git a/src/test/ValentinaTest/tst_tapecommandline.h b/src/test/ValentinaTest/tst_tapecommandline.h index a1ab5b18f..0206497e4 100644 --- a/src/test/ValentinaTest/tst_tapecommandline.h +++ b/src/test/ValentinaTest/tst_tapecommandline.h @@ -35,7 +35,7 @@ class TST_TapeCommandLine : public AbstractTest { Q_OBJECT public: - explicit TST_TapeCommandLine(QObject *parent = 0); + explicit TST_TapeCommandLine(QObject *parent = nullptr); private slots: void init(); diff --git a/src/test/ValentinaTest/tst_tstranslation.h b/src/test/ValentinaTest/tst_tstranslation.h index 3bac4e1e3..fb7fa45e3 100644 --- a/src/test/ValentinaTest/tst_tstranslation.h +++ b/src/test/ValentinaTest/tst_tstranslation.h @@ -38,7 +38,7 @@ class TST_TSTranslation : public QObject { Q_OBJECT public: - explicit TST_TSTranslation(QObject *parent = 0); + explicit TST_TSTranslation(QObject *parent = nullptr); private slots: void CheckEnglishLocalization(); diff --git a/src/test/ValentinaTest/tst_vabstractdetail.h b/src/test/ValentinaTest/tst_vabstractdetail.h index fc8759e92..ea45ab650 100644 --- a/src/test/ValentinaTest/tst_vabstractdetail.h +++ b/src/test/ValentinaTest/tst_vabstractdetail.h @@ -35,7 +35,7 @@ class TST_VAbstractDetail : public AbstractTest { Q_OBJECT public: - explicit TST_VAbstractDetail(QObject *parent = 0); + explicit TST_VAbstractDetail(QObject *parent = nullptr); signals: diff --git a/src/test/ValentinaTest/tst_valentinacommandline.h b/src/test/ValentinaTest/tst_valentinacommandline.h index eb3459436..92c3db54a 100644 --- a/src/test/ValentinaTest/tst_valentinacommandline.h +++ b/src/test/ValentinaTest/tst_valentinacommandline.h @@ -35,7 +35,7 @@ class TST_ValentinaCommandLine : public AbstractTest { Q_OBJECT public: - explicit TST_ValentinaCommandLine(QObject *parent = 0); + explicit TST_ValentinaCommandLine(QObject *parent = nullptr); private slots: void init(); diff --git a/src/test/ValentinaTest/tst_varc.cpp b/src/test/ValentinaTest/tst_varc.cpp index 2f56ae3cb..127d45022 100644 --- a/src/test/ValentinaTest/tst_varc.cpp +++ b/src/test/ValentinaTest/tst_varc.cpp @@ -190,19 +190,19 @@ void TST_VArc::TestGetPoints() } { - qreal gSquere = 0.0;// geometry squere + qreal gSquere = 0.0;// geometry square if (qFuzzyCompare(arc.AngleArc(), 360.0)) - {// circle squere + {// circle square gSquere = M_PI * radius * radius; } else - {// sector squere + {// sector square gSquere = (M_PI * radius * radius) / 360.0 * arc.AngleArc(); points.append(center.toQPointF()); } - // calculated squere + // calculated square const qreal cSquare = qAbs(VAbstractDetail::SumTrapezoids(points)/2.0); const qreal value = qAbs(gSquere - cSquare); const QString errorMsg = diff --git a/src/test/ValentinaTest/tst_varc.h b/src/test/ValentinaTest/tst_varc.h index de4ce7eb7..997533627 100644 --- a/src/test/ValentinaTest/tst_varc.h +++ b/src/test/ValentinaTest/tst_varc.h @@ -35,7 +35,7 @@ class TST_VArc : public QObject { Q_OBJECT public: - explicit TST_VArc(QObject *parent = 0); + explicit TST_VArc(QObject *parent = nullptr); private slots: void CompareTwoWays(); diff --git a/src/test/ValentinaTest/tst_vellipticalarc.cpp b/src/test/ValentinaTest/tst_vellipticalarc.cpp new file mode 100644 index 000000000..84fb24133 --- /dev/null +++ b/src/test/ValentinaTest/tst_vellipticalarc.cpp @@ -0,0 +1,375 @@ +/************************************************************************ + ** + ** @file tst_vellipticalarc.cpp + ** @author Valentina Zhuravska + ** @date 12 2, 2016 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2015 Valentina project + ** All Rights Reserved. + ** + ** Valentina is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#include "tst_vellipticalarc.h" +#include "../vgeometry/vellipticalarc.h" +#include "../vlayout/vabstractdetail.h" + +#include + +//--------------------------------------------------------------------------------------------------------------------- +TST_VEllipticalArc::TST_VEllipticalArc(QObject *parent) : QObject(parent) +{} + +//--------------------------------------------------------------------------------------------------------------------- +// cppcheck-suppress unusedFunction +void TST_VEllipticalArc::CompareTwoWays() +{ + const VPointF center; + const qreal radius1 = 100; + const qreal radius2 = 200; + const qreal f1 = 0; + const qreal f2 = 90; + const qreal rotationAngle = 0; + + const qreal h = ((radius1-radius2)*(radius1-radius2))/((radius1+radius2)*(radius1+radius2)); + const qreal length = M_PI*(radius1+radius2)*(1+3*h/(10+qSqrt(4-3*h)))/4; + + VEllipticalArc arc1(center, radius1, radius2, f1, f2, rotationAngle); + VEllipticalArc arc2(length, center, radius1, radius2, f1, rotationAngle); + + const qreal eps = length*0.5/100; // computing error + const QString errorMsg = + QString("Difference between real and computing lengthes bigger than eps = %1.").number(eps); + QVERIFY2(qAbs(arc1.GetLength() - length) <= eps, qUtf8Printable(errorMsg)); + QVERIFY2(qAbs(arc2.GetLength() - length) <= eps, qUtf8Printable(errorMsg)); + QVERIFY2(qAbs(arc1.GetLength() - arc2.GetLength()) <= eps, qUtf8Printable(errorMsg)); + + // compare angles + QVERIFY2(qAbs(arc1.GetEndAngle() - arc2.GetEndAngle()) <= eps, qUtf8Printable(errorMsg)); + QVERIFY2(qAbs(arc1.GetEndAngle() - f2) <= eps, qUtf8Printable(errorMsg)); + QVERIFY2(qAbs(arc1.GetEndAngle() - f2) <= eps, qUtf8Printable(errorMsg)); +} + +//--------------------------------------------------------------------------------------------------------------------- +// cppcheck-suppress unusedFunction +void TST_VEllipticalArc::NegativeArc() +{ + const VPointF center; + const qreal radius1 = 100; + const qreal radius2 = 200; + const qreal f1 = 1; + const qreal f2 = 181; + const qreal rotationAngle = 0; + + const qreal h = ((radius1-radius2)*(radius1-radius2))/((radius1+radius2)*(radius1+radius2)); + const qreal length = M_PI*(radius1+radius2)*(1+3*h/(10+qSqrt(4-3*h)))/2; + qreal l = -length; + VEllipticalArc arc(l, center, radius1, radius2, f1, rotationAngle); + + const qreal eps = 1; // computing error + const QString errorMsg = + QString("Difference between real and computing lengthes bigger than eps = %1.").number(eps); + + QVERIFY2(qAbs(arc.GetLength() + length) <= eps, qUtf8Printable(errorMsg)); + QVERIFY2(arc.GetEndAngle() - f2 <= eps, qUtf8Printable(errorMsg)); +} + +// cppcheck-suppress unusedFunction +//--------------------------------------------------------------------------------------------------------------------- +void TST_VEllipticalArc::TestGetPoints1_data() +{ + TestData(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void TST_VEllipticalArc::TestGetPoints2_data() +{ + TestData(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void TST_VEllipticalArc::TestGetPoints3_data() +{ + TestData(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void TST_VEllipticalArc::TestGetPoints4_data() +{ + TestData(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void TST_VEllipticalArc::TestData() +{ + QTest::addColumn("radius1"); + QTest::addColumn("radius2"); + QTest::addColumn("startAngle"); + QTest::addColumn("endAngle"); + QTest::addColumn("rotationAngle"); + + QTest::newRow("Full circle: radiuses 10, 20") << 10.0 << 20.0 << 0.0 << 360.0 << 0.0; + QTest::newRow("Full circle: radiuses 150, 200") << 150.0 << 200.0 << 0.0 << 360.0 << 0.0; + QTest::newRow("Full circle: radiuses 150, 200, rotation 30") << 150.0 << 200.0 << 0.0 << 360.0 << 30.0; + QTest::newRow("Full circle: radiuses 1500, 1000") << 1500.0 << 1000.0 << 0.0 << 360.0 << 0.0; + QTest::newRow("Full circle: radiuses 1500, 1000, rotation 50") << 1500.0 << 1000.0 << 0.0 << 360.0 << 50.0; + QTest::newRow("Full circle: radiuses 90000, 80000, rotation 90") << 90000.0 << 80000.0 << 0.0 << 360.0 << 90.0; + + QTest::newRow("Arc less than 45 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 10.5 << 0.0; + QTest::newRow("Arc less than 45 degree, radiuses 150, 50, rotation 180") << 150.0 << 50.0 << 0.0 << 10.5 << 180.0; + QTest::newRow("Arc less than 45 degree, radiuses 1500, 800, rotation 90") << 1500.0 << 800.0 << 0.0 << 10.5 << 90.0; + QTest::newRow("Arc less than 45 degree, radiuses 50000, 10000, rotation 40") + << 50000.0 << 10000.0 << 0.0 << 10.5 << 40.0; + QTest::newRow("Arc less than 45 degree, radiuses 90000, 10000") << 90000.0 << 10000.0 << 0.0 << 10.5 << 0.0; + + QTest::newRow("Arc 45 degree, radiuses 100, 50, rotation 45") << 100.0 << 50.0 << 0.0 << 45.0 << 45.0; + QTest::newRow("Arc 45 degree, radiuses 150, 15, rotation 30") << 150.0 << 15.0 << 0.0 << 45.0 << 30.0; + QTest::newRow("Arc 45 degree, radiuses 1500, 150, rotation 45") << 1500.0 << 150.0 << 0.0 << 45.0 << 45.0; + QTest::newRow("Arc 45 degree, radiuses 50000, 50000") << 50000.0 << 50000.0 << 0.0 << 45.0 << 0.0; + QTest::newRow("Arc 45 degree, radiuses 90000, 50000, rotation 270") << 90000.0 << 50000.0 << 0.0 << 45.0 << 270.0; + + QTest::newRow("Arc less than 90 degree, radiuses 100, 400, rotation 50") << 100.0 << 400.0 << 0.0 << 75.0 << 50.0; + QTest::newRow("Arc less than 90 degree, radiuses 150, 400, rotation 90") << 150.0 << 400.0 << 0.0 << 75.0 << 90.0; + QTest::newRow("Arc less than 90 degree, radiuses 1500, 50000, rotation 180") + << 1500.0 << 50000.0 << 0.0 << 75.0 << 180.0; + QTest::newRow("Arc less than 90 degree, radiuses 50000, 5000, rotation 30") + << 50000.0 << 5000.0 << 0.0 << 75.0 << 30.0; + QTest::newRow("Arc less than 90 degree, radiuses 90000, 50000, rotation 30") + << 90000.0 << 50000.0 << 0.0 << 75.0 << 30.0; + + QTest::newRow("Arc 90 degree, radiuses 100, 50, rotation 30") << 100.0 << 50.0 << 0.0 << 90.0 << 30.0; + QTest::newRow("Arc 90 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 90.0 << 0.0; + QTest::newRow("Arc 90 degree, radiuses 1500, 800, rotation 70") << 1500.0 << 800.0 << 0.0 << 90.0 << 70.0; + QTest::newRow("Arc 90 degree, radiuses 50000, 5000, rotation 30") << 50000.0 << 5000.0 << 0.0 << 90.0 << 30.0; + QTest::newRow("Arc 90 degree, radiuses 90000, 50000, rotation 235") << 90000.0 << 50000.0 << 0.0 << 90.0 << 235.0; + + QTest::newRow("Arc less than 135 degree, radiuses 100, 50, rotation 60") << 100.0 << 50.0 << 0.0 << 110.6 << 60.0; + QTest::newRow("Arc less than 135 degree, radiuses 150, 400, rotation 300") + << 150.0 << 400.0 << 0.0 << 110.6 << 300.0; + QTest::newRow("Arc less than 135 degree, radiuses 1500, 800, rotation 360") + << 1500.0 << 800.0 << 0.0 << 110.6 << 360.0; + QTest::newRow("Arc less than 135 degree, radiuses 50000, 5000, rotation 290") + << 50000.0 << 5000.0 << 0.0 << 110.6 << 290.0; + QTest::newRow("Arc less than 135 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 110.6 << 0.0; + + QTest::newRow("Arc 135 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 135.0 << 0.0; + QTest::newRow("Arc 135 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 135.0 << 0.0; + QTest::newRow("Arc 135 degree, radiuses 1500, 800") << 1500.0 << 800.0 << 0.0 << 135.0 << 0.0; + QTest::newRow("Arc 135 degree, radiuses 50000, 5000, rotation 20") << 50000.0 << 5000.0 << 0.0 << 135.0 << 20.0; + QTest::newRow("Arc 135 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 135.0 << 0.0; + + QTest::newRow("Arc less than 180 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 160.7 << 0.0; + QTest::newRow("Arc less than 180 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 160.7 << 0.0; + QTest::newRow("Arc less than 180 degree, radiuses 1500, 800") << 1500.0 << 800.0 << 0.0 << 160.7 << 0.0; + QTest::newRow("Arc less than 180 degree, radiuses 50000, 5000, rotation 270") + << 50000.0 << 5000.0 << 0.0 << 160.7 << 270.0; + QTest::newRow("Arc less than 180 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 160.7 << 0.0; + + QTest::newRow("Arc 180 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 180.0 << 0.0; + QTest::newRow("Arc 180 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 180.0 << 0.0; + QTest::newRow("Arc 180 degree, radiuses 1500, 800") << 1500.0 << 800.0 << 0.0 << 180.0 << 0.0; + QTest::newRow("Arc 180 degree, radiuses 50000, 5000, rotation 60") << 50000.0 << 5000.0 << 0.0 << 180.0 << 60.0; + QTest::newRow("Arc 180 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 180.0 << 0.0; + + QTest::newRow("Arc less than 270 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 150.3 << 0.0; + QTest::newRow("Arc less than 270 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 150.3 << 0.0; + QTest::newRow("Arc less than 270 degree, radiuses 1500, 800") << 1500.0 << 800.0 << 0.0 << 150.3 << 0.0; + QTest::newRow("Arc less than 270 degree, radiuses 50000, 5000, rotation 20") + << 50000.0 << 5000.0 << 0.0 << 150.3 << 20.0; + QTest::newRow("Arc less than 270 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 150.3 << 0.0; + + QTest::newRow("Arc 270 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 270.0 << 0.0; + QTest::newRow("Arc 270 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 270.0 << 0.0; + QTest::newRow("Arc 270 degree, radiuses 1500, 800") << 1500.0 << 800.0 << 0.0 << 270.0 << 0.0; + QTest::newRow("Arc 270 degree, radiuses 50000, 5000, rotation 90") << 50000.0 << 5000.0 << 0.0 << 270.0 << 90.0; + QTest::newRow("Arc 270 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 270.0 << 0.0; + + QTest::newRow("Arc less than 360 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 340.0 << 0.0; + QTest::newRow("Arc less than 360 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 340.0 << 0.0; + QTest::newRow("Arc less than 360 degree, radiuses 1500, 800") << 1500.0 << 800.0 << 0.0 << 340.0 << 0.0; + QTest::newRow("Arc less than 360 degree, radiuses 50000, 5000, rotation 30") + << 50000.0 << 5000.0 << 0.0 << 340.0 << 30.0; + QTest::newRow("Arc less than 360 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 340.0 << 0.0; + + QTest::newRow("Arc start 90 degree, angle 45 degree, radiuses 100, 50") << 100.0 << 50.0 << 90.0 << 135.0 << 0.0; + QTest::newRow("Arc start 90 degree, angle 45 degree, radiuses 150, 400") << 150.0 << 400.0 << 90.0 << 135.0 << 0.0; + QTest::newRow("Arc start 90 degree, angle 45 degree, radiuses 1500, 800") + << 1500.0 << 800.0 << 90.0 << 135.0 << 0.0; + QTest::newRow("Arc start 90 degree, angle 45 degree, radiuses 50000, 5000") + << 50000.0 << 5000.0 << 90.0 << 135.0 << 0.0; + QTest::newRow("Arc start 90 degree, angle 45 degree, radiuses 90000, 50000") + << 90000.0 << 50000.0 << 90.0 << 135.0 << 0.0; +} + +//--------------------------------------------------------------------------------------------------------------------- +// cppcheck-suppress unusedFunction +void TST_VEllipticalArc::TestGetPoints1() +{ + //Any point must satisfy the equation of ellipse + QFETCH(qreal, radius1); + QFETCH(qreal, radius2); + QFETCH(qreal, startAngle); + QFETCH(qreal, endAngle); + QFETCH(qreal, rotationAngle); + + const VPointF center; + VEllipticalArc arc(center, radius1, radius2, startAngle, endAngle, rotationAngle); + + QVector points = arc.GetPoints(); + if (rotationAngle == 0.0) + { // equation of ellipse will be different when rotation angle isn't 0 so we can't use this test in this case + qreal eps = 0.05; + + for (int i=0; i < points.size(); ++i) + { + QPointF p = points.at(i); + const qreal equationRes = p.rx()*p.rx()/(radius1*radius1) + p.ry()*p.ry()/(radius2*radius2); + const qreal diff = qAbs(equationRes - 1); + const QString errorMsg = QString("Broken the first rule. Any point must satisfy the equation of ellipse." + "diff = '%1' > eps = '%2'").number(diff).number(eps); + QVERIFY2( diff <= eps, qUtf8Printable(errorMsg)); + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +// cppcheck-suppress unusedFunction +void TST_VEllipticalArc::TestGetPoints2() +{ + // Distance from the any point to the focus1 plus distance from this point to the focus2 should be the same. + QFETCH(qreal, radius1); + QFETCH(qreal, radius2); + QFETCH(qreal, startAngle); + QFETCH(qreal, endAngle); + QFETCH(qreal, rotationAngle); + + const VPointF center; + VEllipticalArc arc(center, radius1, radius2, startAngle, endAngle, rotationAngle); + QVector points = arc.GetPoints(); + + const qreal c = qSqrt(qAbs(radius2*radius2 - radius1*radius1)); + // distance from the center to the focus + + QPointF focus1 = center.toQPointF(); + QPointF focus2 = center.toQPointF(); + + if (radius1 < radius2) + { + focus1.setY(focus1.ry() + c); + QLineF line(center.toQPointF(), focus1); + line.setAngle(line.angle() + rotationAngle); + focus1 = line.p2(); + + focus2.setY(focus2.ry() - c); + line.setP2(focus2); + line.setAngle(line.angle() + rotationAngle); + focus2 = line.p2(); + } + else + { + focus1.setX(focus1.rx() + c); + QLineF line(center.toQPointF(), focus1); + line.setAngle(line.angle() + rotationAngle); + focus1 = line.p2(); + + focus2.setX(focus2.rx() - c); + line.setP2(focus2); + line.setAngle(line.angle() + rotationAngle); + focus2 = line.p2(); + } + + QPointF ellipsePoint(center.x() + radius1, center.y()); + QLineF line(center.toQPointF(), ellipsePoint); + line.setAngle(line.angle() + rotationAngle); + ellipsePoint = line.p2(); + + const QLineF distance1(focus1, ellipsePoint); + const QLineF distance2(focus2, ellipsePoint); + + const qreal distance = distance1.length() + distance2.length(); + const qreal eps = distance * 1.1 / 100; // computing error 1.1 % from origin distance + for (int i=0; i < points.size(); ++i) + { + const QLineF rLine1(focus1, points.at(i)); + const QLineF rLine2(focus2, points.at(i)); + const qreal resultingDistance = rLine1.length()+rLine2.length(); + const qreal diff = qAbs(resultingDistance - distance); + const QString errorMsg = QString("Broken the first rule, part 2. Distance from the any point to the focus1" + " plus distance from this point to the focus2 should be the same. Problem" + " with point '%1'. The disired distance is '%2', but resulting distance" + " is '%3'. Difference is '%4' and it biggest than eps '%5')").number(i) + .number(distance).number(resultingDistance).number(diff).number(eps); + QVERIFY2( diff <= eps, qUtf8Printable(errorMsg)); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +// cppcheck-suppress unusedFunction +void TST_VEllipticalArc::TestGetPoints3() +{ + // Compare full ellipse square with square of VAbstractDetail + QFETCH(qreal, radius1); + QFETCH(qreal, radius2); + QFETCH(qreal, startAngle); + QFETCH(qreal, endAngle); + QFETCH(qreal, rotationAngle); + + const VPointF center; + VEllipticalArc arc(center, radius1, radius2, startAngle, endAngle, rotationAngle); + QVector points = arc.GetPoints(); + + if (qFuzzyCompare(arc.AngleArc(), 360.0)) + {// calculated full ellipse square + const qreal ellipseSquare = M_PI * radius1 * radius2; + const qreal epsSquare = ellipseSquare * 0.5 / 100; // computing error 0.5 % from origin squere + const qreal arcSquare = qAbs(VAbstractDetail::SumTrapezoids(points)/2.0); + const qreal diffSquare = qAbs(ellipseSquare - arcSquare); + const QString errorMsg1 = QString("Broken the second rule. Interpolation has too big computing error. " + "Difference ='%1' bigger than eps = '%2'.").arg(diffSquare).arg(epsSquare); + QVERIFY2(diffSquare <= epsSquare, qUtf8Printable(errorMsg1)); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +// cppcheck-suppress unusedFunction +void TST_VEllipticalArc::TestGetPoints4() +{ + // Compare real full ellipse length with calculated + QFETCH(qreal, radius1); + QFETCH(qreal, radius2); + QFETCH(qreal, startAngle); + QFETCH(qreal, endAngle); + QFETCH(qreal, rotationAngle); + + const VPointF center; + VEllipticalArc arc(center, radius1, radius2, startAngle, endAngle, rotationAngle); + + if (qFuzzyCompare(arc.AngleArc(), 360.0)) + {// calculated full ellipse length + const qreal h = ((radius1-radius2)*(radius1-radius2))/((radius1+radius2)*(radius1+radius2)); + const qreal ellipseLength = M_PI*(radius1+radius2)*(1+3*h/(10+qSqrt(4-3*h))); + const qreal epsLength = ellipseLength*0.5/100; // computing error + VEllipticalArc arc(center, radius1, radius2, 0, 360, 0); + const qreal arcLength = arc.GetLength(); + const qreal diffLength = qAbs(arcLength - ellipseLength); + const QString errorMsg2 = QString("Difference between real and computing lengthes " + "(diff = '%1') bigger than eps = '%2'.").arg(diffLength).arg(epsLength); + QVERIFY2(diffLength <= epsLength, qUtf8Printable(errorMsg2)); + } +} diff --git a/src/test/ValentinaTest/tst_vellipticalarc.h b/src/test/ValentinaTest/tst_vellipticalarc.h new file mode 100644 index 000000000..179227f91 --- /dev/null +++ b/src/test/ValentinaTest/tst_vellipticalarc.h @@ -0,0 +1,57 @@ +/************************************************************************ + ** + ** @file tst_vellipticalarc.h + ** @author Valentina Zhuravska + ** @date 12 2, 2016 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2015 Valentina project + ** All Rights Reserved. + ** + ** Valentina is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#ifndef TST_VELLIPTICALARC_H +#define TST_VELLIPTICALARC_H + +#include + +class TST_VEllipticalArc : public QObject +{ + Q_OBJECT +public: + explicit TST_VEllipticalArc(QObject *parent = nullptr); + +private slots: + void CompareTwoWays(); + void NegativeArc(); + void TestGetPoints1_data(); + void TestGetPoints2_data(); + void TestGetPoints3_data(); + void TestGetPoints4_data(); + void TestGetPoints1(); + void TestGetPoints2(); + void TestGetPoints3(); + void TestGetPoints4(); + +private: + Q_DISABLE_COPY(TST_VEllipticalArc) + void TestData(); +}; + +#endif // TST_VELLIPTICALARC_H diff --git a/src/test/ValentinaTest/tst_vlayoutdetail.h b/src/test/ValentinaTest/tst_vlayoutdetail.h index 2b0f08509..e67988ccf 100644 --- a/src/test/ValentinaTest/tst_vlayoutdetail.h +++ b/src/test/ValentinaTest/tst_vlayoutdetail.h @@ -35,7 +35,7 @@ class TST_VLayoutDetail : public AbstractTest { Q_OBJECT public: - explicit TST_VLayoutDetail(QObject *parent = 0); + explicit TST_VLayoutDetail(QObject *parent = nullptr); private slots: void RemoveDublicates() const; diff --git a/src/test/ValentinaTest/tst_vposter.h b/src/test/ValentinaTest/tst_vposter.h index 6fd218d1f..bb403da84 100644 --- a/src/test/ValentinaTest/tst_vposter.h +++ b/src/test/ValentinaTest/tst_vposter.h @@ -38,7 +38,7 @@ class TST_VPoster : public QObject Q_OBJECT public: - explicit TST_VPoster(QObject *parent = 0); + explicit TST_VPoster(QObject *parent = nullptr); signals: diff --git a/src/test/ValentinaTest/tst_vspline.h b/src/test/ValentinaTest/tst_vspline.h index efcf8b2f4..6891b6675 100644 --- a/src/test/ValentinaTest/tst_vspline.h +++ b/src/test/ValentinaTest/tst_vspline.h @@ -35,7 +35,7 @@ class TST_VSpline : public AbstractTest { Q_OBJECT public: - explicit TST_VSpline(QObject *parent = 0); + explicit TST_VSpline(QObject *parent = nullptr); signals: