diff --git a/src/app/core/vapplication.cpp b/src/app/core/vapplication.cpp
index 74bb563de..5986897ad 100644
--- a/src/app/core/vapplication.cpp
+++ b/src/app/core/vapplication.cpp
@@ -516,6 +516,7 @@ void VApplication::ClearOldLogs() const
                 qCDebug(vApp) << "Failed to lock"<<info.absoluteFilePath();
             }
             delete lock;
+            lock = nullptr;
         }
     }
     else
diff --git a/src/app/dialogs/tools/dialogdetail.cpp b/src/app/dialogs/tools/dialogdetail.cpp
index b4bded7e0..4605084a4 100644
--- a/src/app/dialogs/tools/dialogdetail.cpp
+++ b/src/app/dialogs/tools/dialogdetail.cpp
@@ -69,6 +69,7 @@ DialogDetail::DialogDetail(const VContainer *data, const quint32 &toolId, QWidge
             this, &DialogDetail::BiasYChanged);
     connect(ui.checkBoxSeams, &QCheckBox::clicked, this, &DialogDetail::ClickedSeams);
     connect(ui.checkBoxClosed, &QCheckBox::clicked, this, &DialogDetail::ClickedClosed);
+    connect(ui.checkBoxReverse, &QCheckBox::clicked, this, &DialogDetail::ClickedReverse);
     connect(ui.lineEditNameDetail, &QLineEdit::textChanged, this, &DialogDetail::NamePointChanged);
 
     connect(ui.toolButtonDelete, &QToolButton::clicked, this, &DialogDetail::DeleteItem);
@@ -133,9 +134,10 @@ void DialogDetail::SaveData()
  * @param typeNode type of node in detail
  * @param mx offset respect to x
  * @param my offset respect to y
+ * @param reverse reverse list of points
  */
 void DialogDetail::NewItem(quint32 id, const Tool &typeTool, const NodeDetail &typeNode,
-                           qreal mx, qreal my)
+                           qreal mx, qreal my, bool reverse)
 {
     QString name;
     switch (typeTool)
@@ -171,14 +173,27 @@ void DialogDetail::NewItem(quint32 id, const Tool &typeTool, const NodeDetail &t
 
     QListWidgetItem *item = new QListWidgetItem(name);
     item->setFont(QFont("Times", 12, QFont::Bold));
-    VNodeDetail node(id, typeTool, typeNode, mx, my);
+    VNodeDetail node(id, typeTool, typeNode, mx, my, reverse);
     item->setData(Qt::UserRole, QVariant::fromValue(node));
     ui.listWidget->addItem(item);
     ui.listWidget->setCurrentRow(ui.listWidget->count()-1);
+
     ui.doubleSpinBoxBiasX->blockSignals(true);
     ui.doubleSpinBoxBiasY->blockSignals(true);
+
     ui.doubleSpinBoxBiasX->setValue(qApp->fromPixel(node.getMx()));
     ui.doubleSpinBoxBiasY->setValue(qApp->fromPixel(node.getMy()));
+    if (node.getTypeTool() == Tool::NodePoint)
+    {
+        ui.checkBoxReverse->setChecked(false);
+        ui.checkBoxReverse->setEnabled(false);
+    }
+    else
+    {
+        ui.checkBoxReverse->setEnabled(true);
+        ui.checkBoxReverse->setChecked(node.getReverse());
+    }
+
     ui.doubleSpinBoxBiasX->blockSignals(false);
     ui.doubleSpinBoxBiasY->blockSignals(false);
 }
@@ -195,7 +210,7 @@ void DialogDetail::setDetails(const VDetail &value)
     for (int i = 0; i < details.CountNode(); ++i)
     {
         NewItem(details.at(i).getId(), details.at(i).getTypeTool(), details.at(i).getTypeNode(), details.at(i).getMx(),
-                details.at(i).getMy());
+                details.at(i).getMy(), details.at(i).getReverse());
     }
     ui.lineEditNameDetail->setText(details.getName());
     ui.checkBoxSeams->setChecked(details.getSeamAllowance());
@@ -260,6 +275,17 @@ void DialogDetail::ClickedClosed(bool checked)
     closed = checked;
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+void DialogDetail::ClickedReverse(bool checked)
+{
+    qint32 row = ui.listWidget->currentRow();
+    QListWidgetItem *item = ui.listWidget->item( row );
+    SCASSERT(item != nullptr);
+    VNodeDetail node = qvariant_cast<VNodeDetail>(item->data(Qt::UserRole));
+    node.setReverse(checked);
+    item->setData(Qt::UserRole, QVariant::fromValue(node));
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief ObjectChanged changed new object (point, arc, spline or spline path) form list
@@ -271,10 +297,20 @@ void DialogDetail::ObjectChanged(int row)
     {
         return;
     }
-    QListWidgetItem *item = ui.listWidget->item( row );
-    VNodeDetail node = qvariant_cast<VNodeDetail>(item->data(Qt::UserRole));
+    const QListWidgetItem *item = ui.listWidget->item( row );
+    const VNodeDetail node = qvariant_cast<VNodeDetail>(item->data(Qt::UserRole));
     ui.doubleSpinBoxBiasX->setValue(qApp->fromPixel(node.getMx()));
     ui.doubleSpinBoxBiasY->setValue(qApp->fromPixel(node.getMy()));
+    if (node.getTypeTool() == Tool::NodePoint)
+    {
+        ui.checkBoxReverse->setChecked(false);
+        ui.checkBoxReverse->setEnabled(false);
+    }
+    else
+    {
+        ui.checkBoxReverse->setEnabled(true);
+        ui.checkBoxReverse->setChecked(node.getReverse());
+    }
 }
 
 //---------------------------------------------------------------------------------------------------------------------
diff --git a/src/app/dialogs/tools/dialogdetail.h b/src/app/dialogs/tools/dialogdetail.h
index 98791899e..8f8efe965 100644
--- a/src/app/dialogs/tools/dialogdetail.h
+++ b/src/app/dialogs/tools/dialogdetail.h
@@ -50,6 +50,7 @@ public slots:
     void             BiasYChanged(qreal d);
     void             ClickedSeams(bool checked);
     void             ClickedClosed(bool checked);
+    void             ClickedReverse(bool checked);
     void             ObjectChanged(int row);
     void             DeleteItem();
     virtual void     UpdateList();
@@ -73,7 +74,7 @@ private:
     bool             closed;
 
     void             NewItem(quint32 id, const Tool &typeTool, const NodeDetail &typeNode,
-                             qreal mx = 0, qreal my = 0);
+                             qreal mx = 0, qreal my = 0, bool reverse = false);
 };
 
 //---------------------------------------------------------------------------------------------------------------------
diff --git a/src/app/dialogs/tools/dialogdetail.ui b/src/app/dialogs/tools/dialogdetail.ui
index 4dcd40f8b..212625aef 100644
--- a/src/app/dialogs/tools/dialogdetail.ui
+++ b/src/app/dialogs/tools/dialogdetail.ui
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>565</width>
-    <height>324</height>
+    <height>342</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -126,6 +126,17 @@
          </item>
         </layout>
        </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_6">
+         <item>
+          <widget class="QCheckBox" name="checkBoxReverse">
+           <property name="text">
+            <string>Reverse</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
        <item>
         <widget class="QGroupBox" name="groupBox">
          <property name="title">
@@ -244,6 +255,9 @@
               <property name="singleStep">
                <double>0.100000000000000</double>
               </property>
+              <property name="value">
+               <double>1.000000000000000</double>
+              </property>
              </widget>
             </item>
             <item>
diff --git a/src/app/geometry/vabstractcurve.cpp b/src/app/geometry/vabstractcurve.cpp
index d91ca5ed6..6919dfea4 100644
--- a/src/app/geometry/vabstractcurve.cpp
+++ b/src/app/geometry/vabstractcurve.cpp
@@ -51,6 +51,76 @@ VAbstractCurve &VAbstractCurve::operator=(const VAbstractCurve &curve)
     return *this;
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VAbstractCurve::GetSegmentPoints(const QPointF &begin, const QPointF &end, bool reverse) const
+{
+    QVector<QPointF> points = GetPoints();
+    if (reverse)
+    {
+        points = GetReversePoints(points);
+    }
+    points = FromBegin(points, begin);
+    points = ToEnd(points, end);
+    return points;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VAbstractCurve::FromBegin(const QVector<QPointF> &points, const QPointF &begin) const
+{
+    if (points.count() >= 2)
+    {
+        QVector<QPointF> segment;
+        bool theBegin = false;
+        for (qint32 i = 0; i < points.count()-1; ++i)
+        {
+            if (theBegin == false)
+            {
+                if (PointInSegment(begin, points.at(i), points.at(i+1)))
+                {
+                    theBegin = true;
+                    segment.append(begin);
+                    if (i == points.count()-2)
+                    {
+                         segment.append(points.at(i+1));
+                    }
+                    continue;
+                }
+            }
+            else
+            {
+                segment.append(points.at(i));
+                if (i == points.count()-2)
+                {
+                     segment.append(points.at(i+1));
+                }
+            }
+        }
+
+        if (segment.isEmpty())
+        {
+            return points;
+        }
+        else
+        {
+            return segment;
+        }
+    }
+    else
+    {
+        return points;
+    }
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VAbstractCurve::ToEnd(const QVector<QPointF> &points, const QPointF &end) const
+{
+    QVector<QPointF> reversed = GetReversePoints(points);
+    reversed = FromBegin(reversed, end);
+    return GetReversePoints(reversed);
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 QPainterPath VAbstractCurve::GetPath(PathDirection direction) const
 {
diff --git a/src/app/geometry/vabstractcurve.h b/src/app/geometry/vabstractcurve.h
index 82065f79d..1c38482ed 100644
--- a/src/app/geometry/vabstractcurve.h
+++ b/src/app/geometry/vabstractcurve.h
@@ -43,12 +43,18 @@ public:
     VAbstractCurve(const GOType &type, const quint32 &idObject = NULL_ID, const Draw &mode = Draw::Calculation);
     VAbstractCurve(const VAbstractCurve &curve);
     VAbstractCurve& operator= (const VAbstractCurve &curve);
+
     virtual QVector<QPointF> GetPoints() const =0;
+    QVector<QPointF>         GetSegmentPoints(const QPointF &begin, const QPointF &end, bool reverse = false) const;
+
     virtual QPainterPath     GetPath(PathDirection direction = PathDirection::Hide) const;
     virtual qreal            GetLength() const =0;
     virtual QVector<QPointF> IntersectLine(const QLineF &line) const;
 protected:
     QPainterPath             ShowDirection(const QVector<QPointF> &points) const;
+private:
+    QVector<QPointF>         FromBegin(const QVector<QPointF> &points, const QPointF &begin) const;
+    QVector<QPointF>         ToEnd(const QVector<QPointF> &points, const QPointF &end) const;
 };
 
 #endif // VABSTRACTCURVE_H
diff --git a/src/app/geometry/varc.cpp b/src/app/geometry/varc.cpp
index 83546cfa3..2f9c434b8 100644
--- a/src/app/geometry/varc.cpp
+++ b/src/app/geometry/varc.cpp
@@ -181,7 +181,8 @@ QVector<QPointF> VArc::GetPoints() const
             points.append(line.p2());
         }
     } while (i <= angle);
-    return points;
+    // Detail points clockwise, but arc we draw counterclockwise. Main contour need reverse.
+    return GetReversePoints(points);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
diff --git a/src/app/geometry/vequidistant.cpp b/src/app/geometry/vequidistant.cpp
index a5547de35..2abdc2dc9 100644
--- a/src/app/geometry/vequidistant.cpp
+++ b/src/app/geometry/vequidistant.cpp
@@ -38,7 +38,14 @@
 #include <QtMath>
 
 //---------------------------------------------------------------------------------------------------------------------
-QPainterPath VEquidistant::ContourPath(const quint32 &idDetail, const VContainer *data) const
+VEquidistant::VEquidistant(const VContainer *data)
+    :data(data)
+{
+    SCASSERT(data != nullptr);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QPainterPath VEquidistant::ContourPath(const quint32 &idDetail) const
 {
     SCASSERT(data != nullptr);
     VDetail detail = data->GetDetail(idDetail);
@@ -62,23 +69,20 @@ QPainterPath VEquidistant::ContourPath(const quint32 &idDetail, const VContainer
             }
             break;
             case (Tool::NodeArc):
-            {
-                const QSharedPointer<VArc> arc = data->GeometricObject<VArc>(detail.at(i).getId());
-                // Detail points clockwise, but arc we draw counterclockwise. Main contour need reverse.
-                const QVector<QPointF> reversedPoints = GetReversePoint(arc->GetPoints());
-                AddContour(reversedPoints, points, pointsEkv, detail, i);
-            }
-            break;
             case (Tool::NodeSpline):
-            {
-                const QSharedPointer<VSpline> spline = data->GeometricObject<VSpline>(detail.at(i).getId());
-                AddContour(spline->GetPoints(), points, pointsEkv, detail, i);
-            }
-            break;
             case (Tool::NodeSplinePath):
             {
-                const QSharedPointer<VSplinePath> splinePath = data->GeometricObject<VSplinePath>(detail.at(i).getId());
-                AddContour(splinePath->GetPoints(), points, pointsEkv, detail, i);
+                const QSharedPointer<VAbstractCurve> curve=data->GeometricObject<VAbstractCurve>(detail.at(i).getId());
+
+                const QPointF begin = StartSegment(detail, i);
+                const QPointF end = EndSegment(detail, i);
+
+                QVector<QPointF> nodePoints = curve->GetSegmentPoints(begin, end, detail.at(i).getReverse());
+                points << nodePoints;
+                if (detail.getSeamAllowance() == true)
+                {
+                    pointsEkv << biasPoints(nodePoints, detail.at(i).getMx(), detail.at(i).getMy());
+                }
             }
             break;
             default:
@@ -116,17 +120,51 @@ QPainterPath VEquidistant::ContourPath(const quint32 &idDetail, const VContainer
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-int VEquidistant::GetLengthContour(const QVector<QPointF> &contour, const QVector<QPointF> &newPoints)
+QPointF VEquidistant::StartSegment(const VDetail &detail, const int &i) const
 {
-    qreal length = 0;
-    QVector<QPointF> points;
-    points << contour << newPoints;
-    for (qint32 i = 0; i < points.size()-1; ++i)
+    QPointF begin;
+    if (detail.CountNode() > 1)
     {
-        QLineF line(points.at(i), points.at(i+1));
-        length += line.length();
+        if (i == 0)
+        {
+            if (detail.at(detail.CountNode()-1).getTypeTool() == Tool::NodePoint)
+            {
+                begin = data->GeometricObject<VPointF>(detail.at(detail.CountNode()-1).getId())->toQPointF();
+            }
+        }
+        else
+        {
+            if (detail.at(i-1).getTypeTool() == Tool::NodePoint)
+            {
+                begin = data->GeometricObject<VPointF>(detail.at(i-1).getId())->toQPointF();
+            }
+        }
     }
-    return qFloor(length);
+    return begin;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QPointF VEquidistant::EndSegment(const VDetail &detail, const int &i) const
+{
+    QPointF end;
+    if (detail.CountNode() > 2)
+    {
+        if (i == detail.CountNode() - 1)
+        {
+            if (detail.at(0).getTypeTool() == Tool::NodePoint)
+            {
+                end = data->GeometricObject<VPointF>(detail.at(0).getId())->toQPointF();
+            }
+        }
+        else
+        {
+            if (detail.at(i+1).getTypeTool() == Tool::NodePoint)
+            {
+                end = data->GeometricObject<VPointF>(detail.at(i+1).getId())->toQPointF();
+            }
+        }
+    }
+    return end;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -320,18 +358,6 @@ QVector<QPointF> VEquidistant::CheckLoops(const QVector<QPointF> &points)
     return ekvPoints;
 }
 
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> VEquidistant::GetReversePoint(const QVector<QPointF> &points)
-{
-    SCASSERT(points.size() > 0);
-    QVector<QPointF> reversePoints;
-    for (qint32 i = points.size() - 1; i >= 0; --i)
-    {
-        reversePoints.append(points.at(i));
-    }
-    return reversePoints;
-}
-
 //---------------------------------------------------------------------------------------------------------------------
 QVector<QPointF> VEquidistant::EkvPoint(const QLineF &line1, const QLineF &line2, const qreal &width)
 {
@@ -354,15 +380,22 @@ QVector<QPointF> VEquidistant::EkvPoint(const QLineF &line1, const QLineF &line2
         case (QLineF::UnboundedIntersection):
         {
                 QLineF line( line1.p2(), CrosPoint );
-                if (line.length() > width + qApp->toPixel(8))
-                {
-                    QLineF lineL = QLineF(bigLine1.p2(), CrosPoint);
-                    lineL.setLength(width);
-                    points.append(lineL.p2());
+                const qreal length = line.length();
+                if (length > width*2.4)
+                { // Cutting too long an acute angle
+                    line.setLength(width); // Not sure about width value here
+                    QLineF cutLine(line.p2(), CrosPoint); // Cut line is a perpendicular
+                    cutLine.setLength(length); // Decided take this length
 
-                    lineL = QLineF(bigLine2.p1(), CrosPoint);
-                    lineL.setLength(width);
-                    points.append(lineL.p2());
+                    // We do not check intersection type because intersection must alwayse exist
+                    QPointF px;
+                    cutLine.setAngle(cutLine.angle()+90);
+                    bigLine1.intersect( cutLine, &px );
+                    points.append(px);
+
+                    cutLine.setAngle(cutLine.angle()-180);
+                    bigLine2.intersect( cutLine, &px );
+                    points.append(px);
                 }
                 else
                 {
@@ -400,28 +433,3 @@ QPointF VEquidistant::SingleParallelPoint(const QLineF &line, const qreal &angle
     pLine.setLength( width );
     return pLine.p2();
 }
-
-//---------------------------------------------------------------------------------------------------------------------
-void VEquidistant::AddContour(const QVector<QPointF> &nodePoints, QVector<QPointF> &points, QVector<QPointF> &pointsEkv,
-                              const VDetail &detail, int i)
-{
-    int len1 = GetLengthContour(points, nodePoints);
-    QVector<QPointF> reversedPoints = GetReversePoint(nodePoints);
-    int lenReverse = GetLengthContour(points, reversedPoints);
-    if (len1 <= lenReverse)
-    {
-        points << nodePoints;
-        if (detail.getSeamAllowance() == true)
-        {
-            pointsEkv << biasPoints(nodePoints, detail.at(i).getMx(), detail.at(i).getMy());
-        }
-    }
-    else
-    {
-        points << reversedPoints;
-        if (detail.getSeamAllowance() == true)
-        {
-            pointsEkv << biasPoints(reversedPoints, detail.at(i).getMx(), detail.at(i).getMy());
-        }
-    }
-}
diff --git a/src/app/geometry/vequidistant.h b/src/app/geometry/vequidistant.h
index 8d89bc678..9e19df5d5 100644
--- a/src/app/geometry/vequidistant.h
+++ b/src/app/geometry/vequidistant.h
@@ -42,21 +42,18 @@ class QLineF;
 class VEquidistant
 {
 public:
+    VEquidistant(const VContainer *data);
+    ~VEquidistant(){}
     /**
      * @brief ContourPath create painter path for detail.
      * @param idDetail id of detail.
      * @param data container with objects (points, arcs, splines).
      * @return return painter path of contour detail.
      */
-    QPainterPath     ContourPath(const quint32 &idDetail, const VContainer *data) const;
+    QPainterPath     ContourPath(const quint32 &idDetail) const;
 private:
-    /**
-     * @brief GetLengthContour return length of contour.
-     * @param contour container with points of contour.
-     * @param newPoints point whos we try to add to contour.
-     * @return length length of contour.
-     */
-    static int GetLengthContour(const QVector<QPointF> &contour, const QVector<QPointF> &newPoints);
+    Q_DISABLE_COPY(VEquidistant)
+    const VContainer *data;
     /**
      * @brief biasPoints bias point.
      * @param points vector of points.
@@ -85,12 +82,6 @@ private:
      * @return vector of points of equidistant.
      */
     static QVector<QPointF> CheckLoops(const QVector<QPointF> &points);
-    /**
-     * @brief GetReversePoint return revers container of points.
-     * @param points container with points.
-     * @return reverced points.
-     */
-    static QVector<QPointF> GetReversePoint(const QVector<QPointF> &points);
     /**
      * @brief EkvPoint return vector of points of equidistant two lines. Last point of two lines must be equal.
      * @param line1 first line.
@@ -115,8 +106,8 @@ private:
      */
     static QPointF   SingleParallelPoint(const QLineF &line, const qreal &angle, const qreal &width);
 
-    static void      AddContour(const QVector<QPointF> &nodePoints, QVector<QPointF> &points,
-                                QVector<QPointF> &pointsEkv, const VDetail &detail, int i);
+    QPointF StartSegment(const VDetail &detail, const int &i) const;
+    QPointF EndSegment(const VDetail &detail, const int &i) const;
 };
 
 #endif // VEQUIDISTANT_H
diff --git a/src/app/geometry/vgobject.cpp b/src/app/geometry/vgobject.cpp
index 0c17fc860..a191354c3 100644
--- a/src/app/geometry/vgobject.cpp
+++ b/src/app/geometry/vgobject.cpp
@@ -350,3 +350,70 @@ void VGObject::LineCoefficients(const QLineF &line, qreal *a, qreal *b, qreal *c
     *b = p1.x() - line.p2().x();
     *c = - *a * p1.x() - *b * p1.y();
 }
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VGObject::PointInSegment(const QPointF &t, const QPointF &p1, const QPointF &p2)
+{
+    const qreal eps = 1e-8;
+
+    qreal a = p2.y() - p1.y();
+    qreal b = p1.x() - p2.x();
+    qreal c = - a * p1.x() - b * p1.y();
+    if (qAbs(a * t.x() + b * t.y() + c) > eps)
+    {
+        return false;
+    }
+
+    return PointInBox (t, p1, p2);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VGObject::PointInBox(const QPointF &t, const QPointF &p1, const QPointF &p2)
+{
+    const qreal eps = 1e-8;
+
+    return  (qAbs (t.x() - qMin(p1.x(), p2.x())) <= eps || qMin(p1.x(), p2.x()) <= t.x()) &&
+            (qAbs (qMax(p1.x(), p2.x()) - t.x()) <= eps || qMax(p1.x(), p2.x()) >= t.x()) &&
+            (qAbs (t.y() - qMin(p1.y(), p2.y())) <= eps || qMin(p1.y(), p2.y()) <= t.y()) &&
+            (qAbs (qMax(p1.y(), p2.y()) - t.y()) <= eps || qMax(p1.y(), p2.y()) >= t.y());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief GetReversePoint return revers container of points.
+ * @param points container with points.
+ * @return reverced points.
+ */
+QVector<QPointF> VGObject::GetReversePoints(const QVector<QPointF> &points)
+{
+    if (points.isEmpty())
+    {
+        return points;
+    }
+    QVector<QPointF> reversePoints;
+    for (qint32 i = points.size() - 1; i >= 0; --i)
+    {
+        reversePoints.append(points.at(i));
+    }
+    return reversePoints;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief GetLengthContour return length of contour.
+ * @param contour container with points of contour.
+ * @param newPoints point whos we try to add to contour.
+ * @return length length of contour.
+ */
+int VGObject::GetLengthContour(const QVector<QPointF> &contour, const QVector<QPointF> &newPoints)
+{
+    qreal length = 0;
+    QVector<QPointF> points;
+    points << contour << newPoints;
+    for (qint32 i = 0; i < points.size()-1; ++i)
+    {
+        QLineF line(points.at(i), points.at(i+1));
+        length += line.length();
+    }
+    return qFloor(length);
+}
diff --git a/src/app/geometry/vgobject.h b/src/app/geometry/vgobject.h
index 04e963fa0..8c91fd54f 100644
--- a/src/app/geometry/vgobject.h
+++ b/src/app/geometry/vgobject.h
@@ -77,6 +77,11 @@ public:
     static QPointF ClosestPoint(const QLineF &line, const QPointF &point);
     static QPointF addVector (const QPointF &p, const QPointF &p1, const QPointF &p2, qreal k);
     static void    LineCoefficients(const QLineF &line, qreal *a, qreal *b, qreal *c);
+    static bool    PointInSegment (const QPointF &t, const QPointF &p1, const QPointF &p2);
+    static bool    PointInBox (const QPointF &t, const QPointF &p1, const QPointF &p2);
+
+    static QVector<QPointF> GetReversePoints(const QVector<QPointF> &points);
+    static int GetLengthContour(const QVector<QPointF> &contour, const QVector<QPointF> &newPoints);
 private:
     QSharedDataPointer<VGObjectData> d;
 };
diff --git a/src/app/geometry/vnodedetail.cpp b/src/app/geometry/vnodedetail.cpp
index 41a8fb74f..80b54c6fa 100644
--- a/src/app/geometry/vnodedetail.cpp
+++ b/src/app/geometry/vnodedetail.cpp
@@ -35,8 +35,8 @@ VNodeDetail::VNodeDetail()
 {}
 
 //---------------------------------------------------------------------------------------------------------------------
-VNodeDetail::VNodeDetail(quint32 id, Tool typeTool, NodeDetail typeNode, qreal mx, qreal my)
-    :d(new VNodeDetailData(id, typeTool, typeNode, mx, my))
+VNodeDetail::VNodeDetail(quint32 id, Tool typeTool, NodeDetail typeNode, qreal mx, qreal my, bool reverse)
+    :d(new VNodeDetailData(id, typeTool, typeNode, mx, my, reverse))
 {}
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -118,3 +118,29 @@ void VNodeDetail::setMy(const qreal &value)
 {
     d->my = value;
 }
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VNodeDetail::getReverse() const
+{
+    if (getTypeTool() == Tool::NodePoint)
+    {
+        return false;
+    }
+    else
+    {
+        return d->reverse;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VNodeDetail::setReverse(bool reverse)
+{
+    if (getTypeTool() == Tool::NodePoint)
+    {
+        d->reverse = false;
+    }
+    else
+    {
+        d->reverse = reverse;
+    }
+}
diff --git a/src/app/geometry/vnodedetail.h b/src/app/geometry/vnodedetail.h
index c2b0c21d1..ab557f8bc 100644
--- a/src/app/geometry/vnodedetail.h
+++ b/src/app/geometry/vnodedetail.h
@@ -53,7 +53,7 @@ public:
      * @param mx object bias x axis
      * @param my object bias y axis
      */
-    VNodeDetail(quint32 id, Tool typeTool, NodeDetail typeNode, qreal mx = 0, qreal my = 0);
+    VNodeDetail(quint32 id, Tool typeTool, NodeDetail typeNode, qreal mx = 0, qreal my = 0, bool reverse = false);
     /**
      * @brief VNodeDetail copy constructor
      * @param node node
@@ -116,6 +116,9 @@ public:
      * @param value bias y axis.
      */
     void        setMy(const qreal &value);
+
+    bool        getReverse() const;
+    void        setReverse(bool reverse);
 private:
     QSharedDataPointer<VNodeDetailData> d;
 };
diff --git a/src/app/geometry/vnodedetail_p.h b/src/app/geometry/vnodedetail_p.h
index 6c676cd51..3de2ea778 100644
--- a/src/app/geometry/vnodedetail_p.h
+++ b/src/app/geometry/vnodedetail_p.h
@@ -41,15 +41,16 @@ class VNodeDetailData : public QSharedData
 {
 public:
   VNodeDetailData()
-    :id(NULL_ID), typeTool(Tool::NodePoint), typeNode(NodeDetail::Contour), mx(0), my(0)
+    :id(NULL_ID), typeTool(Tool::NodePoint), typeNode(NodeDetail::Contour), mx(0), my(0), reverse(false)
   {}
 
-  VNodeDetailData(quint32 id, Tool typeTool, NodeDetail typeNode, qreal mx, qreal my)
-      :id(id), typeTool(typeTool), typeNode(typeNode), mx(mx), my(my)
+  VNodeDetailData(quint32 id, Tool typeTool, NodeDetail typeNode, qreal mx, qreal my, bool reverse)
+      :id(id), typeTool(typeTool), typeNode(typeNode), mx(mx), my(my), reverse(reverse)
   {}
 
   VNodeDetailData (const VNodeDetailData& node)
-      :QSharedData(node), id(node.id), typeTool(node.typeTool), typeNode(node.typeNode), mx(node.mx), my(node.my)
+      :QSharedData(node), id(node.id), typeTool(node.typeTool), typeNode(node.typeNode), mx(node.mx), my(node.my),
+        reverse(node.reverse)
   {}
 
   ~VNodeDetailData() {}
@@ -74,6 +75,10 @@ public:
    * @brief my bias y axis.
    */
   qreal       my;
+  /**
+   * @brief reverse true if need reverse points list for node.
+   */
+  bool        reverse;
 };
 
 #ifdef Q_CC_GNU
diff --git a/src/app/mainwindow.cpp b/src/app/mainwindow.cpp
index 25fb334b8..d881f3413 100644
--- a/src/app/mainwindow.cpp
+++ b/src/app/mainwindow.cpp
@@ -1454,6 +1454,8 @@ void MainWindow::Clear()
     qCDebug(vMainWindow)<<"Reseting main window";
 
     delete lock; // Unlock pattern file
+    lock = nullptr;
+
     ui->actionDetails->setChecked(false);
     ui->actionDetails->setEnabled(false);
     ui->actionDraw->setChecked(true);
@@ -1901,7 +1903,7 @@ void MainWindow::ActionLayout(bool checked)
     while (idetail.hasNext())
     {
         idetail.next();
-        QPainterPath path = VEquidistant().ContourPath(idetail.key(), pattern);
+        QPainterPath path = VEquidistant(pattern).ContourPath(idetail.key());
         listDetails.append(new VItem(path, listDetails.size()));
     }
     QString description = doc->GetDescription();
@@ -2453,6 +2455,7 @@ QStringList MainWindow::GetUnlokedRestoreFileList() const
                 restoreFiles.append(files.at(i));
             }
             delete lock;
+            lock = nullptr;
         }
 
         // Clearing list after filtering
diff --git a/src/app/tools/nodeDetails/vnodearc.cpp b/src/app/tools/nodeDetails/vnodearc.cpp
index 0e51c5755..d7c0aeb68 100644
--- a/src/app/tools/nodeDetails/vnodearc.cpp
+++ b/src/app/tools/nodeDetails/vnodearc.cpp
@@ -217,9 +217,9 @@ void VNodeArc::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
  */
 void VNodeArc::RefreshGeometry()
 {
-    const QSharedPointer<VArc> arc = VAbstractTool::data.GeometricObject<VArc>(id);
-    QPainterPath path;
-    path.addPath(arc->GetPath());
-    path.setFillRule( Qt::WindingFill );
-    this->setPath(path);
+//    const QSharedPointer<VArc> arc = VAbstractTool::data.GeometricObject<VArc>(id);
+//    QPainterPath path;
+//    path.addPath(arc->GetPath());
+//    path.setFillRule( Qt::WindingFill );
+//    this->setPath(path);
 }
diff --git a/src/app/tools/nodeDetails/vnodespline.cpp b/src/app/tools/nodeDetails/vnodespline.cpp
index a875ebf46..a83545287 100644
--- a/src/app/tools/nodeDetails/vnodespline.cpp
+++ b/src/app/tools/nodeDetails/vnodespline.cpp
@@ -220,9 +220,9 @@ void VNodeSpline::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
  */
 void VNodeSpline::RefreshGeometry()
 {
-    const QSharedPointer<VSpline> spl = VAbstractTool::data.GeometricObject<VSpline>(id);
-    QPainterPath path;
-    path.addPath(spl->GetPath());
-    path.setFillRule( Qt::WindingFill );
-    this->setPath(path);
+//    const QSharedPointer<VSpline> spl = VAbstractTool::data.GeometricObject<VSpline>(id);
+//    QPainterPath path;
+//    path.addPath(spl->GetPath());
+//    path.setFillRule( Qt::WindingFill );
+//    this->setPath(path);
 }
diff --git a/src/app/tools/nodeDetails/vnodesplinepath.cpp b/src/app/tools/nodeDetails/vnodesplinepath.cpp
index b1f523b0b..a2654e473 100644
--- a/src/app/tools/nodeDetails/vnodesplinepath.cpp
+++ b/src/app/tools/nodeDetails/vnodesplinepath.cpp
@@ -223,9 +223,9 @@ void VNodeSplinePath::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
  */
 void VNodeSplinePath::RefreshGeometry()
 {
-    const QSharedPointer<VSplinePath> splPath = VAbstractTool::data.GeometricObject<VSplinePath>(id);
-    QPainterPath path;
-    path.addPath(splPath->GetPath());
-    path.setFillRule( Qt::WindingFill );
-    this->setPath(path);
+//    const QSharedPointer<VSplinePath> splPath = VAbstractTool::data.GeometricObject<VSplinePath>(id);
+//    QPainterPath path;
+//    path.addPath(splPath->GetPath());
+//    path.setFillRule( Qt::WindingFill );
+//    this->setPath(path);
 }
diff --git a/src/app/tools/vtooldetail.cpp b/src/app/tools/vtooldetail.cpp
index 24e9572b1..9205c334f 100644
--- a/src/app/tools/vtooldetail.cpp
+++ b/src/app/tools/vtooldetail.cpp
@@ -52,6 +52,7 @@ const QString VToolDetail::AttrClosed       = QStringLiteral("closed");
 const QString VToolDetail::AttrWidth        = QStringLiteral("width");
 const QString VToolDetail::AttrIdObject     = QStringLiteral("idObject");
 const QString VToolDetail::AttrNodeType     = QStringLiteral("nodeType");
+const QString VToolDetail::AttrReverse      = QStringLiteral("reverse");
 
 const QString VToolDetail::NodeTypeContour  = QStringLiteral("Contour");
 const QString VToolDetail::NodeTypeModeling = QStringLiteral("Modeling");
@@ -181,7 +182,8 @@ void VToolDetail::Create(DialogTool *dialog, VMainGraphicsScene *scene, VPattern
                 qDebug()<<"May be wrong tool type!!! Ignoring."<<Q_FUNC_INFO;
                 break;
         }
-        VNodeDetail node(id, detail.at(i).getTypeTool(), NodeDetail::Contour);
+        VNodeDetail node(id, detail.at(i).getTypeTool(), NodeDetail::Contour, detail.at(i).getMx(),
+                         detail.at(i).getMy(), detail.at(i).getReverse());
         det.append(node);
     }
     det.setName(detail.getName());
@@ -455,6 +457,12 @@ void VToolDetail::AddNode(VPattern *doc, QDomElement &domElement, const VNodeDet
     doc->SetAttribute(nod, AttrIdObject, node.getId());
     doc->SetAttribute(nod, AttrMx, qApp->fromPixel(node.getMx()));
     doc->SetAttribute(nod, AttrMy, qApp->fromPixel(node.getMy()));
+
+    if (node.getTypeTool() != Tool::NodePoint)
+    {
+        doc->SetAttribute(nod, AttrReverse, static_cast<quint8>(node.getReverse()));
+    }
+
     if (node.getTypeNode() == NodeDetail::Contour)
     {
         doc->SetAttribute(nod, AttrNodeType, NodeTypeContour);
@@ -503,7 +511,7 @@ void VToolDetail::ShowVisualization(bool show)
 void VToolDetail::RefreshGeometry()
 {
     this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
-    QPainterPath path = VEquidistant().ContourPath(id, this->getData());
+    QPainterPath path = VEquidistant(this->getData()).ContourPath(id);
     this->setPath(path);
 
     VDetail detail = VAbstractTool::data.GetDetail(id);
@@ -511,6 +519,7 @@ void VToolDetail::RefreshGeometry()
     this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
 }
 
+//---------------------------------------------------------------------------------------------------------------------
 void VToolDetail::DeleteTool(bool ask)
 {
     DeleteDetail *delDet = new DeleteDetail(doc, id);
diff --git a/src/app/tools/vtooldetail.h b/src/app/tools/vtooldetail.h
index 61cf79210..f5aeefe06 100644
--- a/src/app/tools/vtooldetail.h
+++ b/src/app/tools/vtooldetail.h
@@ -74,6 +74,7 @@ public:
     static const QString AttrWidth;
     static const QString AttrIdObject;
     static const QString AttrNodeType;
+    static const QString AttrReverse;
     static const QString NodeTypeContour;
     static const QString NodeTypeModeling;
     static const QString NodeArc;
diff --git a/src/app/tools/vtooluniondetails.cpp b/src/app/tools/vtooluniondetails.cpp
index 8baf5946a..d59f93e40 100644
--- a/src/app/tools/vtooluniondetails.cpp
+++ b/src/app/tools/vtooluniondetails.cpp
@@ -257,7 +257,7 @@ void VToolUnionDetails::AddToNewDetail(QObject *tool, VPattern *doc, VContainer
             qDebug()<<"May be wrong tool type!!! Ignoring."<<Q_FUNC_INFO;
             break;
     }
-    newDetail.append(VNodeDetail(id, det.at(i).getTypeTool(), NodeDetail::Contour));
+    newDetail.append(VNodeDetail(id, det.at(i).getTypeTool(), NodeDetail::Contour, 0, 0, det.at(i).getReverse()));
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -694,6 +694,7 @@ QVector<VDetail> VToolUnionDetails::GetDetailFromFile(VPattern *doc, const QDomE
                             quint32 id = doc->GetParametrUInt(element, VToolDetail::AttrIdObject, NULL_ID_STR);
                             qreal mx = qApp->toPixel(doc->GetParametrDouble(element, VAbstractTool::AttrMx, "0.0"));
                             qreal my = qApp->toPixel(doc->GetParametrDouble(element, VAbstractTool::AttrMy, "0.0"));
+                            const bool reversed = doc->GetParametrUInt(element, VToolDetail::AttrReverse, "0");
                             Tool tool = Tool::NodePoint;
                             NodeDetail nodeType = NodeDetail::Contour;
                             QString t = doc->GetParametrString(element, "type", "NodePoint");
@@ -713,7 +714,7 @@ QVector<VDetail> VToolUnionDetails::GetDetailFromFile(VPattern *doc, const QDomE
                             {
                                 tool = Tool::NodeSplinePath;
                             }
-                            d.append(VNodeDetail(id, tool, nodeType, mx, my));
+                            d.append(VNodeDetail(id, tool, nodeType, mx, my, reversed));
                         }
                     }
                 }
diff --git a/src/app/xml/vpattern.cpp b/src/app/xml/vpattern.cpp
index ed8efa99e..85df02add 100644
--- a/src/app/xml/vpattern.cpp
+++ b/src/app/xml/vpattern.cpp
@@ -514,16 +514,6 @@ void VPattern::DecrementReferens(quint32 id) const
     tool->decrementReferens();
 }
 
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief TestUniqueId test exist unique id in pattern file. Each id must be unique.
- */
-void VPattern::TestUniqueId() const
-{
-    QVector<quint32> vector;
-    CollectId(documentElement(), vector);
-}
-
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief SPointActiveDraw return id base point current pattern peace.
@@ -717,7 +707,7 @@ MeasurementsType VPattern::MType() const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-bool VPattern::SaveDocument(const QString &fileName, QString &error)
+bool VPattern::SaveDocument(const QString &fileName, QString &error) const
 {
     try
     {
@@ -990,6 +980,7 @@ void VPattern::ParseDetailElement(const QDomElement &domElement, const Document
                     const quint32 id = GetParametrUInt(element, VToolDetail::AttrIdObject, NULL_ID_STR);
                     const qreal mx = qApp->toPixel(GetParametrDouble(element, VAbstractTool::AttrMx, "0.0"));
                     const qreal my = qApp->toPixel(GetParametrDouble(element, VAbstractTool::AttrMy, "0.0"));
+                    const bool reverse = GetParametrUInt(element, VToolDetail::AttrReverse, "0");
                     const NodeDetail nodeType = NodeDetail::Contour;
 
                     const QString t = GetParametrString(element, AttrType, "NodePoint");
@@ -1014,7 +1005,7 @@ void VPattern::ParseDetailElement(const QDomElement &domElement, const Document
                             continue;
                             break;
                     }
-                    detail.append(VNodeDetail(id, tool, nodeType, mx, my));
+                    detail.append(VNodeDetail(id, tool, nodeType, mx, my, reverse));
                 }
             }
         }
@@ -2075,36 +2066,6 @@ void VPattern::ParseIncrementsElement(const QDomNode &node)
     }
 }
 
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief GetParametrId return value id attribute.
- * @param domElement tag in xml tree.
- * @return id value.
- */
-quint32 VPattern::GetParametrId(const QDomElement &domElement) const
-{
-    Q_ASSERT_X(domElement.isNull() == false, Q_FUNC_INFO, "domElement is null");
-
-    quint32 id = 0;
-
-    QString message = tr("Got wrong parameter id. Need only id > 0.");
-    try
-    {
-        id = GetParametrUInt(domElement, VDomDocument::AttrId, NULL_ID_STR);
-        if (id <= 0)
-        {
-            throw VExceptionWrongId(message, domElement);
-        }
-    }
-    catch (const VExceptionConversionError &e)
-    {
-        VExceptionWrongId excep(message, domElement);
-        excep.AddMoreInformation(e.ErrorMessage());
-        throw excep;
-    }
-    return id;
-}
-
 //---------------------------------------------------------------------------------------------------------------------
 QMap<GHeights, bool> VPattern::GetGradationHeights() const
 {
@@ -2507,34 +2468,6 @@ QString VPattern::GenerateLabel(const LabelType &type) const
     return QString();
 }
 
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief CollectId recursive function, try find id attribute in file. Throw exclusion if find not unique.
- * @param node tag in xml tree.
- * @param vector list with ids.
- */
-void VPattern::CollectId(const QDomElement &node, QVector<quint32> &vector) const
-{
-    if (node.hasAttribute(VDomDocument::AttrId))
-    {
-        const quint32 id = GetParametrId(node);
-        if (vector.contains(id))
-        {
-            throw VExceptionWrongId(tr("This id is not unique."), node);
-        }
-        vector.append(id);
-    }
-
-    for (qint32 i=0; i<node.childNodes().length(); ++i)
-    {
-        const QDomNode n = node.childNodes().at(i);
-        if (n.isElement())
-        {
-            CollectId(n.toElement(), vector);
-        }
-    }
-}
-
 //---------------------------------------------------------------------------------------------------------------------
 void VPattern::PrepareForParse(const Document &parse)
 {
diff --git a/src/app/xml/vpattern.h b/src/app/xml/vpattern.h
index 0765ae62f..439d5c0be 100644
--- a/src/app/xml/vpattern.h
+++ b/src/app/xml/vpattern.h
@@ -71,7 +71,6 @@ public:
     void           UpdateToolData(const quint32 &id, VContainer *data);
     void           IncrementReferens(quint32 id) const;
     void           DecrementReferens(quint32 id) const;
-    void           TestUniqueId() const;
     quint32        SPointActiveDraw();
     bool           isPatternModified() const;
     void           setPatternModified(bool value);
@@ -150,10 +149,9 @@ public:
     static const QString IncrementKgrowth;
     static const QString IncrementDescription;
 
-    virtual bool   SaveDocument(const QString &fileName, QString &error);
+    virtual bool   SaveDocument(const QString &fileName, QString &error) const;
     QStringList    getPatternPieces() const;
     QRectF         ActiveDrawBoundingRect() const;
-    quint32        GetParametrId(const QDomElement& domElement) const;
 
     QMap<GHeights, bool> GetGradationHeights() const;
     void                 SetGradationHeights(const QMap<GHeights, bool> &options);
@@ -265,7 +263,6 @@ private:
     void           ParseToolsElement(VMainGraphicsScene *scene, const QDomElement& domElement,
                                      const Document &parse, const QString& type);
     void           ParseIncrementsElement(const QDomNode& node);
-    void           CollectId(const QDomElement &node, QVector<quint32> &vector)const;
     void           PrepareForParse(const Document &parse);
     void           UpdateMeasurements();
     void           ToolsCommonAttributes(const QDomElement &domElement, quint32 &id);
diff --git a/src/libs/ifc/schema.qrc b/src/libs/ifc/schema.qrc
index ce37b86bc..93866bf60 100644
--- a/src/libs/ifc/schema.qrc
+++ b/src/libs/ifc/schema.qrc
@@ -3,5 +3,6 @@
         <file>schema/individual_measurements.xsd</file>
         <file>schema/standard_measurements.xsd</file>
         <file>schema/pattern/v0.1.1.xsd</file>
+        <file>schema/pattern/v0.1.2.xsd</file>
     </qresource>
 </RCC>
diff --git a/src/libs/ifc/schema/pattern/v0.1.2.xsd b/src/libs/ifc/schema/pattern/v0.1.2.xsd
new file mode 100644
index 000000000..134c9be89
--- /dev/null
+++ b/src/libs/ifc/schema/pattern/v0.1.2.xsd
@@ -0,0 +1,292 @@
+<?xml version="1.0" encoding="UTF-8"?>
+   <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+         <!-- XML Schema Generated from XML Document-->
+         <xs:element name="pattern">
+               <xs:complexType>
+                     <xs:sequence minOccurs="1" maxOccurs="unbounded">
+							<xs:element name="version" type="formatVersion"></xs:element>
+							<xs:element name="author" type="xs:string" minOccurs="0" maxOccurs="1"></xs:element>
+							<xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"></xs:element>
+							<xs:element name="notes" type="xs:string" minOccurs="0" maxOccurs="1"></xs:element>
+							<xs:element name="gradation" minOccurs="0" maxOccurs="1">
+								<xs:complexType>
+                                       <xs:sequence>
+                                             <xs:element name="heights">
+                                                   <xs:complexType>
+                                                         <xs:attribute name="all" type="xs:boolean" use="required"></xs:attribute>
+                                                         <xs:attribute name="h92" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h98" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h104" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h110" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h116" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h122" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h128" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h134" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h140" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h146" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h152" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h158" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h164" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h170" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h176" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h182" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h188" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="h194" type="xs:boolean"></xs:attribute>	   
+                                                   </xs:complexType>
+                                             </xs:element>
+                                             <xs:element name="sizes">
+                                                   <xs:complexType>
+                                                         <xs:attribute name="all" type="xs:boolean" use="required"></xs:attribute>
+                                                         <xs:attribute name="s22" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s24" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s26" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s28" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s30" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s32" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s34" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s36" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s38" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s40" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s42" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s44" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s46" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s48" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s50" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s52" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s54" type="xs:boolean"></xs:attribute>
+														 <xs:attribute name="s56" type="xs:boolean"></xs:attribute>	   
+                                                   </xs:complexType>
+                                             </xs:element>
+                                       </xs:sequence>
+                                 </xs:complexType>
+							</xs:element>
+							<xs:element name="measurements" minOccurs="0" maxOccurs="unbounded">
+								<xs:complexType>
+									<xs:attribute name="type" type="measurementsTypes" use="required"></xs:attribute>
+									<xs:attribute name="path" type="xs:string" use="required"></xs:attribute>
+									<xs:attribute name="unit" type="units" use="required"></xs:attribute>   
+							   	</xs:complexType>
+							</xs:element>
+                           <xs:element name="increments" minOccurs="0" maxOccurs="1">
+                                 <xs:complexType>
+                                       <xs:sequence minOccurs="0" maxOccurs="unbounded">
+                                             <xs:element name="increment" minOccurs="0" maxOccurs="unbounded">
+                                                   <xs:complexType>
+                                                         <xs:attribute name="ksize" type="xs:double" use="required"></xs:attribute>
+													     <xs:attribute name="id" type="xs:unsignedInt" use="required"></xs:attribute>
+														 <xs:attribute name="description" type="xs:string" use="required"></xs:attribute>
+														 <xs:attribute name="kgrowth" type="xs:double" use="required"></xs:attribute>
+														 <xs:attribute name="name" type="shortName" use="required"></xs:attribute>
+														 <xs:attribute name="base" type="xs:double" use="required"></xs:attribute>	   
+                                                   </xs:complexType>
+                                             </xs:element>
+                                       </xs:sequence>
+                                 </xs:complexType>
+                           </xs:element>
+                           <xs:element name="draw" minOccurs="1" maxOccurs="unbounded">
+                                 <xs:complexType>
+                                       <xs:sequence>
+                                             <xs:element name="calculation" minOccurs="1" maxOccurs="unbounded">
+                                                   <xs:complexType>
+                                                         <xs:sequence>
+														       <xs:choice minOccurs="0" maxOccurs="unbounded">	 
+                                                                     <xs:element name="point" minOccurs="0" maxOccurs="unbounded">
+																	       <xs:complexType>
+																		         <xs:attribute name="id" type="xs:unsignedInt" use="required"></xs:attribute>
+																			     <xs:attribute name="x" type="xs:double"></xs:attribute>
+																			     <xs:attribute name="y" type="xs:double"></xs:attribute>
+																			     <xs:attribute name="mx" type="xs:double"></xs:attribute>
+																			     <xs:attribute name="my" type="xs:double"></xs:attribute>
+																			     <xs:attribute name="type" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="name" type="shortName"></xs:attribute>
+																			     <xs:attribute name="firstPoint" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="secondPoint" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="thirdPoint" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="basePoint" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="pShoulder" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="p1Line" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="p2Line" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="length" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="angle" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="typeLine" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="splinePath" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="spline" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="p1Line1" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="p1Line2" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="p2Line1" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="p2Line2" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="center" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="radius" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="axisP1" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="axisP2" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="arc" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="curve" type="xs:unsignedInt"></xs:attribute>
+																	       </xs:complexType>
+                                                                     </xs:element>                                                              
+																     <xs:element name="line" minOccurs="0" maxOccurs="unbounded">
+																		   <xs:complexType>
+																			     <xs:attribute name="id" type="xs:unsignedInt" use="required"></xs:attribute>
+																			     <xs:attribute name="firstPoint" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="secondPoint" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="typeLine" type="xs:string"></xs:attribute>
+																		   </xs:complexType>
+																     </xs:element> 
+																     <xs:element name="arc" minOccurs="0" maxOccurs="unbounded">
+																		   <xs:complexType>
+																			     <xs:attribute name="angle1" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="id" type="xs:unsignedInt" use="required"></xs:attribute>
+																			     <xs:attribute name="angle2" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="radius" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="center" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="type" type="xs:string"></xs:attribute>
+																		   </xs:complexType>
+																     </xs:element>
+																     <xs:element name="spline" minOccurs="0" maxOccurs="unbounded">
+																		   <xs:complexType>
+																			     <xs:sequence>
+																					   <xs:element name="pathPoint" minOccurs="0" maxOccurs="unbounded">
+																						     <xs:complexType>
+																								   <xs:attribute name="kAsm2" type="xs:string"></xs:attribute>
+																								   <xs:attribute name="pSpline" type="xs:unsignedInt"></xs:attribute>
+																								   <xs:attribute name="angle" type="xs:string"></xs:attribute>
+																								   <xs:attribute name="kAsm1" type="xs:string"></xs:attribute>
+																						     </xs:complexType>
+																					   </xs:element>
+																			     </xs:sequence>
+																			     <xs:attribute name="id" type="xs:unsignedInt" use="required"></xs:attribute>
+																			     <xs:attribute name="kCurve" type="xs:double"></xs:attribute>
+																			     <xs:attribute name="type" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="kAsm1" type="xs:double"></xs:attribute>
+																			     <xs:attribute name="kAsm2" type="xs:double"></xs:attribute>
+																			     <xs:attribute name="angle1" type="xs:double"></xs:attribute>
+																			     <xs:attribute name="angle2" type="xs:double"></xs:attribute>
+																			     <xs:attribute name="point1" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="point4" type="xs:unsignedInt"></xs:attribute>
+																		   </xs:complexType>
+																     </xs:element>
+                                                               </xs:choice>
+                                                         </xs:sequence>
+                                                   </xs:complexType>
+                                             </xs:element>
+                                             <xs:element name="modeling" minOccurs="1" maxOccurs="unbounded">
+                                                   <xs:complexType>
+                                                         <xs:sequence>
+														       <xs:choice minOccurs="0" maxOccurs="unbounded">
+																     <xs:element name="point" minOccurs="0" maxOccurs="unbounded">
+																		   <xs:complexType>
+																			     <xs:attribute name="id" type="xs:unsignedInt" use="required"></xs:attribute>
+																			     <xs:attribute name="idObject" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="mx" type="xs:double"></xs:attribute>
+																			     <xs:attribute name="typeObject" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="my" type="xs:double"></xs:attribute>
+																			     <xs:attribute name="type" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="idTool" type="xs:unsignedInt"></xs:attribute>
+																		   </xs:complexType>
+																     </xs:element>
+																     <xs:element name="arc" minOccurs="0" maxOccurs="unbounded">
+																		   <xs:complexType>
+																			     <xs:attribute name="id" type="xs:unsignedInt" use="required"></xs:attribute>
+																			     <xs:attribute name="idObject" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="typeObject" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="type" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="idTool" type="xs:unsignedInt"></xs:attribute>
+																		   </xs:complexType>
+																     </xs:element>
+																     <xs:element name="spline" minOccurs="0" maxOccurs="unbounded">
+																		   <xs:complexType>
+																			     <xs:attribute name="id" type="xs:unsignedInt" use="required"></xs:attribute>
+																			     <xs:attribute name="idObject" type="xs:unsignedInt"></xs:attribute>
+																			     <xs:attribute name="typeObject" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="type" type="xs:string"></xs:attribute>
+																			     <xs:attribute name="idTool" type="xs:unsignedInt"></xs:attribute>
+																		   </xs:complexType>
+																     </xs:element>
+																     <xs:element name="tools" minOccurs="0" maxOccurs="unbounded">
+                                                                       <xs:complexType>
+                                                                             <xs:sequence>
+                                                                                   <xs:element name="det" minOccurs="2" maxOccurs="2">
+                                                                                         <xs:complexType>
+                                                                                               <xs:sequence>
+                                                                                                     <xs:element name="node" maxOccurs="unbounded">
+                                                                                                           <xs:complexType>
+                                                                                                                 <xs:attribute name="nodeType" type="xs:string"></xs:attribute>
+                                                                                                                 <xs:attribute name="idObject" type="xs:unsignedInt"></xs:attribute>
+                                                                                                                 <xs:attribute name="mx" type="xs:double"></xs:attribute>
+                                                                                                                 <xs:attribute name="my" type="xs:double"></xs:attribute>
+                                                                                                                 <xs:attribute name="type" type="xs:string"></xs:attribute>
+                                                                                                           </xs:complexType>
+                                                                                                     </xs:element>
+                                                                                               </xs:sequence>
+                                                                                         </xs:complexType>
+                                                                                   </xs:element>
+                                                                             </xs:sequence>
+                                                                             <xs:attribute name="id" type="xs:unsignedInt" use="required"></xs:attribute>
+                                                                             <xs:attribute name="type" type="xs:string"></xs:attribute>
+                                                                             <xs:attribute name="indexD1" type="xs:unsignedInt"></xs:attribute>
+                                                                             <xs:attribute name="indexD2" type="xs:unsignedInt"></xs:attribute>
+                                                                       </xs:complexType>
+                                                                    </xs:element>
+                                                               </xs:choice>           
+                                                         </xs:sequence>
+                                                   </xs:complexType>
+                                             </xs:element>
+                                             <xs:element name="details" minOccurs="1" maxOccurs="unbounded">
+                                                   <xs:complexType>
+                                                         <xs:sequence>
+                                                               <xs:element name="detail" minOccurs="0" maxOccurs="unbounded">
+                                                                     <xs:complexType>
+                                                                           <xs:sequence>
+                                                                                 <xs:element name="node" maxOccurs="unbounded">
+                                                                                       <xs:complexType>
+                                                                                             <xs:attribute name="nodeType" type="xs:string"></xs:attribute>
+                                                                                             <xs:attribute name="idObject" type="xs:unsignedInt"></xs:attribute>
+                                                                                             <xs:attribute name="mx" type="xs:double"></xs:attribute>
+                                                                                             <xs:attribute name="my" type="xs:double"></xs:attribute>
+                                                                                             <xs:attribute name="type" type="xs:string"></xs:attribute>
+                                                                                             <xs:attribute name="reverse" type="xs:unsignedInt"></xs:attribute>
+                                                                                       </xs:complexType>
+                                                                                 </xs:element>
+                                                                           </xs:sequence>
+                                                                           <xs:attribute name="id" type="xs:unsignedInt" use="required"></xs:attribute>
+                                                                           <xs:attribute name="supplement" type="xs:unsignedInt"></xs:attribute>
+                                                                           <xs:attribute name="mx" type="xs:double"></xs:attribute>
+                                                                           <xs:attribute name="my" type="xs:double"></xs:attribute>
+                                                                           <xs:attribute name="width" type="xs:double"></xs:attribute>
+                                                                           <xs:attribute name="name" type="xs:string"></xs:attribute>
+                                                                           <xs:attribute name="closed" type="xs:unsignedInt"></xs:attribute>
+                                                                     </xs:complexType>
+                                                               </xs:element>
+                                                         </xs:sequence>
+                                                   </xs:complexType>
+                                             </xs:element>
+                                       </xs:sequence>
+                                       <xs:attribute name="name" type="xs:string"></xs:attribute>
+                                 </xs:complexType>
+                           </xs:element>
+                     </xs:sequence>
+               </xs:complexType>
+         </xs:element>
+	<xs:simpleType name="shortName">
+		<xs:restriction base="xs:string">   
+			<xs:pattern value="^([^0-9-*/^+=\s\(\)%:;!.,`'\&quot;]){1,1}([^-*/^+=\s\(\)%:;!.,`'\&quot;]){0,}$"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:simpleType name="units">
+		<xs:restriction base="xs:string">
+			<xs:enumeration value="mm"/>
+			<xs:enumeration value="cm"/>
+			<xs:enumeration value="inch"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:simpleType name="measurementsTypes">
+		<xs:restriction base="xs:string">
+			<xs:enumeration value="standard"/>
+			<xs:enumeration value="individual"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:simpleType name="formatVersion">
+		<xs:restriction base="xs:string">
+			<xs:pattern value="^(0|([1-9][0-9]*))\.(0|([1-9][0-9]*))\.(0|([1-9][0-9]*))$"/>
+		</xs:restriction>
+	</xs:simpleType>
+   </xs:schema>
diff --git a/src/libs/ifc/xml/vabstractconverter.cpp b/src/libs/ifc/xml/vabstractconverter.cpp
index a5fec8d05..f148d3fac 100644
--- a/src/libs/ifc/xml/vabstractconverter.cpp
+++ b/src/libs/ifc/xml/vabstractconverter.cpp
@@ -28,6 +28,7 @@
 
 #include "vabstractconverter.h"
 #include "exception/vexception.h"
+#include "exception/vexceptionwrongid.h"
 
 #include <QFile>
 
@@ -45,7 +46,7 @@ VAbstractConverter::~VAbstractConverter()
 {}
 
 //---------------------------------------------------------------------------------------------------------------------
-void VAbstractConverter::Convert() const
+void VAbstractConverter::Convert()
 {
     if (ver == MaxVer())
     {
@@ -158,3 +159,40 @@ void VAbstractConverter::CheckVersion(int ver) const
         throw VException(errorMsg);
     }
 }
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VAbstractConverter::SaveDocument(const QString &fileName, QString &error) const
+{
+    try
+    {
+        TestUniqueId();
+    }
+    catch (const VExceptionWrongId &e)
+    {
+        error = tr("Error no unique id.");
+        return false;
+    }
+
+    return VDomDocument::SaveDocument(fileName, error);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VAbstractConverter::Save() const
+{
+    QString error;
+    if (SaveDocument(fileName, error) == false)
+    {
+        VException e(error);
+        throw e;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VAbstractConverter::SetVersion(const QString &version)
+{
+    if (setTagText(TagVersion, version) == false)
+    {
+        VException e(tr("Could not change version."));
+        throw e;
+    }
+}
diff --git a/src/libs/ifc/xml/vabstractconverter.h b/src/libs/ifc/xml/vabstractconverter.h
index a4cc94ecd..4f7746380 100644
--- a/src/libs/ifc/xml/vabstractconverter.h
+++ b/src/libs/ifc/xml/vabstractconverter.h
@@ -38,7 +38,8 @@ public:
     VAbstractConverter(const QString &fileName);
     virtual ~VAbstractConverter();
 
-    void Convert() const;
+    void         Convert();
+    virtual bool SaveDocument(const QString &fileName, QString &error) const;
 
 protected:
     int     ver;
@@ -46,6 +47,8 @@ protected:
 
     int  GetVersion(const QString &version) const;
     void CheckVersion(int ver) const;
+    void Save() const;
+    void SetVersion(const QString &version);
 
     virtual int     MinVer() const =0;
     virtual int     MaxVer() const =0;
@@ -54,7 +57,7 @@ protected:
     virtual QString MaxVerStr() const =0;
 
     virtual QString XSDSchema(int ver) const =0;
-    virtual void    ApplyPatches() const =0;
+    virtual void    ApplyPatches() =0;
 
 private:
     Q_DISABLE_COPY(VAbstractConverter)
diff --git a/src/libs/ifc/xml/vdomdocument.cpp b/src/libs/ifc/xml/vdomdocument.cpp
index 5dcf8d698..0f29fb26f 100644
--- a/src/libs/ifc/xml/vdomdocument.cpp
+++ b/src/libs/ifc/xml/vdomdocument.cpp
@@ -30,6 +30,7 @@
 #include "exception/vexceptionconversionerror.h"
 #include "exception/vexceptionemptyparameter.h"
 #include "exception/vexceptionbadid.h"
+#include "exception/vexceptionwrongid.h"
 
 #include <QAbstractMessageHandler>
 #include <QXmlSchema>
@@ -323,6 +324,36 @@ qreal VDomDocument::GetParametrDouble(const QDomElement &domElement, const QStri
     return param;
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief GetParametrId return value id attribute.
+ * @param domElement tag in xml tree.
+ * @return id value.
+ */
+quint32 VDomDocument::GetParametrId(const QDomElement &domElement) const
+{
+    Q_ASSERT_X(domElement.isNull() == false, Q_FUNC_INFO, "domElement is null");
+
+    quint32 id = 0;
+
+    QString message = tr("Got wrong parameter id. Need only id > 0.");
+    try
+    {
+        id = GetParametrUInt(domElement, VDomDocument::AttrId, NULL_ID_STR);
+        if (id <= 0)
+        {
+            throw VExceptionWrongId(message, domElement);
+        }
+    }
+    catch (const VExceptionConversionError &e)
+    {
+        VExceptionWrongId excep(message, domElement);
+        excep.AddMoreInformation(e.ErrorMessage());
+        throw excep;
+    }
+    return id;
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 QString VDomDocument::UniqueTagText(const QString &tagName, const QString &defVal) const
 {
@@ -346,6 +377,39 @@ QString VDomDocument::UniqueTagText(const QString &tagName, const QString &defVa
     return defVal;
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief TestUniqueId test exist unique id in pattern file. Each id must be unique.
+ */
+void VDomDocument::TestUniqueId() const
+{
+    QVector<quint32> vector;
+    CollectId(documentElement(), vector);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VDomDocument::CollectId(const QDomElement &node, QVector<quint32> &vector) const
+{
+    if (node.hasAttribute(VDomDocument::AttrId))
+    {
+        const quint32 id = GetParametrId(node);
+        if (vector.contains(id))
+        {
+            throw VExceptionWrongId(tr("This id is not unique."), node);
+        }
+        vector.append(id);
+    }
+
+    for (qint32 i=0; i<node.childNodes().length(); ++i)
+    {
+        const QDomNode n = node.childNodes().at(i);
+        if (n.isElement())
+        {
+            CollectId(n.toElement(), vector);
+        }
+    }
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief ValidateXML validate xml file by xsd schema.
@@ -514,7 +578,7 @@ QString VDomDocument::UnitsToStr(const Unit &unit, const bool translate)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-bool VDomDocument::SaveDocument(const QString &fileName, QString &error)
+bool VDomDocument::SaveDocument(const QString &fileName, QString &error) const
 {
     if (fileName.isEmpty())
     {
@@ -565,13 +629,12 @@ QString VDomDocument::Patch() const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VDomDocument::setTagText(const QString &tag, const QString &text)
+bool VDomDocument::setTagText(const QString &tag, const QString &text)
 {
     const QDomNodeList nodeList = this->elementsByTagName(tag);
     if (nodeList.isEmpty())
     {
         qDebug()<<"Can't save tag "<<tag<<Q_FUNC_INFO;
-        return;
     }
     else
     {
@@ -587,10 +650,11 @@ void VDomDocument::setTagText(const QString &tag, const QString &text)
                 newTag.appendChild(newTagText);
 
                 parent.replaceChild(newTag, domElement);
-                return;
+                return true;
             }
         }
     }
+    return false;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
diff --git a/src/libs/ifc/xml/vdomdocument.h b/src/libs/ifc/xml/vdomdocument.h
index 34aa2215f..ac2d5029a 100644
--- a/src/libs/ifc/xml/vdomdocument.h
+++ b/src/libs/ifc/xml/vdomdocument.h
@@ -38,11 +38,6 @@
 
 Q_DECLARE_LOGGING_CATEGORY(vXML)
 
-/*
-   can be used like #if (V_FORMAT_VERSION >= V_FORMAT_VERSION_CHECK(4, 4, 0))
-*/
-#define V_FORMAT_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch))
-
 #ifdef Q_CC_GNU
     #pragma GCC diagnostic push
     #pragma GCC diagnostic ignored "-Weffc++"
@@ -104,12 +99,13 @@ public:
     QString        GetParametrString(const QDomElement& domElement, const QString &name,
                                      const QString &defValue = QString()) const;
     qreal          GetParametrDouble(const QDomElement& domElement, const QString &name, const QString &defValue) const;
+    quint32        GetParametrId(const QDomElement& domElement) const;
 
     static void    ValidateXML(const QString &schema, const QString &fileName);
     void           setXMLContent(const QString &fileName);
     static Unit    StrToUnits(const QString &unit);
     static QString UnitsToStr(const Unit &unit, const bool translate = false);
-    virtual bool   SaveDocument(const QString &fileName, QString &error);
+    virtual bool   SaveDocument(const QString &fileName, QString &error) const;
     QString        Major() const;
     QString        Minor() const;
     QString        Patch() const;
@@ -118,12 +114,16 @@ public:
     QDomNode       ParentNodeById(const quint32 &nodeId);
     QDomElement    CloneNodeById(const quint32 &nodeId);
     QDomElement    NodeById(const quint32 &nodeId);
+
     static bool    SafeCopy(const QString &source, const QString &destination, QString &error);
 
 protected:
-    void           setTagText(const QString &tag, const QString &text);
+    bool           setTagText(const QString &tag, const QString &text);
     QString        UniqueTagText(const QString &tagName, const QString &defVal = QString()) const;
 
+    void           TestUniqueId() const;
+    void           CollectId(const QDomElement &node, QVector<quint32> &vector)const;
+
 private:
     Q_DISABLE_COPY(VDomDocument)
     /** @brief Map used for finding element by id. */
diff --git a/src/libs/ifc/xml/vpatternconverter.cpp b/src/libs/ifc/xml/vpatternconverter.cpp
index 59aba9b57..1a7165978 100644
--- a/src/libs/ifc/xml/vpatternconverter.cpp
+++ b/src/libs/ifc/xml/vpatternconverter.cpp
@@ -40,8 +40,8 @@
  */
 
 const QString VPatternConverter::PatternMinVerStr = QStringLiteral("0.1.1");
-const QString VPatternConverter::PatternMaxVerStr = QStringLiteral("0.1.1");
-const QString VPatternConverter::CurrentSchema    = QStringLiteral("://schema/pattern/v0.1.1.xsd");
+const QString VPatternConverter::PatternMaxVerStr = QStringLiteral("0.1.2");
+const QString VPatternConverter::CurrentSchema    = QStringLiteral("://schema/pattern/v0.1.2.xsd");
 
 //---------------------------------------------------------------------------------------------------------------------
 VPatternConverter::VPatternConverter(const QString &fileName)
@@ -87,6 +87,8 @@ QString VPatternConverter::XSDSchema(int ver) const
     switch(ver)
     {
         case (0x000101):
+            return QStringLiteral("://schema/pattern/v0.1.1.xsd");
+        case (0x000102):
             return CurrentSchema;
         default:
         {
@@ -98,13 +100,20 @@ QString VPatternConverter::XSDSchema(int ver) const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VPatternConverter::ApplyPatches() const
+void VPatternConverter::ApplyPatches()
 {
     try
     {
         switch(ver)
         {
             case (0x000101):
+            {
+                ToV0_1_2();
+                const QString schema = XSDSchema(0x000102);
+                ValidateXML(schema, fileName);
+                break;
+            }
+            case (0x000102):
                 break;
             default:
                 break;
@@ -128,3 +137,10 @@ void VPatternConverter::ApplyPatches() const
         throw e;
     }
 }
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPatternConverter::ToV0_1_2()
+{
+    SetVersion("0.1.2");
+    Save();
+}
diff --git a/src/libs/ifc/xml/vpatternconverter.h b/src/libs/ifc/xml/vpatternconverter.h
index e4d3db2b3..118176eea 100644
--- a/src/libs/ifc/xml/vpatternconverter.h
+++ b/src/libs/ifc/xml/vpatternconverter.h
@@ -48,11 +48,13 @@ protected:
     virtual QString MaxVerStr() const;
 
     QString         XSDSchema(int ver) const;
-    virtual void    ApplyPatches() const;
+    virtual void    ApplyPatches();
 
 private:
     Q_DISABLE_COPY(VPatternConverter)
     static const QString    PatternMinVerStr;
+
+    void ToV0_1_2();
 };
 
 #endif // VPATTERNCONVERTER_H