/************************************************************************ ** ** @file vtooluniondetails.cpp ** @author Roman Telezhynskyi ** @date 26 12, 2013 ** ** @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 "vtooluniondetails.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "../dialogs/tools/dialoguniondetails.h" #include "../ifc/xml/vabstractconverter.h" #include "../ifc/xml/vdomdocument.h" #include "../ifc/xml/vpatternconverter.h" #include "../vgeometry/varc.h" #include "../vgeometry/vellipticalarc.h" #include "../vgeometry/vsplinepath.h" #include "../vgeometry/vabstractcubicbezier.h" #include "../vgeometry/vabstractcubicbezierpath.h" #include "../vgeometry/vgeometrydef.h" #include "../vgeometry/vpointf.h" #include "../vgeometry/vspline.h" #include "../vgeometry/vsplinepoint.h" #include "../vmisc/diagnostic.h" #include "../vmisc/logging.h" #include "../vmisc/vabstractapplication.h" #include "../vpatterndb/vcontainer.h" #include "../vpatterndb/vpiecepath.h" #include "../vpatterndb/vpiecenode.h" #include "../dialogs/tools/dialogtool.h" #include "nodeDetails/vnodearc.h" #include "nodeDetails/vnodeellipticalarc.h" #include "nodeDetails/vnodepoint.h" #include "nodeDetails/vnodespline.h" #include "nodeDetails/vnodesplinepath.h" #include "vdatatool.h" #include "vnodedetail.h" #include "vtoolseamallowance.h" class QDomElement; class QDomNode; class QPointF; const QString VToolUnionDetails::ToolType = QStringLiteral("unionDetails"); const QString VToolUnionDetails::TagDetail = QStringLiteral("det"); const QString VToolUnionDetails::TagNode = QStringLiteral("node"); const QString VToolUnionDetails::TagChildren = QStringLiteral("children"); const QString VToolUnionDetails::TagChild = QStringLiteral("child"); const QString VToolUnionDetails::AttrIndexD1 = QStringLiteral("indexD1"); const QString VToolUnionDetails::AttrIndexD2 = QStringLiteral("indexD2"); const QString VToolUnionDetails::AttrIdObject = QStringLiteral("idObject"); const QString VToolUnionDetails::AttrNodeType = QStringLiteral("nodeType"); const QString VToolUnionDetails::NodeTypeContour = QStringLiteral("Contour"); const QString VToolUnionDetails::NodeTypeModeling = QStringLiteral("Modeling"); QT_WARNING_PUSH QT_WARNING_DISABLE_CLANG("-Wmissing-prototypes") QT_WARNING_DISABLE_INTEL(1418) Q_LOGGING_CATEGORY(vToolUnion, "v.toolUnion") QT_WARNING_POP namespace { //--------------------------------------------------------------------------------------------------------------------- VPiecePath GetPieceMainPath(int piece, VAbstractPattern *doc, quint32 id) { const QDomElement tool = doc->elementById(id); if (tool.isNull()) { VException e(QString("Can't get tool by id='%1'.").arg(id)); throw e; } const QDomNodeList nodesList = tool.childNodes(); for (qint32 i = 0; i < nodesList.size(); ++i) { const QDomElement element = nodesList.at(i).toElement(); if (not element.isNull() && element.tagName() == VToolUnionDetails::TagDetail) { const QDomNodeList detList = element.childNodes(); for (qint32 j = 0; j < detList.size(); ++j) { const QDomElement element = detList.at(j).toElement(); if (not element.isNull() && element.tagName() == VAbstractPattern::TagNodes && j+1 == piece) { return VAbstractPattern::ParsePieceNodes(element); } } } } return VPiecePath(); } //--------------------------------------------------------------------------------------------------------------------- VPiecePath GetPiece1MainPath(VAbstractPattern *doc, quint32 id) { return GetPieceMainPath(1, doc, id); } //--------------------------------------------------------------------------------------------------------------------- VPiecePath GetPiece2MainPath(VAbstractPattern *doc, quint32 id) { return GetPieceMainPath(2, doc, id); } //--------------------------------------------------------------------------------------------------------------------- QString DrawName(VAbstractPattern *doc, quint32 d1id, quint32 d2id) { const QDomElement detail1 = doc->elementById(d1id); if (detail1.isNull()) { return QString(); } const QDomElement detail2 = doc->elementById(d2id); if (detail2.isNull()) { return QString(); } const QDomElement draw1 = detail1.parentNode().parentNode().toElement(); if (draw1.isNull() || not draw1.hasAttribute(VAbstractPattern::AttrName)) { return QString(); } const QDomElement draw2 = detail2.parentNode().parentNode().toElement(); if (draw2.isNull() || not draw2.hasAttribute(VAbstractPattern::AttrName)) { return QString(); } const QString draw1Name = draw1.attribute(VAbstractPattern::AttrName); const QString draw2Name = draw2.attribute(VAbstractPattern::AttrName); if (draw1Name == draw2Name) { return draw1Name; } const QDomElement pattern = draw1.parentNode().toElement(); if (pattern.isNull()) { return QString(); } int indexD1 = 0; int indexD2 = 0; const QDomNodeList listDraws = pattern.elementsByTagName(VAbstractPattern::TagDraw); for (int i=0; i < listDraws.size(); ++i) { const QDomElement draw = listDraws.at(i).toElement(); if (draw == draw1) { indexD1 = i; } if (draw == draw2) { indexD2 = i; } } if (indexD1 >= indexD2) { return draw1Name; } else { return draw2Name; } } //--------------------------------------------------------------------------------------------------------------------- /** * @brief BiasRotatePoint bias and rotate point. * @param point point. * @param dx bias x axis. * @param dy bias y axis. * @param pRotate point rotation. * @param angle angle rotation. */ void BiasRotatePoint(VPointF *point, const qreal &dx, const qreal &dy, const QPointF &pRotate, const qreal &angle) { point->setX(point->x()+dx); point->setY(point->y()+dy); QLineF line(pRotate, *point); line.setAngle(line.angle()+angle); point->setX(line.p2().x()); point->setY(line.p2().y()); } //--------------------------------------------------------------------------------------------------------------------- void PointsOnEdge(const VPiece &d, quint32 index, VPointF &p1, VPointF &p2, VContainer *data) { VPieceNode det2p1; VPieceNode det2p2; d.GetPath().NodeOnEdge(index, det2p1, det2p2); p1 = VPointF(*data->GeometricObject(det2p1.GetId())); p2 = VPointF(*data->GeometricObject(det2p2.GetId())); } //--------------------------------------------------------------------------------------------------------------------- void UnionInitParameters(const VToolUnionDetailsInitData &initData, VPieceNode &det1p1, qreal &dx, qreal &dy, qreal &angle) { const VPiece d1 = initData.data->GetPiece(initData.d1id); VPieceNode det1p2; d1.GetPath().NodeOnEdge(initData.indexD1, det1p1, det1p2); Q_UNUSED(det1p2) VPointF point1; VPointF point2; PointsOnEdge(d1, initData.indexD1, point1, point2, initData.data); VPointF point3; VPointF point4; const VPiece d2 = initData.data->GetPiece(initData.d2id); PointsOnEdge(d2, initData.indexD2, point3, point4, initData.data); dx = point1.x() - point4.x(); dy = point1.y() - point4.y(); point3.setX(point3.x()+dx); point3.setY(point3.y()+dy); point4.setX(point4.x()+dx); point4.setY(point4.y()+dy); const QLineF p4p3 = QLineF(point4, point3); const QLineF p1p2 = QLineF(point1, point2); angle = p4p3.angleTo(p1p2); } //--------------------------------------------------------------------------------------------------------------------- quint32 AddNodePoint(const VPieceNode &node, const VToolUnionDetailsInitData &initData, quint32 idTool, QVector &children, const QString &drawName, qreal dx, qreal dy, quint32 pRotate, qreal angle) { QScopedPointer point(new VPointF(*initData.data->GeometricObject(node.GetId()))); point->setMode(Draw::Modeling); if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID) { BiasRotatePoint(point.data(), dx, dy, *initData.data->GeometricObject(pRotate), angle); } QScopedPointer point1(new VPointF(*point)); const quint32 idObject = initData.data->AddGObject(point.take()); children.append(idObject); point1->setMode(Draw::Modeling); const quint32 id = initData.data->AddGObject(point1.take()); VNodePoint::Create(initData.doc, initData.data, initData.scene, id, idObject, Document::FullParse, Source::FromGui, drawName, idTool); return id; } //--------------------------------------------------------------------------------------------------------------------- quint32 AddNodeArc(const VPieceNode &node, const VToolUnionDetailsInitData &initData, quint32 idTool, QVector &children, const QString &drawName, qreal dx, qreal dy, quint32 pRotate, qreal angle) { const QSharedPointer arc = initData.data->GeometricObject(node.GetId()); VPointF p1 = VPointF(arc->GetP1(), "A", 0, 0); VPointF p2 = VPointF(arc->GetP2(), "A", 0, 0); QScopedPointer center(new VPointF(arc->GetCenter())); if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID) { const QPointF p = *initData.data->GeometricObject(pRotate); BiasRotatePoint(&p1, dx, dy, p, angle); BiasRotatePoint(&p2, dx, dy, p, angle); BiasRotatePoint(center.data(), dx, dy, p, angle); } QLineF l1(*center, p1); QLineF l2(*center, p2); center->setMode(Draw::Modeling); VPointF *tmpCenter = center.take(); const quint32 idCenter = initData.data->AddGObject(tmpCenter); Q_UNUSED(idCenter) QScopedPointer arc1(new VArc(*tmpCenter, arc->GetRadius(), arc->GetFormulaRadius(), l1.angle(), QString().setNum(l1.angle()), l2.angle(), QString().setNum(l2.angle()))); arc1->setMode(Draw::Modeling); QScopedPointerarc2(new VArc(*arc1)); const quint32 idObject = initData.data->AddGObject(arc1.take()); children.append(idObject); arc2->setMode(Draw::Modeling); const quint32 id = initData.data->AddGObject(arc2.take()); VNodeArc::Create(initData.doc, initData.data, id, idObject, Document::FullParse, Source::FromGui, drawName, idTool); return id; } //--------------------------------------------------------------------------------------------------------------------- quint32 AddNodeElArc(const VPieceNode &node, const VToolUnionDetailsInitData &initData, quint32 idTool, QVector &children, const QString &drawName, qreal dx, qreal dy, quint32 pRotate, qreal angle) { const QSharedPointer arc = initData.data->GeometricObject(node.GetId()); VPointF p1 = VPointF(arc->GetP1(), "A", 0, 0); VPointF p2 = VPointF(arc->GetP2(), "A", 0, 0); QScopedPointer center(new VPointF(arc->GetCenter())); if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID) { const QPointF p = *initData.data->GeometricObject(pRotate); BiasRotatePoint(&p1, dx, dy, p, angle); BiasRotatePoint(&p2, dx, dy, p, angle); BiasRotatePoint(center.data(), dx, dy, p, angle); } QLineF l1(*center, p1); QLineF l2(*center, p2); center->setMode(Draw::Modeling); VPointF *tmpCenter = center.take(); quint32 idCenter = initData.data->AddGObject(tmpCenter); Q_UNUSED(idCenter) QScopedPointer arc1(new VEllipticalArc (*tmpCenter, arc->GetRadius1(), arc->GetRadius2(), arc->GetFormulaRadius1(), arc->GetFormulaRadius2(), l1.angle(), QString().setNum(l1.angle()), l2.angle(), QString().setNum(l2.angle()), 0, "0")); arc1->setMode(Draw::Modeling); QScopedPointer arc2(new VEllipticalArc(*arc1)); const quint32 idObject = initData.data->AddGObject(arc1.take()); children.append(idObject); arc2->setMode(Draw::Modeling); const quint32 id = initData.data->AddGObject(arc2.take()); VNodeEllipticalArc::Create(initData.doc, initData.data, id, idObject, Document::FullParse, Source::FromGui, drawName, idTool); return id; } //--------------------------------------------------------------------------------------------------------------------- quint32 AddNodeSpline(const VPieceNode &node, const VToolUnionDetailsInitData &initData, quint32 idTool, QVector &children, const QString &drawName, qreal dx, qreal dy, quint32 pRotate, qreal angle) { const QSharedPointer spline = initData.data->GeometricObject(node.GetId()); QScopedPointer p1(new VPointF(spline->GetP1())); VPointF p2 = VPointF(spline->GetP2()); VPointF p3 = VPointF(spline->GetP3()); QScopedPointer p4(new VPointF(spline->GetP4())); if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID) { const QPointF p = *initData.data->GeometricObject(pRotate); BiasRotatePoint(p1.data(), dx, dy, p, angle); BiasRotatePoint(&p2, dx, dy, p, angle); BiasRotatePoint(&p3, dx, dy, p, angle); BiasRotatePoint(p4.data(), dx, dy, p, angle); } VSpline *spl = new VSpline(*p1, p2, p3, *p4, 0, Draw::Modeling); const quint32 idObject = initData.data->AddGObject(spl); children.append(idObject); VSpline *spl1 = new VSpline(*spl); spl1->setMode(Draw::Modeling); const quint32 id = initData.data->AddGObject(spl1); VNodeSpline::Create(initData.doc, initData.data, id, idObject, Document::FullParse, Source::FromGui, drawName, idTool); return id; } //--------------------------------------------------------------------------------------------------------------------- quint32 AddNodeSplinePath(const VPieceNode &node, const VToolUnionDetailsInitData &initData, quint32 idTool, QVector &children, const QString &drawName, qreal dx, qreal dy, quint32 pRotate, qreal angle) { QScopedPointer path(new VSplinePath()); path->setMode(Draw::Modeling); const QSharedPointer splinePath = initData.data->GeometricObject(node.GetId()); for (qint32 i = 1; i <= splinePath->CountSubSpl(); ++i) { const VSpline spline = splinePath->GetSpline(i); QScopedPointer p1(new VPointF(spline.GetP1())); VPointF p2 = VPointF(spline.GetP2()); VPointF p3 = VPointF(spline.GetP3()); QScopedPointer p4(new VPointF(spline.GetP4())); if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID) { const QPointF p = *initData.data->GeometricObject(pRotate); BiasRotatePoint(p1.data(), dx, dy, p, angle); BiasRotatePoint(&p2, dx, dy, p, angle); BiasRotatePoint(&p3, dx, dy, p, angle); BiasRotatePoint(p4.data(), dx, dy, p, angle); } VSpline spl = VSpline(*p1, p2, p3, *p4); if (i==1) { const qreal angle1 = spl.GetStartAngle()+180; const QString angle1F = QString().number(angle1); path->append(VSplinePoint(*p1, angle1, angle1F, spl.GetStartAngle(), spl.GetStartAngleFormula(), 0, "0", spline.GetC1Length(), spline.GetC1LengthFormula())); } const qreal angle2 = spl.GetEndAngle()+180; const QString angle2F = QString().number(angle2); qreal pL2 = 0; QString pL2F("0"); if (i+1 <= splinePath->CountSubSpl()) { const VSpline nextSpline = splinePath->GetSpline(i+1); pL2 = nextSpline.GetC1Length(); pL2F = nextSpline.GetC1LengthFormula(); } path->append(VSplinePoint(*p4, spl.GetEndAngle(), spl.GetEndAngleFormula(), angle2, angle2F, spline.GetC2Length(), spline.GetC2LengthFormula(), pL2, pL2F)); } QScopedPointer path1(new VSplinePath(*path)); const quint32 idObject = initData.data->AddGObject(path.take()); children.append(idObject); path1->setMode(Draw::Modeling); const quint32 id = initData.data->AddGObject(path1.take()); VNodeSplinePath::Create(initData.doc, initData.data, id, idObject, Document::FullParse, Source::FromGui, drawName, idTool); return id; } //--------------------------------------------------------------------------------------------------------------------- /** * @brief AddToNewDetail create united detail adding one node per time. */ void AddNodeToNewDetail(const VToolUnionDetailsInitData &initData, VPiece &newDetail, const VPiecePath &det, int i, quint32 idTool, QVector &children, const QString &drawName, qreal dx = 0, qreal dy = 0, quint32 pRotate = NULL_ID, qreal angle = 0); void AddNodeToNewDetail(const VToolUnionDetailsInitData &initData, VPiece &newDetail, const VPiecePath &det, int i, quint32 idTool, QVector &children, const QString &drawName, qreal dx, qreal dy, quint32 pRotate, qreal angle) { const VPieceNode &node = det.at(i); quint32 id = 0; switch (node.GetTypeTool()) { case (Tool::NodePoint): id = AddNodePoint(node, initData, idTool, children, drawName, dx, dy, pRotate, angle); break; case (Tool::NodeArc): id = AddNodeArc(node, initData, idTool, children, drawName, dx, dy, pRotate, angle); break; case (Tool::NodeElArc): id = AddNodeElArc(node, initData, idTool, children, drawName, dx, dy, pRotate, angle); break; case (Tool::NodeSpline): id = AddNodeSplinePath(node, initData, idTool, children, drawName, dx, dy, pRotate, angle); break; case (Tool::NodeSplinePath): id = AddNodeSplinePath(node, initData, idTool, children, drawName, dx, dy, pRotate, angle); break; default: qDebug()<<"May be wrong tool type!!! Ignoring."< &children) { QDomElement toolUnion = doc->elementById(id); if (toolUnion.isNull()) { return; } QDomElement tagChildren = doc->createElement(VToolUnionDetails::TagChildren); QDomElement tagNodes = doc->createElement(VAbstractPattern::TagNodes); for (int i=0; icreateElement(VToolUnionDetails::TagChild); tagChild.appendChild(doc->createTextNode(QString().setNum(children.at(i)))); tagNodes.appendChild(tagChild); } tagChildren.appendChild(tagNodes); toolUnion.appendChild(tagChildren); } //--------------------------------------------------------------------------------------------------------------------- QVector GetNodesChildren(VAbstractPattern *doc, quint32 id) { const QDomElement toolUnion = doc->elementById(id); if (toolUnion.isNull()) { return QVector(); } const QDomElement tagChildren = toolUnion.firstChildElement(VToolUnionDetails::TagChildren); if (tagChildren.isNull()) { return QVector(); } const QDomElement tagNodes = tagChildren.firstChildElement(VAbstractPattern::TagNodes); if (tagNodes.isNull()) { return QVector(); } QVector childrenId; const QDomNodeList listChildren = tagNodes.elementsByTagName(VToolUnionDetails::TagChild); for (int i=0; i < listChildren.size(); ++i) { const QDomElement domElement = listChildren.at(i).toElement(); if (not domElement.isNull()) { childrenId.append(domElement.text().toUInt()); } } return childrenId; } //--------------------------------------------------------------------------------------------------------------------- quint32 TakeNextId(QVector &children) { quint32 idChild = NULL_ID; if (not children.isEmpty()) { #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) idChild = children.takeFirst(); #else idChild = children.first(); children.remove(0); #endif } else { idChild = NULL_ID; } return idChild; } //--------------------------------------------------------------------------------------------------------------------- void UpdateNodePoint(VContainer *data, const VPieceNode &node, QVector &children, qreal dx, qreal dy, quint32 pRotate, qreal angle) { QScopedPointer point(new VPointF(*data->GeometricObject(node.GetId()))); point->setMode(Draw::Modeling); if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID) { BiasRotatePoint(point.data(), dx, dy, *data->GeometricObject(pRotate), angle); } data->UpdateGObject(TakeNextId(children), point.take()); } //--------------------------------------------------------------------------------------------------------------------- void UpdateNodeArc(VContainer *data, const VPieceNode &node, QVector &children, qreal dx, qreal dy, quint32 pRotate, qreal angle) { const QSharedPointer arc = data->GeometricObject(node.GetId()); VPointF p1 = VPointF(arc->GetP1()); VPointF p2 = VPointF(arc->GetP2()); QScopedPointer center(new VPointF(arc->GetCenter())); if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID) { const QPointF p = *data->GeometricObject(pRotate); BiasRotatePoint(&p1, dx, dy, p, angle); BiasRotatePoint(&p2, dx, dy, p, angle); BiasRotatePoint(center.data(), dx, dy, p, angle); } QLineF l1(*center, p1); QLineF l2(*center, p2); QScopedPointer arc1(new VArc(*center, arc->GetRadius(), arc->GetFormulaRadius(), l1.angle(), QString().setNum(l1.angle()), l2.angle(), QString().setNum(l2.angle()))); arc1->setMode(Draw::Modeling); data->UpdateGObject(TakeNextId(children), arc1.take()); } //--------------------------------------------------------------------------------------------------------------------- void UpdateNodeElArc(VContainer *data, const VPieceNode &node, QVector &children, qreal dx, qreal dy, quint32 pRotate, qreal angle) { const QSharedPointer arc = data->GeometricObject(node.GetId()); VPointF p1 = VPointF(arc->GetP1()); VPointF p2 = VPointF(arc->GetP2()); QScopedPointer center(new VPointF(arc->GetCenter())); if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID) { const QPointF p = *data->GeometricObject(pRotate); BiasRotatePoint(&p1, dx, dy, p, angle); BiasRotatePoint(&p2, dx, dy, p, angle); BiasRotatePoint(center.data(), dx, dy, p, angle); } QLineF l1(*center, p1); QLineF l2(*center, p2); QScopedPointer arc1(new VEllipticalArc (*center, arc->GetRadius1(), arc->GetRadius2(), arc->GetFormulaRadius1(), arc->GetFormulaRadius2(), l1.angle(), QString().setNum(l1.angle()), l2.angle(), QString().setNum(l2.angle()), 0, "0")); arc1->setMode(Draw::Modeling); data->UpdateGObject(TakeNextId(children), arc1.take()); } //--------------------------------------------------------------------------------------------------------------------- void UpdateNodeSpline(VContainer *data, const VPieceNode &node, QVector &children, qreal dx, qreal dy, quint32 pRotate, qreal angle) { const QSharedPointer spline = data->GeometricObject(node.GetId()); QScopedPointer p1(new VPointF(spline->GetP1())); VPointF p2 = VPointF(spline->GetP2()); VPointF p3 = VPointF(spline->GetP3()); QScopedPointer p4(new VPointF(spline->GetP4())); if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID) { const QPointF p = *data->GeometricObject(pRotate); BiasRotatePoint(p1.data(), dx, dy, p, angle); BiasRotatePoint(&p2, dx, dy, p, angle); BiasRotatePoint(&p3, dx, dy, p, angle); BiasRotatePoint(p4.data(), dx, dy, p, angle); } QScopedPointer spl(new VSpline(*p1, p2, p3, *p4, 0, Draw::Modeling)); data->UpdateGObject(TakeNextId(children), spl.take()); } //--------------------------------------------------------------------------------------------------------------------- void UpdateNodeSplinePath(VContainer *data, const VPieceNode &node, QVector &children, qreal dx, qreal dy, quint32 pRotate, qreal angle) { QScopedPointer path(new VSplinePath()); path->setMode(Draw::Modeling); const QSharedPointer splinePath = data->GeometricObject(node.GetId()); SCASSERT(splinePath != nullptr) for (qint32 i = 1; i <= splinePath->CountSubSpl(); ++i) { const VSpline spline = splinePath->GetSpline(i); QScopedPointer p1(new VPointF(spline.GetP1())); VPointF p2 = VPointF(spline.GetP2()); VPointF p3 = VPointF(spline.GetP3()); QScopedPointer p4(new VPointF(spline.GetP4())); if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID) { const QPointF p = *data->GeometricObject(pRotate); BiasRotatePoint(p1.data(), dx, dy, p, angle); BiasRotatePoint(&p2, dx, dy, p, angle); BiasRotatePoint(&p3, dx, dy, p, angle); BiasRotatePoint(p4.data(), dx, dy, p, angle); } VSpline spl = VSpline(*p1, p2, p3, *p4); if (i==1) { const qreal angle1 = spl.GetStartAngle()+180; const QString angle1F = QString().number(angle1); path->append(VSplinePoint(*p1, angle1, angle1F, spl.GetStartAngle(), spl.GetStartAngleFormula(), 0, "0", spline.GetC1Length(), spline.GetC1LengthFormula())); } const qreal angle2 = spl.GetEndAngle()+180; const QString angle2F = QString().number(angle2); qreal pL2 = 0; QString pL2F("0"); if (i+1 <= splinePath->CountSubSpl()) { const VSpline nextSpline = splinePath->GetSpline(i+1); pL2 = nextSpline.GetC1Length(); pL2F = nextSpline.GetC1LengthFormula(); } path->append(VSplinePoint(*p4, spl.GetEndAngle(), spl.GetEndAngleFormula(), angle2, angle2F, spline.GetC2Length(), spline.GetC2LengthFormula(), pL2, pL2F)); } data->UpdateGObject(TakeNextId(children), path.take()); } //--------------------------------------------------------------------------------------------------------------------- /** * @brief UpdateNodes update nodes of united detail. * @param data container with variables. * @param det detail's nodes. * @param i index node in detail. * @param children list ids of all children. * @param dx bias node x axis. * @param dy bias node y axis. * @param pRotate point rotation. * @param angle angle rotation. */ void UpdateNodes(VContainer *data, const VPiecePath &det, int i, QVector &children, qreal dx = 0, qreal dy = 0, quint32 pRotate = NULL_ID, qreal angle = 0); void UpdateNodes(VContainer *data, const VPiecePath &det, int i, QVector &children, qreal dx, qreal dy, quint32 pRotate, qreal angle) { const VPieceNode &node = det.at(i); switch (node.GetTypeTool()) { case (Tool::NodePoint): UpdateNodePoint(data, node, children, dx, dy, pRotate, angle); break; case (Tool::NodeArc): UpdateNodeArc(data, node, children, dx, dy, pRotate, angle); break; case (Tool::NodeElArc): UpdateNodeElArc(data, node, children, dx, dy, pRotate, angle); break; case (Tool::NodeSpline): UpdateNodeSpline(data, node, children, dx, dy, pRotate, angle); break; case (Tool::NodeSplinePath): UpdateNodeSplinePath(data, node, children, dx, dy, pRotate, angle); break; default: qDebug()<<"May be wrong tool type!!! Ignoring."<GetPiece(initData.d1id); const VPiecePath d1Path = d1.GetPath().RemoveEdge(initData.indexD1); const VPiece d2 = initData.data->GetPiece(initData.d2id); const VPiecePath d2Path = d2.GetPath().RemoveEdge(initData.indexD2); const qint32 countNodeD1 = d1Path.CountNodes(); const qint32 countNodeD2 = d2Path.CountNodes(); qint32 i = 0; VPiece newDetail; QVector children; const int det1P1Index = d1.GetPath().indexOfNode(det1p1.GetId()); do { AddNodeToNewDetail(initData, newDetail, d1Path, i, id, children, drawName); ++i; if (i > det1P1Index && pointsD2 < countNodeD2-1) { qint32 j = 0; FindIndexJ(pointsD2, d2.GetPath(), initData.indexD2, j); do { if (j >= countNodeD2) { j=0; } AddNodeToNewDetail(initData, newDetail, d2Path, j, id, children, drawName, dx, dy, det1p1.GetId(), angle); ++pointsD2; ++j; } while (pointsD2 < countNodeD2-1); } } while (i < countNodeD1); SCASSERT(not children.isEmpty()) SaveNodesChildren(initData.doc, id, children); newDetail.SetName(QObject::tr("United detail")); newDetail.SetSAWidth(d1.GetSAWidth()); newDetail.SetMx(d1.GetMx()); newDetail.SetMy(d1.GetMy()); VToolSeamAllowance::Create(0, newDetail, initData.scene, initData.doc, initData.data, initData.parse, Source::FromTool, drawName); auto RemoveDetail = [initData](quint32 id) { VToolSeamAllowance *toolDet = qobject_cast(initData.doc->getTool(id)); SCASSERT(toolDet != nullptr); bool ask = false; toolDet->Remove(ask); }; if (not initData.retainPieces) { RemoveDetail(initData.d1id); RemoveDetail(initData.d2id); } } //--------------------------------------------------------------------------------------------------------------------- void UpdateUnitedDetail(qint32 &pointsD2, quint32 id, const VToolUnionDetailsInitData &initData, const VPieceNode &det1p1, qreal dx, qreal dy, qreal angle) { const VPiecePath d1Path = GetPiece1MainPath(initData.doc, initData.d1id); const VPiecePath d1REPath = d1Path.RemoveEdge(initData.indexD1); const VPiecePath d2Path = GetPiece2MainPath(initData.doc, initData.d2id); const VPiecePath d2REPath = d2Path.RemoveEdge(initData.indexD2); const qint32 countNodeD1 = d1REPath.CountNodes(); const qint32 countNodeD2 = d2REPath.CountNodes(); QVector children = GetNodesChildren(initData.doc, id); if (not children.isEmpty()) { // This check need for backward compatibility // Remove check and "else" part if min version is 0.3.2 Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 3, 2), "Time to refactor the code."); if (children.size() == countNodeD1 + countNodeD2-1) { qint32 i = 0; const int indexOfNode = d1Path.indexOfNode(det1p1.GetId()); do { UpdateNodes(initData.data, d1REPath, i, children); ++i; if (i > indexOfNode && pointsD2 < countNodeD2-1) { qint32 j = 0; FindIndexJ(pointsD2, d2Path, initData.indexD2, j); do { if (j >= countNodeD2) { j=0; } UpdateNodes(initData.data, d2REPath, j, children, dx, dy, det1p1.GetId(), angle); ++pointsD2; ++j; } while (pointsD2 < countNodeD2-1); } } while (i indexOfNode) { const int childrenCount = children.size(); qint32 j = 0; FindIndexJ(pointsD2, d2Path, initData.indexD2, j); do { if (j >= countNodeD2) { j=0; } UpdateNodes(initData.data, d2REPath, j, children, dx, dy, det1p1.GetId(), angle); ++pointsD2; ++j; } while (pointsD2 < childrenCount); break; } } while (i objects = GetReferenceObjects(); for(int i = 0; i < objects.size(); ++i) { doc->IncrementReferens(objects.at(i)); } QDomElement domElement = doc->elementById(id); if (domElement.isElement()) { doc->SetParametrUsage(domElement, AttrInUse, NodeUsage::InUse); } } } //--------------------------------------------------------------------------------------------------------------------- void VToolUnionDetails::decrementReferens() { VDataTool::decrementReferens(); if (_referens == 0) { const QVector objects = GetReferenceObjects(); for(int i = 0; i < objects.size(); ++i) { doc->DecrementReferens(objects.at(i)); } QDomElement domElement = doc->elementById(id); if (domElement.isElement()) { doc->SetParametrUsage(domElement, AttrInUse, NodeUsage::NotInUse); } } } //--------------------------------------------------------------------------------------------------------------------- void VToolUnionDetails::GroupVisibility(quint32 object, bool visible) { Q_UNUSED(object) Q_UNUSED(visible) } //--------------------------------------------------------------------------------------------------------------------- /** * @brief Create help create tool from GUI. * @param dialog dialog. * @param doc dom document container. * @param data container with variables. */ VToolUnionDetails* VToolUnionDetails::Create(DialogTool *dialog, VMainGraphicsScene *scene, VAbstractPattern *doc, VContainer *data) { SCASSERT(dialog != nullptr) const DialogUnionDetails *dialogTool = qobject_cast(dialog); SCASSERT(dialogTool != nullptr) VToolUnionDetailsInitData initData; initData.d1id = dialogTool->getD1(); initData.d2id = dialogTool->getD2(); initData.indexD1 = static_cast(dialogTool->getIndexD1()); initData.indexD2 = static_cast(dialogTool->getIndexD2()); initData.scene = scene; initData.doc = doc; initData.data = data; initData.parse = Document::FullParse; initData.typeCreation = Source::FromGui; initData.retainPieces = dialogTool->RetainPieces(); qApp->getUndoStack()->beginMacro(tr("union details")); VToolUnionDetails* tool = Create(0, initData); qApp->getUndoStack()->endMacro(); return tool; } //--------------------------------------------------------------------------------------------------------------------- /** * @brief Create help create tool. * @param _id tool id, 0 if tool doesn't exist yet. * @param d1 first detail. * @param d2 second detail. * @param d1id id first detail. * @param d2id id second detail. * @param indexD1 index edge in first detail. * @param indexD2 index edge in second detail. * @param scene pointer to scene. * @param doc dom document container. * @param data container with variables. * @param parse parser file mode. * @param typeCreation way we create this tool. */ VToolUnionDetails* VToolUnionDetails::Create(const quint32 _id, const VToolUnionDetailsInitData &initData) { VToolUnionDetails *unionDetails = nullptr; quint32 id = _id; if (initData.typeCreation == Source::FromGui) { id = initData.data->getNextId(); } else { if (initData.parse != Document::FullParse) { initData.doc->UpdateToolData(id, initData.data); } } //First add tool to file VAbstractTool::AddRecord(id, Tool::UnionDetails, initData.doc); if (initData.parse == Document::FullParse) { //Scene doesn't show this tool, so doc will destroy this object. unionDetails = new VToolUnionDetails(id, initData); initData.doc->AddTool(id, unionDetails); // Unfortunatelly doc will destroy all objects only in the end, but we should delete them before each FullParse initData.doc->AddToolOnRemove(unionDetails); } UniteDetails(id, initData); return unionDetails; } //--------------------------------------------------------------------------------------------------------------------- /** * @brief AddToFile add tag with informations about tool into file. */ void VToolUnionDetails::AddToFile() { QDomElement domElement = doc->createElement(getTagName()); doc->SetAttribute(domElement, VDomDocument::AttrId, id); doc->SetAttribute(domElement, AttrType, ToolType); doc->SetAttribute(domElement, AttrIndexD1, indexD1); doc->SetAttribute(domElement, AttrIndexD2, indexD2); AddDetail(domElement, data.GetPiece(d1id)); AddDetail(domElement, data.GetPiece(d2id)); AddToModeling(domElement); } //--------------------------------------------------------------------------------------------------------------------- /** * @brief RefreshDataInFile refresh attributes in file. If attributes don't exist create them. */ void VToolUnionDetails::RefreshDataInFile() { // do nothing } //--------------------------------------------------------------------------------------------------------------------- /** * @brief AddDetail add detail to xml file. * @param domElement tag in xml tree. * @param d detail. */ void VToolUnionDetails::AddDetail(QDomElement &domElement, const VPiece &d) const { QDomElement det = doc->createElement(TagDetail); // nodes VToolSeamAllowance::AddNodes(doc, det, d); //custom seam allowance VToolSeamAllowance::AddCSARecords(doc, det, d.GetCustomSARecords()); VToolSeamAllowance::AddInternalPaths(doc, det, d.GetInternalPaths()); domElement.appendChild(det); } //--------------------------------------------------------------------------------------------------------------------- /** * @brief AddToModeling add tool to xml tree. * @param domElement tag in xml tree. */ void VToolUnionDetails::AddToModeling(const QDomElement &domElement) { const QString drawName = DrawName(doc, d1id, d2id); SCASSERT(not drawName.isEmpty()) QDomElement modeling = doc->GetDraw(drawName).firstChildElement(VAbstractPattern::TagModeling); if (not modeling.isNull()) { modeling.appendChild(domElement); } else { qCCritical(vToolUnion, "Can't find tag %s.", qUtf8Printable(VAbstractPattern::TagModeling)); return; } } //--------------------------------------------------------------------------------------------------------------------- QVector VToolUnionDetails::GetReferenceObjects() const { QVector list; const QDomElement tool = doc->elementById(id); if (tool.isNull()) { return list; } const QStringList parts = QStringList() << VAbstractPattern::TagNodes /*0*/ << VToolSeamAllowance::TagCSA /*1*/ << VToolSeamAllowance::TagIPaths; /*2*/ const QDomNodeList nodesList = tool.childNodes(); for (qint32 i = 0; i < nodesList.size(); ++i) { const QDomElement element = nodesList.at(i).toElement(); if (not element.isNull() && element.tagName() == VToolUnionDetails::TagDetail) { const QDomNodeList detList = element.childNodes(); for (qint32 j = 0; j < detList.size(); ++j) { const QDomElement element = detList.at(j).toElement(); if (not element.isNull()) { switch (parts.indexOf(element.tagName())) { case 0://VAbstractPattern::TagNodes list += NodesReferenceObjects(element); break; case 1://VToolSeamAllowance::TagCSA case 2://VToolSeamAllowance::TagIPaths { const quint32 id = doc->GetParametrUInt(element, VToolSeamAllowance::AttrPath, NULL_ID_STR); if (id > NULL_ID) { list.append(id); } break; } default: break; } } } } } return list; } //--------------------------------------------------------------------------------------------------------------------- QVector VToolUnionDetails::NodesReferenceObjects(const QDomElement &nodes) const { QVector list; const QDomNodeList nodeList = nodes.childNodes(); for (qint32 i = 0; i < nodeList.size(); ++i) { const QDomElement element = nodeList.at(i).toElement(); if (not element.isNull() && element.tagName() == VToolUnionDetails::TagNode) { const quint32 id = doc->GetParametrUInt(element, AttrIdObject, NULL_ID_STR); if (id > NULL_ID) { list.append(id); } } } return list; }