diff --git a/ChangeLog.txt b/ChangeLog.txt
index 0539717c8..6363689a1 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -50,6 +50,10 @@
 - [#589] Valentina lock up if not enough space for label.
 - [#606] Mac OS X. Can’t type in measurements due to digit count limitation.
 - [#612] Valentina crashes when network is disabled on Linux.
+- [#406] New feature: Seam allowance tool -> Preview.
+- [#88] New feature: Variable width seam allowances.
+- [#280] New tool: 'Hem' in Detail mode.
+- [#509] Improve feature: Support internal Paths in Detail tool.
 
 # Version 0.4.6
 - [#594] Broken export on Mac.
diff --git a/src/app/share/collection/MaleShirt/MaleShirt.val b/src/app/share/collection/MaleShirt/MaleShirt.val
index cec3bc8f0..1ac2621df 100644
--- a/src/app/share/collection/MaleShirt/MaleShirt.val
+++ b/src/app/share/collection/MaleShirt/MaleShirt.val
@@ -1,7 +1,7 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <pattern>
     <!--Pattern created with Valentina (http://www.valentina-project.org/).-->
-    <version>0.3.1</version>
+    <version>0.4.0</version>
     <unit>cm</unit>
     <author>Timo Virtaneva</author>
     <description>This a male shirt pattern.
@@ -14,7 +14,7 @@ The design is based on the measuring table. The table must be loaded, but the va
 Adjust/verify curves after parameter modifications.
 
 Delete layouts which are not needed.</description>
-    <notes></notes>
+    <notes/>
     <measurements>MaleShirt.vit</measurements>
     <increments>
         <increment name="#ToBeVerified" description="" formula="0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0"/>
@@ -197,49 +197,55 @@ Delete layouts which are not needed.</description>
             <point type="modeling" inUse="true" id="440" idObject="55" mx="0.132292" my="0.264583"/>
         </modeling>
         <details>
-            <detail closed="1" id="174" name="Yoke" supplement="1" mx="-8.05221" width="1" my="3.27846">
-                <node type="NodePoint" nodeType="Contour" idObject="167" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="0" nodeType="Contour" idObject="168" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="169" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="170" mx="0" my="0"/>
-                <node type="NodeSpline" reverse="0" nodeType="Contour" idObject="171" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="172" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="173" mx="0" my="0"/>
+            <detail closed="1" id="174" name="Yoke" seamAllowance="1" mx="-8.05221" width="1" my="3.27846" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="167"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="168"/>
+                    <node type="NodePoint" idObject="169"/>
+                    <node type="NodePoint" idObject="170"/>
+                    <node type="NodeSpline" reverse="0" idObject="171"/>
+                    <node type="NodePoint" idObject="172"/>
+                    <node type="NodePoint" idObject="173"/>
+                </nodes>
             </detail>
-            <detail closed="1" id="401" name="FrontPanel" supplement="1" mx="-11.0934" width="1" my="6.43098">
-                <node type="NodePoint" nodeType="Contour" idObject="389" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="390" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="391" mx="0" my="0"/>
-                <node type="NodeSpline" reverse="0" nodeType="Contour" idObject="392" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="393" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="394" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="0" nodeType="Contour" idObject="395" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="396" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="397" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="398" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="1" nodeType="Contour" idObject="399" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="400" mx="0" my="0"/>
+            <detail closed="1" id="401" name="FrontPanel" seamAllowance="1" mx="-11.0934" width="1" my="6.43098" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="389"/>
+                    <node type="NodePoint" idObject="390"/>
+                    <node type="NodePoint" idObject="391"/>
+                    <node type="NodeSpline" reverse="0" idObject="392"/>
+                    <node type="NodePoint" idObject="393"/>
+                    <node type="NodePoint" idObject="394"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="395"/>
+                    <node type="NodePoint" idObject="396"/>
+                    <node type="NodePoint" idObject="397"/>
+                    <node type="NodePoint" idObject="398"/>
+                    <node type="NodeSplinePath" reverse="1" idObject="399"/>
+                    <node type="NodePoint" idObject="400"/>
+                </nodes>
             </detail>
-            <detail closed="1" id="441" name="BackPanel" supplement="1" mx="-7.55641" width="1" my="6.27021">
-                <node type="NodePoint" nodeType="Contour" idObject="422" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="423" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="1" nodeType="Contour" idObject="424" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="425" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="426" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="427" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="428" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="429" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="430" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="431" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="1" nodeType="Contour" idObject="432" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="433" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="434" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="435" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="0" nodeType="Contour" idObject="436" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="437" mx="0" my="0"/>
-                <node type="NodeSpline" reverse="0" nodeType="Contour" idObject="438" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="439" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="440" mx="0" my="0"/>
+            <detail closed="1" id="441" name="BackPanel" seamAllowance="1" mx="-7.55641" width="1" my="6.27021" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="422"/>
+                    <node type="NodePoint" idObject="423"/>
+                    <node type="NodeSplinePath" reverse="1" idObject="424"/>
+                    <node type="NodePoint" idObject="425"/>
+                    <node type="NodePoint" idObject="426"/>
+                    <node type="NodePoint" idObject="427"/>
+                    <node type="NodePoint" idObject="428"/>
+                    <node type="NodePoint" idObject="429"/>
+                    <node type="NodePoint" idObject="430"/>
+                    <node type="NodePoint" idObject="431"/>
+                    <node type="NodeSplinePath" reverse="1" idObject="432"/>
+                    <node type="NodePoint" idObject="433"/>
+                    <node type="NodePoint" idObject="434"/>
+                    <node type="NodePoint" idObject="435"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="436"/>
+                    <node type="NodePoint" idObject="437"/>
+                    <node type="NodeSpline" reverse="0" idObject="438"/>
+                    <node type="NodePoint" idObject="439"/>
+                    <node type="NodePoint" idObject="440"/>
+                </nodes>
             </detail>
         </details>
         <groups/>
@@ -310,36 +316,44 @@ Delete layouts which are not needed.</description>
             <spline type="modelingPath" inUse="true" id="331" idObject="312"/>
         </modeling>
         <details>
-            <detail closed="1" id="182" name="Pocket" supplement="1" mx="68.0595" width="1" my="45.4124">
-                <node type="NodePoint" nodeType="Contour" idObject="175" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="176" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="177" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="178" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="179" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="180" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="181" mx="0" my="0"/>
+            <detail closed="1" id="182" name="Pocket" seamAllowance="1" mx="68.0595" width="1" my="45.4124" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="175"/>
+                    <node type="NodePoint" idObject="176"/>
+                    <node type="NodePoint" idObject="177"/>
+                    <node type="NodePoint" idObject="178"/>
+                    <node type="NodePoint" idObject="179"/>
+                    <node type="NodePoint" idObject="180"/>
+                    <node type="NodePoint" idObject="181"/>
+                </nodes>
             </detail>
-            <detail closed="1" id="320" name="PocketRound" supplement="1" mx="81.7244" width="1" my="45.8357">
-                <node type="NodePoint" nodeType="Contour" idObject="314" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="315" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="0" nodeType="Contour" idObject="316" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="317" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="318" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="1" nodeType="Contour" idObject="319" mx="0" my="0"/>
+            <detail closed="1" id="320" name="PocketRound" seamAllowance="1" mx="81.7244" width="1" my="45.8357" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="314"/>
+                    <node type="NodePoint" idObject="315"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="316"/>
+                    <node type="NodePoint" idObject="317"/>
+                    <node type="NodePoint" idObject="318"/>
+                    <node type="NodeSplinePath" reverse="1" idObject="319"/>
+                </nodes>
             </detail>
-            <detail closed="1" id="326" name="PocketFlap" supplement="1" mx="67.876" width="1" my="32.9628">
-                <node type="NodePoint" nodeType="Contour" idObject="321" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="322" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="323" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="324" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="325" mx="0" my="0"/>
+            <detail closed="1" id="326" name="PocketFlap" seamAllowance="1" mx="67.876" width="1" my="32.9628" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="321"/>
+                    <node type="NodePoint" idObject="322"/>
+                    <node type="NodePoint" idObject="323"/>
+                    <node type="NodePoint" idObject="324"/>
+                    <node type="NodePoint" idObject="325"/>
+                </nodes>
             </detail>
-            <detail closed="1" id="332" name="PocketFlapRound" supplement="1" mx="81.7244" width="1" my="32.9627">
-                <node type="NodePoint" nodeType="Contour" idObject="327" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="328" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="329" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="330" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="1" nodeType="Contour" idObject="331" mx="0" my="0"/>
+            <detail closed="1" id="332" name="PocketFlapRound" seamAllowance="1" mx="81.7244" width="1" my="32.9627" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="327"/>
+                    <node type="NodePoint" idObject="328"/>
+                    <node type="NodePoint" idObject="329"/>
+                    <node type="NodePoint" idObject="330"/>
+                    <node type="NodeSplinePath" reverse="1" idObject="331"/>
+                </nodes>
             </detail>
         </details>
         <groups/>
@@ -393,7 +407,7 @@ Delete layouts which are not needed.</description>
             <line typeLine="hair" id="107" firstPoint="99" secondPoint="96" lineColor="black"/>
             <line typeLine="hair" id="108" firstPoint="98" secondPoint="94" lineColor="black"/>
             <line typeLine="hair" id="109" firstPoint="100" secondPoint="93" lineColor="black"/>
-            <spline type="simpleInteractive" point4="89" angle1="12.2644" angle2="338.776" id="110" color="black" length1="4.83467" length2="0.851297" point1="104"/>
+            <spline type="simpleInteractive" point4="89" angle1="12.2644" angle2="208.953" id="110" color="black" length1="4.83467" length2="0.750071" point1="104"/>
             <spline type="simpleInteractive" point4="100" angle1="164.47" angle2="0" id="111" color="black" length1="2.91869" length2="0" point1="106"/>
             <line typeLine="hair" id="112" firstPoint="96" secondPoint="95" lineColor="black"/>
             <line typeLine="hair" id="113" firstPoint="94" secondPoint="92" lineColor="black"/>
@@ -447,45 +461,53 @@ Delete layouts which are not needed.</description>
             <point type="modeling" inUse="true" id="299" idObject="97" mx="-0.222289" my="0.696084"/>
         </modeling>
         <details>
-            <detail closed="1" id="204" name="Collar" supplement="1" mx="27.4551" width="1" my="0.587081">
-                <node type="NodePoint" nodeType="Contour" idObject="200" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="201" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="202" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="203" mx="0" my="0"/>
+            <detail closed="1" id="204" name="Collar" seamAllowance="1" mx="27.4551" width="1" my="0.587081" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="200"/>
+                    <node type="NodePoint" idObject="201"/>
+                    <node type="NodePoint" idObject="202"/>
+                    <node type="NodePoint" idObject="203"/>
+                </nodes>
             </detail>
-            <detail closed="1" id="209" name="CuffInterface" supplement="0" mx="26.9909" width="1" my="-8.22145">
-                <node type="NodePoint" nodeType="Contour" idObject="205" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="206" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="207" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="208" mx="0" my="0"/>
+            <detail closed="1" id="209" name="CuffInterface" seamAllowance="0" mx="26.9909" width="1" my="-8.22145" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="205"/>
+                    <node type="NodePoint" idObject="206"/>
+                    <node type="NodePoint" idObject="207"/>
+                    <node type="NodePoint" idObject="208"/>
+                </nodes>
             </detail>
-            <detail closed="1" id="217" name="ShortSleeve" supplement="1" mx="-16.9664" width="1" my="-23.4126">
-                <node type="NodePoint" nodeType="Contour" idObject="210" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="211" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="212" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="0" nodeType="Contour" idObject="213" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="214" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="215" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="216" mx="0" my="0"/>
+            <detail closed="1" id="217" name="ShortSleeve" seamAllowance="1" mx="-16.9664" width="1" my="-23.4126" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="210"/>
+                    <node type="NodePoint" idObject="211"/>
+                    <node type="NodePoint" idObject="212"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="213"/>
+                    <node type="NodePoint" idObject="214"/>
+                    <node type="NodePoint" idObject="215"/>
+                    <node type="NodePoint" idObject="216"/>
+                </nodes>
             </detail>
-            <detail closed="1" id="300" name="FullSleeve" supplement="1" mx="-16.0896" width="1" my="15.2013">
-                <node type="NodePoint" nodeType="Contour" idObject="283" mx="0" my="0"/>
-                <node type="NodeSpline" reverse="1" nodeType="Contour" idObject="284" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="285" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="286" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="0" nodeType="Contour" idObject="287" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="288" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="289" mx="0" my="0"/>
-                <node type="NodeSpline" reverse="0" nodeType="Contour" idObject="290" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="291" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="292" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="293" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="294" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="295" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="296" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="297" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="298" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="299" mx="0" my="0"/>
+            <detail closed="1" id="300" name="FullSleeve" seamAllowance="1" mx="-16.0896" width="1" my="15.2013" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="283"/>
+                    <node type="NodeSpline" reverse="1" idObject="284"/>
+                    <node type="NodePoint" idObject="285"/>
+                    <node type="NodePoint" idObject="286"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="287"/>
+                    <node type="NodePoint" idObject="288"/>
+                    <node type="NodePoint" idObject="289"/>
+                    <node type="NodeSpline" reverse="0" idObject="290"/>
+                    <node type="NodePoint" idObject="291"/>
+                    <node type="NodePoint" idObject="292"/>
+                    <node type="NodePoint" idObject="293"/>
+                    <node type="NodePoint" idObject="294"/>
+                    <node type="NodePoint" idObject="295"/>
+                    <node type="NodePoint" idObject="296"/>
+                    <node type="NodePoint" idObject="297"/>
+                    <node type="NodePoint" idObject="298"/>
+                    <node type="NodePoint" idObject="299"/>
+                </nodes>
             </detail>
         </details>
         <groups/>
@@ -543,37 +565,45 @@ Delete layouts which are not needed.</description>
             <spline type="modelingSpline" inUse="true" id="254" idObject="248"/>
         </modeling>
         <details>
-            <detail closed="1" id="224" name="CollarBase" supplement="1" mx="28.4767" width="1" my="21.6501">
-                <node type="NodePoint" nodeType="Contour" idObject="218" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="1" nodeType="Contour" idObject="219" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="220" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="221" mx="0" my="0"/>
-                <node type="NodeSpline" reverse="1" nodeType="Contour" idObject="222" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="223" mx="0" my="0"/>
+            <detail closed="1" id="224" name="CollarBase" seamAllowance="1" mx="28.4767" width="1" my="21.6501" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="218"/>
+                    <node type="NodeSplinePath" reverse="1" idObject="219"/>
+                    <node type="NodePoint" idObject="220"/>
+                    <node type="NodePoint" idObject="221"/>
+                    <node type="NodeSpline" reverse="1" idObject="222"/>
+                    <node type="NodePoint" idObject="223"/>
+                </nodes>
             </detail>
-            <detail closed="1" id="231" name="CollarBaseInterface" supplement="0" mx="28.6569" width="1" my="15.2047">
-                <node type="NodePoint" nodeType="Contour" idObject="225" mx="0" my="0"/>
-                <node type="NodeSplinePath" reverse="1" nodeType="Contour" idObject="226" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="227" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="228" mx="0" my="0"/>
-                <node type="NodeSpline" reverse="1" nodeType="Contour" idObject="229" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="230" mx="0" my="0"/>
+            <detail closed="1" id="231" name="CollarBaseInterface" seamAllowance="0" mx="28.6569" width="1" my="15.2047" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="225"/>
+                    <node type="NodeSplinePath" reverse="1" idObject="226"/>
+                    <node type="NodePoint" idObject="227"/>
+                    <node type="NodePoint" idObject="228"/>
+                    <node type="NodeSpline" reverse="1" idObject="229"/>
+                    <node type="NodePoint" idObject="230"/>
+                </nodes>
             </detail>
-            <detail closed="1" id="238" name="CollarTop" supplement="1" mx="28.0866" width="1" my="9.53729">
-                <node type="NodePoint" nodeType="Contour" idObject="232" mx="0" my="0"/>
-                <node type="NodeSpline" reverse="0" nodeType="Contour" idObject="233" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="234" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="235" mx="0" my="0"/>
-                <node type="NodeSpline" reverse="0" nodeType="Contour" idObject="236" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="237" mx="0" my="0"/>
+            <detail closed="1" id="238" name="CollarTop" seamAllowance="1" mx="28.0866" width="1" my="9.53729" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="232"/>
+                    <node type="NodeSpline" reverse="0" idObject="233"/>
+                    <node type="NodePoint" idObject="234"/>
+                    <node type="NodePoint" idObject="235"/>
+                    <node type="NodeSpline" reverse="0" idObject="236"/>
+                    <node type="NodePoint" idObject="237"/>
+                </nodes>
             </detail>
-            <detail closed="1" id="255" name="CollarTopInterface" supplement="0" mx="27.8619" width="1" my="-1.37137">
-                <node type="NodePoint" nodeType="Contour" idObject="249" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="250" mx="0" my="0"/>
-                <node type="NodeSpline" reverse="0" nodeType="Contour" idObject="251" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="252" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="253" mx="0" my="0"/>
-                <node type="NodeSpline" reverse="0" nodeType="Contour" idObject="254" mx="0" my="0"/>
+            <detail closed="1" id="255" name="CollarTopInterface" seamAllowance="0" mx="27.8619" width="1" my="-1.37137" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="249"/>
+                    <node type="NodePoint" idObject="250"/>
+                    <node type="NodeSpline" reverse="0" idObject="251"/>
+                    <node type="NodePoint" idObject="252"/>
+                    <node type="NodePoint" idObject="253"/>
+                    <node type="NodeSpline" reverse="0" idObject="254"/>
+                </nodes>
             </detail>
         </details>
         <groups/>
@@ -609,20 +639,24 @@ Delete layouts which are not needed.</description>
             <point type="modeling" inUse="true" id="281" idObject="260" mx="0.132292" my="0.264583"/>
         </modeling>
         <details>
-            <detail closed="1" id="274" name="PlacketUnder" supplement="1" mx="27.725" width="1" my="-0.179464">
-                <node type="NodePoint" nodeType="Contour" idObject="270" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="271" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="272" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="273" mx="0" my="0"/>
+            <detail closed="1" id="274" name="PlacketUnder" seamAllowance="1" mx="27.725" width="1" my="-0.179464" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="270"/>
+                    <node type="NodePoint" idObject="271"/>
+                    <node type="NodePoint" idObject="272"/>
+                    <node type="NodePoint" idObject="273"/>
+                </nodes>
             </detail>
-            <detail closed="1" id="282" name="PlacketTop" supplement="1" mx="46.1968" width="1" my="-5.58778">
-                <node type="NodePoint" nodeType="Contour" idObject="275" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="276" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="277" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="278" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="279" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="280" mx="0" my="0"/>
-                <node type="NodePoint" nodeType="Contour" idObject="281" mx="0" my="0"/>
+            <detail closed="1" id="282" name="PlacketTop" seamAllowance="1" mx="46.1968" width="1" my="-5.58778" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="275"/>
+                    <node type="NodePoint" idObject="276"/>
+                    <node type="NodePoint" idObject="277"/>
+                    <node type="NodePoint" idObject="278"/>
+                    <node type="NodePoint" idObject="279"/>
+                    <node type="NodePoint" idObject="280"/>
+                    <node type="NodePoint" idObject="281"/>
+                </nodes>
             </detail>
         </details>
         <groups/>
diff --git a/src/app/share/collection/bugs/Issue_#604.val b/src/app/share/collection/bugs/Issue_#604.val
index 084ddd57b..f43d59593 100644
--- a/src/app/share/collection/bugs/Issue_#604.val
+++ b/src/app/share/collection/bugs/Issue_#604.val
@@ -6,7 +6,7 @@
     <author/>
     <description/>
     <notes/>
-    <measurements>3XL.vit</measurements>
+    <measurements>Issue_#604.vit</measurements>
     <increments/>
     <draw name="Élément de patron 1">
         <calculation>
diff --git a/src/app/share/collection/bugs/pointOnCurve.val b/src/app/share/collection/bugs/pointOnCurve.val
new file mode 100644
index 000000000..58baf1e84
--- /dev/null
+++ b/src/app/share/collection/bugs/pointOnCurve.val
@@ -0,0 +1,282 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<pattern>
+    <!--Valentina pattern format.-->
+    <version>0.4.0</version>
+    <unit>mm</unit>
+    <author/>
+    <description/>
+    <notes/>
+    <gradation defSize="300" defHeight="1100" custom="true">
+        <heights all="true"/>
+        <sizes all="true"/>
+    </gradation>
+    <measurements>../../../../../../../Valentina_0.5.x/build-Valentina-Qt_5_2_1_GCC_32bit-Debug/src/app/valentina/bin/tables/standard/GOST_man_ru.vst</measurements>
+    <increments>
+        <increment name="#Пс_впрз" description="Высота основания" formula="16.1"/>
+        <increment name="#Пк_впрз1" description="проймы сзади АГ" formula="14"/>
+        <increment name="#Пдтс1" description="Длина спинки" formula="13"/>
+        <increment name="#Пдтс2" description="до линии талии АТ" formula="20"/>
+        <increment name="#Пус_ди" description="Длина куртки АН" formula="-67"/>
+        <increment name="#Пс_шс" description="Ширина спинки ГГ2" formula="21"/>
+        <increment name="#Пк_шс1" description="Опис" formula="2"/>
+        <increment name="#Пк_шс2" description="Опис" formula="2"/>
+        <increment name="#Пшпр1" description="Ширина проймы Г2Г3" formula="46"/>
+        <increment name="#Пшпр2" description="Опис" formula="-24"/>
+        <increment name="#Пс_шг" description="Ширина полочки на" formula="42"/>
+        <increment name="#Пк_шг1" description="уровне линии груди" formula="4"/>
+        <increment name="#Пк_шг2" description="Г3Г4" formula="0"/>
+        <increment name="#Пс_шпт" description=" Ширина полочки на уровне линии талии Т3Т4" formula="19"/>
+        <increment name="#Пс_впрс" description="Высота проймы спинки" formula="42"/>
+        <increment name="#Пс_впр" description="Высота проймы полочки Г3П3" formula="28"/>
+        <increment name="#Пк_впр1" description="Опис" formula="8.5"/>
+        <increment name="#Пс_впрп" description="Высота горловины" formula="38"/>
+        <increment name="#Пк_впрп1" description="полочки Г5А4" formula="9"/>
+        <increment name="#Пшгс" description="Ширина горловины спинки А1А2" formula="30"/>
+        <increment name="#Пк_шп1" description="Длина плечевой линии" formula="3"/>
+        <increment name="#Пк_шп2" description="спинки А3П2" formula="-1"/>
+        <increment name="#Ппос_шп" description="Опис" formula="-2"/>
+        <increment name="#Пс_сб" description="Ширина куртки на линии бедер" formula="20"/>
+        <increment name="#Пдр1" description="Длина рукава АН" formula="82"/>
+        <increment name="#Пдр2" description="Опис" formula="20"/>
+        <increment name="#Пдр_лок1" description="Длина рукава до" formula="38"/>
+        <increment name="#Пдр_лок2" description="локтя АЛ" formula="-10"/>
+        <increment name="#Пшр" description="Ширина рукава с курточным окатом АА1 и ББ2" formula="42"/>
+        <increment name="#Ппос_ор" description="Прибавка на посадку по окату рукава" formula="34"/>
+        <increment name="#Пшр1" description="Description" formula="50"/>
+        <increment name="#Пшр2" description="Description" formula="62"/>
+        <increment name="#Швс" description="Description" formula="70"/>
+        <increment name="#Пвк" description="Висота капишона" formula="20"/>
+        <increment name="#Пшк" description="ширина капишона" formula="20"/>
+    </increments>
+    <draw name="Куртка">
+        <calculation>
+            <point type="single" x="16.3689" y="57.7733" id="33" name="А" mx="1.32292" my="2.64583"/>
+            <point type="endLine" typeLine="none" id="34" name="Г" basePoint="33" lineColor="black" mx="1.32292" angle="270" my="2.64583" length="0.2 * bust_arc_f + 0.07 * height + #Пс_впрз+10"/>
+            <point type="alongLine" typeLine="none" id="35" name="У" firstPoint="33" secondPoint="34" lineColor="black" mx="1.32292" my="2.64583" length="0.5*Line_А_Г"/>
+            <point type="endLine" typeLine="none" id="36" name="Т" basePoint="33" lineColor="black" mx="1.32292" angle="270" my="2.64583" length="0.25 * height + #Пдтс2"/>
+            <point type="endLine" typeLine="hair" id="37" name="Н" basePoint="33" lineColor="black" mx="1.32292" angle="270" my="2.64583" length="0.33 * height + 0.33 * indent_neck_back"/>
+            <point type="endLine" typeLine="hair" id="38" name="Г2" basePoint="34" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="0.35 * bust_arc_f + 0.017 * height + #Пс_шс + #Пк_шс2"/>
+            <point type="endLine" typeLine="hair" id="39" name="Г3" basePoint="38" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="0.3 * bust_arc_f + #Пшпр2"/>
+            <point type="endLine" typeLine="hair" id="40" name="Г4" basePoint="39" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="0.35 * bust_arc_f + 0.01 * height + #Пс_шг + #Пк_шг2"/>
+            <point type="endLine" typeLine="hair" id="41" name="А2" basePoint="33" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="0.35*neck_mid_circ + #Пшгс"/>
+            <point type="endLine" typeLine="none" id="42" name="Г5" basePoint="40" lineColor="black" mx="1.32292" angle="180" my="2.64583" length="Line_А_А2"/>
+            <point type="endLine" typeLine="hair" id="43" name="А3" basePoint="41" lineColor="black" mx="1.32292" angle="90" my="2.64583" length="0.35*Line_А_А2"/>
+            <point type="endLine" typeLine="hair" id="44" name="А20" basePoint="41" lineColor="black" mx="-2.08003" angle="135" my="6.61594" length="0.75*Line_А2_А3"/>
+            <point type="endLine" typeLine="hair" id="45" name="П" basePoint="38" lineColor="black" mx="1.32292" angle="90" my="2.64583" length="0.2 * bust_arc_f + 0.05 * height + #Пс_впрс+10"/>
+            <point type="endLine" typeLine="hair" id="46" name="П1" basePoint="35" lineColor="black" mx="28.6501" angle="0" my="-31.8727" length="Line_Г_Г2"/>
+            <point type="alongLine" typeLine="hair" id="47" name="П2" firstPoint="43" secondPoint="45" lineColor="black" mx="1.32292" my="2.64583" length="0.2 * bust_arc_f + 0.03 * height + #Пк_шп2 + #Ппос_шп"/>
+            <point type="alongLine" typeLine="none" id="48" name="П20" firstPoint="43" secondPoint="45" lineColor="black" mx="1.32292" my="2.64583" length="50"/>
+            <point type="endLine" typeLine="hair" id="49" name="П3" basePoint="39" lineColor="black" mx="1.32292" angle="90" my="2.64583" length="Line_Г2_П"/>
+            <point type="endLine" typeLine="hair" id="50" name="А4" basePoint="42" lineColor="black" mx="1.32292" angle="90" my="2.64583" length="Line_А_Г+Line_А2_А3"/>
+            <point type="alongLine" typeLine="hair" id="51" name="П4" firstPoint="50" secondPoint="49" lineColor="black" mx="-1.00541" my="-11.3242" length="Line_А3_П2"/>
+            <point type="endLine" typeLine="none" id="52" name="П5" basePoint="39" lineColor="black" mx="8.59896" angle="90" my="-2.01084" length="Line_Г3_П3*0.4444"/>
+            <line typeLine="hair" id="53" firstPoint="51" secondPoint="52" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="54" name="П7" firstPoint="52" secondPoint="51" lineColor="black" mx="-9.23943" my="2.64583" length="0.5*Line_П4_П5"/>
+            <point type="normal" typeLine="hair" id="55" name="П8" firstPoint="54" secondPoint="52" lineColor="black" mx="2.61006" angle="0" my="-10.595" length="1"/>
+            <point type="endLine" typeLine="none" id="56" name="Г6" basePoint="34" lineColor="black" mx="5.48569" angle="0" my="4.79765" length="0.5*(Line_Г_Г2+Line_Г2_Г3+Line_Г3_Г4)"/>
+            <point type="endLine" typeLine="hair" id="57" name="З" basePoint="38" lineColor="black" mx="-3.0442" angle="45" my="8.2607" length="0.24*Line_Г2_Г3"/>
+            <point type="endLine" typeLine="hair" id="58" name="З3" basePoint="39" lineColor="black" mx="0.0751693" angle="135" my="8.88457" length="0.24*Line_Г2_Г3"/>
+            <point type="endLine" typeLine="hair" id="59" name="А5" basePoint="50" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="Line_А_А2"/>
+            <line typeLine="hair" id="60" firstPoint="59" secondPoint="40" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="61" name="А6" firstPoint="59" secondPoint="40" lineColor="black" mx="22.4896" my="-8.99584" length="0.82*Line_А4_А5"/>
+            <point type="alongLine" typeLine="none" id="62" name="А7" firstPoint="50" secondPoint="42" lineColor="black" mx="1.32292" my="2.64583" length="0.8*Line_А4_А5"/>
+            <line typeLine="hair" id="63" firstPoint="62" secondPoint="61" lineColor="black"/>
+            <point type="bisector" typeLine="hair" id="64" name="А51" thirdPoint="61" firstPoint="50" secondPoint="62" lineColor="black" mx="1.32292" my="2.64583" length="150"/>
+            <point type="lineIntersect" id="65" name="А50" p2Line1="59" p2Line2="64" p1Line1="50" p1Line2="62" mx="1.32292" my="2.64583"/>
+            <point type="pointOfContact" id="66" name="Ак" radius="Line_А4_А50" firstPoint="62" center="65" secondPoint="61" mx="1.32292" my="2.64583"/>
+            <point type="endLine" typeLine="hair" id="67" name="Т3" basePoint="36" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="Line_Г_Г2+Line_Г2_Г3"/>
+            <line typeLine="hair" id="68" firstPoint="39" secondPoint="67" lineColor="black"/>
+            <point type="endLine" typeLine="hair" id="69" name="Т4" basePoint="67" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="Line_Г3_Г4"/>
+            <line typeLine="hair" id="70" firstPoint="40" secondPoint="69" lineColor="black"/>
+            <point type="endLine" typeLine="hair" id="71" name="Н3" basePoint="37" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="Line_Т3_Т4+Line_Т_Т3"/>
+            <line typeLine="hair" id="72" firstPoint="69" secondPoint="71" lineColor="black"/>
+            <point type="endLine" typeLine="none" id="73" name="Н5" basePoint="37" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="Line_Г_Г6"/>
+            <line typeLine="hair" id="74" firstPoint="56" secondPoint="73" lineColor="black"/>
+            <line typeLine="hair" id="75" firstPoint="65" secondPoint="66" lineColor="black"/>
+            <arc type="simple" angle1="180" angle2="AngleLine_А50_Ак" id="76" radius="Line_А4_А50" center="65" color="black"/>
+            <spline type="pathInteractive" id="77" color="black">
+                <pathPoint angle1="184.205" pSpline="33" angle2="4.20522" length1="0" length2="27.556"/>
+                <pathPoint angle1="215.751" pSpline="44" angle2="35.7515" length1="12.4503" length2="8.15772"/>
+                <pathPoint angle1="234.166" pSpline="43" angle2="54.166" length1="5.84299" length2="0"/>
+            </spline>
+            <spline type="pathInteractive" id="78" color="black">
+                <pathPoint angle1="80.258" pSpline="47" angle2="260.258" length1="0" length2="20.8645"/>
+                <pathPoint angle1="87.674" pSpline="46" angle2="267.674" length1="30.751" length2="50.1703"/>
+                <pathPoint angle1="120.24" pSpline="57" angle2="300.24" length1="11.5169" length2="12.8071"/>
+                <pathPoint angle1="184.589" pSpline="56" angle2="4.58891" length1="12.5947" length2="0"/>
+            </spline>
+            <point type="endLine" typeLine="hair" id="79" name="П5н" basePoint="52" lineColor="black" mx="-13.6151" angle="180" my="5.24991" length="1"/>
+            <spline type="pathInteractive" id="80" color="black">
+                <pathPoint angle1="101.835" pSpline="51" angle2="281.835" length1="0" length2="27.3441"/>
+                <pathPoint angle1="100.326" pSpline="55" angle2="280.326" length1="3.61809" length2="21.5186"/>
+                <pathPoint angle1="93.053" pSpline="79" angle2="273.053" length1="12.096" length2="38.3854"/>
+                <pathPoint angle1="56.906" pSpline="58" angle2="236.906" length1="13.1026" length2="8.79047"/>
+                <pathPoint angle1="355.114" pSpline="56" angle2="175.114" length1="9.58048" length2="0"/>
+            </spline>
+            <line typeLine="hair" id="81" firstPoint="43" secondPoint="50" lineColor="black"/>
+            <line typeLine="hair" id="82" firstPoint="47" secondPoint="51" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="83" name="П11" firstPoint="47" secondPoint="51" lineColor="black" mx="1.32292" my="2.64583" length="Line_П2_П4*0.5"/>
+            <point type="endLine" typeLine="none" id="86" name="Г81" basePoint="83" lineColor="black" mx="-23.9299" angle="270" my="11.8341" length="Line_А_Г"/>
+            <point type="lineIntersect" id="87" name="Г8" p2Line1="86" p2Line2="39" p1Line1="83" p1Line2="34" mx="-26.0772" my="7.75128"/>
+            <line typeLine="hair" id="88" firstPoint="87" secondPoint="83" lineColor="black"/>
+            <point type="endLine" typeLine="hair" id="89" name="К2" basePoint="67" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="0.1*bust_arc_f"/>
+            <point type="endLine" typeLine="hair" id="90" name="К3" basePoint="89" lineColor="black" mx="1.32292" angle="80" my="2.64583" length="50"/>
+            <point type="endLine" typeLine="hair" id="91" name="К4" basePoint="89" lineColor="black" mx="1.32292" angle="260" my="2.64583" length="50"/>
+            <point type="endLine" typeLine="hair" id="92" name="К5" basePoint="90" lineColor="black" mx="1.32292" angle="170" my="2.64583" length="15"/>
+            <point type="endLine" typeLine="hair" id="93" name="К6" basePoint="91" lineColor="black" mx="1.32292" angle="170" my="2.64583" length="15"/>
+            <line typeLine="hair" id="94" firstPoint="92" secondPoint="93" lineColor="black"/>
+            <point type="alongLine" typeLine="hair" id="95" name="А41" firstPoint="50" secondPoint="49" lineColor="black" mx="1.32292" my="2.64583" length="20"/>
+            <line typeLine="hair" id="96" firstPoint="73" secondPoint="71" lineColor="black"/>
+            <point type="alongLine" typeLine="hair" id="97" name="Н31" firstPoint="73" secondPoint="71" lineColor="black" mx="1.32292" my="2.64583" length="Line_Н5_Н3-50"/>
+            <spline type="simpleInteractive" point4="97" angle1="286.103" angle2="92.0822" id="98" color="black" length1="160.559" length2="101.493" point1="95"/>
+            <point type="cutSplinePath" id="203" name="С1" splinePath="78" mx="23.5479" my="13.2292" length="SplPath_П2_Г6*0.5"/>
+            <point type="cutSplinePath" id="209" name="С3" splinePath="80" mx="18.0755" my="25.1094" length="SplPath_П4_Г6*0.5"/>
+            <point type="alongLine" typeLine="none" id="286" name="Ф1" firstPoint="33" secondPoint="36" lineColor="black" mx="1.32292" my="2.64583" length="Line_А_Т*0.205"/>
+            <point type="cutSplinePath" id="287" name="Ф2" splinePath="78" mx="1.32292" my="2.64583" length="SplPath_П2_С1*0.67"/>
+            <line typeLine="hair" id="290" firstPoint="286" secondPoint="287" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="291" name="Ф3" firstPoint="69" secondPoint="59" lineColor="black" mx="1.32292" my="2.64583" length="Line_Ф1_Т"/>
+            <point type="cutSplinePath" id="292" name="Ф4" splinePath="80" mx="1.32292" my="2.64583" length="SplPath_П4_С3*0.67"/>
+            <line typeLine="hair" id="295" firstPoint="292" secondPoint="291" lineColor="black"/>
+        </calculation>
+        <modeling>
+            <point type="modeling" inUse="true" id="296" idObject="33" mx="1.32292" my="2.64583"/>
+            <spline type="modelingPath" inUse="true" id="297" idObject="77"/>
+            <point type="modeling" inUse="true" id="298" idObject="43" mx="1.32292" my="2.64583"/>
+            <point type="modeling" inUse="true" id="299" idObject="47" mx="1.32292" my="2.64583"/>
+            <spline type="modelingPath" inUse="true" id="300" idObject="78"/>
+            <point type="modeling" inUse="true" id="301" idObject="287" mx="1.32292" my="2.64583"/>
+            <point type="modeling" inUse="true" id="302" idObject="286" mx="1.32292" my="2.64583"/>
+        </modeling>
+        <details>
+            <detail closed="0" id="303" name="Деталь" forbidFlipping="true" united="false" seamAllowance="true" width="7" mx="10.0402" inLayout="true" my="-26.0133" version="2">
+                <data rotation="0" letter="" fontSize="0" visible="true" mx="0" width="0" my="0" height="0"/>
+                <patternInfo rotation="0" fontSize="0" visible="true" mx="0" width="0" my="0" height="0"/>
+                <grainline arrows="0" rotation="90" visible="false" mx="0" my="0" length="0"/>
+                <nodes>
+                    <node type="NodePoint" idObject="299"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="300"/>
+                    <node type="NodePoint" idObject="301"/>
+                    <node type="NodePoint" after="0" idObject="302"/>
+                    <node before="0" type="NodePoint" idObject="296"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="297"/>
+                    <node type="NodePoint" idObject="298"/>
+                </nodes>
+            </detail>
+        </details>
+        <groups/>
+    </draw>
+    <draw name="Рукав">
+        <calculation>
+            <point type="single" x="662.911" y="-31.3691" id="125" name="А" mx="1.32292" my="2.64583"/>
+            <point type="endLine" typeLine="hair" id="126" name="Н" basePoint="125" lineColor="black" mx="1.32292" angle="270" my="2.64583" length="0.33*height+0.15*bust_arc_f-50"/>
+            <point type="alongLine" typeLine="none" id="127" name="Б" firstPoint="125" secondPoint="126" lineColor="black" mx="1.32292" my="2.64583" length="0.3792*Line_Г8_П11"/>
+            <point type="endLine" typeLine="none" id="128" name="Б1" basePoint="127" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="Line_Г2_Г3+#Пшр1"/>
+            <point type="endLine" typeLine="none" id="129" name="Б4" basePoint="127" lineColor="black" mx="1.32292" angle="180" my="2.64583" length="Line_Г2_Г3+#Пшр1"/>
+            <point type="endLine" typeLine="hair" id="130" name="Н1" basePoint="126" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="0.6*Line_Б_Б1+38"/>
+            <line typeLine="hair" id="131" firstPoint="128" secondPoint="130" lineColor="black"/>
+            <point type="endLine" typeLine="hair" id="132" name="Н2" basePoint="126" lineColor="black" mx="1.32292" angle="180" my="2.64583" length="0.6*Line_Б_Б1+38"/>
+            <line typeLine="hair" id="133" firstPoint="129" secondPoint="132" lineColor="black"/>
+            <point type="alongLine" typeLine="hair" id="138" name="Б2" firstPoint="127" secondPoint="128" lineColor="black" mx="1.32292" my="2.64583" length="((0.5 * (SplPath_П2_Г6+SplPath_П4_Г6) +3)^2 - Line_А_Б^2)^0.5"/>
+            <point type="alongLine" typeLine="hair" id="139" name="Б3" firstPoint="127" secondPoint="129" lineColor="black" mx="1.32292" my="2.64583" length="((0.5 * (SplPath_П2_Г6+SplPath_П4_Г6) -8)^2 - Line_А_Б^2)^0.5"/>
+            <line typeLine="hair" id="140" firstPoint="125" secondPoint="138" lineColor="black"/>
+            <line typeLine="hair" id="141" firstPoint="125" secondPoint="139" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="142" name="А1" firstPoint="125" secondPoint="138" lineColor="black" mx="19.0616" my="-50.5702" length="Line_А_Б2*0.5"/>
+            <point type="alongLine" typeLine="none" id="143" name="А2" firstPoint="125" secondPoint="142" lineColor="black" mx="0.130208" my="6.82032" length="Line_А_А1*0.5"/>
+            <point type="alongLine" typeLine="none" id="144" name="А3" firstPoint="142" secondPoint="138" lineColor="black" mx="5.9633" my="-10.2441" length="Line_А1_Б2*0.5"/>
+            <point type="alongLine" typeLine="none" id="145" name="А1з" firstPoint="125" secondPoint="139" lineColor="black" mx="-4.43017" my="-60.6381" length="Line_А_Б3*0.5"/>
+            <point type="alongLine" typeLine="none" id="146" name="А2з" firstPoint="125" secondPoint="145" lineColor="black" mx="4.33266" my="4.97457" length="Line_А_А1з*0.5"/>
+            <point type="alongLine" typeLine="none" id="147" name="А3з" firstPoint="145" secondPoint="139" lineColor="black" mx="-2.80186" my="-13.3377" length="Line_А1з_Б3*0.5"/>
+            <point type="normal" typeLine="hair" id="148" name="А4" firstPoint="143" secondPoint="138" lineColor="black" mx="1.89007" angle="0" my="-12.1003" length="0.10*Line_А_Б"/>
+            <point type="normal" typeLine="hair" id="149" name="А4з" firstPoint="146" secondPoint="125" lineColor="black" mx="-15.3305" angle="0" my="-20.8475" length="0.10*Line_А_Б"/>
+            <point type="normal" typeLine="hair" id="150" name="А5" firstPoint="144" secondPoint="125" lineColor="black" mx="-5.89299" angle="0" my="6.80045" length="Line_А2_А4"/>
+            <point type="normal" typeLine="hair" id="151" name="А5з" firstPoint="147" secondPoint="139" lineColor="black" mx="2.85356" angle="0" my="5.92579" length="Line_А2з_А4з"/>
+            <line typeLine="hair" id="152" firstPoint="148" secondPoint="150" lineColor="black"/>
+            <line typeLine="hair" id="153" firstPoint="149" secondPoint="151" lineColor="black"/>
+            <point type="alongLine" typeLine="hair" id="154" name="О" firstPoint="148" secondPoint="143" lineColor="black" mx="-9.59601" my="-2.49453" length="Line_А2_А4*0.25"/>
+            <point type="alongLine" typeLine="hair" id="155" name="Оз" firstPoint="149" secondPoint="146" lineColor="black" mx="5.23899" my="-5.3851" length="Line_А2з_А4з*0.25"/>
+            <point type="alongLine" typeLine="hair" id="156" name="О1" firstPoint="150" secondPoint="144" lineColor="black" mx="8.1015" my="5.05114" length="Line_А4_О"/>
+            <point type="alongLine" typeLine="hair" id="157" name="О1з" firstPoint="151" secondPoint="147" lineColor="black" mx="-14.4209" my="2.20851" length="Line_А4з_Оз"/>
+            <point type="alongLine" typeLine="hair" id="158" name="О2" firstPoint="142" secondPoint="148" lineColor="black" mx="6.04115" my="-33.125" length="Line_А4_А5*0.25"/>
+            <point type="alongLine" typeLine="hair" id="159" name="О2з" firstPoint="145" secondPoint="149" lineColor="black" mx="8.66898" my="14.5691" length="Line_А4з_А5з*0.25"/>
+            <point type="alongLine" typeLine="hair" id="160" name="А6" firstPoint="144" secondPoint="150" lineColor="black" mx="9.12091" my="2.93381" length="Line_А3_А5*0.5"/>
+            <point type="alongLine" typeLine="hair" id="161" name="А6з" firstPoint="147" secondPoint="151" lineColor="black" mx="-12.8902" my="-0.415461" length="Line_А3з_А5з*0.5"/>
+            <point type="lineIntersect" id="162" name="О3" p2Line1="158" p2Line2="138" p1Line1="160" p1Line2="125" mx="5.68854" my="-6.37646"/>
+            <point type="lineIntersect" id="163" name="О3з" p2Line1="159" p2Line2="139" p1Line1="161" p1Line2="125" mx="-22.6642" my="-26.58"/>
+            <point type="alongLine" typeLine="hair" id="164" name="О4" firstPoint="160" secondPoint="144" lineColor="black" mx="13.8377" my="-4.63021" length="Line_А3_А6*0.25"/>
+            <point type="alongLine" typeLine="hair" id="165" name="О4з" firstPoint="161" secondPoint="147" lineColor="black" mx="7.08554" my="-5.9981" length="Line_А3з_А6з*0.25"/>
+            <spline type="pathInteractive" id="166" color="black">
+                <pathPoint angle1="179.998" pSpline="125" angle2="359.998" length1="0" length2="12.3634"/>
+                <pathPoint angle1="153.959" pSpline="154" angle2="333.959" length1="14.6138" length2="5.85177"/>
+                <pathPoint angle1="153.373" pSpline="158" angle2="333.373" length1="5.10362" length2="9.46745"/>
+                <pathPoint angle1="152.532" pSpline="142" angle2="332.532" length1="5.90789" length2="19.9914"/>
+                <pathPoint angle1="158.016" pSpline="156" angle2="338.016" length1="13.1046" length2="12.3332"/>
+                <pathPoint angle1="173.032" pSpline="138" angle2="353.032" length1="17.7872" length2="0"/>
+            </spline>
+            <spline type="pathInteractive" id="167" color="black">
+                <pathPoint angle1="1.148" pSpline="125" angle2="181.148" length1="0" length2="9.88634"/>
+                <pathPoint angle1="24.198" pSpline="155" angle2="204.198" length1="17.7795" length2="4.99338"/>
+                <pathPoint angle1="27.376" pSpline="159" angle2="207.376" length1="8.73578" length2="7.35637"/>
+                <pathPoint angle1="26.864" pSpline="163" angle2="206.864" length1="13.129" length2="8.98105"/>
+                <pathPoint angle1="25.87" pSpline="165" angle2="205.87" length1="13.1037" length2="6.12142"/>
+                <pathPoint angle1="9.899" pSpline="139" angle2="189.899" length1="17.6503" length2="0"/>
+            </spline>
+            <spline type="simpleInteractive" point4="138" angle1="84.068" angle2="255.161" id="168" color="black" length1="135.76" length2="82.0371" point1="130"/>
+            <spline type="simpleInteractive" point4="139" angle1="98.0171" angle2="286.671" id="169" color="black" length1="175.212" length2="76.4262" point1="132"/>
+        </calculation>
+        <modeling/>
+        <details/>
+    </draw>
+    <draw name="Комір">
+        <calculation>
+            <point type="single" x="711.333" y="736.791" id="190" name="В" mx="1.32292" my="2.64583"/>
+            <point type="endLine" typeLine="hair" id="192" name="В1" basePoint="190" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="SplPath_А_А3*2+(Arc_А50_76+Line_А6_Ак)*2"/>
+            <point type="endLine" typeLine="hair" id="193" name="В2" basePoint="190" lineColor="black" mx="1.32292" angle="90" my="2.64583" length="#Швс"/>
+            <point type="endLine" typeLine="hair" id="194" name="В3" basePoint="193" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="SplPath_А_А3*2+(Arc_А50_76+Line_А6_Ак)*2"/>
+            <line typeLine="hair" id="195" firstPoint="194" secondPoint="192" lineColor="black"/>
+        </calculation>
+        <modeling/>
+        <details/>
+    </draw>
+    <draw name="капишон">
+        <calculation>
+            <point type="single" x="-264.749" y="32.1467" id="224" name="А" mx="-8.83849" my="-20.0204"/>
+            <point type="endLine" typeLine="hair" id="225" name="Б" basePoint="224" lineColor="black" mx="1.32292" angle="270" my="2.64583" length="1.33*(height-height_neck_back)+#Пвк"/>
+            <point type="alongLine" typeLine="none" id="226" name="В" firstPoint="224" secondPoint="225" lineColor="black" mx="1.32292" my="2.64583" length="0.33*Line_А_Б"/>
+            <point type="alongLine" typeLine="none" id="227" name="Д" firstPoint="225" secondPoint="226" lineColor="black" mx="1.32292" my="2.64583" length="0.25*(height-height_neck_back)"/>
+            <point type="endLine" typeLine="hair" id="228" name="Г" basePoint="225" lineColor="black" mx="0.709236" angle="270" my="2.03215" length="0.33*Line_А5_А6"/>
+            <point type="endLine" typeLine="hair" id="229" name="А1" basePoint="224" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="0.4*head_circ+#Пшк"/>
+            <point type="alongLine" typeLine="none" id="230" name="А2" firstPoint="229" secondPoint="224" lineColor="black" mx="1.32292" my="2.64583" length="Line_А_В"/>
+            <point type="endLine" typeLine="hair" id="231" name="В1" basePoint="226" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="Line_А_А1"/>
+            <point type="alongLine" typeLine="none" id="232" name="В2" firstPoint="231" secondPoint="226" lineColor="black" mx="1.32292" my="2.64583" length="Line_А_В"/>
+            <line typeLine="hair" id="233" firstPoint="230" secondPoint="232" lineColor="black"/>
+            <point type="endLine" typeLine="hair" id="235" name="Г1" basePoint="228" lineColor="black" mx="8.68713" angle="180" my="2.03215" length="0.6*Line_А4_А5"/>
+            <point type="alongLine" typeLine="hair" id="236" name="Г2" firstPoint="235" secondPoint="228" lineColor="black" mx="1.32292" my="2.64583" length="SplPath_А_А3+Arc_А50_76+Line_А6_Ак"/>
+            <point type="endLine" typeLine="hair" id="237" name="Б1" basePoint="236" lineColor="black" mx="1.32292" angle="90" my="2.64583" length="Line_Б_Г"/>
+            <line typeLine="hair" id="238" firstPoint="225" secondPoint="237" lineColor="black"/>
+            <point type="endLine" typeLine="hair" id="239" name="Д1" basePoint="227" lineColor="black" mx="1.32292" angle="0" my="2.64583" length="Line_Б_Б1+2"/>
+            <line typeLine="hair" id="240" firstPoint="239" secondPoint="237" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="243" name="А4" firstPoint="224" secondPoint="226" lineColor="black" mx="1.32292" my="2.64583" length="8"/>
+            <point type="alongLine" typeLine="none" id="244" name="А3" firstPoint="224" secondPoint="230" lineColor="black" mx="1.32292" my="2.64583" length="0.65*Line_А2_А"/>
+            <line typeLine="hair" id="249" firstPoint="244" secondPoint="243" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="250" name="А5" firstPoint="244" secondPoint="243" lineColor="black" mx="1.32292" my="2.64583" length="Line_А3_А4+10"/>
+            <point type="endLine" typeLine="hair" id="254" name="Л" basePoint="235" lineColor="black" mx="1.32292" angle="90" my="2.64583" length="50"/>
+            <point type="alongLine" typeLine="none" id="255" name="Л1" firstPoint="228" secondPoint="227" lineColor="black" mx="6.63051" my="0.750261" length="Line_Г1_Л"/>
+            <line typeLine="hair" id="256" firstPoint="254" secondPoint="255" lineColor="black"/>
+            <spline type="simpleInteractive" point4="237" angle1="358.736" angle2="178.86" id="258" color="black" length1="122.19" length2="106.948" point1="235"/>
+            <spline type="pathInteractive" id="261" color="black">
+                <pathPoint angle1="175.568" pSpline="230" angle2="355.568" length1="0" length2="79.6733"/>
+                <pathPoint angle1="81.86" pSpline="231" angle2="261.86" length1="54.8681" length2="104.96"/>
+                <pathPoint angle1="73.099" pSpline="237" angle2="253.099" length1="60.9341" length2="0"/>
+            </spline>
+            <spline type="pathInteractive" id="263" color="black">
+                <pathPoint angle1="96.992" pSpline="250" angle2="276.992" length1="0" length2="39.4593"/>
+                <pathPoint angle1="94.44" pSpline="226" angle2="274.44" length1="31.3315" length2="57.3187"/>
+                <pathPoint angle1="2.828" pSpline="254" angle2="182.828" length1="65.4653" length2="0"/>
+            </spline>
+            <spline type="simpleInteractive" point4="230" angle1="11.0159" angle2="176.295" id="275" color="black" length1="53.2682" length2="26.8703" point1="250"/>
+        </calculation>
+        <modeling/>
+        <details/>
+        <groups/>
+    </draw>
+</pattern>
diff --git a/src/app/share/collection/test/merki27.vit b/src/app/share/collection/test/merki27.vit
new file mode 100644
index 000000000..4b7527a98
--- /dev/null
+++ b/src/app/share/collection/test/merki27.vit
@@ -0,0 +1,24 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<vit>
+    <!--Measurements created with Valentina (http://www.valentina-project.org/).-->
+    <version>0.3.3</version>
+    <read-only>false</read-only>
+    <notes/>
+    <unit>cm</unit>
+    <pm_system>998</pm_system>
+    <personal>
+        <family-name/>
+        <given-name/>
+        <birth-date>1800-01-01</birth-date>
+        <gender>unknown</gender>
+        <email/>
+    </personal>
+    <body-measurements>
+        <m name="lowbust_circ" value="107"/>
+        <m name="hip_circ_with_abdomen" value="88"/>
+        <m name="waist_circ" value="60"/>
+        <m name="neck_back_to_waist_b" value="39"/>
+        <m name="waist_to_highhip_b" value="19"/>
+        <m name="arm_shoulder_tip_to_wrist" value="57"/>
+    </body-measurements>
+</vit>
diff --git a/src/app/share/collection/test/seamtest1.val b/src/app/share/collection/test/seamtest1.val
new file mode 100644
index 000000000..d36f80aba
--- /dev/null
+++ b/src/app/share/collection/test/seamtest1.val
@@ -0,0 +1,162 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<pattern>
+    <!--Pattern created with Valentina (http://www.valentina-project.org/).-->
+    <version>0.4.0</version>
+    <unit>cm</unit>
+    <author/>
+    <description/>
+    <notes/>
+    <measurements>merki27.vit</measurements>
+    <increments/>
+    <draw name="Чертеж 1">
+        <calculation>
+            <point type="single" x="0.79375" y="1.05833" id="1" name="А" mx="0.132292" my="0.264583"/>
+            <point type="endLine" typeLine="hair" id="2" name="А1" basePoint="1" mx="0.132292" lineColor="black" angle="270" my="0.264583" length="neck_back_to_waist_b"/>
+            <point type="endLine" typeLine="hair" id="3" name="А2" basePoint="2" mx="0.132292" lineColor="black" angle="0" my="0.264583" length="lowbust_circ/2+6"/>
+            <point type="alongLine" typeLine="none" id="4" name="А3" firstPoint="1" secondPoint="2" mx="0.0821985" lineColor="black" my="0.21449" length="lowbust_circ/12+13.7"/>
+            <point type="pointOfIntersection" id="5" name="А4" firstPoint="3" secondPoint="4" mx="0.132292" my="0.264583"/>
+            <line typeLine="hair" id="6" firstPoint="5" secondPoint="3" lineColor="black"/>
+            <point type="endLine" typeLine="hair" id="7" name="А5" basePoint="4" mx="0.132292" lineColor="black" angle="0" my="0.264583" length="lowbust_circ/8+7.4"/>
+            <point type="pointOfIntersection" id="8" name="А6" firstPoint="7" secondPoint="1" mx="0.132292" my="0.264583"/>
+            <line typeLine="hair" id="9" firstPoint="1" secondPoint="8" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="10" name="А7" firstPoint="1" secondPoint="4" mx="0.132292" lineColor="black" my="0.264583" length="8"/>
+            <point type="pointOfIntersection" id="11" name="А8" firstPoint="8" secondPoint="10" mx="0.132292" my="0.264583"/>
+            <line typeLine="hair" id="12" firstPoint="10" secondPoint="11" lineColor="black"/>
+            <line typeLine="hair" id="14" firstPoint="11" secondPoint="7" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="15" name="А9" firstPoint="11" secondPoint="7" mx="0.132292" lineColor="black" my="0.264583" length="(Line_А8_А5/2)+0.5"/>
+            <point type="endLine" typeLine="hair" id="16" name="А10" basePoint="5" mx="0.132292" lineColor="black" angle="90" my="0.264583" length="lowbust_circ/5+8.3+1"/>
+            <point type="endLine" typeLine="hair" id="17" name="А11" basePoint="5" mx="0.132292" lineColor="black" angle="180" my="0.264583" length="lowbust_circ/8+6.2"/>
+            <point type="pointOfIntersection" id="18" name="А12" firstPoint="17" secondPoint="16" mx="0.132292" my="0.264583"/>
+            <line typeLine="hair" id="19" firstPoint="18" secondPoint="17" lineColor="black"/>
+            <line typeLine="hair" id="20" firstPoint="18" secondPoint="16" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="21" name="А13" firstPoint="17" secondPoint="7" mx="0.132292" lineColor="black" my="0.264583" length="lowbust_circ/32"/>
+            <point type="pointOfIntersection" id="22" name="А14" firstPoint="21" secondPoint="15" mx="0.132292" my="0.264583"/>
+            <point type="alongLine" typeLine="none" id="23" name="А15" firstPoint="5" secondPoint="17" mx="0.182385" lineColor="black" my="0.264583" length="(Line_А4_А11/2)+0.7"/>
+            <line typeLine="hair" id="24" firstPoint="22" secondPoint="23" lineColor="black"/>
+            <line typeLine="hair" id="25" firstPoint="21" secondPoint="17" lineColor="black"/>
+            <line typeLine="hair" id="26" firstPoint="21" secondPoint="22" lineColor="black"/>
+            <line typeLine="hair" id="27" firstPoint="11" secondPoint="8" lineColor="black"/>
+            <line typeLine="hair" id="28" firstPoint="7" secondPoint="21" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="29" name="А16" firstPoint="7" secondPoint="21" mx="0.132292" lineColor="black" my="0.264583" length="Line_А5_А13/2"/>
+            <point type="pointOfIntersection" id="30" name="А17" firstPoint="29" secondPoint="2" mx="0.132292" my="0.264583"/>
+            <line typeLine="hair" id="31" firstPoint="29" secondPoint="30" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="32" name="А18" firstPoint="10" secondPoint="11" mx="0.132292" lineColor="black" my="0.264583" length="(Line_А7_А8/2)+1"/>
+            <point type="alongLine" typeLine="none" id="33" name="А19" firstPoint="16" secondPoint="18" mx="0.172819" lineColor="black" my="0.264583" length="lowbust_circ/24+3.4"/>
+            <point type="alongLine" typeLine="none" id="34" name="А20" firstPoint="16" secondPoint="5" mx="0.132292" lineColor="black" my="0.264583" length="Line_А10_А19+0.5"/>
+            <point type="pointOfIntersection" id="35" name="А21" firstPoint="33" secondPoint="34" mx="0.132292" my="0.264583"/>
+            <line typeLine="hair" id="38" firstPoint="35" secondPoint="16" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="39" name="А22" firstPoint="35" secondPoint="16" mx="0.132292" lineColor="black" my="0.264583" length="(Line_А21_А10/3)-0.5"/>
+            <spline point4="34" type="simpleInteractive" angle1="cos=270" angle2="sin=180" id="40" length1="4.89524" color="black" length2="4.34579" point1="33"/>
+            <line typeLine="hair" id="41" firstPoint="34" secondPoint="35" lineColor="black"/>
+            <line typeLine="hair" id="42" firstPoint="33" secondPoint="35" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="43" name="А23" firstPoint="33" secondPoint="18" mx="0.132292" lineColor="black" my="0.264583" length="8"/>
+            <point type="endLine" typeLine="none" id="44" name="А24" basePoint="43" mx="0.132292" lineColor="black" angle="270" my="0.264583" length="3.2"/>
+            <point type="lineIntersect" id="45" name="А25" p2Line1="44" p2Line2="17" p1Line1="33" p1Line2="18" mx="0.132292" my="0.264583"/>
+            <point type="alongLine" typeLine="none" id="46" name="А26" firstPoint="33" secondPoint="45" mx="0.132292" lineColor="black" my="0.264583" length="Line_А19_А25+1.8"/>
+            <point type="alongLine" typeLine="none" id="47" name="А27" firstPoint="1" secondPoint="8" mx="-0.514964" lineColor="black" my="0.552252" length="Line_А10_А19+0.2"/>
+            <point type="endLine" typeLine="hair" id="48" name="А28" basePoint="47" mx="-1.00881" lineColor="black" angle="90" my="-1.66652" length="Line_А_А27/3"/>
+            <spline point4="48" type="simpleInteractive" angle1="max=0" angle2="235.888" id="49" length1="2.42673" color="black" length2="3.03166" point1="1"/>
+            <point type="endLine" typeLine="none" id="50" name="А29" basePoint="48" mx="-0.745481" lineColor="black" angle="0" my="-1.52022" length="8"/>
+            <point type="endLine" typeLine="none" id="51" name="А30" basePoint="50" mx="0.132292" lineColor="black" angle="270" my="0.264583" length="2.6"/>
+            <point type="pointOfIntersection" id="52" name="А31" firstPoint="32" secondPoint="48" mx="-0.921036" my="-1.57874"/>
+            <point type="lineIntersect" id="53" name="А32" p2Line1="51" p2Line2="32" p1Line1="48" p1Line2="52" mx="-2.0914" my="-1.31541"/>
+            <point type="alongLine" typeLine="none" id="54" name="А33" firstPoint="53" secondPoint="51" mx="-1.82807" lineColor="black" my="0.0305105" length="1.5"/>
+            <point type="alongLine" typeLine="none" id="55" name="А34" firstPoint="54" secondPoint="51" mx="0.34558" lineColor="black" my="4.05045" length="lowbust_circ/32-0.8"/>
+            <point type="alongLine" typeLine="none" id="56" name="А35" firstPoint="48" secondPoint="51" mx="0.132292" lineColor="black" my="0.264583" length="Line_А19_А26+Line_А33_А34"/>
+            <point dartP3="55" type="trueDarts" my1="-1.63726" my2="-2.89101" id="57" mx1="-0.423631" mx2="2.30483" name1="А36" point1="58" baseLineP1="48" point2="59" name2="А37" dartP1="54" baseLineP2="56" dartP2="32"/>
+            <line typeLine="hair" id="60" firstPoint="48" secondPoint="58" lineColor="black"/>
+            <line typeLine="hair" id="61" firstPoint="32" secondPoint="58" lineColor="black"/>
+            <line typeLine="hair" id="62" firstPoint="32" secondPoint="59" lineColor="black"/>
+            <line typeLine="hair" id="63" firstPoint="59" secondPoint="56" lineColor="black"/>
+            <point type="alongLine" typeLine="none" id="64" name="А38" firstPoint="33" secondPoint="44" mx="0.132292" lineColor="black" my="0.264583" length="Line_А28_А36"/>
+            <line typeLine="hair" id="65" firstPoint="33" secondPoint="64" lineColor="black"/>
+            <line typeLine="hair" id="66" firstPoint="23" secondPoint="64" lineColor="black"/>
+            <arc type="simple" angle1="AngleLine_А15_А38" angle2="180" id="67" radius="Line_А14_А15" center="23" color="black"/>
+            <point type="cutArc" arc="67" id="68" name="А39" mx="0.132292" my="0.264583" length="lowbust_circ/12-3.2"/>
+            <point type="alongLine" typeLine="none" id="69" name="А40" firstPoint="23" secondPoint="68" mx="-1.12242" lineColor="black" my="-1.69277" length="Line_А15_А38"/>
+            <line typeLine="hair" id="70" firstPoint="23" secondPoint="69" lineColor="black"/>
+            <operation type="rotation" suffix="а1" id="71" center="23" angle="AngleLine_А15_А40-AngleLine_А15_А38">
+                <source>
+                    <item idObject="46"/>
+                </source>
+                <destination>
+                    <item idObject="72" mx="0.132292" my="0.264583"/>
+                </destination>
+            </operation>
+            <line typeLine="hair" id="73" firstPoint="69" secondPoint="72" lineColor="black"/>
+            <point type="normal" typeLine="hair" id="74" name="А41" firstPoint="56" secondPoint="59" mx="0.132292" lineColor="black" angle="0" my="0.264583" length="7"/>
+            <point type="normal" typeLine="hair" id="75" name="А42" firstPoint="72" secondPoint="69" mx="0.132292" lineColor="black" angle="180" my="0.264583" length="7"/>
+            <point type="bisector" typeLine="hair" id="77" thirdPoint="22" name="А43" firstPoint="29" secondPoint="21" mx="0.132292" lineColor="black" my="0.264583" length="Line_А5_А16/3+0.5"/>
+            <point type="bisector" typeLine="hair" id="78" thirdPoint="29" name="А44" firstPoint="15" secondPoint="7" mx="0.132292" lineColor="black" my="0.264583" length="Line_А5_А16/3+0.8"/>
+            <spline type="pathInteractive" id="100" color="black">
+                <pathPoint angle1="180.19" pSpline="29" angle2="0.189514" length1="0" length2="5.5002"/>
+                <pathPoint angle1="261.299" pSpline="22" angle2="81.2993" length1="2.57033" length2="5.3812"/>
+                <pathPoint angle1="327.914" pSpline="72" angle2="147.914" length1="8.44184" length2="13.3029"/>
+            </spline>
+            <point type="alongLine" typeLine="none" id="116" name="А45" firstPoint="11" secondPoint="15" mx="0.132292" lineColor="black" my="0.264583" length="(Line_А8_А5/2)"/>
+            <spline type="pathInteractive" id="117" color="black">
+                <pathPoint angle1="63.8459" pSpline="56" angle2="243.846" length1="0" length2="8.76616"/>
+                <pathPoint angle1="95.8866" pSpline="116" angle2="275.887" length1="1.32614" length2="2.74113"/>
+                <pathPoint angle1="180" pSpline="29" angle2="0" length1="5.03118" length2="1.36011"/>
+            </spline>
+            <operation type="moving" suffix="a1" id="149" angle="90.6703" length="40.35">
+                <source>
+                    <item idObject="117"/>
+                    <item idObject="100"/>
+                </source>
+                <destination>
+                    <item idObject="150" mx="2.14748e+09" my="2.14748e+09"/>
+                    <item idObject="151" mx="2.14748e+09" my="2.14748e+09"/>
+                </destination>
+            </operation>
+        </calculation>
+        <modeling>
+            <point type="modeling" inUse="true" id="155" idObject="4" mx="0.0821985" my="0.21449"/>
+            <point type="modeling" inUse="true" id="156" idObject="1" mx="0.132292" my="0.264583"/>
+            <spline type="modelingSpline" inUse="true" id="157" idObject="49"/>
+            <point type="modeling" inUse="true" id="158" idObject="48" mx="-1.00881" my="-1.66652"/>
+            <point type="modeling" inUse="true" id="159" idObject="58" mx="-0.423631" my="-1.63726"/>
+            <point type="modeling" inUse="true" id="160" idObject="32" mx="0.132292" my="0.264583"/>
+            <point type="modeling" inUse="true" id="161" idObject="59" mx="2.30483" my="-2.89101"/>
+            <point type="modeling" inUse="true" id="162" idObject="56" mx="0.132292" my="0.264583"/>
+            <spline type="modelingPath" inUse="true" id="163" idObject="117"/>
+            <point type="modeling" inUse="true" id="164" idObject="29" mx="0.132292" my="0.264583"/>
+        </modeling>
+        <details>
+            <detail id="165" name="" forbidFlipping="true" seamAllowance="true" mx="1.41527" inLayout="true" width="1" my="3.02812" version="2">
+                <nodes>
+                    <node before="2" type="NodePoint" after="0" idObject="155"/>
+                    <node before="0" type="NodePoint" idObject="156"/>
+                    <node type="NodeSpline" reverse="0" idObject="157"/>
+                    <node type="NodePoint" after="0" idObject="158"/>
+                    <node before="0" type="NodePoint" idObject="159"/>
+                    <node type="NodePoint" idObject="160"/>
+                    <node type="NodePoint" after="0" idObject="161"/>
+                    <node before="0" type="NodePoint" after="5" idObject="162"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="163"/>
+                    <node before="5" type="NodePoint" after="0" idObject="164"/>
+                </nodes>
+            </detail>
+        </details>
+        <groups/>
+    </draw>
+    <draw name="Чертеж 2">
+        <calculation>
+            <point type="single" x="36.3125" y="34.6144" id="141" name="Б" mx="0.132292" my="0.264583"/>
+            <point type="endLine" typeLine="hair" id="142" name="Б1" basePoint="141" mx="0.132292" lineColor="black" angle="0" my="0.264583" length="Line_А5_А16"/>
+            <point type="endLine" typeLine="hair" id="143" name="Б2" basePoint="141" mx="0.132292" lineColor="black" angle="90" my="0.264583" length="Line_А8_А5/2"/>
+            <point type="endLine" typeLine="hair" id="144" name="Б3" basePoint="143" mx="0.132292" lineColor="black" angle="90" my="0.264583" length="Line_Б_Б2"/>
+            <point type="endLine" typeLine="hair" id="145" name="Б4" basePoint="144" mx="0.132292" lineColor="black" angle="180" my="0.264583" length="Line_А18_А8"/>
+            <point type="endLine" typeLine="hair" id="146" name="Б5" basePoint="145" mx="0.132292" lineColor="black" angle="AngleLine_А18_А37" my="0.264583" length="Line_А18_А37"/>
+            <point type="endLine" typeLine="hair" id="147" name="Б6" basePoint="146" mx="0.132292" lineColor="black" angle="AngleLine_А37_А35" my="0.264583" length="Line_А37_А35"/>
+            <spline type="pathInteractive" id="148" color="black">
+                <pathPoint angle1="64.6053" pSpline="147" angle2="243.846" length1="0" length2="8.76616"/>
+                <pathPoint angle1="Angle2SplPath_А35_А16_Seg_1" pSpline="143" angle2="275.887" length1="C2LengthSplPath_А35_А16_Seg_1" length2="2.74113"/>
+                <pathPoint angle1="Angle2SplPath_А35_А16" pSpline="142" angle2="0.12" length1="4.97078" length2="1.36701"/>
+            </spline>
+        </calculation>
+        <modeling/>
+        <details/>
+        <groups/>
+    </draw>
+</pattern>
diff --git a/src/app/share/collection/test/seamtest2.val b/src/app/share/collection/test/seamtest2.val
new file mode 100644
index 000000000..751483d4e
--- /dev/null
+++ b/src/app/share/collection/test/seamtest2.val
@@ -0,0 +1,42 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<pattern>
+    <!--Pattern created with Valentina (http://www.valentina-project.org/).-->
+    <version>0.4.0</version>
+    <unit>cm</unit>
+    <author/>
+    <description/>
+    <notes/>
+    <measurements/>
+    <increments/>
+    <draw name="Pattern piece 1">
+        <calculation>
+            <point type="single" x="0.79375" y="1.05833" id="1" name="A" mx="0.132292" my="0.264583"/>
+            <point type="endLine" typeLine="hair" id="2" name="A1" basePoint="1" mx="0.132292" lineColor="black" my="0.264583" angle="0" length="10"/>
+            <point type="normal" typeLine="hair" id="3" name="A2" firstPoint="2" secondPoint="1" mx="0.132292" lineColor="black" my="0.264583" angle="0" length="5"/>
+            <point type="alongLine" typeLine="none" id="4" name="A3" firstPoint="1" secondPoint="3" mx="0.132292" lineColor="black" my="0.264583" length="CurrentLength/2"/>
+            <spline type="simpleInteractive" point4="3" angle1="236.89" angle2="209.202" id="5" color="black" length1="1.06381" length2="2.9538" point1="4"/>
+            <spline type="simpleInteractive" point4="4" angle1="241.792" angle2="241.791" id="6" color="black" length1="2.22517" length2="2.12741" point1="1"/>
+        </calculation>
+        <modeling>
+            <point type="modeling" inUse="true" id="12" idObject="1" mx="0.132292" my="0.264583"/>
+            <point type="modeling" inUse="true" id="13" idObject="2" mx="0.132292" my="0.264583"/>
+            <point type="modeling" inUse="true" id="14" idObject="3" mx="0.132292" my="0.264583"/>
+            <spline type="modelingSpline" inUse="true" id="15" idObject="5"/>
+            <point type="modeling" inUse="true" id="16" idObject="4" mx="0.132292" my="0.264583"/>
+            <spline type="modelingSpline" inUse="true" id="17" idObject="6"/>
+        </modeling>
+        <details>
+            <detail id="18" name="" forbidFlipping="true" seamAllowance="true" mx="0" inLayout="true" width="1" my="0" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="12"/>
+                    <node type="NodePoint" idObject="13"/>
+                    <node type="NodePoint" idObject="14"/>
+                    <node type="NodeSpline" reverse="1" idObject="15"/>
+                    <node before="1.01" type="NodePoint" after="1.01" idObject="16"/>
+                    <node type="NodeSpline" reverse="1" idObject="17"/>
+                </nodes>
+            </detail>
+        </details>
+        <groups/>
+    </draw>
+</pattern>
diff --git a/src/app/share/collection/test/seamtest3.val b/src/app/share/collection/test/seamtest3.val
new file mode 100644
index 000000000..2141cf046
--- /dev/null
+++ b/src/app/share/collection/test/seamtest3.val
@@ -0,0 +1,57 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<pattern>
+    <!--Pattern created with Valentina (http://www.valentina-project.org/).-->
+    <version>0.4.0</version>
+    <unit>cm</unit>
+    <author/>
+    <description/>
+    <notes/>
+    <measurements/>
+    <increments/>
+    <draw name="Pattern piece 1">
+        <calculation>
+            <point type="single" x="0.79375" y="1.05833" id="1" name="A" mx="0.132292" my="0.264583"/>
+            <point type="endLine" typeLine="hair" id="2" name="A1" basePoint="1" mx="0.132292" lineColor="black" my="0.264583" angle="0" length="10"/>
+            <point type="normal" typeLine="hair" id="3" name="A2" firstPoint="2" secondPoint="1" mx="0.132292" lineColor="black" my="0.264583" angle="0" length="5"/>
+            <point type="alongLine" typeLine="none" id="4" name="A3" firstPoint="1" secondPoint="3" mx="0.132292" lineColor="black" my="0.264583" length="CurrentLength/2"/>
+            <point type="alongLine" typeLine="none" id="5" name="A4" firstPoint="4" secondPoint="3" mx="0.132292" lineColor="black" my="0.264583" length="CurrentLength/2"/>
+            <point type="alongLine" typeLine="none" id="6" name="A5" firstPoint="1" secondPoint="4" mx="0.132292" lineColor="black" my="0.264583" length="CurrentLength/2"/>
+            <spline type="pathInteractive" id="7" color="black">
+                <pathPoint angle1="65.3764" pSpline="3" angle2="245.376" length1="0" length2="2.1538"/>
+                <pathPoint angle1="248.531" pSpline="5" angle2="68.531" length1="1.80107" length2="2.63289"/>
+                <pathPoint angle1="42.0794" pSpline="4" angle2="222.079" length1="0.714555" length2="3.76242"/>
+                <pathPoint angle1="50.1229" pSpline="6" angle2="230.123" length1="2.19303" length2="2.72501"/>
+                <pathPoint angle1="228.872" pSpline="1" angle2="48.872" length1="0.486869" length2="0"/>
+            </spline>
+        </calculation>
+        <modeling>
+            <point type="modeling" inUse="true" id="8" idObject="1" mx="0.132292" my="0.264583"/>
+            <point type="modeling" inUse="true" id="9" idObject="2" mx="0.132292" my="0.264583"/>
+            <point type="modeling" inUse="true" id="10" idObject="3" mx="0.132292" my="0.264583"/>
+            <spline type="modelingPath" inUse="true" id="11" idObject="7"/>
+            <point type="modeling" inUse="true" id="12" idObject="5" mx="0.132292" my="0.264583"/>
+            <spline type="modelingPath" inUse="true" id="13" idObject="7"/>
+            <point type="modeling" inUse="true" id="14" idObject="4" mx="0.132292" my="0.264583"/>
+            <spline type="modelingPath" inUse="true" id="15" idObject="7"/>
+            <point type="modeling" inUse="true" id="16" idObject="6" mx="0.132292" my="0.264583"/>
+            <spline type="modelingPath" inUse="true" id="17" idObject="7"/>
+        </modeling>
+        <details>
+            <detail id="18" name="" forbidFlipping="true" seamAllowance="true" mx="0" inLayout="true" width="1" my="0" version="2">
+                <nodes>
+                    <node type="NodePoint" idObject="8"/>
+                    <node type="NodePoint" idObject="9"/>
+                    <node type="NodePoint" idObject="10"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="11"/>
+                    <node before="0.5" type="NodePoint" after="0.5" idObject="12"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="13"/>
+                    <node type="NodePoint" idObject="14"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="15"/>
+                    <node before="0.2" type="NodePoint" idObject="16"/>
+                    <node type="NodeSplinePath" reverse="0" idObject="17"/>
+                </nodes>
+            </detail>
+        </details>
+        <groups/>
+    </draw>
+</pattern>
diff --git a/src/app/tape/tmainwindow.cpp b/src/app/tape/tmainwindow.cpp
index e0be0b916..d6e4f6e63 100644
--- a/src/app/tape/tmainwindow.cpp
+++ b/src/app/tape/tmainwindow.cpp
@@ -1258,10 +1258,9 @@ void TMainWindow::ImportFromPattern()
         converter.Convert();
 
         VDomDocument::ValidateXML(VPatternConverter::CurrentSchema, mPath);
-        VLitePattern *doc = new VLitePattern();
+        QScopedPointer<VLitePattern> doc(new VLitePattern());
         doc->setXMLContent(mPath);
         measurements = doc->ListMeasurements();
-        delete doc; // close a pattern
     }
     catch (VException &e)
     {
diff --git a/src/app/valentina/core/vtooloptionspropertybrowser.cpp b/src/app/valentina/core/vtooloptionspropertybrowser.cpp
index b4426a712..09e22849e 100644
--- a/src/app/valentina/core/vtooloptionspropertybrowser.cpp
+++ b/src/app/valentina/core/vtooloptionspropertybrowser.cpp
@@ -76,7 +76,7 @@ void VToolOptionsPropertyBrowser::ClearPropertyBrowser()
 void VToolOptionsPropertyBrowser::ShowItemOptions(QGraphicsItem *item)
 {
     // This check helps to find missed tools in the switch
-    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50, "Not all tools were used in switch.");
+    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51, "Not all tools were used in switch.");
 
     switch (item->type())
     {
@@ -203,7 +203,7 @@ void VToolOptionsPropertyBrowser::UpdateOptions()
     }
 
     // This check helps to find missed tools in the switch
-    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50, "Not all tools were used in switch.");
+    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51, "Not all tools were used in switch.");
 
     switch (currentItem->type())
     {
@@ -348,7 +348,7 @@ void VToolOptionsPropertyBrowser::userChangedData(VPE::VProperty *property)
     }
 
     // This check helps to find missed tools in the switch
-    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50, "Not all tools were used in switch.");
+    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51, "Not all tools were used in switch.");
 
     switch (currentItem->type())
     {
diff --git a/src/app/valentina/dialogs/dialoghistory.cpp b/src/app/valentina/dialogs/dialoghistory.cpp
index 7cd426595..a168827b8 100644
--- a/src/app/valentina/dialogs/dialoghistory.cpp
+++ b/src/app/valentina/dialogs/dialoghistory.cpp
@@ -212,7 +212,7 @@ QT_WARNING_DISABLE_GCC("-Wswitch-default")
 QString DialogHistory::Record(const VToolRecord &tool)
 {
     // This check helps to find missed tools in the switch
-    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50, "Not all tools were used in history.");
+    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51, "Not all tools were used in history.");
 
     const QDomElement domElem = doc->elementById(tool.getId());
     if (domElem.isElement() == false)
@@ -392,7 +392,7 @@ QString DialogHistory::Record(const VToolRecord &tool)
             }
             //Because "history" not only show history of pattern, but help restore current data for each pattern's
             //piece, we need add record about details and nodes, but don't show them.
-            case Tool::Detail:
+            case Tool::Piece:
             case Tool::UnionDetails:
             case Tool::NodeArc:
             case Tool::NodeElArc:
@@ -404,6 +404,7 @@ QString DialogHistory::Record(const VToolRecord &tool)
             case Tool::FlippingByLine:
             case Tool::FlippingByAxis:
             case Tool::Move:
+            case Tool::PiecePath:
                 return QString();
         }
     }
diff --git a/src/app/valentina/dialogs/vwidgetdetails.cpp b/src/app/valentina/dialogs/vwidgetdetails.cpp
index 1942ca3fc..7fe50975a 100644
--- a/src/app/valentina/dialogs/vwidgetdetails.cpp
+++ b/src/app/valentina/dialogs/vwidgetdetails.cpp
@@ -31,7 +31,7 @@
 #include "../ifc/xml/vabstractpattern.h"
 #include "../vpatterndb/vcontainer.h"
 #include "../vmisc/vabstractapplication.h"
-#include "../vtools/undocommands/toggledetailinlayout.h"
+#include "../vtools/undocommands/togglepieceinlayout.h"
 
 #include <QMenu>
 #include <QUndoStack>
@@ -45,7 +45,7 @@ VWidgetDetails::VWidgetDetails(VContainer *data, VAbstractPattern *doc, QWidget
 {
     ui->setupUi(this);
 
-    FillTable(m_data->DataDetails());
+    FillTable(m_data->DataPieces());
 
     ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);
 
@@ -62,7 +62,7 @@ VWidgetDetails::~VWidgetDetails()
 //---------------------------------------------------------------------------------------------------------------------
 void VWidgetDetails::UpdateList()
 {
-    FillTable(m_data->DataDetails());
+    FillTable(m_data->DataPieces());
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -93,16 +93,16 @@ void VWidgetDetails::InLayoutStateChanged(int row, int column)
         return;
     }
 
-    const QHash<quint32, VDetail> *allDetails = m_data->DataDetails();
+    const QHash<quint32, VPiece> *allDetails = m_data->DataPieces();
     const bool inLayout = not allDetails->value(id).IsInLayout();
 
-    ToggleDetailInLayout *togglePrint = new ToggleDetailInLayout(id, inLayout, m_data, m_doc);
-    connect(togglePrint, &ToggleDetailInLayout::UpdateList, this, &VWidgetDetails::UpdateList);
+    TogglePieceInLayout *togglePrint = new TogglePieceInLayout(id, inLayout, m_data, m_doc);
+    connect(togglePrint, &TogglePieceInLayout::UpdateList, this, &VWidgetDetails::UpdateList);
     qApp->getUndoStack()->push(togglePrint);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VWidgetDetails::FillTable(const QHash<quint32, VDetail> *details)
+void VWidgetDetails::FillTable(const QHash<quint32, VPiece> *details)
 {
     const int selectedRow = ui->tableWidget->currentRow();
     ui->tableWidget->clear();
@@ -114,7 +114,7 @@ void VWidgetDetails::FillTable(const QHash<quint32, VDetail> *details)
     while (i != details->constEnd())
     {
         ++currentRow;
-        const VDetail det = i.value();
+        const VPiece det = i.value();
 
         QTableWidgetItem *item = new QTableWidgetItem();
         item->setTextAlignment(Qt::AlignHCenter);
@@ -134,7 +134,7 @@ void VWidgetDetails::FillTable(const QHash<quint32, VDetail> *details)
 
         ui->tableWidget->setItem(currentRow, 0, item);
 
-        QString name = det.getName();
+        QString name = det.GetName();
         if (name.isEmpty())
         {
             name = tr("Unnamed");
@@ -158,7 +158,7 @@ void VWidgetDetails::FillTable(const QHash<quint32, VDetail> *details)
 //---------------------------------------------------------------------------------------------------------------------
 void VWidgetDetails::ToggleSectionDetails(bool select)
 {
-    const QHash<quint32, VDetail> *allDetails = m_data->DataDetails();
+    const QHash<quint32, VPiece> *allDetails = m_data->DataPieces();
     if (allDetails->count() == 0)
     {
         return;
@@ -172,8 +172,8 @@ void VWidgetDetails::ToggleSectionDetails(bool select)
         {
             if (not select == allDetails->value(id).IsInLayout())
             {
-                ToggleDetailInLayout *togglePrint = new ToggleDetailInLayout(id, select, m_data, m_doc);
-                connect(togglePrint, &ToggleDetailInLayout::UpdateList, this, &VWidgetDetails::UpdateList);
+                TogglePieceInLayout *togglePrint = new TogglePieceInLayout(id, select, m_data, m_doc);
+                connect(togglePrint, &TogglePieceInLayout::UpdateList, this, &VWidgetDetails::UpdateList);
                 qApp->getUndoStack()->push(togglePrint);
             }
         }
@@ -193,7 +193,7 @@ void VWidgetDetails::ShowContextMenu(const QPoint &pos)
 
     QAction *actionInvertSelection = menu->addAction(tr("Invert selection"));
 
-    const QHash<quint32, VDetail> *allDetails = m_data->DataDetails();
+    const QHash<quint32, VPiece> *allDetails = m_data->DataPieces();
     if (allDetails->count() == 0)
     {
         return;
@@ -201,7 +201,7 @@ void VWidgetDetails::ShowContextMenu(const QPoint &pos)
 
     int selectedDetails = 0;
 
-    QHash<quint32, VDetail>::const_iterator iter = allDetails->constBegin();
+    auto iter = allDetails->constBegin();
     while (iter != allDetails->constEnd())
     {
         if(iter.value().IsInLayout())
@@ -220,7 +220,6 @@ void VWidgetDetails::ShowContextMenu(const QPoint &pos)
         actionSelectAll->setDisabled(true);
     }
 
-
     QAction *selectedAction = menu->exec(ui->tableWidget->viewport()->mapToGlobal(pos));
 
     bool select;
@@ -250,8 +249,8 @@ void VWidgetDetails::ShowContextMenu(const QPoint &pos)
             {
                 select = not allDetails->value(id).IsInLayout();
 
-                ToggleDetailInLayout *togglePrint = new ToggleDetailInLayout(id, select, m_data, m_doc);
-                connect(togglePrint, &ToggleDetailInLayout::UpdateList, this, &VWidgetDetails::UpdateList);
+                TogglePieceInLayout *togglePrint = new TogglePieceInLayout(id, select, m_data, m_doc);
+                connect(togglePrint, &TogglePieceInLayout::UpdateList, this, &VWidgetDetails::UpdateList);
                 qApp->getUndoStack()->push(togglePrint);
             }
         }
diff --git a/src/app/valentina/dialogs/vwidgetdetails.h b/src/app/valentina/dialogs/vwidgetdetails.h
index 987bb74d1..f33ce9efc 100644
--- a/src/app/valentina/dialogs/vwidgetdetails.h
+++ b/src/app/valentina/dialogs/vwidgetdetails.h
@@ -33,7 +33,7 @@
 
 class VAbstractPattern;
 class VContainer;
-class VDetail;
+class VPiece;
 
 namespace Ui
 {
@@ -65,7 +65,7 @@ private:
     VAbstractPattern   *m_doc;
     VContainer         *m_data;
 
-    void FillTable(const QHash<quint32, VDetail> *details);
+    void FillTable(const QHash<quint32, VPiece> *details);
     void ToggleSectionDetails(bool select);
 };
 
diff --git a/src/app/valentina/main.cpp b/src/app/valentina/main.cpp
index 275dae711..530f40ac8 100644
--- a/src/app/valentina/main.cpp
+++ b/src/app/valentina/main.cpp
@@ -29,6 +29,7 @@
 #include "mainwindow.h"
 #include "core/vapplication.h"
 #include "../fervor/fvupdater.h"
+#include "../vpatterndb/vpiecenode.h"
 
 #include <QMessageBox> // For QT_REQUIRE_VERSION
 #include <QTimer>
@@ -53,6 +54,8 @@ int main(int argc, char *argv[])
 
     qt_qhash_seed.store(0); // Lock producing random attribute order in XML
 
+    qRegisterMetaTypeStreamOperators<VPieceNode>("VPieceNode");
+
 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
     QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // DPI support
 #endif
diff --git a/src/app/valentina/mainwindow.cpp b/src/app/valentina/mainwindow.cpp
index 8598c04ac..801df66a2 100644
--- a/src/app/valentina/mainwindow.cpp
+++ b/src/app/valentina/mainwindow.cpp
@@ -51,12 +51,14 @@
 #include "../vwidgets/vmaingraphicsscene.h"
 #include "tools/drawTools/drawtools.h"
 #include "../vtools/dialogs/tooldialogs.h"
-#include "tools/vtooldetail.h"
+#include "tools/vtoolseamallowance.h"
+#include "tools/nodeDetails/vtoolpiecepath.h"
 #include "tools/vtooluniondetails.h"
 #include "dialogs/dialogs.h"
 #include "dialogs/vwidgetgroups.h"
 #include "../vtools/undocommands/addgroup.h"
 #include "dialogs/vwidgetdetails.h"
+#include "../vpatterndb/vpiecepath.h"
 
 #include <QInputDialog>
 #include <QtDebug>
@@ -134,7 +136,7 @@ MainWindow::MainWindow(QWidget *parent)
     connect(doc, &VPattern::SetEnabledGUI, this, &MainWindow::SetEnabledGUI);
     connect(doc, &VPattern::CheckLayout, RECEIVER(this)[this]()
     {
-        if (pattern->DataDetails()->count() == 0)
+        if (pattern->DataPieces()->count() == 0)
         {
             if(not ui->actionDraw->isChecked())
             {
@@ -306,9 +308,9 @@ QPointF MainWindow::StartPositionNewPP() const
 //---------------------------------------------------------------------------------------------------------------------
 void MainWindow::InitScenes()
 {
-    sceneDraw = new VMainGraphicsScene();
+    sceneDraw = new VMainGraphicsScene(this);
     currentScene = sceneDraw;
-    qApp->setCurrentScene(currentScene);
+    qApp->setCurrentScene(&currentScene);
     connect(this, &MainWindow::EnableItemMove, sceneDraw, &VMainGraphicsScene::EnableItemMove);
     connect(this, &MainWindow::ItemsSelection, sceneDraw, &VMainGraphicsScene::ItemsSelection);
 
@@ -330,7 +332,7 @@ void MainWindow::InitScenes()
 
     connect(sceneDraw, &VMainGraphicsScene::mouseMove, this, &MainWindow::MouseMove);
 
-    sceneDetails = new VMainGraphicsScene();
+    sceneDetails = new VMainGraphicsScene(this);
     connect(this, &MainWindow::EnableItemMove, sceneDetails, &VMainGraphicsScene::EnableItemMove);
 
     connect(this, &MainWindow::EnableNodeLabelSelection, sceneDetails, &VMainGraphicsScene::ToggleNodeLabelSelection);
@@ -398,16 +400,7 @@ QSharedPointer<VMeasurements> MainWindow::OpenMeasurementFile(const QString &pat
             throw e;
         }
 
-        const QStringList mList = m->ListAll();
-        const QStringList pList = doc->ListMeasurements();
-
-        const QSet<QString> match = pList.toSet().subtract(mList.toSet());
-        if (not match.isEmpty())
-        {
-            VException e(tr("Measurement file doesn't include all required measurements."));
-            e.AddMoreInformation(tr("Please, additionaly provide: %1").arg(QStringList(match.toList()).join(", ")));
-            throw e;
-        }
+        CheckRequiredMeasurements(m.data());
 
         if (m->Type() == MeasurementsType::Standard)
         {
@@ -524,6 +517,24 @@ bool MainWindow::UpdateMeasurements(const QString &path, int size, int height)
     return true;
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+void MainWindow::CheckRequiredMeasurements(const VMeasurements *m)
+{
+    const QSet<QString> match = doc->ListMeasurements().toSet().subtract(m->ListAll().toSet());
+    if (not match.isEmpty())
+    {
+        QList<QString> list = match.toList();
+        for (int i = 0; i < list.size(); ++i)
+        {
+            list[i] = qApp->TrVars()->MToUser(list.at(i));
+        }
+
+        VException e(tr("Measurement file doesn't include all required measurements."));
+        e.AddMoreInformation(tr("Please, additionaly provide: %1").arg(QStringList(list).join(", ")));
+        throw e;
+    }
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief SetToolButton set tool and show dialog.
@@ -542,13 +553,35 @@ void MainWindow::SetToolButton(bool checked, Tool t, const QString &cursor, cons
         CancelTool();
         emit EnableItemMove(false);
         currentTool = lastUsedTool = t;
-        QPixmap pixmap(cursor);
+        auto cursorResource = cursor;
+        if (qApp->devicePixelRatio() >= 2)
+        {
+            // Try to load HiDPI versions of the cursors if availible
+            auto cursorHidpiResource = QString(cursor).replace(".png", "@2x.png");
+            if (QFileInfo(cursorResource).exists())
+            {
+                cursorResource = cursorHidpiResource;
+            }
+        }
+        QPixmap pixmap(cursorResource);
         QCursor cur(pixmap, 2, 3);
         ui->view->setCursor(cur);
         helpLabel->setText(toolTip);
         ui->view->setShowToolOptions(false);
         dialogTool = new Dialog(pattern, 0, this);
 
+        switch(t)
+        {
+            case Tool::Midpoint:
+                dialogTool->Build(t);
+                break;
+            case Tool::PiecePath:
+                dialogTool->SetPiecesList(doc->GetActivePPPieces());
+                break;
+            default:
+                break;
+        }
+
         VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(currentScene);
         SCASSERT(scene != nullptr)
 
@@ -556,6 +589,7 @@ void MainWindow::SetToolButton(bool checked, Tool t, const QString &cursor, cons
         connect(scene, &VMainGraphicsScene::SelectedObject, dialogTool.data(), &DialogTool::SelectedObject);
         connect(dialogTool.data(), &DialogTool::DialogClosed, this, closeDialogSlot);
         connect(dialogTool.data(), &DialogTool::ToolTip, this, &MainWindow::ShowToolTip);
+        connect(ui->view, &VMainGraphicsView::MouseRelease, [this](){EndVisualization(true);});
         ui->view->itemClicked(nullptr);
     }
     else
@@ -579,45 +613,13 @@ template <typename Dialog, typename Func, typename Func2>
  * @param applyDialogSlot function to handle apply in dialog.
  */
 void MainWindow::SetToolButtonWithApply(bool checked, Tool t, const QString &cursor, const QString &toolTip,
-                               Func closeDialogSlot, Func2 applyDialogSlot)
+                                        Func closeDialogSlot, Func2 applyDialogSlot)
 {
     if (checked)
     {
-        CancelTool();
-        emit EnableItemMove(false);
-        currentTool = lastUsedTool = t;
-        auto cursorResource = cursor;
-        if (qApp->devicePixelRatio() >= 2)
-        {
-            // Try to load HiDPI versions of the cursors if availible
-            auto cursorHidpiResource = QString(cursor).replace(".png", "@2x.png");
-            if (QFileInfo(cursorResource).exists())
-            {
-                cursorResource = cursorHidpiResource;
-            }
-        }
-        QPixmap pixmap(cursorResource);
-        QCursor cur(pixmap, 2, 3);
-        ui->view->setCursor(cur);
-        ui->view->setShowToolOptions(false);
-        helpLabel->setText(toolTip);
-        dialogTool = new Dialog(pattern, NULL_ID, this);
+        SetToolButton<Dialog>(checked, t, cursor, toolTip, closeDialogSlot);
 
-        if (t == Tool::Midpoint)
-        {
-            dialogTool->Build(t);
-        }
-
-        VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(currentScene);
-        SCASSERT(scene != nullptr)
-
-        connect(scene, &VMainGraphicsScene::ChoosedObject, dialogTool.data(), &DialogTool::ChosenObject);
-        connect(scene, &VMainGraphicsScene::SelectedObject, dialogTool.data(), &DialogTool::SelectedObject);
-        connect(dialogTool.data(), &DialogTool::DialogClosed, this, closeDialogSlot);
         connect(dialogTool.data(), &DialogTool::DialogApplied, this, applyDialogSlot);
-        connect(dialogTool.data(), &DialogTool::ToolTip, this, &MainWindow::ShowToolTip);
-        connect(ui->view, &VMainGraphicsView::MouseRelease, RECEIVER(this)[this](){EndVisualization(true);});
-        ui->view->itemClicked(nullptr);
     }
     else
     {
@@ -653,7 +655,7 @@ void MainWindow::ClosedDialog(int result)
  * @param result result working dialog.
  */
 template <typename DrawTool>
-void MainWindow::ClosedDialogWithApply(int result)
+void MainWindow::ClosedDialogWithApply(int result, VMainGraphicsScene *scene)
 {
     SCASSERT(not dialogTool.isNull())
     if (result == QDialog::Accepted)
@@ -661,7 +663,6 @@ void MainWindow::ClosedDialogWithApply(int result)
         // Only create tool if not already created with apply
         if (dialogTool->GetAssociatedTool() == nullptr)
         {
-            VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(currentScene);
             SCASSERT(scene != nullptr)
 
             dialogTool->SetAssociatedTool(
@@ -699,14 +700,13 @@ void MainWindow::ClosedDialogWithApply(int result)
  * @brief ApplyDialog handle apply in dialog
  */
 template <typename DrawTool>
-void MainWindow::ApplyDialog()
+void MainWindow::ApplyDialog(VMainGraphicsScene *scene)
 {
     SCASSERT(not dialogTool.isNull())
 
     // Only create tool if not already created with apply
     if (dialogTool->GetAssociatedTool() == nullptr)
     {
-        VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(currentScene);
         SCASSERT(scene != nullptr)
 
         dialogTool->SetAssociatedTool(
@@ -720,6 +720,34 @@ void MainWindow::ApplyDialog()
     }
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+template <typename DrawTool>
+void MainWindow::ClosedDrawDialogWithApply(int result)
+{
+    ClosedDialogWithApply<DrawTool>(result, sceneDraw);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+template <typename DrawTool>
+void MainWindow::ApplyDrawDialog()
+{
+    ApplyDialog<DrawTool>(sceneDraw);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+template <typename DrawTool>
+void MainWindow::ClosedDetailsDialogWithApply(int result)
+{
+    ClosedDialogWithApply<DrawTool>(result, sceneDetails);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+template <typename DrawTool>
+void MainWindow::ApplyDetailsDialog()
+{
+    ApplyDialog<DrawTool>(sceneDetails);
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief ToolEndLine handler tool endLine.
@@ -729,8 +757,8 @@ void MainWindow::ToolEndLine(bool checked)
 {
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogEndLine>(checked, Tool::EndLine, ":/cursor/endline_cursor.png", tr("Select point"),
-                                          &MainWindow::ClosedDialogWithApply<VToolEndLine>,
-                                          &MainWindow::ApplyDialog<VToolEndLine>);
+                                          &MainWindow::ClosedDrawDialogWithApply<VToolEndLine>,
+                                          &MainWindow::ApplyDrawDialog<VToolEndLine>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -742,8 +770,8 @@ void MainWindow::ToolLine(bool checked)
 {
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogLine>(checked, Tool::Line, ":/cursor/line_cursor.png", tr("Select first point"),
-                                       &MainWindow::ClosedDialogWithApply<VToolLine>,
-                                       &MainWindow::ApplyDialog<VToolLine>);
+                                       &MainWindow::ClosedDrawDialogWithApply<VToolLine>,
+                                       &MainWindow::ApplyDrawDialog<VToolLine>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -755,8 +783,8 @@ void MainWindow::ToolAlongLine(bool checked)
 {
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogAlongLine>(checked, Tool::AlongLine, ":/cursor/alongline_cursor.png",
-                                            tr("Select point"), &MainWindow::ClosedDialogWithApply<VToolAlongLine>,
-                                            &MainWindow::ApplyDialog<VToolAlongLine>);
+                                            tr("Select point"), &MainWindow::ClosedDrawDialogWithApply<VToolAlongLine>,
+                                            &MainWindow::ApplyDrawDialog<VToolAlongLine>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -765,8 +793,8 @@ void MainWindow::ToolMidpoint(bool checked)
     ToolSelectPointByRelease();
     // Reuse DialogAlongLine and VToolAlongLine but with different cursor
     SetToolButtonWithApply<DialogAlongLine>(checked, Tool::Midpoint, ":/cursor/midpoint_cursor.png",
-                                            tr("Select point"), &MainWindow::ClosedDialogWithApply<VToolAlongLine>,
-                                            &MainWindow::ApplyDialog<VToolAlongLine>);
+                                            tr("Select point"), &MainWindow::ClosedDrawDialogWithApply<VToolAlongLine>,
+                                            &MainWindow::ApplyDrawDialog<VToolAlongLine>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -779,8 +807,8 @@ void MainWindow::ToolShoulderPoint(bool checked)
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogShoulderPoint>(checked, Tool::ShoulderPoint, ":/cursor/shoulder_cursor.png",
                                                 tr("Select point"),
-                                                &MainWindow::ClosedDialogWithApply<VToolShoulderPoint>,
-                                                &MainWindow::ApplyDialog<VToolShoulderPoint>);
+                                                &MainWindow::ClosedDrawDialogWithApply<VToolShoulderPoint>,
+                                                &MainWindow::ApplyDrawDialog<VToolShoulderPoint>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -793,8 +821,8 @@ void MainWindow::ToolNormal(bool checked)
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogNormal>(checked, Tool::Normal, ":/cursor/normal_cursor.png",
                                          tr("Select first point of line"),
-                                         &MainWindow::ClosedDialogWithApply<VToolNormal>,
-                                         &MainWindow::ApplyDialog<VToolNormal>);
+                                         &MainWindow::ClosedDrawDialogWithApply<VToolNormal>,
+                                         &MainWindow::ApplyDrawDialog<VToolNormal>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -807,8 +835,8 @@ void MainWindow::ToolBisector(bool checked)
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogBisector>(checked, Tool::Bisector, ":/cursor/bisector_cursor.png",
                                            tr("Select first point of angle"),
-                                           &MainWindow::ClosedDialogWithApply<VToolBisector>,
-                                           &MainWindow::ApplyDialog<VToolBisector>);
+                                           &MainWindow::ClosedDrawDialogWithApply<VToolBisector>,
+                                           &MainWindow::ApplyDrawDialog<VToolBisector>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -821,8 +849,8 @@ void MainWindow::ToolLineIntersect(bool checked)
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogLineIntersect>(checked, Tool::LineIntersect, ":/cursor/intersect_cursor.png",
                                                 tr("Select first point of first line"),
-                                                &MainWindow::ClosedDialogWithApply<VToolLineIntersect>,
-                                                &MainWindow::ApplyDialog<VToolLineIntersect>);
+                                                &MainWindow::ClosedDrawDialogWithApply<VToolLineIntersect>,
+                                                &MainWindow::ApplyDrawDialog<VToolLineIntersect>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -835,8 +863,8 @@ void MainWindow::ToolSpline(bool checked)
     ToolSelectPointByPress();
     SetToolButtonWithApply<DialogSpline>(checked, Tool::Spline, ":/cursor/spline_cursor.png",
                                          tr("Select first point curve"),
-                                         &MainWindow::ClosedDialogWithApply<VToolSpline>,
-                                         &MainWindow::ApplyDialog<VToolSpline>);
+                                         &MainWindow::ClosedDrawDialogWithApply<VToolSpline>,
+                                         &MainWindow::ApplyDrawDialog<VToolSpline>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -845,8 +873,8 @@ void MainWindow::ToolCubicBezier(bool checked)
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogCubicBezier>(checked, Tool::CubicBezier, ":/cursor/cubic_bezier_cursor.png",
                                               tr("Select first curve point"),
-                                              &MainWindow::ClosedDialogWithApply<VToolCubicBezier>,
-                                              &MainWindow::ApplyDialog<VToolCubicBezier>);
+                                              &MainWindow::ClosedDrawDialogWithApply<VToolCubicBezier>,
+                                              &MainWindow::ApplyDrawDialog<VToolCubicBezier>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -859,8 +887,8 @@ void MainWindow::ToolCutSpline(bool checked)
     ToolSelectSpline();
     SetToolButtonWithApply<DialogCutSpline>(checked, Tool::CutSpline, ":/cursor/spline_cut_point_cursor.png",
                                             tr("Select simple curve"),
-                                            &MainWindow::ClosedDialogWithApply<VToolCutSpline>,
-                                            &MainWindow::ApplyDialog<VToolCutSpline>);
+                                            &MainWindow::ClosedDrawDialogWithApply<VToolCutSpline>,
+                                            &MainWindow::ApplyDrawDialog<VToolCutSpline>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -872,8 +900,9 @@ void MainWindow::ToolArc(bool checked)
 {
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogArc>(checked, Tool::Arc, ":/cursor/arc_cursor.png",
-                                      tr("Select point of center of arc"), &MainWindow::ClosedDialogWithApply<VToolArc>,
-                                      &MainWindow::ApplyDialog<VToolArc>);
+                                      tr("Select point of center of arc"),
+                                      &MainWindow::ClosedDrawDialogWithApply<VToolArc>,
+                                      &MainWindow::ApplyDrawDialog<VToolArc>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -885,9 +914,9 @@ void MainWindow::ToolEllipticalArc(bool checked)
 {
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogEllipticalArc>(checked, Tool::EllipticalArc, ":/cursor/el_arc_cursor.png",
-                                      tr("Select point of center of elliptical arc"),
-                                      &MainWindow::ClosedDialogWithApply<VToolEllipticalArc>,
-                                      &MainWindow::ApplyDialog<VToolEllipticalArc>);
+                                                tr("Select point of center of elliptical arc"),
+                                                &MainWindow::ClosedDrawDialogWithApply<VToolEllipticalArc>,
+                                                &MainWindow::ApplyDrawDialog<VToolEllipticalArc>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -900,8 +929,8 @@ void MainWindow::ToolSplinePath(bool checked)
     ToolSelectPointByPress();
     SetToolButtonWithApply<DialogSplinePath>(checked, Tool::SplinePath, ":/cursor/splinepath_cursor.png",
                                              tr("Select point of curve path"),
-                                             &MainWindow::ClosedDialogWithApply<VToolSplinePath>,
-                                             &MainWindow::ApplyDialog<VToolSplinePath>);
+                                             &MainWindow::ClosedDrawDialogWithApply<VToolSplinePath>,
+                                             &MainWindow::ApplyDrawDialog<VToolSplinePath>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -911,8 +940,8 @@ void MainWindow::ToolCubicBezierPath(bool checked)
     SetToolButtonWithApply<DialogCubicBezierPath>(checked, Tool::CubicBezierPath,
                                                   ":/cursor/cubic_bezier_path_cursor.png",
                                                   tr("Select point of cubic bezier path"),
-                                                  &MainWindow::ClosedDialogWithApply<VToolCubicBezierPath>,
-                                                  &MainWindow::ApplyDialog<VToolCubicBezierPath>);
+                                                  &MainWindow::ClosedDrawDialogWithApply<VToolCubicBezierPath>,
+                                                  &MainWindow::ApplyDrawDialog<VToolCubicBezierPath>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -925,8 +954,8 @@ void MainWindow::ToolCutSplinePath(bool checked)
     ToolSelectSplinePath();
     SetToolButtonWithApply<DialogCutSplinePath>(checked, Tool::CutSplinePath,
                                                 ":/cursor/splinepath_cut_point_cursor.png", tr("Select curve path"),
-                                                &MainWindow::ClosedDialogWithApply<VToolCutSplinePath>,
-                                                &MainWindow::ApplyDialog<VToolCutSplinePath>);
+                                                &MainWindow::ClosedDrawDialogWithApply<VToolCutSplinePath>,
+                                                &MainWindow::ApplyDrawDialog<VToolCutSplinePath>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -939,8 +968,8 @@ void MainWindow::ToolPointOfContact(bool checked)
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogPointOfContact>(checked, Tool::PointOfContact, ":/cursor/pointcontact_cursor.png",
                                                  tr("Select first point of line"),
-                                                 &MainWindow::ClosedDialogWithApply<VToolPointOfContact>,
-                                                 &MainWindow::ApplyDialog<VToolPointOfContact>);
+                                                 &MainWindow::ClosedDrawDialogWithApply<VToolPointOfContact>,
+                                                 &MainWindow::ApplyDrawDialog<VToolPointOfContact>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -951,23 +980,19 @@ void MainWindow::ToolPointOfContact(bool checked)
 void MainWindow::ToolDetail(bool checked)
 {
     ToolSelectAllDrawObjects();
-    SetToolButton<DialogDetail>(checked, Tool::Detail, "://cursor/new_detail_cursor.png",
-                                tr("Select points, arcs, curves clockwise."), &MainWindow::ClosedDialogDetail);
+    SetToolButtonWithApply<DialogSeamAllowance>(checked, Tool::Piece, "://cursor/new_detail_cursor.png",
+                                                tr("Select main path objects clockwise."),
+                                                &MainWindow::ClosedDetailsDialogWithApply<VToolSeamAllowance>,
+                                                &MainWindow::ApplyDetailsDialog<VToolSeamAllowance>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief ClosedDialogDetail actions after closing DialogDetail.
- * @param result result of dialog working.
- */
-void MainWindow::ClosedDialogDetail(int result)
+void MainWindow::ToolPiecePath(bool checked)
 {
-    if (result == QDialog::Accepted)
-    {
-        VToolDetail::Create(dialogTool, sceneDetails, doc, pattern);
-    }
-    ArrowTool();
-    doc->LiteParseTree(Document::LiteParse);
+    ToolSelectAllDrawObjects();
+    SetToolButton<DialogPiecePath>(checked, Tool::PiecePath, "://cursor/path_cursor.png",
+                                   tr("Select path objects, <b>Shift</b> - reverse direction curve"),
+                                   &MainWindow::ClosedDialogPiecePath);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -979,8 +1004,8 @@ void MainWindow::ToolHeight(bool checked)
 {
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogHeight>(checked, Tool::Height, ":/cursor/height_cursor.png", tr("Select base point"),
-                                         &MainWindow::ClosedDialogWithApply<VToolHeight>,
-                                         &MainWindow::ApplyDialog<VToolHeight>);
+                                         &MainWindow::ClosedDrawDialogWithApply<VToolHeight>,
+                                         &MainWindow::ApplyDrawDialog<VToolHeight>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -993,8 +1018,8 @@ void MainWindow::ToolTriangle(bool checked)
     ToolSelectPointByRelease();
     SetToolButtonWithApply<DialogTriangle>(checked, Tool::Triangle, ":/cursor/triangle_cursor.png",
                                            tr("Select first point of axis"),
-                                           &MainWindow::ClosedDialogWithApply<VToolTriangle>,
-                                           &MainWindow::ApplyDialog<VToolTriangle>);
+                                           &MainWindow::ClosedDrawDialogWithApply<VToolTriangle>,
+                                           &MainWindow::ApplyDrawDialog<VToolTriangle>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1008,8 +1033,8 @@ void MainWindow::ToolPointOfIntersection(bool checked)
     SetToolButtonWithApply<DialogPointOfIntersection>(checked, Tool::PointOfIntersection,
                                                       ":/cursor/pointofintersect_cursor.png",
                                                       tr("Select point for X value (vertical)"),
-                                                      &MainWindow::ClosedDialogWithApply<VToolPointOfIntersection>,
-                                                      &MainWindow::ApplyDialog<VToolPointOfIntersection>);
+                                                      &MainWindow::ClosedDrawDialogWithApply<VToolPointOfIntersection>,
+                                                      &MainWindow::ApplyDrawDialog<VToolPointOfIntersection>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1051,8 +1076,8 @@ void MainWindow::ToolRotation(bool checked)
     SetToolButtonWithApply<DialogRotation>(checked, Tool::Rotation,
                                            ":/cursor/rotation_cursor.png",
                                            tr("Select one or more objects, <b>Enter</b> - confirm selection"),
-                                           &MainWindow::ClosedDialogWithApply<VToolRotation>,
-                                           &MainWindow::ApplyDialog<VToolRotation>);
+                                           &MainWindow::ClosedDrawDialogWithApply<VToolRotation>,
+                                           &MainWindow::ApplyDrawDialog<VToolRotation>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1062,8 +1087,8 @@ void MainWindow::ToolFlippingByLine(bool checked)
     SetToolButtonWithApply<DialogFlippingByLine>(checked, Tool::FlippingByLine,
                                            ":/cursor/flipping_line_cursor.png",
                                            tr("Select one or more objects, <b>Enter</b> - confirm selection"),
-                                           &MainWindow::ClosedDialogWithApply<VToolFlippingByLine>,
-                                           &MainWindow::ApplyDialog<VToolFlippingByLine>);
+                                           &MainWindow::ClosedDrawDialogWithApply<VToolFlippingByLine>,
+                                           &MainWindow::ApplyDrawDialog<VToolFlippingByLine>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1073,8 +1098,8 @@ void MainWindow::ToolFlippingByAxis(bool checked)
     SetToolButtonWithApply<DialogFlippingByAxis>(checked, Tool::FlippingByAxis,
                                            ":/cursor/flipping_axis_cursor.png",
                                            tr("Select one or more objects, <b>Enter</b> - confirm selection"),
-                                           &MainWindow::ClosedDialogWithApply<VToolFlippingByAxis>,
-                                                 &MainWindow::ApplyDialog<VToolFlippingByAxis>);
+                                           &MainWindow::ClosedDrawDialogWithApply<VToolFlippingByAxis>,
+                                                 &MainWindow::ApplyDrawDialog<VToolFlippingByAxis>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1084,8 +1109,8 @@ void MainWindow::ToolMove(bool checked)
     SetToolButtonWithApply<DialogMove>(checked, Tool::Move,
                                          ":/cursor/move_cursor.png",
                                          tr("Select one or more objects, <b>Enter</b> - confirm selection"),
-                                         &MainWindow::ClosedDialogWithApply<VToolMove>,
-                                         &MainWindow::ApplyDialog<VToolMove>);
+                                         &MainWindow::ClosedDrawDialogWithApply<VToolMove>,
+                                         &MainWindow::ApplyDrawDialog<VToolMove>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1107,6 +1132,20 @@ void MainWindow::ClosedDialogGroup(int result)
     ArrowTool();
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+void MainWindow::ClosedDialogPiecePath(int result)
+{
+    SCASSERT(dialogTool != nullptr);
+    if (result == QDialog::Accepted)
+    {
+        DialogPiecePath *dialog = qobject_cast<DialogPiecePath*>(dialogTool);
+        SCASSERT(dialog != nullptr);
+        VToolPiecePath::Create(dialogTool, sceneDetails, doc, pattern);
+    }
+    ArrowTool();
+    doc->LiteParseTree(Document::LiteParse);
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief ToolCutArc handler tool cutArc.
@@ -1116,8 +1155,8 @@ void MainWindow::ToolCutArc(bool checked)
 {
     ToolSelectArc();
     SetToolButtonWithApply<DialogCutArc>(checked, Tool::CutArc, ":/cursor/arc_cut_cursor.png",
-                                         tr("Select arc"), &MainWindow::ClosedDialogWithApply<VToolCutArc>,
-                                         &MainWindow::ApplyDialog<VToolCutArc>);
+                                         tr("Select arc"), &MainWindow::ClosedDrawDialogWithApply<VToolCutArc>,
+                                         &MainWindow::ApplyDrawDialog<VToolCutArc>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1127,8 +1166,8 @@ void MainWindow::ToolLineIntersectAxis(bool checked)
     SetToolButtonWithApply<DialogLineIntersectAxis>(checked, Tool::LineIntersectAxis,
                                                     ":/cursor/line_intersect_axis_cursor.png",
                                                     tr("Select first point of line"),
-                                                    &MainWindow::ClosedDialogWithApply<VToolLineIntersectAxis>,
-                                                    &MainWindow::ApplyDialog<VToolLineIntersectAxis>);
+                                                    &MainWindow::ClosedDrawDialogWithApply<VToolLineIntersectAxis>,
+                                                    &MainWindow::ApplyDrawDialog<VToolLineIntersectAxis>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1138,8 +1177,8 @@ void MainWindow::ToolCurveIntersectAxis(bool checked)
     SetToolButtonWithApply<DialogCurveIntersectAxis>(checked, Tool::CurveIntersectAxis,
                                                      ":/cursor/curve_intersect_axis_cursor.png",
                                                      tr("Select curve"),
-                                                     &MainWindow::ClosedDialogWithApply<VToolCurveIntersectAxis>,
-                                                     &MainWindow::ApplyDialog<VToolCurveIntersectAxis>);
+                                                     &MainWindow::ClosedDrawDialogWithApply<VToolCurveIntersectAxis>,
+                                                     &MainWindow::ApplyDrawDialog<VToolCurveIntersectAxis>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1150,8 +1189,8 @@ void MainWindow::ToolArcIntersectAxis(bool checked)
     SetToolButtonWithApply<DialogCurveIntersectAxis>(checked, Tool::ArcIntersectAxis,
                                                      ":/cursor/arc_intersect_axis_cursor.png",
                                                      tr("Select arc"),
-                                                     &MainWindow::ClosedDialogWithApply<VToolCurveIntersectAxis>,
-                                                     &MainWindow::ApplyDialog<VToolCurveIntersectAxis>);
+                                                     &MainWindow::ClosedDrawDialogWithApply<VToolCurveIntersectAxis>,
+                                                     &MainWindow::ApplyDrawDialog<VToolCurveIntersectAxis>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1161,8 +1200,8 @@ void MainWindow::ToolPointOfIntersectionArcs(bool checked)
     SetToolButtonWithApply<DialogPointOfIntersectionArcs>(checked, Tool::PointOfIntersectionArcs,
                                                           "://cursor/point_of_intersection_arcs.png",
                                                           tr("Select first an arc"),
-                                                       &MainWindow::ClosedDialogWithApply<VToolPointOfIntersectionArcs>,
-                                                          &MainWindow::ApplyDialog<VToolPointOfIntersectionArcs>);
+                                                       &MainWindow::ClosedDrawDialogWithApply<VToolPointOfIntersectionArcs>,
+                                                          &MainWindow::ApplyDrawDialog<VToolPointOfIntersectionArcs>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1172,8 +1211,8 @@ void MainWindow::ToolPointOfIntersectionCircles(bool checked)
     SetToolButtonWithApply<DialogPointOfIntersectionCircles>(checked, Tool::PointOfIntersectionCircles,
                                                              "://cursor/point_of_intersection_circles.png",
                                                              tr("Select first circle center"),
-                                                    &MainWindow::ClosedDialogWithApply<VToolPointOfIntersectionCircles>,
-                                                             &MainWindow::ApplyDialog<VToolPointOfIntersectionCircles>);
+                                                    &MainWindow::ClosedDrawDialogWithApply<VToolPointOfIntersectionCircles>,
+                                                             &MainWindow::ApplyDrawDialog<VToolPointOfIntersectionCircles>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1183,8 +1222,8 @@ void MainWindow::ToolPointOfIntersectionCurves(bool checked)
     SetToolButtonWithApply<DialogPointOfIntersectionCurves>(checked, Tool::PointOfIntersectionCurves,
                                                              "://cursor/intersection_curves_cursor.png",
                                                              tr("Select first curve"),
-                                                    &MainWindow::ClosedDialogWithApply<VToolPointOfIntersectionCurves>,
-                                                             &MainWindow::ApplyDialog<VToolPointOfIntersectionCurves>);
+                                                    &MainWindow::ClosedDrawDialogWithApply<VToolPointOfIntersectionCurves>,
+                                                             &MainWindow::ApplyDrawDialog<VToolPointOfIntersectionCurves>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1194,8 +1233,8 @@ void MainWindow::ToolPointFromCircleAndTangent(bool checked)
     SetToolButtonWithApply<DialogPointFromCircleAndTangent>(checked, Tool::PointFromCircleAndTangent,
                                                             "://cursor/point_from_circle_and_tangent_cursor.png",
                                                             tr("Select point on tangent"),
-                                                    &MainWindow::ClosedDialogWithApply<VToolPointFromCircleAndTangent>,
-                                                            &MainWindow::ApplyDialog<VToolPointFromCircleAndTangent>);
+                                                    &MainWindow::ClosedDrawDialogWithApply<VToolPointFromCircleAndTangent>,
+                                                            &MainWindow::ApplyDrawDialog<VToolPointFromCircleAndTangent>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1205,8 +1244,8 @@ void MainWindow::ToolPointFromArcAndTangent(bool checked)
     SetToolButtonWithApply<DialogPointFromArcAndTangent>(checked, Tool::PointFromArcAndTangent,
                                                          "://cursor/point_from_arc_and_tangent_cursor.png",
                                                          tr("Select point on tangent"),
-                                                        &MainWindow::ClosedDialogWithApply<VToolPointFromArcAndTangent>,
-                                                         &MainWindow::ApplyDialog<VToolPointFromArcAndTangent>);
+                                                        &MainWindow::ClosedDrawDialogWithApply<VToolPointFromArcAndTangent>,
+                                                         &MainWindow::ApplyDrawDialog<VToolPointFromArcAndTangent>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1216,8 +1255,8 @@ void MainWindow::ToolArcWithLength(bool checked)
     SetToolButtonWithApply<DialogArcWithLength>(checked, Tool::ArcWithLength,
                                                 "://cursor/arc_with_length_cursor.png",
                                                 tr("Select point of the center of the arc"),
-                                                &MainWindow::ClosedDialogWithApply<VToolArcWithLength>,
-                                                &MainWindow::ApplyDialog<VToolArcWithLength>);
+                                                &MainWindow::ClosedDrawDialogWithApply<VToolArcWithLength>,
+                                                &MainWindow::ApplyDrawDialog<VToolArcWithLength>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1227,8 +1266,8 @@ void MainWindow::ToolTrueDarts(bool checked)
     SetToolButtonWithApply<DialogTrueDarts>(checked, Tool::TrueDarts,
                                                 "://cursor/true_darts_cursor.png",
                                                 tr("Select the first base line point"),
-                                                &MainWindow::ClosedDialogWithApply<VToolTrueDarts>,
-                                            &MainWindow::ApplyDialog<VToolTrueDarts>);
+                                                &MainWindow::ClosedDrawDialogWithApply<VToolTrueDarts>,
+                                            &MainWindow::ApplyDrawDialog<VToolTrueDarts>);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -1674,6 +1713,7 @@ void MainWindow::ToolBarDraws()
     });
 }
 
+//---------------------------------------------------------------------------------------------------------------------
 void MainWindow::ToolBarTools()
 {
     /*First we will try use Standard Shortcuts from Qt, but because keypad "-" and "+" not the same keys like in main
@@ -1721,6 +1761,9 @@ void MainWindow::InitToolButtons()
         connect(pointer, &QToolButton::clicked, this, &MainWindow::ArrowTool);
     }
 
+    // This check helps to find missed tools
+    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51, "Check if all tools were connected.");
+
     connect(ui->toolButtonEndLine, &QToolButton::clicked, this, &MainWindow::ToolEndLine);
     connect(ui->toolButtonLine, &QToolButton::clicked, this, &MainWindow::ToolLine);
     connect(ui->toolButtonAlongLine, &QToolButton::clicked, this, &MainWindow::ToolAlongLine);
@@ -1735,6 +1778,7 @@ void MainWindow::InitToolButtons()
     connect(ui->toolButtonCubicBezierPath, &QToolButton::clicked, this, &MainWindow::ToolCubicBezierPath);
     connect(ui->toolButtonPointOfContact, &QToolButton::clicked, this, &MainWindow::ToolPointOfContact);
     connect(ui->toolButtonNewDetail, &QToolButton::clicked, this, &MainWindow::ToolDetail);
+    connect(ui->toolButtonPiecePath, &QToolButton::clicked, this, &MainWindow::ToolPiecePath);
     connect(ui->toolButtonHeight, &QToolButton::clicked, this, &MainWindow::ToolHeight);
     connect(ui->toolButtonTriangle, &QToolButton::clicked, this, &MainWindow::ToolTriangle);
     connect(ui->toolButtonPointOfIntersection, &QToolButton::clicked, this, &MainWindow::ToolPointOfIntersection);
@@ -1791,7 +1835,7 @@ QT_WARNING_DISABLE_GCC("-Wswitch-default")
 void MainWindow::CancelTool()
 {
     // This check helps to find missed tools in the switch
-    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50, "Not all tools were handled.");
+    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51, "Not all tools were handled.");
 
     qCDebug(vMainWindow, "Canceling tool.");
     delete dialogTool;
@@ -1875,9 +1919,12 @@ void MainWindow::CancelTool()
         case Tool::PointOfContact:
             ui->toolButtonPointOfContact->setChecked(false);
             break;
-        case Tool::Detail:
+        case Tool::Piece:
             ui->toolButtonNewDetail->setChecked(false);
             break;
+        case Tool::PiecePath:
+            ui->toolButtonPiecePath->setChecked(false);
+            break;
         case Tool::Height:
             ui->toolButtonHeight->setChecked(false);
             break;
@@ -2146,7 +2193,7 @@ void MainWindow::ActionDetails(bool checked)
 
         if(not qApp->getOpeningPattern())
         {
-            if (pattern->DataDetails()->count() == 0)
+            if (pattern->DataPieces()->count() == 0)
             {
                 QMessageBox::information(this, tr("Detail mode"), tr("You can't use now the Detail mode. "
                                                                      "Please, create at least one workpiece."),
@@ -2221,10 +2268,10 @@ void MainWindow::ActionLayout(bool checked)
         ui->actionDetails->setChecked(false);
         ui->actionLayout->setChecked(true);
 
-        QHash<quint32, VDetail> details;
+        QHash<quint32, VPiece> details;
         if(not qApp->getOpeningPattern())
         {
-            const QHash<quint32, VDetail> *allDetails = pattern->DataDetails();
+            const QHash<quint32, VPiece> *allDetails = pattern->DataPieces();
             if (allDetails->count() == 0)
             {
                 QMessageBox::information(this, tr("Layout mode"), tr("You can't use now the Layout mode. "
@@ -2235,7 +2282,7 @@ void MainWindow::ActionLayout(bool checked)
             }
             else
             {
-                QHash<quint32, VDetail>::const_iterator i = allDetails->constBegin();
+                QHash<quint32, VPiece>::const_iterator i = allDetails->constBegin();
                 while (i != allDetails->constEnd())
                 {
                     if (i.value().IsInLayout())
@@ -2656,6 +2703,9 @@ void MainWindow::FullParseFile()
     patternReadOnly = doc->IsReadOnly();
     SetEnableWidgets(true);
     detailsWidget->UpdateList();
+
+    VMainGraphicsView::NewSceneRect(sceneDraw, qApp->getSceneView());
+    VMainGraphicsView::NewSceneRect(sceneDetails, qApp->getSceneView());
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -2992,7 +3042,7 @@ void MainWindow::SetEnableTool(bool enable)
     }
 
     // This check helps to find missed tools
-    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50, "Not all tools were handled.");
+    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51, "Not all tools were handled.");
 
     //Drawing Tools
     ui->toolButtonEndLine->setEnabled(drawTools);
@@ -3009,6 +3059,7 @@ void MainWindow::SetEnableTool(bool enable)
     ui->toolButtonCubicBezierPath->setEnabled(drawTools);
     ui->toolButtonPointOfContact->setEnabled(drawTools);
     ui->toolButtonNewDetail->setEnabled(drawTools);
+    ui->toolButtonPiecePath->setEnabled(drawTools);
     ui->toolButtonHeight->setEnabled(drawTools);
     ui->toolButtonTriangle->setEnabled(drawTools);
     ui->toolButtonPointOfIntersection->setEnabled(drawTools);
@@ -3313,7 +3364,7 @@ QT_WARNING_DISABLE_GCC("-Wswitch-default")
 void MainWindow::LastUsedTool()
 {
     // This check helps to find missed tools in the switch
-    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50, "Not all tools were handled.");
+    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51, "Not all tools were handled.");
 
     if (currentTool == lastUsedTool)
     {
@@ -3400,10 +3451,14 @@ void MainWindow::LastUsedTool()
             ui->toolButtonPointOfContact->setChecked(true);
             ToolPointOfContact(true);
             break;
-        case Tool::Detail:
+        case Tool::Piece:
             ui->toolButtonNewDetail->setChecked(true);
             ToolDetail(true);
             break;
+        case Tool::PiecePath:
+            ui->toolButtonPiecePath->setChecked(true);
+            ToolPiecePath(true);
+            break;
         case Tool::Height:
             ui->toolButtonHeight->setChecked(true);
             ToolHeight(true);
@@ -3785,8 +3840,6 @@ MainWindow::~MainWindow()
     CleanLayout();
 
     delete doc;
-    delete sceneDetails;
-    delete sceneDraw;
     delete ui;
 }
 
@@ -4232,7 +4285,7 @@ QString MainWindow::CheckPathToMeasurements(const QString &patternPath, const QS
                 }
                 else
                 {
-                    VMeasurements *m = new VMeasurements(pattern);
+                    QScopedPointer<VMeasurements> m(new VMeasurements(pattern));
                     m->setXMLContent(mPath);
 
                     patternType = m->Type();
@@ -4266,19 +4319,7 @@ QString MainWindow::CheckPathToMeasurements(const QString &patternPath, const QS
                         throw e;
                     }
 
-                    const QStringList mList = m->ListAll();
-                    const QStringList pList = doc->ListMeasurements();
-
-                    delete m;
-
-                    const QSet<QString> match = pList.toSet().subtract(mList.toSet());
-                    if (not match.isEmpty())
-                    {
-                        VException e(tr("Measurement file doesn't include all required measurements."));
-                        e.AddMoreInformation(tr("Please, additionaly provide: %1")
-                                             .arg(QStringList(match.toList()).join(", ")));
-                        throw e;
-                    }
+                    CheckRequiredMeasurements(m.data());
 
                     doc->SetPath(RelativeMPath(patternPath, mPath));
                     PatternChangesWereSaved(false);
@@ -4332,7 +4373,7 @@ void MainWindow::ZoomFirstShow()
      * pattern will be moved. Looks very ugly. It is best solution that i have now.
      */
 
-    if (pattern->DataDetails()->size() > 0)
+    if (pattern->DataPieces()->size() > 0)
     {
         ActionDetails(true);
         ui->view->ZoomFitBest();
@@ -4347,7 +4388,7 @@ void MainWindow::ZoomFirstShow()
     VMainGraphicsView::NewSceneRect(sceneDraw, ui->view);
     VMainGraphicsView::NewSceneRect(sceneDetails, ui->view);
 
-    if (pattern->DataDetails()->size() > 0)
+    if (pattern->DataPieces()->size() > 0)
     {
         ActionDetails(true);
         ui->view->ZoomFitBest();
@@ -4364,7 +4405,7 @@ void MainWindow::DoExport(const VCommandLinePtr &expParams)
 {
     auto settings = expParams->DefaultGenerator();
 
-    const QHash<quint32, VDetail> *details = pattern->DataDetails();
+    const QHash<quint32, VPiece> *details = pattern->DataPieces();
     if(not qApp->getOpeningPattern())
     {
         if (details->count() == 0)
diff --git a/src/app/valentina/mainwindow.h b/src/app/valentina/mainwindow.h
index d7c939a77..61e5999f1 100644
--- a/src/app/valentina/mainwindow.h
+++ b/src/app/valentina/mainwindow.h
@@ -137,6 +137,7 @@ private slots:
     void ToolCutSplinePath(bool checked);
     void ToolPointOfContact(bool checked);
     void ToolDetail(bool checked);
+    void ToolPiecePath(bool checked);
     void ToolHeight(bool checked);
     void ToolTriangle(bool checked);
     void ToolPointOfIntersection(bool checked);
@@ -167,9 +168,9 @@ private slots:
     bool Save();
     void Open();
 
-    void ClosedDialogDetail(int result);
     void ClosedDialogUnionDetails(int result);
     void ClosedDialogGroup(int result);
+    void ClosedDialogPiecePath(int result);
 
     void LoadIndividual();
     void LoadStandard();
@@ -285,10 +286,20 @@ private:
                                               Func closeDialogSlot, Func2 applyDialogSlot);
     template <typename DrawTool>
     void               ClosedDialog(int result);
+
     template <typename DrawTool>
-    void               ClosedDialogWithApply(int result);
+    void ClosedDialogWithApply(int result, VMainGraphicsScene *scene);
     template <typename DrawTool>
-    void               ApplyDialog();
+    void ApplyDialog(VMainGraphicsScene *scene);
+    template <typename DrawTool>
+    void ClosedDrawDialogWithApply(int result);
+    template <typename DrawTool>
+    void ApplyDrawDialog();
+    template <typename DrawTool>
+    void ClosedDetailsDialogWithApply(int result);
+    template <typename DrawTool>
+    void ApplyDetailsDialog();
+
     bool               SavePattern(const QString &curFile, QString &error);
     void               AutoSavePattern();
     void               setCurrentFile(const QString &fileName);
@@ -328,6 +339,7 @@ private:
     QSharedPointer<VMeasurements> OpenMeasurementFile(const QString &path);
     bool               LoadMeasurements(const QString &path);
     bool               UpdateMeasurements(const QString &path, int size, int height);
+    void               CheckRequiredMeasurements(const VMeasurements *m);
 
     void               ReopenFilesAfterCrash(QStringList &args);
     void               DoExport(const VCommandLinePtr& expParams);
diff --git a/src/app/valentina/mainwindow.ui b/src/app/valentina/mainwindow.ui
index fe04e4b67..34f5c066a 100644
--- a/src/app/valentina/mainwindow.ui
+++ b/src/app/valentina/mainwindow.ui
@@ -48,14 +48,14 @@
        <string>Tools</string>
       </property>
       <property name="currentIndex">
-       <number>7</number>
+       <number>5</number>
       </property>
       <widget class="QWidget" name="page">
        <property name="geometry">
         <rect>
          <x>0</x>
          <y>0</y>
-         <width>100</width>
+         <width>117</width>
          <height>358</height>
         </rect>
        </property>
@@ -427,7 +427,7 @@
         <rect>
          <x>0</x>
          <y>0</y>
-         <width>100</width>
+         <width>130</width>
          <height>110</height>
         </rect>
        </property>
@@ -536,7 +536,7 @@
         <rect>
          <x>0</x>
          <y>0</y>
-         <width>100</width>
+         <width>130</width>
          <height>248</height>
         </rect>
        </property>
@@ -798,7 +798,7 @@
         <rect>
          <x>0</x>
          <y>0</y>
-         <width>100</width>
+         <width>130</width>
          <height>248</height>
         </rect>
        </property>
@@ -1063,7 +1063,7 @@
         <rect>
          <x>0</x>
          <y>0</y>
-         <width>100</width>
+         <width>130</width>
          <height>58</height>
         </rect>
        </property>
@@ -1143,8 +1143,8 @@
         <rect>
          <x>0</x>
          <y>0</y>
-         <width>100</width>
-         <height>196</height>
+         <width>130</width>
+         <height>356</height>
         </rect>
        </property>
        <attribute name="icon">
@@ -1321,8 +1321,8 @@
         <rect>
          <x>0</x>
          <y>0</y>
-         <width>100</width>
-         <height>104</height>
+         <width>130</width>
+         <height>150</height>
         </rect>
        </property>
        <property name="sizePolicy">
@@ -1423,6 +1423,32 @@
           </property>
          </widget>
         </item>
+        <item row="2" column="0">
+         <widget class="QToolButton" name="toolButtonPiecePath">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="toolTip">
+           <string>Piece path tool</string>
+          </property>
+          <property name="text">
+           <string notr="true">...</string>
+          </property>
+          <property name="icon">
+           <iconset resource="share/resources/toolicon.qrc">
+            <normaloff>:/toolicon/32x32/path.png</normaloff>:/toolicon/32x32/path.png</iconset>
+          </property>
+          <property name="iconSize">
+           <size>
+            <width>32</width>
+            <height>32</height>
+           </size>
+          </property>
+          <property name="checkable">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
        </layout>
       </widget>
       <widget class="QWidget" name="layoutPage">
@@ -1431,7 +1457,7 @@
          <x>0</x>
          <y>0</y>
          <width>130</width>
-         <height>326</height>
+         <height>356</height>
         </rect>
        </property>
        <attribute name="icon">
@@ -2548,8 +2574,8 @@
   </customwidget>
  </customwidgets>
  <resources>
-  <include location="share/resources/toolicon.qrc"/>
   <include location="../../libs/vmisc/share/resources/icon.qrc"/>
+  <include location="share/resources/toolicon.qrc"/>
  </resources>
  <connections/>
 </ui>
diff --git a/src/app/valentina/mainwindowsnogui.cpp b/src/app/valentina/mainwindowsnogui.cpp
index b2c369fd4..9ba89c342 100644
--- a/src/app/valentina/mainwindowsnogui.cpp
+++ b/src/app/valentina/mainwindowsnogui.cpp
@@ -60,7 +60,7 @@
 
 //---------------------------------------------------------------------------------------------------------------------
 MainWindowsNoGUI::MainWindowsNoGUI(QWidget *parent)
-    : VAbstractMainWindow(parent), listDetails(QVector<VLayoutDetail>()), currentScene(nullptr), tempSceneLayout(nullptr),
+    : VAbstractMainWindow(parent), listDetails(QVector<VLayoutPiece>()), currentScene(nullptr), tempSceneLayout(nullptr),
       pattern(new VContainer(qApp->TrVars(), qApp->patternUnitP())), doc(nullptr), papers(QList<QGraphicsItem *>()),
       shadows(QList<QGraphicsItem *>()), scenes(QList<QGraphicsScene *>()), details(QList<QList<QGraphicsItem *> >()),
       undoAction(nullptr), redoAction(nullptr), actionDockWidgetToolOptions(nullptr), actionDockWidgetGroups(nullptr),
@@ -463,7 +463,7 @@ void MainWindowsNoGUI::PrintTiled()
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void MainWindowsNoGUI::PrepareDetailsForLayout(const QHash<quint32, VDetail> *details)
+void MainWindowsNoGUI::PrepareDetailsForLayout(const QHash<quint32, VPiece> *details)
 {
     listDetails.clear();
     SCASSERT(details != nullptr)
@@ -472,40 +472,10 @@ void MainWindowsNoGUI::PrepareDetailsForLayout(const QHash<quint32, VDetail> *de
         return;
     }
 
-    QHash<quint32, VDetail>::const_iterator i = details->constBegin();
+    QHash<quint32, VPiece>::const_iterator i = details->constBegin();
     while (i != details->constEnd())
     {
-        VLayoutDetail det = VLayoutDetail();
-        const VDetail d = i.value();
-        det.SetCountourPoints(d.ContourPoints(pattern));
-        det.SetSeamAllowencePoints(d.SeamAllowancePoints(pattern), d.getSeamAllowance(), d.getClosed());
-        det.setName(d.getName());
-        const VPatternPieceData& data = d.GetPatternPieceData();
-        if (data.IsVisible() == true)
-        {
-            det.SetDetail(d.getName(), data, qApp->font());
-        }
-        const VPatternInfoGeometry& geom = d.GetPatternInfo();
-        if (geom.IsVisible() == true)
-        {
-            VAbstractPattern* pDoc = qApp->getCurrentDocument();
-            QDate date;
-            if (pDoc->IsDateVisible() == true)
-            {
-                date = QDate::currentDate();
-            }
-            det.SetPatternInfo(pDoc, geom, qApp->font(), pattern->size(), pattern->height());
-        }
-        const VGrainlineGeometry& grainlineGeom = d.GetGrainlineGeometry();
-        if (grainlineGeom.IsVisible() == true)
-        {
-            det.SetGrainline(grainlineGeom, *pattern);
-        }
-        det.setWidth(qApp->toPixel(d.getWidth()));
-        det.CreateTextItems();
-        det.setForbidFlipping(d.getForbidFlipping());
-
-        listDetails.append(det);
+        listDetails.append(VLayoutPiece::Create(i.value(), pattern));
         ++i;
     }
 }
diff --git a/src/app/valentina/mainwindowsnogui.h b/src/app/valentina/mainwindowsnogui.h
index 6febda374..17f715dfb 100644
--- a/src/app/valentina/mainwindowsnogui.h
+++ b/src/app/valentina/mainwindowsnogui.h
@@ -32,8 +32,7 @@
 #include <QMainWindow>
 #include <QPrinter>
 
-#include "../vpatterndb/vdetail.h"
-#include "../vlayout/vlayoutdetail.h"
+#include "../vlayout/vlayoutpiece.h"
 #include "xml/vpattern.h"
 #include "dialogs/dialogsavelayout.h"
 #include "../vlayout/vlayoutgenerator.h"
@@ -59,7 +58,7 @@ public slots:
     void PrintOrigin();
     void PrintTiled();
 protected:
-    QVector<VLayoutDetail> listDetails;
+    QVector<VLayoutPiece> listDetails;
 
     /** @brief currentScene pointer to current scene. */
     QGraphicsScene *currentScene;
@@ -90,7 +89,7 @@ protected:
     QMarginsF margins;
     QSizeF paperSize;
 
-    void PrepareDetailsForLayout(const QHash<quint32, VDetail> *details);
+    void PrepareDetailsForLayout(const QHash<quint32, VPiece> *details);
     void ExportLayout(const DialogSaveLayout &dialog);
 
     void InitTempLayoutScene();
diff --git a/src/app/valentina/share/resources/cursor.qrc b/src/app/valentina/share/resources/cursor.qrc
index e92f24e13..44323cc41 100644
--- a/src/app/valentina/share/resources/cursor.qrc
+++ b/src/app/valentina/share/resources/cursor.qrc
@@ -78,5 +78,7 @@
         <file>cursor/move_cursor@2x.png</file>
         <file>cursor/el_arc_cursor.png</file>
         <file>cursor/el_arc_cursor@2x.png</file>
+        <file>cursor/path_cursor.png</file>
+        <file>cursor/path_cursor@2x.png</file>
     </qresource>
 </RCC>
diff --git a/src/app/valentina/share/resources/cursor/path_cursor.png b/src/app/valentina/share/resources/cursor/path_cursor.png
new file mode 100644
index 000000000..2819f260a
Binary files /dev/null and b/src/app/valentina/share/resources/cursor/path_cursor.png differ
diff --git a/src/app/valentina/share/resources/cursor/path_cursor@2x.png b/src/app/valentina/share/resources/cursor/path_cursor@2x.png
new file mode 100644
index 000000000..09c3a01ab
Binary files /dev/null and b/src/app/valentina/share/resources/cursor/path_cursor@2x.png differ
diff --git a/src/app/valentina/share/resources/toolicon.qrc b/src/app/valentina/share/resources/toolicon.qrc
index 41de1c552..528ab18c2 100644
--- a/src/app/valentina/share/resources/toolicon.qrc
+++ b/src/app/valentina/share/resources/toolicon.qrc
@@ -76,5 +76,7 @@
         <file>toolicon/32x32/move@2x.png</file>
         <file>toolicon/32x32/el_arc.png</file>
         <file>toolicon/32x32/el_arc@2x.png</file>
+        <file>toolicon/32x32/path.png</file>
+        <file>toolicon/32x32/path@2x.png</file>
     </qresource>
 </RCC>
diff --git a/src/app/valentina/share/resources/toolicon/32x32/path.png b/src/app/valentina/share/resources/toolicon/32x32/path.png
new file mode 100644
index 000000000..a95d6e90d
Binary files /dev/null and b/src/app/valentina/share/resources/toolicon/32x32/path.png differ
diff --git a/src/app/valentina/share/resources/toolicon/32x32/path@2x.png b/src/app/valentina/share/resources/toolicon/32x32/path@2x.png
new file mode 100644
index 000000000..46efce5f6
Binary files /dev/null and b/src/app/valentina/share/resources/toolicon/32x32/path@2x.png differ
diff --git a/src/app/valentina/share/resources/toolicon/svg/path.svg b/src/app/valentina/share/resources/toolicon/svg/path.svg
new file mode 100644
index 000000000..fede8eb12
--- /dev/null
+++ b/src/app/valentina/share/resources/toolicon/svg/path.svg
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="32"
+   height="32"
+   id="svg3837"
+   inkscape:version="0.91 r"
+   sodipodi:docname="path.svg"
+   inkscape:export-filename="normal.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1855"
+     inkscape:window-height="1056"
+     id="namedview12"
+     showgrid="false"
+     inkscape:zoom="10.429825"
+     inkscape:cx="-10.695145"
+     inkscape:cy="17.373127"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="layer1" />
+  <defs
+     id="defs3839" />
+  <metadata
+     id="metadata3842">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1">
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#f70000;stroke-width:1.808;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 0.69867705,29.000338 18.91523895,0"
+       id="path4205"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       d="m 4.55558,29.025223 a 1.7375,1.7294948 0 0 1 -3.475,0 1.7375,1.7294948 0 1 1 3.475,0 z"
+       id="path2985-2"
+       style="fill:#000000;fill-opacity:1;stroke:#370000;stroke-width:1.56700003;stroke-linejoin:round;stroke-miterlimit:4.9000001;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.93950177"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#f70000;stroke-width:1.79597759;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 18.613918,3.1640977 c 16.627356,3.2556205 16.092696,24.3053213 0,25.7434553"
+       id="path3385"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       inkscape:connector-curvature="0"
+       style="fill:#000000;fill-opacity:1;stroke:#370000;stroke-width:1.57200003;stroke-linejoin:round;stroke-miterlimit:4.9000001;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.93950177"
+       id="path5373"
+       d="m 20.178354,28.833465 a 1.8239208,1.9086996 0 0 1 -3.647841,0 1.8239208,1.9086996 0 1 1 3.647841,0 z" />
+    <path
+       inkscape:connector-curvature="0"
+       style="fill:#000000;fill-opacity:1;stroke:#370000;stroke-width:1.57200003;stroke-linejoin:round;stroke-miterlimit:4.9000001;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.93950177"
+       id="path5373-7"
+       d="m 20.424424,3.1415223 a 1.8239208,1.9086996 0 0 1 -3.647841,0 1.8239208,1.9086996 0 1 1 3.647841,0 z" />
+  </g>
+</svg>
diff --git a/src/app/valentina/xml/vpattern.cpp b/src/app/valentina/xml/vpattern.cpp
index ad5eb8c61..1fa4b300a 100644
--- a/src/app/valentina/xml/vpattern.cpp
+++ b/src/app/valentina/xml/vpattern.cpp
@@ -29,7 +29,7 @@
 #include "vpattern.h"
 #include "../vwidgets/vabstractmainwindow.h"
 #include "../vtools/tools/vdatatool.h"
-#include "../vtools/tools/vtooldetail.h"
+#include "../vtools/tools/vtoolseamallowance.h"
 #include "../vtools/tools/vtooluniondetails.h"
 #include "../vtools/tools/drawTools/drawtools.h"
 #include "../vtools/tools/nodeDetails/nodedetails.h"
@@ -49,10 +49,13 @@
 #include "../vgeometry/vcubicbezier.h"
 #include "../vgeometry/vcubicbezierpath.h"
 #include "../core/vapplication.h"
+#include "../vpatterndb/vpiecenode.h"
 #include "../vpatterndb/calculator.h"
 #include "../vpatterndb/vpatternpiecedata.h"
 #include "../vpatterndb/vpatterninfogeometry.h"
 #include "../vpatterndb/vgrainlinegeometry.h"
+#include "../vpatterndb/vpiecepath.h"
+#include "../vpatterndb/vnodedetail.h"
 
 #include <QMessageBox>
 #include <QUndoStack>
@@ -293,8 +296,9 @@ void VPattern::setCurrentData()
 
                 const VDataTool *vTool = tools.value(id);
                 *data = vTool->getData();
-                //Delete special variable if exist
+                //Delete special variables if exist
                 data->RemoveVariable(currentLength);
+                data->RemoveVariable(currentSeamAllowance);
                 qCDebug(vXML, "Data successfully updated.");
             }
             else
@@ -348,6 +352,31 @@ quint32 VPattern::SPointActiveDraw()
     return 0;
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+QVector<quint32> VPattern::GetActivePPPieces() const
+{
+    QVector<quint32> pieces;
+    QDomElement drawElement;
+    if (GetActivDrawElement(drawElement))
+    {
+        const QDomElement details = drawElement.firstChildElement(TagDetails);
+        if (not details.isNull())
+        {
+            QDomElement detail = details.firstChildElement(TagDetail);
+            while(not detail.isNull())
+            {
+                bool united = GetParametrBool(detail, VToolSeamAllowance::AttrUnited, falseStr);
+                if (not united)
+                {
+                    pieces.append(GetParametrId(detail));
+                }
+                detail = detail.nextSiblingElement(TagDetail);
+            }
+        }
+    }
+    return pieces;
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 bool VPattern::SaveDocument(const QString &fileName, QString &error) const
 {
@@ -493,6 +522,47 @@ void VPattern::customEvent(QEvent *event)
     }
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+VNodeDetail VPattern::ParseDetailNode(const QDomElement &domElement) const
+{
+    const quint32 id = GetParametrUInt(domElement, AttrIdObject, NULL_ID_STR);
+    const qreal mx = GetParametrDouble(domElement, AttrMx, "0.0");
+    const qreal my = GetParametrDouble(domElement, AttrMy, "0.0");
+    const bool reverse = GetParametrUInt(domElement, VAbstractPattern::AttrNodeReverse, "0");
+    const NodeDetail nodeType = NodeDetail::Contour;
+
+    const QString t = GetParametrString(domElement, AttrType, "NodePoint");
+    Tool tool;
+
+    QStringList types = QStringList() << VAbstractPattern::NodePoint
+                                      << VAbstractPattern::NodeArc
+                                      << VAbstractPattern::NodeSpline
+                                      << VAbstractPattern::NodeSplinePath
+                                      << VAbstractPattern::NodeElArc;
+    switch (types.indexOf(t))
+    {
+        case 0: // NodePoint
+            tool = Tool::NodePoint;
+            break;
+        case 1: // NodeArc
+            tool = Tool::NodeArc;
+            break;
+        case 2: // NodeSpline
+            tool = Tool::NodeSpline;
+            break;
+        case 3: // NodeSplinePath
+            tool = Tool::NodeSplinePath;
+            break;
+        case 4: // NodeElArc
+            tool = Tool::NodeElArc;
+            break;
+        default:
+            VException e(tr("Wrong tag name '%1'.").arg(t));
+            throw e;
+    }
+    return VNodeDetail(id, tool, nodeType, mx, my, reverse);
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief ParseDrawElement parse draw tag.
@@ -559,8 +629,14 @@ void VPattern::ParseDrawMode(const QDomNode &node, const Document &parse, const
     {
         scene = sceneDetail;
     }
-    const QStringList tags = QStringList() << TagPoint << TagLine << TagSpline << TagArc << TagTools << TagOperation
-                                           << TagElArc;
+    const QStringList tags = QStringList() << TagPoint
+                                           << TagLine
+                                           << TagSpline
+                                           << TagArc
+                                           << TagTools
+                                           << TagOperation
+                                           << TagElArc
+                                           << TagPath;
     const QDomNodeList nodeList = node.childNodes();
     const qint32 num = nodeList.size();
     for (qint32 i = 0; i < num; ++i)
@@ -597,6 +673,9 @@ void VPattern::ParseDrawMode(const QDomNode &node, const Document &parse, const
                 case 6: // TagElArc
                     qCDebug(vXML, "Tag elliptical arc.");
                     ParseEllipticalArcElement(scene, domElement, parse, domElement.attribute(AttrType, ""));
+                case 7: // TagPath
+                    qCDebug(vXML, "Tag path.");
+                    ParsePathElement(scene, domElement, parse);
                     break;
                 default:
                     VException e(tr("Wrong tag name '%1'.").arg(domElement.tagName()));
@@ -612,143 +691,83 @@ void VPattern::ParseDrawMode(const QDomNode &node, const Document &parse, const
  * @param domElement tag in xml tree.
  * @param parse parser file mode.
  */
-void VPattern::ParseDetailElement(const QDomElement &domElement, const Document &parse)
+void VPattern::ParseDetailElement(QDomElement &domElement, const Document &parse)
 {
     Q_ASSERT_X(not domElement.isNull(), Q_FUNC_INFO, "domElement is null");
     try
     {
-        VDetail detail;
+        VPiece detail;
         const quint32 id = GetParametrId(domElement);
-        detail.setName(GetParametrString(domElement, AttrName, ""));
-        detail.setMx(qApp->toPixel(GetParametrDouble(domElement, AttrMx, "0.0")));
-        detail.setMy(qApp->toPixel(GetParametrDouble(domElement, AttrMy, "0.0")));
-        detail.setSeamAllowance(GetParametrUInt(domElement, VToolDetail::AttrSupplement, "1"));
-        detail.setWidth(GetParametrDouble(domElement, VToolDetail::AttrWidth, "10.0"));
-        detail.setClosed(GetParametrUInt(domElement, VToolDetail::AttrClosed, "1"));
-        detail.setForbidFlipping(GetParametrUInt(domElement, VToolDetail::AttrForbidFlipping,
+        detail.SetName(GetParametrString(domElement, AttrName, tr("Detail")));
+        detail.SetMx(qApp->toPixel(GetParametrDouble(domElement, AttrMx, "0.0")));
+        detail.SetMy(qApp->toPixel(GetParametrDouble(domElement, AttrMy, "0.0")));
+        detail.SetSeamAllowance(GetParametrBool(domElement, VToolSeamAllowance::AttrSeamAllowance, falseStr));
+        detail.SetForbidFlipping(GetParametrBool(domElement, VToolSeamAllowance::AttrForbidFlipping,
                                            QString().setNum(qApp->ValentinaSettings()->GetForbidWorkpieceFlipping())));
         detail.SetInLayout(GetParametrBool(domElement, AttrInLayout, trueStr));
+        detail.SetUnited(GetParametrBool(domElement, VToolSeamAllowance::AttrUnited, falseStr));
+
+        const QString width = GetParametrString(domElement, AttrWidth, "0.0");
+        QString w = width;//need for saving fixed formula;
+        const uint version = GetParametrUInt(domElement, VToolSeamAllowance::AttrVersion, "1");
+
+        const QStringList tags = QStringList() << TagNodes
+                                               << TagData
+                                               << TagPatternInfo
+                                               << TagGrainline
+                                               << VToolSeamAllowance::TagCSA
+                                               << VToolSeamAllowance::TagIPaths;
 
-        QStringList types = QStringList() << VToolDetail::NodePoint
-                                          << VToolDetail::NodeArc
-                                          << VToolDetail::NodeSpline
-                                          << VToolDetail::NodeSplinePath
-                                          << VToolDetail::NodeElArc;
         const QDomNodeList nodeList = domElement.childNodes();
-        const qint32 num = nodeList.size();
-        for (qint32 i = 0; i < num; ++i)
+        for (qint32 i = 0; i < nodeList.size(); ++i)
         {
             const QDomElement element = nodeList.at(i).toElement();
-            if (element.isNull() == false)
+            if (not element.isNull())
             {
-                if (element.tagName() == VToolDetail::TagNode)
+                switch (tags.indexOf(element.tagName()))
                 {
-                    const quint32 id = GetParametrUInt(element, AttrIdObject, NULL_ID_STR);
-                    const qreal mx = qApp->toPixel(GetParametrDouble(element, AttrMx, "0.0"));
-                    const qreal my = qApp->toPixel(GetParametrDouble(element, AttrMy, "0.0"));
-                    const bool reverse = GetParametrUInt(element, VToolDetail::AttrReverse, "0");
-                    const NodeDetail nodeType = NodeDetail::Contour;
-
-                    const QString t = GetParametrString(element, AttrType, "NodePoint");
-                    Tool tool;
-
-                    switch (types.indexOf(t))
-                    {
-                        case 0: // VToolDetail::NodePoint
-                            tool = Tool::NodePoint;
-                            break;
-                        case 1: // VToolDetail::NodeArc
-                            tool = Tool::NodeArc;
-                            break;
-                        case 2: // VToolDetail::NodeSpline
-                            tool = Tool::NodeSpline;
-                            break;
-                        case 3: // VToolDetail::NodeSplinePath
-                            tool = Tool::NodeSplinePath;
-                            break;
-                        case 4: // VToolDetail::NodeElArc
-                            tool = Tool::NodeElArc;
-                            break;
-                        default:
-                            VException e(tr("Wrong tag name '%1'.").arg(t));
-                            throw e;
-                    }
-                    detail.append(VNodeDetail(id, tool, nodeType, mx, my, reverse));
-                }
-                else if (element.tagName() == TagData)
-                {
-                    bool bVisible = GetParametrBool(element, AttrVisible, trueStr);
-                    detail.GetPatternPieceData().SetVisible(bVisible);
-                    try
-                    {
-                        QString qsLetter = GetParametrString(element, AttrLetter, "");
-                        detail.GetPatternPieceData().SetLetter(qsLetter);
-                    } catch(...)
-                    {
-                        detail.GetPatternPieceData().SetLetter("");
-                    }
-                    QPointF ptPos;
-                    ptPos.setX(GetParametrDouble(element, AttrMx, "0"));
-                    ptPos.setY(GetParametrDouble(element, AttrMy, "0"));
-                    detail.GetPatternPieceData().SetPos(ptPos);
-                    qreal dLW = GetParametrDouble(element, VToolDetail::AttrWidth, "0");
-                    detail.GetPatternPieceData().SetLabelWidth(dLW);
-                    qreal dLH = GetParametrDouble(element, VToolDetail::AttrHeight, "0");
-                    detail.GetPatternPieceData().SetLabelHeight(dLH);
-                    int iFS = static_cast<int>(GetParametrUInt(element, VToolDetail::AttrFont, "0"));
-                    detail.GetPatternPieceData().SetFontSize(iFS);
-                    qreal dRot = GetParametrDouble(element, VToolDetail::AttrRotation, "0");
-                    detail.GetPatternPieceData().SetRotation(dRot);
-
-                    QDomNodeList nodeListMCP = element.childNodes();
-                    for (int iMCP = 0; iMCP < nodeListMCP.count(); ++iMCP)
-                    {
-                        MaterialCutPlacement mcp;
-                        QDomElement domMCP = nodeListMCP.at(iMCP).toElement();
-                        mcp.m_eMaterial = MaterialType(GetParametrUInt(domMCP, AttrMaterial, 0));
-                        if (mcp.m_eMaterial == MaterialType::mtUserDefined)
+                    case 0:// TagNodes
+                        if (version == 1)
                         {
-                            mcp.m_qsMaterialUserDef = GetParametrString(domMCP, AttrUserDefined, "");
+                            // TODO. Delete if minimal supported version is 0.4.0
+                            Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 4, 0),
+                                              "Time to refactor the code.");
+                            const bool closed = GetParametrUInt(domElement, AttrClosed, "1");
+                            const qreal width = GetParametrDouble(domElement, AttrWidth, "0.0");
+                            ParseDetailNodes(element, detail, width, closed);
                         }
-                        mcp.m_iCutNumber = static_cast<int>(GetParametrUInt(domMCP, AttrCutNumber, 0));
-                        mcp.m_ePlacement = PlacementType(GetParametrUInt(domMCP, AttrPlacement, 0));
-                        detail.GetPatternPieceData().Append(mcp);
-                    }
-                }
-                else if (element.tagName() == TagPatternInfo)
-                {
-                    detail.GetPatternInfo().SetVisible(GetParametrBool(element, AttrVisible, trueStr));
-                    QPointF ptPos;
-                    ptPos.setX(GetParametrDouble(element, AttrMx, "0"));
-                    ptPos.setY(GetParametrDouble(element, AttrMy, "0"));
-                    detail.GetPatternInfo().SetPos(ptPos);
-                    qreal dLW = GetParametrDouble(element, VToolDetail::AttrWidth, "0");
-                    detail.GetPatternInfo().SetLabelWidth(dLW);
-                    qreal dLH = GetParametrDouble(element, VToolDetail::AttrHeight, "0");
-                    detail.GetPatternInfo().SetLabelHeight(dLH);
-                    int iFS = static_cast<int>(GetParametrUInt(element, VToolDetail::AttrFont, "0"));
-                    detail.GetPatternInfo().SetFontSize(iFS);
-                    qreal dRot = GetParametrDouble(element, VToolDetail::AttrRotation, "0");
-                    detail.GetPatternInfo().SetRotation(dRot);
-                }
-                else if (element.tagName() == TagGrainline)
-                {
-                    detail.GetGrainlineGeometry().SetVisible(GetParametrBool(element, AttrVisible, falseStr));
-                    QPointF ptPos;
-                    ptPos.setX(GetParametrDouble(element, AttrMx, "0"));
-                    ptPos.setY(GetParametrDouble(element, AttrMy, "0"));
-                    detail.GetGrainlineGeometry().SetPos(ptPos);
-                    QString qsLength = GetParametrString(element, AttrLength, "0");
-                    detail.GetGrainlineGeometry().SetLength(qsLength);
-                    QString qsRot = GetParametrString(element, VToolDetail::AttrRotation, "90");
-                    detail.GetGrainlineGeometry().SetRotation(qsRot);
-                    VGrainlineGeometry::ArrowType eAT =
-                            VGrainlineGeometry::ArrowType(GetParametrUInt(element, AttrArrows, "0"));
-                    detail.GetGrainlineGeometry().SetArrowType(eAT);
+                        else
+                        {
+                            detail.SetPath(ParsePieceNodes(element));
+                        }
+                        break;
+                    case 1:// TagData
+                        ParsePieceDataTag(element, detail);
+                        break;
+                    case 2:// TagPatternInfo
+                        ParsePiecePatternInfo(element, detail);
+                        break;
+                    case 3:// TagGrainline
+                        ParsePieceGrainline(element, detail);
+                        break;
+                    case 4:// VToolSeamAllowance::TagCSA
+                        detail.SetCustomSARecords(ParsePieceCSARecords(element));
+                        break;
+                    case 5:// VToolSeamAllowance::TagIPaths
+                        detail.SetInternalPaths(ParsePieceInternalPaths(element));
+                    default:
+                        break;
                 }
             }
         }
-        VToolDetail::Create(id, detail, sceneDetail, this, data, parse, Source::FromFile);
+        VToolSeamAllowance::Create(id, detail, w, sceneDetail, this, data, parse, Source::FromFile);
+        //Rewrite attribute formula. Need for situation when we have wrong formula.
+        if (w != width)
+        {
+            SetAttribute(domElement, AttrWidth, w);
+            modified = true;
+            haveLiteChange();
+        }
     }
     catch (const VExceptionBadId &e)
     {
@@ -758,6 +777,102 @@ void VPattern::ParseDetailElement(const QDomElement &domElement, const Document
     }
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+void VPattern::ParseDetailNodes(const QDomElement &domElement, VPiece &detail, qreal width, bool closed) const
+{
+    QVector<VNodeDetail> oldNodes;
+    const QDomNodeList nodeList = domElement.childNodes();
+    for (qint32 i = 0; i < nodeList.size(); ++i)
+    {
+        const QDomElement element = nodeList.at(i).toElement();
+        if (not element.isNull()
+                && element.tagName() == VAbstractPattern::TagNode) // Old detail version need this check!
+        {
+            oldNodes.append(ParseDetailNode(element));
+        }
+    }
+
+    detail.GetPath().SetNodes(VNodeDetail::Convert(data, oldNodes, width, closed));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPattern::ParsePieceDataTag(const QDomElement &domElement, VPiece &detail) const
+{
+    detail.GetPatternPieceData().SetVisible(GetParametrBool(domElement, AttrVisible, trueStr));
+    try
+    {
+        QString qsLetter = GetParametrString(domElement, AttrLetter, "");
+        detail.GetPatternPieceData().SetLetter(qsLetter);
+    }
+    catch(const VExceptionEmptyParameter &e)
+    {
+        Q_UNUSED(e)
+        detail.GetPatternPieceData().SetLetter("");
+    }
+    QPointF ptPos;
+    ptPos.setX(GetParametrDouble(domElement, AttrMx, "0"));
+    ptPos.setY(GetParametrDouble(domElement, AttrMy, "0"));
+    detail.GetPatternPieceData().SetPos(ptPos);
+    qreal dLW = GetParametrDouble(domElement, AttrWidth, "0");
+    detail.GetPatternPieceData().SetLabelWidth(dLW);
+    qreal dLH = GetParametrDouble(domElement, VToolSeamAllowance::AttrHeight, "0");
+    detail.GetPatternPieceData().SetLabelHeight(dLH);
+    int iFS = static_cast<int>(GetParametrUInt(domElement, VToolSeamAllowance::AttrFont, "0"));
+    detail.GetPatternPieceData().SetFontSize(iFS);
+    qreal dRot = GetParametrDouble(domElement, AttrRotation, "0");
+    detail.GetPatternPieceData().SetRotation(dRot);
+
+    QDomNodeList nodeListMCP = domElement.childNodes();
+    for (int iMCP = 0; iMCP < nodeListMCP.count(); ++iMCP)
+    {
+        MaterialCutPlacement mcp;
+        QDomElement domMCP = nodeListMCP.at(iMCP).toElement();
+        mcp.m_eMaterial = MaterialType(GetParametrUInt(domMCP, AttrMaterial, 0));
+        if (mcp.m_eMaterial == MaterialType::mtUserDefined)
+        {
+            mcp.m_qsMaterialUserDef = GetParametrString(domMCP, AttrUserDefined, "");
+        }
+        mcp.m_iCutNumber = static_cast<int>(GetParametrUInt(domMCP, AttrCutNumber, 0));
+        mcp.m_ePlacement = PlacementType(GetParametrUInt(domMCP, AttrPlacement, 0));
+        detail.GetPatternPieceData().Append(mcp);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPattern::ParsePiecePatternInfo(const QDomElement &domElement, VPiece &detail) const
+{
+    detail.GetPatternInfo().SetVisible(GetParametrBool(domElement, AttrVisible, trueStr));
+    QPointF ptPos;
+    ptPos.setX(GetParametrDouble(domElement, AttrMx, "0"));
+    ptPos.setY(GetParametrDouble(domElement, AttrMy, "0"));
+    detail.GetPatternInfo().SetPos(ptPos);
+    qreal dLW = GetParametrDouble(domElement, AttrWidth, "0");
+    detail.GetPatternInfo().SetLabelWidth(dLW);
+    qreal dLH = GetParametrDouble(domElement, VToolSeamAllowance::AttrHeight, "0");
+    detail.GetPatternInfo().SetLabelHeight(dLH);
+    int iFS = static_cast<int>(GetParametrUInt(domElement, VToolSeamAllowance::AttrFont, "0"));
+    detail.GetPatternInfo().SetFontSize(iFS);
+    qreal dRot = GetParametrDouble(domElement, AttrRotation, "0");
+    detail.GetPatternInfo().SetRotation(dRot);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPattern::ParsePieceGrainline(const QDomElement &domElement, VPiece &detail) const
+{
+    detail.GetGrainlineGeometry().SetVisible(GetParametrBool(domElement, AttrVisible, falseStr));
+    QPointF ptPos;
+    ptPos.setX(GetParametrDouble(domElement, AttrMx, "0"));
+    ptPos.setY(GetParametrDouble(domElement, AttrMy, "0"));
+    detail.GetGrainlineGeometry().SetPos(ptPos);
+    QString qsLength = GetParametrString(domElement, AttrLength, "0");
+    detail.GetGrainlineGeometry().SetLength(qsLength);
+    QString qsRot = GetParametrString(domElement, AttrRotation, "90");
+    detail.GetGrainlineGeometry().SetRotation(qsRot);
+    VGrainlineGeometry::ArrowType eAT =
+            VGrainlineGeometry::ArrowType(GetParametrUInt(domElement, AttrArrows, "0"));
+    detail.GetGrainlineGeometry().SetArrowType(eAT);
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief ParseDetails parse details tag.
@@ -772,7 +887,7 @@ void VPattern::ParseDetails(const QDomElement &domElement, const Document &parse
     {
         if (domNode.isElement())
         {
-            const QDomElement domElement = domNode.toElement();
+            QDomElement domElement = domNode.toElement();
             if (domElement.isNull() == false)
             {
                 if (domElement.tagName() == TagDetail)
@@ -3015,13 +3130,17 @@ void VPattern::ParseToolsElement(VMainGraphicsScene *scene, const QDomElement &d
             {
                 quint32 id = 0;
                 ToolsCommonAttributes(domElement, id);
-                const quint32 indexD1 = GetParametrUInt(domElement, VToolUnionDetails::AttrIndexD1, "-1");
-                const quint32 indexD2 = GetParametrUInt(domElement, VToolUnionDetails::AttrIndexD2, "-1");
 
-                const QVector<VDetail> vector = VToolUnionDetails::GetDetailFromFile(this, domElement);
+                VToolUnionDetailsInitData initData;
+                initData.indexD1 = GetParametrUInt(domElement, VToolUnionDetails::AttrIndexD1, "-1");
+                initData.indexD2 = GetParametrUInt(domElement, VToolUnionDetails::AttrIndexD2, "-1");
+                initData.scene = scene;
+                initData.doc = this;
+                initData.data = data;
+                initData.parse = parse;
+                initData.typeCreation = Source::FromFile;
 
-                VToolUnionDetails::Create(id, vector[0], vector[1], 0, 0, indexD1, indexD2, scene, this, data, parse,
-                                          Source::FromFile);
+                VToolUnionDetails::Create(id, initData);
             }
             catch (const VExceptionBadId &e)
             {
@@ -3069,6 +3188,42 @@ void VPattern::ParseOperationElement(VMainGraphicsScene *scene, QDomElement &dom
     }
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+void VPattern::ParsePathElement(VMainGraphicsScene *scene, QDomElement &domElement, const Document &parse)
+{
+    SCASSERT(scene != nullptr);
+    Q_ASSERT_X(not domElement.isNull(), Q_FUNC_INFO, "domElement is null");
+    try
+    {
+        quint32 id = 0;
+        ToolsCommonAttributes(domElement, id);
+        const QString name = GetParametrString(domElement, AttrName, tr("Unnamed path"));
+        const QString defType = QString().setNum(static_cast<int>(PiecePathType::CustomSeamAllowance));
+        const PiecePathType type = static_cast<PiecePathType>(GetParametrUInt(domElement, AttrType, defType));
+        const quint32 idTool = GetParametrUInt(domElement, VAbstractNode::AttrIdTool, NULL_ID_STR);
+        const QString penType = GetParametrString(domElement, AttrTypeLine, TypeLineLine);
+
+        VPiecePath path;
+        const QDomElement element = domElement.firstChildElement(VAbstractPattern::TagNodes);
+        if (not element.isNull())
+        {
+            path = ParsePathNodes(element);
+        }
+
+        path.SetType(type);
+        path.SetName(name);
+        path.SetPenType(VAbstractTool::LineStyleToPenStyle(penType));
+
+        VToolPiecePath::Create(id, path, 0, scene, this, data, parse, Source::FromFile, "", idTool);
+    }
+    catch (const VExceptionBadId &e)
+    {
+        VExceptionObjectError excep(tr("Error creating or updating a piece path"), domElement);
+        excep.AddMoreInformation(e.ErrorMessage());
+        throw excep;
+    }
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief ParseIncrementsElement parse increments tag.
@@ -3569,7 +3724,7 @@ QT_WARNING_DISABLE_GCC("-Wswitch-default")
 QRectF VPattern::ActiveDrawBoundingRect() const
 {
     // This check helps to find missed tools in the switch
-    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50, "Not all tools were used.");
+    Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51, "Not all tools were used.");
 
     QRectF rec;
 
@@ -3694,7 +3849,7 @@ QRectF VPattern::ActiveDrawBoundingRect() const
                     rec = ToolBoundingRect<VToolEllipticalArc>(rec, tool.getId());
                     break;
                 //These tools are not accesseble in Draw mode, but still 'history' contains them.
-                case Tool::Detail:
+                case Tool::Piece:
                 case Tool::UnionDetails:
                 case Tool::NodeArc:
                 case Tool::NodeElArc:
@@ -3702,6 +3857,7 @@ QRectF VPattern::ActiveDrawBoundingRect() const
                 case Tool::NodeSpline:
                 case Tool::NodeSplinePath:
                 case Tool::Group:
+                case Tool::PiecePath:
                     break;
             }
         }
diff --git a/src/app/valentina/xml/vpattern.h b/src/app/valentina/xml/vpattern.h
index 02ce823c7..1c0fb2f3f 100644
--- a/src/app/valentina/xml/vpattern.h
+++ b/src/app/valentina/xml/vpattern.h
@@ -36,6 +36,7 @@
 
 class VDataTool;
 class VMainGraphicsScene;
+class VNodeDetail;
 
 /**
  * @brief The VPattern class working with pattern file.
@@ -59,6 +60,8 @@ public:
 
     quint32        SPointActiveDraw();
 
+    QVector<quint32> GetActivePPPieces() const;
+
     virtual void   setXMLContent(const QString &fileName) Q_DECL_OVERRIDE;
     virtual bool   SaveDocument(const QString &fileName, QString &error) const Q_DECL_OVERRIDE;
 
@@ -112,9 +115,15 @@ private:
     VMainGraphicsScene *sceneDraw;
     VMainGraphicsScene *sceneDetail;
 
+    VNodeDetail    ParseDetailNode(const QDomElement &domElement) const;
+
     void           ParseDrawElement(const QDomNode& node, const Document &parse);
     void           ParseDrawMode(const QDomNode& node, const Document &parse, const Draw &mode);
-    void           ParseDetailElement(const QDomElement &domElement, const Document &parse);
+    void           ParseDetailElement(QDomElement &domElement, const Document &parse);
+    void           ParseDetailNodes(const QDomElement &domElement, VPiece &detail, qreal width, bool closed) const;
+    void           ParsePieceDataTag(const QDomElement &domElement, VPiece &detail) const;
+    void           ParsePiecePatternInfo(const QDomElement &domElement, VPiece &detail) const;
+    void           ParsePieceGrainline(const QDomElement &domElement, VPiece &detail) const;
     void           ParseDetails(const QDomElement &domElement, const Document &parse);
 
     void           ParsePointElement(VMainGraphicsScene *scene, QDomElement &domElement,
@@ -131,6 +140,9 @@ private:
                                      const Document &parse, const QString& type);
     void           ParseOperationElement(VMainGraphicsScene *scene, QDomElement &domElement, const Document &parse,
                                          const QString& type);
+
+    void           ParsePathElement(VMainGraphicsScene *scene, QDomElement &domElement, const Document &parse);
+
     void           ParseIncrementsElement(const QDomNode& node);
     void           PrepareForParse(const Document &parse);
     void           ToolsCommonAttributes(const QDomElement &domElement, quint32 &id);
diff --git a/src/libs/ifc/ifcdef.cpp b/src/libs/ifc/ifcdef.cpp
index 0e4fa1022..eb5565f02 100644
--- a/src/libs/ifc/ifcdef.cpp
+++ b/src/libs/ifc/ifcdef.cpp
@@ -138,7 +138,8 @@ const QString AttrArc         = QStringLiteral("arc");
 const QString AttrSuffix      = QStringLiteral("suffix");
 const QString AttrIdObject    = QStringLiteral("idObject");
 const QString AttrInLayout    = QStringLiteral("inLayout");
-const QString AttrRotationAngle      = QStringLiteral("rotationAngle");
+const QString AttrRotationAngle = QStringLiteral("rotationAngle");
+const QString AttrClosed      = QStringLiteral("closed");
 
 const QString TypeLineNone           = QStringLiteral("none");
 const QString TypeLineLine           = QStringLiteral("hair");
@@ -166,29 +167,30 @@ const QString ColorDeepSkyBlue      = QStringLiteral("deepskyblue");
 const QString ColorCornFlowerBlue   = QStringLiteral("cornflowerblue");
 
 //variables
-const QString line_           = QStringLiteral("Line_");
-const QString angleLine_      = QStringLiteral("AngleLine_");
-const QString spl_            = QStringLiteral(SPL_);
-const QString arc_            = QStringLiteral(ARC_);
-const QString splPath         = QStringLiteral("SplPath");
-const QString radius_V        = QStringLiteral("Radius");
-const QString radiusArc_      = radius_V + arc_;
-const QString angle1_V        = QStringLiteral("Angle1");
-const QString angle2_V        = QStringLiteral("Angle2");
-const QString c1Length_V      = QStringLiteral("C1Length");
-const QString c2Length_V      = QStringLiteral("C2Length");
-const QString c1LengthSpl_    = c1Length_V + spl_;
-const QString c2LengthSpl_    = c2Length_V + spl_;
-const QString c1LengthSplPath = c1Length_V + splPath;
-const QString c2LengthSplPath = c2Length_V + splPath;
-const QString angle1Arc_      = angle1_V + arc_;
-const QString angle2Arc_      = angle2_V + arc_;
-const QString angle1Spl_      = angle1_V + spl_;
-const QString angle2Spl_      = angle2_V + spl_;
-const QString angle1SplPath   = angle1_V + splPath;
-const QString angle2SplPath   = angle2_V + splPath;
-const QString seg_            = QStringLiteral("Seg_");
-const QString currentLength   = QStringLiteral("CurrentLength");
+const QString line_                = QStringLiteral("Line_");
+const QString angleLine_           = QStringLiteral("AngleLine_");
+const QString spl_                 = QStringLiteral(SPL_);
+const QString arc_                 = QStringLiteral(ARC_);
+const QString splPath              = QStringLiteral("SplPath");
+const QString radius_V             = QStringLiteral("Radius");
+const QString radiusArc_           = radius_V + arc_;
+const QString angle1_V             = QStringLiteral("Angle1");
+const QString angle2_V             = QStringLiteral("Angle2");
+const QString c1Length_V           = QStringLiteral("C1Length");
+const QString c2Length_V           = QStringLiteral("C2Length");
+const QString c1LengthSpl_         = c1Length_V + spl_;
+const QString c2LengthSpl_         = c2Length_V + spl_;
+const QString c1LengthSplPath      = c1Length_V + splPath;
+const QString c2LengthSplPath      = c2Length_V + splPath;
+const QString angle1Arc_           = angle1_V + arc_;
+const QString angle2Arc_           = angle2_V + arc_;
+const QString angle1Spl_           = angle1_V + spl_;
+const QString angle2Spl_           = angle2_V + spl_;
+const QString angle1SplPath        = angle1_V + splPath;
+const QString angle2SplPath        = angle2_V + splPath;
+const QString seg_                 = QStringLiteral("Seg_");
+const QString currentLength        = QStringLiteral("CurrentLength");
+const QString currentSeamAllowance = QStringLiteral("CurrentSeamAllowance");
 
 const QStringList builInVariables = QStringList() << line_
                                                   << angleLine_
@@ -204,6 +206,7 @@ const QStringList builInVariables = QStringList() << line_
                                                   << angle2SplPath
                                                   << seg_
                                                   << currentLength
+                                                  << currentSeamAllowance
                                                   << c1LengthSpl_
                                                   << c2LengthSpl_
                                                   << c1LengthSplPath
diff --git a/src/libs/ifc/ifcdef.h b/src/libs/ifc/ifcdef.h
index dfc86eb6b..143fee251 100644
--- a/src/libs/ifc/ifcdef.h
+++ b/src/libs/ifc/ifcdef.h
@@ -140,6 +140,7 @@ extern const QString AttrArc;
 extern const QString AttrSuffix;
 extern const QString AttrIdObject;
 extern const QString AttrInLayout;
+extern const QString AttrClosed;
 
 extern const QString TypeLineNone;
 extern const QString TypeLineLine;
@@ -196,6 +197,7 @@ extern const QString angle1SplPath;
 extern const QString angle2SplPath;
 extern const QString seg_;
 extern const QString currentLength;
+extern const QString currentSeamAllowance;
 
 extern const QStringList builInVariables;
 
diff --git a/src/libs/ifc/schema.qrc b/src/libs/ifc/schema.qrc
index 50b5d4de9..aa5a46d40 100644
--- a/src/libs/ifc/schema.qrc
+++ b/src/libs/ifc/schema.qrc
@@ -23,6 +23,7 @@
         <file>schema/pattern/v0.3.7.xsd</file>
         <file>schema/pattern/v0.3.8.xsd</file>
         <file>schema/pattern/v0.3.9.xsd</file>
+        <file>schema/pattern/v0.4.0.xsd</file>
         <file>schema/standard_measurements/v0.3.0.xsd</file>
         <file>schema/standard_measurements/v0.4.0.xsd</file>
         <file>schema/standard_measurements/v0.4.1.xsd</file>
diff --git a/src/libs/ifc/schema/individual_measurements/v0.3.3.xsd b/src/libs/ifc/schema/individual_measurements/v0.3.3.xsd
index 489ebd973..044a44471 100644
--- a/src/libs/ifc/schema/individual_measurements/v0.3.3.xsd
+++ b/src/libs/ifc/schema/individual_measurements/v0.3.3.xsd
@@ -1,72 +1,72 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
-	<xs:element name="vit">
-		<xs:complexType>
-			<xs:sequence>
-				<xs:element name="version" type="formatVersion"></xs:element>
-				<xs:element name="read-only" type="xs:boolean"></xs:element>
-				<xs:element name="notes" type="xs:string" minOccurs="0" maxOccurs="1"></xs:element>
-				<xs:element name="unit" type="units"></xs:element>
-				<xs:element name="pm_system" type="psCode"></xs:element>
-				<xs:element name="personal">
-					<xs:complexType>
-						<xs:sequence>
-							<xs:element name="family-name" type="xs:string"></xs:element>
-							<xs:element name="given-name" type="xs:string"></xs:element>
-							<xs:element name="birth-date" type="xs:date"></xs:element>
-							<xs:element name="gender" type="gender"></xs:element>
-							<xs:element name="email" type="xs:string"></xs:element>
-					   </xs:sequence>
-					</xs:complexType>
-				</xs:element>
-				<xs:element name="body-measurements">
-					<xs:complexType>
-						<xs:sequence>
-							<xs:element name="m" minOccurs="0" maxOccurs="unbounded">
-								<xs:complexType>
-									<xs:attribute name="name" type="shortName" use="required"></xs:attribute>
-									<xs:attribute name="value" type="xs:string" use="required"></xs:attribute>
-									<xs:attribute name="full_name" type="xs:string"></xs:attribute>
-									<xs:attribute name="description" type="xs:string"></xs:attribute>
-								</xs:complexType>
-							</xs:element>
-						</xs:sequence>
-					</xs:complexType>
-				</xs:element>
-			</xs:sequence>
-		</xs:complexType>
-		<xs:unique name="measurementName">
-			<xs:selector xpath="body-measurements/m"/>
-			<xs:field xpath="@name"/>
-		</xs:unique>
-	</xs:element>
-	<xs:simpleType name="shortName">
-		<xs:restriction base="xs:string">   
-			<xs:pattern value="^([^\p{Nd}\p{Zs}*/&amp;|!&lt;&gt;^\-()–+−=?:;'\&quot;]){1,1}([^\p{Zs}*/&amp;|!&lt;&gt;^\-()–+−=?:;\&quot;]){0,}$"/>
-		</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: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="gender">
-		<xs:restriction base="xs:string">
-			<xs:enumeration value="unknown"/>
-			<xs:enumeration value="male"/>
-			<xs:enumeration value="female"/>
-		</xs:restriction>
-	</xs:simpleType>
-	<xs:simpleType name="psCode">
-		<xs:restriction base="xs:string">
-			<xs:pattern value="^^(([0-9]|[1-4][0-9]|5[0-4])|998)$"/>
-		</xs:restriction>
-	</xs:simpleType>
+  <xs:element name="vit">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="version" type="formatVersion"/>
+        <xs:element name="read-only" type="xs:boolean"/>
+        <xs:element name="notes" type="xs:string" minOccurs="0" maxOccurs="1"/>
+        <xs:element name="unit" type="units"/>
+        <xs:element name="pm_system" type="psCode"/>
+        <xs:element name="personal">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="family-name" type="xs:string"/>
+              <xs:element name="given-name" type="xs:string"/>
+              <xs:element name="birth-date" type="xs:date"/>
+              <xs:element name="gender" type="gender"/>
+              <xs:element name="email" type="xs:string"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+        <xs:element name="body-measurements">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="m" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                  <xs:attribute name="name" type="shortName" use="required"/>
+                  <xs:attribute name="value" type="xs:string" use="required"/>
+                  <xs:attribute name="full_name" type="xs:string"/>
+                  <xs:attribute name="description" type="xs:string"/>
+                </xs:complexType>
+              </xs:element>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+    <xs:unique name="measurementName">
+      <xs:selector xpath="body-measurements/m"/>
+      <xs:field xpath="@name"/>
+    </xs:unique>
+  </xs:element>
+  <xs:simpleType name="shortName">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="^([^\p{Nd}\p{Zs}*/&amp;|!&lt;&gt;^\-()–+−=?:;'\&quot;]){1,1}([^\p{Zs}*/&amp;|!&lt;&gt;^\-()–+−=?:;\&quot;]){0,}$"/>
+    </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: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="gender">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="unknown"/>
+      <xs:enumeration value="male"/>
+      <xs:enumeration value="female"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="psCode">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="^^(([0-9]|[1-4][0-9]|5[0-4])|998)$"/>
+    </xs:restriction>
+  </xs:simpleType>
 </xs:schema>
diff --git a/src/libs/ifc/schema/pattern/v0.3.9.xsd b/src/libs/ifc/schema/pattern/v0.3.9.xsd
index bd98bd5e3..0cecf1409 100644
--- a/src/libs/ifc/schema/pattern/v0.3.9.xsd
+++ b/src/libs/ifc/schema/pattern/v0.3.9.xsd
@@ -416,7 +416,7 @@
                                                                                        <xs:attribute name="my" type="xs:double"></xs:attribute>
                                                                                        <xs:attribute name="length" type="xs:string"></xs:attribute>
                                                                                        <xs:attribute name="rotation" type="xs:string"></xs:attribute>
-										       <xs:attribute name="arrows" type="arrowType"></xs:attribute>
+                                                                                       <xs:attribute name="arrows" type="arrowType"></xs:attribute>
                                                                                     </xs:complexType>
                                                                                </xs:element>
                                                                                <xs:element name="node" maxOccurs="unbounded">
diff --git a/src/libs/ifc/schema/pattern/v0.4.0.xsd b/src/libs/ifc/schema/pattern/v0.4.0.xsd
new file mode 100644
index 000000000..bcb5da26f
--- /dev/null
+++ b/src/libs/ifc/schema/pattern/v0.4.0.xsd
@@ -0,0 +1,817 @@
+<?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 name="unit" type="units"/>
+        <xs:element name="image" minOccurs="0" maxOccurs="1">
+          <xs:complexType>
+            <xs:simpleContent>
+              <xs:extension base="xs:string">
+                <xs:attribute name="extension" type="imageExtension"/>
+              </xs:extension>
+            </xs:simpleContent>
+          </xs:complexType>
+        </xs:element>
+        <xs:element name="author" type="xs:string" minOccurs="0" maxOccurs="1"/>
+        <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"/>
+        <xs:element name="notes" type="xs:string" minOccurs="0" maxOccurs="1"/>
+        <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 name="h50" type="xs:boolean"/>
+                  <xs:attribute name="h56" type="xs:boolean"/>
+                  <xs:attribute name="h62" type="xs:boolean"/>
+                  <xs:attribute name="h68" type="xs:boolean"/>
+                  <xs:attribute name="h74" type="xs:boolean"/>
+                  <xs:attribute name="h80" type="xs:boolean"/>
+                  <xs:attribute name="h86" type="xs:boolean"/>
+                  <xs:attribute name="h92" type="xs:boolean"/>
+                  <xs:attribute name="h98" type="xs:boolean"/>
+                  <xs:attribute name="h104" type="xs:boolean"/>
+                  <xs:attribute name="h110" type="xs:boolean"/>
+                  <xs:attribute name="h116" type="xs:boolean"/>
+                  <xs:attribute name="h122" type="xs:boolean"/>
+                  <xs:attribute name="h128" type="xs:boolean"/>
+                  <xs:attribute name="h134" type="xs:boolean"/>
+                  <xs:attribute name="h140" type="xs:boolean"/>
+                  <xs:attribute name="h146" type="xs:boolean"/>
+                  <xs:attribute name="h152" type="xs:boolean"/>
+                  <xs:attribute name="h158" type="xs:boolean"/>
+                  <xs:attribute name="h164" type="xs:boolean"/>
+                  <xs:attribute name="h170" type="xs:boolean"/>
+                  <xs:attribute name="h176" type="xs:boolean"/>
+                  <xs:attribute name="h182" type="xs:boolean"/>
+                  <xs:attribute name="h188" type="xs:boolean"/>
+                  <xs:attribute name="h194" type="xs:boolean"/>
+                </xs:complexType>
+              </xs:element>
+              <xs:element name="sizes">
+                <xs:complexType>
+                  <xs:attribute name="all" type="xs:boolean" use="required"/>
+                  <xs:attribute name="s22" type="xs:boolean"/>
+                  <xs:attribute name="s24" type="xs:boolean"/>
+                  <xs:attribute name="s26" type="xs:boolean"/>
+                  <xs:attribute name="s28" type="xs:boolean"/>
+                  <xs:attribute name="s30" type="xs:boolean"/>
+                  <xs:attribute name="s32" type="xs:boolean"/>
+                  <xs:attribute name="s34" type="xs:boolean"/>
+                  <xs:attribute name="s36" type="xs:boolean"/>
+                  <xs:attribute name="s38" type="xs:boolean"/>
+                  <xs:attribute name="s40" type="xs:boolean"/>
+                  <xs:attribute name="s42" type="xs:boolean"/>
+                  <xs:attribute name="s44" type="xs:boolean"/>
+                  <xs:attribute name="s46" type="xs:boolean"/>
+                  <xs:attribute name="s48" type="xs:boolean"/>
+                  <xs:attribute name="s50" type="xs:boolean"/>
+                  <xs:attribute name="s52" type="xs:boolean"/>
+                  <xs:attribute name="s54" type="xs:boolean"/>
+                  <xs:attribute name="s56" type="xs:boolean"/>
+                </xs:complexType>
+              </xs:element>
+            </xs:sequence>
+            <xs:attribute name="custom" type="xs:boolean"/>
+            <xs:attribute name="defHeight" type="baseHeight"/>
+            <xs:attribute name="defSize" type="baseSize"/>
+          </xs:complexType>
+        </xs:element>
+        <xs:element name="patternName" type="xs:string" minOccurs="0" maxOccurs="1"/>
+        <xs:element name="patternNumber" type="xs:string" minOccurs="0" maxOccurs="1"/>
+        <xs:element name="company" type="xs:string" minOccurs="0" maxOccurs="1"/>
+        <xs:element name="customer" type="xs:string" minOccurs="0" maxOccurs="1"/>
+        <xs:element name="size" type="xs:string" minOccurs="0" maxOccurs="1"/>
+        <xs:element name="showDate" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+        <xs:element name="showMeasurements" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+        <xs:element name="measurements" type="xs:string"/>
+        <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="description" type="xs:string" use="required"/>
+                  <xs:attribute name="name" type="shortName" use="required"/>
+                  <xs:attribute name="formula" type="xs:string" use="required"/>
+                </xs:complexType>
+              </xs:element>
+            </xs:sequence>
+          </xs:complexType>
+          <xs:unique name="incrementName">
+            <xs:selector xpath="increment"/>
+            <xs:field xpath="@name"/>
+          </xs:unique>
+        </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 name="x" type="xs:double"/>
+                          <xs:attribute name="y" type="xs:double"/>
+                          <xs:attribute name="mx" type="xs:double"/>
+                          <xs:attribute name="my" type="xs:double"/>
+                          <xs:attribute name="type" type="xs:string"/>
+                          <xs:attribute name="name" type="shortName"/>
+                          <xs:attribute name="firstPoint" type="xs:unsignedInt"/>
+                          <xs:attribute name="secondPoint" type="xs:unsignedInt"/>
+                          <xs:attribute name="thirdPoint" type="xs:unsignedInt"/>
+                          <xs:attribute name="basePoint" type="xs:unsignedInt"/>
+                          <xs:attribute name="pShoulder" type="xs:unsignedInt"/>
+                          <xs:attribute name="p1Line" type="xs:unsignedInt"/>
+                          <xs:attribute name="p2Line" type="xs:unsignedInt"/>
+                          <xs:attribute name="length" type="xs:string"/>
+                          <xs:attribute name="angle" type="xs:string"/>
+                          <xs:attribute name="typeLine" type="xs:string"/>
+                          <xs:attribute name="splinePath" type="xs:unsignedInt"/>
+                          <xs:attribute name="spline" type="xs:unsignedInt"/>
+                          <xs:attribute name="p1Line1" type="xs:unsignedInt"/>
+                          <xs:attribute name="p1Line2" type="xs:unsignedInt"/>
+                          <xs:attribute name="p2Line1" type="xs:unsignedInt"/>
+                          <xs:attribute name="p2Line2" type="xs:unsignedInt"/>
+                          <xs:attribute name="center" type="xs:unsignedInt"/>
+                          <xs:attribute name="radius" type="xs:string"/>
+                          <xs:attribute name="axisP1" type="xs:unsignedInt"/>
+                          <xs:attribute name="axisP2" type="xs:unsignedInt"/>
+                          <xs:attribute name="arc" type="xs:unsignedInt"/>
+                          <xs:attribute name="elArc" type="xs:unsignedInt"/>
+                          <xs:attribute name="curve" type="xs:unsignedInt"/>
+                          <xs:attribute name="curve1" type="xs:unsignedInt"/>
+                          <xs:attribute name="curve2" type="xs:unsignedInt"/>
+                          <xs:attribute name="lineColor" type="colors"/>
+                          <xs:attribute name="color" type="colors"/>
+                          <xs:attribute name="firstArc" type="xs:unsignedInt"/>
+                          <xs:attribute name="secondArc" type="xs:unsignedInt"/>
+                          <xs:attribute name="crossPoint" type="crossType"/>
+                          <xs:attribute name="vCrossPoint" type="crossType"/>
+                          <xs:attribute name="hCrossPoint" type="crossType"/>
+                          <xs:attribute name="c1Center" type="xs:unsignedInt"/>
+                          <xs:attribute name="c2Center" type="xs:unsignedInt"/>
+                          <xs:attribute name="c1Radius" type="xs:string"/>
+                          <xs:attribute name="c2Radius" type="xs:string"/>
+                          <xs:attribute name="cRadius" type="xs:string"/>
+                          <xs:attribute name="tangent" type="xs:unsignedInt"/>
+                          <xs:attribute name="cCenter" type="xs:unsignedInt"/>
+                          <xs:attribute name="name1" type="shortName"/>
+                          <xs:attribute name="mx1" type="xs:double"/>
+                          <xs:attribute name="my1" type="xs:double"/>
+                          <xs:attribute name="name2" type="shortName"/>
+                          <xs:attribute name="mx2" type="xs:double"/>
+                          <xs:attribute name="my2" type="xs:double"/>
+                          <xs:attribute name="point1" type="xs:unsignedInt"/>
+                          <xs:attribute name="point2" type="xs:unsignedInt"/>
+                          <xs:attribute name="dartP1" type="xs:unsignedInt"/>
+                          <xs:attribute name="dartP2" type="xs:unsignedInt"/>
+                          <xs:attribute name="dartP3" type="xs:unsignedInt"/>
+                          <xs:attribute name="baseLineP1" type="xs:unsignedInt"/>
+                          <xs:attribute name="baseLineP2" type="xs:unsignedInt"/>
+                        </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 name="firstPoint" type="xs:unsignedInt"/>
+                          <xs:attribute name="secondPoint" type="xs:unsignedInt"/>
+                          <xs:attribute name="typeLine" type="xs:string"/>
+                          <xs:attribute name="lineColor" type="colors"/>
+                        </xs:complexType>
+                      </xs:element>
+                      <xs:element name="operation" minOccurs="0" maxOccurs="unbounded">
+                        <xs:complexType>
+                          <xs:sequence>
+                            <xs:element name="source" minOccurs="1" maxOccurs="1">
+                              <xs:complexType>
+                                <xs:sequence>
+                                  <xs:element name="item" minOccurs="1" maxOccurs="unbounded">
+                                    <xs:complexType>
+                                      <xs:attribute name="idObject" type="xs:unsignedInt" use="required"/>
+                                    </xs:complexType>
+                                  </xs:element>
+                                </xs:sequence>
+                              </xs:complexType>
+                            </xs:element>
+                            <xs:element name="destination" minOccurs="1" maxOccurs="1">
+                              <xs:complexType>
+                                <xs:sequence>
+                                  <xs:element name="item" minOccurs="1" maxOccurs="unbounded">
+                                    <xs:complexType>
+                                      <xs:attribute name="idObject" type="xs:unsignedInt" use="required"/>
+                                      <xs:attribute name="mx" type="xs:double"/>
+                                      <xs:attribute name="my" type="xs:double"/>
+                                    </xs:complexType>
+                                  </xs:element>
+                                </xs:sequence>
+                              </xs:complexType>
+                            </xs:element>
+                          </xs:sequence>
+                          <xs:attribute name="id" type="xs:unsignedInt" use="required"/>
+                          <xs:attribute name="center" type="xs:unsignedInt"/>
+                          <xs:attribute name="angle" type="xs:string"/>
+                          <xs:attribute name="length" type="xs:string"/>
+                          <xs:attribute name="suffix" type="xs:string"/>
+                          <xs:attribute name="type" type="xs:string" use="required"/>
+                          <xs:attribute name="p1Line" type="xs:unsignedInt"/>
+                          <xs:attribute name="p2Line" type="xs:unsignedInt"/>
+                          <xs:attribute name="axisType" type="axisType"/>
+                        </xs:complexType>
+                      </xs:element>
+                      <xs:element name="arc" minOccurs="0" maxOccurs="unbounded">
+                        <xs:complexType>
+                          <xs:attribute name="angle1" type="xs:string"/>
+                          <xs:attribute name="id" type="xs:unsignedInt" use="required"/>
+                          <xs:attribute name="angle2" type="xs:string"/>
+                          <xs:attribute name="radius" type="xs:string"/>
+                          <xs:attribute name="center" type="xs:unsignedInt"/>
+                          <xs:attribute name="type" type="xs:string"/>
+                          <xs:attribute name="color" type="colors"/>
+                          <xs:attribute name="length" type="xs:string"/>
+                        </xs:complexType>
+                      </xs:element>
+                      <xs:element name="elArc" minOccurs="0" maxOccurs="unbounded">
+                        <xs:complexType>
+                          <xs:attribute name="angle1" type="xs:string"/>
+                          <xs:attribute name="id" type="xs:unsignedInt" use="required"/>
+                          <xs:attribute name="angle2" type="xs:string"/>
+                          <xs:attribute name="rotationAngle" type="xs:string"/>
+                          <xs:attribute name="radius1" type="xs:string"/>
+                          <xs:attribute name="radius2" type="xs:string"/>
+                          <xs:attribute name="center" type="xs:unsignedInt"/>
+                          <xs:attribute name="type" type="xs:string"/>
+                          <xs:attribute name="color" type="colors"/>
+                          <xs:attribute name="length" type="xs:string"/>
+                        </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 name="pSpline" type="xs:unsignedInt"/>
+                                <xs:attribute name="angle" type="xs:string"/>
+                                <xs:attribute name="angle1" type="xs:string"/>
+                                <xs:attribute name="angle2" type="xs:string"/>
+                                <xs:attribute name="length1" type="xs:string"/>
+                                <xs:attribute name="length2" type="xs:string"/>
+                                <xs:attribute name="kAsm1" type="xs:string"/>
+                              </xs:complexType>
+                            </xs:element>
+                          </xs:sequence>
+                          <xs:attribute name="id" type="xs:unsignedInt" use="required"/>
+                          <xs:attribute name="kCurve" type="xs:double"/>
+                          <xs:attribute name="type" type="xs:string"/>
+                          <xs:attribute name="kAsm1" type="xs:double"/>
+                          <xs:attribute name="kAsm2" type="xs:double"/>
+                          <xs:attribute name="angle1" type="xs:string"/>
+                          <xs:attribute name="angle2" type="xs:string"/>
+                          <xs:attribute name="length1" type="xs:string"/>
+                          <xs:attribute name="length2" type="xs:string"/>
+                          <xs:attribute name="point1" type="xs:unsignedInt"/>
+                          <xs:attribute name="point2" type="xs:unsignedInt"/>
+                          <xs:attribute name="point3" type="xs:unsignedInt"/>
+                          <xs:attribute name="point4" type="xs:unsignedInt"/>
+                          <xs:attribute name="color" type="colors"/>
+                          <xs:attribute name="duplicate" type="xs:unsignedInt"/>
+                        </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 name="idObject" type="xs:unsignedInt"/>
+                          <xs:attribute name="mx" type="xs:double"/>
+                          <xs:attribute name="my" type="xs:double"/>
+                          <xs:attribute name="type" type="xs:string"/>
+                          <xs:attribute name="idTool" type="xs:unsignedInt"/>
+                          <xs:attribute name="inUse" type="xs:boolean"/>
+                        </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 name="idObject" type="xs:unsignedInt"/>
+                          <xs:attribute name="type" type="xs:string"/>
+                          <xs:attribute name="idTool" type="xs:unsignedInt"/>
+                          <xs:attribute name="inUse" type="xs:boolean"/>
+                        </xs:complexType>
+                      </xs:element>
+                      <xs:element name="elArc" minOccurs="0" maxOccurs="unbounded">
+                        <xs:complexType>
+                          <xs:attribute name="id" type="xs:unsignedInt" use="required"/>
+                          <xs:attribute name="idObject" type="xs:unsignedInt"/>
+                          <xs:attribute name="type" type="xs:string"/>
+                          <xs:attribute name="idTool" type="xs:unsignedInt"/>
+                          <xs:attribute name="inUse" type="xs:boolean"/>
+                        </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 name="idObject" type="xs:unsignedInt"/>
+                          <xs:attribute name="type" type="xs:string"/>
+                          <xs:attribute name="idTool" type="xs:unsignedInt"/>
+                          <xs:attribute name="inUse" type="xs:boolean"/>
+                        </xs:complexType>
+                      </xs:element>
+                      <xs:element name="path" minOccurs="0" maxOccurs="unbounded">
+                        <xs:complexType>
+                          <xs:sequence>
+                            <xs:element name="nodes" minOccurs="1" maxOccurs="1">
+                              <xs:complexType>
+                                <xs:sequence>
+                                  <xs:element name="node" minOccurs="1" maxOccurs="unbounded">
+                                    <xs:complexType>
+                                      <xs:attribute name="type" type="xs:string" use="required"/>
+                                      <xs:attribute name="idObject" type="xs:unsignedInt" use="required"/>
+                                      <xs:attribute name="reverse" type="xs:unsignedInt"/>
+                                      <xs:attribute name="before" type="xs:double"/>
+                                      <xs:attribute name="after" type="xs:double"/>
+                                      <xs:attribute name="angle" type="nodeAngle"/>
+                                    </xs:complexType>
+                                  </xs:element>
+                                </xs:sequence>
+                              </xs:complexType>
+                            </xs:element>
+                          </xs:sequence>
+                          <xs:attribute name="id" type="xs:unsignedInt" use="required"/>
+                          <xs:attribute name="type" type="piecePathType"/>
+                          <xs:attribute name="idTool" type="xs:unsignedInt"/>
+                          <xs:attribute name="inUse" type="xs:boolean"/>
+                          <xs:attribute name="name" type="xs:string"/>
+                          <xs:attribute name="typeLine" type="xs:string"/>
+                        </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="nodes" minOccurs="1" maxOccurs="1">
+                                    <xs:complexType>
+                                      <xs:sequence>
+                                        <xs:element name="node" minOccurs="1" maxOccurs="unbounded">
+                                          <xs:complexType>
+                                            <xs:attribute name="type" type="xs:string" use="required"/>
+                                            <xs:attribute name="idObject" type="xs:unsignedInt" use="required"/>
+                                            <xs:attribute name="reverse" type="xs:unsignedInt"/>
+                                            <xs:attribute name="before" type="xs:string"/>
+                                            <xs:attribute name="after" type="xs:string"/>
+                                            <xs:attribute name="angle" type="nodeAngle"/>
+                                          </xs:complexType>
+                                        </xs:element>
+                                      </xs:sequence>
+                                    </xs:complexType>
+                                  </xs:element>
+                                  <xs:element name="csa" minOccurs="0" maxOccurs="1">
+                                    <xs:complexType>
+                                      <xs:sequence>
+                                        <xs:element name="record" minOccurs="1" maxOccurs="unbounded">
+                                          <xs:complexType>
+                                            <xs:attribute name="start" type="xs:unsignedInt"/>
+                                            <xs:attribute name="path" type="xs:unsignedInt" use="required"/>
+                                            <xs:attribute name="end" type="xs:unsignedInt"/>
+                                            <xs:attribute name="reverse" type="xs:boolean"/>
+                                            <xs:attribute name="includeAs" type="piecePathIncludeType"/>
+                                          </xs:complexType>
+                                        </xs:element>
+                                      </xs:sequence>
+                                    </xs:complexType>
+                                  </xs:element>
+                                  <xs:element name="iPaths" minOccurs="0" maxOccurs="1">
+                                    <xs:complexType>
+                                      <xs:sequence>
+                                        <xs:element name="record" minOccurs="1" maxOccurs="unbounded">
+                                          <xs:complexType>
+                                            <xs:attribute name="path" type="xs:unsignedInt" use="required"/>
+                                          </xs:complexType>
+                                        </xs:element>
+                                      </xs:sequence>
+                                    </xs:complexType>
+                                  </xs:element>
+                                </xs:sequence>
+                              </xs:complexType>
+                            </xs:element>
+                            <xs:element name="children" minOccurs="1" maxOccurs="1">
+                              <xs:complexType>
+                                <xs:sequence>
+                                  <xs:element name="nodes" minOccurs="1" maxOccurs="1">
+                                    <xs:complexType>
+                                      <xs:sequence>
+                                        <xs:element name="child" type="xs:unsignedInt" minOccurs="1" maxOccurs="unbounded"/>
+                                      </xs:sequence>
+                                    </xs:complexType>
+                                  </xs:element>
+                                  <xs:element name="csa" minOccurs="0" maxOccurs="1">
+                                    <xs:complexType>
+                                      <xs:sequence>
+                                        <xs:element name="child" type="xs:unsignedInt" minOccurs="1" maxOccurs="unbounded"/>
+                                      </xs:sequence>
+                                    </xs:complexType>
+                                  </xs:element>
+                                  <xs:element name="iPaths" minOccurs="0" maxOccurs="1">
+                                    <xs:complexType>
+                                      <xs:sequence>
+                                        <xs:element name="child" type="xs:unsignedInt" minOccurs="1" maxOccurs="unbounded"/>
+                                      </xs:sequence>
+                                    </xs:complexType>
+                                  </xs:element>
+                                </xs:sequence>
+                              </xs:complexType>
+                            </xs:element>
+                          </xs:sequence>
+                          <xs:attribute name="id" type="xs:unsignedInt" use="required"/>
+                          <xs:attribute name="type" type="xs:string"/>
+                          <xs:attribute name="indexD1" type="xs:unsignedInt"/>
+                          <xs:attribute name="indexD2" type="xs:unsignedInt"/>
+                          <xs:attribute name="inUse" type="xs:boolean"/>
+                        </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="data" minOccurs="0" maxOccurs="1">
+                            <xs:complexType>
+                              <xs:sequence>
+                                <xs:element name="mcp" minOccurs="0" maxOccurs="unbounded">
+                                  <xs:complexType>
+                                    <xs:attribute name="cutNumber" type="xs:unsignedInt"/>
+                                    <xs:attribute name="userDef" type="xs:string"/>
+                                    <xs:attribute name="material" type="materialType"/>
+                                    <xs:attribute name="placement" type="placementType"/>
+                                  </xs:complexType>
+                                </xs:element>
+                              </xs:sequence>
+                              <xs:attribute name="letter" type="xs:string"/>
+                              <xs:attribute name="visible" type="xs:boolean"/>
+                              <xs:attribute name="fontSize" type="xs:unsignedInt"/>
+                              <xs:attribute name="mx" type="xs:double"/>
+                              <xs:attribute name="my" type="xs:double"/>
+                              <xs:attribute name="width" type="xs:double"/>
+                              <xs:attribute name="height" type="xs:double"/>
+                              <xs:attribute name="rotation" type="xs:double"/>
+                            </xs:complexType>
+                          </xs:element>
+                          <xs:element name="patternInfo" minOccurs="0" maxOccurs="1">
+                            <xs:complexType>
+                              <xs:attribute name="visible" type="xs:boolean"/>
+                              <xs:attribute name="fontSize" type="xs:unsignedInt"/>
+                              <xs:attribute name="mx" type="xs:double"/>
+                              <xs:attribute name="my" type="xs:double"/>
+                              <xs:attribute name="width" type="xs:double"/>
+                              <xs:attribute name="height" type="xs:double"/>
+                              <xs:attribute name="rotation" type="xs:double"/>
+                            </xs:complexType>
+                          </xs:element>
+                          <xs:element name="grainline" minOccurs="0" maxOccurs="1">
+                            <xs:complexType>
+                              <xs:attribute name="visible" type="xs:boolean"/>
+                              <xs:attribute name="mx" type="xs:double"/>
+                              <xs:attribute name="my" type="xs:double"/>
+                              <xs:attribute name="length" type="xs:string"/>
+                              <xs:attribute name="rotation" type="xs:string"/>
+                              <xs:attribute name="arrows" type="arrowType"/>
+                            </xs:complexType>
+                          </xs:element>
+                          <xs:element name="nodes" minOccurs="1" maxOccurs="1">
+                            <xs:complexType>
+                              <xs:sequence>
+                                <xs:element name="node" minOccurs="1" maxOccurs="unbounded">
+                                  <xs:complexType>
+                                    <xs:attribute name="type" type="xs:string" use="required"/>
+                                    <xs:attribute name="idObject" type="xs:unsignedInt" use="required"/>
+                                    <xs:attribute name="reverse" type="xs:unsignedInt"/>
+                                    <xs:attribute name="before" type="xs:string"/>
+                                    <xs:attribute name="after" type="xs:string"/>
+                                    <xs:attribute name="angle" type="nodeAngle"/>
+                                    <xs:attribute name="mx" type="xs:double"/>
+                                    <xs:attribute name="my" type="xs:double"/>
+                                  </xs:complexType>
+                                </xs:element>
+                              </xs:sequence>
+                            </xs:complexType>
+                          </xs:element>
+                          <xs:element name="csa" minOccurs="0" maxOccurs="1">
+                            <xs:complexType>
+                              <xs:sequence>
+                                <xs:element name="record" minOccurs="1" maxOccurs="unbounded">
+                                  <xs:complexType>
+                                    <xs:attribute name="start" type="xs:unsignedInt"/>
+                                    <xs:attribute name="path" type="xs:unsignedInt" use="required"/>
+                                    <xs:attribute name="end" type="xs:unsignedInt"/>
+                                    <xs:attribute name="reverse" type="xs:boolean"/>
+                                    <xs:attribute name="includeAs" type="piecePathIncludeType"/>
+                                  </xs:complexType>
+                                </xs:element>
+                              </xs:sequence>
+                            </xs:complexType>
+                          </xs:element>
+                          <xs:element name="iPaths" minOccurs="0" maxOccurs="1">
+                            <xs:complexType>
+                              <xs:sequence>
+                                <xs:element name="record" minOccurs="1" maxOccurs="unbounded">
+                                  <xs:complexType>
+                                    <xs:attribute name="path" type="xs:unsignedInt" use="required"/>
+                                  </xs:complexType>
+                                </xs:element>
+                              </xs:sequence>
+                            </xs:complexType>
+                          </xs:element>
+                        </xs:sequence>
+                        <xs:attribute name="id" type="xs:unsignedInt" use="required"/>
+                        <xs:attribute name="version" type="pieceVersion"/>
+                        <xs:attribute name="mx" type="xs:double"/>
+                        <xs:attribute name="my" type="xs:double"/>
+                        <xs:attribute name="name" type="xs:string"/>
+                        <xs:attribute name="inLayout" type="xs:boolean"/>
+                        <xs:attribute name="forbidFlipping" type="xs:boolean"/>
+                        <xs:attribute name="width" type="xs:string"/>
+                        <xs:attribute name="seamAllowance" type="xs:boolean"/>
+                        <xs:attribute name="united" type="xs:boolean"/>
+                        <xs:attribute name="closed" type="xs:unsignedInt"/>
+                      </xs:complexType>
+                    </xs:element>
+                  </xs:sequence>
+                </xs:complexType>
+              </xs:element>
+              <xs:element name="groups" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                  <xs:sequence>
+                    <xs:element name="group" minOccurs="0" maxOccurs="unbounded">
+                      <xs:complexType>
+                        <xs:sequence>
+                          <xs:element name="item" maxOccurs="unbounded">
+                            <xs:complexType>
+                              <xs:attribute name="object" type="xs:unsignedInt"/>
+                              <xs:attribute name="tool" type="xs:unsignedInt"/>
+                            </xs:complexType>
+                          </xs:element>
+                        </xs:sequence>
+                        <xs:attribute name="id" type="xs:unsignedInt" use="required"/>
+                        <xs:attribute name="name" type="xs:string"/>
+                        <xs:attribute name="visible" type="xs:boolean"/>
+                      </xs:complexType>
+                    </xs:element>
+                  </xs:sequence>
+                </xs:complexType>
+              </xs:element>
+            </xs:sequence>
+            <xs:attribute name="name" type="xs:string"/>
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+      <xs:attribute name="readOnly" type="xs:boolean"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:simpleType name="shortName">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="^([^\p{Nd}\p{Zs}*/&amp;|!&lt;&gt;^\-()–+−=?:;'\&quot;]){1,1}([^\p{Zs}*/&amp;|!&lt;&gt;^\-()–+−=?:;\&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:simpleType name="imageExtension">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="PNG"/>
+      <xs:enumeration value="JPG"/>
+      <xs:enumeration value="BMP"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="colors">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="black"/>
+      <xs:enumeration value="green"/>
+      <xs:enumeration value="blue"/>
+      <xs:enumeration value="darkRed"/>
+      <xs:enumeration value="darkGreen"/>
+      <xs:enumeration value="darkBlue"/>
+      <xs:enumeration value="yellow"/>
+      <xs:enumeration value="lightsalmon"/>
+      <xs:enumeration value="goldenrod"/>
+      <xs:enumeration value="orange"/>
+      <xs:enumeration value="deeppink"/>
+      <xs:enumeration value="violet"/>
+      <xs:enumeration value="darkviolet"/>
+      <xs:enumeration value="mediumseagreen"/>
+      <xs:enumeration value="lime"/>
+      <xs:enumeration value="deepskyblue"/>
+      <xs:enumeration value="cornflowerblue"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="baseHeight">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="50"/>
+      <xs:enumeration value="56"/>
+      <xs:enumeration value="62"/>
+      <xs:enumeration value="68"/>
+      <xs:enumeration value="74"/>
+      <xs:enumeration value="80"/>
+      <xs:enumeration value="86"/>
+      <xs:enumeration value="92"/>
+      <xs:enumeration value="98"/>
+      <xs:enumeration value="104"/>
+      <xs:enumeration value="110"/>
+      <xs:enumeration value="116"/>
+      <xs:enumeration value="122"/>
+      <xs:enumeration value="128"/>
+      <xs:enumeration value="134"/>
+      <xs:enumeration value="140"/>
+      <xs:enumeration value="146"/>
+      <xs:enumeration value="152"/>
+      <xs:enumeration value="158"/>
+      <xs:enumeration value="164"/>
+      <xs:enumeration value="170"/>
+      <xs:enumeration value="176"/>
+      <xs:enumeration value="182"/>
+      <xs:enumeration value="188"/>
+      <xs:enumeration value="194"/>
+      <xs:enumeration value="500"/>
+      <xs:enumeration value="560"/>
+      <xs:enumeration value="620"/>
+      <xs:enumeration value="680"/>
+      <xs:enumeration value="740"/>
+      <xs:enumeration value="800"/>
+      <xs:enumeration value="860"/>
+      <xs:enumeration value="920"/>
+      <xs:enumeration value="980"/>
+      <xs:enumeration value="1040"/>
+      <xs:enumeration value="1100"/>
+      <xs:enumeration value="1160"/>
+      <xs:enumeration value="1220"/>
+      <xs:enumeration value="1280"/>
+      <xs:enumeration value="1340"/>
+      <xs:enumeration value="1400"/>
+      <xs:enumeration value="1460"/>
+      <xs:enumeration value="1520"/>
+      <xs:enumeration value="1580"/>
+      <xs:enumeration value="1640"/>
+      <xs:enumeration value="1700"/>
+      <xs:enumeration value="1760"/>
+      <xs:enumeration value="1820"/>
+      <xs:enumeration value="1880"/>
+      <xs:enumeration value="1940"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="baseSize">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="22"/>
+      <xs:enumeration value="24"/>
+      <xs:enumeration value="26"/>
+      <xs:enumeration value="28"/>
+      <xs:enumeration value="30"/>
+      <xs:enumeration value="32"/>
+      <xs:enumeration value="34"/>
+      <xs:enumeration value="36"/>
+      <xs:enumeration value="38"/>
+      <xs:enumeration value="40"/>
+      <xs:enumeration value="42"/>
+      <xs:enumeration value="44"/>
+      <xs:enumeration value="46"/>
+      <xs:enumeration value="48"/>
+      <xs:enumeration value="50"/>
+      <xs:enumeration value="52"/>
+      <xs:enumeration value="54"/>
+      <xs:enumeration value="56"/>
+      <xs:enumeration value="220"/>
+      <xs:enumeration value="240"/>
+      <xs:enumeration value="260"/>
+      <xs:enumeration value="280"/>
+      <xs:enumeration value="300"/>
+      <xs:enumeration value="320"/>
+      <xs:enumeration value="340"/>
+      <xs:enumeration value="360"/>
+      <xs:enumeration value="380"/>
+      <xs:enumeration value="400"/>
+      <xs:enumeration value="420"/>
+      <xs:enumeration value="440"/>
+      <xs:enumeration value="460"/>
+      <xs:enumeration value="480"/>
+      <xs:enumeration value="500"/>
+      <xs:enumeration value="520"/>
+      <xs:enumeration value="540"/>
+      <xs:enumeration value="560"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="crossType">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="1"/>
+      <xs:enumeration value="2"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="axisType">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="1"/>
+      <xs:enumeration value="2"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="materialType">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="0"/>
+      <!--Fabric-->
+      <xs:enumeration value="1"/>
+      <!--Lining-->
+      <xs:enumeration value="2"/>
+      <!--Interfacing-->
+      <xs:enumeration value="3"/>
+      <!--Interlining-->
+      <xs:enumeration value="4"/>
+      <!--UserDefined-->
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="placementType">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="0"/>
+      <!--No placement-->
+      <xs:enumeration value="1"/>
+      <!--Cut on Fold-->
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="arrowType">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="0"/>
+      <!--Both-->
+      <xs:enumeration value="1"/>
+      <!--Front-->
+      <xs:enumeration value="2"/>
+      <!--Rear-->
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="pieceVersion">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="1"/>
+      <!--Old version-->
+      <xs:enumeration value="2"/>
+      <!--New version-->
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="nodeAngle">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="0"/>
+      <!--by length-->
+      <xs:enumeration value="1"/>
+      <!--by points intersections-->
+      <xs:enumeration value="2"/>
+      <!--by second edge symmetry-->
+      <xs:enumeration value="3"/>
+      <!--by first edge symmetry-->
+      <xs:enumeration value="4"/>
+      <!--by first edge right angle-->
+      <xs:enumeration value="5"/>
+      <!--by first edge right angle-->
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="piecePathType">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="1"/>
+      <!--custom seam allowance-->
+      <xs:enumeration value="2"/>
+      <!--internal path-->
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="piecePathIncludeType">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="0"/>
+      <!--as main path-->
+      <xs:enumeration value="1"/>
+      <!--as custom seam allowance-->
+    </xs:restriction>
+  </xs:simpleType>
+</xs:schema>
diff --git a/src/libs/ifc/schema/standard_measurements/v0.4.3.xsd b/src/libs/ifc/schema/standard_measurements/v0.4.3.xsd
index dc72b8300..4b246e839 100644
--- a/src/libs/ifc/schema/standard_measurements/v0.4.3.xsd
+++ b/src/libs/ifc/schema/standard_measurements/v0.4.3.xsd
@@ -1,160 +1,160 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
-	<xs:element name="vst">
-		<xs:complexType>
-			<xs:sequence>
-				<xs:element name="version" type="formatVersion"></xs:element>
-				<xs:element name="read-only" type="xs:boolean"></xs:element>
-				<xs:element name="notes" type="xs:string" minOccurs="0" maxOccurs="1"></xs:element>
-				<xs:element name="unit" type="units"></xs:element>
-				<xs:element name="pm_system" type="psCode"></xs:element>
-				<xs:element name="size">
-					<xs:complexType>
-						<xs:attribute name="base" type="baseSize" use="required"></xs:attribute>
-					</xs:complexType>
-				</xs:element>
-				<xs:element name="height">
-					<xs:complexType>
-						<xs:attribute name="base" type="baseHeight" use="required"></xs:attribute>
-					</xs:complexType>
-				</xs:element>
-				<xs:element name="body-measurements">
-					<xs:complexType>
-						<xs:sequence>
-							<xs:element name="m" minOccurs="0" maxOccurs="unbounded">
-								<xs:complexType>
-									<xs:attribute name="name" type="shortName" use="required"></xs:attribute>
-									<xs:attribute name="base" type="xs:double" use="required"></xs:attribute>
-									<xs:attribute name="height_increase" type="xs:double" use="required"></xs:attribute>
-									<xs:attribute name="size_increase" type="xs:double" use="required"></xs:attribute>
-									<xs:attribute name="full_name" type="xs:string"></xs:attribute>
-									<xs:attribute name="description" type="xs:string"></xs:attribute>
-								</xs:complexType>
-							</xs:element>
-						</xs:sequence>
-					</xs:complexType>
-				</xs:element>
-			</xs:sequence>
-		 </xs:complexType>
-		<xs:unique name="measurementName">
-			<xs:selector xpath="body-measurements/m"/>
-			<xs:field xpath="@name"/>
-		</xs:unique>
-	  </xs:element>
-	<xs:simpleType name="shortName">
-		<xs:restriction base="xs:string">   
-			<xs:pattern value="^([^\p{Nd}\p{Zs}*/&amp;|!&lt;&gt;^\-()–+−=?:;'\&quot;]){1,1}([^\p{Zs}*/&amp;|!&lt;&gt;^\-()–+−=?:;\&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="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:simpleType name="psCode">
-		<xs:restriction base="xs:string">
-			<xs:pattern value="^^(([0-9]|[1-4][0-9]|5[0-4])|998)$"/>
-		</xs:restriction>
-	</xs:simpleType>
-    <xs:simpleType name="baseHeight">
-        <xs:restriction base="xs:unsignedInt">
-            <xs:enumeration value="50"/>
-            <xs:enumeration value="56"/>
-            <xs:enumeration value="62"/>
-            <xs:enumeration value="68"/>
-            <xs:enumeration value="74"/>
-            <xs:enumeration value="80"/>
-            <xs:enumeration value="86"/>
-            <xs:enumeration value="92"/>
-            <xs:enumeration value="98"/>
-            <xs:enumeration value="104"/>
-            <xs:enumeration value="110"/>
-            <xs:enumeration value="116"/>
-            <xs:enumeration value="122"/>
-            <xs:enumeration value="128"/>
-            <xs:enumeration value="134"/>
-            <xs:enumeration value="140"/>
-            <xs:enumeration value="146"/>
-            <xs:enumeration value="152"/>
-            <xs:enumeration value="158"/>
-            <xs:enumeration value="164"/>
-            <xs:enumeration value="170"/>
-            <xs:enumeration value="176"/>
-            <xs:enumeration value="182"/>
-            <xs:enumeration value="188"/>
-            <xs:enumeration value="194"/>
-            <xs:enumeration value="500"/>
-            <xs:enumeration value="560"/>
-            <xs:enumeration value="620"/>
-            <xs:enumeration value="680"/>
-            <xs:enumeration value="740"/>
-            <xs:enumeration value="800"/>
-            <xs:enumeration value="860"/>
-            <xs:enumeration value="920"/>
-            <xs:enumeration value="980"/>
-            <xs:enumeration value="1040"/>
-            <xs:enumeration value="1100"/>
-            <xs:enumeration value="1160"/>
-            <xs:enumeration value="1220"/>
-            <xs:enumeration value="1280"/>
-            <xs:enumeration value="1340"/>
-            <xs:enumeration value="1400"/>
-            <xs:enumeration value="1460"/>
-            <xs:enumeration value="1520"/>
-            <xs:enumeration value="1580"/>
-            <xs:enumeration value="1640"/>
-            <xs:enumeration value="1700"/>
-            <xs:enumeration value="1760"/>
-            <xs:enumeration value="1820"/>
-            <xs:enumeration value="1880"/>
-            <xs:enumeration value="1940"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="baseSize">
-        <xs:restriction base="xs:unsignedInt">
-            <xs:enumeration value="22"/>
-            <xs:enumeration value="24"/>
-            <xs:enumeration value="26"/>
-            <xs:enumeration value="28"/>
-            <xs:enumeration value="30"/>
-            <xs:enumeration value="32"/>
-            <xs:enumeration value="34"/>
-            <xs:enumeration value="36"/>
-            <xs:enumeration value="38"/>
-            <xs:enumeration value="40"/>
-            <xs:enumeration value="42"/>
-            <xs:enumeration value="44"/>
-            <xs:enumeration value="46"/>
-            <xs:enumeration value="48"/>
-            <xs:enumeration value="50"/>
-            <xs:enumeration value="52"/>
-            <xs:enumeration value="54"/>
-            <xs:enumeration value="56"/>
-            <xs:enumeration value="220"/>
-            <xs:enumeration value="240"/>
-            <xs:enumeration value="260"/>
-            <xs:enumeration value="280"/>
-            <xs:enumeration value="300"/>
-            <xs:enumeration value="320"/>
-            <xs:enumeration value="340"/>
-            <xs:enumeration value="360"/>
-            <xs:enumeration value="380"/>
-            <xs:enumeration value="400"/>
-            <xs:enumeration value="420"/>
-            <xs:enumeration value="440"/>
-            <xs:enumeration value="460"/>
-            <xs:enumeration value="480"/>
-            <xs:enumeration value="500"/>
-            <xs:enumeration value="520"/>
-            <xs:enumeration value="540"/>
-            <xs:enumeration value="560"/>
-        </xs:restriction>
-    </xs:simpleType>
+  <xs:element name="vst">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="version" type="formatVersion"/>
+        <xs:element name="read-only" type="xs:boolean"/>
+        <xs:element name="notes" type="xs:string" minOccurs="0" maxOccurs="1"/>
+        <xs:element name="unit" type="units"/>
+        <xs:element name="pm_system" type="psCode"/>
+        <xs:element name="size">
+          <xs:complexType>
+            <xs:attribute name="base" type="baseSize" use="required"/>
+          </xs:complexType>
+        </xs:element>
+        <xs:element name="height">
+          <xs:complexType>
+            <xs:attribute name="base" type="baseHeight" use="required"/>
+          </xs:complexType>
+        </xs:element>
+        <xs:element name="body-measurements">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="m" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                  <xs:attribute name="name" type="shortName" use="required"/>
+                  <xs:attribute name="base" type="xs:double" use="required"/>
+                  <xs:attribute name="height_increase" type="xs:double" use="required"/>
+                  <xs:attribute name="size_increase" type="xs:double" use="required"/>
+                  <xs:attribute name="full_name" type="xs:string"/>
+                  <xs:attribute name="description" type="xs:string"/>
+                </xs:complexType>
+              </xs:element>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+    <xs:unique name="measurementName">
+      <xs:selector xpath="body-measurements/m"/>
+      <xs:field xpath="@name"/>
+    </xs:unique>
+  </xs:element>
+  <xs:simpleType name="shortName">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="^([^\p{Nd}\p{Zs}*/&amp;|!&lt;&gt;^\-()–+−=?:;'\&quot;]){1,1}([^\p{Zs}*/&amp;|!&lt;&gt;^\-()–+−=?:;\&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="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:simpleType name="psCode">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="^^(([0-9]|[1-4][0-9]|5[0-4])|998)$"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="baseHeight">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="50"/>
+      <xs:enumeration value="56"/>
+      <xs:enumeration value="62"/>
+      <xs:enumeration value="68"/>
+      <xs:enumeration value="74"/>
+      <xs:enumeration value="80"/>
+      <xs:enumeration value="86"/>
+      <xs:enumeration value="92"/>
+      <xs:enumeration value="98"/>
+      <xs:enumeration value="104"/>
+      <xs:enumeration value="110"/>
+      <xs:enumeration value="116"/>
+      <xs:enumeration value="122"/>
+      <xs:enumeration value="128"/>
+      <xs:enumeration value="134"/>
+      <xs:enumeration value="140"/>
+      <xs:enumeration value="146"/>
+      <xs:enumeration value="152"/>
+      <xs:enumeration value="158"/>
+      <xs:enumeration value="164"/>
+      <xs:enumeration value="170"/>
+      <xs:enumeration value="176"/>
+      <xs:enumeration value="182"/>
+      <xs:enumeration value="188"/>
+      <xs:enumeration value="194"/>
+      <xs:enumeration value="500"/>
+      <xs:enumeration value="560"/>
+      <xs:enumeration value="620"/>
+      <xs:enumeration value="680"/>
+      <xs:enumeration value="740"/>
+      <xs:enumeration value="800"/>
+      <xs:enumeration value="860"/>
+      <xs:enumeration value="920"/>
+      <xs:enumeration value="980"/>
+      <xs:enumeration value="1040"/>
+      <xs:enumeration value="1100"/>
+      <xs:enumeration value="1160"/>
+      <xs:enumeration value="1220"/>
+      <xs:enumeration value="1280"/>
+      <xs:enumeration value="1340"/>
+      <xs:enumeration value="1400"/>
+      <xs:enumeration value="1460"/>
+      <xs:enumeration value="1520"/>
+      <xs:enumeration value="1580"/>
+      <xs:enumeration value="1640"/>
+      <xs:enumeration value="1700"/>
+      <xs:enumeration value="1760"/>
+      <xs:enumeration value="1820"/>
+      <xs:enumeration value="1880"/>
+      <xs:enumeration value="1940"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="baseSize">
+    <xs:restriction base="xs:unsignedInt">
+      <xs:enumeration value="22"/>
+      <xs:enumeration value="24"/>
+      <xs:enumeration value="26"/>
+      <xs:enumeration value="28"/>
+      <xs:enumeration value="30"/>
+      <xs:enumeration value="32"/>
+      <xs:enumeration value="34"/>
+      <xs:enumeration value="36"/>
+      <xs:enumeration value="38"/>
+      <xs:enumeration value="40"/>
+      <xs:enumeration value="42"/>
+      <xs:enumeration value="44"/>
+      <xs:enumeration value="46"/>
+      <xs:enumeration value="48"/>
+      <xs:enumeration value="50"/>
+      <xs:enumeration value="52"/>
+      <xs:enumeration value="54"/>
+      <xs:enumeration value="56"/>
+      <xs:enumeration value="220"/>
+      <xs:enumeration value="240"/>
+      <xs:enumeration value="260"/>
+      <xs:enumeration value="280"/>
+      <xs:enumeration value="300"/>
+      <xs:enumeration value="320"/>
+      <xs:enumeration value="340"/>
+      <xs:enumeration value="360"/>
+      <xs:enumeration value="380"/>
+      <xs:enumeration value="400"/>
+      <xs:enumeration value="420"/>
+      <xs:enumeration value="440"/>
+      <xs:enumeration value="460"/>
+      <xs:enumeration value="480"/>
+      <xs:enumeration value="500"/>
+      <xs:enumeration value="520"/>
+      <xs:enumeration value="540"/>
+      <xs:enumeration value="560"/>
+    </xs:restriction>
+  </xs:simpleType>
 </xs:schema>
diff --git a/src/libs/ifc/xml/vabstractpattern.cpp b/src/libs/ifc/xml/vabstractpattern.cpp
index e1e5071c5..122428173 100644
--- a/src/libs/ifc/xml/vabstractpattern.cpp
+++ b/src/libs/ifc/xml/vabstractpattern.cpp
@@ -45,6 +45,7 @@
 #include "../ifc/exception/vexceptionbadid.h"
 #include "../ifc/ifcdef.h"
 #include "../vpatterndb/vcontainer.h"
+#include "../vpatterndb/vpiecenode.h"
 #include "../vtools/tools/vdatatool.h"
 #include "vpatternconverter.h"
 #include "vdomdocument.h"
@@ -90,6 +91,9 @@ const QString VAbstractPattern::TagSize             = QStringLiteral("size");
 const QString VAbstractPattern::TagShowDate         = QStringLiteral("showDate");
 const QString VAbstractPattern::TagShowMeasurements = QStringLiteral("showMeasurements");
 const QString VAbstractPattern::TagGrainline        = QStringLiteral("grainline");
+const QString VAbstractPattern::TagPath             = QStringLiteral("path");
+const QString VAbstractPattern::TagNodes            = QStringLiteral("nodes");
+const QString VAbstractPattern::TagNode             = QStringLiteral("node");
 
 const QString VAbstractPattern::AttrName            = QStringLiteral("name");
 const QString VAbstractPattern::AttrVisible         = QStringLiteral("visible");
@@ -102,6 +106,15 @@ const QString VAbstractPattern::AttrUserDefined     = QStringLiteral("userDef");
 const QString VAbstractPattern::AttrCutNumber       = QStringLiteral("cutNumber");
 const QString VAbstractPattern::AttrPlacement       = QStringLiteral("placement");
 const QString VAbstractPattern::AttrArrows          = QStringLiteral("arrows");
+const QString VAbstractPattern::AttrNodeReverse     = QStringLiteral("reverse");
+const QString VAbstractPattern::AttrSABefore        = QStringLiteral("before");
+const QString VAbstractPattern::AttrSAAfter         = QStringLiteral("after");
+const QString VAbstractPattern::AttrStart           = QStringLiteral("start");
+const QString VAbstractPattern::AttrPath            = QStringLiteral("path");
+const QString VAbstractPattern::AttrEnd             = QStringLiteral("end");
+const QString VAbstractPattern::AttrIncludeAs       = QStringLiteral("includeAs");
+const QString VAbstractPattern::AttrWidth           = QStringLiteral("width");
+const QString VAbstractPattern::AttrRotation        = QStringLiteral("rotation");
 
 const QString VAbstractPattern::AttrAll             = QStringLiteral("all");
 
@@ -159,10 +172,23 @@ const QString VAbstractPattern::IncrementName        = QStringLiteral("name");
 const QString VAbstractPattern::IncrementFormula     = QStringLiteral("formula");
 const QString VAbstractPattern::IncrementDescription = QStringLiteral("description");
 
+const QString VAbstractPattern::NodeArc        = QStringLiteral("NodeArc");
+const QString VAbstractPattern::NodeElArc      = QStringLiteral("NodeElArc");
+const QString VAbstractPattern::NodePoint      = QStringLiteral("NodePoint");
+const QString VAbstractPattern::NodeSpline     = QStringLiteral("NodeSpline");
+const QString VAbstractPattern::NodeSplinePath = QStringLiteral("NodeSplinePath");
+
+QHash<quint32, VDataTool*> VAbstractPattern::tools = QHash<quint32, VDataTool*>();
+
 //---------------------------------------------------------------------------------------------------------------------
 VAbstractPattern::VAbstractPattern(QObject *parent)
-    : QObject(parent), VDomDocument(), nameActivPP(QString()), cursor(0), tools(QHash<quint32, VDataTool*>()),
-      toolsOnRemove(QVector<VDataTool*>()), history(QVector<VToolRecord>()), patternPieces(QStringList()),
+    : QObject(parent),
+      VDomDocument(),
+      nameActivPP(QString()),
+      cursor(0),
+      toolsOnRemove(QVector<VDataTool*>()),
+      history(QVector<VToolRecord>()),
+      patternPieces(QStringList()),
       modified(false)
 {}
 
@@ -520,7 +546,7 @@ void VAbstractPattern::setCursor(const quint32 &value)
  * @param id tool id.
  * @return tool.
  */
-VDataTool *VAbstractPattern::getTool(const quint32 &id)
+VDataTool *VAbstractPattern::getTool(quint32 id)
 {
     ToolExists(id);
     return tools.value(id);
@@ -532,11 +558,126 @@ VDataTool *VAbstractPattern::getTool(const quint32 &id)
  * @param id tool id.
  * @param tool tool.
  */
-void VAbstractPattern::AddTool(const quint32 &id, VDataTool *tool)
+void VAbstractPattern::AddTool(quint32 id, VDataTool *tool)
 {
     Q_ASSERT_X(id != 0, Q_FUNC_INFO, "id == 0");
     SCASSERT(tool != nullptr)
-    tools.insert(id, tool);
+            tools.insert(id, tool);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VAbstractPattern::RemoveTool(quint32 id)
+{
+    tools.remove(id);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath VAbstractPattern::ParsePieceNodes(const QDomElement &domElement)
+{
+    VPiecePath path;
+    const QDomNodeList nodeList = domElement.childNodes();
+    for (qint32 i = 0; i < nodeList.size(); ++i)
+    {
+        const QDomElement element = nodeList.at(i).toElement();
+        if (not element.isNull())
+        {
+            path.Append(ParseSANode(element));
+        }
+    }
+    return path;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<CustomSARecord> VAbstractPattern::ParsePieceCSARecords(const QDomElement &domElement)
+{
+    QVector<CustomSARecord> records;
+    const QDomNodeList nodeList = domElement.childNodes();
+    for (qint32 i = 0; i < nodeList.size(); ++i)
+    {
+        const QDomElement element = nodeList.at(i).toElement();
+        if (not element.isNull())
+        {
+            CustomSARecord record;
+            record.startPoint = GetParametrUInt(element, VAbstractPattern::AttrStart, NULL_ID_STR);
+            record.path = GetParametrUInt(element, VAbstractPattern::AttrPath, NULL_ID_STR);
+            record.endPoint = GetParametrUInt(element, VAbstractPattern::AttrEnd, NULL_ID_STR);
+            record.reverse = GetParametrBool(element, VAbstractPattern::AttrNodeReverse, falseStr);
+            record.includeType = static_cast<PiecePathIncludeType>(GetParametrUInt(element,
+                                                                                   VAbstractPattern::AttrIncludeAs,
+                                                                                   "1"));
+            records.append(record);
+        }
+    }
+    return records;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<quint32> VAbstractPattern::ParsePieceInternalPaths(const QDomElement &domElement)
+{
+    QVector<quint32> records;
+    const QDomNodeList nodeList = domElement.childNodes();
+    for (qint32 i = 0; i < nodeList.size(); ++i)
+    {
+        const QDomElement element = nodeList.at(i).toElement();
+        if (not element.isNull())
+        {
+            const quint32 path = GetParametrUInt(element, VAbstractPattern::AttrPath, NULL_ID_STR);
+            if (path > NULL_ID)
+            {
+                records.append(path);
+            }
+        }
+    }
+    return records;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPieceNode VAbstractPattern::ParseSANode(const QDomElement &domElement)
+{
+    const quint32 id = VDomDocument::GetParametrUInt(domElement, AttrIdObject, NULL_ID_STR);
+    const bool reverse = VDomDocument::GetParametrUInt(domElement, VAbstractPattern::AttrNodeReverse, "0");
+    const QString saBefore = VDomDocument::GetParametrString(domElement, VAbstractPattern::AttrSABefore,
+                                                             currentSeamAllowance);
+    const QString saAfter = VDomDocument::GetParametrString(domElement, VAbstractPattern::AttrSAAfter,
+                                                            currentSeamAllowance);
+    const PieceNodeAngle angle = static_cast<PieceNodeAngle>(VDomDocument::GetParametrUInt(domElement, AttrAngle, "0"));
+
+    const QString t = VDomDocument::GetParametrString(domElement, AttrType, VAbstractPattern::NodePoint);
+    Tool tool;
+
+    const QStringList types = QStringList() << VAbstractPattern::NodePoint
+                                            << VAbstractPattern::NodeArc
+                                            << VAbstractPattern::NodeSpline
+                                            << VAbstractPattern::NodeSplinePath
+                                            << VAbstractPattern::NodeElArc;
+
+    switch (types.indexOf(t))
+    {
+        case 0: // VAbstractPattern::NodePoint
+            tool = Tool::NodePoint;
+            break;
+        case 1: // VAbstractPattern::NodeArc
+            tool = Tool::NodeArc;
+            break;
+        case 2: // VAbstractPattern::NodeSpline
+            tool = Tool::NodeSpline;
+            break;
+        case 3: // VAbstractPattern::NodeSplinePath
+            tool = Tool::NodeSplinePath;
+            break;
+        case 4: // NodeElArc
+            tool = Tool::NodeElArc;
+            break;
+        default:
+            VException e(QObject::tr("Wrong tag name '%1'.").arg(t));
+            throw e;
+    }
+    VPieceNode node(id, tool, reverse);
+    node.SetFormulaSABefore(saBefore);
+    node.SetFormulaSAAfter(saAfter);
+    node.SetAngleType(angle);
+
+    return node;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -635,7 +776,7 @@ quint32 VAbstractPattern::SiblingNodeId(const quint32 &nodeId) const
                     const VToolRecord tool = history.at(j-1);
                     switch ( tool.getTypeTool() )
                     {
-                        case Tool::Detail:
+                        case Tool::Piece:
                         case Tool::UnionDetails:
                         case Tool::NodeArc:
                         case Tool::NodeElArc:
@@ -1255,7 +1396,7 @@ void VAbstractPattern::SelectedDetail(quint32 id)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VAbstractPattern::ToolExists(const quint32 &id) const
+void VAbstractPattern::ToolExists(const quint32 &id)
 {
     if (tools.contains(id) == false)
     {
@@ -1263,6 +1404,22 @@ void VAbstractPattern::ToolExists(const quint32 &id) const
     }
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath VAbstractPattern::ParsePathNodes(const QDomElement &domElement)
+{
+    VPiecePath path;
+    const QDomNodeList nodeList = domElement.childNodes();
+    for (qint32 i = 0; i < nodeList.size(); ++i)
+    {
+        const QDomElement element = nodeList.at(i).toElement();
+        if (not element.isNull() && element.tagName() == VAbstractPattern::TagNode)
+        {
+            path.Append(ParseSANode(element));
+        }
+    }
+    return path;
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief SetActivPP set current pattern piece.
@@ -1411,12 +1568,16 @@ QStringList VAbstractPattern::ListExpressions() const
     QStringList list;
 
     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
+    // Note. Tool Union Details also contains formulas, but we don't use them for union and keep only to simplifying
+    // working with nodes. Same code for saving reading.
     list << ListPointExpressions();
     list << ListArcExpressions();
     list << ListElArcExpressions();
     list << ListSplineExpressions();
     list << ListIncrementExpressions();
     list << ListOperationExpressions();
+    list << ListPathExpressions();
+    list << ListPieceExpressions();
 
     return list;
 }
@@ -1427,7 +1588,7 @@ QStringList VAbstractPattern::ListPointExpressions() const
     // Check if new tool doesn't bring new attribute with a formula.
     // If no just increment a number.
     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
-    Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50);
+    Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51);
 
     QStringList expressions;
     const QDomNodeList list = elementsByTagName(TagPoint);
@@ -1499,7 +1660,7 @@ QStringList VAbstractPattern::ListArcExpressions() const
     // Check if new tool doesn't bring new attribute with a formula.
     // If no just increment number.
     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
-    Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50);
+    Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51);
 
     QStringList expressions;
     const QDomNodeList list = elementsByTagName(TagArc);
@@ -1553,7 +1714,7 @@ QStringList VAbstractPattern::ListElArcExpressions() const
     // Check if new tool doesn't bring new attribute with a formula.
     // If no just increment number.
     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
-    Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50);
+    Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51);
 
     QStringList expressions;
     const QDomNodeList list = elementsByTagName(TagElArc);
@@ -1624,7 +1785,7 @@ QStringList VAbstractPattern::ListPathPointExpressions() const
     // Check if new tool doesn't bring new attribute with a formula.
     // If no just increment number.
     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
-    Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50);
+    Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51);
 
     QStringList expressions;
     const QDomNodeList list = elementsByTagName(AttrPathPoint);
@@ -1691,7 +1852,7 @@ QStringList VAbstractPattern::ListOperationExpressions() const
     // Check if new tool doesn't bring new attribute with a formula.
     // If no just increment number.
     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
-    Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 50);
+    Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51);
 
     QStringList expressions;
     const QDomNodeList list = elementsByTagName(TagOperation);
@@ -1722,6 +1883,112 @@ QStringList VAbstractPattern::ListOperationExpressions() const
     return expressions;
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+QStringList VAbstractPattern::ListNodesExpressions(const QDomElement &nodes) const
+{
+    QStringList expressions;
+    VPiecePath path;
+    if (not nodes.isNull())
+    {
+        path = ParsePathNodes(nodes);
+    }
+
+    for(int i = 0; i < path.CountNodes(); ++i)
+    {
+        expressions.append(path.at(i).GetFormulaSABefore());
+        expressions.append(path.at(i).GetFormulaSAAfter());
+    }
+    return expressions;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QStringList VAbstractPattern::ListPathExpressions() const
+{
+    // Check if new tool doesn't bring new attribute with a formula.
+    // If no just increment number.
+    // If new tool bring absolutely new type and has formula(s) create new method to cover it.
+    Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51);
+
+    QStringList expressions;
+    const QDomNodeList list = elementsByTagName(TagPath);
+    for (int i=0; i < list.size(); ++i)
+    {
+        const QDomElement dom = list.at(i).toElement();
+        if (dom.isNull())
+        {
+            continue;
+        }
+
+        expressions << ListNodesExpressions(dom.firstChildElement(TagNodes));
+    }
+
+    return expressions;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QStringList VAbstractPattern::ListGrainlineExpressions(const QDomElement &element) const
+{
+    QStringList expressions;
+    if (not element.isNull())
+    {
+        // Each tag can contains several attributes.
+        try
+        {
+            expressions.append(GetParametrString(element, AttrRotation));
+        }
+        catch (VExceptionEmptyParameter &e)
+        {
+            Q_UNUSED(e)
+        }
+
+        try
+        {
+            expressions.append(GetParametrString(element, AttrLength));
+        }
+        catch (VExceptionEmptyParameter &e)
+        {
+            Q_UNUSED(e)
+        }
+    }
+
+    return expressions;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QStringList VAbstractPattern::ListPieceExpressions() const
+{
+    // Check if new tool doesn't bring new attribute with a formula.
+    // If no just increment number.
+    // If new tool bring absolutely new type and has formula(s) create new method to cover it.
+    Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 51);
+
+    QStringList expressions;
+    const QDomNodeList list = elementsByTagName(TagDetail);
+    for (int i=0; i < list.size(); ++i)
+    {
+        const QDomElement dom = list.at(i).toElement();
+        if (dom.isNull())
+        {
+            continue;
+        }
+
+        // Each tag can contains several attributes.
+        try
+        {
+            expressions.append(GetParametrString(dom, AttrWidth));
+        }
+        catch (VExceptionEmptyParameter &e)
+        {
+            Q_UNUSED(e)
+        }
+
+        expressions << ListNodesExpressions(dom.firstChildElement(TagNodes));
+        expressions << ListGrainlineExpressions(dom.firstChildElement(TagGrainline));
+    }
+
+    return expressions;
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 bool VAbstractPattern::IsVariable(const QString &token) const
 {
diff --git a/src/libs/ifc/xml/vabstractpattern.h b/src/libs/ifc/xml/vabstractpattern.h
index 213479757..2e590c9a1 100644
--- a/src/libs/ifc/xml/vabstractpattern.h
+++ b/src/libs/ifc/xml/vabstractpattern.h
@@ -45,6 +45,8 @@
 #include "vtoolrecord.h"
 
 class QDomElement;
+class VPiecePath;
+class VPieceNode;
 
 enum class Document : char { LiteParse, LitePPParse, FullParse };
 enum class LabelType : char {NewPatternPiece, NewLabel};
@@ -77,7 +79,6 @@ public:
     bool           ChangeNamePP(const QString& oldName, const QString &newName);
     bool           appendPP(const QString& name);
 
-    bool           GetActivDrawElement(QDomElement &element) const;
     bool           GetActivNodeElement(const QString& name, QDomElement& element) const;
 
     quint32        getCursor() const;
@@ -91,9 +92,13 @@ public:
 
     virtual void   UpdateToolData(const quint32 &id, VContainer *data)=0;
 
-    QHash<quint32, VDataTool *> *getTools();
-    VDataTool     *getTool(const quint32 &id);
-    void           AddTool(const quint32 &id, VDataTool *tool);
+    static VDataTool* getTool(quint32 id);
+    static void       AddTool(quint32 id, VDataTool *tool);
+    static void       RemoveTool(quint32 id);
+
+    static VPiecePath              ParsePieceNodes(const QDomElement &domElement);
+    static QVector<CustomSARecord> ParsePieceCSARecords(const QDomElement &domElement);
+    static QVector<quint32>        ParsePieceInternalPaths(const QDomElement &domElement);
 
     void           AddToolOnRemove(VDataTool *tool);
 
@@ -195,6 +200,9 @@ public:
     static const QString TagShowDate;
     static const QString TagShowMeasurements;
     static const QString TagGrainline;
+    static const QString TagPath;
+    static const QString TagNodes;
+    static const QString TagNode;
 
     static const QString AttrName;
     static const QString AttrVisible;
@@ -207,6 +215,15 @@ public:
     static const QString AttrCutNumber;
     static const QString AttrPlacement;
     static const QString AttrArrows;
+    static const QString AttrNodeReverse;
+    static const QString AttrSABefore;
+    static const QString AttrSAAfter;
+    static const QString AttrStart;
+    static const QString AttrPath;
+    static const QString AttrEnd;
+    static const QString AttrIncludeAs;
+    static const QString AttrWidth;
+    static const QString AttrRotation;
 
     static const QString AttrAll;
 
@@ -264,6 +281,12 @@ public:
     static const QString IncrementFormula;
     static const QString IncrementDescription;
 
+    static const QString NodeArc;
+    static const QString NodeElArc;
+    static const QString NodePoint;
+    static const QString NodeSpline;
+    static const QString NodeSplinePath;
+
 signals:
     /**
      * @brief ChangedActivPP change active pattern peace.
@@ -320,9 +343,6 @@ protected:
     /** @brief cursor cursor keep id tool after which we will add new tool in file. */
     quint32        cursor;
 
-    /** @brief tools list with pointer on tools. */
-    QHash<quint32, VDataTool*> tools;
-
     QVector<VDataTool*> toolsOnRemove;
 
     /** @brief history history records. */
@@ -334,7 +354,12 @@ protected:
     /** @brief modified keep state of the document for cases that do not cover QUndoStack*/
     mutable bool   modified;
 
-    void           ToolExists(const quint32 &id) const;
+    /** @brief tools list with pointer on tools. */
+    static QHash<quint32, VDataTool*> tools;
+
+    static void       ToolExists(const quint32 &id);
+    static VPiecePath ParsePathNodes(const QDomElement &domElement);
+    static VPieceNode ParseSANode(const QDomElement &domElement);
 
     void           SetActivPP(const QString& name);
 
@@ -343,7 +368,8 @@ protected:
 
     void           SetChildTag(const QString& qsParent, const QString& qsChild, const QString& qsValue);
 
-    int GetIndexActivPP() const;
+    int  GetIndexActivPP() const;
+    bool GetActivDrawElement(QDomElement &element) const;
 private:
     Q_DISABLE_COPY(VAbstractPattern)
 
@@ -356,22 +382,17 @@ private:
     QStringList ListPathPointExpressions() const;
     QStringList ListIncrementExpressions() const;
     QStringList ListOperationExpressions() const;
+    QStringList ListNodesExpressions(const QDomElement &nodes) const;
+    QStringList ListPathExpressions() const;
+    QStringList ListGrainlineExpressions(const QDomElement &element) const;
+    QStringList ListPieceExpressions() const;
 
     bool IsVariable(const QString& token) const;
     bool IsPostfixOperator(const QString& token) const;
     bool IsFunction(const QString& token) const;
 
     QPair<bool, QMap<quint32, quint32> > ParseItemElement(const QDomElement &domElement);
+
 };
 
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief getTools return list of tools pointers.
- * @return list.
- */
-inline QHash<quint32, VDataTool *> *VAbstractPattern::getTools()
-{
-    return &tools;
-}
-
 #endif // VABSTRACTPATTERN_H
diff --git a/src/libs/ifc/xml/vdomdocument.cpp b/src/libs/ifc/xml/vdomdocument.cpp
index aff76405c..e5a590f11 100644
--- a/src/libs/ifc/xml/vdomdocument.cpp
+++ b/src/libs/ifc/xml/vdomdocument.cpp
@@ -203,7 +203,7 @@ bool VDomDocument::find(const QDomElement &node, const QString& id)
  * @param name attribute name
  * @return long long value
  */
-quint32 VDomDocument::GetParametrUInt(const QDomElement &domElement, const QString &name, const QString &defValue) const
+quint32 VDomDocument::GetParametrUInt(const QDomElement &domElement, const QString &name, const QString &defValue)
 {
     Q_ASSERT_X(not name.isEmpty(), Q_FUNC_INFO, "name of parametr is empty");
     Q_ASSERT_X(not domElement.isNull(), Q_FUNC_INFO, "domElement is null"); //-V591
@@ -212,7 +212,7 @@ quint32 VDomDocument::GetParametrUInt(const QDomElement &domElement, const QStri
     QString parametr;
     quint32 id = 0;
 
-    QString message = tr("Can't convert toUInt parameter");
+    const QString message = QObject::tr("Can't convert toUInt parameter");
     try
     {
         parametr = GetParametrString(domElement, name, defValue);
@@ -233,7 +233,7 @@ quint32 VDomDocument::GetParametrUInt(const QDomElement &domElement, const QStri
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-bool VDomDocument::GetParametrBool(const QDomElement &domElement, const QString &name, const QString &defValue) const
+bool VDomDocument::GetParametrBool(const QDomElement &domElement, const QString &name, const QString &defValue)
 {
     Q_ASSERT_X(not name.isEmpty(), Q_FUNC_INFO, "name of parametr is empty");
     Q_ASSERT_X(not domElement.isNull(), Q_FUNC_INFO, "domElement is null");
@@ -241,12 +241,15 @@ bool VDomDocument::GetParametrBool(const QDomElement &domElement, const QString
     QString parametr;
     bool val = true;
 
-    QString message = tr("Can't convert toBool parameter");
+    const QString message = QObject::tr("Can't convert toBool parameter");
     try
     {
         parametr = GetParametrString(domElement, name, defValue);
 
-        QStringList bools = QStringList() << QLatin1String("true") << QLatin1String("false");
+        const QStringList bools = QStringList() << QLatin1String("true")
+                                                << QLatin1String("false")
+                                                << QLatin1String("1")
+                                                << QLatin1String("0");
         switch (bools.indexOf(parametr))
         {
             case 0: // true
@@ -255,6 +258,12 @@ bool VDomDocument::GetParametrBool(const QDomElement &domElement, const QString
             case 1: // false
                 val = false;
                 break;
+            case 2: // 1
+                val = true;
+                break;
+            case 3: // 0
+                val = false;
+                break;
             default:// others
                 throw VExceptionConversionError(message, name);
                 break;
@@ -271,7 +280,7 @@ bool VDomDocument::GetParametrBool(const QDomElement &domElement, const QString
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-NodeUsage VDomDocument::GetParametrUsage(const QDomElement &domElement, const QString &name) const
+NodeUsage VDomDocument::GetParametrUsage(const QDomElement &domElement, const QString &name)
 {
     const bool value = GetParametrBool(domElement, name, trueStr);
     if (value)
@@ -306,7 +315,7 @@ void VDomDocument::SetParametrUsage(QDomElement &domElement, const QString &name
  * @throw VExceptionEmptyParameter when attribute is empty
  */
 QString VDomDocument::GetParametrString(const QDomElement &domElement, const QString &name,
-                                        const QString &defValue) const
+                                        const QString &defValue)
 {
     Q_ASSERT_X(not name.isEmpty(), Q_FUNC_INFO, "name of parametr is empty");
     Q_ASSERT_X(not domElement.isNull(), Q_FUNC_INFO, "domElement is null");
@@ -315,7 +324,7 @@ QString VDomDocument::GetParametrString(const QDomElement &domElement, const QSt
     {
         if (defValue.isEmpty())
         {
-            throw VExceptionEmptyParameter(tr("Got empty parameter"), name, domElement);
+            throw VExceptionEmptyParameter(QObject::tr("Got empty parameter"), name, domElement);
         }
         else
         {
@@ -332,7 +341,7 @@ QString VDomDocument::GetParametrString(const QDomElement &domElement, const QSt
  * @param name attribute name
  * @return double value
  */
-qreal VDomDocument::GetParametrDouble(const QDomElement &domElement, const QString &name, const QString &defValue) const
+qreal VDomDocument::GetParametrDouble(const QDomElement &domElement, const QString &name, const QString &defValue)
 {
     Q_ASSERT_X(not name.isEmpty(), Q_FUNC_INFO, "name of parametr is empty");
     Q_ASSERT_X(not domElement.isNull(), Q_FUNC_INFO, "domElement is null");
@@ -340,7 +349,7 @@ qreal VDomDocument::GetParametrDouble(const QDomElement &domElement, const QStri
     bool ok = false;
     qreal param = 0;
 
-    QString message = tr("Can't convert toDouble parameter");
+    const QString message = QObject::tr("Can't convert toDouble parameter");
     try
     {
         QString parametr = GetParametrString(domElement, name, defValue);
@@ -365,13 +374,13 @@ qreal VDomDocument::GetParametrDouble(const QDomElement &domElement, const QStri
  * @param domElement tag in xml tree.
  * @return id value.
  */
-quint32 VDomDocument::GetParametrId(const QDomElement &domElement) const
+quint32 VDomDocument::GetParametrId(const QDomElement &domElement)
 {
     Q_ASSERT_X(not domElement.isNull(), Q_FUNC_INFO, "domElement is null");
 
     quint32 id = NULL_ID;
 
-    const QString message = tr("Got wrong parameter id. Need only id > 0.");
+    const QString message = QObject::tr("Got wrong parameter id. Need only id > 0.");
     try
     {
         id = GetParametrUInt(domElement, VDomDocument::AttrId, NULL_ID_STR);
@@ -486,8 +495,9 @@ void VDomDocument::ValidateXML(const QString &schema, const QString &fileName)
     {
         pattern.close();
         fileSchema.close();
-        const QString errorMsg(tr("Could not load schema file '%1'.").arg(fileSchema.fileName()));
-        throw VException(errorMsg);
+        VException e(messageHandler.statusMessage());
+        e.AddMoreInformation(tr("Could not load schema file '%1'.").arg(fileSchema.fileName()));
+        throw e;
     }
     qCDebug(vXML, "Schema loaded.");
 
diff --git a/src/libs/ifc/xml/vdomdocument.h b/src/libs/ifc/xml/vdomdocument.h
index 1d1ed589b..540be9aea 100644
--- a/src/libs/ifc/xml/vdomdocument.h
+++ b/src/libs/ifc/xml/vdomdocument.h
@@ -96,16 +96,16 @@ public:
     template <typename T>
     void SetAttribute(QDomElement &domElement, const QString &name, const T &value) const;
 
-    quint32        GetParametrUInt(const QDomElement& domElement, const QString &name, const QString &defValue) const;
-    bool           GetParametrBool(const QDomElement& domElement, const QString &name, const QString &defValue) const;
+    static quint32 GetParametrUInt(const QDomElement& domElement, const QString &name, const QString &defValue);
+    static bool    GetParametrBool(const QDomElement& domElement, const QString &name, const QString &defValue);
 
-    NodeUsage      GetParametrUsage(const QDomElement& domElement, const QString &name) const;
-    void           SetParametrUsage(QDomElement& domElement, const QString &name, const NodeUsage &value);
+    static NodeUsage GetParametrUsage(const QDomElement& domElement, const QString &name);
+    static void      SetParametrUsage(QDomElement& domElement, const QString &name, const NodeUsage &value);
 
-    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 QString GetParametrString(const QDomElement& domElement, const QString &name,
+                                     const QString &defValue = QString());
+    static qreal   GetParametrDouble(const QDomElement& domElement, const QString &name, const QString &defValue);
+    static quint32 GetParametrId(const QDomElement& domElement);
 
     static void    ValidateXML(const QString &schema, const QString &fileName);
     virtual void   setXMLContent(const QString &fileName);
diff --git a/src/libs/ifc/xml/vpatternconverter.cpp b/src/libs/ifc/xml/vpatternconverter.cpp
index 189c90d53..ab86535da 100644
--- a/src/libs/ifc/xml/vpatternconverter.cpp
+++ b/src/libs/ifc/xml/vpatternconverter.cpp
@@ -58,63 +58,81 @@ class QDomElement;
  */
 
 const QString VPatternConverter::PatternMinVerStr = QStringLiteral("0.1.0");
-const QString VPatternConverter::PatternMaxVerStr = QStringLiteral("0.3.9");
-const QString VPatternConverter::CurrentSchema    = QStringLiteral("://schema/pattern/v0.3.9.xsd");
+const QString VPatternConverter::PatternMaxVerStr = QStringLiteral("0.4.0");
+const QString VPatternConverter::CurrentSchema    = QStringLiteral("://schema/pattern/v0.4.0.xsd");
 
 //VPatternConverter::PatternMinVer; // <== DON'T FORGET TO UPDATE TOO!!!!
 //VPatternConverter::PatternMaxVer; // <== DON'T FORGET TO UPDATE TOO!!!!
 
 // The list of all string we use for conversion
 // Better to use global variables because repeating QStringLiteral blows up code size
-const QString strUnit                      = QStringLiteral("unit");
-const QString strVersion                   = QStringLiteral("version");
-const QString strName                      = QStringLiteral("name");
-const QString strBase                      = QStringLiteral("base");
-const QString strFormula                   = QStringLiteral("formula");
-const QString strId                        = QStringLiteral("id");
-const QString strKGrowth                   = QStringLiteral("kgrowth");
-const QString strKSize                     = QStringLiteral("ksize");
-const QString strPoint                     = QStringLiteral("point");
-const QString strLength                    = QStringLiteral("length");
-const QString strAngle                     = QStringLiteral("angle");
-const QString strC1Radius                  = QStringLiteral("c1Radius");
-const QString strC2Radius                  = QStringLiteral("c2Radius");
-const QString strCRadius                   = QStringLiteral("cRadius");
-const QString strArc                       = QStringLiteral("arc");
-const QString strAngle1                    = QStringLiteral("angle1");
-const QString strAngle2                    = QStringLiteral("angle2");
-const QString strRadius                    = QStringLiteral("radius");
-const QString strPathPoint                 = QStringLiteral("pathPoint");
-const QString strKAsm1                     = QStringLiteral("kAsm1");
-const QString strKAsm2                     = QStringLiteral("kAsm2");
-const QString strPath                      = QStringLiteral("path");
-const QString strType                      = QStringLiteral("type");
-const QString strCutArc                    = QStringLiteral("cutArc");
-const QString strSpline                    = QStringLiteral("spline");
-const QString strSplinePath                = QStringLiteral("splinePath");
-const QString strCutSpline                 = QStringLiteral("cutSpline");
-const QString strCutSplinePath             = QStringLiteral("cutSplinePath");
-const QString strColor                     = QStringLiteral("color");
-const QString strMeasurements              = QStringLiteral("measurements");
-const QString strIncrement                 = QStringLiteral("increment");
-const QString strIncrements                = QStringLiteral("increments");
-const QString strModeling                  = QStringLiteral("modeling");
-const QString strTools                     = QStringLiteral("tools");
-const QString strIdTool                    = QStringLiteral("idTool");
-const QString strIdObject                  = QStringLiteral("idObject");
-const QString strChildren                  = QStringLiteral("children");
-const QString strChild                     = QStringLiteral("child");
-const QString strPointOfIntersectionCurves = QStringLiteral("pointOfIntersectionCurves");
-const QString strCurveIntersectAxis        = QStringLiteral("curveIntersectAxis");
-const QString strCurve                     = QStringLiteral("curve");
-const QString strCurve1                    = QStringLiteral("curve1");
-const QString strCurve2                    = QStringLiteral("curve2");
-const QString strModelingPath              = QStringLiteral("modelingPath");
-const QString strModelingSpline            = QStringLiteral("modelingSpline");
-const QString strPointFromArcAndTangent    = QStringLiteral("pointFromArcAndTangent");
-const QString strPointOfIntersectionArcs   = QStringLiteral("pointOfIntersectionArcs");
-const QString strFirstArc                  = QStringLiteral("firstArc");
-const QString strSecondArc                 = QStringLiteral("secondArc");
+static const QString strUnit                      = QStringLiteral("unit");
+static const QString strVersion                   = QStringLiteral("version");
+static const QString strName                      = QStringLiteral("name");
+static const QString strBase                      = QStringLiteral("base");
+static const QString strFormula                   = QStringLiteral("formula");
+static const QString strId                        = QStringLiteral("id");
+static const QString strKGrowth                   = QStringLiteral("kgrowth");
+static const QString strKSize                     = QStringLiteral("ksize");
+static const QString strPoint                     = QStringLiteral("point");
+static const QString strLength                    = QStringLiteral("length");
+static const QString strAngle                     = QStringLiteral("angle");
+static const QString strC1Radius                  = QStringLiteral("c1Radius");
+static const QString strC2Radius                  = QStringLiteral("c2Radius");
+static const QString strCRadius                   = QStringLiteral("cRadius");
+static const QString strArc                       = QStringLiteral("arc");
+static const QString strAngle1                    = QStringLiteral("angle1");
+static const QString strAngle2                    = QStringLiteral("angle2");
+static const QString strRadius                    = QStringLiteral("radius");
+static const QString strPathPoint                 = QStringLiteral("pathPoint");
+static const QString strKAsm1                     = QStringLiteral("kAsm1");
+static const QString strKAsm2                     = QStringLiteral("kAsm2");
+static const QString strPath                      = QStringLiteral("path");
+static const QString strType                      = QStringLiteral("type");
+static const QString strCutArc                    = QStringLiteral("cutArc");
+static const QString strSpline                    = QStringLiteral("spline");
+static const QString strSplinePath                = QStringLiteral("splinePath");
+static const QString strCutSpline                 = QStringLiteral("cutSpline");
+static const QString strCutSplinePath             = QStringLiteral("cutSplinePath");
+static const QString strColor                     = QStringLiteral("color");
+static const QString strMeasurements              = QStringLiteral("measurements");
+static const QString strIncrement                 = QStringLiteral("increment");
+static const QString strIncrements                = QStringLiteral("increments");
+static const QString strModeling                  = QStringLiteral("modeling");
+static const QString strTools                     = QStringLiteral("tools");
+static const QString strIdTool                    = QStringLiteral("idTool");
+static const QString strIdObject                  = QStringLiteral("idObject");
+static const QString strChildren                  = QStringLiteral("children");
+static const QString strChild                     = QStringLiteral("child");
+static const QString strPointOfIntersectionCurves = QStringLiteral("pointOfIntersectionCurves");
+static const QString strCurveIntersectAxis        = QStringLiteral("curveIntersectAxis");
+static const QString strCurve                     = QStringLiteral("curve");
+static const QString strCurve1                    = QStringLiteral("curve1");
+static const QString strCurve2                    = QStringLiteral("curve2");
+static const QString strModelingPath              = QStringLiteral("modelingPath");
+static const QString strModelingSpline            = QStringLiteral("modelingSpline");
+static const QString strPointFromArcAndTangent    = QStringLiteral("pointFromArcAndTangent");
+static const QString strPointOfIntersectionArcs   = QStringLiteral("pointOfIntersectionArcs");
+static const QString strFirstArc                  = QStringLiteral("firstArc");
+static const QString strSecondArc                 = QStringLiteral("secondArc");
+static const QString strDetail                    = QStringLiteral("detail");
+static const QString strSupplement                = QStringLiteral("supplement");
+static const QString strClosed                    = QStringLiteral("closed");
+static const QString strWidth                     = QStringLiteral("width");
+static const QString strNode                      = QStringLiteral("node");
+static const QString strNodes                     = QStringLiteral("nodes");
+static const QString strData                      = QStringLiteral("data");
+static const QString strPatternInfo               = QStringLiteral("patternInfo");
+static const QString strGrainline                 = QStringLiteral("grainline");
+static const QString strReverse                   = QStringLiteral("reverse");
+static const QString strMx                        = QStringLiteral("mx");
+static const QString strMy                        = QStringLiteral("my");
+static const QString strForbidFlipping            = QStringLiteral("forbidFlipping");
+static const QString strInLayout                  = QStringLiteral("inLayout");
+static const QString strSeamAllowance             = QStringLiteral("seamAllowance");
+static const QString strNodeType                  = QStringLiteral("nodeType");
+static const QString strDet                       = QStringLiteral("det");
+static const QString strTypeObject                = QStringLiteral("typeObject");
 
 //---------------------------------------------------------------------------------------------------------------------
 VPatternConverter::VPatternConverter(const QString &fileName)
@@ -177,6 +195,8 @@ QString VPatternConverter::XSDSchema(int ver) const
         case (0x000308):
             return QStringLiteral("://schema/pattern/v0.3.8.xsd");
         case (0x000309):
+            return QStringLiteral("://schema/pattern/v0.3.9.xsd");
+        case (0x000400):
             return CurrentSchema;
         default:
             InvalidVersion(ver);
@@ -280,6 +300,9 @@ void VPatternConverter::ApplyPatches()
                 ValidateXML(XSDSchema(0x000309), fileName);
                 V_FALLTHROUGH
             case (0x000309):
+                ToV0_4_0();
+                ValidateXML(XSDSchema(0x000400), fileName);
+            case (0x000400):
                 break;
             default:
                 break;
@@ -314,6 +337,10 @@ void VPatternConverter::DowngradeToCurrentMaxVersion()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_1_1()
 {
+    // TODO. Delete if minimal supported version is 0.1.1
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 1, 1),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.1.1"));
     Save();
 }
@@ -321,6 +348,10 @@ void VPatternConverter::ToV0_1_1()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_1_2()
 {
+    // TODO. Delete if minimal supported version is 0.1.2
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 1, 2),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.1.2"));
     Save();
 }
@@ -328,6 +359,10 @@ void VPatternConverter::ToV0_1_2()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_1_3()
 {
+    // TODO. Delete if minimal supported version is 0.1.3
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 1, 3),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.1.3"));
     Save();
 }
@@ -335,6 +370,10 @@ void VPatternConverter::ToV0_1_3()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_1_4()
 {
+    // TODO. Delete if minimal supported version is 0.1.4
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 1, 4),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.1.4"));
     Save();
 }
@@ -342,6 +381,10 @@ void VPatternConverter::ToV0_1_4()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_2_0()
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.2.0"));
     TagUnitToV0_2_0();
     TagIncrementToV0_2_0();
@@ -353,6 +396,10 @@ void VPatternConverter::ToV0_2_0()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_2_1()
 {
+    // TODO. Delete if minimal supported version is 0.2.1
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 1),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.2.1"));
     ConvertMeasurementsToV0_2_1();
     Save();
@@ -361,6 +408,10 @@ void VPatternConverter::ToV0_2_1()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_2_2()
 {
+    // TODO. Delete if minimal supported version is 0.2.2
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 2),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.2.2"));
     Save();
 }
@@ -368,6 +419,10 @@ void VPatternConverter::ToV0_2_2()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_2_3()
 {
+    // TODO. Delete if minimal supported version is 0.2.3
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 3),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.2.3"));
     Save();
 }
@@ -375,6 +430,10 @@ void VPatternConverter::ToV0_2_3()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_2_4()
 {
+    // TODO. Delete if minimal supported version is 0.2.4
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 4),
+                      "Time to refactor the code.");
+
     FixToolUnionToV0_2_4();
     SetVersion(QStringLiteral("0.2.4"));
     Save();
@@ -383,6 +442,10 @@ void VPatternConverter::ToV0_2_4()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_2_5()
 {
+    // TODO. Delete if minimal supported version is 0.2.5
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 5),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.2.5"));
     Save();
 }
@@ -390,6 +453,10 @@ void VPatternConverter::ToV0_2_5()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_2_6()
 {
+    // TODO. Delete if minimal supported version is 0.2.6
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 6),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.2.6"));
     Save();
 }
@@ -397,6 +464,10 @@ void VPatternConverter::ToV0_2_6()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_2_7()
 {
+    // TODO. Delete if minimal supported version is 0.2.7
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 7),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.2.7"));
     Save();
 }
@@ -404,6 +475,10 @@ void VPatternConverter::ToV0_2_7()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_3_0()
 {
+    // TODO. Delete if minimal supported version is 0.3.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 3, 0),
+                      "Time to refactor the code.");
+
     //Cutting path do not create anymore subpaths
     FixCutPoint();
     FixCutPoint();
@@ -414,6 +489,10 @@ void VPatternConverter::ToV0_3_0()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_3_1()
 {
+    // TODO. Delete if minimal supported version is 0.3.1
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 3, 1),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.3.1"));
     RemoveColorToolCutV0_3_1();
     Save();
@@ -422,6 +501,10 @@ void VPatternConverter::ToV0_3_1()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_3_2()
 {
+    // TODO. Delete if minimal supported version is 0.3.2
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 3, 2),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.3.2"));
     Save();
 }
@@ -429,6 +512,10 @@ void VPatternConverter::ToV0_3_2()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_3_3()
 {
+    // TODO. Delete if minimal supported version is 0.3.3
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 3, 3),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.3.3"));
     Save();
 }
@@ -436,6 +523,10 @@ void VPatternConverter::ToV0_3_3()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_3_4()
 {
+    // TODO. Delete if minimal supported version is 0.3.4
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 3, 4),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.3.4"));
     Save();
 }
@@ -443,6 +534,10 @@ void VPatternConverter::ToV0_3_4()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_3_5()
 {
+    // TODO. Delete if minimal supported version is 0.3.5
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 3, 5),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.3.5"));
     Save();
 }
@@ -450,6 +545,10 @@ void VPatternConverter::ToV0_3_5()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_3_6()
 {
+    // TODO. Delete if minimal supported version is 0.3.6
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 3, 6),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.3.6"));
     Save();
 }
@@ -457,6 +556,10 @@ void VPatternConverter::ToV0_3_6()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_3_7()
 {
+    // TODO. Delete if minimal supported version is 0.3.7
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 3, 7),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.3.7"));
     Save();
 }
@@ -464,6 +567,10 @@ void VPatternConverter::ToV0_3_7()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ToV0_3_8()
 {
+    // TODO. Delete if minimal supported version is 0.3.8
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 3, 8),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.3.8"));
     Save();
 }
@@ -475,9 +582,27 @@ void VPatternConverter::ToV0_3_9()
     Save();
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+void VPatternConverter::ToV0_4_0()
+{
+    // TODO. Delete if minimal supported version is 0.4.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 4, 0),
+                      "Time to refactor the code.");
+
+    SetVersion(QStringLiteral("0.4.0"));
+    TagRemoveAttributeTypeObjectInV0_4_0();
+    TagDetailToV0_4_0();
+    TagUnionDetailsToV0_4_0();
+    Save();
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::TagUnitToV0_2_0()
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     QDomElement unit = createElement(strUnit);
     QDomText newNodeText = createTextNode(MUnitV0_1_4());
     unit.appendChild(newNodeText);
@@ -489,6 +614,10 @@ void VPatternConverter::TagUnitToV0_2_0()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::TagIncrementToV0_2_0()
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     const QSet<QString> names = FixIncrementsToV0_2_0();
 
     FixPointExpressionsToV0_2_0(names);
@@ -499,6 +628,10 @@ void VPatternConverter::TagIncrementToV0_2_0()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ConvertMeasurementsToV0_2_0()
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     const QMap<QString, QString> names = OldNamesToNewNames_InV0_2_0();
     ConvertPointExpressionsToV0_2_0(names);
     ConvertArcExpressionsToV0_2_0(names);
@@ -508,6 +641,10 @@ void VPatternConverter::ConvertMeasurementsToV0_2_0()
 //---------------------------------------------------------------------------------------------------------------------
 QSet<QString> VPatternConverter::FixIncrementsToV0_2_0()
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     QSet<QString> names;
     const QDomElement incr = TagIncrementsV0_1_4();
     QDomNode domNode = incr.firstChild();
@@ -550,6 +687,10 @@ QSet<QString> VPatternConverter::FixIncrementsToV0_2_0()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::FixPointExpressionsToV0_2_0(const QSet<QString> &names)
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     QString formula;
     const QDomNodeList list = elementsByTagName(strPoint);
     for (int i=0; i < list.size(); ++i)
@@ -610,6 +751,10 @@ void VPatternConverter::FixPointExpressionsToV0_2_0(const QSet<QString> &names)
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::FixArcExpressionsToV0_2_0(const QSet<QString> &names)
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     QString formula;
     const QDomNodeList list = elementsByTagName(strArc);
     for (int i=0; i < list.size(); ++i)
@@ -661,6 +806,10 @@ void VPatternConverter::FixArcExpressionsToV0_2_0(const QSet<QString> &names)
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::FixPathPointExpressionsToV0_2_0(const QSet<QString> &names)
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     QString formula;
     const QDomNodeList list = elementsByTagName(strPathPoint);
     for (int i=0; i < list.size(); ++i)
@@ -702,6 +851,10 @@ void VPatternConverter::FixPathPointExpressionsToV0_2_0(const QSet<QString> &nam
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ConvertPointExpressionsToV0_2_0(const QMap<QString, QString> &names)
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     QString formula;
     const QDomNodeList list = elementsByTagName(strPoint);
     for (int i=0; i < list.size(); ++i)
@@ -762,6 +915,10 @@ void VPatternConverter::ConvertPointExpressionsToV0_2_0(const QMap<QString, QStr
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ConvertArcExpressionsToV0_2_0(const QMap<QString, QString> &names)
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     QString formula;
     const QDomNodeList list = elementsByTagName(strArc);
     for (int i=0; i < list.size(); ++i)
@@ -813,6 +970,10 @@ void VPatternConverter::ConvertArcExpressionsToV0_2_0(const QMap<QString, QStrin
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ConvertPathPointExpressionsToV0_2_0(const QMap<QString, QString> &names)
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     QString formula;
     const QDomNodeList list = elementsByTagName(strPathPoint);
     for (int i=0; i < list.size(); ++i)
@@ -854,6 +1015,10 @@ void VPatternConverter::ConvertPathPointExpressionsToV0_2_0(const QMap<QString,
 //---------------------------------------------------------------------------------------------------------------------
 QString VPatternConverter::FixMeasurementInFormulaToV0_2_0(const QString &formula, const QMap<QString, QString> &names)
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     QScopedPointer<qmu::QmuTokenParser> cal(new qmu::QmuTokenParser(formula, false, false));// Eval formula
     QMap<int, QString> tokens = cal->GetTokens();// Tokens (variables, measurements)
     delete cal.take();
@@ -884,6 +1049,10 @@ QString VPatternConverter::FixMeasurementInFormulaToV0_2_0(const QString &formul
 //---------------------------------------------------------------------------------------------------------------------
 QString VPatternConverter::FixIncrementInFormulaToV0_2_0(const QString &formula, const QSet<QString> &names)
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     qmu::QmuTokenParser *cal = new qmu::QmuTokenParser(formula, false, false);// Eval formula
     QMap<int, QString> tokens = cal->GetTokens();// Tokens (variables, measurements)
     delete cal;
@@ -914,6 +1083,10 @@ QString VPatternConverter::FixIncrementInFormulaToV0_2_0(const QString &formula,
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::TagMeasurementsToV0_2_0()
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     QDomElement ms = TagMeasurementsV0_1_4();
     const QString path = GetParametrString(ms, strPath);
 
@@ -928,6 +1101,10 @@ void VPatternConverter::TagMeasurementsToV0_2_0()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ConvertMeasurementsToV0_2_1()
 {
+    // TODO. Delete if minimal supported version is 0.2.1
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 1),
+                      "Time to refactor the code.");
+
     const QMap<QString, QString> names = OldNamesToNewNames_InV0_2_1();
 
     // Structure did not change. We can use the same code.
@@ -939,6 +1116,10 @@ void VPatternConverter::ConvertMeasurementsToV0_2_1()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::RemoveColorToolCutV0_3_1()
 {
+    // TODO. Delete if minimal supported version is 0.3.1
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 3, 1),
+                      "Time to refactor the code.");
+
     const QDomNodeList list = elementsByTagName(strPoint);
     for (int i=0; i < list.size(); ++i)
     {
@@ -957,6 +1138,10 @@ void VPatternConverter::RemoveColorToolCutV0_3_1()
 //---------------------------------------------------------------------------------------------------------------------
 QString VPatternConverter::MUnitV0_1_4() const
 {
+    // TODO. Delete if minimal supported version is 0.1.4
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 1, 4),
+                      "Time to refactor the code.");
+
     const QDomElement element = TagMeasurementsV0_1_4();
     try
     {
@@ -973,6 +1158,10 @@ QString VPatternConverter::MUnitV0_1_4() const
 //---------------------------------------------------------------------------------------------------------------------
 QDomElement VPatternConverter::TagMeasurementsV0_1_4() const
 {
+    // TODO. Delete if minimal supported version is 0.1.4
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 1, 4),
+                      "Time to refactor the code.");
+
     const QDomNodeList list = elementsByTagName(strMeasurements);
     const QDomElement element = list.at(0).toElement();
     if (not element.isElement())
@@ -986,6 +1175,10 @@ QDomElement VPatternConverter::TagMeasurementsV0_1_4() const
 //---------------------------------------------------------------------------------------------------------------------
 QDomElement VPatternConverter::TagIncrementsV0_1_4() const
 {
+    // TODO. Delete if minimal supported version is 0.1.4
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 1, 4),
+                      "Time to refactor the code.");
+
     const QDomNodeList list = elementsByTagName(strIncrements);
     const QDomElement element = list.at(0).toElement();
     if (not element.isElement())
@@ -999,6 +1192,10 @@ QDomElement VPatternConverter::TagIncrementsV0_1_4() const
 //---------------------------------------------------------------------------------------------------------------------
 QStringList VPatternConverter::ListPathPointExpressionsV0_1_4() const
 {
+    // TODO. Delete if minimal supported version is 0.1.4
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 1, 4),
+                      "Time to refactor the code.");
+
     QStringList expressions;
     const QDomNodeList list = elementsByTagName(strPathPoint);
     for (int i=0; i < list.size(); ++i)
@@ -1039,6 +1236,10 @@ QStringList VPatternConverter::ListPathPointExpressionsV0_1_4() const
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::FixToolUnionToV0_2_4()
 {
+    // TODO. Delete if minimal supported version is 0.2.4
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 4),
+                      "Time to refactor the code.");
+
     QDomElement root = documentElement();
     const QDomNodeList modelings = root.elementsByTagName(strModeling);
     for (int i=0; i<modelings.size(); ++i)
@@ -1050,6 +1251,10 @@ void VPatternConverter::FixToolUnionToV0_2_4()
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::ParseModelingToV0_2_4(const QDomElement &modeling)
 {
+    // TODO. Delete if minimal supported version is 0.2.4
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 4),
+                      "Time to refactor the code.");
+
     QDomElement node = modeling.firstChild().toElement();
     while (not node.isNull())
     {
@@ -1085,6 +1290,10 @@ void VPatternConverter::ParseModelingToV0_2_4(const QDomElement &modeling)
 //---------------------------------------------------------------------------------------------------------------------
 void VPatternConverter::SaveChildrenToolUnionToV0_2_4(quint32 id, const QVector<quint32> &children)
 {
+    // TODO. Delete if minimal supported version is 0.2.4
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 4),
+                      "Time to refactor the code.");
+
     QDomElement toolUnion = elementById(id);
     if (toolUnion.isNull())
     {
@@ -1106,6 +1315,10 @@ void VPatternConverter::SaveChildrenToolUnionToV0_2_4(quint32 id, const QVector<
 //---------------------------------------------------------------------------------------------------------------------
 QMap<QString, QString> VPatternConverter::OldNamesToNewNames_InV0_2_0()
 {
+    // TODO. Delete if minimal supported version is 0.2.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 0),
+                      "Time to refactor the code.");
+
     // old name, new name
     QMap<QString, QString> names;
 
@@ -1282,6 +1495,10 @@ QMap<QString, QString> VPatternConverter::OldNamesToNewNames_InV0_2_0()
 //---------------------------------------------------------------------------------------------------------------------
 QMap<QString, QString> VPatternConverter::OldNamesToNewNames_InV0_2_1()
 {
+    // TODO. Delete if minimal supported version is 0.2.1
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 2, 1),
+                      "Time to refactor the code.");
+
     // old name, new name
     QMap<QString, QString> names;
 
@@ -1480,3 +1697,225 @@ void VPatternConverter::FixSubPaths(int i, quint32 id, quint32 baseCurve)
         }
     }
 }
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPatternConverter::TagRemoveAttributeTypeObjectInV0_4_0()
+{
+    // TODO. Delete if minimal supported version is 0.4.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 4, 0),
+                      "Time to refactor the code.");
+
+    const QDomNodeList list = elementsByTagName(strModeling);
+    for (int i = 0; i < list.size(); ++i)
+    {
+        QDomElement modeling = list.at(i).toElement();
+        if (not modeling.isNull())
+        {
+            QDomNode domNode = modeling.firstChild();
+            while (not domNode.isNull())
+            {
+                QDomElement domElement = domNode.toElement();
+                if (not domElement.isNull())
+                {
+                    if (domElement.hasAttribute(strTypeObject))
+                    {
+                        domElement.removeAttribute(strTypeObject);
+                    }
+                }
+                domNode = domNode.nextSibling();
+            }
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPatternConverter::TagDetailToV0_4_0()
+{
+    // TODO. Delete if minimal supported version is 0.4.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 4, 0),
+                      "Time to refactor the code.");
+
+    const QDomNodeList list = elementsByTagName(strDetail);
+    for (int i=0; i < list.size(); ++i)
+    {
+        QDomElement dom = list.at(i).toElement();
+
+        if (not dom.isNull())
+        {
+            dom.setAttribute(strSeamAllowance, dom.attribute(strSupplement, "0"));
+            dom.removeAttribute(strSupplement);
+
+            dom.setAttribute(strVersion, "1");
+
+            const QStringList tags = QStringList() << strNode << strData << strPatternInfo << strGrainline;
+
+            QDomElement tagData;
+            QDomElement tagPatternInfo;
+            QDomElement tagGrainline;
+            QDomElement tagNodes = createElement(strNodes);
+
+            const QDomNodeList childList = dom.childNodes();
+            for (qint32 i = 0; i < childList.size(); ++i)
+            {
+                const QDomElement element = childList.at(i).toElement();
+                if (not element.isNull())
+                {
+                    switch (tags.indexOf(element.tagName()))
+                    {
+                        case 0://strNode
+                        {
+                            QDomElement tagNode = createElement(strNode);
+
+                            tagNode.setAttribute(strIdObject, element.attribute(strIdObject, NULL_ID_STR));
+
+                            if (element.hasAttribute(strReverse))
+                            {
+                                tagNode.setAttribute(strReverse, element.attribute(strReverse, "0"));
+                            }
+
+                            if (element.hasAttribute(strMx))
+                            {
+                                tagNode.setAttribute(strMx, element.attribute(strMx, "0"));
+                            }
+
+                            if (element.hasAttribute(strMy))
+                            {
+                                tagNode.setAttribute(strMy, element.attribute(strMy, "0"));
+                            }
+
+                            tagNode.setAttribute(strType, element.attribute(strType, ""));
+
+                            tagNodes.appendChild(tagNode);
+
+                            break;
+                        }
+                        case 1://strData
+                            tagData = element.cloneNode().toElement();
+                            break;
+                        case 2://strPatternInfo
+                            tagPatternInfo = element.cloneNode().toElement();
+                            break;
+                        case 3://strGrainline
+                            tagGrainline = element.cloneNode().toElement();
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
+
+            RemoveAllChildren(dom);
+
+            dom.appendChild(tagData);
+            dom.appendChild(tagPatternInfo);
+            dom.appendChild(tagGrainline);
+            dom.appendChild(tagNodes);
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QDomElement VPatternConverter::GetUnionDetailNodesV0_4_0(const QDomElement &detail)
+{
+    QDomElement tagNodes = createElement(strNodes);
+
+    if (not detail.isNull())
+    {
+        const QDomNodeList childList = detail.childNodes();
+        for (qint32 i = 0; i < childList.size(); ++i)
+        {
+            const QDomElement node = childList.at(i).toElement();
+            if (not node.isNull())
+            {
+                QDomElement tagNode = createElement(strNode);
+
+                tagNode.setAttribute(strIdObject, node.attribute(strIdObject, NULL_ID_STR));
+
+                if (node.hasAttribute(strReverse))
+                {
+                    tagNode.setAttribute(strReverse, node.attribute(strReverse, "0"));
+                }
+
+                tagNode.setAttribute(strType, node.attribute(strType, ""));
+
+                tagNodes.appendChild(tagNode);
+            }
+        }
+    }
+
+    return tagNodes;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QDomElement VPatternConverter::GetUnionChildrenNodesV0_4_0(const QDomElement &detail)
+{
+    QDomElement tagNodes = createElement(strNodes);
+
+    if (not detail.isNull())
+    {
+        const QDomNodeList childList = detail.childNodes();
+        for (qint32 i = 0; i < childList.size(); ++i)
+        {
+            const QDomElement node = childList.at(i).toElement();
+            if (not node.isNull())
+            {
+                QDomElement tagNode = node.cloneNode().toElement();
+                tagNodes.appendChild(tagNode);
+            }
+        }
+    }
+
+    return tagNodes;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPatternConverter::TagUnionDetailsToV0_4_0()
+{
+    // TODO. Delete if minimal supported version is 0.4.0
+    Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 4, 0),
+                      "Time to refactor the code.");
+
+    const QDomNodeList list = elementsByTagName(strTools);
+    for (int i=0; i < list.size(); ++i)
+    {
+        // Tag 'tools' used only for union details, so no need to check any additional attributes
+        QDomElement toolDOM = list.at(i).toElement();
+        if (not toolDOM.isNull())
+        {
+            const QStringList tags = QStringList() << strDet << strChildren;
+
+            QVector<QDomElement> nodes;
+            QDomElement tagChildrenNodes = createElement(strChildren);
+
+            const QDomNodeList childList = toolDOM.childNodes();
+            for (qint32 i = 0; i < childList.size(); ++i)
+            {
+                const QDomElement element = childList.at(i).toElement();
+                if (not element.isNull())
+                {
+                    switch (tags.indexOf(element.tagName()))
+                    {
+                        case 0://strDet
+                            nodes.append(GetUnionDetailNodesV0_4_0(element));
+                            break;
+                        case 1://strChildren
+                            tagChildrenNodes.appendChild(GetUnionChildrenNodesV0_4_0(element));
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
+
+            RemoveAllChildren(toolDOM);
+
+            for (int i = 0; i < nodes.size(); ++i)
+            {
+                QDomElement tagDet = createElement(strDet);
+                tagDet.appendChild(nodes.at(i));
+                toolDOM.appendChild(tagDet);
+            }
+            toolDOM.appendChild(tagChildrenNodes);
+        }
+    }
+}
diff --git a/src/libs/ifc/xml/vpatternconverter.h b/src/libs/ifc/xml/vpatternconverter.h
index 2a3676c25..3341fecaf 100644
--- a/src/libs/ifc/xml/vpatternconverter.h
+++ b/src/libs/ifc/xml/vpatternconverter.h
@@ -55,10 +55,10 @@ public:
 // GCC 4.6 doesn't allow constexpr and const together
 #if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) <= 406
     static Q_DECL_CONSTEXPR int PatternMinVer = CONVERTER_VERSION_CHECK(0, 1, 0);
-    static Q_DECL_CONSTEXPR int PatternMaxVer = CONVERTER_VERSION_CHECK(0, 3, 9);
+    static Q_DECL_CONSTEXPR int PatternMaxVer = CONVERTER_VERSION_CHECK(0, 4, 0);
 #else
     static Q_DECL_CONSTEXPR const int PatternMinVer = CONVERTER_VERSION_CHECK(0, 1, 0);
-    static Q_DECL_CONSTEXPR const int PatternMaxVer = CONVERTER_VERSION_CHECK(0, 3, 9);
+    static Q_DECL_CONSTEXPR const int PatternMaxVer = CONVERTER_VERSION_CHECK(0, 4, 0);
 #endif
 
 protected:
@@ -98,6 +98,7 @@ private:
     void ToV0_3_7();
     void ToV0_3_8();
     void ToV0_3_9();
+    void ToV0_4_0();
 
     void          TagUnitToV0_2_0();
     void          TagIncrementToV0_2_0();
@@ -133,6 +134,12 @@ private:
 
     void FixCutPoint();
     void FixSubPaths(int i, quint32 id, quint32 baseCurve);
+
+    void TagRemoveAttributeTypeObjectInV0_4_0();
+    void TagDetailToV0_4_0();
+    void TagUnionDetailsToV0_4_0();
+    QDomElement GetUnionDetailNodesV0_4_0(const QDomElement &detail);
+    QDomElement GetUnionChildrenNodesV0_4_0(const QDomElement &detail);
 };
 
 //---------------------------------------------------------------------------------------------------------------------
diff --git a/src/libs/ifc/xml/vvitconverter.cpp b/src/libs/ifc/xml/vvitconverter.cpp
index bb5c857c9..49c7a397d 100644
--- a/src/libs/ifc/xml/vvitconverter.cpp
+++ b/src/libs/ifc/xml/vvitconverter.cpp
@@ -150,6 +150,10 @@ void VVITConverter::DowngradeToCurrentMaxVersion()
 //---------------------------------------------------------------------------------------------------------------------
 void VVITConverter::AddNewTagsForV0_3_0()
 {
+    // TODO. Delete if minimal supported version is 0.3.0
+    Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 3, 0),
+                      "Time to refactor the code.");
+
     QDomElement rootElement = this->documentElement();
     QDomNode refChild = rootElement.firstChildElement("version");
 
@@ -168,12 +172,20 @@ void VVITConverter::AddNewTagsForV0_3_0()
 //---------------------------------------------------------------------------------------------------------------------
 QString VVITConverter::MUnitV0_2_0()
 {
+    // TODO. Delete if minimal supported version is 0.3.0
+    Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 3, 0),
+                      "Time to refactor the code.");
+
     return UniqueTagText(QStringLiteral("unit"), QStringLiteral("cm"));
 }
 
 //---------------------------------------------------------------------------------------------------------------------
 void VVITConverter::ConvertMeasurementsToV0_3_0()
 {
+    // TODO. Delete if minimal supported version is 0.3.0
+    Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 3, 0),
+                      "Time to refactor the code.");
+
     const QString tagBM = QStringLiteral("body-measurements");
 
     QDomElement bm = createElement(tagBM);
@@ -213,6 +225,10 @@ void VVITConverter::ConvertMeasurementsToV0_3_0()
 //---------------------------------------------------------------------------------------------------------------------
 QDomElement VVITConverter::AddMV0_3_0(const QString &name, qreal value)
 {
+    // TODO. Delete if minimal supported version is 0.3.0
+    Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 3, 0),
+                      "Time to refactor the code.");
+
     QDomElement element = createElement(QStringLiteral("m"));
 
     SetAttribute(element, QStringLiteral("name"), name);
@@ -226,6 +242,10 @@ QDomElement VVITConverter::AddMV0_3_0(const QString &name, qreal value)
 //---------------------------------------------------------------------------------------------------------------------
 void VVITConverter::GenderV0_3_1()
 {
+    // TODO. Delete if minimal supported version is 0.3.1
+    Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 3, 1),
+                      "Time to refactor the code.");
+
     const QDomNodeList nodeList = this->elementsByTagName(QStringLiteral("sex"));
     QDomElement sex = nodeList.at(0).toElement();
 
@@ -239,6 +259,10 @@ void VVITConverter::GenderV0_3_1()
 //---------------------------------------------------------------------------------------------------------------------
 void VVITConverter::PM_SystemV0_3_2()
 {
+    // TODO. Delete if minimal supported version is 0.3.2
+    Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 3, 2),
+                      "Time to refactor the code.");
+
     QDomElement pm_system = createElement(QStringLiteral("pm_system"));
     pm_system.appendChild(createTextNode(QStringLiteral("998")));
 
@@ -252,6 +276,10 @@ void VVITConverter::PM_SystemV0_3_2()
 //---------------------------------------------------------------------------------------------------------------------
 void VVITConverter::ConvertMeasurementsToV0_3_3()
 {
+    // TODO. Delete if minimal supported version is 0.3.3
+    Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 3, 3),
+                      "Time to refactor the code.");
+
     const QMap<QString, QString> names = OldNamesToNewNames_InV0_3_3();
     auto i = names.constBegin();
     while (i != names.constEnd())
@@ -281,6 +309,10 @@ void VVITConverter::ConvertMeasurementsToV0_3_3()
 //---------------------------------------------------------------------------------------------------------------------
 void VVITConverter::ToV0_3_0()
 {
+    // TODO. Delete if minimal supported version is 0.3.0
+    Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 3, 0),
+                      "Time to refactor the code.");
+
     AddRootComment();
     SetVersion(QStringLiteral("0.3.0"));
     AddNewTagsForV0_3_0();
@@ -291,6 +323,10 @@ void VVITConverter::ToV0_3_0()
 //---------------------------------------------------------------------------------------------------------------------
 void VVITConverter::ToV0_3_1()
 {
+    // TODO. Delete if minimal supported version is 0.3.1
+    Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 3, 1),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.3.1"));
     GenderV0_3_1();
     Save();
@@ -299,6 +335,10 @@ void VVITConverter::ToV0_3_1()
 //---------------------------------------------------------------------------------------------------------------------
 void VVITConverter::ToV0_3_2()
 {
+    // TODO. Delete if minimal supported version is 0.3.2
+    Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 3, 2),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.3.2"));
     PM_SystemV0_3_2();
     Save();
@@ -307,6 +347,10 @@ void VVITConverter::ToV0_3_2()
 //---------------------------------------------------------------------------------------------------------------------
 void VVITConverter::ToV0_3_3()
 {
+    // TODO. Delete if minimal supported version is 0.3.3
+    Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 3, 3),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.3.3"));
     ConvertMeasurementsToV0_3_3();
     Save();
diff --git a/src/libs/ifc/xml/vvstconverter.cpp b/src/libs/ifc/xml/vvstconverter.cpp
index 051255156..5f7518dbf 100644
--- a/src/libs/ifc/xml/vvstconverter.cpp
+++ b/src/libs/ifc/xml/vvstconverter.cpp
@@ -150,6 +150,10 @@ void VVSTConverter::DowngradeToCurrentMaxVersion()
 //---------------------------------------------------------------------------------------------------------------------
 void VVSTConverter::AddNewTagsForV0_4_0()
 {
+    // TODO. Delete if minimal supported version is 0.4.0
+    Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 4, 0),
+                      "Time to refactor the code.");
+
     QDomElement rootElement = this->documentElement();
     QDomNode refChild = rootElement.firstChildElement("version");
 
@@ -171,6 +175,10 @@ void VVSTConverter::AddNewTagsForV0_4_0()
 //---------------------------------------------------------------------------------------------------------------------
 void VVSTConverter::RemoveTagsForV0_4_0()
 {
+    // TODO. Delete if minimal supported version is 0.4.0
+    Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 4, 0),
+                      "Time to refactor the code.");
+
     QDomElement rootElement = this->documentElement();
 
     {
@@ -193,6 +201,10 @@ void VVSTConverter::RemoveTagsForV0_4_0()
 //---------------------------------------------------------------------------------------------------------------------
 void VVSTConverter::ConvertMeasurementsToV0_4_0()
 {
+    // TODO. Delete if minimal supported version is 0.4.0
+    Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 4, 0),
+                      "Time to refactor the code.");
+
     const QString tagBM = QStringLiteral("body-measurements");
 
     QDomElement bm = createElement(tagBM);
@@ -239,6 +251,10 @@ void VVSTConverter::ConvertMeasurementsToV0_4_0()
 //---------------------------------------------------------------------------------------------------------------------
 QDomElement VVSTConverter::AddMV0_4_0(const QString &name, qreal value, qreal sizeIncrease, qreal heightIncrease)
 {
+    // TODO. Delete if minimal supported version is 0.4.0
+    Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 4, 0),
+                      "Time to refactor the code.");
+
     QDomElement element = createElement(QStringLiteral("m"));
 
     SetAttribute(element, QStringLiteral("name"), name);
@@ -254,6 +270,10 @@ QDomElement VVSTConverter::AddMV0_4_0(const QString &name, qreal value, qreal si
 //---------------------------------------------------------------------------------------------------------------------
 void VVSTConverter::PM_SystemV0_4_1()
 {
+    // TODO. Delete if minimal supported version is 0.4.1
+    Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 4, 1),
+                      "Time to refactor the code.");
+
     QDomElement pm_system = createElement(QStringLiteral("pm_system"));
     pm_system.appendChild(createTextNode(QStringLiteral("998")));
 
@@ -267,6 +287,10 @@ void VVSTConverter::PM_SystemV0_4_1()
 //---------------------------------------------------------------------------------------------------------------------
 void VVSTConverter::ConvertMeasurementsToV0_4_2()
 {
+    // TODO. Delete if minimal supported version is 0.4.2
+    Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 4, 2),
+                      "Time to refactor the code.");
+
     const QMap<QString, QString> names = OldNamesToNewNames_InV0_3_3();
     auto i = names.constBegin();
     while (i != names.constEnd())
@@ -296,6 +320,10 @@ void VVSTConverter::ConvertMeasurementsToV0_4_2()
 //---------------------------------------------------------------------------------------------------------------------
 void VVSTConverter::ToV0_4_0()
 {
+    // TODO. Delete if minimal supported version is 0.4.0
+    Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 4, 0),
+                      "Time to refactor the code.");
+
     AddRootComment();
     SetVersion(QStringLiteral("0.4.0"));
     AddNewTagsForV0_4_0();
@@ -307,6 +335,10 @@ void VVSTConverter::ToV0_4_0()
 //---------------------------------------------------------------------------------------------------------------------
 void VVSTConverter::ToV0_4_1()
 {
+    // TODO. Delete if minimal supported version is 0.4.1
+    Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 4, 1),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.4.1"));
     PM_SystemV0_4_1();
     Save();
@@ -315,6 +347,10 @@ void VVSTConverter::ToV0_4_1()
 //---------------------------------------------------------------------------------------------------------------------
 void VVSTConverter::ToV0_4_2()
 {
+    // TODO. Delete if minimal supported version is 0.4.2
+    Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 4, 2),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.4.2"));
     ConvertMeasurementsToV0_4_2();
     Save();
@@ -323,6 +359,10 @@ void VVSTConverter::ToV0_4_2()
 //---------------------------------------------------------------------------------------------------------------------
 void VVSTConverter::ToV0_4_3()
 {
+    // TODO. Delete if minimal supported version is 0.4.3
+    Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < CONVERTER_VERSION_CHECK(0, 4, 3),
+                      "Time to refactor the code.");
+
     SetVersion(QStringLiteral("0.4.3"));
     Save();
 }
diff --git a/src/libs/vgeometry/vabstractcurve.cpp b/src/libs/vgeometry/vabstractcurve.cpp
index d50762799..5d00aca93 100644
--- a/src/libs/vgeometry/vabstractcurve.cpp
+++ b/src/libs/vgeometry/vabstractcurve.cpp
@@ -236,6 +236,37 @@ bool VAbstractCurve::IsIntersectLine(const QLineF &line) const
     return not points.isEmpty();
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+bool VAbstractCurve::IsPointOnCurve(const QVector<QPointF> &points, const QPointF &p)
+{
+    if (points.isEmpty())
+    {
+        return false;
+    }
+    else if (points.size() < 2)
+    {
+        return points.at(0) == p;
+    }
+    else
+    {
+        for (qint32 i = 0; i < points.count()-1; ++i)
+        {
+            if (IsPointOnLineSegment(p, points.at(i), points.at(i+1)))
+            {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VAbstractCurve::IsPointOnCurve(const QPointF &p) const
+{
+    return IsPointOnCurve(GetPoints(), p);
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 quint32 VAbstractCurve::GetDuplicate() const
 {
@@ -321,6 +352,11 @@ QPainterPath VAbstractCurve::ShowDirection(const QVector<QPointF> &points) const
 //---------------------------------------------------------------------------------------------------------------------
 qreal VAbstractCurve::PathLength(const QVector<QPointF> &path)
 {
+    if (path.size() < 2)
+    {
+        return 0;
+    }
+
     QPainterPath splinePath;
     splinePath.moveTo(path.at(0));
     for (qint32 i = 1; i < path.count(); ++i)
diff --git a/src/libs/vgeometry/vabstractcurve.h b/src/libs/vgeometry/vabstractcurve.h
index 13d16969c..6cad2bb9c 100644
--- a/src/libs/vgeometry/vabstractcurve.h
+++ b/src/libs/vgeometry/vabstractcurve.h
@@ -70,6 +70,9 @@ public:
     virtual QVector<QPointF> IntersectLine(const QLineF &line) const;
     virtual bool             IsIntersectLine(const QLineF &line) const;
 
+    static bool              IsPointOnCurve(const QVector<QPointF> &points, const QPointF &p);
+    bool                     IsPointOnCurve(const QPointF &p) const;
+
     virtual qreal            GetStartAngle () const=0;
     virtual qreal            GetEndAngle () const=0;
 
@@ -79,13 +82,14 @@ public:
     QString                  GetColor() const;
     void                     SetColor(const QString &color);
 
+    static qreal             PathLength(const QVector<QPointF> &path);
+
     static QVector<QPointF>  CurveIntersectLine(const QVector<QPointF> &points, const QLineF &line);
 
     virtual QString          NameForHistory(const QString &toolName) const=0;
 protected:
     QPainterPath             ShowDirection(const QVector<QPointF> &points) const;
     virtual void             CreateName() =0;
-    static qreal             PathLength(const QVector<QPointF> &path);
 private:
     QSharedDataPointer<VAbstractCurveData> d;
 
diff --git a/src/libs/vgeometry/vgobject.cpp b/src/libs/vgeometry/vgobject.cpp
index 3ac67e251..a72e0b8c8 100644
--- a/src/libs/vgeometry/vgobject.cpp
+++ b/src/libs/vgeometry/vgobject.cpp
@@ -539,28 +539,6 @@ int VGObject::PointInCircle(const QPointF &p, const QPointF &center, qreal radiu
     return 2; // inside circle
 }
 
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @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(points.size());
-    qint32 j = 0;
-    for (qint32 i = points.size() - 1; i >= 0; --i)
-    {
-        reversePoints.replace(j, points.at(i));
-        ++j;
-    }
-    return reversePoints;
-}
-
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief GetLengthContour return length of contour.
diff --git a/src/libs/vgeometry/vgobject.h b/src/libs/vgeometry/vgobject.h
index 56ef87f94..18894c77f 100644
--- a/src/libs/vgeometry/vgobject.h
+++ b/src/libs/vgeometry/vgobject.h
@@ -90,7 +90,8 @@ public:
     static bool    IsPointOnLineSegment (const QPointF &t, const QPointF &p1, const QPointF &p2);
     static bool    IsPointOnLineviaPDP(const QPointF &t, const QPointF &p1, const QPointF &p2);
 
-    static QVector<QPointF> GetReversePoints(const QVector<QPointF> &points);
+    template <typename T>
+    static QVector<T> GetReversePoints(const QVector<T> &points);
     static int GetLengthContour(const QVector<QPointF> &contour, const QVector<QPointF> &newPoints);
 
     static const double accuracyPointOnLine;
@@ -105,6 +106,29 @@ private:
     static int     PointInCircle (const QPointF &p, const QPointF &center, qreal radius);
 };
 
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief GetReversePoint return revers container of points.
+ * @param points container with points.
+ * @return reverced points.
+ */
+template <typename T>
+QVector<T> VGObject::GetReversePoints(const QVector<T> &points)
+{
+    if (points.isEmpty())
+    {
+        return points;
+    }
+    QVector<T> reversePoints(points.size());
+    qint32 j = 0;
+    for (qint32 i = points.size() - 1; i >= 0; --i)
+    {
+        reversePoints.replace(j, points.at(i));
+        ++j;
+    }
+    return reversePoints;
+}
+
 Q_DECLARE_TYPEINFO(VGObject, Q_MOVABLE_TYPE);
 
 #endif // VGOBJECT_H
diff --git a/src/libs/vlayout/vabstractdetail.cpp b/src/libs/vlayout/vabstractdetail.cpp
deleted file mode 100644
index 00372a5c2..000000000
--- a/src/libs/vlayout/vabstractdetail.cpp
+++ /dev/null
@@ -1,855 +0,0 @@
-/************************************************************************
- **
- **  @file   vabstractdetail.cpp
- **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   2 1, 2015
- **
- **  @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
- **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
- **
- *************************************************************************/
-
-#include "vabstractdetail.h"
-
-#include <QLine>
-#include <QLineF>
-#include <QMessageLogger>
-#include <QPainterPath>
-#include <QPoint>
-#include <QPointF>
-#include <QString>
-#include <QVector>
-#include <QtDebug>
-
-#include "../vgeometry/vgobject.h"
-#include "vabstractdetail_p.h"
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VAbstractDetail default contructor. Create empty detail.
- */
-VAbstractDetail::VAbstractDetail()
-    :d(new VAbstractDetailData)
-{}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VAbstractDetail constructor.
- * @param name detail name.
- */
-VAbstractDetail::VAbstractDetail(const QString &name)
-    :d(new VAbstractDetailData(name))
-{}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VAbstractDetail copy constructor.
- * @param detail detail.
- */
-VAbstractDetail::VAbstractDetail(const VAbstractDetail &detail)
-    :d (detail.d)
-{}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief operator = assignment operator.
- * @param detail detail.
- * @return new detail.
- */
-VAbstractDetail &VAbstractDetail::operator=(const VAbstractDetail &detail)
-{
-    if ( &detail == this )
-    {
-        return *this;
-    }
-    d = detail.d;
-    return *this;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-VAbstractDetail::~VAbstractDetail()
-{}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief Clear detail full clear.
- */
-void VAbstractDetail::Clear()
-{
-    d->name.clear();
-    d->seamAllowance = false;
-    d->closed = true;
-    d->width = 0;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief getName return detail name.
- * @return name.
- */
-QString VAbstractDetail::getName() const
-{
-    return d->name;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief setName set detail name.
- * @param value new name.
- */
-void VAbstractDetail::setName(const QString &value)
-{
-    d->name = value;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief getSeamAllowance keep status for seam allowance detail.
- * @return true - need seam allowance, false - no need seam allowance.
- */
-bool VAbstractDetail::getSeamAllowance() const
-{
-    return d->seamAllowance;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief setSeamAllowance set status for seam allowance detail.
- * @param value true - need seam allowance, false - no need seam allowance.
- */
-void VAbstractDetail::setSeamAllowance(bool value)
-{
-    d->seamAllowance = value;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief getClosed keep close status for detail equdistant.
- * @return true - close equdistant, false - don't close equdistant.
- */
-bool VAbstractDetail::getClosed() const
-{
-    return d->closed;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief setClosed set close status for detail equdistant.
- * @param value true - close equdistant, false - don't close equdistant.
- */
-void VAbstractDetail::setClosed(bool value)
-{
-    d->closed = value;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief getWidth return value detail seam allowance.
- * @return value in mm.
- */
-qreal VAbstractDetail::getWidth() const
-{
-    return d->width;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief setWidth set value detail seam allowance.
- * @param value width in mm.
- */
-void VAbstractDetail::setWidth(const qreal &value)
-{
-    d->width = value;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-bool VAbstractDetail::getForbidFlipping() const
-{
-    return d->forbidFlipping;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VAbstractDetail::setForbidFlipping(bool value)
-{
-    d->forbidFlipping = value;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> VAbstractDetail::Equidistant(const QVector<QPointF> &points, const EquidistantType &eqv, qreal width)
-{
-    QVector<QPointF> ekvPoints;
-
-    if (width <= 0)
-    {
-        qDebug()<<"Width <= 0.";
-        return QVector<QPointF>();
-    }
-
-    QVector<QPointF> p = CorrectEquidistantPoints(points);
-    if ( p.size() < 3 )
-    {
-        qDebug()<<"Not enough points for building the equidistant.";
-        return QVector<QPointF>();
-    }
-
-    if (eqv == EquidistantType::CloseEquidistant)
-    {
-        p.append(p.at(0));
-    }
-    for (qint32 i = 0; i < p.size(); ++i )
-    {
-        if ( i == 0 && eqv == EquidistantType::CloseEquidistant)
-        {//first point, polyline closed
-            ekvPoints<<EkvPoint(QLineF(p.at(p.size()-2), p.at(p.size()-1)), QLineF(p.at(1), p.at(0)), width);
-            continue;
-        }
-        else if (i == 0 && eqv == EquidistantType::OpenEquidistant)
-        {//first point, polyline doesn't closed
-            ekvPoints.append(UnclosedEkvPoint(QLineF(p.at(0), p.at(1)), QLineF(p.at(0), p.at(p.size()-1)), width));
-            continue;
-        }
-        if (i == p.size()-1 && eqv == EquidistantType::CloseEquidistant)
-        {//last point, polyline closed
-            if (not ekvPoints.isEmpty())
-            {
-                ekvPoints.append(ekvPoints.at(0));
-            }
-            continue;
-        }
-        else if (i == p.size()-1 && eqv == EquidistantType::OpenEquidistant)
-        {//last point, polyline doesn't closed
-            ekvPoints.append(UnclosedEkvPoint(QLineF(p.at(p.size()-2), p.at(p.size()-1)),
-                                              QLineF(p.at(0), p.at(p.size()-1)), width));
-            continue;
-        }
-        //points in the middle of polyline
-        ekvPoints<<EkvPoint(QLineF(p.at(i-1), p.at(i)), QLineF(p.at(i+1), p.at(i)), width);
-    }
-
-    bool removeFirstAndLast = true;
-    if (eqv == EquidistantType::CloseEquidistant)
-    {
-        removeFirstAndLast = false;
-    }
-
-    ekvPoints = CheckLoops(CorrectEquidistantPoints(ekvPoints, removeFirstAndLast));//Result path can contain loops
-    return ekvPoints;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> VAbstractDetail::RemoveDublicates(const QVector<QPointF> &points, bool removeFirstAndLast)
-{
-    QVector<QPointF> p = points;
-
-    if (removeFirstAndLast)
-    {
-        if (not p.isEmpty() && p.size() > 1)
-        {
-            // Path can't be closed
-            if (p.first() == p.last())
-            {
-            #if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
-                p.remove(p.size() - 1);
-            #else
-                p.removeLast();
-            #endif
-            }
-        }
-    }
-
-    for (int i = 0; i < p.size()-1; ++i)
-    {
-        if (p.at(i) == p.at(i+1))
-        {
-            if (not removeFirstAndLast && (i == p.size()-1))
-            {
-                continue;
-            }
-
-            p.erase(p.begin() + i + 1);
-            --i;
-            continue;
-        }
-    }
-
-    return p;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-bool VAbstractDetail::CheckIntersection(const QVector<QPointF> &points, int i, int iNext, int j, int jNext,
-                                        const QPointF &crossPoint)
-{
-    QVector<QPointF> sub1 = SubPath(points, iNext, j);
-    sub1.append(crossPoint);
-    sub1 = CheckLoops(CorrectEquidistantPoints(sub1, false));
-    const qreal sub1Sum = SumTrapezoids(sub1);
-
-    QVector<QPointF> sub2 = SubPath(points, jNext, i);
-    sub2.append(crossPoint);
-    sub2 = CheckLoops(CorrectEquidistantPoints(sub2, false));
-    const qreal sub2Sum = SumTrapezoids(sub2);
-
-    if (sub1Sum < 0 && sub2Sum < 0)
-    {
-        if (Crossing(sub1, sub2))
-        {
-            return true;
-        }
-    }
-    else
-    {
-        if (not Crossing(sub1, sub2))
-        {
-            return true;
-        }
-    }
-    return false;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-bool VAbstractDetail::ParallelCrossPoint(const QLineF &line1, const QLineF &line2, QPointF &point)
-{
-    const bool l1p1el2p1 = (line1.p1() == line2.p1());
-    const bool l1p2el2p2 = (line1.p2() == line2.p2());
-    const bool l1p1el2p2 = (line1.p1() == line2.p2());
-    const bool l1p2el2p1 = (line1.p2() == line2.p1());
-
-    if (l1p2el2p2 || l1p2el2p1)
-    {
-        point = line1.p2();
-        return true;
-    }
-    else if (l1p1el2p1 || l1p1el2p2)
-    {
-        point = line1.p1();
-        return true;
-    }
-    else
-    {
-        point = QPointF();
-        return false;
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-bool VAbstractDetail::Crossing(const QVector<QPointF> &sub1, const QVector<QPointF> &sub2)
-{
-    if (sub1.isEmpty() || sub2.isEmpty())
-    {
-        return false;
-    }
-
-    const QRectF sub1Rect = QPolygonF(sub1).boundingRect();
-    const QRectF sub2Rect = QPolygonF(sub2).boundingRect();
-    if (not sub1Rect.intersects(sub2Rect))
-    {
-        return false;
-    }
-
-    QPainterPath sub1Path;
-    sub1Path.setFillRule(Qt::WindingFill);
-    sub1Path.moveTo(sub1.at(0));
-    for (qint32 i = 1; i < sub1.count(); ++i)
-    {
-        sub1Path.lineTo(sub1.at(i));
-    }
-    sub1Path.lineTo(sub1.at(0));
-
-    QPainterPath sub2Path;
-    sub2Path.setFillRule(Qt::WindingFill);
-    sub2Path.moveTo(sub2.at(0));
-    for (qint32 i = 1; i < sub2.count(); ++i)
-    {
-        sub2Path.lineTo(sub2.at(i));
-    }
-    sub2Path.lineTo(sub2.at(0));
-
-    if (not sub1Path.intersects(sub2Path))
-    {
-        return false;
-    }
-    else
-    {
-        return true;
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> VAbstractDetail::SubPath(const QVector<QPointF> &path, int startIndex, int endIndex)
-{
-    if (path.isEmpty()
-       || startIndex < 0 || startIndex >= path.size()
-       || endIndex < 0 || endIndex >= path.size()
-       || startIndex == endIndex)
-    {
-        return path;
-    }
-
-    QVector<QPointF> subPath;
-    int i = startIndex - 1;
-    do
-    {
-        ++i;
-        if (i >= path.size())
-        {
-            i = 0;
-        }
-        subPath.append(path.at(i));
-    } while (i != endIndex);
-
-    return subPath;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief CorrectEquidistantPoints clear equivalent points and remove point on line from equdistant.
- * @param points list of points equdistant.
- * @return corrected list.
- */
-QVector<QPointF> VAbstractDetail::CorrectEquidistantPoints(const QVector<QPointF> &points, bool removeFirstAndLast)
-{
-    if (points.size()<4)//Better don't check if only three points. We can destroy equidistant.
-    {
-        qDebug()<<"Only three points.";
-        return points;
-    }
-
-    //Clear equivalent points
-    QVector<QPointF> buf1 = RemoveDublicates(points, removeFirstAndLast);
-
-    if (buf1.size()<3)
-    {
-        return buf1;
-    }
-
-    QVector<QPointF> buf2;
-    //Remove point on line
-    for (qint32 i = 0; i < buf1.size(); ++i)
-    {// In this case we alwayse will have bounded intersection, so all is need is to check if point i is on line.
-     // Unfortunatelly QLineF::intersect can't be used in this case because of the floating-point accuraccy problem.
-        int prev = i-1;
-        int next = i+1;
-        if (i == 0)
-        {
-            prev = buf1.size() - 1;
-        }
-        else if (i == buf1.size() - 1)
-        {
-            next = 0;
-        }
-
-        const QPointF &iPoint = buf1.at(i);
-        const QPointF &prevPoint = buf1.at(prev);
-        const QPointF &nextPoint = buf1.at(next);
-
-        if (not VGObject::IsPointOnLineviaPDP(buf1.at(i), buf1.at(prev), buf1.at(next))
-                && prevPoint != nextPoint) // not zigzag
-        {
-            buf2.append(buf1.at(i));
-        }
-        else if ((i == 0 || i == buf1.size() - 1) && (iPoint == prevPoint || iPoint == nextPoint))
-        {
-            // If RemoveDublicates does not remove these points it is a valid case.
-            // Case where last point equal first point
-            buf2.append(buf1.at(i));
-        }
-    }
-
-    buf2 = RemoveDublicates(buf2, false);
-
-    return buf2;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief CheckLoops seek and delete loops in equidistant.
- * @param points vector of points of equidistant.
- * @return vector of points of equidistant.
- */
-QVector<QPointF> VAbstractDetail::CheckLoops(const QVector<QPointF> &points)
-{
-    int count = points.size();
-    /*If we got less than 4 points no need seek loops.*/
-    if (count < 4)
-    {
-        return points;
-    }
-
-    const bool pathClosed = (points.first() == points.last());
-
-    QVector<QPointF> ekvPoints;
-
-    qint32 i, j, jNext = 0;
-    for (i = 0; i < count; ++i)
-    {
-        /*Last three points no need check.*/
-        /*Triangle has not contain loops*/
-        if (i > count-3)
-        {
-            ekvPoints.append(points.at(i));
-            continue;
-        }
-
-        enum LoopIntersectType { NoIntersection, BoundedIntersection, ParallelIntersection };
-
-        QPointF crosPoint;
-        LoopIntersectType status = NoIntersection;
-        const QLineF line1(points.at(i), points.at(i+1));
-        // Because a path can contains several loops we will seek the last and only then remove the loop(s)
-        // That's why we parse from the end
-        for (j = count-1; j >= i+2; --j)
-        {
-            j == count-1 ? jNext = 0 : jNext = j+1;
-            QLineF line2(points.at(j), points.at(jNext));
-
-            if(qFuzzyIsNull(line2.length()))
-            {//If a path is closed the edge (count-1;0) length will be 0
-                continue;
-            }
-
-            QSet<qint32> uniqueVertices;
-            uniqueVertices << i << i+1 << j;
-
-            // For closed path last point is equal to first. Using index of the first.
-            pathClosed && jNext == count-1 ? uniqueVertices << 0 : uniqueVertices << jNext;
-
-            const QLineF::IntersectType intersect = line1.intersect(line2, &crosPoint);
-            if (intersect == QLineF::NoIntersection)
-            { // According to the documentation QLineF::NoIntersection indicates that the lines do not intersect;
-              // i.e. they are parallel. But parallel also mean they can be on the same line.
-              // Method IsPointOnLineviaPDP will check it.
-                if (VGObject::IsPointOnLineviaPDP(points.at(j), points.at(i), points.at(i+1))
-                    // Lines are not neighbors
-                    && uniqueVertices.size() == 4)
-                {
-                    // Left to catch case where segments are on the same line, but do not have real intersections.
-                    QLineF tmpLine1 = line1;
-                    QLineF tmpLine2 = line2;
-
-                    tmpLine1.setAngle(tmpLine1.angle()+90);
-
-                    QPointF tmpCrosPoint;
-                    const QLineF::IntersectType tmpIntrs1 = tmpLine1.intersect(tmpLine2, &tmpCrosPoint);
-
-                    tmpLine1 = line1;
-                    tmpLine2.setAngle(tmpLine2.angle()+90);
-
-                    const QLineF::IntersectType tmpIntrs2 = tmpLine1.intersect(tmpLine2, &tmpCrosPoint);
-
-                    if (tmpIntrs1 == QLineF::BoundedIntersection || tmpIntrs2 == QLineF::BoundedIntersection)
-                    { // Now we really sure that lines are on the same line and have real intersections.
-                        QPointF cPoint;
-                        const bool caseFlag = ParallelCrossPoint(line1, line2, cPoint);
-                        if (not caseFlag || CheckIntersection(points, i, i+1, j, jNext, cPoint))
-                        {
-                            status = ParallelIntersection;
-                            break;
-                        }
-                    }
-                }
-            }
-            else if (intersect == QLineF::BoundedIntersection)
-            {
-                if (uniqueVertices.size() == 4)
-                { // Break, but not if lines are neighbors
-                    if ((line1.p1() != crosPoint
-                        && line1.p2() != crosPoint
-                        && line2.p1() != crosPoint
-                        && line2.p2() != crosPoint) || CheckIntersection(points, i, i+1, j, jNext, crosPoint))
-                    {
-                        status = BoundedIntersection;
-                        break;
-                    }
-                }
-            }
-            status = NoIntersection;
-        }
-
-        switch (status)
-        {
-            case ParallelIntersection:
-                /*We have found a loop.*/
-                ekvPoints.append(points.at(i));
-                ekvPoints.append(points.at(jNext));
-                jNext > j ? i = jNext : i = j; // Skip a loop
-                break;
-            case BoundedIntersection:
-                ekvPoints.append(points.at(i));
-                ekvPoints.append(crosPoint);
-                i = j;
-                break;
-            case NoIntersection:
-                /*We have not found loop.*/
-                ekvPoints.append(points.at(i));
-                break;
-            default:
-                break;
-        }
-    }
-    return ekvPoints;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief EkvPoint return vector of points of equidistant two lines. Last point of two lines must be equal.
- * @param line1 first line.
- * @param line2 second line.
- * @param width width of equidistant.
- * @return vector of points.
- */
-QVector<QPointF> VAbstractDetail::EkvPoint(const QLineF &line1, const QLineF &line2, const qreal &width)
-{
-    if (width <= 0)
-    {
-        return QVector<QPointF>();
-    }
-    QVector<QPointF> points;
-    if (line1.p2() != line2.p2())
-    {
-        qDebug()<<"Last points of two lines must be equal.";
-        return QVector<QPointF>();
-    }
-    QPointF CrosPoint;
-    const QLineF bigLine1 = ParallelLine(line1, width );
-    const QLineF bigLine2 = ParallelLine(QLineF(line2.p2(), line2.p1()), width );
-    QLineF::IntersectType type = bigLine1.intersect( bigLine2, &CrosPoint );
-    switch (type)
-    {
-        case (QLineF::BoundedIntersection):
-            points.append(CrosPoint);
-            return points;
-            break;
-        case (QLineF::UnboundedIntersection):
-        {
-            QLineF line( line1.p2(), CrosPoint );
-
-            const int angle1 = BisectorAngle(line1.p1(), line1.p2(), line2.p1());
-            const int angle2 = BisectorAngle(bigLine1.p1(), CrosPoint, bigLine2.p2());
-
-            if (angle1 == angle2)
-            {//Regular equdistant case
-                const qreal length = line.length();
-                if (length > width*2.4)
-                { // Cutting too long a cut 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
-
-                    // We do not check intersection type because intersection must alwayse exist
-                    QPointF px;
-                    cutLine.setAngle(cutLine.angle()+90);
-                    QLineF::IntersectType type = bigLine1.intersect( cutLine, &px );
-                    if (type == QLineF::NoIntersection)
-                    {
-                        qDebug()<<"Couldn't find intersection with cut line.";
-                    }
-                    points.append(px);
-
-                    cutLine.setAngle(cutLine.angle()-180);
-                    type = bigLine2.intersect( cutLine, &px );
-                    if (type == QLineF::NoIntersection)
-                    {
-                        qDebug()<<"Couldn't find intersection with cut line.";
-                    }
-                    points.append(px);
-                }
-                else
-                {
-                    points.append(CrosPoint);
-                    return points;
-                }
-            }
-            else
-            {// Dart. Create a loop.
-                points.append(bigLine1.p2());
-                points.append(bigLine2.p1());
-                return points;
-            }
-            break;
-        }
-        case (QLineF::NoIntersection):
-            /*If we have correct lines this means lines lie on a line.*/
-            points.append(bigLine1.p2());
-            return points;
-            break;
-        default:
-            break;
-    }
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief UnclosedEkvPoint helps find point of an unclosed seam allowance. One side of two lines should be equal.
- *
- * In case of the first seam allowance point equal should be the first point of the two lines. In case the last point -
- * the last point of the two lines.
- *
- * @param line line of a seam allowance
- * @param helpLine help line of the main path that cut unclosed seam allowance
- * @param width seam allowance width
- * @return seam allowance point
- */
-QPointF VAbstractDetail::UnclosedEkvPoint(const QLineF &line, const QLineF &helpLine, const qreal &width)
-{
-    if (width <= 0)
-    {
-        return QPointF();
-    }
-
-    const bool firstPoint = line.p1() == helpLine.p1();
-    if (not (line.p2() == helpLine.p2() || firstPoint))
-    {
-        qDebug()<<"Two points of two lines must be equal.";
-        return QPointF();
-    }
-
-    QPointF CrosPoint;
-    const QLineF bigLine = ParallelLine(line, width );
-    QLineF::IntersectType type = bigLine.intersect( helpLine, &CrosPoint );
-    switch (type)
-    {
-        case (QLineF::BoundedIntersection):
-            return CrosPoint;
-            break;
-        case (QLineF::UnboundedIntersection):
-        {
-            // This case is very tricky.
-            // User can create very wrong path that will create crospoint far from main path.
-            // Such an annomaly we try to catch and fix.
-            // If don't do this the program will crash.
-            QLineF test;
-            firstPoint ? test = QLineF(line.p1(), CrosPoint) : test = QLineF(line.p2(), CrosPoint);
-            const qreal length = test.length();
-            if (length > width*2.4)
-            {
-                test.setLength(width);
-                return test.p2();
-            }
-            else
-            {
-                return CrosPoint;
-            }
-            break;
-        }
-        case (QLineF::NoIntersection):
-            /*If we have correct lines this means lines lie on a line.*/
-            if (firstPoint)
-            {
-                return bigLine.p1();
-            }
-            else
-            {
-                return bigLine.p2();
-            }
-            break;
-        default:
-            break;
-    }
-    return QPointF();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief ParallelLine create parallel line.
- * @param line starting line.
- * @param width width to parallel line.
- * @return parallel line.
- */
-QLineF VAbstractDetail::ParallelLine(const QLineF &line, qreal width)
-{
-    QLineF paralel = QLineF (SingleParallelPoint(line, 90, width), SingleParallelPoint(QLineF(line.p2(), line.p1()),
-                                                                                       -90, width));
-    return paralel;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief SingleParallelPoint return point of parallel line.
- * @param line starting line.
- * @param angle angle in degree.
- * @param width width to parallel line.
- * @return point of parallel line.
- */
-QPointF VAbstractDetail::SingleParallelPoint(const QLineF &line, const qreal &angle, const qreal &width)
-{
-    QLineF pLine = line;
-    pLine.setAngle( pLine.angle() + angle );
-    pLine.setLength( width );
-    return pLine.p2();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-int VAbstractDetail::BisectorAngle(const QPointF &p1, const QPointF &p2, const QPointF &p3)
-{
-    QLineF line1(p2, p1);
-    QLineF line2(p2, p3);
-    QLineF bLine;
-
-    const qreal angle1 = line1.angleTo(line2);
-    const qreal angle2 = line2.angleTo(line1);
-
-    if (angle1 <= angle2)
-    {
-        bLine = line1;
-        bLine.setAngle(bLine.angle() + angle1/2.0);
-    }
-    else
-    {
-        bLine = line2;
-        bLine.setAngle(bLine.angle() + angle2/2.0);
-    }
-
-    return qRound(bLine.angle());
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-qreal VAbstractDetail::SumTrapezoids(const QVector<QPointF> &points)
-{
-    // Calculation a polygon area through the sum of the areas of trapezoids
-    qreal s, res = 0;
-    const int n = points.size();
-
-    if(n > 2)
-    {
-        for (int i = 0; i < n; ++i)
-        {
-            if (i == 0)
-            {
-                s = points.at(i).x()*(points.at(n-1).y() - points.at(i+1).y()); //if i == 0, then y[i-1] replace on y[n-1]
-                res += s;
-            }
-            else
-            {
-                if (i == n-1)
-                {
-                    s = points.at(i).x()*(points.at(i-1).y() - points.at(0).y()); // if i == n-1, then y[i+1] replace on y[0]
-                    res += s;
-                }
-                else
-                {
-                    s = points.at(i).x()*(points.at(i-1).y() - points.at(i+1).y());
-                    res += s;
-                }
-            }
-        }
-    }
-    return res;
-}
diff --git a/src/libs/vlayout/vabstractdetail.h b/src/libs/vlayout/vabstractdetail.h
deleted file mode 100644
index 902b15dd2..000000000
--- a/src/libs/vlayout/vabstractdetail.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/************************************************************************
- **
- **  @file   vabstractdetail.h
- **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   2 1, 2015
- **
- **  @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
- **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
- **
- *************************************************************************/
-
-#ifndef VABSTRACTDETAIL_H
-#define VABSTRACTDETAIL_H
-
-#include <QSharedDataPointer>
-#include <QTypeInfo>
-#include <QtGlobal>
-
-#include "vlayoutdef.h"
-
-class QLineF;
-class QPointF;
-class QString;
-class VAbstractDetailData;
-template <typename T> class QVector;
-
-/**
- * @brief The VAbstractDetail class abstract class for all details.
- */
-class VAbstractDetail
-{
-public:
-    VAbstractDetail();
-    explicit VAbstractDetail(const QString &name);
-    VAbstractDetail(const VAbstractDetail &detail);
-    VAbstractDetail &operator=(const VAbstractDetail &detail);
-    virtual ~VAbstractDetail();
-
-    void    Clear();
-
-    QString getName() const;
-    void    setName(const QString &value);
-
-    bool    getSeamAllowance() const;
-    void    setSeamAllowance(bool value);
-
-    bool    getClosed() const;
-    void    setClosed(bool value);
-
-    qreal   getWidth() const;
-    void    setWidth(const qreal &value);
-
-    bool    getForbidFlipping() const;
-    void    setForbidFlipping(bool value);
-
-    static QVector<QPointF> Equidistant(const QVector<QPointF> &points, const EquidistantType &eqv, qreal width);
-    static qreal            SumTrapezoids(const QVector<QPointF> &points);
-    static QVector<QPointF> CheckLoops(const QVector<QPointF> &points);
-    static QVector<QPointF> CorrectEquidistantPoints(const QVector<QPointF> &points, bool removeFirstAndLast = true);
-
-protected:
-    static QVector<QPointF> RemoveDublicates(const QVector<QPointF> &points, bool removeFirstAndLast = true);
-
-private:
-    QSharedDataPointer<VAbstractDetailData> d;
-
-    static bool             CheckIntersection(const QVector<QPointF> &points, int i, int iNext, int j, int jNext,
-                                              const QPointF &crossPoint);
-    static bool             ParallelCrossPoint(const QLineF &line1, const QLineF &line2, QPointF &point);
-    static bool             Crossing(const QVector<QPointF> &sub1, const QVector<QPointF> &sub2);
-    static QVector<QPointF> SubPath(const QVector<QPointF> &path, int startIndex, int endIndex);
-    static QVector<QPointF> EkvPoint(const QLineF &line1, const QLineF &line2, const qreal &width);
-    static QPointF          UnclosedEkvPoint(const QLineF &line, const QLineF &helpLine, const qreal &width);
-    static QLineF           ParallelLine(const QLineF &line, qreal width );
-    static QPointF          SingleParallelPoint(const QLineF &line, const qreal &angle, const qreal &width);
-    static int              BisectorAngle(const QPointF &p1, const QPointF &p2, const QPointF &p3);
-};
-
-Q_DECLARE_TYPEINFO(VAbstractDetail, Q_MOVABLE_TYPE);
-
-#endif // VABSTRACTDETAIL_H
diff --git a/src/libs/vlayout/vabstractpiece.cpp b/src/libs/vlayout/vabstractpiece.cpp
new file mode 100644
index 000000000..061375072
--- /dev/null
+++ b/src/libs/vlayout/vabstractpiece.cpp
@@ -0,0 +1,938 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   3 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "vabstractpiece.h"
+#include "vabstractpiece_p.h"
+#include "../vmisc/vabstractapplication.h"
+#include "../vgeometry/vpointf.h"
+
+#include <QLineF>
+#include <QSet>
+#include <QVector>
+#include <QPainterPath>
+
+const qreal maxL = 2.4;
+
+//---------------------------------------------------------------------------------------------------------------------
+VAbstractPiece::VAbstractPiece()
+    : d(new VAbstractPieceData)
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+VAbstractPiece::VAbstractPiece(const VAbstractPiece &piece)
+    :d (piece.d)
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+VAbstractPiece &VAbstractPiece::operator=(const VAbstractPiece &piece)
+{
+    if ( &piece == this )
+    {
+        return *this;
+    }
+    d = piece.d;
+    return *this;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VAbstractPiece::~VAbstractPiece()
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString VAbstractPiece::GetName() const
+{
+    return d->m_name;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VAbstractPiece::SetName(const QString &value)
+{
+    d->m_name = value;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VAbstractPiece::IsForbidFlipping() const
+{
+    return d->m_forbidFlipping;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VAbstractPiece::SetForbidFlipping(bool value)
+{
+    d->m_forbidFlipping = value;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VAbstractPiece::IsSeamAllowance() const
+{
+    return d->m_seamAllowance;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VAbstractPiece::SetSeamAllowance(bool value)
+{
+    d->m_seamAllowance = value;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+qreal VAbstractPiece::GetSAWidth() const
+{
+    return d->m_width;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VAbstractPiece::SetSAWidth(qreal value)
+{
+    value >= 0 ? d->m_width = value : d->m_width = 0;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VAbstractPiece::Equidistant(const QVector<VSAPoint> &points, qreal width)
+{
+    if (width < 0)
+    {
+        qDebug()<<"Width < 0.";
+        return QVector<QPointF>();
+    }
+
+    QVector<VSAPoint> p = CorrectEquidistantPoints(points);
+    if ( p.size() < 3 )
+    {
+        qDebug()<<"Not enough points for building the equidistant.";
+        return QVector<QPointF>();
+    }
+
+    if (p.last().toPoint() != p.first().toPoint())
+    {
+        p.append(p.at(0));// Should be always closed
+    }
+
+    QVector<QPointF> ekvPoints;
+    for (qint32 i = 0; i < p.size(); ++i )
+    {
+        if ( i == 0)
+        {//first point
+            ekvPoints << EkvPoint(p.at(p.size()-2), p.at(p.size()-1),
+                                  p.at(1), p.at(0), width);
+            continue;
+        }
+
+        if (i == p.size()-1)
+        {//last point
+            if (not ekvPoints.isEmpty())
+            {
+                ekvPoints.append(ekvPoints.at(0));
+            }
+            continue;
+        }
+        //points in the middle of polyline
+        ekvPoints << EkvPoint(p.at(i-1), p.at(i),
+                              p.at(i+1), p.at(i), width);
+    }
+
+    const bool removeFirstAndLast = false;
+    ekvPoints = CheckLoops(CorrectEquidistantPoints(ekvPoints, removeFirstAndLast));//Result path can contain loops
+    return ekvPoints;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+qreal VAbstractPiece::SumTrapezoids(const QVector<QPointF> &points)
+{
+    // Calculation a polygon area through the sum of the areas of trapezoids
+    qreal s, res = 0;
+    const int n = points.size();
+
+    if(n > 2)
+    {
+        for (int i = 0; i < n; ++i)
+        {
+            if (i == 0)
+            {
+                //if i == 0, then y[i-1] replace on y[n-1]
+                s = points.at(i).x()*(points.at(n-1).y() - points.at(i+1).y());
+                res += s;
+            }
+            else
+            {
+                if (i == n-1)
+                {
+                    // if i == n-1, then y[i+1] replace on y[0]
+                    s = points.at(i).x()*(points.at(i-1).y() - points.at(0).y());
+                    res += s;
+                }
+                else
+                {
+                    s = points.at(i).x()*(points.at(i-1).y() - points.at(i+1).y());
+                    res += s;
+                }
+            }
+        }
+    }
+    return res;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief CheckLoops seek and delete loops in equidistant.
+ * @param points vector of points of equidistant.
+ * @return vector of points of equidistant.
+ */
+QVector<QPointF> VAbstractPiece::CheckLoops(const QVector<QPointF> &points)
+{
+    int count = points.size();
+    /*If we got less than 4 points no need seek loops.*/
+    if (count < 4)
+    {
+        return points;
+    }
+
+    const bool pathClosed = (points.first() == points.last());
+
+    QVector<QPointF> ekvPoints;
+
+    qint32 i, j, jNext = 0;
+    for (i = 0; i < count; ++i)
+    {
+        /*Last three points no need check.*/
+        /*Triangle has not contain loops*/
+        if (i > count-3)
+        {
+            ekvPoints.append(points.at(i));
+            continue;
+        }
+
+        enum LoopIntersectType { NoIntersection, BoundedIntersection, ParallelIntersection };
+
+        QPointF crosPoint;
+        LoopIntersectType status = NoIntersection;
+        const QLineF line1(points.at(i), points.at(i+1));
+        // Because a path can contains several loops we will seek the last and only then remove the loop(s)
+        // That's why we parse from the end
+        for (j = count-1; j >= i+2; --j)
+        {
+            j == count-1 ? jNext = 0 : jNext = j+1;
+            QLineF line2(points.at(j), points.at(jNext));
+
+            if(qFuzzyIsNull(line2.length()))
+            {//If a path is closed the edge (count-1;0) length will be 0
+                continue;
+            }
+
+            QSet<qint32> uniqueVertices;
+            uniqueVertices << i << i+1 << j;
+
+            // For closed path last point is equal to first. Using index of the first.
+            pathClosed && jNext == count-1 ? uniqueVertices << 0 : uniqueVertices << jNext;
+
+            const QLineF::IntersectType intersect = line1.intersect(line2, &crosPoint);
+            if (intersect == QLineF::NoIntersection)
+            { // According to the documentation QLineF::NoIntersection indicates that the lines do not intersect;
+              // i.e. they are parallel. But parallel also mean they can be on the same line.
+              // Method IsPointOnLineviaPDP will check it.
+                if (VGObject::IsPointOnLineviaPDP(points.at(j), points.at(i), points.at(i+1))
+                    // Lines are not neighbors
+                    && uniqueVertices.size() == 4)
+                {
+                    // Left to catch case where segments are on the same line, but do not have real intersections.
+                    QLineF tmpLine1 = line1;
+                    QLineF tmpLine2 = line2;
+
+                    tmpLine1.setAngle(tmpLine1.angle()+90);
+
+                    QPointF tmpCrosPoint;
+                    const QLineF::IntersectType tmpIntrs1 = tmpLine1.intersect(tmpLine2, &tmpCrosPoint);
+
+                    tmpLine1 = line1;
+                    tmpLine2.setAngle(tmpLine2.angle()+90);
+
+                    const QLineF::IntersectType tmpIntrs2 = tmpLine1.intersect(tmpLine2, &tmpCrosPoint);
+
+                    if (tmpIntrs1 == QLineF::BoundedIntersection || tmpIntrs2 == QLineF::BoundedIntersection)
+                    { // Now we really sure that lines are on the same lines and have real intersections.
+                        QPointF cPoint;
+                        const bool caseFlag = ParallelCrossPoint(line1, line2, cPoint);
+                        if (not caseFlag || CheckIntersection(points, i, i+1, j, jNext, cPoint))
+                        {
+                            status = ParallelIntersection;
+                            break;
+                        }
+                    }
+                }
+            }
+            else if (intersect == QLineF::BoundedIntersection)
+            {
+                if (uniqueVertices.size() == 4)
+                { // Break, but not if lines are neighbors
+                    if ((line1.p1() != crosPoint
+                        && line1.p2() != crosPoint
+                        && line2.p1() != crosPoint
+                        && line2.p2() != crosPoint) || CheckIntersection(points, i, i+1, j, jNext, crosPoint))
+                    {
+                        status = BoundedIntersection;
+                        break;
+                    }
+                }
+            }
+            status = NoIntersection;
+        }
+
+        switch (status)
+        {
+            case ParallelIntersection:
+                /*We have found a loop.*/
+                ekvPoints.append(points.at(i));
+                ekvPoints.append(points.at(jNext));
+                jNext > j ? i = jNext : i = j; // Skip a loop
+                break;
+            case BoundedIntersection:
+                ekvPoints.append(points.at(i));
+                ekvPoints.append(crosPoint);
+                i = j;
+                break;
+            case NoIntersection:
+                /*We have not found loop.*/
+                ekvPoints.append(points.at(i));
+                break;
+            default:
+                break;
+        }
+    }
+    return ekvPoints;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+Q_DECL_CONSTEXPR qreal VAbstractPiece::PointPosition(const QPointF &p, const QLineF &line)
+{
+    return (line.p2().x() - line.p1().x()) * (p.y() - line.p1().y()) -
+           (line.p2().y() - line.p1().y()) * (p.x() - line.p1().x());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+qreal VAbstractPiece::MaxLocalSA(const VSAPoint &p, qreal width)
+{
+    qreal w1 = p.GetSAAfter();
+    if (w1 < 0)
+    {
+        w1 = width;
+    }
+
+    qreal w2 = p.GetSABefore();
+    if (w2 < 0)
+    {
+        w2 = width;
+    }
+
+    return qMax(w1, w2);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief EkvPoint return seam aloowance points in place of intersection two edges. Last points of two edges should be
+ * equal.
+ * @param width global seam allowance width.
+ * @return seam aloowance points.
+ */
+QVector<QPointF> VAbstractPiece::EkvPoint(const VSAPoint &p1Line1, const VSAPoint &p2Line1,
+                                          const VSAPoint &p1Line2, const VSAPoint &p2Line2, qreal width)
+{
+    if (width < 0)
+    { // width can't be < 0
+        return QVector<QPointF>();
+    }
+
+    QVector<QPointF> points;
+    if (p2Line1 != p2Line2)
+    {
+        qDebug()<<"Last points of two lines must be equal.";
+        return QVector<QPointF>(); // Wrong edges
+    }
+
+    const QLineF bigLine1 = ParallelLine(p1Line1, p2Line1, width );
+    const QLineF bigLine2 = ParallelLine(p2Line2, p1Line2, width );
+    QPointF CrosPoint;
+    const QLineF::IntersectType type = bigLine1.intersect( bigLine2, &CrosPoint );
+    switch (type)
+    {// There are at least three big cases
+        case (QLineF::BoundedIntersection):
+            // The easiest, real intersection
+            points.append(CrosPoint);
+            return points;
+            break;
+        case (QLineF::UnboundedIntersection):
+        { // Most common case
+            const qreal localWidth = MaxLocalSA(p2Line1, width);
+            QLineF line( p2Line1, CrosPoint );
+
+            // Checking two subcases
+            const QLineF b1 = BisectorLine(p1Line1, p2Line1, p1Line2);
+            const QLineF b2 = BisectorLine(bigLine1.p1(), CrosPoint, bigLine2.p2());
+
+            const qreal angle = AngleBetweenBisectors(b1, b2);
+
+            // Comparison bisector angles helps to find direction
+            if (angle <= 90)// Go in a same direction
+            {//Regular equdistant case
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wswitch-default")
+                switch (p2Line1.GetAngleType())
+                {
+                    case PieceNodeAngle::ByLength:
+                        return AngleByLength(p2Line1, bigLine1.p1(), CrosPoint, bigLine2.p2(), localWidth);
+                    case PieceNodeAngle::ByPointsIntersection:
+                        return AngleByIntersection(p1Line1, p2Line1, p1Line2, bigLine1.p1(), CrosPoint, bigLine2.p2(),
+                                                   localWidth);
+                    case PieceNodeAngle::ByFirstEdgeSymmetry:
+                        return AngleByFirstSymmetry(p1Line1, p2Line1, bigLine1.p1(), CrosPoint, bigLine2.p2(),
+                                                    localWidth);
+                    case PieceNodeAngle::BySecondEdgeSymmetry:
+                        return AngleBySecondSymmetry(p2Line1, p1Line2, bigLine1.p1(), CrosPoint,bigLine2.p2(),
+                                                     localWidth);
+                    case PieceNodeAngle::ByFirstEdgeRightAngle:
+                        return AngleByFirstRightAngle(p1Line1, p2Line1, bigLine1.p1(), CrosPoint, bigLine2.p2(),
+                                                      localWidth);
+                    case PieceNodeAngle::BySecondEdgeRightAngle:
+                        return AngleBySecondRightAngle(p2Line1, p1Line2, bigLine1.p1(), CrosPoint, bigLine2.p2(),
+                                                       localWidth);
+                }
+QT_WARNING_POP
+            }
+            else
+            { // Different directions
+                QLineF bisector(p2Line1, p1Line1);
+                bisector.setAngle(b1.angle());
+
+                const qreal result1 = PointPosition(bisector.p2(), QLineF(p1Line1, p2Line1));
+                const qreal result2 = PointPosition(bisector.p2(), QLineF(p2Line2, p1Line2));
+
+                if (result1 <=0 && result2 <= 0)
+                {// Dart case. A bisector watch outside. In some cases a point still valid, but ignore if going
+                 // outside of an equdistant.
+
+                    const QLineF bigEdge = ParallelLine(p1Line1, p1Line2, localWidth );
+                    QPointF px;
+                    const QLineF::IntersectType type = bigEdge.intersect(line, &px);
+                    if (type != QLineF::BoundedIntersection)
+                    {
+                        if (line.length() < QLineF(p2Line1, px).length())
+                        {
+                            points.append(CrosPoint);
+                            return points;
+                        }
+                    }
+                }
+                else
+                { // New subcase. This is not a dart. An angle is acute and bisector watch inside.
+                    const qreal result1 = PointPosition(CrosPoint, QLineF(p1Line1, p2Line1));
+                    const qreal result2 = PointPosition(CrosPoint, QLineF(p2Line2, p1Line2));
+
+                    if (result1 <=0 && result2 <= 0)
+                    {// The cross point is still outside of a piece
+                        if (line.length() >= localWidth)
+                        {
+                            points.append(CrosPoint);
+                            return points;
+                        }
+                        else
+                        {// but not enough far, fix it
+                            line.setLength(localWidth);
+                            points.append(line.p2());
+                            return points;
+                        }
+                    }
+                    else
+                    {// Wrong cross point, probably inside of a piece. Manually creating correct seam allowance
+                        const QLineF bigEdge = ParallelLine(bigLine1.p2(), bigLine2.p1(), localWidth );
+                        points.append(bigEdge.p1());
+                        points.append(bigEdge.p2());
+                        return points;
+                    }
+                }
+            }
+            break;
+        }
+        case (QLineF::NoIntersection):
+            /*If we have correct lines this means lines lie on a line.*/
+            points.append(bigLine1.p2());
+            return points;
+            break;
+        default:
+            break;
+    }
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VAbstractPiece::AngleByLength(const QPointF &p2, const QPointF &sp1, const QPointF &sp2,
+                                               const QPointF &sp3, qreal width)
+{
+    QVector<QPointF> points;
+
+    QLineF line(p2, sp2);
+    const qreal length = line.length();
+    if (length > width*maxL)
+    { // Cutting too long a cut angle
+        line.setLength(width);
+        QLineF cutLine(line.p2(), sp2); // Cut line is a perpendicular
+        cutLine.setLength(length); // Decided take this length
+
+        // We do not check intersection type because intersection must alwayse exist
+        QPointF px;
+        cutLine.setAngle(cutLine.angle()+90);
+        QLineF::IntersectType type = QLineF(sp1, sp2).intersect(cutLine, &px);
+        if (type == QLineF::NoIntersection)
+        {
+            qDebug()<<"Couldn't find intersection with cut line.";
+        }
+        points.append(px);
+
+        cutLine.setAngle(cutLine.angle()-180);
+        type = QLineF(sp2, sp3).intersect(cutLine, &px);
+        if (type == QLineF::NoIntersection)
+        {
+            qDebug()<<"Couldn't find intersection with cut line.";
+        }
+        points.append(px);
+    }
+    else
+    { // The point just fine
+        points.append(sp2);
+    }
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VAbstractPiece::AngleByIntersection(const QPointF &p1, const QPointF &p2, const QPointF &p3,
+                                                     const QPointF &sp1, const QPointF &sp2, const QPointF &sp3,
+                                                     qreal width)
+{
+    QVector<QPointF> points;
+
+    QLineF edge2(p2, p3);
+    QLineF sEdge1(sp1, sp2);
+
+    QPointF px;
+    QLineF::IntersectType type = edge2.intersect(sEdge1, &px);
+    if (type == QLineF::NoIntersection)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+
+    if (QLineF(p2, px).length() > width*maxL)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+    points.append(px);
+
+    QLineF edge1(p1, p2);
+    QLineF sEdge2(sp2, sp3);
+
+    type = edge1.intersect(sEdge2, &px);
+    if (type == QLineF::NoIntersection)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+
+    if (QLineF(p2, px).length() > width*maxL)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+    points.append(px);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VAbstractPiece::AngleByFirstSymmetry(const QPointF &p1, const QPointF &p2,
+                                                      const QPointF &sp1, const QPointF &sp2, const QPointF &sp3,
+                                                      qreal width)
+{
+    QVector<QPointF> points;
+
+    QLineF sEdge2(sp2, sp3);
+    QPointF fp1 = VPointF::FlipPF(sEdge2, p1);
+    QPointF fp2 = VPointF::FlipPF(sEdge2, p2);
+    QLineF fEdge(fp1, fp2);
+
+    QPointF px;
+    QLineF sEdge1(sp1, sp2);
+    QLineF::IntersectType type = fEdge.intersect(sEdge1, &px);
+    if (type == QLineF::NoIntersection)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+
+    if (QLineF(p2, px).length() > width*maxL)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+    points.append(px);
+
+    type = fEdge.intersect(sEdge2, &px);
+    if (type == QLineF::NoIntersection)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+
+    if (QLineF(p2, px).length() > width*maxL)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+    points.append(px);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VAbstractPiece::AngleBySecondSymmetry(const QPointF &p2, const QPointF &p3,
+                                                       const QPointF &sp1, const QPointF &sp2, const QPointF &sp3,
+                                                       qreal width)
+{
+    QVector<QPointF> points;
+
+    QLineF sEdge1(sp1, sp2);
+    QPointF fp2 = VPointF::FlipPF(sEdge1, p2);
+    QPointF fp3 = VPointF::FlipPF(sEdge1, p3);
+    QLineF fEdge(fp2, fp3);
+
+    QPointF px;
+    QLineF::IntersectType type = fEdge.intersect(sEdge1, &px);
+    if (type == QLineF::NoIntersection)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+
+    if (QLineF(p2, px).length() > width*maxL)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+    points.append(px);
+
+    QLineF sEdge2(sp2, sp3);
+    type = fEdge.intersect(sEdge2, &px);
+    if (type == QLineF::NoIntersection)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+
+    if (QLineF(p2, px).length() > width*maxL)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+    points.append(px);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VAbstractPiece::AngleByFirstRightAngle(const QPointF &p1, const QPointF &p2,
+                                                        const QPointF &sp1, const QPointF &sp2, const QPointF &sp3,
+                                                        qreal width)
+{
+    QVector<QPointF> points;
+
+    QLineF edge1(p2, p1);
+    edge1.setAngle(edge1.angle()-90);
+
+    QPointF px;
+    QLineF::IntersectType type = edge1.intersect(QLineF(sp1, sp2), &px);
+    if (type == QLineF::NoIntersection)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+
+    if (QLineF(p2, px).length() > width*maxL)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+    points.append(px);
+
+    type = edge1.intersect(QLineF(sp2, sp3), &px);
+    if (type == QLineF::NoIntersection)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+
+    if (QLineF(p2, px).length() > width*maxL)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+    points.append(px);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VAbstractPiece::AngleBySecondRightAngle(const QPointF &p2, const QPointF &p3,
+                                                         const QPointF &sp1, const QPointF &sp2, const QPointF &sp3,
+                                                         qreal width)
+{
+    QVector<QPointF> points;
+
+    QLineF edge2(p2, p3);
+    edge2.setAngle(edge2.angle()+90);
+
+    QPointF px;
+    QLineF::IntersectType type = edge2.intersect(QLineF(sp1, sp2), &px);
+    if (type == QLineF::NoIntersection)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+
+    if (QLineF(p2, px).length() > width*maxL)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+    points.append(px);
+
+    type = edge2.intersect(QLineF(sp2, sp3), &px);
+    if (type == QLineF::NoIntersection)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+
+    if (QLineF(p2, px).length() > width*maxL)
+    {
+        return AngleByLength(p2, sp1, sp2, sp3, width);
+    }
+    points.append(px);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QLineF VAbstractPiece::ParallelLine(const VSAPoint &p1, const VSAPoint &p2, qreal width)
+{
+    qreal w1 = p1.GetSAAfter();
+    if (w1 < 0)
+    {
+        w1 = width;
+    }
+
+    qreal w2 = p2.GetSABefore();
+    if (w2 < 0)
+    {
+        w2 = width;
+    }
+
+    const QLineF paralel = QLineF(SingleParallelPoint(p1, p2, 90, w1),
+                                  SingleParallelPoint(p2, p1, -90, w2));
+    return paralel;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QLineF VAbstractPiece::ParallelLine(const QPointF &p1, const QPointF &p2, qreal width)
+{
+    const QLineF paralel = QLineF(SingleParallelPoint(p1, p2, 90, width),
+                                  SingleParallelPoint(p2, p1, -90, width));
+    return paralel;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QPointF VAbstractPiece::SingleParallelPoint(const QPointF &p1, const QPointF &p2, qreal angle, qreal width)
+{
+    QLineF pLine(p1, p2);
+    pLine.setAngle( pLine.angle() + angle );
+    pLine.setLength( width );
+    return pLine.p2();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QLineF VAbstractPiece::BisectorLine(const QPointF &p1, const QPointF &p2, const QPointF &p3)
+{
+    QLineF line1(p2, p1);
+    QLineF line2(p2, p3);
+    QLineF bLine;
+
+    const qreal angle1 = line1.angleTo(line2);
+    const qreal angle2 = line2.angleTo(line1);
+
+    if (angle1 <= angle2)
+    {
+        bLine = line1;
+        bLine.setAngle(bLine.angle() + angle1/2.0);
+    }
+    else
+    {
+        bLine = line2;
+        bLine.setAngle(bLine.angle() + angle2/2.0);
+    }
+
+    return bLine;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+qreal VAbstractPiece::AngleBetweenBisectors(const QLineF &b1, const QLineF &b2)
+{
+    const QLineF newB2 = b2.translated(-(b2.p1().x() - b1.p1().x()), -(b2.p1().y() - b1.p1().y()));
+
+    qreal angle1 = newB2.angleTo(b1);
+    if (VFuzzyComparePossibleNulls(angle1, 360))
+    {
+        angle1 = 0;
+    }
+
+    qreal angle2 = b1.angleTo(newB2);
+    if (VFuzzyComparePossibleNulls(angle2, 360))
+    {
+        angle2 = 0;
+    }
+
+    if (angle1 <= angle2)
+    {
+        return angle1;
+    }
+    else
+    {
+        return angle2;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VAbstractPiece::CheckIntersection(const QVector<QPointF> &points, int i, int iNext, int j, int jNext,
+                                        const QPointF &crossPoint)
+{
+    QVector<QPointF> sub1 = SubPath(points, iNext, j);
+    sub1.append(crossPoint);
+    sub1 = CheckLoops(CorrectEquidistantPoints(sub1, false));
+    const qreal sub1Sum = SumTrapezoids(sub1);
+
+    QVector<QPointF> sub2 = SubPath(points, jNext, i);
+    sub2.append(crossPoint);
+    sub2 = CheckLoops(CorrectEquidistantPoints(sub2, false));
+    const qreal sub2Sum = SumTrapezoids(sub2);
+
+    if (sub1Sum < 0 && sub2Sum < 0)
+    {
+        if (Crossing(sub1, sub2))
+        {
+            return true;
+        }
+    }
+    else
+    {
+        if (not Crossing(sub1, sub2))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VAbstractPiece::ParallelCrossPoint(const QLineF &line1, const QLineF &line2, QPointF &point)
+{
+    const bool l1p1el2p1 = (line1.p1() == line2.p1());
+    const bool l1p2el2p2 = (line1.p2() == line2.p2());
+    const bool l1p1el2p2 = (line1.p1() == line2.p2());
+    const bool l1p2el2p1 = (line1.p2() == line2.p1());
+
+    if (l1p2el2p2 || l1p2el2p1)
+    {
+        point = line1.p2();
+        return true;
+    }
+    else if (l1p1el2p1 || l1p1el2p2)
+    {
+        point = line1.p1();
+        return true;
+    }
+    else
+    {
+        point = QPointF();
+        return false;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VAbstractPiece::Crossing(const QVector<QPointF> &sub1, const QVector<QPointF> &sub2)
+{
+    if (sub1.isEmpty() || sub2.isEmpty())
+    {
+        return false;
+    }
+
+    const QRectF sub1Rect = QPolygonF(sub1).boundingRect();
+    const QRectF sub2Rect = QPolygonF(sub2).boundingRect();
+    if (not sub1Rect.intersects(sub2Rect))
+    {
+        return false;
+    }
+
+    QPainterPath sub1Path;
+    sub1Path.setFillRule(Qt::WindingFill);
+    sub1Path.moveTo(sub1.at(0));
+    for (qint32 i = 1; i < sub1.count(); ++i)
+    {
+        sub1Path.lineTo(sub1.at(i));
+    }
+    sub1Path.lineTo(sub1.at(0));
+
+    QPainterPath sub2Path;
+    sub2Path.setFillRule(Qt::WindingFill);
+    sub2Path.moveTo(sub2.at(0));
+    for (qint32 i = 1; i < sub2.count(); ++i)
+    {
+        sub2Path.lineTo(sub2.at(i));
+    }
+    sub2Path.lineTo(sub2.at(0));
+
+    if (not sub1Path.intersects(sub2Path))
+    {
+        return false;
+    }
+    else
+    {
+        return true;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VAbstractPiece::SubPath(const QVector<QPointF> &path, int startIndex, int endIndex)
+{
+    if (path.isEmpty()
+       || startIndex < 0 || startIndex >= path.size()
+       || endIndex < 0 || endIndex >= path.size()
+       || startIndex == endIndex)
+    {
+        return path;
+    }
+
+    QVector<QPointF> subPath;
+    int i = startIndex - 1;
+    do
+    {
+        ++i;
+        if (i >= path.size())
+        {
+            i = 0;
+        }
+        subPath.append(path.at(i));
+    } while (i != endIndex);
+
+    return subPath;
+}
diff --git a/src/libs/vlayout/vabstractpiece.h b/src/libs/vlayout/vabstractpiece.h
new file mode 100644
index 000000000..a6b0a8dc5
--- /dev/null
+++ b/src/libs/vlayout/vabstractpiece.h
@@ -0,0 +1,309 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   3 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VABSTRACTPIECE_H
+#define VABSTRACTPIECE_H
+
+#include <QtGlobal>
+#include <QSharedDataPointer>
+#include <QPointF>
+#include <QDebug>
+
+#include "../vmisc/diagnostic.h"
+#include "../vmisc/def.h"
+#include "../vgeometry/vgobject.h"
+
+template <class T> class QVector;
+
+class VAbstractPieceData;
+class QLineF;
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Weffc++")
+
+/**
+ * @brief The VSAPoint class seam allowance point
+ */
+class VSAPoint : public QPointF
+{
+public:
+    Q_DECL_CONSTEXPR VSAPoint();
+    Q_DECL_CONSTEXPR VSAPoint(qreal xpos, qreal ypos);
+    Q_DECL_CONSTEXPR explicit VSAPoint(const QPointF &p);
+
+    Q_DECL_CONSTEXPR qreal GetSABefore() const;
+                     void  SetSABefore(qreal value);
+
+    Q_DECL_CONSTEXPR qreal GetSAAfter() const;
+                     void  SetSAAfter(qreal value);
+
+    Q_DECL_CONSTEXPR PieceNodeAngle GetAngleType() const;
+                     void           SetAngleType(PieceNodeAngle value);
+
+private:
+    qreal          m_before;
+    qreal          m_after;
+    PieceNodeAngle m_angle;
+};
+
+Q_DECLARE_METATYPE(VSAPoint)
+Q_DECLARE_TYPEINFO(VSAPoint, Q_MOVABLE_TYPE);
+
+//---------------------------------------------------------------------------------------------------------------------
+Q_DECL_CONSTEXPR inline VSAPoint::VSAPoint()
+    : QPointF(),
+      m_before(-1),
+      m_after(-1),
+      m_angle(PieceNodeAngle::ByLength)
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+Q_DECL_CONSTEXPR inline VSAPoint::VSAPoint(qreal xpos, qreal ypos)
+    : QPointF(xpos, ypos),
+      m_before(-1),
+      m_after(-1),
+      m_angle(PieceNodeAngle::ByLength)
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+Q_DECL_CONSTEXPR inline VSAPoint::VSAPoint(const QPointF &p)
+    : QPointF(p),
+      m_before(-1),
+      m_after(-1),
+      m_angle(PieceNodeAngle::ByLength)
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+Q_DECL_CONSTEXPR inline qreal VSAPoint::GetSABefore() const
+{
+    return m_before;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+inline void VSAPoint::SetSABefore(qreal value)
+{
+    value < 0 ? m_before = -1 : m_before = value;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+Q_DECL_CONSTEXPR inline qreal VSAPoint::GetSAAfter() const
+{
+    return m_after;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+inline void VSAPoint::SetSAAfter(qreal value)
+{
+    value < 0 ? m_after = -1 : m_after = value;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+Q_DECL_CONSTEXPR inline PieceNodeAngle VSAPoint::GetAngleType() const
+{
+    return m_angle;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+inline void VSAPoint::SetAngleType(PieceNodeAngle value)
+{
+    m_angle = value;
+}
+
+QT_WARNING_POP
+
+class VAbstractPiece
+{
+public:
+    VAbstractPiece();
+    VAbstractPiece(const VAbstractPiece &piece);
+    VAbstractPiece &operator=(const VAbstractPiece &piece);
+    virtual ~VAbstractPiece();
+
+    QString GetName() const;
+    void    SetName(const QString &value);
+
+    bool IsForbidFlipping() const;
+    void SetForbidFlipping(bool value);
+
+    bool IsSeamAllowance() const;
+    void SetSeamAllowance(bool value);
+
+    qreal GetSAWidth() const;
+    void  SetSAWidth(qreal value);
+
+    static QVector<QPointF> Equidistant(const QVector<VSAPoint> &points, qreal width);
+    static qreal            SumTrapezoids(const QVector<QPointF> &points);
+    static QVector<QPointF> CheckLoops(const QVector<QPointF> &points);
+
+    template <class T>
+    static QVector<T> CorrectEquidistantPoints(const QVector<T> &points, bool removeFirstAndLast = true);
+
+protected:
+    template <class T>
+    static QVector<T> RemoveDublicates(const QVector<T> &points, bool removeFirstAndLast = true);
+
+private:
+    QSharedDataPointer<VAbstractPieceData> d;
+
+    static bool             CheckIntersection(const QVector<QPointF> &points, int i, int iNext, int j, int jNext,
+                                              const QPointF &crossPoint);
+    static bool             ParallelCrossPoint(const QLineF &line1, const QLineF &line2, QPointF &point);
+    static bool             Crossing(const QVector<QPointF> &sub1, const QVector<QPointF> &sub2);
+    static QVector<QPointF> SubPath(const QVector<QPointF> &path, int startIndex, int endIndex);
+    static Q_DECL_CONSTEXPR qreal PointPosition(const QPointF &p, const QLineF &line);
+    static qreal            MaxLocalSA(const VSAPoint &p, qreal width);
+    static QVector<QPointF> EkvPoint(const VSAPoint &p1Line1, const VSAPoint &p2Line1,
+                                     const VSAPoint &p1Line2, const VSAPoint &p2Line2, qreal width);
+    static QVector<QPointF> AngleByLength(const QPointF &p2, const QPointF &sp1, const QPointF &sp2, const QPointF &sp3,
+                                          qreal width);
+    static QVector<QPointF> AngleByIntersection(const QPointF &p1, const QPointF &p2, const QPointF &p3,
+                                                const QPointF &sp1, const QPointF &sp2, const QPointF &sp3,
+                                                qreal width);
+    static QVector<QPointF> AngleByFirstSymmetry(const QPointF &p1, const QPointF &p2,
+                                                 const QPointF &sp1, const QPointF &sp2, const QPointF &sp3,
+                                                 qreal width);
+    static QVector<QPointF> AngleBySecondSymmetry(const QPointF &p2, const QPointF &p3,
+                                                  const QPointF &sp1, const QPointF &sp2, const QPointF &sp3,
+                                                  qreal width);
+    static QVector<QPointF> AngleByFirstRightAngle(const QPointF &p1, const QPointF &p2,
+                                                   const QPointF &sp1, const QPointF &sp2, const QPointF &sp3,
+                                                   qreal width);
+    static QVector<QPointF> AngleBySecondRightAngle(const QPointF &p2, const QPointF &p3,
+                                                    const QPointF &sp1, const QPointF &sp2, const QPointF &sp3,
+                                                    qreal width);
+    static QLineF           ParallelLine(const VSAPoint &p1, const VSAPoint &p2, qreal width);
+    static QLineF           ParallelLine(const QPointF &p1, const QPointF &p2, qreal width);
+    static QPointF          SingleParallelPoint(const QPointF &p1, const QPointF &p2, qreal angle, qreal width);
+    static QLineF           BisectorLine(const QPointF &p1, const QPointF &p2, const QPointF &p3);
+    static qreal            AngleBetweenBisectors(const QLineF &b1, const QLineF &b2);
+};
+
+Q_DECLARE_TYPEINFO(VAbstractPiece, Q_MOVABLE_TYPE);
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief CorrectEquidistantPoints clear equivalent points and remove point on line from equdistant.
+ * @param points list of points equdistant.
+ * @return corrected list.
+ */
+template <class T>
+QVector<T> VAbstractPiece::CorrectEquidistantPoints(const QVector<T> &points, bool removeFirstAndLast)
+{
+    if (points.size()<4)//Better don't check if only three points. We can destroy equidistant.
+    {
+        qDebug()<<"Only three points.";
+        return points;
+    }
+
+    //Clear equivalent points
+    QVector<T> buf1 = RemoveDublicates(points, removeFirstAndLast);
+
+    if (buf1.size()<3)
+    {
+        return buf1;
+    }
+
+    QVector<T> buf2;
+    //Remove point on line
+    for (qint32 i = 0; i < buf1.size(); ++i)
+    {// In this case we alwayse will have bounded intersection, so all is need is to check if point i is on line.
+     // Unfortunatelly QLineF::intersect can't be used in this case because of the floating-point accuraccy problem.
+        int prev = i-1;
+        int next = i+1;
+        if (i == 0)
+        {
+            prev = buf1.size() - 1;
+        }
+        else if (i == buf1.size() - 1)
+        {
+            next = 0;
+        }
+
+        const QPointF &iPoint = buf1.at(i);
+        const QPointF &prevPoint = buf1.at(prev);
+        const QPointF &nextPoint = buf1.at(next);
+
+        if (not VGObject::IsPointOnLineviaPDP(buf1.at(i), buf1.at(prev), buf1.at(next))
+                && prevPoint != nextPoint) // not zigzag
+        {
+            buf2.append(buf1.at(i));
+        }
+        else if ((i == 0 || i == buf1.size() - 1) && (iPoint == prevPoint || iPoint == nextPoint))
+        {
+            // If RemoveDublicates does not remove these points it is a valid case.
+            // Case where last point equal first point
+            buf2.append(buf1.at(i));
+        }
+    }
+
+    buf2 = RemoveDublicates(buf2, false);
+
+    return buf2;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+template <class T>
+QVector<T> VAbstractPiece::RemoveDublicates(const QVector<T> &points, bool removeFirstAndLast)
+{
+    QVector<T> p = points;
+
+    if (removeFirstAndLast)
+    {
+        if (not p.isEmpty() && p.size() > 1)
+        {
+            // Path can't be closed
+            if (p.first() == p.last())
+            {
+            #if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
+                p.remove(p.size() - 1);
+            #else
+                p.removeLast();
+            #endif
+            }
+        }
+    }
+
+    for (int i = 0; i < p.size()-1; ++i)
+    {
+        if (p.at(i) == p.at(i+1))
+        {
+            if (not removeFirstAndLast && (i == p.size()-1))
+            {
+                continue;
+            }
+
+            p.erase(p.begin() + i + 1);
+            --i;
+            continue;
+        }
+    }
+
+    return p;
+}
+
+#endif // VABSTRACTPIECE_H
diff --git a/src/libs/vlayout/vabstractdetail_p.h b/src/libs/vlayout/vabstractpiece_p.h
similarity index 53%
rename from src/libs/vlayout/vabstractdetail_p.h
rename to src/libs/vlayout/vabstractpiece_p.h
index 54fded0b3..c99abd5c0 100644
--- a/src/libs/vlayout/vabstractdetail_p.h
+++ b/src/libs/vlayout/vabstractpiece_p.h
@@ -1,14 +1,14 @@
 /************************************************************************
  **
- **  @file   vabstractdetail_p.h
+ **  @file
  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   2 1, 2015
+ **  @date   9 11, 2016
  **
  **  @brief
  **  @copyright
  **  This source code is part of the Valentine project, a pattern making
  **  program, whose allow create and modeling patterns of clothing.
- **  Copyright (C) 2013-2015 Valentina project
+ **  Copyright (C) 2016 Valentina project
  **  <https://bitbucket.org/dismine/valentina> All Rights Reserved.
  **
  **  Valentina is free software: you can redistribute it and/or modify
@@ -26,50 +26,53 @@
  **
  *************************************************************************/
 
-#ifndef VABSTRACTDETAIL_P_H
-#define VABSTRACTDETAIL_P_H
+#ifndef VABSTRACTPIECE_P_H
+#define VABSTRACTPIECE_P_H
 
 #include <QSharedData>
 #include <QString>
+#include <QCoreApplication>
 
 #include "../vmisc/diagnostic.h"
 
 QT_WARNING_PUSH
 QT_WARNING_DISABLE_GCC("-Weffc++")
 
-class VAbstractDetailData : public QSharedData
+class VAbstractPieceData : public QSharedData
 {
+    Q_DECLARE_TR_FUNCTIONS(VAbstractPieceData)
 public:
-    VAbstractDetailData()
-        :name(QString()), seamAllowance(false), closed(true), width(0), forbidFlipping(false)
+    VAbstractPieceData()
+        : m_name(tr("Detail")),
+          m_forbidFlipping(false),
+          m_seamAllowance(false),
+          m_width(0)
     {}
 
-    explicit VAbstractDetailData(const QString &name)
-        :name(name), seamAllowance(false), closed(true), width(0), forbidFlipping(false)
+    VAbstractPieceData(const VAbstractPieceData &piece)
+        : QSharedData(piece),
+          m_name(piece.m_name),
+          m_forbidFlipping(piece.m_forbidFlipping),
+          m_seamAllowance(piece.m_seamAllowance),
+          m_width(piece.m_width)
     {}
 
-    VAbstractDetailData(const VAbstractDetailData &detail)
-        :QSharedData(detail), name(detail.name), seamAllowance(detail.seamAllowance), closed(detail.closed),
-          width(detail.width), forbidFlipping(detail.forbidFlipping)
-    {}
+    ~VAbstractPieceData();
 
-    ~VAbstractDetailData() {}
-
-    /** @brief name detail name. */
-    QString        name;
-    /** @brief seamAllowance status seamAllowance detail. */
-    bool           seamAllowance;
-    /** @brief closed status equdistant detail. */
-    bool           closed;
-    /** @brief width value seamAllowance in mm. */
-    qreal          width;
+    QString m_name;
     /** @brief forbidFlipping forbid piece be mirrored in a layout. */
-    bool           forbidFlipping;
+    bool    m_forbidFlipping;
+    bool    m_seamAllowance;
+    qreal   m_width;
 
 private:
-    VAbstractDetailData &operator=(const VAbstractDetailData &) Q_DECL_EQ_DELETE;
+    VAbstractPieceData &operator=(const VAbstractPieceData &) Q_DECL_EQ_DELETE;
 };
 
+VAbstractPieceData::~VAbstractPieceData()
+{}
+
 QT_WARNING_POP
 
-#endif // VABSTRACTDETAIL_P_H
+#endif // VABSTRACTPIECE_P_H
+
diff --git a/src/libs/vlayout/vbank.cpp b/src/libs/vlayout/vbank.cpp
index f28787391..9d889a9c7 100644
--- a/src/libs/vlayout/vbank.cpp
+++ b/src/libs/vlayout/vbank.cpp
@@ -32,7 +32,7 @@
 
 #include "../vmisc/diagnostic.h"
 #include "../vmisc/logging.h"
-#include "vlayoutdetail.h"
+#include "vlayoutpiece.h"
 
 QT_WARNING_PUSH
 QT_WARNING_DISABLE_CLANG("-Wmissing-prototypes")
@@ -52,7 +52,7 @@ QT_WARNING_POP
 
 //---------------------------------------------------------------------------------------------------------------------
 VBank::VBank()
-    :details(QVector<VLayoutDetail>()), unsorted(QHash<int, qint64>()), big(QHash<int, qint64>()),
+    :details(QVector<VLayoutPiece>()), unsorted(QHash<int, qint64>()), big(QHash<int, qint64>()),
       middle(QHash<int, qint64>()), small(QHash<int, qint64>()), layoutWidth(0), caseType(Cases::CaseDesc),
       prepare(false), diagonal(0)
 {}
@@ -71,7 +71,7 @@ void VBank::SetLayoutWidth(const qreal &value)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VBank::SetDetails(const QVector<VLayoutDetail> &details)
+void VBank::SetDetails(const QVector<VLayoutPiece> &details)
 {
     this->details = details;
     Reset();
@@ -111,7 +111,7 @@ int VBank::GetTiket()
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-VLayoutDetail VBank::GetDetail(int i) const
+VLayoutPiece VBank::GetDetail(int i) const
 {
     if (i >= 0 && i < details.size())
     {
@@ -119,7 +119,7 @@ VLayoutDetail VBank::GetDetail(int i) const
     }
     else
     {
-        return VLayoutDetail();
+        return VLayoutPiece();
     }
 }
 
@@ -191,7 +191,7 @@ bool VBank::Prepare()
     for (int i=0; i < details.size(); ++i)
     {
         details[i].SetLayoutWidth(layoutWidth);
-        details[i].SetLayoutAllowencePoints();
+        details[i].SetLayoutAllowancePoints();
 
         const qreal d = details.at(i).Diagonal();
         if (d > diagonal)
diff --git a/src/libs/vlayout/vbank.h b/src/libs/vlayout/vbank.h
index 51cd7e312..340f034d2 100644
--- a/src/libs/vlayout/vbank.h
+++ b/src/libs/vlayout/vbank.h
@@ -43,7 +43,7 @@
 #endif
 
 class QPointF;
-class VLayoutDetail;
+class VLayoutPiece;
 
 enum class Cases : char { CaseThreeGroup = 0, CaseTwoGroup, CaseDesc, UnknownCase};
 
@@ -55,9 +55,9 @@ public:
     qreal GetLayoutWidth() const;
     void SetLayoutWidth(const qreal &value);
 
-    void SetDetails(const QVector<VLayoutDetail> &details);
+    void SetDetails(const QVector<VLayoutPiece> &details);
     int  GetTiket();
-    VLayoutDetail GetDetail(int i) const;
+    VLayoutPiece GetDetail(int i) const;
 
     void Arranged(int i);
     void NotArranged(int i);
@@ -74,7 +74,7 @@ public:
 
 private:
     Q_DISABLE_COPY(VBank)
-    QVector<VLayoutDetail> details;
+    QVector<VLayoutPiece> details;
     QHash<int, qint64> unsorted;
 
     QHash<int, qint64> big;
diff --git a/src/libs/vlayout/vcontour.cpp b/src/libs/vlayout/vcontour.cpp
index 03ae18dee..da72142cb 100644
--- a/src/libs/vlayout/vcontour.cpp
+++ b/src/libs/vlayout/vcontour.cpp
@@ -37,7 +37,7 @@
 #include <Qt>
 
 #include "vcontour_p.h"
-#include "vlayoutdetail.h"
+#include "vlayoutpiece.h"
 #include "../vmisc/vmath.h"
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -125,7 +125,7 @@ QSizeF VContour::GetSize() const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> VContour::UniteWithContour(const VLayoutDetail &detail, int globalI, int detJ, BestFrom type) const
+QVector<QPointF> VContour::UniteWithContour(const VLayoutPiece &detail, int globalI, int detJ, BestFrom type) const
 {
     QVector<QPointF> newContour;
     if (d->globalContour.isEmpty()) //-V807
@@ -333,7 +333,7 @@ QPainterPath VContour::ContourPath() const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VContour::AppendWhole(QVector<QPointF> &contour, const VLayoutDetail &detail, int detJ) const
+void VContour::AppendWhole(QVector<QPointF> &contour, const VLayoutPiece &detail, int detJ) const
 {
     int processedEdges = 0;
     const int nD = detail.LayoutEdgesCount();
diff --git a/src/libs/vlayout/vcontour.h b/src/libs/vlayout/vcontour.h
index baa64f963..cfa622da4 100644
--- a/src/libs/vlayout/vcontour.h
+++ b/src/libs/vlayout/vcontour.h
@@ -43,7 +43,7 @@ class QPointF;
 class QRectF;
 class QSizeF;
 class VContourData;
-class VLayoutDetail;
+class VLayoutPiece;
 
 class VContour
 {
@@ -68,7 +68,7 @@ public:
 
     QSizeF GetSize() const;
 
-    QVector<QPointF> UniteWithContour(const VLayoutDetail &detail, int globalI, int detJ, BestFrom type) const;
+    QVector<QPointF> UniteWithContour(const VLayoutPiece &detail, int globalI, int detJ, BestFrom type) const;
 
     QLineF EmptySheetEdge() const;
     int    GlobalEdgesCount() const;
@@ -85,7 +85,7 @@ public:
 private:
     QSharedDataPointer<VContourData> d;
 
-    void AppendWhole(QVector<QPointF> &contour, const VLayoutDetail &detail, int detJ) const;
+    void AppendWhole(QVector<QPointF> &contour, const VLayoutPiece &detail, int detJ) const;
 };
 
 Q_DECLARE_TYPEINFO(VContour, Q_MOVABLE_TYPE);
diff --git a/src/libs/vlayout/vgraphicsfillitem.cpp b/src/libs/vlayout/vgraphicsfillitem.cpp
index d619b1278..e29fbb5b0 100644
--- a/src/libs/vlayout/vgraphicsfillitem.cpp
+++ b/src/libs/vlayout/vgraphicsfillitem.cpp
@@ -29,8 +29,8 @@
 #include "vgraphicsfillitem.h"
 
 //---------------------------------------------------------------------------------------------------------------------
-VGraphicsFillItem::VGraphicsFillItem()
-    :QGraphicsPathItem()
+VGraphicsFillItem::VGraphicsFillItem(QGraphicsItem *parent)
+    :QGraphicsPathItem(parent)
 {}
 
 //---------------------------------------------------------------------------------------------------------------------
diff --git a/src/libs/vlayout/vgraphicsfillitem.h b/src/libs/vlayout/vgraphicsfillitem.h
index 467d62e12..564e36986 100644
--- a/src/libs/vlayout/vgraphicsfillitem.h
+++ b/src/libs/vlayout/vgraphicsfillitem.h
@@ -38,7 +38,7 @@ public:
     /**
      * @brief VGraphicsFillItem Constructor
      */
-    VGraphicsFillItem();
+    explicit VGraphicsFillItem(QGraphicsItem *parent = nullptr);
     /**
      * @brief ~VGraphicsFillItem Destructor
      */
diff --git a/src/libs/vlayout/vlayout.pri b/src/libs/vlayout/vlayout.pri
index 6d82d469f..11a46ad9c 100644
--- a/src/libs/vlayout/vlayout.pri
+++ b/src/libs/vlayout/vlayout.pri
@@ -4,10 +4,6 @@
 HEADERS += \
     $$PWD/stable.h \
     $$PWD/vlayoutgenerator.h \
-    $$PWD/vlayoutdetail.h \
-    $$PWD/vabstractdetail.h \
-    $$PWD/vabstractdetail_p.h \
-    $$PWD/vlayoutdetail_p.h \
     $$PWD/vlayoutdef.h \
     $$PWD/vlayoutpaper.h \
     $$PWD/vlayoutpaper_p.h \
@@ -17,20 +13,24 @@ HEADERS += \
     $$PWD/vbestsquare.h \
     $$PWD/vposition.h \
     $$PWD/vtextmanager.h \
-    vposter.h \
-    vgraphicsfillitem.h
+    $$PWD/vposter.h \
+    $$PWD/vgraphicsfillitem.h \
+    $$PWD/vabstractpiece.h \
+    $$PWD/vabstractpiece_p.h \
+    $$PWD/vlayoutpiece.h \
+    $$PWD/vlayoutpiece_p.h
 
 SOURCES += \
     $$PWD/vlayoutgenerator.cpp \
-    $$PWD/vlayoutdetail.cpp \
-    $$PWD/vabstractdetail.cpp \
     $$PWD/vlayoutpaper.cpp \
     $$PWD/vbank.cpp \
     $$PWD/vcontour.cpp \
     $$PWD/vbestsquare.cpp \
     $$PWD/vposition.cpp \
     $$PWD/vtextmanager.cpp \
-    vposter.cpp \
-    vgraphicsfillitem.cpp
+    $$PWD/vposter.cpp \
+    $$PWD/vgraphicsfillitem.cpp \
+    $$PWD/vabstractpiece.cpp \
+    $$PWD/vlayoutpiece.cpp
 
 win32-msvc*:SOURCES += $$PWD/stable.cpp
diff --git a/src/libs/vlayout/vlayoutdef.h b/src/libs/vlayout/vlayoutdef.h
index 19fbcc297..d302fd957 100644
--- a/src/libs/vlayout/vlayoutdef.h
+++ b/src/libs/vlayout/vlayoutdef.h
@@ -33,8 +33,6 @@
     #include <ciso646>
 #endif /* Q_CC_MSVC */
 
-enum class EquidistantType : char { OpenEquidistant, CloseEquidistant };
-
 enum class LayoutErrors : char
 {
     NoError,
diff --git a/src/libs/vlayout/vlayoutgenerator.cpp b/src/libs/vlayout/vlayoutgenerator.cpp
index cc374eed7..0117f04ee 100644
--- a/src/libs/vlayout/vlayoutgenerator.cpp
+++ b/src/libs/vlayout/vlayoutgenerator.cpp
@@ -34,7 +34,7 @@
 
 #include "../vmisc/def.h"
 #include "../vmisc/vmath.h"
-#include "vlayoutdetail.h"
+#include "vlayoutpiece.h"
 #include "vlayoutpaper.h"
 
 class QMarginsF;
@@ -54,7 +54,7 @@ VLayoutGenerator::~VLayoutGenerator()
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutGenerator::SetDetails(const QVector<VLayoutDetail> &details)
+void VLayoutGenerator::SetDetails(const QVector<VLayoutPiece> &details)
 {
     bank->SetDetails(details);
 }
@@ -273,7 +273,7 @@ void VLayoutGenerator::GatherPages()
         return;
     }
 
-    QList<QList<VLayoutDetail>> nDetails;
+    QList<QList<VLayoutPiece>> nDetails;
     qreal length = 0;
     int j = 0; // papers count
 
@@ -328,7 +328,7 @@ void VLayoutGenerator::UnitePages()
     }
 
     QList<qreal> papersLength;
-    QList<QList<VLayoutDetail> > nDetails;
+    QList<QList<VLayoutPiece> > nDetails;
     qreal length = 0;
     int j = 0; // papers count
 
@@ -385,7 +385,7 @@ void VLayoutGenerator::UnitePages()
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutGenerator::UniteDetails(int j, QList<QList<VLayoutDetail> > &nDetails, qreal length, int i)
+void VLayoutGenerator::UniteDetails(int j, QList<QList<VLayoutPiece> > &nDetails, qreal length, int i)
 {
     if ((j == 0 && nDetails.isEmpty()) || j >= nDetails.size())
     {//First or new details in paper
@@ -411,17 +411,17 @@ void VLayoutGenerator::UnitePapers(int j, QList<qreal> &papersLength, qreal leng
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QList<VLayoutDetail> VLayoutGenerator::MoveDetails(qreal length, const QVector<VLayoutDetail> &details)
+QList<VLayoutPiece> VLayoutGenerator::MoveDetails(qreal length, const QVector<VLayoutPiece> &details)
 {
     if (qFuzzyIsNull(length))
     {
         return details.toList();
     }
 
-    QList<VLayoutDetail> newDetails;
+    QList<VLayoutPiece> newDetails;
     for (int i = 0; i < details.size(); ++i)
     {
-        VLayoutDetail d = details.at(i);
+        VLayoutPiece d = details.at(i);
         d.Translate(0, length);
         newDetails.append(d);
     }
diff --git a/src/libs/vlayout/vlayoutgenerator.h b/src/libs/vlayout/vlayoutgenerator.h
index 90caa59bd..822e35658 100644
--- a/src/libs/vlayout/vlayoutgenerator.h
+++ b/src/libs/vlayout/vlayoutgenerator.h
@@ -50,7 +50,7 @@ class QMarginsF;
 #endif
 
 class QGraphicsItem;
-class VLayoutDetail;
+class VLayoutPiece;
 class VLayoutPaper;
 
 class VLayoutGenerator :public QObject
@@ -60,7 +60,7 @@ public:
     explicit VLayoutGenerator(QObject *parent = nullptr);
     virtual ~VLayoutGenerator() Q_DECL_OVERRIDE;
 
-    void SetDetails(const QVector<VLayoutDetail> &details);
+    void SetDetails(const QVector<VLayoutPiece> &details);
     void SetLayoutWidth(qreal width);
     void SetCaseType(Cases caseType);
     int DetailsCount();
@@ -140,9 +140,9 @@ private:
 
     void GatherPages();
     void UnitePages();
-    void UniteDetails(int j, QList<QList<VLayoutDetail> > &nDetails, qreal length, int i);
+    void UniteDetails(int j, QList<QList<VLayoutPiece> > &nDetails, qreal length, int i);
     void UnitePapers(int j, QList<qreal> &papersLength, qreal length);
-    QList<VLayoutDetail> MoveDetails(qreal length, const QVector<VLayoutDetail> &details);
+    QList<VLayoutPiece> MoveDetails(qreal length, const QVector<VLayoutPiece> &details);
 };
 
 typedef std::shared_ptr<VLayoutGenerator> VLayoutGeneratorPtr;
diff --git a/src/libs/vlayout/vlayoutpaper.cpp b/src/libs/vlayout/vlayoutpaper.cpp
index 3cd1b4b15..d3c21749c 100644
--- a/src/libs/vlayout/vlayoutpaper.cpp
+++ b/src/libs/vlayout/vlayoutpaper.cpp
@@ -45,7 +45,7 @@
 
 #include "vbestsquare.h"
 #include "vcontour.h"
-#include "vlayoutdetail.h"
+#include "vlayoutpiece.h"
 #include "vlayoutpaper_p.h"
 #include "vposition.h"
 
@@ -185,7 +185,7 @@ void VLayoutPaper::SetPaperIndex(quint32 index)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-bool VLayoutPaper::ArrangeDetail(const VLayoutDetail &detail, volatile bool &stop)
+bool VLayoutPaper::ArrangeDetail(const VLayoutPiece &detail, volatile bool &stop)
 {
     // First need set size of paper
     if (d->globalContour.GetHeight() <= 0 || d->globalContour.GetWidth() <= 0)
@@ -198,7 +198,7 @@ bool VLayoutPaper::ArrangeDetail(const VLayoutDetail &detail, volatile bool &sto
         return false;//Not enough edges
     }
 
-    if (detail.getForbidFlipping() && not d->globalRotate)
+    if (detail.IsForbidFlipping() && not d->globalRotate)
     { // Compensate forbidden flipping by rotating. 180 degree will be enough.
         d->localRotate = true;
         d->localRotationIncrease = 180;
@@ -221,7 +221,7 @@ int VLayoutPaper::Count() const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-bool VLayoutPaper::AddToSheet(const VLayoutDetail &detail, volatile bool &stop)
+bool VLayoutPaper::AddToSheet(const VLayoutPiece &detail, volatile bool &stop)
 {
     VBestSquare bestResult(d->globalContour.GetSize(), d->saveLength);
     QThreadPool *thread_pool = QThreadPool::globalInstance();
@@ -289,11 +289,11 @@ bool VLayoutPaper::AddToSheet(const VLayoutDetail &detail, volatile bool &stop)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-bool VLayoutPaper::SaveResult(const VBestSquare &bestResult, const VLayoutDetail &detail)
+bool VLayoutPaper::SaveResult(const VBestSquare &bestResult, const VLayoutPiece &detail)
 {
     if (bestResult.ValidResult())
     {
-        VLayoutDetail workDetail = detail;
+        VLayoutPiece workDetail = detail;
         workDetail.SetMatrix(bestResult.Matrix());// Don't forget set matrix
         workDetail.SetMirror(bestResult.Mirror());
         const QVector<QPointF> newGContour = d->globalContour.UniteWithContour(workDetail, bestResult.GContourEdge(),
@@ -354,28 +354,18 @@ QList<QGraphicsItem *> VLayoutPaper::GetItemDetails() const
     for (int i=0; i < d->details.count(); ++i)
     {
         list.append(d->details.at(i).GetItem());
-        for (int iT = 0; iT < d->details.at(i).GetTextItemsCount(); ++iT)
-        {
-            list.append(d->details.at(i).GetTextItem(iT));
-        }
-
-        QGraphicsItem* pItem = d->details.at(i).GetGrainlineItem();
-        if (pItem != 0)
-        {
-            list.append(pItem);
-        }
     }
     return list;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QVector<VLayoutDetail> VLayoutPaper::GetDetails() const
+QVector<VLayoutPiece> VLayoutPaper::GetDetails() const
 {
     return d->details;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutPaper::SetDetails(const QList<VLayoutDetail> &details)
+void VLayoutPaper::SetDetails(const QList<VLayoutPiece> &details)
 {
     d->details = details.toVector();
 }
diff --git a/src/libs/vlayout/vlayoutpaper.h b/src/libs/vlayout/vlayoutpaper.h
index 8c48a076d..7a28b8d74 100644
--- a/src/libs/vlayout/vlayoutpaper.h
+++ b/src/libs/vlayout/vlayoutpaper.h
@@ -40,7 +40,7 @@ class QGraphicsItem;
 class QGraphicsRectItem;
 class QRectF;
 class VBestSquare;
-class VLayoutDetail;
+class VLayoutPiece;
 class VLayoutPaperData;
 template <typename T> class QList;
 template <typename T> class QVector;
@@ -77,22 +77,22 @@ public:
 
     void SetPaperIndex(quint32 index);
 
-    bool ArrangeDetail(const VLayoutDetail &detail, volatile bool &stop);
+    bool ArrangeDetail(const VLayoutPiece &detail, volatile bool &stop);
     int  Count() const;
     QGraphicsRectItem *GetPaperItem(bool autoCrop) const Q_REQUIRED_RESULT;
     QList<QGraphicsItem *> GetItemDetails() const Q_REQUIRED_RESULT;
 
-    QVector<VLayoutDetail> GetDetails() const;
-    void                   SetDetails(const QList<VLayoutDetail>& details);
+    QVector<VLayoutPiece> GetDetails() const;
+    void                   SetDetails(const QList<VLayoutPiece>& details);
 
     QRectF DetailsBoundingRect() const;
 
 private:
     QSharedDataPointer<VLayoutPaperData> d;
 
-    bool AddToSheet(const VLayoutDetail &detail, volatile bool &stop);
+    bool AddToSheet(const VLayoutPiece &detail, volatile bool &stop);
 
-    bool SaveResult(const VBestSquare &bestResult, const VLayoutDetail &detail);
+    bool SaveResult(const VBestSquare &bestResult, const VLayoutPiece &detail);
 
 };
 
diff --git a/src/libs/vlayout/vlayoutpaper_p.h b/src/libs/vlayout/vlayoutpaper_p.h
index 34ec699bf..81acb7a45 100644
--- a/src/libs/vlayout/vlayoutpaper_p.h
+++ b/src/libs/vlayout/vlayoutpaper_p.h
@@ -33,7 +33,7 @@
 #include <QVector>
 #include <QPointF>
 
-#include "vlayoutdetail.h"
+#include "vlayoutpiece.h"
 #include "vcontour.h"
 
 QT_WARNING_PUSH
@@ -43,7 +43,7 @@ class VLayoutPaperData : public QSharedData
 {
 public:
     VLayoutPaperData()
-        : details(QVector<VLayoutDetail>()),
+        : details(QVector<VLayoutPiece>()),
           globalContour(VContour()),
           paperIndex(0),
           frame(0),
@@ -57,7 +57,7 @@ public:
 
     VLayoutPaperData(int height,
                      int width)
-        : details(QVector<VLayoutDetail>()),
+        : details(QVector<VLayoutPiece>()),
           globalContour(VContour(height, width)),
           paperIndex(0),
           frame(0),
@@ -86,7 +86,7 @@ public:
     ~VLayoutPaperData() {}
 
     /** @brief details list of arranged details. */
-    QVector<VLayoutDetail> details;
+    QVector<VLayoutPiece> details;
 
     /** @brief globalContour list of global points contour. */
     VContour globalContour;
diff --git a/src/libs/vlayout/vlayoutdetail.cpp b/src/libs/vlayout/vlayoutpiece.cpp
similarity index 74%
rename from src/libs/vlayout/vlayoutdetail.cpp
rename to src/libs/vlayout/vlayoutpiece.cpp
index cb00675b7..e8585188e 100644
--- a/src/libs/vlayout/vlayoutdetail.cpp
+++ b/src/libs/vlayout/vlayoutpiece.cpp
@@ -26,7 +26,7 @@
  **
  *************************************************************************/
 
-#include "vlayoutdetail.h"
+#include "vlayoutpiece.h"
 
 #include <QBrush>
 #include <QFlags>
@@ -49,7 +49,7 @@
 #include "../vmisc/vabstractapplication.h"
 #include "../vpatterndb/calculator.h"
 #include "vlayoutdef.h"
-#include "vlayoutdetail_p.h"
+#include "vlayoutpiece_p.h"
 #include "vtextmanager.h"
 #include "vgraphicsfillitem.h"
 
@@ -58,79 +58,114 @@ class QLineF;
 class VAbstractPattern;
 
 //---------------------------------------------------------------------------------------------------------------------
-VLayoutDetail::VLayoutDetail()
-    :VAbstractDetail(), d(new VLayoutDetailData)
+VLayoutPiece::VLayoutPiece()
+    :VAbstractPiece(), d(new VLayoutPieceData)
 {}
 
 //---------------------------------------------------------------------------------------------------------------------
-VLayoutDetail::VLayoutDetail(const VLayoutDetail &detail)
-    :VAbstractDetail(detail), d(detail.d)
+VLayoutPiece::VLayoutPiece(const VLayoutPiece &detail)
+    :VAbstractPiece(detail), d(detail.d)
 {}
 
 //---------------------------------------------------------------------------------------------------------------------
-VLayoutDetail &VLayoutDetail::operator=(const VLayoutDetail &detail)
+VLayoutPiece &VLayoutPiece::operator=(const VLayoutPiece &detail)
 {
     if ( &detail == this )
     {
         return *this;
     }
-    VAbstractDetail::operator=(detail);
+    VAbstractPiece::operator=(detail);
     d = detail.d;
     return *this;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-VLayoutDetail::~VLayoutDetail()
+VLayoutPiece::~VLayoutPiece()
 {}
 
+//---------------------------------------------------------------------------------------------------------------------
+VLayoutPiece VLayoutPiece::Create(const VPiece &piece, const VContainer *pattern)
+{
+    VLayoutPiece det;
+    det.SetCountourPoints(piece.MainPathPoints(pattern));
+    det.SetSeamAllowancePoints(piece.SeamAllowancePoints(pattern), piece.IsSeamAllowance());
+    det.SetInternlaPathsPoints(piece.GetInternalPathsPoints(pattern));
+    det.SetName(piece.GetName());
+    const VPatternPieceData& data = piece.GetPatternPieceData();
+    if (data.IsVisible() == true)
+    {
+        det.SetDetail(piece.GetName(), data, qApp->font());
+    }
+    const VPatternInfoGeometry& geom = piece.GetPatternInfo();
+    if (geom.IsVisible() == true)
+    {
+        VAbstractPattern* pDoc = qApp->getCurrentDocument();
+        QDate date;
+        if (pDoc->IsDateVisible() == true)
+        {
+            date = QDate::currentDate();
+        }
+        det.SetPatternInfo(pDoc, geom, qApp->font(), pattern->size(), pattern->height());
+    }
+    const VGrainlineGeometry& grainlineGeom = piece.GetGrainlineGeometry();
+    if (grainlineGeom.IsVisible() == true)
+    {
+        det.SetGrainline(grainlineGeom, *pattern);
+    }
+    det.SetSAWidth(qApp->toPixel(piece.GetSAWidth()));
+    det.CreateTextItems();
+    det.SetForbidFlipping(piece.IsForbidFlipping());
+
+    return det;
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 // cppcheck-suppress unusedFunction
-QVector<QPointF> VLayoutDetail::GetContourPoints() const
+QVector<QPointF> VLayoutPiece::GetContourPoints() const
 {
     return Map(d->contour);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::SetCountourPoints(const QVector<QPointF> &points)
+void VLayoutPiece::SetCountourPoints(const QVector<QPointF> &points)
 {
-    d->contour = RemoveDublicates(RoundPoints(points));
+    d->contour = RemoveDublicates(RoundPoints(points), false);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
 // cppcheck-suppress unusedFunction
-QVector<QPointF> VLayoutDetail::GetSeamAllowencePoints() const
+QVector<QPointF> VLayoutPiece::GetSeamAllowancePoints() const
 {
-    return Map(d->seamAllowence);
+    return Map(d->seamAllowance);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::SetSeamAllowencePoints(const QVector<QPointF> &points, bool seamAllowence, bool closed)
+void VLayoutPiece::SetSeamAllowancePoints(const QVector<QPointF> &points, bool seamAllowance)
 {
-    if (seamAllowence)
+    if (seamAllowance)
     {
-        setSeamAllowance(seamAllowence);
-        setClosed(closed);
-        d->seamAllowence = points;
-        if (not d->seamAllowence.isEmpty())
+        SetSeamAllowance(seamAllowance);
+        d->seamAllowance = points;
+        if (not d->seamAllowance.isEmpty())
         {
-            d->seamAllowence = RemoveDublicates(RoundPoints(d->seamAllowence));
+            d->seamAllowance = RemoveDublicates(RoundPoints(d->seamAllowance), false);
         }
         else
         {
             qWarning()<<"Seam allowance is empty.";
-            setSeamAllowance(false);
+            SetSeamAllowance(false);
         }
     }
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> VLayoutDetail::GetLayoutAllowencePoints() const
+QVector<QPointF> VLayoutPiece::GetLayoutAllowancePoints() const
 {
-    return Map(d->layoutAllowence);
+    return Map(d->layoutAllowance);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::SetDetail(const QString& qsName, const VPatternPieceData& data, const QFont &font)
+void VLayoutPiece::SetDetail(const QString& qsName, const VPatternPieceData& data, const QFont &font)
 {
     d->detailData = data;
     qreal dAng = qDegreesToRadians(data.GetRotation());
@@ -156,7 +191,7 @@ void VLayoutDetail::SetDetail(const QString& qsName, const VPatternPieceData& da
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::SetPatternInfo(const VAbstractPattern* pDoc, const VPatternInfoGeometry& geom, const QFont &font,
+void VLayoutPiece::SetPatternInfo(const VAbstractPattern* pDoc, const VPatternInfoGeometry& geom, const QFont &font,
                                    qreal dSize, qreal dHeight)
 {
     d->patternGeom = geom;
@@ -185,7 +220,7 @@ void VLayoutDetail::SetPatternInfo(const VAbstractPattern* pDoc, const VPatternI
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::SetGrainline(const VGrainlineGeometry& geom, const VContainer& rPattern)
+void VLayoutPiece::SetGrainline(const VGrainlineGeometry& geom, const VContainer& rPattern)
 {
     d->grainlineGeom = geom;
     qreal dAng;
@@ -252,31 +287,31 @@ void VLayoutDetail::SetGrainline(const VGrainlineGeometry& geom, const VContaine
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QTransform VLayoutDetail::GetMatrix() const
+QTransform VLayoutPiece::GetMatrix() const
 {
     return d->matrix;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::SetMatrix(const QTransform &matrix)
+void VLayoutPiece::SetMatrix(const QTransform &matrix)
 {
     d->matrix = matrix;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-qreal VLayoutDetail::GetLayoutWidth() const
+qreal VLayoutPiece::GetLayoutWidth() const
 {
     return d->layoutWidth;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::SetLayoutWidth(const qreal &value)
+void VLayoutPiece::SetLayoutWidth(const qreal &value)
 {
     d->layoutWidth = value;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::Translate(qreal dx, qreal dy)
+void VLayoutPiece::Translate(qreal dx, qreal dy)
 {
     QTransform m;
     m.translate(dx, dy);
@@ -284,7 +319,7 @@ void VLayoutDetail::Translate(qreal dx, qreal dy)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::Rotate(const QPointF &originPoint, qreal degrees)
+void VLayoutPiece::Rotate(const QPointF &originPoint, qreal degrees)
 {
     QTransform m;
     m.translate(originPoint.x(), originPoint.y());
@@ -294,7 +329,7 @@ void VLayoutDetail::Rotate(const QPointF &originPoint, qreal degrees)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::Mirror(const QLineF &edge)
+void VLayoutPiece::Mirror(const QLineF &edge)
 {
     if (edge.isNull())
     {
@@ -327,48 +362,48 @@ void VLayoutDetail::Mirror(const QLineF &edge)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-int VLayoutDetail::DetailEdgesCount() const
+int VLayoutPiece::DetailEdgesCount() const
 {
     return DetailPath().count();
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-int VLayoutDetail::LayoutEdgesCount() const
+int VLayoutPiece::LayoutEdgesCount() const
 {
-    return d->layoutAllowence.count();
+    return d->layoutAllowance.count();
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QLineF VLayoutDetail::DetailEdge(int i) const
+QLineF VLayoutPiece::DetailEdge(int i) const
 {
     return Edge(DetailPath(), i);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QLineF VLayoutDetail::LayoutEdge(int i) const
+QLineF VLayoutPiece::LayoutEdge(int i) const
 {
-    return Edge(d->layoutAllowence, i);
+    return Edge(d->layoutAllowance, i);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-int VLayoutDetail::DetailEdgeByPoint(const QPointF &p1) const
+int VLayoutPiece::DetailEdgeByPoint(const QPointF &p1) const
 {
     return EdgeByPoint(DetailPath(), p1);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-int VLayoutDetail::LayoutEdgeByPoint(const QPointF &p1) const
+int VLayoutPiece::LayoutEdgeByPoint(const QPointF &p1) const
 {
-    return EdgeByPoint(d->layoutAllowence, p1);
+    return EdgeByPoint(d->layoutAllowance, p1);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QRectF VLayoutDetail::DetailBoundingRect() const
+QRectF VLayoutPiece::DetailBoundingRect() const
 {
     QVector<QPointF> points;
-    if (getSeamAllowance())
+    if (IsSeamAllowance())
     {
-        points = GetSeamAllowencePoints();
+        points = GetSeamAllowancePoints();
     }
     else
     {
@@ -380,26 +415,26 @@ QRectF VLayoutDetail::DetailBoundingRect() const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QRectF VLayoutDetail::LayoutBoundingRect() const
+QRectF VLayoutPiece::LayoutBoundingRect() const
 {
-    QVector<QPointF> points = GetLayoutAllowencePoints();
+    QVector<QPointF> points = GetLayoutAllowancePoints();
     points.append(points.first());
     return QPolygonF(points).boundingRect();
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-qreal VLayoutDetail::Diagonal() const
+qreal VLayoutPiece::Diagonal() const
 {
     const QRectF rec = LayoutBoundingRect();
     return qSqrt(pow(rec.height(), 2) + pow(rec.width(), 2));
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-bool VLayoutDetail::isNull() const
+bool VLayoutPiece::isNull() const
 {
     if (d->contour.isEmpty() == false && d->layoutWidth > 0)
     {
-        if (getSeamAllowance() && d->seamAllowence.isEmpty() == false)
+        if (IsSeamAllowance() && d->seamAllowance.isEmpty() == false)
         {
             return false;
         }
@@ -415,58 +450,69 @@ bool VLayoutDetail::isNull() const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-qint64 VLayoutDetail::Square() const
+qint64 VLayoutPiece::Square() const
 {
-    if (d->layoutAllowence.isEmpty()) //-V807
+    if (d->layoutAllowance.isEmpty()) //-V807
     {
         return 0;
     }
 
-    const qreal res = SumTrapezoids(d->layoutAllowence);
+    const qreal res = SumTrapezoids(d->layoutAllowance);
 
     const qint64 sq = qFloor(qAbs(res/2.0));
     return sq;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::SetLayoutAllowencePoints()
+void VLayoutPiece::SetLayoutAllowancePoints()
 {
     if (d->layoutWidth > 0)
     {
-        if (getSeamAllowance())
+        if (IsSeamAllowance())
         {
-            d->layoutAllowence = Equidistant(GetSeamAllowencePoints(), EquidistantType::CloseEquidistant,
-                                             d->layoutWidth);
-            if (d->layoutAllowence.isEmpty() == false)
+            d->layoutAllowance = Equidistant(PrepareAllowance(GetSeamAllowancePoints()), d->layoutWidth);
+            if (d->layoutAllowance.isEmpty() == false)
             {
                 #if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
-                    d->layoutAllowence.remove(d->layoutAllowence.size() - 1);
+                    d->layoutAllowance.remove(d->layoutAllowance.size() - 1);
                 #else
-                    d->layoutAllowence.removeLast();
+                    d->layoutAllowance.removeLast();
                 #endif
             }
         }
         else
         {
-            d->layoutAllowence = Equidistant(GetContourPoints(), EquidistantType::CloseEquidistant, d->layoutWidth);
-            if (d->layoutAllowence.isEmpty() == false)
+            d->layoutAllowance = Equidistant(PrepareAllowance(GetContourPoints()), d->layoutWidth);
+            if (d->layoutAllowance.isEmpty() == false)
             {
             #if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
-                d->layoutAllowence.remove(d->layoutAllowence.size() - 1);
+                d->layoutAllowance.remove(d->layoutAllowance.size() - 1);
             #else
-                d->layoutAllowence.removeLast();
+                d->layoutAllowance.removeLast();
             #endif
             }
         }
     }
     else
     {
-        d->layoutAllowence.clear();
+        d->layoutAllowance.clear();
     }
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> VLayoutDetail::Map(const QVector<QPointF> &points) const
+QVector<QVector<QPointF>> VLayoutPiece::GetInternlaPathsPoints() const
+{
+    return d->m_internalPaths;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VLayoutPiece::SetInternlaPathsPoints(const QVector<QVector<QPointF>> &internalPathsPoints)
+{
+    d->m_internalPaths = internalPathsPoints;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VLayoutPiece::Map(const QVector<QPointF> &points) const
 {
     QVector<QPointF> p;
     for (int i = 0; i < points.size(); ++i)
@@ -487,7 +533,7 @@ QVector<QPointF> VLayoutDetail::Map(const QVector<QPointF> &points) const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> VLayoutDetail::RoundPoints(const QVector<QPointF> &points)
+QVector<QPointF> VLayoutPiece::RoundPoints(const QVector<QPointF> &points)
 {
     QVector<QPointF> p;
     for (int i=0; i < points.size(); ++i)
@@ -498,7 +544,7 @@ QVector<QPointF> VLayoutDetail::RoundPoints(const QVector<QPointF> &points)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QPainterPath VLayoutDetail::ContourPath() const
+QPainterPath VLayoutPiece::ContourPath() const
 {
     QPainterPath path;
 
@@ -512,13 +558,13 @@ QPainterPath VLayoutDetail::ContourPath() const
     path.lineTo(points.at(0));
 
     // seam allowance
-    if (getSeamAllowance() == true)
+    if (IsSeamAllowance() == true)
     {
-        points = GetSeamAllowencePoints();
+        points = GetSeamAllowancePoints();
 
-        if (getClosed() == true)
+        if (points.last().toPoint() != points.first().toPoint())
         {
-            points.append(points.at(0));
+            points.append(points.at(0));// Should be always closed
         }
 
         QPainterPath ekv;
@@ -536,13 +582,13 @@ QPainterPath VLayoutDetail::ContourPath() const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::ClearTextItems()
+void VLayoutPiece::ClearTextItems()
 {
     d->m_liPP.clear();
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::CreateTextItems()
+void VLayoutPiece::CreateTextItems()
 {
     ClearTextItems();
     // first add detail texts
@@ -662,21 +708,17 @@ void VLayoutDetail::CreateTextItems()
     }
 }
 
-//---------------------------------------------------------------------------------------------------------------------
-int VLayoutDetail::GetTextItemsCount() const
-{
-    return d->m_liPP.count();
-}
-
 //---------------------------------------------------------------------------------------------------------------------
 /**
- * @brief VLayoutDetail::GetTextItem Creates and returns the i-th text item
+ * @brief CreateTextItem Creates the i-th text item
  * @param i index of the requested item
- * @return pointer to the newly created item. The caller is responsible to delete it.
+ * @param parent parent of this text item. Can't be null.
  */
-QGraphicsItem* VLayoutDetail::GetTextItem(int i) const
+void VLayoutPiece::CreateTextItem(int i, QGraphicsItem *parent) const
 {
-    QGraphicsPathItem* item = new QGraphicsPathItem();
+    SCASSERT(parent != nullptr)
+
+    QGraphicsPathItem* item = new QGraphicsPathItem(parent);
     QTransform transform = d->matrix;
 
     QPainterPath path = transform.map(d->m_liPP[i]);
@@ -714,16 +756,15 @@ QGraphicsItem* VLayoutDetail::GetTextItem(int i) const
 
     item->setPath(path);
     item->setBrush(QBrush(Qt::black));
-    return item;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QPainterPath VLayoutDetail::LayoutAllowencePath() const
+QPainterPath VLayoutPiece::LayoutAllowancePath() const
 {
     QPainterPath path;
     path.setFillRule(Qt::WindingFill);
 
-    const QVector<QPointF> points = GetLayoutAllowencePoints();
+    const QVector<QPointF> points = GetLayoutAllowancePoints();
     path.moveTo(points.at(0));
     for (qint32 i = 1; i < points.count(); ++i)
     {
@@ -735,21 +776,33 @@ QPainterPath VLayoutDetail::LayoutAllowencePath() const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QGraphicsItem *VLayoutDetail::GetItem() const
+QGraphicsItem *VLayoutPiece::GetItem() const
 {
     QGraphicsPathItem *item = new QGraphicsPathItem();
-    item->setPath(ContourPath());
+    QPainterPath contour = ContourPath();
+    contour.addPath(InternalPathsPath());
+    item->setPath(contour);
+
+    for (int i = 0; i < d->m_liPP.count(); ++i)
+    {
+        CreateTextItem(i, item);
+    }
+
+    CreateGrainlineItem(item);
+
     return item;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QGraphicsItem* VLayoutDetail::GetGrainlineItem() const
+void VLayoutPiece::CreateGrainlineItem(QGraphicsItem *parent) const
 {
+    SCASSERT(parent != nullptr)
+
     if (d->grainlinePoints.count() < 2)
     {
-        return 0;
+        return;
     }
-    VGraphicsFillItem* item = new VGraphicsFillItem();
+    VGraphicsFillItem* item = new VGraphicsFillItem(parent);
     QPainterPath path;
     QVector<QPointF> v = Map(d->grainlinePoints);
     path.moveTo(v.at(0));
@@ -758,15 +811,37 @@ QGraphicsItem* VLayoutDetail::GetGrainlineItem() const
         path.lineTo(v.at(i));
     }
     item->setPath(path);
-    return item;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> VLayoutDetail::DetailPath() const
+QPainterPath VLayoutPiece::InternalPathsPath() const
 {
-    if (getSeamAllowance())
+    QPainterPath allPaths;
+    allPaths.setFillRule(Qt::WindingFill);
+
+    for (qint32 i = 0; i < d->m_internalPaths.count(); ++i)
     {
-        return d->seamAllowence;
+        const QVector<QPointF> points = Map(d->m_internalPaths.at(i));
+        QPainterPath path;
+        path.setFillRule(Qt::WindingFill);
+        path.moveTo(points.at(0));
+        for (qint32 j = 1; j < points.count(); ++j)
+        {
+            path.lineTo(points.at(j));
+        }
+        path.lineTo(points.at(0));
+        allPaths.addPath(path);
+    }
+
+    return allPaths;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VLayoutPiece::DetailPath() const
+{
+    if (IsSeamAllowance())
+    {
+        return d->seamAllowance;
     }
     else
     {
@@ -775,13 +850,24 @@ QVector<QPointF> VLayoutDetail::DetailPath() const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-bool VLayoutDetail::IsMirror() const
+QVector<VSAPoint> VLayoutPiece::PrepareAllowance(const QVector<QPointF> &points)
+{
+    QVector<VSAPoint> allowancePoints;
+    for(int i = 0; i < points.size(); ++i)
+    {
+        allowancePoints.append(VSAPoint(points.at(i)));
+    }
+    return allowancePoints;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VLayoutPiece::IsMirror() const
 {
     return d->mirror;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VLayoutDetail::SetMirror(bool value)
+void VLayoutPiece::SetMirror(bool value)
 {
     d->mirror = value;
 }
@@ -794,7 +880,7 @@ void VLayoutDetail::SetMirror(bool value)
  * @param dAng angle of rotation
  * @return position of point pt after rotating it around the center for dAng radians
  */
-QPointF VLayoutDetail::RotatePoint(const QPointF &ptCenter, const QPointF& pt, qreal dAng)
+QPointF VLayoutPiece::RotatePoint(const QPointF &ptCenter, const QPointF& pt, qreal dAng)
 {
     QPointF ptDest;
     QPointF ptRel = pt - ptCenter;
@@ -811,7 +897,7 @@ QPointF VLayoutDetail::RotatePoint(const QPointF &ptCenter, const QPointF& pt, q
  * @param points list of 4 label vertices
  * @return list of flipped points
  */
-QVector<QPointF> VLayoutDetail::Mirror(const QVector<QPointF> &points) const
+QVector<QPointF> VLayoutPiece::Mirror(const QVector<QPointF> &points) const
 {
     // should only call this method with rectangular shapes
     Q_ASSERT(points.count() == 4);
@@ -836,7 +922,7 @@ QVector<QPointF> VLayoutDetail::Mirror(const QVector<QPointF> &points) const
  * @param pt2 second point
  * @return Euclidian distance between the two points
  */
-qreal VLayoutDetail::GetDistance(const QPointF &pt1, const QPointF &pt2)
+qreal VLayoutPiece::GetDistance(const QPointF &pt1, const QPointF &pt2)
 {
     const qreal dX = pt1.x() - pt2.x();
     const qreal dY = pt1.y() - pt2.y();
@@ -845,7 +931,7 @@ qreal VLayoutDetail::GetDistance(const QPointF &pt1, const QPointF &pt2)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QLineF VLayoutDetail::Edge(const QVector<QPointF> &path, int i) const
+QLineF VLayoutPiece::Edge(const QVector<QPointF> &path, int i) const
 {
     if (i < 1 || i > path.count())
     { // Doesn't exist such edge
@@ -879,7 +965,7 @@ QLineF VLayoutDetail::Edge(const QVector<QPointF> &path, int i) const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-int VLayoutDetail::EdgeByPoint(const QVector<QPointF> &path, const QPointF &p1) const
+int VLayoutPiece::EdgeByPoint(const QVector<QPointF> &path, const QPointF &p1) const
 {
     if (p1.isNull())
     {
diff --git a/src/libs/vlayout/vlayoutdetail.h b/src/libs/vlayout/vlayoutpiece.h
similarity index 77%
rename from src/libs/vlayout/vlayoutdetail.h
rename to src/libs/vlayout/vlayoutpiece.h
index e23924dcf..5bd966a0a 100644
--- a/src/libs/vlayout/vlayoutdetail.h
+++ b/src/libs/vlayout/vlayoutpiece.h
@@ -45,7 +45,7 @@
 #include "../vpatterndb/vpatterninfogeometry.h"
 #include "../vpatterndb/vpatternpiecedata.h"
 #include "../vpatterndb/vcontainer.h"
-#include "vabstractdetail.h"
+#include "vabstractpiece.h"
 
 class QFont;
 class QGraphicsItem;
@@ -55,27 +55,32 @@ class QPointF;
 class QRectF;
 class QTransform;
 class VAbstractPattern;
-class VLayoutDetailData;
+class VLayoutPieceData;
 class VPatternInfoGeometry;
 class VPatternPieceData;
 class VGrainlineGeometry;
 
-class VLayoutDetail :public VAbstractDetail
+class VLayoutPiece :public VAbstractPiece
 {
 public:
-    VLayoutDetail();
-    VLayoutDetail(const VLayoutDetail &detail);
-    VLayoutDetail &operator=(const VLayoutDetail &detail);
-    virtual ~VLayoutDetail() Q_DECL_OVERRIDE;
+    VLayoutPiece();
+    VLayoutPiece(const VLayoutPiece &detail);
+    VLayoutPiece &operator=(const VLayoutPiece &detail);
+    virtual ~VLayoutPiece() Q_DECL_OVERRIDE;
+
+    static VLayoutPiece Create(const VPiece &piece, const VContainer *pattern);
 
     QVector<QPointF> GetContourPoints() const;
     void SetCountourPoints(const QVector<QPointF> &points);
 
-    QVector<QPointF> GetSeamAllowencePoints() const;
-    void SetSeamAllowencePoints(const QVector<QPointF> &points, bool seamAllowence = true, bool closed = true);
+    QVector<QPointF> GetSeamAllowancePoints() const;
+    void SetSeamAllowancePoints(const QVector<QPointF> &points, bool seamAllowance = true);
 
-    QVector<QPointF> GetLayoutAllowencePoints() const;
-    void SetLayoutAllowencePoints();
+    QVector<QPointF> GetLayoutAllowancePoints() const;
+    void SetLayoutAllowancePoints();
+
+    QVector<QVector<QPointF>> GetInternlaPathsPoints() const;
+    void SetInternlaPathsPoints(const QVector<QVector<QPointF>> &internalPathsPoints);
 
     void SetDetail(const QString &qsName, const VPatternPieceData& data, const QFont& font);
 
@@ -113,19 +118,24 @@ public:
     bool isNull() const;
     qint64 Square() const;
     QPainterPath ContourPath() const;
-    void ClearTextItems();
-    void CreateTextItems();
-    int GetTextItemsCount() const Q_REQUIRED_RESULT;
-    QGraphicsItem* GetTextItem(int i) const Q_REQUIRED_RESULT;
-    QPainterPath LayoutAllowencePath() const;
+
+    QPainterPath LayoutAllowancePath() const;
     QGraphicsItem *GetItem() const Q_REQUIRED_RESULT;
-    QGraphicsItem* GetGrainlineItem() const Q_REQUIRED_RESULT;
 
 private:
-    QSharedDataPointer<VLayoutDetailData>   d;
+    QSharedDataPointer<VLayoutPieceData>   d;
 
     QVector<QPointF> DetailPath() const;
 
+    void ClearTextItems();
+    void CreateTextItems();
+
+    void CreateTextItem(int i, QGraphicsItem *parent) const;
+    void CreateGrainlineItem(QGraphicsItem *parent) const;
+
+    QPainterPath InternalPathsPath() const;
+
+    static QVector<VSAPoint> PrepareAllowance(const QVector<QPointF> &points);
     QVector<QPointF> Map(const QVector<QPointF> &points) const;
     static QVector<QPointF> RoundPoints(const QVector<QPointF> &points);
 
@@ -137,6 +147,6 @@ private:
     int    EdgeByPoint(const QVector<QPointF> &path, const QPointF &p1) const;
 };
 
-Q_DECLARE_TYPEINFO(VLayoutDetail, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(VLayoutPiece, Q_MOVABLE_TYPE);
 
 #endif // VLAYOUTDETAIL_H
diff --git a/src/libs/vlayout/vlayoutdetail_p.h b/src/libs/vlayout/vlayoutpiece_p.h
similarity index 51%
rename from src/libs/vlayout/vlayoutdetail_p.h
rename to src/libs/vlayout/vlayoutpiece_p.h
index cd4478fb7..aab150348 100644
--- a/src/libs/vlayout/vlayoutdetail_p.h
+++ b/src/libs/vlayout/vlayoutpiece_p.h
@@ -43,65 +43,91 @@
 QT_WARNING_PUSH
 QT_WARNING_DISABLE_GCC("-Weffc++")
 
-class VLayoutDetailData : public QSharedData
+class VLayoutPieceData : public QSharedData
 {
 public:
-    VLayoutDetailData()
-        :contour(QVector<QPointF>()), seamAllowence(QVector<QPointF>()), layoutAllowence(QVector<QPointF>()),
-          matrix(QMatrix()), layoutWidth(0), mirror(false), detailLabel(QVector<QPointF>()),
-          patternInfo(QVector<QPointF>()), grainlinePoints(QVector<QPointF>()), detailData(), patternGeom(),
-          grainlineGeom(), m_tmDetail(), m_tmPattern(), m_liPP(QList<QPainterPath>())
+    VLayoutPieceData()
+        : contour(),
+          seamAllowance(),
+          layoutAllowance(),
+          m_internalPaths(),
+          matrix(),
+          layoutWidth(0),
+          mirror(false),
+          detailLabel(),
+          patternInfo(),
+          grainlinePoints(),
+          detailData(),
+          patternGeom(),
+          grainlineGeom(),
+          m_tmDetail(),
+          m_tmPattern(),
+          m_liPP()
     {}
 
-    VLayoutDetailData(const VLayoutDetailData &detail)
-        :QSharedData(detail), contour(detail.contour), seamAllowence(detail.seamAllowence),
-          layoutAllowence(detail.layoutAllowence), matrix(detail.matrix),
-          layoutWidth(detail.layoutWidth), mirror(detail.mirror), detailLabel(detail.detailLabel),
-          patternInfo(detail.patternInfo), grainlinePoints(detail.grainlinePoints), detailData(detail.detailData),
-          patternGeom(detail.patternGeom), grainlineGeom(detail.grainlineGeom), m_tmDetail(detail.m_tmDetail),
-          m_tmPattern(detail.m_tmPattern), m_liPP(detail.m_liPP)
+    VLayoutPieceData(const VLayoutPieceData &detail)
+        : QSharedData(detail),
+          contour(detail.contour),
+          seamAllowance(detail.seamAllowance),
+          layoutAllowance(detail.layoutAllowance),
+          m_internalPaths(detail.m_internalPaths),
+          matrix(detail.matrix),
+          layoutWidth(detail.layoutWidth),
+          mirror(detail.mirror),
+          detailLabel(detail.detailLabel),
+          patternInfo(detail.patternInfo),
+          grainlinePoints(detail.grainlinePoints),
+          detailData(detail.detailData),
+          patternGeom(detail.patternGeom),
+          grainlineGeom(detail.grainlineGeom),
+          m_tmDetail(detail.m_tmDetail),
+          m_tmPattern(detail.m_tmPattern),
+          m_liPP(detail.m_liPP)
     {}
 
-    ~VLayoutDetailData() {}
+    ~VLayoutPieceData() {}
 
     /** @brief contour list of contour points. */
-    QVector<QPointF>                        contour;
+    QVector<QPointF>          contour;
 
-    /** @brief seamAllowence list of seam allowance points. */
-    QVector<QPointF>                        seamAllowence;
+    /** @brief seamAllowance list of seam allowance points. */
+    QVector<QPointF>          seamAllowance;
 
-    /** @brief layoutAllowence list of layout allowance points. */
-    QVector<QPointF>                        layoutAllowence;
+    /** @brief layoutAllowance list of layout allowance points. */
+    QVector<QPointF>          layoutAllowance;
+
+    /** @brief m_internalPaths list of internal paths points. */
+    QVector<QVector<QPointF>> m_internalPaths;
 
     /** @brief matrix transformation matrix*/
-    QTransform                              matrix;
+    QTransform                matrix;
 
     /** @brief layoutWidth value layout allowance width in pixels. */
-    qreal                                   layoutWidth;
+    qreal                     layoutWidth;
 
-    bool                                    mirror;
+    bool                      mirror;
 
     /** @brief detailLabel detail label rectangle */
-    QVector<QPointF>                        detailLabel;
+    QVector<QPointF>          detailLabel;
     /** @brief patternInfo pattern info rectangle */
-    QVector<QPointF>                        patternInfo;
+    QVector<QPointF>          patternInfo;
     /** @brief grainlineInfo line */
-    QVector<QPointF>                        grainlinePoints;
+    QVector<QPointF>          grainlinePoints;
     /** @brief detailData detail data */
-    VPatternPieceData                       detailData;
+    VPatternPieceData         detailData;
     /** @brief patternGeom pattern geometry */
-    VPatternInfoGeometry                    patternGeom;
+    VPatternInfoGeometry      patternGeom;
     /** @brief grainlineGeom grainline geometry */
-    VGrainlineGeometry                      grainlineGeom;
+    VGrainlineGeometry        grainlineGeom;
     /** @brief m_tmDetail text manager for laying out detail info */
-    VTextManager                            m_tmDetail;
+    VTextManager              m_tmDetail;
     /** @brief m_tmPattern text manager for laying out pattern info */
-    VTextManager                            m_tmPattern;
+    VTextManager              m_tmPattern;
     /** @bried m_liPP list of generated text painter paths */
-    QList<QPainterPath>                     m_liPP;
+    QList<QPainterPath>       m_liPP;
 
 private:
-    VLayoutDetailData &operator=(const VLayoutDetailData &) Q_DECL_EQ_DELETE;
+    VLayoutPieceData &operator=(const VLayoutPieceData &) Q_DECL_EQ_DELETE;
 };
 
 QT_WARNING_POP
diff --git a/src/libs/vlayout/vposition.cpp b/src/libs/vlayout/vposition.cpp
index 9308536f2..6c7345a67 100644
--- a/src/libs/vlayout/vposition.cpp
+++ b/src/libs/vlayout/vposition.cpp
@@ -50,10 +50,10 @@
 #include "../vmisc/vmath.h"
 
 //---------------------------------------------------------------------------------------------------------------------
-VPosition::VPosition(const VContour &gContour, int j, const VLayoutDetail &detail, int i, volatile bool *stop,
+VPosition::VPosition(const VContour &gContour, int j, const VLayoutPiece &detail, int i, volatile bool *stop,
                      bool rotate, int rotationIncrease, bool saveLength)
     :QRunnable(), bestResult(VBestSquare(gContour.GetSize(), saveLength)), gContour(gContour), detail(detail), i(i),
-      j(j), paperIndex(0), frame(0), detailsCount(0), details(QVector<VLayoutDetail>()), stop(stop), rotate(rotate),
+      j(j), paperIndex(0), frame(0), detailsCount(0), details(QVector<VLayoutPiece>()), stop(stop), rotate(rotate),
       rotationIncrease(rotationIncrease), angle_between(0)
 {
     if ((rotationIncrease >= 1 && rotationIncrease <= 180 && 360 % rotationIncrease == 0) == false)
@@ -71,7 +71,7 @@ void VPosition::run()
     }
 
     // We should use copy of the detail.
-    VLayoutDetail workDetail = detail;
+    VLayoutPiece workDetail = detail;
 
     int dEdge = i;// For mirror detail edge will be different
     if (CheckCombineEdges(workDetail, j, dEdge))
@@ -139,7 +139,7 @@ void VPosition::setDetailsCount(const quint32 &value)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VPosition::setDetails(const QVector<VLayoutDetail> &details)
+void VPosition::setDetails(const QVector<VLayoutPiece> &details)
 {
     this->details = details;
 }
@@ -151,8 +151,8 @@ VBestSquare VPosition::getBestResult() const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VPosition::DrawDebug(const VContour &contour, const VLayoutDetail &detail, int frame, quint32 paperIndex,
-                          int detailsCount, const QVector<VLayoutDetail> &details)
+void VPosition::DrawDebug(const VContour &contour, const VLayoutPiece &detail, int frame, quint32 paperIndex,
+                          int detailsCount, const QVector<VLayoutPiece> &details)
 {
     const int biasWidth = Bias(contour.GetWidth(), QIMAGE_MAX);
     const int biasHeight = Bias(contour.GetHeight(), QIMAGE_MAX);
@@ -178,7 +178,7 @@ void VPosition::DrawDebug(const VContour &contour, const VLayoutDetail &detail,
 
 #ifdef SHOW_CANDIDATE
     paint.setPen(QPen(Qt::darkGreen, 6, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
-    p = DrawContour(detail.GetLayoutAllowencePoints());
+    p = DrawContour(detail.GetLayoutAllowancePoints());
     p.translate(biasWidth/2, biasHeight/2);
     paint.drawPath(p);
 #else
@@ -242,7 +242,7 @@ int VPosition::Bias(int length, int maxLength)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VPosition::SaveCandidate(VBestSquare &bestResult, const VLayoutDetail &detail, int globalI, int detJ,
+void VPosition::SaveCandidate(VBestSquare &bestResult, const VLayoutPiece &detail, int globalI, int detJ,
                               BestFrom type)
 {
     QVector<QPointF> newGContour = gContour.UniteWithContour(detail, globalI, detJ, type);
@@ -252,7 +252,7 @@ void VPosition::SaveCandidate(VBestSquare &bestResult, const VLayoutDetail &deta
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-bool VPosition::CheckCombineEdges(VLayoutDetail &detail, int j, int &dEdge)
+bool VPosition::CheckCombineEdges(VLayoutPiece &detail, int j, int &dEdge)
 {
     const QLineF globalEdge = gContour.GlobalEdge(j);
     bool flagMirror = false;
@@ -294,7 +294,7 @@ bool VPosition::CheckCombineEdges(VLayoutDetail &detail, int j, int &dEdge)
             break;
     }
 
-    if (flagMirror && not detail.getForbidFlipping())
+    if (flagMirror && not detail.IsForbidFlipping())
     {
         #ifdef LAYOUT_DEBUG
             #ifdef SHOW_MIRROR
@@ -340,7 +340,7 @@ bool VPosition::CheckCombineEdges(VLayoutDetail &detail, int j, int &dEdge)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-bool VPosition::CheckRotationEdges(VLayoutDetail &detail, int j, int dEdge, int angle) const
+bool VPosition::CheckRotationEdges(VLayoutPiece &detail, int j, int dEdge, int angle) const
 {
     const QLineF globalEdge = gContour.GlobalEdge(j);
     bool flagSquare = false;
@@ -376,7 +376,7 @@ bool VPosition::CheckRotationEdges(VLayoutDetail &detail, int j, int dEdge, int
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-VPosition::CrossingType VPosition::Crossing(const VLayoutDetail &detail) const
+VPosition::CrossingType VPosition::Crossing(const VLayoutPiece &detail) const
 {
     const QRectF gRect = gContour.BoundingRect();
     if (not gRect.intersects(detail.LayoutBoundingRect()) && not gRect.contains(detail.DetailBoundingRect()))
@@ -386,7 +386,7 @@ VPosition::CrossingType VPosition::Crossing(const VLayoutDetail &detail) const
     }
 
     const QPainterPath gPath = gContour.ContourPath();
-    if (not gPath.intersects(detail.LayoutAllowencePath()) && not gPath.contains(detail.ContourPath()))
+    if (not gPath.intersects(detail.LayoutAllowancePath()) && not gPath.contains(detail.ContourPath()))
     {
         return CrossingType::NoIntersection;
     }
@@ -404,7 +404,7 @@ bool VPosition::SheetContains(const QRectF &rect) const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VPosition::CombineEdges(VLayoutDetail &detail, const QLineF &globalEdge, const int &dEdge)
+void VPosition::CombineEdges(VLayoutPiece &detail, const QLineF &globalEdge, const int &dEdge)
 {
     QLineF detailEdge;
     if (gContour.GetContour().isEmpty())
@@ -433,7 +433,7 @@ void VPosition::CombineEdges(VLayoutDetail &detail, const QLineF &globalEdge, co
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VPosition::RotateEdges(VLayoutDetail &detail, const QLineF &globalEdge, int dEdge, int angle) const
+void VPosition::RotateEdges(VLayoutPiece &detail, const QLineF &globalEdge, int dEdge, int angle) const
 {
     QLineF detailEdge;
     if (gContour.GetContour().isEmpty())
@@ -472,7 +472,7 @@ void VPosition::Rotate(int increase)
         }
 
         // We should use copy of the detail.
-        VLayoutDetail workDetail = detail;
+        VLayoutPiece workDetail = detail;
 
         if (CheckRotationEdges(workDetail, j, i, angle))
         {
@@ -549,7 +549,7 @@ QPainterPath VPosition::DrawContour(const QVector<QPointF> &points)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QPainterPath VPosition::DrawDetails(const QVector<VLayoutDetail> &details)
+QPainterPath VPosition::DrawDetails(const QVector<VLayoutPiece> &details)
 {
     QPainterPath path;
     path.setFillRule(Qt::WindingFill);
diff --git a/src/libs/vlayout/vposition.h b/src/libs/vlayout/vposition.h
index 692d05d42..c607d4777 100644
--- a/src/libs/vlayout/vposition.h
+++ b/src/libs/vlayout/vposition.h
@@ -37,7 +37,7 @@
 #include "vbestsquare.h"
 #include "vcontour.h"
 #include "vlayoutdef.h"
-#include "vlayoutdetail.h"
+#include "vlayoutpiece.h"
 
 class QLineF;
 class QPainterPath;
@@ -48,7 +48,7 @@ class QRectF;
 class VPosition : public QRunnable
 {
 public:
-    VPosition(const VContour &gContour, int j, const VLayoutDetail &detail, int i, volatile bool *stop, bool rotate,
+    VPosition(const VContour &gContour, int j, const VLayoutPiece &detail, int i, volatile bool *stop, bool rotate,
               int rotationIncrease, bool saveLength);
     virtual ~VPosition() Q_DECL_OVERRIDE{}
 
@@ -61,12 +61,12 @@ public:
     quint32 getDetailsCount() const;
     void setDetailsCount(const quint32 &value);
 
-    void setDetails(const QVector<VLayoutDetail> &details);
+    void setDetails(const QVector<VLayoutPiece> &details);
 
     VBestSquare getBestResult() const;
 
-    static void DrawDebug(const VContour &contour, const VLayoutDetail &detail, int frame, quint32 paperIndex,
-                          int detailsCount, const QVector<VLayoutDetail> &details = QVector<VLayoutDetail>());
+    static void DrawDebug(const VContour &contour, const VLayoutPiece &detail, int frame, quint32 paperIndex,
+                          int detailsCount, const QVector<VLayoutPiece> &details = QVector<VLayoutPiece>());
 
     static int Bias(int length, int maxLength);
 
@@ -74,13 +74,13 @@ private:
     Q_DISABLE_COPY(VPosition)
     VBestSquare bestResult;
     const VContour gContour;
-    const VLayoutDetail detail;
+    const VLayoutPiece detail;
     int i;
     int j;
     quint32 paperIndex;
     quint32 frame;
     quint32 detailsCount;
-    QVector<VLayoutDetail> details;
+    QVector<VLayoutPiece> details;
     volatile bool *stop;
     bool rotate;
     int rotationIncrease;
@@ -105,20 +105,20 @@ private:
 
     virtual void run() Q_DECL_OVERRIDE;
 
-    void SaveCandidate(VBestSquare &bestResult, const VLayoutDetail &detail, int globalI, int detJ, BestFrom type);
+    void SaveCandidate(VBestSquare &bestResult, const VLayoutPiece &detail, int globalI, int detJ, BestFrom type);
 
-    bool CheckCombineEdges(VLayoutDetail &detail, int j, int &dEdge);
-    bool CheckRotationEdges(VLayoutDetail &detail, int j, int dEdge, int angle) const;
+    bool CheckCombineEdges(VLayoutPiece &detail, int j, int &dEdge);
+    bool CheckRotationEdges(VLayoutPiece &detail, int j, int dEdge, int angle) const;
 
-    CrossingType Crossing(const VLayoutDetail &detail) const;
+    CrossingType Crossing(const VLayoutPiece &detail) const;
     bool         SheetContains(const QRectF &rect) const;
 
-    void CombineEdges(VLayoutDetail &detail, const QLineF &globalEdge, const int &dEdge);
-    void RotateEdges(VLayoutDetail &detail, const QLineF &globalEdge, int dEdge, int angle) const;
+    void CombineEdges(VLayoutPiece &detail, const QLineF &globalEdge, const int &dEdge);
+    void RotateEdges(VLayoutPiece &detail, const QLineF &globalEdge, int dEdge, int angle) const;
 
     static QPainterPath ShowDirection(const QLineF &edge);
     static QPainterPath DrawContour(const QVector<QPointF> &points);
-    static QPainterPath DrawDetails(const QVector<VLayoutDetail> &details);
+    static QPainterPath DrawDetails(const QVector<VLayoutPiece> &details);
 
     void Rotate(int increase);
 };
diff --git a/src/libs/vmisc/abstracttest.cpp b/src/libs/vmisc/abstracttest.cpp
index d22c3e696..74e5d79b9 100644
--- a/src/libs/vmisc/abstracttest.cpp
+++ b/src/libs/vmisc/abstracttest.cpp
@@ -67,7 +67,8 @@ void AbstractTest::Comparison(const QVector<QPointF> &ekv, const QVector<QPointF
     {
         const QPoint p1 = ekv.at(i).toPoint();
         const QPoint p2 = ekvOrig.at(i).toPoint();
-        const QString msg = QString("Got '%1;%2', Exprected '%3;%4'.").arg(p1.x(), p1.y()).arg(p2.x(), p2.y());
+        const QString msg = QString("Index: %1. Got '%2;%3', Expected '%4;%5'.")
+                .arg(i).arg(p1.x()).arg(p1.y()).arg(p2.x()).arg(p2.y());
         // Check each point. Don't use comparison float values
         QVERIFY2(p1 == p2, qUtf8Printable(msg));
     }
diff --git a/src/libs/vmisc/def.h b/src/libs/vmisc/def.h
index c23c9785a..15a5ef7aa 100644
--- a/src/libs/vmisc/def.h
+++ b/src/libs/vmisc/def.h
@@ -75,6 +75,24 @@ enum class Source : char { FromGui, FromFile, FromTool };
 enum class NodeUsage : bool {NotInUse = false, InUse = true};
 enum class SelectionType : bool {ByMousePress, ByMouseRelease};
 
+enum class PieceNodeAngle : unsigned char
+{
+    ByLength = 0,
+    ByPointsIntersection,
+    ByFirstEdgeSymmetry,
+    BySecondEdgeSymmetry,
+    ByFirstEdgeRightAngle,
+    BySecondEdgeRightAngle
+};
+
+enum class PiecePathIncludeType : unsigned char
+{
+    AsMainPath = 0,
+    AsCustomSA = 1
+};
+
+enum class PiecePathType :  unsigned char {PiecePath = 0, CustomSeamAllowance = 1, InternalPath = 2, Unknown = 3};
+
 typedef unsigned char ToolVisHolderType;
 enum class Tool : ToolVisHolderType
 {
@@ -102,7 +120,8 @@ enum class Tool : ToolVisHolderType
     CubicBezierPath,
     CutSplinePath,
     PointOfContact,
-    Detail,
+    Piece,
+    PiecePath,
     NodePoint,
     NodeArc,
     NodeElArc,
@@ -172,7 +191,9 @@ enum class Vis : ToolVisHolderType
     ToolFlippingByLine,
     ToolFlippingByAxis,
     ToolMove,
-    ToolEllipticalArc
+    ToolEllipticalArc,
+    ToolPiece,
+    ToolPiecePath
 };
 
 enum class VarType : char { Measurement, Increment, LineLength, CurveLength, CurveCLength, LineAngle, CurveAngle,
@@ -675,6 +696,29 @@ static inline bool VFuzzyComparePossibleNulls(double p1, double p2)
     }
 }
 
+/**
+ * @brief The CustomSA struct contains record about custom seam allowanse (SA).
+ */
+struct CustomSARecord
+{
+    CustomSARecord()
+        : startPoint(0),
+          path(0),
+          endPoint(0),
+          reverse(false),
+          includeType(PiecePathIncludeType::AsCustomSA)
+    {}
+
+    quint32 startPoint;
+    quint32 path;
+    quint32 endPoint;
+    bool reverse;
+    PiecePathIncludeType includeType;
+};
+
+Q_DECLARE_METATYPE(CustomSARecord)
+Q_DECLARE_TYPEINFO(CustomSARecord, Q_MOVABLE_TYPE);
+
 /****************************************************************************
 ** This file is derived from code bearing the following notice:
 ** The sole author of this file, Adam Higerd, has explicitly disclaimed all
diff --git a/src/libs/vmisc/vabstractapplication.cpp b/src/libs/vmisc/vabstractapplication.cpp
index 2a2774b72..d7d97cbae 100644
--- a/src/libs/vmisc/vabstractapplication.cpp
+++ b/src/libs/vmisc/vabstractapplication.cpp
@@ -290,12 +290,12 @@ VCommonSettings *VAbstractApplication::Settings()
 //---------------------------------------------------------------------------------------------------------------------
 QGraphicsScene *VAbstractApplication::getCurrentScene() const
 {
-    SCASSERT(currentScene != nullptr)
-    return currentScene;
+    SCASSERT(*currentScene != nullptr)
+    return *currentScene;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VAbstractApplication::setCurrentScene(QGraphicsScene *value)
+void VAbstractApplication::setCurrentScene(QGraphicsScene **value)
 {
     currentScene = value;
 }
diff --git a/src/libs/vmisc/vabstractapplication.h b/src/libs/vmisc/vabstractapplication.h
index cf13f287d..a00a980b4 100644
--- a/src/libs/vmisc/vabstractapplication.h
+++ b/src/libs/vmisc/vabstractapplication.h
@@ -88,7 +88,7 @@ public:
     QString          LocaleToString(const T &value);
 
     QGraphicsScene  *getCurrentScene() const;
-    void             setCurrentScene(QGraphicsScene *value);
+    void             setCurrentScene(QGraphicsScene **value);
 
     VMainGraphicsView *getSceneView() const;
     void               setSceneView(VMainGraphicsView *value);
@@ -137,7 +137,7 @@ private:
     MeasurementsType   _patternType;
 
 
-    QGraphicsScene     *currentScene;
+    QGraphicsScene     **currentScene;
     VMainGraphicsView  *sceneView;
 
     VAbstractPattern   *doc;
diff --git a/src/libs/vpatterndb/vcontainer.cpp b/src/libs/vpatterndb/vcontainer.cpp
index 12e070407..2034fbc3d 100644
--- a/src/libs/vpatterndb/vcontainer.cpp
+++ b/src/libs/vpatterndb/vcontainer.cpp
@@ -151,16 +151,24 @@ const val VContainer::GetObject(const QHash<key, val> &obj, key id) const
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief GetDetail return detail by id
- * @param id id of detail
- * @return detail
- */
-const VDetail VContainer::GetDetail(quint32 id) const
+VPiece VContainer::GetPiece(quint32 id) const
 {
-    if (d->details->contains(id))
+    if (d->pieces->contains(id))
     {
-        return d->details->value(id);
+        return d->pieces->value(id);
+    }
+    else
+    {
+        throw VExceptionBadId(tr("Can't find object"), id);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath VContainer::GetPiecePath(quint32 id) const
+{
+    if (d->piecePaths->contains(id))
+    {
+        return d->piecePaths->value(id);
     }
     else
     {
@@ -183,15 +191,18 @@ quint32 VContainer::AddGObject(VGObject *obj)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief AddDetail add new detail to container
- * @param detail new detail
- * @return return id of new detail in container
- */
-quint32 VContainer::AddDetail(const VDetail &detail)
+quint32 VContainer::AddPiece(const VPiece &detail)
 {
     const quint32 id = getNextId();
-    d->details->insert(id, detail);
+    d->pieces->insert(id, detail);
+    return id;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+quint32 VContainer::AddPiecePath(const VPiecePath &path)
+{
+    const quint32 id = getNextId();
+    d->piecePaths->insert(id, path);
     return id;
 }
 
@@ -262,7 +273,8 @@ void VContainer::Clear()
     qCDebug(vCon, "Clearing container data.");
     _id = NULL_ID;
 
-    d->details->clear();
+    d->pieces->clear();
+    d->piecePaths->clear();
     ClearVariables();
     ClearGObjects();
     ClearUniqueNames();
@@ -274,7 +286,8 @@ void VContainer::ClearForFullParse()
     qCDebug(vCon, "Clearing container data for full parse.");
     _id = NULL_ID;
 
-    d->details->clear();
+    d->pieces->clear();
+    d->piecePaths->clear();
     ClearVariables(VarType::Increment);
     ClearVariables(VarType::LineAngle);
     ClearVariables(VarType::LineLength);
@@ -473,6 +486,12 @@ void VContainer::RemoveVariable(const QString &name)
     d->variables.remove(name);
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+void VContainer::RemovePiece(quint32 id)
+{
+    d->pieces->remove(id);
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief AddObject add object to container
@@ -505,15 +524,18 @@ void VContainer::UpdateGObject(quint32 id, VGObject* obj)
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief UpdateDetail update detail by id
- * @param id id of existing detail
- * @param detail detail
- */
-void VContainer::UpdateDetail(quint32 id, const VDetail &detail)
+void VContainer::UpdatePiece(quint32 id, const VPiece &detail)
 {
     Q_ASSERT_X(id != NULL_ID, Q_FUNC_INFO, "id == 0"); //-V654 //-V712
-    d->details->insert(id, detail);
+    d->pieces->insert(id, detail);
+    UpdateId(id);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VContainer::UpdatePiecePath(quint32 id, const VPiecePath &path)
+{
+    Q_ASSERT_X(id != NULL_ID, Q_FUNC_INFO, "id == 0"); //-V654 //-V712
+    d->piecePaths->insert(id, path);
     UpdateId(id);
 }
 
@@ -666,13 +688,6 @@ const QMap<QString, QSharedPointer<T> > VContainer::DataVar(const VarType &type)
     return map;
 }
 
-//---------------------------------------------------------------------------------------------------------------------
-// cppcheck-suppress unusedFunction
-void VContainer::ClearDetails()
-{
-    d->details->clear();
-}
-
 //---------------------------------------------------------------------------------------------------------------------
 void VContainer::ClearUniqueNames()
 {
@@ -742,13 +757,9 @@ const QHash<quint32, QSharedPointer<VGObject> > *VContainer::DataGObjects() cons
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief data container with dataDetails return container of details
- * @return pointer on container of details
- */
-const QHash<quint32, VDetail> *VContainer::DataDetails() const
+const QHash<quint32, VPiece> *VContainer::DataPieces() const
 {
-    return d->details.data();
+    return d->pieces.data();
 }
 
 //---------------------------------------------------------------------------------------------------------------------
diff --git a/src/libs/vpatterndb/vcontainer.h b/src/libs/vpatterndb/vcontainer.h
index 845808ac1..562cc8330 100644
--- a/src/libs/vpatterndb/vcontainer.h
+++ b/src/libs/vpatterndb/vcontainer.h
@@ -53,7 +53,8 @@
 #include "../vmisc/diagnostic.h"
 #include "variables.h"
 #include "variables/vinternalvariable.h"
-#include "vdetail.h"
+#include "vpiece.h"
+#include "vpiecepath.h"
 #include "vtranslatevars.h"
 
 class VAbstractCubicBezierPath;
@@ -81,15 +82,18 @@ public:
     VContainerData(const VTranslateVars *trVars, const Unit *patternUnit)
         : gObjects(QHash<quint32, QSharedPointer<VGObject> >()),
           variables(QHash<QString, QSharedPointer<VInternalVariable> > ()),
-          details(QSharedPointer<QHash<quint32, VDetail>>(new QHash<quint32, VDetail>())),
-          trVars(trVars), patternUnit(patternUnit)
+          pieces(QSharedPointer<QHash<quint32, VPiece>>(new QHash<quint32, VPiece>())),
+          piecePaths(QSharedPointer<QHash<quint32, VPiecePath>>(new QHash<quint32, VPiecePath>())),
+          trVars(trVars),
+          patternUnit(patternUnit)
     {}
 
     VContainerData(const VContainerData &data)
         : QSharedData(data),
           gObjects(data.gObjects),
           variables(data.variables),
-          details(data.details),
+          pieces(data.pieces),
+          piecePaths(data.piecePaths),
           trVars(data.trVars),
           patternUnit(data.patternUnit)
     {}
@@ -105,10 +109,9 @@ public:
      * @brief variables container for measurements, increments, lines lengths, lines angles, arcs lengths, curve lengths
      */
     QHash<QString, QSharedPointer<VInternalVariable>> variables;
-    /**
-     * @brief details container of details
-     */
-    QSharedPointer<QHash<quint32, VDetail>> details;
+
+    QSharedPointer<QHash<quint32, VPiece>> pieces;
+    QSharedPointer<QHash<quint32, VPiecePath>> piecePaths;
 
     const VTranslateVars *trVars;
     const Unit *patternUnit;
@@ -135,7 +138,8 @@ public:
     const QSharedPointer<T> GeometricObject(const quint32 &id) const;
     const QSharedPointer<VGObject> GetGObject(quint32 id) const;
     static const QSharedPointer<VGObject> GetFakeGObject(quint32 id);
-    const VDetail      GetDetail(quint32 id) const;
+    VPiece             GetPiece(quint32 id) const;
+    VPiecePath         GetPiecePath(quint32 id) const;
     qreal              GetTableValue(const QString& name, MeasurementsType patternType) const;
     template <typename T>
     QSharedPointer<T>  GetVariable(QString name) const;
@@ -144,7 +148,8 @@ public:
     static void        UpdateId(quint32 newId);
 
     quint32            AddGObject(VGObject *obj);
-    quint32            AddDetail(const VDetail &detail);
+    quint32            AddPiece(const VPiece &detail);
+    quint32            AddPiecePath(const VPiecePath &path);
     void               AddLine(const quint32 &firstPointId, const quint32 &secondPointId);
     void               AddArc(const QSharedPointer<VAbstractCurve> &arc, const quint32 &arcId,
                               const quint32 &parentId = NULL_ID);
@@ -155,16 +160,17 @@ public:
     template <typename T>
     void               AddVariable(const QString& name, T *var);
     void               RemoveVariable(const QString& name);
+    void               RemovePiece(quint32 id);
 
     void               UpdateGObject(quint32 id, VGObject* obj);
-    void               UpdateDetail(quint32 id, const VDetail &detail);
+    void               UpdatePiece(quint32 id, const VPiece &detail);
+    void               UpdatePiecePath(quint32 id, const VPiecePath &path);
 
     void               Clear();
     void               ClearForFullParse();
     void               ClearGObjects();
     void               ClearCalculationGObjects();
     void               ClearVariables(const VarType &type = VarType::Unknown);
-    void               ClearDetails();
     static void        ClearUniqueNames();
 
     static void        SetSize(qreal size);
@@ -179,7 +185,7 @@ public:
     void               RemoveIncrement(const QString& name);
 
     const QHash<quint32, QSharedPointer<VGObject> >         *DataGObjects() const;
-    const QHash<quint32, VDetail>                           *DataDetails() const;
+    const QHash<quint32, VPiece>                            *DataPieces() const;
     const QHash<QString, QSharedPointer<VInternalVariable>> *DataVariables() const;
 
     const QMap<QString, QSharedPointer<VMeasurement> >  DataMeasurements() const;
@@ -240,9 +246,9 @@ template <typename T>
 const QSharedPointer<T> VContainer::GeometricObject(const quint32 &id) const
 {
     QSharedPointer<VGObject> gObj = QSharedPointer<VGObject>();
-   if (d->gObjects.contains(id))
-   {
-       gObj = d->gObjects.value(id);
+    if (d->gObjects.contains(id))
+    {
+        gObj = d->gObjects.value(id);
     }
     else
     {
@@ -253,11 +259,11 @@ const QSharedPointer<T> VContainer::GeometricObject(const quint32 &id) const
         QSharedPointer<T> obj = qSharedPointerDynamicCast<T>(gObj);
         SCASSERT(obj.isNull() == false)
         return obj;
-     }
-     catch (const std::bad_alloc &)
-     {
+    }
+    catch (const std::bad_alloc &)
+    {
         throw VExceptionBadId(tr("Can't cast object"), id);
-     }
+    }
 }
 
 
diff --git a/src/libs/vpatterndb/vdetail.cpp b/src/libs/vpatterndb/vdetail.cpp
deleted file mode 100644
index 230b4f3a0..000000000
--- a/src/libs/vpatterndb/vdetail.cpp
+++ /dev/null
@@ -1,814 +0,0 @@
-/************************************************************************
- **
- **  @file   vdetail.cpp
- **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   November 15, 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
- **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
- **
- *************************************************************************/
-
-#include "vdetail.h"
-
-#include <QList>
-#include <QMessageLogger>
-#include <QPainterPath>
-#include <QSet>
-#include <QSharedPointer>
-#include <QString>
-#include <Qt>
-#include <QtDebug>
-#include <new>
-
-#include "../vmisc/def.h"
-#include "../vgeometry/vabstractcurve.h"
-#include "../vgeometry/vgobject.h"
-#include "../vgeometry/vpointf.h"
-#include "../vlayout/vlayoutdef.h"
-#include "vcontainer.h"
-#include "vdetail_p.h"
-#include "vnodedetail.h"
-#include "vpatternpiecedata.h"
-#include "vgrainlinegeometry.h"
-
-class QPointF;
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VDetail default contructor. Create empty detail.
- */
-VDetail::VDetail()
-    :VAbstractDetail(), d(new VDetailData)
-{}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VDetail constructor.
- * @param name detail name.
- * @param nodes list of nodes.
- */
-VDetail::VDetail(const QString &name, const QVector<VNodeDetail> &nodes)
-    :VAbstractDetail(name), d(new VDetailData(nodes))
-{}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VDetail copy constructor.
- * @param detail detail.
- */
-VDetail::VDetail(const VDetail &detail)
-    :VAbstractDetail(detail), d (detail.d)
-{}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief operator = assignment operator.
- * @param detail detail.
- * @return new detail.
- */
-VDetail &VDetail::operator =(const VDetail &detail)
-{
-    if ( &detail == this )
-    {
-        return *this;
-    }
-    VAbstractDetail::operator=(detail);
-    d = detail.d;
-    return *this;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-VDetail::~VDetail()
-{}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief Clear detail full clear.
- */
-void VDetail::Clear()
-{
-    d->nodes.clear();
-    d->mx = 0;
-    d->my = 0;
-    GetPatternPieceData().Clear();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief ClearNodes clear list of nodes.
- */
-void VDetail::ClearNodes()
-{
-    d->nodes.clear();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief Containes check if detail containe this id.
- * @param id object id.
- * @return true if containe.
- */
-bool VDetail::Containes(const quint32 &id) const
-{
-    for (int i = 0; i < d->nodes.size(); ++i)
-    {
-        VNodeDetail node = d->nodes.at(i);
-        if (node.getId() == id)
-        {
-            return true;
-        }
-    }
-    return false;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief operator [] find node by index in list.
- * @param indx index node in list.
- * @return node
- */
-VNodeDetail &VDetail::operator [](int indx)
-{
-    return d->nodes[indx];
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief at find node by index in list.
- * @param indx index node in list.
- * @return const node.
- */
-const VNodeDetail &VDetail::at(int indx) const
-{
-    return d->nodes.at(indx);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief indexOfNode return index in list node using id object.
- * @param id object (arc, point, spline, splinePath) id.
- * @return index in list or -1 id can't find.
- */
-int VDetail::indexOfNode(const quint32 &id) const
-{
-    return indexOfNode(d->nodes, id);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief id return id detail in list data.
- * @return id.
- */
-quint32 VDetail::id() const
-{
-    return d->_id;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief setId set id detail in list data.
- * @param id detail id.
- */
-void VDetail::setId(const quint32 &id)
-{
-    d->_id = id;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-bool VDetail::IsInLayout() const
-{
-    return d->inLayout;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VDetail::SetInLayout(bool inLayout)
-{
-    d->inLayout = inLayout;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief OnEdge checks if two poins located on the edge. Edge is line between two points. If between two points
- * located arcs or splines ignore this.
- * @param p1 id first point.
- * @param p2 id second point.
- * @return true - on edge, false - no.
- */
-bool VDetail::OnEdge(const quint32 &p1, const quint32 &p2) const
-{
-    QVector<VNodeDetail> list = listNodePoint();
-    if (list.size() < 2)
-    {
-        qDebug()<<"Not enough points.";
-        return false;
-    }
-    int i = indexOfNode(list, p1);
-    int j1 = 0, j2 = 0;
-
-    if (i == list.size() - 1)
-    {
-        j1 = i-1;
-        j2 = 0;
-    }
-    else if (i == 0)
-    {
-        j1 = list.size() - 1;
-        j2 = i + 1;
-    }
-    else
-    {
-        j1 = i - 1;
-        j2 = i + 1;
-    }
-
-    if (list.at(j1).getId() == p2 || list.at(j2).getId() == p2)
-    {
-        return true;
-    }
-    else
-    {
-        return false;
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief Edge return edge index in detail. Edge is line between two points. If between two points
- * located arcs or splines ignore this.
- * @param p1 id first point.
- * @param p2 id second point.
- * @return edge index or -1 if points don't located on edge
- */
-int VDetail::Edge(const quint32 &p1, const quint32 &p2) const
-{
-    if (OnEdge(p1, p2) == false)
-    {
-        qDebug()<<"Points don't on edge.";
-        return -1;
-    }
-
-    QVector<VNodeDetail> list = listNodePoint();
-    int i = indexOfNode(list, p1);
-    int j = indexOfNode(list, p2);
-
-    int min = qMin(i, j);
-
-    if (min == 0 && (i == list.size() - 1 || j == list.size() - 1))
-    {
-        return list.size() - 1;
-    }
-    else
-    {
-        return min;
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief NodeOnEdge return nodes located on edge with index.
- * @param index index of edge.
- * @param p1 first node.
- * @param p2 second node.
- */
-void VDetail::NodeOnEdge(const quint32 &index, VNodeDetail &p1, VNodeDetail &p2) const
-{
-    QVector<VNodeDetail> list = listNodePoint();
-    if (index > static_cast<quint32>(list.size()))
-    {
-        qDebug()<<"Wrong edge index index ="<<index;
-        return;
-    }
-    p1 = list.at(static_cast<int>(index));
-    if (index + 1 > static_cast<quint32>(list.size()) - 1)
-    {
-        p2 = list.at(0);
-    }
-    else
-    {
-        p2 = list.at(static_cast<int>(index+1));
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief RemoveEdge return detail without edge with index.
- * @param index idex of edge.
- * @return detail without edge with index.
- */
-VDetail VDetail::RemoveEdge(const quint32 &index) const
-{
-    VDetail det(*this);
-    det.ClearNodes();
-
-    // Edge can be only segment. We ignore all curves inside segments.
-    const quint32 edges = static_cast<quint32>(listNodePoint().size());
-    quint32 k = 0;
-    for (quint32 i=0; i<edges; ++i)
-    {
-        if (i == index)
-        {
-            det.append(this->at(static_cast<int>(k)));
-            ++k;
-        }
-        else
-        {
-            VNodeDetail p1;
-            VNodeDetail p2;
-            this->NodeOnEdge(i, p1, p2);
-            const int j1 = this->indexOfNode(p1.getId());
-            int j2 = this->indexOfNode(p2.getId());
-            if (j2 == 0)
-            {
-                j2 = this->CountNode();
-            }
-            for (int j=j1; j<j2; ++j)
-            {// Add "segment" except last point. Inside can be curves too.
-                det.append(this->at(j));
-                ++k;
-            }
-        }
-    }
-    return det;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief Missing find missing nodes in detail. When we deleted object in detail and return this detail need
- * understand, what nodes need make invisible.
- * @param det changed detail.
- * @return  list with missing nodes.
- */
-QVector<VNodeDetail> VDetail::Missing(const VDetail &det) const
-{
-    if (d->nodes.size() == det.CountNode()) //-V807
-    {
-        return QVector<VNodeDetail>();
-    }
-
-    QSet<quint32> set1;
-    for (qint32 i = 0; i < d->nodes.size(); ++i)
-    {
-        set1.insert(d->nodes.at(i).getId());
-    }
-
-    QSet<quint32> set2;
-    for (qint32 j = 0; j < det.CountNode(); ++j)
-    {
-        set2.insert(det.at(j).getId());
-    }
-
-    const QList<quint32> set3 = set1.subtract(set2).toList();
-    QVector<VNodeDetail> nodes;
-    for (qint32 i = 0; i < set3.size(); ++i)
-    {
-        const int index = indexOfNode(d->nodes, set3.at(i));
-        if (index != -1)
-        {
-            nodes.append(d->nodes.at(index));
-        }
-    }
-
-    return nodes;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> VDetail::ContourPoints(const VContainer *data) const
-{
-    QVector<QPointF> points;
-    for (int i = 0; i< CountNode(); ++i)
-    {
-        switch (at(i).getTypeTool())
-        {
-            case (Tool::NodePoint):
-            {
-                const QSharedPointer<VPointF> point = data->GeometricObject<VPointF>(at(i).getId());
-                points.append(*point);
-            }
-            break;
-            case (Tool::NodeArc):
-            case (Tool::NodeElArc):
-            case (Tool::NodeSpline):
-            case (Tool::NodeSplinePath):
-            {
-                const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(at(i).getId());
-
-                const QPointF begin = StartSegment(data, i, at(i).getReverse());
-                const QPointF end = EndSegment(data, i, at(i).getReverse());
-
-                points << curve->GetSegmentPoints(begin, end, at(i).getReverse());
-            }
-            break;
-            default:
-                qDebug()<<"Get wrong tool type. Ignore."<< static_cast<char>(at(i).getTypeTool());
-                break;
-        }
-    }
-
-    points = CheckLoops(CorrectEquidistantPoints(points));//A path can contains loops
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> VDetail::SeamAllowancePoints(const VContainer *data) const
-{
-    QVector<QPointF> pointsEkv;
-    if (getSeamAllowance() == false)
-    {
-        return pointsEkv;
-    }
-
-    for (int i = 0; i< CountNode(); ++i)
-    {
-        switch (at(i).getTypeTool())
-        {
-            case (Tool::NodePoint):
-            {
-                const QSharedPointer<VPointF> point = data->GeometricObject<VPointF>(at(i).getId());
-                QPointF pEkv = *point;
-                pEkv.setX(pEkv.x()+at(i).getMx());
-                pEkv.setY(pEkv.y()+at(i).getMy());
-                pointsEkv.append(pEkv);
-            }
-            break;
-            case (Tool::NodeArc):
-            case (Tool::NodeElArc):
-            case (Tool::NodeSpline):
-            case (Tool::NodeSplinePath):
-            {
-                const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(at(i).getId());
-
-                const QPointF begin = StartSegment(data, i, at(i).getReverse());
-                const QPointF end = EndSegment(data, i, at(i).getReverse());
-
-                const QVector<QPointF> nodePoints = curve->GetSegmentPoints(begin, end, at(i).getReverse());
-                pointsEkv << biasPoints(nodePoints, at(i).getMx(), at(i).getMy());
-            }
-            break;
-            default:
-                qDebug()<<"Get wrong tool type. Ignore."<< static_cast<char>(at(i).getTypeTool());
-                break;
-        }
-    }
-
-    pointsEkv = CheckLoops(CorrectEquidistantPoints(pointsEkv));//A path can contains loops
-
-    if (getClosed() == true)
-    {
-        pointsEkv = Equidistant(pointsEkv, EquidistantType::CloseEquidistant, ToPixel(getWidth(),
-                                                                                      *data->GetPatternUnit()));
-    }
-    else
-    {
-        pointsEkv = Equidistant(pointsEkv, EquidistantType::OpenEquidistant, ToPixel(getWidth(),
-                                                                                     *data->GetPatternUnit()));
-    }
-    return pointsEkv;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QPainterPath VDetail::ContourPath(const VContainer *data) const
-{
-    const QVector<QPointF> points = ContourPoints(data);
-    QPainterPath path;
-
-    // contour
-    path.moveTo(points[0]);
-    for (qint32 i = 1; i < points.count(); ++i)
-    {
-        path.lineTo(points.at(i));
-    }
-    path.lineTo(points.at(0));
-    path.setFillRule(Qt::WindingFill);
-
-    return path;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QPainterPath VDetail::SeamAllowancePath(const VContainer *data) const
-{
-    const QVector<QPointF> pointsEkv = SeamAllowancePoints(data);
-    QPainterPath ekv;
-
-    // seam allowance
-    if (getSeamAllowance())
-    {
-        if (not pointsEkv.isEmpty())
-        {
-            ekv.moveTo(pointsEkv.at(0));
-            for (qint32 i = 1; i < pointsEkv.count(); ++i)
-            {
-                ekv.lineTo(pointsEkv.at(i));
-            }
-
-            ekv.setFillRule(Qt::WindingFill);
-        }
-    }
-
-    return ekv;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief listNodePoint return list nodes only with points.
- * @return list points node.
- */
-QVector<VNodeDetail> VDetail::listNodePoint() const
-{
-    QVector<VNodeDetail> list;
-    for (int i = 0; i < d->nodes.size(); ++i) //-V807
-    {
-        if (d->nodes.at(i).getTypeTool() == Tool::NodePoint)
-        {
-            list.append(d->nodes.at(i));
-        }
-    }
-    return list;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VDetail::SetPatternPieceData(const VPatternPieceData &data)
-{
-    d->m_ppData = data;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief Returns full access to the pattern piece data object
- * @return pattern piece data object
- */
-VPatternPieceData& VDetail::GetPatternPieceData()
-{
-    return d->m_ppData;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief Returns the read only reference to the pattern piece data object
- * @return pattern piece data object
- */
-const VPatternPieceData& VDetail::GetPatternPieceData() const
-{
-    return d->m_ppData;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VDetail::SetPatternInfo(const VPatternInfoGeometry &info)
-{
-    d->m_piPatternInfo = info;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief Returns full access to the pattern info geometry object
- * @return pattern info geometry object
- */
-VPatternInfoGeometry& VDetail::GetPatternInfo()
-{
-    return d->m_piPatternInfo;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief Returns the read only reference to the pattern info geometry object
- * @return pattern info geometry object
- */
-const VPatternInfoGeometry& VDetail::GetPatternInfo() const
-{
-    return d->m_piPatternInfo;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-
-/**
- * @brief VDetail::GetGrainlineGeometry full access to the grainline geometry object
- * @return reference to grainline geometry object
- */
-VGrainlineGeometry& VDetail::GetGrainlineGeometry()
-{
-    return d->m_glGrainline;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-
-/**
- * @brief VDetail::GetGrainlineGeometry returns the read-only reference to the grainline geometry object
- * @return reference to grainline geometry object
- */
-const VGrainlineGeometry& VDetail::GetGrainlineGeometry() const
-{
-    return d->m_glGrainline;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief indexOfNode return index in list node using id object.
- * @param list list nodes detail.
- * @param id object (arc, point, spline, splinePath) id.
- * @return index in list or -1 id can't find.
- */
-int VDetail::indexOfNode(const QVector<VNodeDetail> &list, const quint32 &id)
-{
-    for (int i = 0; i < list.size(); ++i)
-    {
-        if (list.at(i).getId() == id)
-        {
-            return i;
-        }
-    }
-    qDebug()<<"Can't find node.";
-    return -1;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QPointF VDetail::StartSegment(const VContainer *data, const int &i, bool reverse) const
-{
-    if (i < 0 && i > CountNode()-1)
-    {
-        return QPointF();
-    }
-
-    const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(at(i).getId());
-
-    QVector<QPointF> points = curve->GetPoints();
-    if (reverse)
-    {
-        points = VGObject::GetReversePoints(points);
-    }
-
-    QPointF begin = points.first();
-    if (CountNode() > 1)
-    {
-        if (i == 0)
-        {
-            if (at(CountNode()-1).getTypeTool() == Tool::NodePoint)
-            {
-                begin = *data->GeometricObject<VPointF>(at(CountNode()-1).getId());
-            }
-        }
-        else
-        {
-            if (at(i-1).getTypeTool() == Tool::NodePoint)
-            {
-                begin = *data->GeometricObject<VPointF>(at(i-1).getId());
-            }
-        }
-    }
-    return begin;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QPointF VDetail::EndSegment(const VContainer *data, const int &i, bool reverse) const
-{
-    if (i < 0 && i > CountNode()-1)
-    {
-        return QPointF();
-    }
-
-    const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(at(i).getId());
-
-    QVector<QPointF> points = curve->GetPoints();
-    if (reverse)
-    {
-        points = VGObject::GetReversePoints(points);
-    }
-
-    QPointF end = points.last();
-    if (CountNode() > 2)
-    {
-        if (i == CountNode() - 1)
-        {
-            if (at(0).getTypeTool() == Tool::NodePoint)
-            {
-                end = *data->GeometricObject<VPointF>(at(0).getId());
-            }
-        }
-        else
-        {
-            if (at(i+1).getTypeTool() == Tool::NodePoint)
-            {
-                end = *data->GeometricObject<VPointF>(at(i+1).getId());
-            }
-        }
-    }
-    return end;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief biasPoints bias point.
- * @param points vector of points.
- * @param mx offset respect to x.
- * @param my offset respect to y.
- * @return new vector biased points.
- */
-QVector<QPointF> VDetail::biasPoints(const QVector<QPointF> &points, const qreal &mx, const qreal &my)
-{
-    QVector<QPointF> p;
-    for (qint32 i = 0; i < points.size(); ++i)
-    {
-        QPointF point = points.at(i);
-        point.setX(point.x() + mx);
-        point.setY(point.y() + my);
-        p.append(point);
-    }
-    return p;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief append append in the end of list node.
- * @param node new node.
- */
-void VDetail::append(const VNodeDetail &node)
-{
-    d->nodes.append(node);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief CountNode return count nodes.
- * @return count.
- */
-qint32 VDetail::CountNode() const
-{
-    return d->nodes.size();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief getMx return bias for X axis.
- * @return x bias.
- */
-qreal VDetail::getMx() const
-{
-    return d->mx;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief setMx set bias for X axis.
- * @param value new x bias.
- */
-void VDetail::setMx(const qreal &value)
-{
-    d->mx = value;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief getMy get bias for y axis.
- * @return y axis.
- */
-qreal VDetail::getMy() const
-{
-    return d->my;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief setMy set bias for y axis.
- * @param value new y bias.
- */
-void VDetail::setMy(const qreal &value)
-{
-    d->my = value;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief getNodes return list of nodes.
- * @return list of nodes.
- */
-QVector<VNodeDetail> VDetail::getNodes() const
-{
-    return d->nodes;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief setNodes set list of nodes
- * @param value list of nodes
- */
-// cppcheck-suppress unusedFunction
-void VDetail::setNodes(const QVector<VNodeDetail> &value)
-{
-    d->nodes = value;
-}
diff --git a/src/libs/vpatterndb/vdetail.h b/src/libs/vpatterndb/vdetail.h
deleted file mode 100644
index 54eb0c958..000000000
--- a/src/libs/vpatterndb/vdetail.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/************************************************************************
- **
- **  @file   vdetail.h
- **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   November 15, 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
- **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
- **
- *************************************************************************/
-
-#ifndef VDETAIL_H
-#define VDETAIL_H
-
-#include <qcompilerdetection.h>
-#include <QPointF>
-#include <QSharedDataPointer>
-#include <QString>
-#include <QTypeInfo>
-#include <QVector>
-#include <QtGlobal>
-
-#include "../vlayout/vabstractdetail.h"
-#include "vnodedetail.h"
-
-class QPainterPath;
-class QPointF;
-class VContainer;
-class VDetailData;
-class VNodeDetail;
-class VPatternInfoGeometry;
-class VPatternPieceData;
-class VGrainlineGeometry;
-
-/**
- * @brief The VDetail class for path of object (points, arcs, splines).
- */
-class VDetail :public VAbstractDetail
-{
-public:
-    VDetail();
-    VDetail(const QString &name, const QVector<VNodeDetail> &nodes);
-    VDetail(const VDetail &detail);
-    VDetail &operator=(const VDetail &detail);
-    virtual ~VDetail() Q_DECL_OVERRIDE;
-
-    void           append(const VNodeDetail &node);
-    void           Clear();
-    void           ClearNodes();
-    qint32         CountNode() const;
-    bool           Containes(const quint32 &id)const;
-    VNodeDetail &  operator[](int indx);
-    const VNodeDetail & at ( int indx ) const;
-
-    qreal getMx() const;
-    void  setMx(const qreal &value);
-
-    qreal getMy() const;
-    void  setMy(const qreal &value);
-
-    quint32 id() const;
-    void    setId(const quint32 &id);
-
-    bool IsInLayout() const;
-    void SetInLayout(bool inLayout);
-
-    QVector<VNodeDetail> getNodes() const;
-    void setNodes(const QVector<VNodeDetail> &value);
-
-    int  indexOfNode(const quint32 &id) const;
-    bool OnEdge(const quint32 &p1, const quint32 &p2)const;
-    int  Edge(const quint32 &p1, const quint32 &p2)const;
-    void NodeOnEdge(const quint32 &index, VNodeDetail &p1, VNodeDetail &p2)const;
-    VDetail RemoveEdge(const quint32 &index) const;
-
-    QVector<VNodeDetail> Missing(const VDetail &det) const;
-
-    QVector<QPointF> ContourPoints(const VContainer *data) const;
-    QVector<QPointF> SeamAllowancePoints(const VContainer *data) const;
-
-    QPainterPath ContourPath(const VContainer *data) const;
-    QPainterPath SeamAllowancePath(const VContainer *data) const;
-    QVector<VNodeDetail> listNodePoint()const;
-
-    void                     SetPatternPieceData(const VPatternPieceData &data);
-    VPatternPieceData&       GetPatternPieceData();
-    const VPatternPieceData& GetPatternPieceData() const;
-
-    void                        SetPatternInfo(const VPatternInfoGeometry &info);
-    VPatternInfoGeometry&       GetPatternInfo();
-    const VPatternInfoGeometry& GetPatternInfo() const;
-    VGrainlineGeometry& GetGrainlineGeometry();
-    const VGrainlineGeometry& GetGrainlineGeometry() const;
-
-private:
-    QSharedDataPointer<VDetailData> d;
-
-    static int indexOfNode(const QVector<VNodeDetail> &list, const quint32 &id);
-
-    QPointF StartSegment(const VContainer *data, const int &i, bool reverse) const;
-    QPointF EndSegment(const VContainer *data, const int &i, bool reverse) const;
-
-    static QVector<QPointF> biasPoints(const QVector<QPointF> &points, const qreal &mx, const qreal &my);
-};
-
-Q_DECLARE_TYPEINFO(VDetail, Q_MOVABLE_TYPE);
-
-#endif // VDETAIL_H
diff --git a/src/libs/vpatterndb/vnodedetail.cpp b/src/libs/vpatterndb/vnodedetail.cpp
index decba2343..489c2a257 100644
--- a/src/libs/vpatterndb/vnodedetail.cpp
+++ b/src/libs/vpatterndb/vnodedetail.cpp
@@ -28,6 +28,73 @@
 
 #include "vnodedetail.h"
 #include "vnodedetail_p.h"
+#include "vpiecenode.h"
+#include "vpiecepath.h"
+#include "../vgeometry/vpointf.h"
+#include "../vpatterndb/vcontainer.h"
+
+#include <QLineF>
+#include <QVector>
+
+namespace
+{
+//---------------------------------------------------------------------------------------------------------------------
+bool IsOX(const QLineF &line)
+{
+    return VFuzzyComparePossibleNulls(line.angle(), 0)
+            || VFuzzyComparePossibleNulls(line.angle(), 360)
+            || VFuzzyComparePossibleNulls(line.angle(), 180);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool IsOY(const QLineF &line)
+{
+    return VFuzzyComparePossibleNulls(line.angle(), 90) || VFuzzyComparePossibleNulls(line.angle(), 270);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString LocalWidth(const QLineF &line, const QLineF &movedLine)
+{
+    if (VFuzzyComparePossibleNulls(line.angle(), movedLine.angle()))
+    {
+        return QString().setNum(movedLine.length());
+    }
+    else
+    {// different direction means value is negative
+        return QString("0");
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void ConvertBefore(VPieceNode &node, const QLineF &line, qreal mX, qreal mY)
+{
+    if (not qFuzzyIsNull(mX) && IsOX(line))
+    {
+        const QLineF movedLine(line.p1().x(), line.p1().y(), line.p2().x() + mX, line.p2().y());
+        node.SetFormulaSABefore(LocalWidth(line, movedLine));
+    }
+    else if (not qFuzzyIsNull(mY) && IsOY(line))
+    {
+        const QLineF movedLine(line.p1().x(), line.p1().y(), line.p2().x(), line.p2().y() + mY);
+        node.SetFormulaSABefore(LocalWidth(line, movedLine));
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void ConvertAfter(VPieceNode &node, const QLineF &line, qreal mX, qreal mY)
+{
+    if (not qFuzzyIsNull(mX) && IsOX(line))
+    {
+        const QLineF movedLine(line.p1().x(), line.p1().y(), line.p2().x() + mX, line.p2().y());
+        node.SetFormulaSAAfter(LocalWidth(line, movedLine));
+    }
+    else if (not qFuzzyIsNull(mY) && IsOY(line))
+    {
+        const QLineF movedLine(line.p1().x(), line.p1().y(), line.p2().x(), line.p2().y() + mY);
+        node.SetFormulaSAAfter(LocalWidth(line, movedLine));
+    }
+}
+}//static functions
 
 //---------------------------------------------------------------------------------------------------------------------
 VNodeDetail::VNodeDetail()
@@ -146,3 +213,58 @@ void VNodeDetail::setReverse(bool reverse)
         d->reverse = reverse;
     }
 }
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VPieceNode> VNodeDetail::Convert(const VContainer *data, const QVector<VNodeDetail> &nodes, qreal width,
+                                         bool closed)
+{
+    if (width < 0)
+    {
+        width = 0;
+    }
+
+    VPiecePath path;
+    for (int i = 0; i < nodes.size(); ++i)
+    {
+        const VNodeDetail &node = nodes.at(i);
+        path.Append(VPieceNode(node.getId(), node.getTypeTool(), node.getReverse()));
+    }
+
+    if (path.PathPoints(data).size() > 2)
+    {
+        for (int i = 0; i < nodes.size(); ++i)
+        {
+            const VNodeDetail &node = nodes.at(i);
+            if (node.getTypeTool() == Tool::NodePoint)
+            {
+                if (not qFuzzyIsNull(node.getMx()) || not qFuzzyIsNull(node.getMy()))
+                {
+                    const QPointF previosPoint = path.NodePreviousPoint(data, i);
+                    const QPointF nextPoint = path.NodeNextPoint(data, i);
+
+                    const QPointF point = data->GeometricObject<VPointF>(node.getId())->toQPointF();
+
+                    QLineF lineBefore(point, previosPoint);
+                    lineBefore.setAngle(lineBefore.angle()-90);
+                    lineBefore.setLength(width);
+
+                    ConvertBefore(path[i], lineBefore, node.getMx(), node.getMy());
+
+                    QLineF lineAfter(point, nextPoint);
+                    lineAfter.setAngle(lineAfter.angle()+90);
+                    lineAfter.setLength(width);
+
+                    ConvertAfter(path[i], lineAfter, node.getMx(), node.getMy());
+                }
+            }
+        }
+    }
+
+    if (not closed && path.CountNodes() > 1)
+    {
+        path[0].SetFormulaSABefore("0");
+        path[path.CountNodes()-1].SetFormulaSAAfter("0");
+    }
+
+    return path.GetNodes();
+}
diff --git a/src/libs/vpatterndb/vnodedetail.h b/src/libs/vpatterndb/vnodedetail.h
index d1c5ac152..a26056923 100644
--- a/src/libs/vpatterndb/vnodedetail.h
+++ b/src/libs/vpatterndb/vnodedetail.h
@@ -37,6 +37,8 @@
 #include "../vmisc/def.h"
 
 class VNodeDetailData;
+class VPieceNode;
+class VContainer;
 
 /**
  * @brief The VNodeDetail class keep information about detail node.
@@ -122,6 +124,9 @@ public:
 
     bool        getReverse() const;
     void        setReverse(bool reverse);
+
+    static QVector<VPieceNode> Convert(const VContainer *data, const QVector<VNodeDetail> &nodes, qreal width,
+                                       bool closed);
 private:
     QSharedDataPointer<VNodeDetailData> d;
 };
diff --git a/src/libs/vpatterndb/vpatterndb.pri b/src/libs/vpatterndb/vpatterndb.pri
index ead57870f..5a94d2ff8 100644
--- a/src/libs/vpatterndb/vpatterndb.pri
+++ b/src/libs/vpatterndb/vpatterndb.pri
@@ -1,62 +1,68 @@
-# ADD TO EACH PATH $$PWD VARIABLE!!!!!!
-# This need for corect working file translations.pro
-
-SOURCES += \
-    $$PWD/vcontainer.cpp \
-    $$PWD/calculator.cpp \
-    $$PWD/vdetail.cpp \
-    $$PWD/vnodedetail.cpp \
-    $$PWD/vtranslatevars.cpp \
-    $$PWD/variables/varcradius.cpp \
-    $$PWD/variables/vcurveangle.cpp \
-    $$PWD/variables/vcurvelength.cpp \
-    $$PWD/variables/vcurvevariable.cpp \
-    $$PWD/variables/vincrement.cpp \
-    $$PWD/variables/vinternalvariable.cpp \
-    $$PWD/variables/vlineangle.cpp \
-    $$PWD/variables/vlinelength.cpp \
-    $$PWD/variables/vmeasurement.cpp \
-    $$PWD/variables/vvariable.cpp \
-    $$PWD/vformula.cpp \
-    $$PWD/vpatternpiecedata.cpp \
-    $$PWD/vpatterninfogeometry.cpp \
-    $$PWD/vgrainlinegeometry.cpp \
-    $$PWD/variables/vcurveclength.cpp \
-    $$PWD/variables/vellipticalarcradius.cpp
-
-win32-msvc*:SOURCES += $$PWD/stable.cpp
-
-HEADERS += \
-    $$PWD/vcontainer.h \
-    $$PWD/stable.h \
-    $$PWD/calculator.h \
-    $$PWD/variables.h \
-    $$PWD/vdetail.h \
-    $$PWD/vdetail_p.h \
-    $$PWD/vnodedetail.h \
-    $$PWD/vnodedetail_p.h \
-    $$PWD/vtranslatevars.h \
-    $$PWD/variables/varcradius.h \
-    $$PWD/variables/varcradius_p.h \
-    $$PWD/variables/vcurveangle.h \
-    $$PWD/variables/vcurvelength.h \
-    $$PWD/variables/vcurvevariable.h \
-    $$PWD/variables/vcurvevariable_p.h \
-    $$PWD/variables/vincrement.h \
-    $$PWD/variables/vincrement_p.h \
-    $$PWD/variables/vinternalvariable.h \
-    $$PWD/variables/vinternalvariable_p.h \
-    $$PWD/variables/vlineangle.h \
-    $$PWD/variables/vlineangle_p.h \
-    $$PWD/variables/vlinelength.h \
-    $$PWD/variables/vlinelength_p.h \
-    $$PWD/variables/vmeasurement.h \
-    $$PWD/variables/vmeasurement_p.h \
-    $$PWD/variables/vvariable.h \
-    $$PWD/variables/vvariable_p.h \
-    $$PWD/vformula.h \
-    $$PWD/vpatternpiecedata.h \
-    $$PWD/vpatterninfogeometry.h \
-    $$PWD/vgrainlinegeometry.h \
-    $$PWD/variables/vcurveclength.h \
-    $$PWD/variables/vellipticalarcradius.h
+# ADD TO EACH PATH $$PWD VARIABLE!!!!!!
+# This need for corect working file translations.pro
+
+SOURCES += \
+    $$PWD/vcontainer.cpp \
+    $$PWD/calculator.cpp \
+    $$PWD/vnodedetail.cpp \
+    $$PWD/vtranslatevars.cpp \
+    $$PWD/variables/varcradius.cpp \
+    $$PWD/variables/vcurveangle.cpp \
+    $$PWD/variables/vcurvelength.cpp \
+    $$PWD/variables/vcurvevariable.cpp \
+    $$PWD/variables/vincrement.cpp \
+    $$PWD/variables/vinternalvariable.cpp \
+    $$PWD/variables/vlineangle.cpp \
+    $$PWD/variables/vlinelength.cpp \
+    $$PWD/variables/vmeasurement.cpp \
+    $$PWD/variables/vvariable.cpp \
+    $$PWD/vformula.cpp \
+    $$PWD/vpatternpiecedata.cpp \
+    $$PWD/vpatterninfogeometry.cpp \
+    $$PWD/vgrainlinegeometry.cpp \
+    $$PWD/variables/vcurveclength.cpp \
+    $$PWD/variables/vellipticalarcradius.cpp \
+    $$PWD/vpiece.cpp \
+    $$PWD/vpiecenode.cpp \
+    $$PWD/vpiecepath.cpp
+
+win32-msvc*:SOURCES += $$PWD/stable.cpp
+
+HEADERS += \
+    $$PWD/vcontainer.h \
+    $$PWD/stable.h \
+    $$PWD/calculator.h \
+    $$PWD/variables.h \
+    $$PWD/vnodedetail.h \
+    $$PWD/vnodedetail_p.h \
+    $$PWD/vtranslatevars.h \
+    $$PWD/variables/varcradius.h \
+    $$PWD/variables/varcradius_p.h \
+    $$PWD/variables/vcurveangle.h \
+    $$PWD/variables/vcurvelength.h \
+    $$PWD/variables/vcurvevariable.h \
+    $$PWD/variables/vcurvevariable_p.h \
+    $$PWD/variables/vincrement.h \
+    $$PWD/variables/vincrement_p.h \
+    $$PWD/variables/vinternalvariable.h \
+    $$PWD/variables/vinternalvariable_p.h \
+    $$PWD/variables/vlineangle.h \
+    $$PWD/variables/vlineangle_p.h \
+    $$PWD/variables/vlinelength.h \
+    $$PWD/variables/vlinelength_p.h \
+    $$PWD/variables/vmeasurement.h \
+    $$PWD/variables/vmeasurement_p.h \
+    $$PWD/variables/vvariable.h \
+    $$PWD/variables/vvariable_p.h \
+    $$PWD/vformula.h \
+    $$PWD/vpatternpiecedata.h \
+    $$PWD/vpatterninfogeometry.h \
+    $$PWD/vgrainlinegeometry.h \
+    $$PWD/variables/vcurveclength.h \
+    $$PWD/variables/vellipticalarcradius.h \
+    $$PWD/vpiece.h \
+    $$PWD/vpiece_p.h \
+    $$PWD/vpiecenode.h \
+    $$PWD/vpiecenode_p.h \
+    $$PWD/vpiecepath.h \
+    $$PWD/vpiecepath_p.h
diff --git a/src/libs/vpatterndb/vpiece.cpp b/src/libs/vpatterndb/vpiece.cpp
new file mode 100644
index 000000000..704921167
--- /dev/null
+++ b/src/libs/vpatterndb/vpiece.cpp
@@ -0,0 +1,515 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   3 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "vpiece.h"
+#include "vpiece_p.h"
+#include "../vgeometry/vpointf.h"
+#include "../vgeometry/vabstractcurve.h"
+#include "vcontainer.h"
+
+#include <QSharedPointer>
+#include <QDebug>
+#include <QPainterPath>
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiece::VPiece()
+    : VAbstractPiece(), d(new VPieceData(PiecePathType::PiecePath))
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiece::VPiece(const VPiece &piece)
+    : VAbstractPiece(piece), d (piece.d)
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiece &VPiece::operator=(const VPiece &piece)
+{
+    if ( &piece == this )
+    {
+        return *this;
+    }
+    VAbstractPiece::operator=(piece);
+    d = piece.d;
+    return *this;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiece::~VPiece()
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath VPiece::GetPath() const
+{
+    return d->m_path;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath &VPiece::GetPath()
+{
+    return d->m_path;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiece::SetPath(const VPiecePath &path)
+{
+    d->m_path = path;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VPiece::MainPathPoints(const VContainer *data) const
+{
+    QVector<QPointF> points = GetPath().PathPoints(data);
+    points = CheckLoops(CorrectEquidistantPoints(points));//A path can contains loops
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VPointF> VPiece::MainPathNodePoints(const VContainer *data) const
+{
+    return GetPath().PathNodePoints(data);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VPiece::SeamAllowancePoints(const VContainer *data) const
+{
+    SCASSERT(data != nullptr);
+
+
+    if (not IsSeamAllowance())
+    {
+        return QVector<QPointF>();
+    }
+
+    const QVector<CustomSARecord> records = GetValidRecords();
+    int recordIndex = -1;
+    bool insertingCSA = false;
+    const qreal width = ToPixel(GetSAWidth(), *data->GetPatternUnit());
+
+    QVector<VSAPoint> pointsEkv;
+    for (int i = 0; i< d->m_path.CountNodes(); ++i)
+    {
+        const VPieceNode &node = d->m_path.at(i);
+        switch (node.GetTypeTool())
+        {
+            case (Tool::NodePoint):
+            {
+                if (not insertingCSA)
+                {
+                    pointsEkv.append(VPiecePath::PreparePointEkv(node, data));
+
+                    recordIndex = IsCSAStart(records, node.GetId());
+                    if (recordIndex != -1)
+                    {
+                        insertingCSA = true;
+
+                        const VPiecePath path = data->GetPiecePath(records.at(recordIndex).path);
+                        QVector<VSAPoint> r = path.SeamAllowancePoints(data, width, records.at(recordIndex).reverse);
+
+                        if (records.at(recordIndex).includeType == PiecePathIncludeType::AsCustomSA)
+                        {
+                            for (int j = 0; j < r.size(); ++j)
+                            {
+                                r[j].SetAngleType(PieceNodeAngle::ByLength);
+                                r[j].SetSABefore(0);
+                                r[j].SetSAAfter(0);
+                            }
+                        }
+
+                        pointsEkv += r;
+                    }
+                }
+                else
+                {
+                    if (records.at(recordIndex).endPoint == node.GetId())
+                    {
+                        insertingCSA = false;
+                        recordIndex = -1;
+
+                        pointsEkv.append(VPiecePath::PreparePointEkv(node, data));
+                    }
+                }
+            }
+            break;
+            case (Tool::NodeArc):
+            case (Tool::NodeSpline):
+            case (Tool::NodeSplinePath):
+            {
+                if (not insertingCSA)
+                {
+                    const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(node.GetId());
+
+                    pointsEkv += VPiecePath::CurveSeamAllowanceSegment(data, d->m_path.GetNodes(), curve, i,
+                                                                       node.GetReverse(), width);
+                }
+            }
+            break;
+            default:
+                qDebug()<<"Get wrong tool type. Ignore."<< static_cast<char>(node.GetTypeTool());
+                break;
+        }
+    }
+
+    return Equidistant(pointsEkv, width);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QVector<QPointF>> VPiece::GetInternalPathsPoints(const VContainer *data) const
+{
+    QVector<QVector<QPointF>> pathsPoints;
+    for (int i = 0; i < d->m_internalPaths.size(); ++i)
+    {
+        const VPiecePath path = data->GetPiecePath(d->m_internalPaths.at(i));
+        if (path.GetType() == PiecePathType::InternalPath)
+        {
+            pathsPoints.append(path.PathPoints(data));
+        }
+    }
+    return pathsPoints;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QPainterPath VPiece::MainPathPath(const VContainer *data) const
+{
+    const QVector<QPointF> points = MainPathPoints(data);
+    QPainterPath path;
+
+    if (not points.isEmpty())
+    {
+        path.moveTo(points[0]);
+        for (qint32 i = 1; i < points.count(); ++i)
+        {
+            path.lineTo(points.at(i));
+        }
+        path.lineTo(points.at(0));
+        path.setFillRule(Qt::WindingFill);
+    }
+
+    return path;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QPainterPath VPiece::SeamAllowancePath(const VContainer *data) const
+{
+    const QVector<QPointF> pointsEkv = SeamAllowancePoints(data);
+    QPainterPath ekv;
+
+    // seam allowence
+    if (IsSeamAllowance())
+    {
+        if (not pointsEkv.isEmpty())
+        {
+            ekv.moveTo(pointsEkv.at(0));
+            for (qint32 i = 1; i < pointsEkv.count(); ++i)
+            {
+                ekv.lineTo(pointsEkv.at(i));
+            }
+
+            ekv.setFillRule(Qt::WindingFill);
+        }
+    }
+
+    return ekv;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+qreal VPiece::GetMx() const
+{
+    return d->m_mx;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiece::SetMx(qreal value)
+{
+    d->m_mx = value;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+qreal VPiece::GetMy() const
+{
+    return d->m_my;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiece::SetMy(qreal value)
+{
+    d->m_my = value;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VPiece::IsInLayout() const
+{
+    return d->m_inLayout;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiece::SetInLayout(bool inLayout)
+{
+    d->m_inLayout = inLayout;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VPiece::IsUnited() const
+{
+    return d->m_united;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiece::SetUnited(bool united)
+{
+    d->m_united = united;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString VPiece::GetFormulaSAWidth() const
+{
+    return d->m_formulaWidth;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiece::SetFormulaSAWidth(const QString &formula, qreal value)
+{
+    SetSAWidth(value);
+    const qreal width = GetSAWidth();
+    width >= 0 ? d->m_formulaWidth = formula : d->m_formulaWidth = QLatin1String("0");
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<quint32> VPiece::GetInternalPaths() const
+{
+    return d->m_internalPaths;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiece::SetInternalPaths(const QVector<quint32> &iPaths)
+{
+    d->m_internalPaths = iPaths;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiece::AppendInternalPath(quint32 path)
+{
+    d->m_internalPaths.append(path);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<CustomSARecord> VPiece::GetCustomSARecords() const
+{
+    return d->m_customSARecords;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiece::SetCustomSARecords(const QVector<CustomSARecord> &records)
+{
+    d->m_customSARecords = records;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiece::AppendCustomSARecord(const CustomSARecord &record)
+{
+    d->m_customSARecords.append(record);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief MissingNodes find missing nodes in detail. When we deleted object in detail and return this detail need
+ * understand, what nodes need make invisible.
+ * @param det changed detail.
+ * @return  list with missing nodes.
+ */
+QVector<quint32> VPiece::MissingNodes(const VPiece &det) const
+{
+    return d->m_path.MissingNodes(det.GetPath());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<quint32> VPiece::MissingCSAPath(const VPiece &det) const
+{
+    const QVector<CustomSARecord> detRecords = det.GetCustomSARecords();
+    if (d->m_customSARecords.size() == detRecords.size()) //-V807
+    {
+        return QVector<quint32>();
+    }
+
+    QSet<quint32> set1;
+    for (qint32 i = 0; i < d->m_customSARecords.size(); ++i)
+    {
+        set1.insert(d->m_customSARecords.at(i).path);
+    }
+
+    QSet<quint32> set2;
+    for (qint32 j = 0; j < detRecords.size(); ++j)
+    {
+        set2.insert(detRecords.at(j).path);
+    }
+
+    const QList<quint32> set3 = set1.subtract(set2).toList();
+    QVector<quint32> r;
+    for (qint32 i = 0; i < set3.size(); ++i)
+    {
+        r.append(set3.at(i));
+    }
+
+    return r;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<quint32> VPiece::MissingInternalPaths(const VPiece &det) const
+{
+    const QVector<quint32> detRecords = det.GetInternalPaths();
+    if (d->m_internalPaths.size() == detRecords.size()) //-V807
+    {
+        return QVector<quint32>();
+    }
+
+    QSet<quint32> set1;
+    for (qint32 i = 0; i < d->m_internalPaths.size(); ++i)
+    {
+        set1.insert(d->m_internalPaths.at(i));
+    }
+
+    QSet<quint32> set2;
+    for (qint32 j = 0; j < detRecords.size(); ++j)
+    {
+        set2.insert(detRecords.at(j));
+    }
+
+    const QList<quint32> set3 = set1.subtract(set2).toList();
+    QVector<quint32> r;
+    for (qint32 i = 0; i < set3.size(); ++i)
+    {
+        r.append(set3.at(i));
+    }
+
+    return r;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiece::SetPatternPieceData(const VPatternPieceData &data)
+{
+    d->m_ppData = data;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief Returns full access to the pattern piece data object
+ * @return pattern piece data object
+ */
+VPatternPieceData &VPiece::GetPatternPieceData()
+{
+    return d->m_ppData;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief Returns the read only reference to the pattern piece data object
+ * @return pattern piece data object
+ */
+const VPatternPieceData &VPiece::GetPatternPieceData() const
+{
+    return d->m_ppData;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiece::SetPatternInfo(const VPatternInfoGeometry &info)
+{
+    d->m_piPatternInfo = info;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief Returns full access to the pattern info geometry object
+ * @return pattern info geometry object
+ */
+VPatternInfoGeometry &VPiece::GetPatternInfo()
+{
+    return d->m_piPatternInfo;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief Returns the read only reference to the pattern info geometry object
+ * @return pattern info geometry object
+ */
+const VPatternInfoGeometry &VPiece::GetPatternInfo() const
+{
+    return d->m_piPatternInfo;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief VDetail::GetGrainlineGeometry full access to the grainline geometry object
+ * @return reference to grainline geometry object
+ */
+VGrainlineGeometry &VPiece::GetGrainlineGeometry()
+{
+    return d->m_glGrainline;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief VDetail::GetGrainlineGeometry returns the read-only reference to the grainline geometry object
+ * @return reference to grainline geometry object
+ */
+const VGrainlineGeometry &VPiece::GetGrainlineGeometry() const
+{
+    return d->m_glGrainline;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<CustomSARecord> VPiece::GetValidRecords() const
+{
+    QVector<CustomSARecord> records;
+    for (int i = 0; i < d->m_customSARecords.size(); ++i)
+    {
+        const CustomSARecord &record = d->m_customSARecords.at(i);
+
+        if (record.startPoint > NULL_ID
+                && record.path > NULL_ID
+                && record.endPoint > NULL_ID
+                && d->m_path.indexOfNode(record.startPoint) != -1
+                && d->m_path.indexOfNode(record.endPoint) != -1)
+        {
+            records.append(record);
+        }
+    }
+    return records;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+int VPiece::IsCSAStart(const QVector<CustomSARecord> &records, quint32 id)
+{
+    for (int i = 0; i < records.size(); ++i)
+    {
+        if (records.at(i).startPoint == id)
+        {
+            return i;
+        }
+    }
+
+    return -1;
+}
diff --git a/src/libs/vpatterndb/vpiece.h b/src/libs/vpatterndb/vpiece.h
new file mode 100644
index 000000000..111d368c7
--- /dev/null
+++ b/src/libs/vpatterndb/vpiece.h
@@ -0,0 +1,120 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   3 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VPIECE_H
+#define VPIECE_H
+
+#include <QtGlobal>
+#include <QSharedDataPointer>
+
+#include "../vlayout/vabstractpiece.h"
+
+class QPainterPath;
+class VPieceData;
+class VPieceNode;
+class QPointF;
+class VPointF;
+class VContainer;
+template <class T> class QVector;
+template <class T>class QSharedPointer;
+class VAbstractCurve;
+class VPiecePath;
+class VPatternInfoGeometry;
+class VPatternPieceData;
+class VGrainlineGeometry;
+
+class VPiece : public VAbstractPiece
+{
+public:
+    VPiece();
+    VPiece(const VPiece &piece);
+    VPiece &operator=(const VPiece &piece);
+    virtual ~VPiece();
+
+    VPiecePath GetPath() const;
+    VPiecePath &GetPath();
+    void       SetPath(const VPiecePath &path);
+
+    QVector<QPointF> MainPathPoints(const VContainer *data) const;
+    QVector<VPointF> MainPathNodePoints(const VContainer *data) const;
+    QVector<QPointF> SeamAllowancePoints(const VContainer *data) const;
+
+    QVector<QVector<QPointF>> GetInternalPathsPoints(const VContainer *data) const;
+
+    QPainterPath MainPathPath(const VContainer *data) const;
+    QPainterPath SeamAllowancePath(const VContainer *data) const;
+
+    qreal GetMx() const;
+    void  SetMx(qreal value);
+
+    qreal GetMy() const;
+    void  SetMy(qreal value);
+
+    bool IsInLayout() const;
+    void SetInLayout(bool inLayout);
+
+    bool IsUnited() const;
+    void SetUnited(bool united);
+
+    QString GetFormulaSAWidth() const;
+    void    SetFormulaSAWidth(const QString &formula, qreal value);
+
+    QVector<quint32> GetInternalPaths() const;
+    void             SetInternalPaths(const QVector<quint32> &iPaths);
+    void             AppendInternalPath(quint32 path);
+
+    QVector<CustomSARecord> GetCustomSARecords() const;
+    void                    SetCustomSARecords(const QVector<CustomSARecord> &records);
+    void                    AppendCustomSARecord(const CustomSARecord &record);
+
+    QVector<quint32> MissingNodes(const VPiece &det) const;
+    QVector<quint32> MissingCSAPath(const VPiece &det) const;
+    QVector<quint32> MissingInternalPaths(const VPiece &det) const;
+
+    void                     SetPatternPieceData(const VPatternPieceData &data);
+    VPatternPieceData&       GetPatternPieceData();
+    const VPatternPieceData& GetPatternPieceData() const;
+
+    void                        SetPatternInfo(const VPatternInfoGeometry &info);
+    VPatternInfoGeometry&       GetPatternInfo();
+    const VPatternInfoGeometry& GetPatternInfo() const;
+
+    VGrainlineGeometry&         GetGrainlineGeometry();
+    const VGrainlineGeometry&   GetGrainlineGeometry() const;
+
+private:
+    QSharedDataPointer<VPieceData> d;
+
+    QVector<CustomSARecord> GetValidRecords() const;
+
+    static int IsCSAStart(const QVector<CustomSARecord> &records, quint32 id);
+};
+
+Q_DECLARE_TYPEINFO(VPiece, Q_MOVABLE_TYPE);
+
+#endif // VPIECE_H
diff --git a/src/libs/vpatterndb/vdetail_p.h b/src/libs/vpatterndb/vpiece_p.h
similarity index 51%
rename from src/libs/vpatterndb/vdetail_p.h
rename to src/libs/vpatterndb/vpiece_p.h
index d3692ca24..f937e8488 100644
--- a/src/libs/vpatterndb/vdetail_p.h
+++ b/src/libs/vpatterndb/vpiece_p.h
@@ -1,14 +1,14 @@
 /************************************************************************
  **
- **  @file   vdetail_p.h
+ **  @file
  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   20 8, 2014
+ **  @date   3 11, 2016
  **
  **  @brief
  **  @copyright
  **  This source code is part of the Valentine project, a pattern making
  **  program, whose allow create and modeling patterns of clothing.
- **  Copyright (C) 2013-2015 Valentina project
+ **  Copyright (C) 2016 Valentina project
  **  <https://bitbucket.org/dismine/valentina> All Rights Reserved.
  **
  **  Valentina is free software: you can redistribute it and/or modify
@@ -26,66 +26,88 @@
  **
  *************************************************************************/
 
-#ifndef VDETAIL_P_H
-#define VDETAIL_P_H
+#ifndef VPIECE_P_H
+#define VPIECE_P_H
 
 #include <QSharedData>
-#include "vnodedetail.h"
+#include <QVector>
+
+#include "../vmisc/diagnostic.h"
+#include "../vmisc/def.h"
+#include "vpiecenode.h"
+#include "vpiecepath.h"
 #include "vpatternpiecedata.h"
 #include "vpatterninfogeometry.h"
 #include "vgrainlinegeometry.h"
-#include "../ifc/ifcdef.h"
-#include "../vmisc/diagnostic.h"
 
 QT_WARNING_PUSH
 QT_WARNING_DISABLE_GCC("-Weffc++")
 
-class VDetailData : public QSharedData
+class VPieceData : public QSharedData
 {
 public:
-    VDetailData()
-        :_id(NULL_ID), nodes(QVector<VNodeDetail>()), mx(0), my(0), inLayout(true)
+    explicit VPieceData(PiecePathType type)
+        : m_path(type),
+          m_mx(0),
+          m_my(0),
+          m_inLayout(true),
+          m_united(false),
+          m_customSARecords(),
+          m_internalPaths(),
+          m_ppData(),
+          m_piPatternInfo(),
+          m_glGrainline(),
+          m_formulaWidth("0")
     {}
 
-    explicit VDetailData(const QVector<VNodeDetail> &nodes)
-        :_id(NULL_ID), nodes(nodes), mx(0), my(0), inLayout(true)
+    VPieceData(const VPieceData &detail)
+        : QSharedData(detail),
+          m_path(detail.m_path),
+          m_mx(detail.m_mx),
+          m_my(detail.m_my),
+          m_inLayout(detail.m_inLayout),
+          m_united(detail.m_united),
+          m_customSARecords(detail.m_customSARecords),
+          m_internalPaths(detail.m_internalPaths),
+          m_ppData(detail.m_ppData),
+          m_piPatternInfo(detail.m_piPatternInfo),
+          m_glGrainline(detail.m_glGrainline),
+          m_formulaWidth(detail.m_formulaWidth)
     {}
 
-    VDetailData(const VDetailData &detail)
-        :QSharedData(detail), _id(NULL_ID), nodes(detail.nodes), mx(detail.mx), my(detail.my),
-          m_ppData(detail.m_ppData), m_piPatternInfo(detail.m_piPatternInfo),
-          m_glGrainline(detail.m_glGrainline), inLayout(detail.inLayout)
-    {}
-
-    ~VDetailData() {}
-
-    /** @brief _id id detail. */
-    quint32        _id;
+    ~VPieceData();
 
     /** @brief nodes list detail nodes. */
-    QVector<VNodeDetail> nodes;
+    VPiecePath m_path;
 
-    /** @brief mx bias x axis. */
-    qreal          mx;
+    qreal m_mx;
+    qreal m_my;
 
-    /** @brief my bias y axis. */
-    qreal          my;
+    bool m_inLayout;
+    bool m_united;
+
+    QVector<CustomSARecord> m_customSARecords;
+    QVector<quint32>        m_internalPaths;
 
     /** @brief Pattern piece data */
     VPatternPieceData m_ppData;
+
     /** @brief Pattern info coordinates */
     VPatternInfoGeometry m_piPatternInfo;
-    /**
-     * @brief m_glGrainline grainline geometry object
-     */
+
+    /** @brief m_glGrainline grainline geometry object*/
     VGrainlineGeometry m_glGrainline;
 
-    bool           inLayout;
+    QString m_formulaWidth;
 
 private:
-    VDetailData &operator=(const VDetailData &) Q_DECL_EQ_DELETE;
+    VPieceData &operator=(const VPieceData &) Q_DECL_EQ_DELETE;
 };
 
+VPieceData::~VPieceData()
+{}
+
 QT_WARNING_POP
 
-#endif // VDETAIL_P_H
+#endif // VPIECE_P_H
+
diff --git a/src/libs/vpatterndb/vpiecenode.cpp b/src/libs/vpatterndb/vpiecenode.cpp
new file mode 100644
index 000000000..2d74cd4a5
--- /dev/null
+++ b/src/libs/vpatterndb/vpiecenode.cpp
@@ -0,0 +1,237 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   3 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "vpiecenode.h"
+#include "vpiecenode_p.h"
+#include "vcontainer.h"
+#include "calculator.h"
+
+#include <QDataStream>
+#include <QtNumeric>
+
+namespace
+{
+//---------------------------------------------------------------------------------------------------------------------
+qreal EvalFormula(const VContainer *data, QString formula)
+{
+    if (formula.isEmpty())
+    {
+        return -1;
+    }
+    else
+    {
+        try
+        {
+            // Replace line return character with spaces for calc if exist
+            formula.replace("\n", " ");
+            QScopedPointer<Calculator> cal(new Calculator());
+            const qreal result = cal->EvalFormula(data->PlainVariables(), formula);
+
+            if (qIsInf(result) || qIsNaN(result))
+            {
+                return -1;
+            }
+            return result;
+        }
+        catch (qmu::QmuParserError &e)
+        {
+            Q_UNUSED(e)
+            return -1;
+        }
+    }
+}
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPieceNode::VPieceNode()
+    : d(new VPieceNodeData)
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPieceNode::VPieceNode(quint32 id, Tool typeTool, bool reverse)
+    : d(new VPieceNodeData(id, typeTool, reverse))
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPieceNode::VPieceNode(const VPieceNode &node)
+    : d (node.d)
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPieceNode &VPieceNode::operator=(const VPieceNode &node)
+{
+    if ( &node == this )
+    {
+        return *this;
+    }
+    d = node.d;
+    return *this;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPieceNode::~VPieceNode()
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+quint32 VPieceNode::GetId() const
+{
+    return d->m_id;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPieceNode::SetId(quint32 id)
+{
+    d->m_id = id;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+Tool VPieceNode::GetTypeTool() const
+{
+    return d->m_typeTool;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPieceNode::SetTypeTool(Tool value)
+{
+    d->m_typeTool = value;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VPieceNode::GetReverse() const
+{
+    return d->m_reverse;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPieceNode::SetReverse(bool reverse)
+{
+    if (d->m_typeTool != Tool::NodePoint)
+    {
+        d->m_reverse = reverse;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+qreal VPieceNode::GetSABefore(const VContainer *data) const
+{
+    return EvalFormula(data, d->m_formulaWidthBefore);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+qreal VPieceNode::GetSABefore(const VContainer *data, Unit unit) const
+{
+    qreal value = EvalFormula(data, d->m_formulaWidthBefore);
+    if (value >= 0)
+    {
+        value = ToPixel(value, unit);
+    }
+    return value;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString VPieceNode::GetFormulaSABefore() const
+{
+    return d->m_formulaWidthBefore;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPieceNode::SetFormulaSABefore(const QString &formula)
+{
+    if (d->m_typeTool == Tool::NodePoint)
+    {
+        d->m_formulaWidthBefore = formula;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+qreal VPieceNode::GetSAAfter(const VContainer *data) const
+{
+    return EvalFormula(data, d->m_formulaWidthAfter);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+qreal VPieceNode::GetSAAfter(const VContainer *data, Unit unit) const
+{
+    qreal value = EvalFormula(data, d->m_formulaWidthAfter);
+    if (value >= 0)
+    {
+        value = ToPixel(value, unit);
+    }
+    return value;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString VPieceNode::GetFormulaSAAfter() const
+{
+    return d->m_formulaWidthAfter;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPieceNode::SetFormulaSAAfter(const QString &formula)
+{
+    if (d->m_typeTool == Tool::NodePoint)
+    {
+        d->m_formulaWidthAfter = formula;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+PieceNodeAngle VPieceNode::GetAngleType() const
+{
+    return d->m_angleType;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPieceNode::SetAngleType(PieceNodeAngle type)
+{
+    if (d->m_typeTool == Tool::NodePoint)
+    {
+        d->m_angleType = type;
+    }
+}
+
+// Friend functions
+//---------------------------------------------------------------------------------------------------------------------
+QDataStream& operator<<(QDataStream& out, const VPieceNode& p)
+{
+    out << p.d->m_id << static_cast<int>(p.d->m_typeTool) << p.d->m_reverse;
+    return out;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QDataStream& operator>>(QDataStream& in, VPieceNode& p)
+{
+    in >> p.d->m_id;
+
+    int type = 0;
+    in >> type;
+    p.d->m_typeTool = static_cast<Tool>(type);
+
+    in >> p.d->m_reverse;
+    return in;
+}
diff --git a/src/libs/vpatterndb/vpiecenode.h b/src/libs/vpatterndb/vpiecenode.h
new file mode 100644
index 000000000..c2e7c9b1c
--- /dev/null
+++ b/src/libs/vpatterndb/vpiecenode.h
@@ -0,0 +1,84 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   3 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VPIECENODE_H
+#define VPIECENODE_H
+
+#include <QtGlobal>
+#include <QSharedDataPointer>
+#include <QMetaType>
+
+#include "../vmisc/def.h"
+
+class VPieceNodeData;
+class QDataStream;
+class VContainer;
+
+class VPieceNode
+{
+public:
+    VPieceNode();
+    VPieceNode(quint32 id, Tool typeTool, bool reverse = false);
+    VPieceNode(const VPieceNode &node);
+    VPieceNode &operator=(const VPieceNode &node);
+    ~VPieceNode();
+
+    friend QDataStream& operator<<(QDataStream& out, const VPieceNode& p);
+    friend QDataStream& operator>>(QDataStream& in, VPieceNode& p);
+
+    quint32 GetId() const;
+    void    SetId(quint32 id);
+
+    Tool GetTypeTool() const;
+    void SetTypeTool(Tool value);
+
+    bool GetReverse() const;
+    void SetReverse(bool reverse);
+
+    qreal GetSABefore(const VContainer *data) const;
+    qreal GetSABefore(const VContainer *data, Unit unit) const;
+
+    QString GetFormulaSABefore() const;
+    void    SetFormulaSABefore(const QString &formula);
+
+    qreal GetSAAfter(const VContainer *data) const;
+    qreal GetSAAfter(const VContainer *data, Unit unit) const;
+
+    QString GetFormulaSAAfter() const;
+    void    SetFormulaSAAfter(const QString &formula);
+
+    PieceNodeAngle GetAngleType() const;
+    void           SetAngleType(PieceNodeAngle type);
+private:
+    QSharedDataPointer<VPieceNodeData> d;
+};
+
+Q_DECLARE_METATYPE(VPieceNode)
+Q_DECLARE_TYPEINFO(VPieceNode, Q_MOVABLE_TYPE);
+
+#endif // VPIECENODE_H
diff --git a/src/libs/vpatterndb/vpiecenode_p.h b/src/libs/vpatterndb/vpiecenode_p.h
new file mode 100644
index 000000000..6defef952
--- /dev/null
+++ b/src/libs/vpatterndb/vpiecenode_p.h
@@ -0,0 +1,110 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   3 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VPIECENODE_P_H
+#define VPIECENODE_P_H
+
+#include <QSharedData>
+#include "../ifc/ifcdef.h"
+#include "../vmisc/diagnostic.h"
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Weffc++")
+
+class VPieceNodeData : public QSharedData
+{
+public:
+    VPieceNodeData()
+        : m_id(NULL_ID),
+          m_typeTool(Tool::NodePoint),
+          m_reverse(false),
+          m_saBefore(-1),
+          m_saAfter(-1),
+          m_formulaWidthBefore(currentSeamAllowance),
+          m_formulaWidthAfter(currentSeamAllowance),
+          m_angleType(PieceNodeAngle::ByLength)
+    {}
+
+    VPieceNodeData(quint32 id, Tool typeTool, bool reverse)
+        : m_id(id),
+          m_typeTool(typeTool),
+          m_reverse(reverse),
+          m_saBefore(-1),
+          m_saAfter(-1),
+          m_formulaWidthBefore(currentSeamAllowance),
+          m_formulaWidthAfter(currentSeamAllowance),
+          m_angleType(PieceNodeAngle::ByLength)
+    {
+        if (m_typeTool == Tool::NodePoint)
+        {
+            m_reverse = false;
+        }
+    }
+
+    VPieceNodeData (const VPieceNodeData& node)
+        : QSharedData(node),
+          m_id(node.m_id),
+          m_typeTool(node.m_typeTool),
+          m_reverse(node.m_reverse),
+          m_saBefore(node.m_saBefore),
+          m_saAfter(node.m_saAfter),
+          m_formulaWidthBefore(node.m_formulaWidthBefore),
+          m_formulaWidthAfter(node.m_formulaWidthAfter),
+          m_angleType(node.m_angleType)
+    {}
+
+    ~VPieceNodeData();
+
+    /** @brief id object id. */
+    quint32 m_id;
+
+    /** @brief typeTool type of tool */
+    Tool m_typeTool;
+
+    /** @brief reverse true if need reverse points list for node. */
+    bool m_reverse;
+
+    qreal m_saBefore;
+    qreal m_saAfter;
+
+    QString m_formulaWidthBefore;
+    QString m_formulaWidthAfter;
+
+    PieceNodeAngle m_angleType;
+
+private:
+    VPieceNodeData &operator=(const VPieceNodeData &) Q_DECL_EQ_DELETE;
+};
+
+VPieceNodeData::~VPieceNodeData()
+{}
+
+QT_WARNING_POP
+
+#endif // VPIECENODE_P_H
+
diff --git a/src/libs/vpatterndb/vpiecepath.cpp b/src/libs/vpatterndb/vpiecepath.cpp
new file mode 100644
index 000000000..80c30906f
--- /dev/null
+++ b/src/libs/vpatterndb/vpiecepath.cpp
@@ -0,0 +1,797 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   22 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "vpiecepath.h"
+#include "vpiecepath_p.h"
+#include "vcontainer.h"
+#include "../vgeometry/vpointf.h"
+#include "../vlayout/vabstractpiece.h"
+
+#include <QPainterPath>
+
+namespace
+{
+//---------------------------------------------------------------------------------------------------------------------
+VSAPoint CurvePoint(VSAPoint candidate, const VContainer *data, const VPieceNode &node,
+                    const QVector<QPointF> &curvePoints)
+{
+    if (node.GetTypeTool() == Tool::NodePoint)
+    {
+        const QPointF p = *data->GeometricObject<VPointF>(node.GetId());
+        if (VAbstractCurve::IsPointOnCurve(curvePoints, p))
+        {
+            candidate = VSAPoint(p);
+            candidate.SetSAAfter(node.GetSAAfter(data, *data->GetPatternUnit()));
+            candidate.SetSABefore(node.GetSABefore(data, *data->GetPatternUnit()));
+            candidate.SetAngleType(node.GetAngleType());
+        }
+    }
+    return candidate;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief indexOfNode return index in list node using id object.
+ * @param list list nodes detail.
+ * @param id object (arc, point, spline, splinePath) id.
+ * @return index in list or -1 id can't find.
+ */
+int IndexOfNode(const QVector<VPieceNode> &list, quint32 id)
+{
+    for (int i = 0; i < list.size(); ++i)
+    {
+        if (list.at(i).GetId() == id)
+        {
+            return i;
+        }
+    }
+    qDebug()<<"Can't find node.";
+    return -1;
+}
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath::VPiecePath()
+    : d(new VPiecePathData)
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath::VPiecePath(PiecePathType type)
+    : d(new VPiecePathData(type))
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath::VPiecePath(const VPiecePath &path)
+    : d (path.d)
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath &VPiecePath::operator=(const VPiecePath &path)
+{
+    if ( &path == this )
+    {
+        return *this;
+    }
+    d = path.d;
+    return *this;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath::~VPiecePath()
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiecePath::Append(const VPieceNode &node)
+{
+    d->m_nodes.append(node);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiecePath::Clear()
+{
+    d->m_nodes.clear();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+qint32 VPiecePath::CountNodes() const
+{
+    return d->m_nodes.size();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPieceNode &VPiecePath::operator[](int indx)
+{
+    return d->m_nodes[indx];
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+const VPieceNode &VPiecePath::at(int indx) const
+{
+    return d->m_nodes.at(indx);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VPieceNode> VPiecePath::GetNodes() const
+{
+    return d->m_nodes;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiecePath::SetNodes(const QVector<VPieceNode> &nodes)
+{
+    d->m_nodes = nodes;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+PiecePathType VPiecePath::GetType() const
+{
+    return d->m_type;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiecePath::SetType(PiecePathType type)
+{
+    d->m_type = type;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString VPiecePath::GetName() const
+{
+    return d->m_name;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiecePath::SetName(const QString &name)
+{
+    d->m_name = name;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+Qt::PenStyle VPiecePath::GetPenType() const
+{
+    return d->m_penType;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPiecePath::SetPenType(const Qt::PenStyle &type)
+{
+    d->m_penType = type;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> VPiecePath::PathPoints(const VContainer *data) const
+{
+    QVector<QPointF> points;
+    for (int i = 0; i < CountNodes(); ++i)
+    {
+        switch (at(i).GetTypeTool())
+        {
+            case (Tool::NodePoint):
+            {
+                const QSharedPointer<VPointF> point = data->GeometricObject<VPointF>(at(i).GetId());
+                points.append(*point);
+            }
+            break;
+            case (Tool::NodeArc):
+            case (Tool::NodeSpline):
+            case (Tool::NodeSplinePath):
+            {
+                const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(at(i).GetId());
+
+                const QPointF begin = StartSegment(data, i, at(i).GetReverse());
+                const QPointF end = EndSegment(data, i, at(i).GetReverse());
+
+                points << curve->GetSegmentPoints(begin, end, at(i).GetReverse());
+            }
+            break;
+            default:
+                qDebug()<<"Get wrong tool type. Ignore."<< static_cast<char>(at(i).GetTypeTool());
+                break;
+        }
+    }
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VPointF> VPiecePath::PathNodePoints(const VContainer *data) const
+{
+    QVector<VPointF> points;
+    for (int i = 0; i < CountNodes(); ++i)
+    {
+        switch (at(i).GetTypeTool())
+        {
+            case Tool::NodePoint:
+            {
+                const QSharedPointer<VPointF> point = data->GeometricObject<VPointF>(at(i).GetId());
+                points.append(*point);
+            }
+            break;
+            case Tool::NodeArc:
+            case Tool::NodeSpline:
+            case Tool::NodeSplinePath:
+            default:
+                break;
+        }
+    }
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VSAPoint> VPiecePath::SeamAllowancePoints(const VContainer *data, qreal width, bool reverse) const
+{
+    SCASSERT(data != nullptr);
+
+    QVector<VSAPoint> pointsEkv;
+    for (int i = 0; i< d->m_nodes.size(); ++i)
+    {
+        const VPieceNode &node = d->m_nodes.at(i);
+        switch (node.GetTypeTool())
+        {
+            case (Tool::NodePoint):
+            {
+                pointsEkv.append(PreparePointEkv(node, data));
+            }
+            break;
+            case (Tool::NodeArc):
+            case (Tool::NodeSpline):
+            case (Tool::NodeSplinePath):
+            {
+                const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(node.GetId());
+                pointsEkv += CurveSeamAllowanceSegment(data, d->m_nodes, curve, i, node.GetReverse(), width);
+            }
+            break;
+            default:
+                qDebug()<<"Get wrong tool type. Ignore."<< static_cast<char>(node.GetTypeTool());
+                break;
+        }
+    }
+
+    if (reverse)
+    {
+        pointsEkv = VGObject::GetReversePoints(pointsEkv);
+    }
+
+    return pointsEkv;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QPainterPath VPiecePath::PainterPath(const VContainer *data) const
+{
+    const QVector<QPointF> points = PathPoints(data);
+    QPainterPath path;
+
+    if (not points.isEmpty())
+    {
+        path.moveTo(points[0]);
+        for (qint32 i = 1; i < points.count(); ++i)
+        {
+            path.lineTo(points.at(i));
+        }
+        path.setFillRule(Qt::WindingFill);
+    }
+
+    return path;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VSAPoint VPiecePath::StartSegment(const VContainer *data, const QVector<VPieceNode> &nodes, int i, bool reverse)
+{
+    if (i < 0 || i > nodes.size()-1)
+    {
+        return VSAPoint();
+    }
+
+    const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(nodes.at(i).GetId());
+
+    const QVector<QPointF> points = curve->GetPoints();
+    if (points.isEmpty())
+    {
+        return VSAPoint();
+    }
+
+    VSAPoint begin;
+    reverse ? begin = VSAPoint(points.last()) : begin = VSAPoint(points.first());
+
+    if (nodes.size() > 1)
+    {
+        int index = 0;
+        i == 0 ? index = nodes.size()-1 : index = i-1;
+
+        begin = CurvePoint(begin, data, nodes.at(index), points);
+    }
+    return begin;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VSAPoint VPiecePath::EndSegment(const VContainer *data, const QVector<VPieceNode> &nodes, int i, bool reverse)
+{
+    if (i < 0 || i > nodes.size()-1)
+    {
+        return VSAPoint();
+    }
+
+    const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(nodes.at(i).GetId());
+
+    const QVector<QPointF> points = curve->GetPoints();
+    if (points.isEmpty())
+    {
+        return VSAPoint();
+    }
+
+    VSAPoint end;
+    reverse ? end = VSAPoint(points.first()) : end = VSAPoint(points.last());
+
+    if (nodes.size() > 2)
+    {
+        int index = 0;
+        i == nodes.size() - 1 ? index = 0 : index = i+1;
+
+        end = CurvePoint(end, data, nodes.at(index), points);
+    }
+    return end;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<quint32> VPiecePath::MissingNodes(const VPiecePath &path) const
+{
+    if (d->m_nodes.size() == path.CountNodes()) //-V807
+    {
+        return QVector<quint32>();
+    }
+
+    QSet<quint32> set1;
+    for (qint32 i = 0; i < d->m_nodes.size(); ++i)
+    {
+        set1.insert(d->m_nodes.at(i).GetId());
+    }
+
+    QSet<quint32> set2;
+    for (qint32 j = 0; j < path.CountNodes(); ++j)
+    {
+        set2.insert(path.at(j).GetId());
+    }
+
+    const QList<quint32> set3 = set1.subtract(set2).toList();
+    QVector<quint32> nodes;
+    for (qint32 i = 0; i < set3.size(); ++i)
+    {
+        const int index = indexOfNode(set3.at(i));
+        if (index != -1)
+        {
+            nodes.append(d->m_nodes.at(index).GetId());
+        }
+    }
+
+    return nodes;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+int VPiecePath::indexOfNode(quint32 id) const
+{
+    for (int i = 0; i < d->m_nodes.size(); ++i)
+    {
+        if (d->m_nodes.at(i).GetId() == id)
+        {
+            return i;
+        }
+    }
+    qDebug()<<"Can't find node.";
+    return -1;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief NodeOnEdge return nodes located on edge with index.
+ * @param index index of edge.
+ * @param p1 first node.
+ * @param p2 second node.
+ */
+void VPiecePath::NodeOnEdge(quint32 index, VPieceNode &p1, VPieceNode &p2) const
+{
+    const QVector<VPieceNode> list = ListNodePoint();
+    if (index > static_cast<quint32>(list.size()))
+    {
+        qDebug()<<"Wrong edge index index ="<<index;
+        return;
+    }
+    p1 = list.at(static_cast<int>(index));
+    if (index + 1 > static_cast<quint32>(list.size()) - 1)
+    {
+        p2 = list.at(0);
+    }
+    else
+    {
+        p2 = list.at(static_cast<int>(index+1));
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VPiecePath::Contains(quint32 id) const
+{
+    for (int i = 0; i < d->m_nodes.size(); ++i)
+    {
+        if (d->m_nodes.at(i).GetId() == id)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief OnEdge checks if two poins located on the edge. Edge is line between two points. If between two points
+ * located arcs or splines ignore this.
+ * @param p1 id first point.
+ * @param p2 id second point.
+ * @return true - on edge, false - no.
+ */
+bool VPiecePath::OnEdge(quint32 p1, quint32 p2) const
+{
+    const QVector<VPieceNode> list = ListNodePoint();
+    if (list.size() < 2)
+    {
+        qDebug()<<"Not enough points.";
+        return false;
+    }
+    int i = IndexOfNode(list, p1);
+    int j1 = 0, j2 = 0;
+
+    if (i == list.size() - 1)
+    {
+        j1 = i-1;
+        j2 = 0;
+    }
+    else if (i == 0)
+    {
+        j1 = list.size() - 1;
+        j2 = i + 1;
+    }
+    else
+    {
+        j1 = i - 1;
+        j2 = i + 1;
+    }
+
+    if (list.at(j1).GetId() == p2 || list.at(j2).GetId() == p2)
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief Edge return edge index in detail. Edge is line between two points. If between two points
+ * located arcs or splines ignore this.
+ * @param p1 id first point.
+ * @param p2 id second point.
+ * @return edge index or -1 if points don't located on edge
+ */
+int VPiecePath::Edge(quint32 p1, quint32 p2) const
+{
+    if (OnEdge(p1, p2) == false)
+    {
+        qDebug()<<"Points don't on edge.";
+        return -1;
+    }
+
+    const QVector<VPieceNode> list = ListNodePoint();
+    int i = IndexOfNode(list, p1);
+    int j = IndexOfNode(list, p2);
+
+    int min = qMin(i, j);
+
+    if (min == 0 && (i == list.size() - 1 || j == list.size() - 1))
+    {
+        return list.size() - 1;
+    }
+    else
+    {
+        return min;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief listNodePoint return list nodes only with points.
+ * @return list points node.
+ */
+QVector<VPieceNode> VPiecePath::ListNodePoint() const
+{
+    QVector<VPieceNode> list;
+    for (int i = 0; i < d->m_nodes.size(); ++i) //-V807
+    {
+        if (d->m_nodes.at(i).GetTypeTool() == Tool::NodePoint)
+        {
+            list.append(d->m_nodes.at(i));
+        }
+    }
+    return list;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief RemoveEdge return path without edge with index.
+ * @param index idex of edge.
+ * @return path without edge with index.
+ */
+VPiecePath VPiecePath::RemoveEdge(quint32 index) const
+{
+    VPiecePath path(*this);
+    path.Clear();
+
+    // Edge can be only segment. We ignore all curves inside segments.
+    const quint32 edges = static_cast<quint32>(ListNodePoint().size());
+    quint32 k = 0;
+    for (quint32 i=0; i<edges; ++i)
+    {
+        if (i == index)
+        {
+            path.Append(this->at(static_cast<int>(k)));
+            ++k;
+        }
+        else
+        {
+            VPieceNode p1;
+            VPieceNode p2;
+            this->NodeOnEdge(i, p1, p2);
+            const int j1 = this->indexOfNode(p1.GetId());
+            int j2 = this->indexOfNode(p2.GetId());
+            if (j2 == 0)
+            {
+                j2 = this->CountNodes();
+            }
+            for (int j=j1; j<j2; ++j)
+            {// Add "segment" except last point. Inside can be curves too.
+                path.Append(this->at(j));
+                ++k;
+            }
+        }
+    }
+    return path;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VSAPoint VPiecePath::StartSegment(const VContainer *data, int i, bool reverse) const
+{
+    return StartSegment(data, d->m_nodes, i, reverse);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VSAPoint VPiecePath::EndSegment(const VContainer *data, int i, bool reverse) const
+{
+    return EndSegment(data, d->m_nodes, i, reverse);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QPointF VPiecePath::NodePreviousPoint(const VContainer *data, int i) const
+{
+    if (i < 0 || i > d->m_nodes.size()-1)
+    {
+        return QPointF();
+    }
+
+    if (d->m_nodes.size() > 1)
+    {
+        int index = 0;
+        if (i == 0)
+        {
+            index = d->m_nodes.size()-1;
+        }
+        else
+        {
+            index = i-1;
+        }
+
+        const VPieceNode &node = d->m_nodes.at(index);
+        switch (node.GetTypeTool())
+        {
+            case (Tool::NodePoint):
+                return *data->GeometricObject<VPointF>(node.GetId());
+            case (Tool::NodeArc):
+            case (Tool::NodeSpline):
+            case (Tool::NodeSplinePath):
+            {
+                const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(node.GetId());
+
+                const VSAPoint begin = StartSegment(data, d->m_nodes, index, node.GetReverse());
+                const VSAPoint end = EndSegment(data, d->m_nodes, index, node.GetReverse());
+
+                const QVector<QPointF> points = curve->GetSegmentPoints(begin, end, node.GetReverse());
+                if (points.size() > 1)
+                {
+                    return points.at(points.size()-2);
+                }
+            }
+                break;
+            default:
+                qDebug()<<"Get wrong tool type. Ignore."<< static_cast<char>(node.GetTypeTool());
+                break;
+        }
+    }
+
+    return QPointF();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QPointF VPiecePath::NodeNextPoint(const VContainer *data, int i) const
+{
+    QPointF point;
+    if (i < 0 || i > d->m_nodes.size()-1)
+    {
+        return point;
+    }
+
+    if (d->m_nodes.size() > 1)
+    {
+        int index = 0;
+        if (i == d->m_nodes.size() - 1)
+        {
+            index = 0;
+        }
+        else
+        {
+            index = i+1;
+        }
+
+        const VPieceNode &node = d->m_nodes.at(index);
+        switch (node.GetTypeTool())
+        {
+            case (Tool::NodePoint):
+                return *data->GeometricObject<VPointF>(node.GetId());
+            case (Tool::NodeArc):
+            case (Tool::NodeSpline):
+            case (Tool::NodeSplinePath):
+            {
+                const QSharedPointer<VAbstractCurve> curve = data->GeometricObject<VAbstractCurve>(node.GetId());
+
+                const VSAPoint begin = StartSegment(data, d->m_nodes, index, node.GetReverse());
+                const VSAPoint end = EndSegment(data, d->m_nodes, index, node.GetReverse());
+
+                const QVector<QPointF> points = curve->GetSegmentPoints(begin, end, node.GetReverse());
+                if (points.size() > 1)
+                {
+                    return points.at(1);
+                }
+            }
+                break;
+            default:
+                qDebug()<<"Get wrong tool type. Ignore."<< static_cast<char>(node.GetTypeTool());
+                break;
+        }
+    }
+
+    return point;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VSAPoint VPiecePath::PreparePointEkv(const VPieceNode &node, const VContainer *data)
+{
+    const QSharedPointer<VPointF> point = data->GeometricObject<VPointF>(node.GetId());
+    VSAPoint p(point->toQPointF());
+
+    p.SetSAAfter(node.GetSAAfter(data, *data->GetPatternUnit()));
+    p.SetSABefore(node.GetSABefore(data, *data->GetPatternUnit()));
+    p.SetAngleType(node.GetAngleType());
+
+    return p;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VSAPoint> VPiecePath::CurveSeamAllowanceSegment(const VContainer *data, const QVector<VPieceNode> &nodes,
+                                                        const QSharedPointer<VAbstractCurve> &curve, int i,
+                                                        bool reverse, qreal width)
+{
+    QVector<VSAPoint> pointsEkv;
+
+    const VSAPoint begin = StartSegment(data, nodes, i, reverse);
+    const VSAPoint end = EndSegment(data, nodes, i, reverse);
+
+    const QVector<QPointF> points = curve->GetSegmentPoints(begin, end, reverse);
+    if (points.isEmpty())
+    {
+        return pointsEkv;
+    }
+
+    qreal w1 = begin.GetSAAfter();
+    qreal w2 = end.GetSABefore();
+    if (w1 < 0 && w2 < 0)
+    {// no local widths
+        for(int i = 0; i < points.size(); ++i)
+        {
+            VSAPoint p(points.at(i));
+            if (i == 0)
+            { // first point
+                p.SetSAAfter(begin.GetSAAfter());
+                p.SetSABefore(begin.GetSABefore());
+                p.SetAngleType(begin.GetAngleType());
+            }
+            else if (i == points.size() - 1)
+            { // last point
+                p.SetSAAfter(end.GetSAAfter());
+                p.SetSABefore(end.GetSABefore());
+                p.SetAngleType(end.GetAngleType());
+            }
+            pointsEkv.append(p);
+        }
+    }
+    else
+    {
+        if (w1 < 0)
+        {
+            w1 = width;
+        }
+
+        if (w2 < 0)
+        {
+            w2 = width;
+        }
+
+        const qreal wDiff = w2 - w1;// Difference between to local widths
+        const qreal fullLength = VAbstractCurve::PathLength(points);
+
+        VSAPoint p(points.at(0));//First point in the list
+        p.SetSAAfter(begin.GetSAAfter());
+        p.SetSABefore(begin.GetSABefore());
+        p.SetAngleType(begin.GetAngleType());
+        pointsEkv.append(p);
+
+        qreal length = 0; // how much we handle
+
+        for(int i = 1; i < points.size(); ++i)
+        {
+            p = VSAPoint(points.at(i));
+
+            if (i == points.size() - 1)
+            {// last point
+                p.SetSAAfter(end.GetSAAfter());
+                p.SetSABefore(end.GetSABefore());
+                p.SetAngleType(end.GetAngleType());
+            }
+            else
+            {
+                length += QLineF(points.at(i-1), points.at(i)).length();
+                const qreal localWidth = w1 + wDiff*(length/fullLength);
+
+                p.SetSAAfter(localWidth);
+                p.SetSABefore(localWidth);
+                // curve points have angle type by default
+            }
+
+            pointsEkv.append(p);
+        }
+    }
+
+    return pointsEkv;
+}
diff --git a/src/libs/vpatterndb/vpiecepath.h b/src/libs/vpatterndb/vpiecepath.h
new file mode 100644
index 000000000..40852dd53
--- /dev/null
+++ b/src/libs/vpatterndb/vpiecepath.h
@@ -0,0 +1,113 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   22 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VPIECEPATH_H
+#define VPIECEPATH_H
+
+#include <QtGlobal>
+#include <QSharedDataPointer>
+
+#include "../vmisc/def.h"
+
+class VPiecePathData;
+class VPieceNode;
+class QPointF;
+class VPointF;
+class VContainer;
+class VSAPoint;
+class QPainterPath;
+class VAbstractCurve;
+
+class VPiecePath
+{
+public:
+    VPiecePath();
+    explicit VPiecePath(PiecePathType type);
+    VPiecePath(const VPiecePath &path);
+    VPiecePath &operator=(const VPiecePath &path);
+    ~VPiecePath();
+
+    void   Append(const VPieceNode &node);
+    void   Clear();
+    qint32 CountNodes() const;
+
+    VPieceNode & operator[](int indx);
+    const VPieceNode & at ( int indx ) const;
+
+    QVector<VPieceNode> GetNodes() const;
+    void                SetNodes(const QVector<VPieceNode> &nodes);
+
+    PiecePathType GetType() const;
+    void          SetType(PiecePathType type);
+
+    QString GetName() const;
+    void    SetName(const QString &name);
+
+    Qt::PenStyle GetPenType() const;
+    void         SetPenType(const Qt::PenStyle &type);
+
+    QVector<QPointF>  PathPoints(const VContainer *data) const;
+    QVector<VPointF>  PathNodePoints(const VContainer *data) const;
+    QVector<VSAPoint> SeamAllowancePoints(const VContainer *data, qreal width, bool reverse) const;
+
+    QPainterPath PainterPath(const VContainer *data) const;
+
+    QVector<quint32> MissingNodes(const VPiecePath &path) const;
+
+    int  indexOfNode(quint32 id) const;
+    void NodeOnEdge(quint32 index, VPieceNode &p1, VPieceNode &p2) const;
+    bool Contains(quint32 id) const;
+    bool OnEdge(quint32 p1, quint32 p2) const;
+    int  Edge(quint32 p1, quint32 p2) const;
+
+    QVector<VPieceNode> ListNodePoint() const;
+
+    VPiecePath RemoveEdge(quint32 index) const;
+
+    VSAPoint StartSegment(const VContainer *data, int i, bool reverse) const;
+    VSAPoint EndSegment(const VContainer *data, int i, bool reverse) const;
+
+    QPointF NodePreviousPoint(const VContainer *data, int i) const;
+    QPointF NodeNextPoint(const VContainer *data, int i) const;
+
+    static VSAPoint StartSegment(const VContainer *data, const QVector<VPieceNode> &nodes, int i, bool reverse);
+    static VSAPoint EndSegment(const VContainer *data, const QVector<VPieceNode> &nodes, int i, bool reverse);
+
+    static VSAPoint PreparePointEkv(const VPieceNode &node, const VContainer *data);
+
+    static QVector<VSAPoint> CurveSeamAllowanceSegment(const VContainer *data, const QVector<VPieceNode> &nodes,
+                                                       const QSharedPointer<VAbstractCurve> &curve,
+                                                       int i, bool reverse, qreal width);
+
+private:
+    QSharedDataPointer<VPiecePathData> d;
+};
+
+Q_DECLARE_TYPEINFO(VPiecePath, Q_MOVABLE_TYPE);
+
+#endif // VPIECEPATH_H
diff --git a/src/libs/vpatterndb/vpiecepath_p.h b/src/libs/vpatterndb/vpiecepath_p.h
new file mode 100644
index 000000000..1ad364ce9
--- /dev/null
+++ b/src/libs/vpatterndb/vpiecepath_p.h
@@ -0,0 +1,83 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   22 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VPIECEPATH_P_H
+#define VPIECEPATH_P_H
+
+#include <QSharedData>
+#include <QVector>
+
+#include "../vmisc/diagnostic.h"
+#include "vpiecenode.h"
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Weffc++")
+
+class VPiecePathData : public QSharedData
+{
+public:
+    VPiecePathData()
+        : m_nodes(),
+          m_type(PiecePathType::Unknown),
+          m_name(),
+          m_penType(Qt::SolidLine)
+    {}
+
+    explicit VPiecePathData(PiecePathType type)
+        : m_nodes(),
+          m_type(type),
+          m_name(),
+          m_penType(Qt::SolidLine)
+    {}
+
+    VPiecePathData(const VPiecePathData &path)
+        : QSharedData(path),
+          m_nodes(path.m_nodes),
+          m_type(path.m_type),
+          m_name(path.m_name),
+          m_penType(path.m_penType)
+    {}
+
+    ~VPiecePathData();
+
+    QVector<VPieceNode> m_nodes;
+    PiecePathType m_type;
+    QString m_name;
+    Qt::PenStyle m_penType;
+
+private:
+    VPiecePathData &operator=(const VPiecePathData &) Q_DECL_EQ_DELETE;
+};
+
+VPiecePathData::~VPiecePathData()
+{}
+
+QT_WARNING_POP
+
+#endif // VPIECEPATH_P_H
+
diff --git a/src/libs/vpatterndb/vtranslatevars.cpp b/src/libs/vpatterndb/vtranslatevars.cpp
index e3b51c091..2fce248c3 100644
--- a/src/libs/vpatterndb/vtranslatevars.cpp
+++ b/src/libs/vpatterndb/vtranslatevars.cpp
@@ -388,6 +388,8 @@ void VTranslateVars::InitVariables()
                                               "Do not add symbol _ to the end of the name"));
     variables.insert(seg_, translate("VTranslateVars", "Seg_", "Segment. Left symbol _ in the name"));
     variables.insert(currentLength, translate("VTranslateVars", "CurrentLength", "Do not add space between words"));
+    variables.insert(currentSeamAllowance, translate("VTranslateVars", "CurrentSeamAllowance",
+                                                     "Do not add space between words"));
     variables.insert(c1LengthSpl_, translate("VTranslateVars", "C1LengthSpl_", "Left symbol _ in the name"));
     variables.insert(c2LengthSpl_, translate("VTranslateVars", "C2LengthSpl_", "Left symbol _ in the name"));
     variables.insert(c1LengthSplPath, translate("VTranslateVars", "C1LengthSplPath",
diff --git a/src/libs/vtools/dialogs/dialogs.pri b/src/libs/vtools/dialogs/dialogs.pri
index 9b3ae9de4..d21b0a6ba 100644
--- a/src/libs/vtools/dialogs/dialogs.pri
+++ b/src/libs/vtools/dialogs/dialogs.pri
@@ -1,129 +1,131 @@
-# ADD TO EACH PATH $$PWD VARIABLE!!!!!!
-# This need for corect working file translations.pro
-
-HEADERS += \
-    $$PWD/tooldialogs.h \
-    $$PWD/tools/dialogalongline.h \
-    $$PWD/tools/dialogarc.h \
-    $$PWD/tools/dialogarcwithlength.h \
-    $$PWD/tools/dialogbisector.h \
-    $$PWD/tools/dialogcurveintersectaxis.h \
-    $$PWD/tools/dialogcutarc.h \
-    $$PWD/tools/dialogcutspline.h \
-    $$PWD/tools/dialogcutsplinepath.h \
-    $$PWD/tools/dialogdetail.h \
-    $$PWD/tools/dialogendline.h \
-    $$PWD/tools/dialogheight.h \
-    $$PWD/tools/dialogline.h \
-    $$PWD/tools/dialoglineintersect.h \
-    $$PWD/tools/dialoglineintersectaxis.h \
-    $$PWD/tools/dialognormal.h \
-    $$PWD/tools/dialogpointfromarcandtangent.h \
-    $$PWD/tools/dialogpointfromcircleandtangent.h \
-    $$PWD/tools/dialogpointofcontact.h \
-    $$PWD/tools/dialogpointofintersection.h \
-    $$PWD/tools/dialogpointofintersectionarcs.h \
-    $$PWD/tools/dialogpointofintersectioncircles.h \
-    $$PWD/tools/dialogshoulderpoint.h \
-    $$PWD/tools/dialogsinglepoint.h \
-    $$PWD/tools/dialogspline.h \
-    $$PWD/tools/dialogsplinepath.h \
-    $$PWD/tools/dialogtool.h \
-    $$PWD/tools/dialogtriangle.h \
-    $$PWD/tools/dialoguniondetails.h \
-    $$PWD/support/dialogeditwrongformula.h \
-    $$PWD/support/dialogundo.h \
-    $$PWD/tools/dialogtruedarts.h \
-    $$PWD/tools/dialogpointofintersectioncurves.h \
-    $$PWD/tools/dialogcubicbezier.h \
-    $$PWD/tools/dialogcubicbezierpath.h \
-    $$PWD/tools/dialoggroup.h \
-    $$PWD/tools/dialogrotation.h \
-    $$PWD/tools/dialogflippingbyline.h \
-    $$PWD/tools/dialogflippingbyaxis.h \
-    $$PWD/tools/dialogmove.h \
-    $$PWD/tools/dialogellipticalarc.h
-
-
-SOURCES += \
-    $$PWD/tools/dialogalongline.cpp \
-    $$PWD/tools/dialogarc.cpp \
-    $$PWD/tools/dialogarcwithlength.cpp \
-    $$PWD/tools/dialogbisector.cpp \
-    $$PWD/tools/dialogcurveintersectaxis.cpp \
-    $$PWD/tools/dialogcutarc.cpp \
-    $$PWD/tools/dialogcutspline.cpp \
-    $$PWD/tools/dialogcutsplinepath.cpp \
-    $$PWD/tools/dialogdetail.cpp \
-    $$PWD/tools/dialogendline.cpp \
-    $$PWD/tools/dialogheight.cpp \
-    $$PWD/tools/dialogline.cpp \
-    $$PWD/tools/dialoglineintersect.cpp \
-    $$PWD/tools/dialoglineintersectaxis.cpp \
-    $$PWD/tools/dialognormal.cpp \
-    $$PWD/tools/dialogpointfromarcandtangent.cpp \
-    $$PWD/tools/dialogpointfromcircleandtangent.cpp \
-    $$PWD/tools/dialogpointofcontact.cpp \
-    $$PWD/tools/dialogpointofintersection.cpp \
-    $$PWD/tools/dialogpointofintersectionarcs.cpp \
-    $$PWD/tools/dialogpointofintersectioncircles.cpp \
-    $$PWD/tools/dialogshoulderpoint.cpp \
-    $$PWD/tools/dialogsinglepoint.cpp \
-    $$PWD/tools/dialogspline.cpp \
-    $$PWD/tools/dialogsplinepath.cpp \
-    $$PWD/tools/dialogtool.cpp \
-    $$PWD/tools/dialogtriangle.cpp \
-    $$PWD/tools/dialoguniondetails.cpp \
-    $$PWD/support/dialogeditwrongformula.cpp \
-    $$PWD/support/dialogundo.cpp \
-    $$PWD/tools/dialogtruedarts.cpp \
-    $$PWD/tools/dialogpointofintersectioncurves.cpp \
-    $$PWD/tools/dialogcubicbezier.cpp \
-    $$PWD/tools/dialogcubicbezierpath.cpp \
-    $$PWD/tools/dialoggroup.cpp \
-    $$PWD/tools/dialogrotation.cpp \
-    $$PWD/tools/dialogflippingbyline.cpp \
-    $$PWD/tools/dialogflippingbyaxis.cpp \
-    $$PWD/tools/dialogmove.cpp \
-    $$PWD/tools/dialogellipticalarc.cpp
-
-FORMS += \
-    $$PWD/tools/dialogalongline.ui \
-    $$PWD/tools/dialogarc.ui \
-    $$PWD/tools/dialogarcwithlength.ui \
-    $$PWD/tools/dialogbisector.ui \
-    $$PWD/tools/dialogcurveintersectaxis.ui \
-    $$PWD/tools/dialogcutarc.ui \
-    $$PWD/tools/dialogcutspline.ui \
-    $$PWD/tools/dialogcutsplinepath.ui \
-    $$PWD/tools/dialogdetail.ui \
-    $$PWD/tools/dialogendline.ui \
-    $$PWD/tools/dialogheight.ui \
-    $$PWD/tools/dialogline.ui \
-    $$PWD/tools/dialoglineintersect.ui \
-    $$PWD/tools/dialoglineintersectaxis.ui \
-    $$PWD/tools/dialognormal.ui \
-    $$PWD/tools/dialogpointfromarcandtangent.ui \
-    $$PWD/tools/dialogpointfromcircleandtangent.ui \
-    $$PWD/tools/dialogpointofcontact.ui \
-    $$PWD/tools/dialogpointofintersection.ui \
-    $$PWD/tools/dialogpointofintersectionarcs.ui \
-    $$PWD/tools/dialogpointofintersectioncircles.ui \
-    $$PWD/tools/dialogshoulderpoint.ui \
-    $$PWD/tools/dialogsinglepoint.ui \
-    $$PWD/tools/dialogspline.ui \
-    $$PWD/tools/dialogsplinepath.ui \
-    $$PWD/tools/dialogtriangle.ui \
-    $$PWD/tools/dialoguniondetails.ui \
-    $$PWD/support/dialogeditwrongformula.ui \
-    $$PWD/support/dialogundo.ui \
-    $$PWD/tools/dialogtruedarts.ui \
-    $$PWD/tools/dialogpointofintersectioncurves.ui \
-    $$PWD/tools/dialogcubicbezier.ui \
-    $$PWD/tools/dialogcubicbezierpath.ui \
-    $$PWD/tools/dialoggroup.ui \
-    $$PWD/tools/dialogrotation.ui \
-    $$PWD/tools/dialogflippingbyline.ui \
-    $$PWD/tools/dialogflippingbyaxis.ui \
-    $$PWD/tools/dialogmove.ui \
-    $$PWD/tools/dialogellipticalarc.ui
+# ADD TO EACH PATH $$PWD VARIABLE!!!!!!
+# This need for corect working file translations.pro
+
+HEADERS += \
+    $$PWD/tooldialogs.h \
+    $$PWD/tools/dialogalongline.h \
+    $$PWD/tools/dialogarc.h \
+    $$PWD/tools/dialogarcwithlength.h \
+    $$PWD/tools/dialogbisector.h \
+    $$PWD/tools/dialogcurveintersectaxis.h \
+    $$PWD/tools/dialogcutarc.h \
+    $$PWD/tools/dialogcutspline.h \
+    $$PWD/tools/dialogcutsplinepath.h \
+    $$PWD/tools/dialogendline.h \
+    $$PWD/tools/dialogheight.h \
+    $$PWD/tools/dialogline.h \
+    $$PWD/tools/dialoglineintersect.h \
+    $$PWD/tools/dialoglineintersectaxis.h \
+    $$PWD/tools/dialognormal.h \
+    $$PWD/tools/dialogpointfromarcandtangent.h \
+    $$PWD/tools/dialogpointfromcircleandtangent.h \
+    $$PWD/tools/dialogpointofcontact.h \
+    $$PWD/tools/dialogpointofintersection.h \
+    $$PWD/tools/dialogpointofintersectionarcs.h \
+    $$PWD/tools/dialogpointofintersectioncircles.h \
+    $$PWD/tools/dialogshoulderpoint.h \
+    $$PWD/tools/dialogsinglepoint.h \
+    $$PWD/tools/dialogspline.h \
+    $$PWD/tools/dialogsplinepath.h \
+    $$PWD/tools/dialogtool.h \
+    $$PWD/tools/dialogtriangle.h \
+    $$PWD/tools/dialoguniondetails.h \
+    $$PWD/support/dialogeditwrongformula.h \
+    $$PWD/support/dialogundo.h \
+    $$PWD/tools/dialogtruedarts.h \
+    $$PWD/tools/dialogpointofintersectioncurves.h \
+    $$PWD/tools/dialogcubicbezier.h \
+    $$PWD/tools/dialogcubicbezierpath.h \
+    $$PWD/tools/dialoggroup.h \
+    $$PWD/tools/dialogrotation.h \
+    $$PWD/tools/dialogflippingbyline.h \
+    $$PWD/tools/dialogflippingbyaxis.h \
+    $$PWD/tools/dialogmove.h \
+    $$PWD/tools/dialogellipticalarc.h \
+    $$PWD/tools/dialogseamallowance.h \
+    $$PWD/tools/dialogpiecepath.h
+
+SOURCES += \
+    $$PWD/tools/dialogalongline.cpp \
+    $$PWD/tools/dialogarc.cpp \
+    $$PWD/tools/dialogarcwithlength.cpp \
+    $$PWD/tools/dialogbisector.cpp \
+    $$PWD/tools/dialogcurveintersectaxis.cpp \
+    $$PWD/tools/dialogcutarc.cpp \
+    $$PWD/tools/dialogcutspline.cpp \
+    $$PWD/tools/dialogcutsplinepath.cpp \
+    $$PWD/tools/dialogendline.cpp \
+    $$PWD/tools/dialogheight.cpp \
+    $$PWD/tools/dialogline.cpp \
+    $$PWD/tools/dialoglineintersect.cpp \
+    $$PWD/tools/dialoglineintersectaxis.cpp \
+    $$PWD/tools/dialognormal.cpp \
+    $$PWD/tools/dialogpointfromarcandtangent.cpp \
+    $$PWD/tools/dialogpointfromcircleandtangent.cpp \
+    $$PWD/tools/dialogpointofcontact.cpp \
+    $$PWD/tools/dialogpointofintersection.cpp \
+    $$PWD/tools/dialogpointofintersectionarcs.cpp \
+    $$PWD/tools/dialogpointofintersectioncircles.cpp \
+    $$PWD/tools/dialogshoulderpoint.cpp \
+    $$PWD/tools/dialogsinglepoint.cpp \
+    $$PWD/tools/dialogspline.cpp \
+    $$PWD/tools/dialogsplinepath.cpp \
+    $$PWD/tools/dialogtool.cpp \
+    $$PWD/tools/dialogtriangle.cpp \
+    $$PWD/tools/dialoguniondetails.cpp \
+    $$PWD/support/dialogeditwrongformula.cpp \
+    $$PWD/support/dialogundo.cpp \
+    $$PWD/tools/dialogtruedarts.cpp \
+    $$PWD/tools/dialogpointofintersectioncurves.cpp \
+    $$PWD/tools/dialogcubicbezier.cpp \
+    $$PWD/tools/dialogcubicbezierpath.cpp \
+    $$PWD/tools/dialoggroup.cpp \
+    $$PWD/tools/dialogrotation.cpp \
+    $$PWD/tools/dialogflippingbyline.cpp \
+    $$PWD/tools/dialogflippingbyaxis.cpp \
+    $$PWD/tools/dialogmove.cpp \
+    $$PWD/tools/dialogellipticalarc.cpp \
+    $$PWD/tools/dialogseamallowance.cpp \
+    $$PWD/tools/dialogpiecepath.cpp
+
+FORMS += \
+    $$PWD/tools/dialogalongline.ui \
+    $$PWD/tools/dialogarc.ui \
+    $$PWD/tools/dialogarcwithlength.ui \
+    $$PWD/tools/dialogbisector.ui \
+    $$PWD/tools/dialogcurveintersectaxis.ui \
+    $$PWD/tools/dialogcutarc.ui \
+    $$PWD/tools/dialogcutspline.ui \
+    $$PWD/tools/dialogcutsplinepath.ui \
+    $$PWD/tools/dialogendline.ui \
+    $$PWD/tools/dialogheight.ui \
+    $$PWD/tools/dialogline.ui \
+    $$PWD/tools/dialoglineintersect.ui \
+    $$PWD/tools/dialoglineintersectaxis.ui \
+    $$PWD/tools/dialognormal.ui \
+    $$PWD/tools/dialogpointfromarcandtangent.ui \
+    $$PWD/tools/dialogpointfromcircleandtangent.ui \
+    $$PWD/tools/dialogpointofcontact.ui \
+    $$PWD/tools/dialogpointofintersection.ui \
+    $$PWD/tools/dialogpointofintersectionarcs.ui \
+    $$PWD/tools/dialogpointofintersectioncircles.ui \
+    $$PWD/tools/dialogshoulderpoint.ui \
+    $$PWD/tools/dialogsinglepoint.ui \
+    $$PWD/tools/dialogspline.ui \
+    $$PWD/tools/dialogsplinepath.ui \
+    $$PWD/tools/dialogtriangle.ui \
+    $$PWD/tools/dialoguniondetails.ui \
+    $$PWD/support/dialogeditwrongformula.ui \
+    $$PWD/support/dialogundo.ui \
+    $$PWD/tools/dialogtruedarts.ui \
+    $$PWD/tools/dialogpointofintersectioncurves.ui \
+    $$PWD/tools/dialogcubicbezier.ui \
+    $$PWD/tools/dialogcubicbezierpath.ui \
+    $$PWD/tools/dialoggroup.ui \
+    $$PWD/tools/dialogrotation.ui \
+    $$PWD/tools/dialogflippingbyline.ui \
+    $$PWD/tools/dialogflippingbyaxis.ui \
+    $$PWD/tools/dialogmove.ui \
+    $$PWD/tools/dialogellipticalarc.ui \
+    $$PWD/tools/dialogseamallowance.ui \
+    $$PWD/tools/dialogpiecepath.ui
diff --git a/src/libs/vtools/dialogs/support/dialogeditwrongformula.cpp b/src/libs/vtools/dialogs/support/dialogeditwrongformula.cpp
index 731b3d2ab..db8590590 100644
--- a/src/libs/vtools/dialogs/support/dialogeditwrongformula.cpp
+++ b/src/libs/vtools/dialogs/support/dialogeditwrongformula.cpp
@@ -77,7 +77,7 @@ enum {ColumnName = 0, ColumnFullName};
 //---------------------------------------------------------------------------------------------------------------------
 DialogEditWrongFormula::DialogEditWrongFormula(const VContainer *data, const quint32 &toolId, QWidget *parent)
     :DialogTool(data, toolId, parent), ui(new Ui::DialogEditWrongFormula), formula(QString()), formulaBaseHeight(0),
-      checkZero(false), postfix(QString()), restoreCursor(false)
+      checkZero(false), checkLessThanZero(false), postfix(QString()), restoreCursor(false)
 {
     ui->setupUi(this);
     InitVariables();
@@ -156,7 +156,8 @@ void DialogEditWrongFormula::EvalFormula()
 {
     SCASSERT(plainTextEditFormula != nullptr)
     SCASSERT(labelResultCalculation != nullptr)
-    Eval(plainTextEditFormula->toPlainText(), flagFormula, labelResultCalculation, postfix, checkZero);
+    Eval(plainTextEditFormula->toPlainText(), flagFormula, labelResultCalculation, postfix, checkZero,
+         checkLessThanZero);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -383,6 +384,12 @@ void DialogEditWrongFormula::setCheckZero(bool value)
     checkZero = value;
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+void DialogEditWrongFormula::setCheckLessThanZero(bool value)
+{
+
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 void DialogEditWrongFormula::setPostfix(const QString &value)
 {
diff --git a/src/libs/vtools/dialogs/support/dialogeditwrongformula.h b/src/libs/vtools/dialogs/support/dialogeditwrongformula.h
index 247aeb33c..41b623bdd 100644
--- a/src/libs/vtools/dialogs/support/dialogeditwrongformula.h
+++ b/src/libs/vtools/dialogs/support/dialogeditwrongformula.h
@@ -70,6 +70,7 @@ public:
     QString      GetFormula() const;
     void         SetFormula(const QString &value);
     void         setCheckZero(bool value);
+    void         setCheckLessThanZero(bool value);
     void         setPostfix(const QString &value);
 public slots:
     virtual void DialogAccepted() Q_DECL_OVERRIDE;
@@ -109,6 +110,7 @@ private:
     int formulaBaseHeight;
 
     bool checkZero;
+    bool checkLessThanZero;
     QString postfix;
     bool restoreCursor;
 
diff --git a/src/libs/vtools/dialogs/tooldialogs.h b/src/libs/vtools/dialogs/tooldialogs.h
index 1090e905d..b42272af1 100644
--- a/src/libs/vtools/dialogs/tooldialogs.h
+++ b/src/libs/vtools/dialogs/tooldialogs.h
@@ -33,7 +33,7 @@
 #include "tools/dialogarc.h"
 #include "tools/dialogarcwithlength.h"
 #include "tools/dialogbisector.h"
-#include "tools/dialogdetail.h"
+#include "tools/dialogseamallowance.h"
 #include "tools/dialogendline.h"
 #include "tools/dialogline.h"
 #include "tools/dialoglineintersect.h"
@@ -66,6 +66,7 @@
 #include "tools/dialogflippingbyaxis.h"
 #include "tools/dialogmove.h"
 #include "tools/dialogellipticalarc.h"
+#include "tools/dialogpiecepath.h"
 
 #include "support/dialogeditwrongformula.h"
 #include "support/dialogundo.h"
diff --git a/src/libs/vtools/dialogs/tools/dialogdetail.cpp b/src/libs/vtools/dialogs/tools/dialogdetail.cpp
deleted file mode 100644
index 75561d9a6..000000000
--- a/src/libs/vtools/dialogs/tools/dialogdetail.cpp
+++ /dev/null
@@ -1,1046 +0,0 @@
-/************************************************************************
- **
- **  @file   dialogdetail.cpp
- **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   November 15, 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
- **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
- **
- *************************************************************************/
-
-#include "dialogdetail.h"
-
-#include <QtNumeric>
-#include <QBuffer>
-#include <QByteArray>
-#include <QCheckBox>
-#include <QComboBox>
-#include <QDialogButtonBox>
-#include <QDoubleSpinBox>
-#include <QFlags>
-#include <QFont>
-#include <QIcon>
-#include <QLabel>
-#include <QLatin1String>
-#include <QLineEdit>
-#include <QList>
-#include <QListWidget>
-#include <QListWidgetItem>
-#include <QMessageLogger>
-#include <QPixmap>
-#include <QPointF>
-#include <QPushButton>
-#include <QSharedPointer>
-#include <QSize>
-#include <QSpinBox>
-#include <QTabWidget>
-#include <QToolButton>
-#include <QVariant>
-#include <QVector>
-#include <Qt>
-#include <QtDebug>
-#include <new>
-
-#include "../ifc/xml/vdomdocument.h"
-#include "../vpatterndb/vcontainer.h"
-#include "../vpatterndb/calculator.h"
-#include "../vgeometry/vgobject.h"
-#include "../vmisc/vabstractapplication.h"
-#include "dialogtool.h"
-#include "vnodedetail.h"
-#include "../support/dialogeditwrongformula.h"
-
-class QPointF;
-class QWidget;
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief DialogDetail create dialog
- * @param data container with data
- * @param parent parent widget
- */
-DialogDetail::DialogDetail(const VContainer *data, const quint32 &toolId, QWidget *parent)
-    :DialogTool(data, toolId, parent), ui(), detail(VDetail()), supplement(true), closed(true), flagWidth(true),
-      m_bAddMode(true), m_qslMaterials(), m_qslPlacements(), m_conMCP(), m_oldData(), m_oldGeom(), m_oldGrainline(),
-      m_iRotBaseHeight(0), m_iLenBaseHeight(0)
-{
-    ui.setupUi(this);
-
-#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
-    ui.lineEditName->setClearButtonEnabled(true);
-    ui.lineEditLetter->setClearButtonEnabled(true);
-#endif
-
-    ui.checkBoxForbidFlipping->setChecked(qApp->Settings()->GetForbidWorkpieceFlipping());
-
-    labelEditNamePoint = ui.labelEditName;
-    ui.labelUnit->setText( VDomDocument::UnitsToStr(qApp->patternUnit(), true));
-    ui.labelUnitX->setText(VDomDocument::UnitsToStr(qApp->patternUnit(), true));
-    ui.labelUnitY->setText(VDomDocument::UnitsToStr(qApp->patternUnit(), true));
-
-    if(qApp->patternUnit() == Unit::Inch)
-    {
-        ui.doubleSpinBoxSeams->setDecimals(5);
-    }
-    // Default value for seam allowance is 1 cm. But pattern have different units, so just set 1 in dialog not enough.
-    ui.doubleSpinBoxSeams->setValue(UnitConvertor(1, Unit::Cm, qApp->patternUnit()));
-
-    bOk = ui.buttonBox->button(QDialogButtonBox::Ok);
-    SCASSERT(bOk != nullptr)
-    connect(bOk, &QPushButton::clicked, this, &DialogTool::DialogAccepted);
-    QPushButton *bCancel = ui.buttonBox->button(QDialogButtonBox::Cancel);
-    SCASSERT(bCancel != nullptr)
-    connect(bCancel, &QPushButton::clicked, this, &DialogTool::DialogRejected);
-
-    flagName = true;//We have default name of detail.
-    ChangeColor(labelEditNamePoint, okColor);
-    CheckState();
-
-    connect(ui.listWidget, &QListWidget::currentRowChanged, this, &DialogDetail::ObjectChanged);
-    connect(ui.doubleSpinBoxBiasX,  static_cast<void (QDoubleSpinBox::*)(qreal)>(&QDoubleSpinBox::valueChanged),
-            this, &DialogDetail::BiasXChanged);
-    connect(ui.doubleSpinBoxBiasY,  static_cast<void (QDoubleSpinBox::*)(qreal)>(&QDoubleSpinBox::valueChanged),
-            this, &DialogDetail::BiasYChanged);
-    connect(ui.doubleSpinBoxSeams,  static_cast<void (QDoubleSpinBox::*)(qreal)>(&QDoubleSpinBox::valueChanged),
-            this, &DialogDetail::AlowenceChanged);
-    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.lineEditName, &QLineEdit::textChanged, this, &DialogDetail::NameDetailChanged);
-
-    connect(ui.toolButtonDelete, &QToolButton::clicked, this, &DialogDetail::DeleteItem);
-    connect(ui.toolButtonUp, &QToolButton::clicked, this, &DialogDetail::ScrollUp);
-    connect(ui.toolButtonDown, &QToolButton::clicked, this, &DialogDetail::ScrollDown);
-
-    m_qslMaterials << QApplication::translate("Detail", "Fabric", 0)
-                   << QApplication::translate("Detail", "Lining", 0)
-                   << QApplication::translate("Detail", "Interfacing", 0)
-                   << QApplication::translate("Detail", "Interlining", 0);
-
-    for (int i = 0; i < m_qslMaterials.count(); ++i)
-    {
-        ui.comboBoxMaterial->addItem(m_qslMaterials[i], i);
-    }
-
-    QStringList qsl = qApp->Settings()->GetUserDefinedMaterials();
-    for (int i = 0; i < qsl.count(); ++i)
-    {
-        ui.comboBoxMaterial->addItem(qsl[i], int(MaterialType::mtUserDefined));
-    }
-
-    m_qslPlacements << tr("None") << tr("Cut on fold");
-    ui.comboBoxPlacement->addItems(m_qslPlacements);
-    ui.pushButtonRot->setIcon(QIcon("://icon/16x16/fx.png"));
-    ui.pushButtonLen->setIcon(QIcon("://icon/16x16/fx.png"));
-
-    connect(ui.pushButtonAdd, &QPushButton::clicked, this, &DialogDetail::AddUpdate);
-    connect(ui.pushButtonCancel, &QPushButton::clicked, this, &DialogDetail::Cancel);
-    connect(ui.pushButtonRemove, &QPushButton::clicked, this, &DialogDetail::Remove);
-    connect(ui.listWidgetMCP, &QListWidget::itemClicked, this, &DialogDetail::SetEditMode);
-    connect(ui.comboBoxMaterial, &QComboBox::currentTextChanged, this, &DialogDetail::MaterialChanged);
-    connect(ui.checkBoxGrainline, &QCheckBox::toggled, this, &DialogDetail::EnableGrainlineRotation);
-    connect(ui.pushButtonRot, &QPushButton::clicked, this, &DialogDetail::EditFormula);
-    connect(ui.pushButtonLen, &QPushButton::clicked, this, &DialogDetail::EditFormula);
-    connect(ui.lineEditLenFormula, &QPlainTextEdit::textChanged, this, &DialogDetail::UpdateValues);
-    connect(ui.lineEditRotFormula, &QPlainTextEdit::textChanged, this, &DialogDetail::UpdateValues);
-
-    connect(ui.pushButtonShowRot, &QPushButton::clicked, this, &DialogDetail::DeployRotation);
-    connect(ui.pushButtonShowLen, &QPushButton::clicked, this, &DialogDetail::DeployLength);
-
-    SetAddMode();
-    EnableGrainlineRotation();
-
-    ui.comboBoxArrow->addItem(tr("Both"));
-    ui.comboBoxArrow->addItem(tr("Just front"));
-    ui.comboBoxArrow->addItem(tr("Just rear"));
-
-    ui.tabWidget->setCurrentIndex(0);
-
-    m_iRotBaseHeight = ui.lineEditRotFormula->height();
-    m_iLenBaseHeight = ui.lineEditLenFormula->height();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief ChoosedObject gets id and type of selected object. Save right data and ignore wrong.
- * @param id id of objects (points, arcs, splines, spline paths)
- * @param type type of object
- */
-void DialogDetail::ChosenObject(quint32 id, const SceneObject &type)
-{
-    if (type != SceneObject::Line && type != SceneObject::Detail)
-    {
-        switch (type)
-        {
-            case (SceneObject::Arc):
-                NewItem(id, Tool::NodeArc, NodeDetail::Contour);
-                break;
-            case (SceneObject::ElArc):
-                NewItem(id, Tool::NodeElArc, NodeDetail::Contour);
-                break;
-            case (SceneObject::Point):
-                NewItem(id, Tool::NodePoint, NodeDetail::Contour);
-                break;
-            case (SceneObject::Spline):
-                NewItem(id, Tool::NodeSpline, NodeDetail::Contour);
-                break;
-            case (SceneObject::SplinePath):
-                NewItem(id, Tool::NodeSplinePath, NodeDetail::Contour);
-                break;
-            case (SceneObject::Line):
-            case (SceneObject::Detail):
-            case (SceneObject::Unknown):
-            default:
-                qDebug()<<tr("Got wrong scene object. Ignore.");
-                break;
-        }
-
-        if (ui.listWidget->count() > 0)
-        {
-            EnableObjectGUI(true);
-        }
-
-        ValidObjects(DetailIsValid());
-        // Fix issue #526. Dialog Detail is not on top after selection second object on Mac.
-        setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
-        this->show();
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::SaveData()
-{
-    detail.Clear();
-    detail = CreateDetail();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::CheckState()
-{
-    SCASSERT(bOk != nullptr)
-    bOk->setEnabled(flagFormula && flagName && flagError && flagWidth);
-    // In case dialog hasn't apply button
-    if ( bApply != nullptr)
-    {
-        bApply->setEnabled(bOk->isEnabled());
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::UpdateList()
-{
-    ui.listWidgetMCP->clear();
-    for (int i = 0; i < m_conMCP.count(); ++i)
-    {
-        MaterialCutPlacement mcp = m_conMCP.at(i);
-        QString qsText = tr("Cut %1 of %2%3").arg(mcp.m_iCutNumber);
-        if (mcp.m_eMaterial < MaterialType::mtUserDefined)
-        {
-            qsText = qsText.arg(m_qslMaterials[int(mcp.m_eMaterial)]);
-        }
-        else
-        {
-            qsText = qsText.arg(mcp.m_qsMaterialUserDef);
-        }
-        if (mcp.m_ePlacement == PlacementType::ptCutOnFold)
-        {
-            qsText = qsText.arg(QLatin1String(" ") + tr("on Fold"));
-        }
-        else
-        {
-            qsText = qsText.arg("");
-        }
-
-        ui.listWidgetMCP->addItem(qsText);
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::AddUpdate()
-{
-    MaterialCutPlacement mcp;
-    QStringList qslUserMaterials = qApp->Settings()->GetUserDefinedMaterials();
-
-#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
-    int i = ui.comboBoxMaterial->itemData(ui.comboBoxMaterial->currentIndex()).toInt();
-#else
-    int i = ui.comboBoxMaterial->currentData().toInt();
-#endif
-    QString qsMat = ui.comboBoxMaterial->currentText();
-    if (i < m_qslMaterials.count() && qsMat == m_qslMaterials[i])
-    {
-        mcp.m_eMaterial = MaterialType(i);
-        mcp.m_qsMaterialUserDef.clear();
-    }
-    else
-    {
-        mcp.m_eMaterial = MaterialType::mtUserDefined;
-        mcp.m_qsMaterialUserDef = qsMat;
-        // check if we have new user defined material
-        bool bFound = false;
-        for (int i = 0; i < qslUserMaterials.count() && bFound == false; ++i)
-        {
-            if (mcp.m_qsMaterialUserDef == qslUserMaterials[i])
-            {
-                bFound = true;
-            }
-        }
-        if (bFound == false)
-        {
-            qApp->Settings()->AddUserDefinedMaterial(mcp.m_qsMaterialUserDef);
-            qApp->Settings()->sync();
-            ui.comboBoxMaterial->addItem(mcp.m_qsMaterialUserDef, int(MaterialType::mtUserDefined));
-        }
-    }
-
-    mcp.m_iCutNumber = ui.spinBoxCutNumber->value();
-    mcp.m_ePlacement = PlacementType(ui.comboBoxPlacement->currentIndex());
-
-    if (m_bAddMode == true)
-    {
-        m_conMCP << mcp;
-    }
-    else
-    {
-        int iR = ui.listWidgetMCP->currentRow();
-        SCASSERT(iR >= 0)
-        m_conMCP[iR] = mcp;
-        SetAddMode();
-    }
-    UpdateList();
-    ClearFields();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::Cancel()
-{
-    ClearFields();
-    SetAddMode();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::Remove()
-{
-    int iR = ui.listWidgetMCP->currentRow();
-    SCASSERT(iR >= 0)
-    m_conMCP.removeAt(iR);
-    UpdateList();
-    ClearFields();
-    SetAddMode();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::NameDetailChanged()
-{
-    SCASSERT(labelEditNamePoint != nullptr)
-    QLineEdit* edit = qobject_cast<QLineEdit*>(sender());
-    if (edit)
-    {
-        if (edit->text().isEmpty())
-        {
-            flagName = false;
-            ChangeColor(labelEditNamePoint, Qt::red);
-            QIcon icon(":/icons/win.icon.theme/16x16/status/dialog-warning.png");
-            ui.tabWidget->setTabIcon(1, icon);
-        }
-        else
-        {
-            flagName = true;
-            ChangeColor(labelEditNamePoint, okColor);
-            QIcon icon;
-            ui.tabWidget->setTabIcon(1, icon);
-        }
-    }
-    CheckState();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::MaterialChanged()
-{
-    ui.pushButtonAdd->setEnabled(ui.comboBoxMaterial->currentText().isEmpty() == false);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief NewItem add new object (point, arc, spline or spline path) to list
- * @param id id of object
- * @param typeTool type of tool
- * @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, bool reverse)
-{
-    SCASSERT(id > NULL_ID)
-    QString name;
-    switch (typeTool)
-    {
-        case (Tool::NodePoint):
-        case (Tool::NodeArc):
-        case (Tool::NodeElArc):
-        case (Tool::NodeSpline):
-        case (Tool::NodeSplinePath):
-        {
-            const QSharedPointer<VGObject> obj = data->GeometricObject<VGObject>(id);
-            name = obj->name();
-            break;
-        }
-        default:
-            qDebug()<<"Got wrong tools. Ignore.";
-            return;
-    }
-
-    bool canAddNewPoint = false;
-
-    if(ui.listWidget->count() == 0)
-    {
-        canAddNewPoint = true;
-        ui.toolButtonUp->setEnabled(false);
-        ui.toolButtonDown->setEnabled(false);
-    }
-    else
-    {
-        if(RowId(ui.listWidget->count()-1) != id)
-        {
-            canAddNewPoint = true;
-        }
-        ui.toolButtonUp->setEnabled(true);
-        ui.toolButtonDown->setEnabled(true);
-    }
-
-    if(canAddNewPoint)
-    {
-        QListWidgetItem *item = new QListWidgetItem(name);
-        item->setFont(QFont("Times", 12, QFont::Bold));
-        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);
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-VDetail DialogDetail::CreateDetail() const
-{
-    VDetail detail;
-    for (qint32 i = 0; i < ui.listWidget->count(); ++i)
-    {
-        QListWidgetItem *item = ui.listWidget->item(i);
-        detail.append( qvariant_cast<VNodeDetail>(item->data(Qt::UserRole)));
-    }
-    detail.setWidth(ui.doubleSpinBoxSeams->value());
-    detail.setName(ui.lineEditName->text());
-    detail.setSeamAllowance(supplement);
-    detail.setClosed(closed);
-    detail.setForbidFlipping(ui.checkBoxForbidFlipping->isChecked());
-
-    detail.GetPatternPieceData().SetLetter(ui.lineEditLetter->text());
-
-    for (int i = 0; i < m_conMCP.count(); ++i)
-    {
-        detail.GetPatternPieceData().Append(m_conMCP[i]);
-    }
-
-    detail.GetPatternPieceData().SetPos(m_oldData.GetPos());
-    detail.GetPatternPieceData().SetLabelWidth(m_oldData.GetLabelWidth());
-    detail.GetPatternPieceData().SetLabelHeight(m_oldData.GetLabelHeight());
-    detail.GetPatternPieceData().SetFontSize(m_oldData.GetFontSize());
-    detail.GetPatternPieceData().SetRotation(m_oldData.GetRotation());
-    detail.GetPatternPieceData().SetVisible(ui.checkBoxDetail->isChecked());
-
-    detail.GetPatternInfo() = m_oldGeom;
-    detail.GetPatternInfo().SetVisible(ui.checkBoxPattern->isChecked());
-
-    detail.GetGrainlineGeometry() = m_oldGrainline;
-    detail.GetGrainlineGeometry().SetVisible(ui.checkBoxGrainline->isChecked());
-    detail.GetGrainlineGeometry().SetRotation(ui.lineEditRotFormula->toPlainText());
-    detail.GetGrainlineGeometry().SetLength(ui.lineEditLenFormula->toPlainText());
-    VGrainlineGeometry::ArrowType eAT = VGrainlineGeometry::ArrowType(ui.comboBoxArrow->currentIndex());
-    detail.GetGrainlineGeometry().SetArrowType(eAT);
-
-    return detail;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::ValidObjects(bool value)
-{
-    flagError = value;
-    CheckState();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::EnableObjectGUI(bool value)
-{
-    ui.toolButtonDelete->setEnabled(value);
-    ui.doubleSpinBoxBiasX->setEnabled(value);
-    ui.doubleSpinBoxBiasY->setEnabled(value);
-
-    if (value == false)
-    {
-        ui.checkBoxReverse->setEnabled(value);
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-quint32 DialogDetail::RowId(int i) const
-{
-    const QListWidgetItem *rowItem = ui.listWidget->item(i);
-    SCASSERT(rowItem != nullptr)
-    const VNodeDetail rowNode = qvariant_cast<VNodeDetail>(rowItem->data(Qt::UserRole));
-    return rowNode.getId();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief setDetails set detail
- * @param value detail
- */
-void DialogDetail::setDetail(const VDetail &value)
-{
-    detail = value;
-    ui.listWidget->clear();
-    for (int i = 0; i < detail.CountNode(); ++i)
-    {
-        const VNodeDetail &node = detail.at(i);
-        NewItem(node.getId(), node.getTypeTool(), node.getTypeNode(), node.getMx(),
-                node.getMy(), node.getReverse());
-    }
-    ui.lineEditName->setText(detail.getName());
-    ui.checkBoxSeams->setChecked(detail.getSeamAllowance());
-    ui.checkBoxClosed->setChecked(detail.getClosed());
-    ui.checkBoxForbidFlipping->setChecked(detail.getForbidFlipping());
-    ClickedClosed(detail.getClosed());
-    ClickedSeams(detail.getSeamAllowance());
-    ui.doubleSpinBoxSeams->setValue(detail.getWidth());
-    ui.listWidget->setCurrentRow(0);
-    ui.listWidget->setFocus(Qt::OtherFocusReason);
-    ui.toolButtonDelete->setEnabled(true);
-
-    ui.lineEditLetter->setText(detail.GetPatternPieceData().GetLetter());
-    ui.checkBoxDetail->setChecked(detail.GetPatternPieceData().IsVisible());
-    ui.checkBoxPattern->setChecked(detail.GetPatternInfo().IsVisible());
-
-    m_conMCP.clear();
-    for (int i = 0; i < detail.GetPatternPieceData().GetMCPCount(); ++i)
-    {
-        m_conMCP << detail.GetPatternPieceData().GetMCP(i);
-    }
-
-    UpdateList();
-
-    ui.checkBoxGrainline->setChecked(detail.GetGrainlineGeometry().IsVisible());
-    ui.lineEditRotFormula->setPlainText(detail.GetGrainlineGeometry().GetRotation());
-    ui.lineEditLenFormula->setPlainText(detail.GetGrainlineGeometry().GetLength());
-    ui.comboBoxArrow->setCurrentIndex(int(detail.GetGrainlineGeometry().GetArrowType()));
-
-    m_oldData = detail.GetPatternPieceData();
-    m_oldGeom = detail.GetPatternInfo();
-    m_oldGrainline = detail.GetGrainlineGeometry();
-
-    ValidObjects(DetailIsValid());
-    EnableGrainlineRotation();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief BiasXChanged changed value of offset for object respect to x
- * @param d value in mm
- */
-void DialogDetail::BiasXChanged(qreal d)
-{
-    qint32 row = ui.listWidget->currentRow();
-    QListWidgetItem *item = ui.listWidget->item( row );
-    SCASSERT(item != nullptr)
-    VNodeDetail node = qvariant_cast<VNodeDetail>(item->data(Qt::UserRole));
-    node.setMx(qApp->toPixel(d));
-    item->setData(Qt::UserRole, QVariant::fromValue(node));
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief BiasYChanged changed value of offset for object respect to y
- * @param d value in mm
- */
-void DialogDetail::BiasYChanged(qreal d)
-{
-    qint32 row = ui.listWidget->currentRow();
-    QListWidgetItem *item = ui.listWidget->item( row );
-    SCASSERT(item != nullptr)
-    VNodeDetail node = qvariant_cast<VNodeDetail>(item->data(Qt::UserRole));
-    node.setMy(qApp->toPixel(d));
-    item->setData(Qt::UserRole, QVariant::fromValue(node));
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::AlowenceChanged(qreal d)
-{
-    if (ui.doubleSpinBoxSeams->isEnabled())
-    {
-        if (d <= 0)
-        {
-            flagWidth = false;
-            ChangeColor(ui.labelEditWidth, errorColor);
-        }
-        else
-        {
-            flagWidth = true;
-            ChangeColor(ui.labelEditWidth, okColor);
-        }
-        CheckState();
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief ClickedSeams save supplement of seams for detail
- * @param checked 1 - need supplement, 0 - don't need supplement
- */
-void DialogDetail::ClickedSeams(bool checked)
-{
-    supplement = checked;
-    ui.checkBoxClosed->setEnabled(checked);
-    ui.doubleSpinBoxSeams->setEnabled(checked);
-
-    if (checked && ui.doubleSpinBoxSeams->value() <= 0)
-    {
-        flagWidth = false;
-        ChangeColor(ui.labelEditWidth, errorColor);
-    }
-    else
-    {
-        flagWidth = true;
-        ChangeColor(ui.labelEditWidth, okColor);
-    }
-    CheckState();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief ClickedClosed save closed equdistant or not
- * @param checked 1 - closed, 0 - don't closed
- */
-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));
-    ValidObjects(DetailIsValid());
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief ObjectChanged changed new object (point, arc, spline or spline path) form list
- * @param row number of row
- */
-void DialogDetail::ObjectChanged(int row)
-{
-    if (ui.listWidget->count() == 0 || row == -1 || row >= ui.listWidget->count())
-    {
-        return;
-    }
-    const QListWidgetItem *item = ui.listWidget->item( row );
-    SCASSERT(item != nullptr)
-    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());
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief DeleteItem delete item from list
- */
-void DialogDetail::DeleteItem()
-{
-    if (ui.listWidget->count() == 1)
-    {
-        EnableObjectGUI(false);
-    }
-
-    delete ui.listWidget->item(ui.listWidget->currentRow());
-    ValidObjects(DetailIsValid());
-
-    if(ui.listWidget->count() < 2)
-    {
-        ui.toolButtonUp->setEnabled(false);
-        ui.toolButtonDown->setEnabled(false);
-    }
-    else
-    {
-        ui.toolButtonUp->setEnabled(true);
-        ui.toolButtonDown->setEnabled(true);
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::ScrollUp()
-{
-    if (ui.listWidget->count() > 1)
-    {
-        QListWidgetItem *item = ui.listWidget->takeItem(0);
-        ui.listWidget->addItem(item);
-        ValidObjects(DetailIsValid());
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::ScrollDown()
-{
-    if (ui.listWidget->count() > 1)
-    {
-        QListWidgetItem *item = ui.listWidget->takeItem(ui.listWidget->count()-1);
-        ui.listWidget->insertItem(0, item);
-        ValidObjects(DetailIsValid());
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-bool DialogDetail::DetailIsValid() const
-{
-    const QIcon icon = QIcon::fromTheme("dialog-warning",
-                                  QIcon(":/icons/win.icon.theme/16x16/status/dialog-warning.png"));
-
-    const QPixmap pixmap = icon.pixmap(QSize(16, 16));
-    QByteArray byteArray;
-    QBuffer buffer(&byteArray);
-    pixmap.save(&buffer, "PNG");
-    QString url = QString("<img src=\"data:image/png;base64,") + byteArray.toBase64() + QLatin1String("\"/> ");
-
-    if(CreateDetail().ContourPoints(data).count() < 3)
-    {
-        url += tr("You need more points!");
-        ui.helpLabel->setText(url);
-        return false;
-    }
-    else
-    {
-        if(not DetailIsClockwise())
-        {
-            url += tr("You have to choose points in a clockwise direction!");
-            ui.helpLabel->setText(url);
-            return false;
-        }
-        if (FirstPointEqualLast())
-        {
-            url += tr("First point cannot be equal to the last point!");
-            ui.helpLabel->setText(url);
-            return false;
-        }
-        else
-        {
-            for (int i=0, sz = ui.listWidget->count()-1; i<sz; ++i)
-            {
-                if (RowId(i) == RowId(i+1))
-                {
-                    url += tr("You have double points!");
-                    ui.helpLabel->setText(url);
-                    return false;
-                }
-            }
-        }
-    }
-    ui.helpLabel->setText(tr("Ready!"));
-    return true;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-bool DialogDetail::FirstPointEqualLast() const
-{
-    if (ui.listWidget->count() > 1)
-    {
-        if (RowId(0) == RowId(ui.listWidget->count()-1))
-        {
-            return true;
-        }
-        else
-        {
-            return false;
-        }
-    }
-    return false;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-bool DialogDetail::DetailIsClockwise() const
-{
-    const QVector<QPointF> points = CreateDetail().ContourPoints(data);
-
-    if(points.count() < 3)
-    {
-        return false;
-    }
-
-    const qreal res = VDetail::SumTrapezoids(points);
-    if (res < 0)
-    {
-        return true;
-    }
-    return false;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::ClearFields()
-{
-    ui.comboBoxMaterial->setCurrentIndex(0);
-    ui.spinBoxCutNumber->setValue(0);
-    ui.comboBoxPlacement->setCurrentIndex(0);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::UpdateValues()
-{
-    QPlainTextEdit* apleSender[2];
-    apleSender[0] = ui.lineEditRotFormula;
-    apleSender[1] = ui.lineEditLenFormula;
-    bool bFormulasOK = true;
-
-    for (int i = 0; i < 2; ++i)
-    {
-        QLabel* plbVal;
-        QLabel* plbText;
-        QString qsUnit;
-        if (i == 0)
-        {
-            plbVal = ui.labelRot;
-            plbText = ui.labelEditRot;
-            QChar ch(0x00b0);
-            qsUnit = ch;
-        }
-        else
-        {
-            plbVal = ui.labelLen;
-            plbText = ui.labelEditLen;
-            qsUnit = " " + VDomDocument::UnitsToStr(qApp->patternUnit());
-        }
-
-        QString qsFormula = apleSender[i]->toPlainText().simplified();
-        Calculator cal;
-        QString qsVal;
-        try
-        {
-            qsFormula.replace("\n", " ");
-            qsFormula = qApp->TrVars()->FormulaFromUser(qsFormula, qApp->Settings()->GetOsSeparator());
-            qreal dVal;
-            dVal = cal.EvalFormula(data->PlainVariables(), qsFormula);
-            if (qIsInf(dVal) == true || qIsNaN(dVal) == true)
-            {
-                throw qmu::QmuParserError(tr("Infinite/undefined result"));
-            }
-            else if (i == 1 && dVal <= 0.0)
-            {
-                throw qmu::QmuParserError(tr("Length should be positive"));
-            }
-            else
-            {
-                qsVal.setNum(dVal, 'f', 2);
-                ChangeColor(plbText, okColor);
-            }
-        }
-        catch (...)
-        {
-            qsVal.clear();
-            ChangeColor(plbText, Qt::red);
-            bFormulasOK = false;
-        }
-
-        if (qsVal.isEmpty() == false)
-        {
-            qsVal += qsUnit;
-        }
-        plbVal->setText(qsVal);
-    }
-
-    bOk->setEnabled(bFormulasOK);
-    if (bFormulasOK == false)
-    {
-        QIcon icon(":/icons/win.icon.theme/16x16/status/dialog-warning.png");
-        ui.tabWidget->setTabIcon(2, icon);
-    }
-    else
-    {
-        ResetWarning();
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::SetAddMode()
-{
-    ui.pushButtonAdd->setText(tr("Add"));
-    ui.pushButtonCancel->hide();
-    ui.pushButtonRemove->hide();
-    ui.listWidgetMCP->setCurrentRow(-1);
-    m_bAddMode = true;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::SetEditMode()
-{
-    int iR = ui.listWidgetMCP->currentRow();
-    // this method can be called by clicking on item or by update. In the latter case there is nothing else to do!
-    if (iR < 0 || iR >= m_conMCP.count())
-    {
-        return;
-    }
-
-    ui.pushButtonAdd->setText(tr("Update"));
-    ui.pushButtonCancel->show();
-    ui.pushButtonRemove->show();
-
-    MaterialCutPlacement mcp = m_conMCP.at(iR);
-    if (mcp.m_eMaterial == MaterialType::mtUserDefined)
-    {
-        int iRow = qApp->Settings()->GetUserDefinedMaterials().indexOf(mcp.m_qsMaterialUserDef);
-        if (iRow >= 0)
-        {
-            ui.comboBoxMaterial->setCurrentIndex(iRow + m_qslMaterials.count());
-        }
-        else
-        {
-            ui.comboBoxMaterial->setCurrentText(mcp.m_qsMaterialUserDef);
-        }
-    }
-    else
-    {
-        ui.comboBoxMaterial->setCurrentIndex(int(mcp.m_eMaterial));
-    }
-    ui.spinBoxCutNumber->setValue(mcp.m_iCutNumber);
-    ui.comboBoxPlacement->setCurrentIndex(int(mcp.m_ePlacement));
-
-    m_bAddMode = false;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::EnableGrainlineRotation()
-{
-    ui.lineEditRotFormula->setEnabled(ui.checkBoxGrainline->isChecked());
-    ui.lineEditLenFormula->setEnabled(ui.checkBoxGrainline->isChecked());
-    ui.pushButtonRot->setEnabled(ui.checkBoxGrainline->isChecked());
-    ui.pushButtonLen->setEnabled(ui.checkBoxGrainline->isChecked());
-    ui.pushButtonShowLen->setEnabled(ui.checkBoxGrainline->isChecked());
-    ui.pushButtonShowRot->setEnabled(ui.checkBoxGrainline->isChecked());
-
-    if (ui.checkBoxGrainline->isChecked() == true)
-    {
-        UpdateValues();
-    }
-    else
-    {
-        ChangeColor(ui.labelEditLen, okColor);
-        ChangeColor(ui.labelEditRot, okColor);
-        bOk->setEnabled(true);
-        ResetWarning();
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::EditFormula()
-{
-    QPlainTextEdit* pleFormula;
-    bool bCheckZero;
-
-    if (sender() == ui.pushButtonLen)
-    {
-        pleFormula = ui.lineEditLenFormula;
-        bCheckZero = true;
-    }
-    else if (sender() == ui.pushButtonRot)
-    {
-        pleFormula = ui.lineEditRotFormula;
-        bCheckZero = false;
-    }
-    else
-    {
-        // should not get here!
-        return;
-    }
-
-    DialogEditWrongFormula dlg(data, NULL_ID, this);
-    dlg.SetFormula(pleFormula->toPlainText());
-    dlg.setCheckZero(bCheckZero);
-    if (dlg.exec() == QDialog::Accepted)
-    {
-        QString qsFormula = dlg.GetFormula();
-        qsFormula.replace("\n", " ");
-        pleFormula->setPlainText(qsFormula);
-        UpdateValues();
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::DeployRotation()
-{
-    DeployFormula(ui.lineEditRotFormula, ui.pushButtonShowRot, m_iRotBaseHeight);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::DeployLength()
-{
-    DeployFormula(ui.lineEditLenFormula, ui.pushButtonShowLen, m_iLenBaseHeight);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void DialogDetail::ResetWarning()
-{
-    QIcon icon;
-    ui.tabWidget->setTabIcon(2, icon);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-
diff --git a/src/libs/vtools/dialogs/tools/dialogdetail.h b/src/libs/vtools/dialogs/tools/dialogdetail.h
deleted file mode 100644
index cecc051d7..000000000
--- a/src/libs/vtools/dialogs/tools/dialogdetail.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/************************************************************************
- **
- **  @file   dialogdetail.h
- **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   November 15, 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
- **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
- **
- *************************************************************************/
-
-#ifndef DIALOGDETAIL_H
-#define DIALOGDETAIL_H
-
-#include <qcompilerdetection.h>
-#include <QMetaObject>
-#include <QObject>
-#include <QString>
-#include <QStringList>
-#include <QtGlobal>
-
-#include "../vmisc/def.h"
-#include "../vpatterndb/vdetail.h"
-#include "../vpatterndb/vpatterninfogeometry.h"
-#include "../vpatterndb/vpatternpiecedata.h"
-#include "../vpatterndb/vgrainlinegeometry.h"
-#include "dialogtool.h"
-#include "ui_dialogdetail.h"
-
-class QWidget;
-class VContainer;
-
-/**
- * @brief The DialogDetail class dialog for ToolDetai. Help create detail and edit option.
- */
-class DialogDetail : public DialogTool
-{
-    Q_OBJECT
-public:
-    DialogDetail(const VContainer *data, const quint32 &toolId, QWidget *parent = nullptr);
-
-    VDetail          getDetail() const;
-    void             setDetail(const VDetail &value);
-public slots:
-    virtual void     ChosenObject(quint32 id, const SceneObject &type) Q_DECL_OVERRIDE;
-    void             BiasXChanged(qreal d);
-    void             BiasYChanged(qreal d);
-    void             AlowenceChanged(qreal d);
-    void             ClickedSeams(bool checked);
-    void             ClickedClosed(bool checked);
-    void             ClickedReverse(bool checked);
-    void             ObjectChanged(int row);
-    void             DeleteItem();
-    void             ScrollUp();
-    void             ScrollDown();
-protected:
-    /**
-     * @brief SaveData Put dialog data in local variables
-     */
-    virtual void     SaveData() Q_DECL_OVERRIDE;
-    virtual void     CheckState() Q_DECL_OVERRIDE;
-
-protected slots:
-    void             UpdateList();
-    void             AddUpdate();
-    void             Cancel();
-    void             Remove();
-
-private slots:
-    void             NameDetailChanged();
-    void             MaterialChanged();
-private:
-
-    /** @brief ui keeps information about user interface */
-    Ui::DialogDetail ui;
-
-    /** @brief detail detail */
-    VDetail          detail;
-
-    /** @brief supplement keep option supplement of seams */
-    bool             supplement;
-
-    /** @brief closed keep option about equdistant (closed or not) */
-    bool             closed;
-    bool             flagWidth;
-    bool             m_bAddMode;
-
-    QStringList      m_qslMaterials;
-    QStringList      m_qslPlacements;
-    // temporary container for Material/Cut/Placement 3-tuples
-    MCPContainer     m_conMCP;
-    VPatternPieceData       m_oldData;
-    VPatternInfoGeometry    m_oldGeom;
-    VGrainlineGeometry      m_oldGrainline;
-    int                     m_iRotBaseHeight;
-    int                     m_iLenBaseHeight;
-
-
-    bool             DetailIsValid() const;
-    bool             FirstPointEqualLast() const;
-    bool             DetailIsClockwise() const;
-
-    void             NewItem(quint32 id, const Tool &typeTool, const NodeDetail &typeNode,
-                             qreal mx = 0, qreal my = 0, bool reverse = false);
-    VDetail          CreateDetail() const;
-    void             ValidObjects(bool value);
-    void             EnableObjectGUI(bool value);
-
-    void             ClearFields();
-
-    quint32          RowId(int i) const;
-
-private slots:
-    void             UpdateValues();
-    void             SetAddMode();
-    void             SetEditMode();
-    void             EnableGrainlineRotation();
-    void             EditFormula();
-    void             DeployRotation();
-    void             DeployLength();
-    void             ResetWarning();
-};
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief getDetails return detail
- * @return detail
- */
-inline VDetail DialogDetail::getDetail() const
-{
-    return detail;
-}
-
-#endif // DIALOGDETAIL_H
diff --git a/src/libs/vtools/dialogs/tools/dialogdetail.ui b/src/libs/vtools/dialogs/tools/dialogdetail.ui
deleted file mode 100644
index 7198fcea0..000000000
--- a/src/libs/vtools/dialogs/tools/dialogdetail.ui
+++ /dev/null
@@ -1,1122 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>DialogDetail</class>
- <widget class="QDialog" name="DialogDetail">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>581</width>
-    <height>478</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Seam allowance tool</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="../../../vmisc/share/resources/icon.qrc">
-    <normaloff>:/icon/64x64/icon64x64.png</normaloff>:/icon/64x64/icon64x64.png</iconset>
-  </property>
-  <property name="locale">
-   <locale language="English" country="UnitedStates"/>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout_7">
-   <item>
-    <widget class="QTabWidget" name="tabWidget">
-     <property name="currentIndex">
-      <number>2</number>
-     </property>
-     <widget class="QWidget" name="tab">
-      <attribute name="title">
-       <string>General</string>
-      </attribute>
-      <layout class="QVBoxLayout" name="verticalLayout_3">
-       <item>
-        <layout class="QHBoxLayout" name="horizontalLayout_8">
-         <item>
-          <widget class="QLabel" name="label_3">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="text">
-            <string/>
-           </property>
-           <property name="pixmap">
-            <pixmap resource="../../../vmisc/share/resources/icon.qrc">:/icon/32x32/clockwise.png</pixmap>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QLabel" name="label_4">
-           <property name="text">
-            <string>All objects in path should follow in clockwise direction.</string>
-           </property>
-           <property name="wordWrap">
-            <bool>true</bool>
-           </property>
-          </widget>
-         </item>
-        </layout>
-       </item>
-       <item>
-        <widget class="QSplitter" name="splitter_2">
-         <property name="orientation">
-          <enum>Qt::Horizontal</enum>
-         </property>
-         <widget class="QWidget" name="layoutWidget">
-          <layout class="QVBoxLayout" name="verticalLayout_2">
-           <item>
-            <layout class="QHBoxLayout" name="horizontalLayout_3">
-             <property name="spacing">
-              <number>6</number>
-             </property>
-             <property name="sizeConstraint">
-              <enum>QLayout::SetDefaultConstraint</enum>
-             </property>
-             <property name="leftMargin">
-              <number>0</number>
-             </property>
-             <property name="topMargin">
-              <number>0</number>
-             </property>
-             <item>
-              <widget class="QLabel" name="label">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                 <horstretch>1</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-               <property name="text">
-                <string>Bias X:</string>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QDoubleSpinBox" name="doubleSpinBoxBiasX">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-                 <horstretch>1</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-               <property name="minimum">
-                <double>-900.990000000000009</double>
-               </property>
-               <property name="maximum">
-                <double>900.990000000000009</double>
-               </property>
-               <property name="singleStep">
-                <double>0.100000000000000</double>
-               </property>
-               <property name="value">
-                <double>0.000000000000000</double>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QLabel" name="labelUnitX">
-               <property name="text">
-                <string>cm</string>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </item>
-           <item>
-            <layout class="QHBoxLayout" name="horizontalLayout_4">
-             <item>
-              <widget class="QLabel" name="label_2">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                 <horstretch>1</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-               <property name="text">
-                <string>Bias Y:</string>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QDoubleSpinBox" name="doubleSpinBoxBiasY">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-                 <horstretch>1</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-               <property name="minimum">
-                <double>-900.990000000000009</double>
-               </property>
-               <property name="maximum">
-                <double>900.990000000000009</double>
-               </property>
-               <property name="singleStep">
-                <double>0.100000000000000</double>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QLabel" name="labelUnitY">
-               <property name="text">
-                <string>cm</string>
-               </property>
-              </widget>
-             </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">
-              <string>Options</string>
-             </property>
-             <layout class="QVBoxLayout" name="verticalLayout">
-              <item>
-               <widget class="QCheckBox" name="checkBoxForbidFlipping">
-                <property name="toolTip">
-                 <string>Forbid piece be mirrored in a layout.</string>
-                </property>
-                <property name="text">
-                 <string>Forbid flipping</string>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QCheckBox" name="checkBoxSeams">
-                <property name="text">
-                 <string>Seam allowance</string>
-                </property>
-                <property name="checked">
-                 <bool>true</bool>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <layout class="QHBoxLayout" name="horizontalLayout_2">
-                <item>
-                 <widget class="QLabel" name="labelEditWidth">
-                  <property name="sizePolicy">
-                   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                    <horstretch>1</horstretch>
-                    <verstretch>0</verstretch>
-                   </sizepolicy>
-                  </property>
-                  <property name="locale">
-                   <locale language="English" country="UnitedStates"/>
-                  </property>
-                  <property name="text">
-                   <string>Width:</string>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <widget class="QDoubleSpinBox" name="doubleSpinBoxSeams">
-                  <property name="sizePolicy">
-                   <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-                    <horstretch>1</horstretch>
-                    <verstretch>0</verstretch>
-                   </sizepolicy>
-                  </property>
-                  <property name="maximum">
-                   <double>900.990000000000009</double>
-                  </property>
-                  <property name="singleStep">
-                   <double>0.100000000000000</double>
-                  </property>
-                  <property name="value">
-                   <double>1.000000000000000</double>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <widget class="QLabel" name="labelUnit">
-                  <property name="sizePolicy">
-                   <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
-                    <horstretch>0</horstretch>
-                    <verstretch>0</verstretch>
-                   </sizepolicy>
-                  </property>
-                  <property name="text">
-                   <string>cm</string>
-                  </property>
-                 </widget>
-                </item>
-               </layout>
-              </item>
-              <item>
-               <widget class="QCheckBox" name="checkBoxClosed">
-                <property name="text">
-                 <string>Closed</string>
-                </property>
-                <property name="checked">
-                 <bool>true</bool>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <layout class="QHBoxLayout" name="horizontalLayout_16">
-                <property name="sizeConstraint">
-                 <enum>QLayout::SetFixedSize</enum>
-                </property>
-                <property name="leftMargin">
-                 <number>10</number>
-                </property>
-                <property name="topMargin">
-                 <number>10</number>
-                </property>
-                <property name="rightMargin">
-                 <number>10</number>
-                </property>
-                <property name="bottomMargin">
-                 <number>10</number>
-                </property>
-                <item alignment="Qt::AlignLeft">
-                 <widget class="QToolButton" name="toolButtonDelete">
-                  <property name="enabled">
-                   <bool>false</bool>
-                  </property>
-                  <property name="text">
-                   <string>Delete</string>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <spacer name="horizontalSpacer">
-                  <property name="orientation">
-                   <enum>Qt::Horizontal</enum>
-                  </property>
-                  <property name="sizeHint" stdset="0">
-                   <size>
-                    <width>40</width>
-                    <height>20</height>
-                   </size>
-                  </property>
-                 </spacer>
-                </item>
-                <item alignment="Qt::AlignRight">
-                 <widget class="QToolButton" name="toolButtonDown">
-                  <property name="toolTip">
-                   <string>Scroll down the list</string>
-                  </property>
-                  <property name="text">
-                   <string notr="true">...</string>
-                  </property>
-                  <property name="icon">
-                   <iconset theme="go-down">
-                    <normaloff/>
-                   </iconset>
-                  </property>
-                 </widget>
-                </item>
-                <item alignment="Qt::AlignRight">
-                 <widget class="QToolButton" name="toolButtonUp">
-                  <property name="toolTip">
-                   <string>Scroll up the list</string>
-                  </property>
-                  <property name="text">
-                   <string notr="true">...</string>
-                  </property>
-                  <property name="icon">
-                   <iconset theme="go-up">
-                    <normaloff/>
-                   </iconset>
-                  </property>
-                 </widget>
-                </item>
-               </layout>
-              </item>
-             </layout>
-            </widget>
-           </item>
-          </layout>
-         </widget>
-         <widget class="QListWidget" name="listWidget"/>
-        </widget>
-       </item>
-       <item>
-        <widget class="QLabel" name="helpLabel">
-         <property name="text">
-          <string>Ready!</string>
-         </property>
-         <property name="textFormat">
-          <enum>Qt::RichText</enum>
-         </property>
-         <property name="scaledContents">
-          <bool>false</bool>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-     <widget class="QWidget" name="tab_2">
-      <attribute name="title">
-       <string>Pattern piece data</string>
-      </attribute>
-      <layout class="QVBoxLayout" name="verticalLayout_5">
-       <item>
-        <widget class="QSplitter" name="splitter">
-         <property name="orientation">
-          <enum>Qt::Horizontal</enum>
-         </property>
-         <widget class="QWidget" name="layoutWidget1">
-          <layout class="QVBoxLayout" name="verticalLayout_4">
-           <item>
-            <layout class="QFormLayout" name="formLayout">
-             <property name="fieldGrowthPolicy">
-              <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
-             </property>
-             <item row="0" column="0">
-              <widget class="QLabel" name="label_5">
-               <property name="text">
-                <string>Letter:</string>
-               </property>
-              </widget>
-             </item>
-             <item row="0" column="1">
-              <widget class="QLineEdit" name="lineEditLetter">
-               <property name="maxLength">
-                <number>3</number>
-               </property>
-               <property name="placeholderText">
-                <string>Letter of pattern piece</string>
-               </property>
-              </widget>
-             </item>
-             <item row="1" column="0">
-              <widget class="QLabel" name="labelEditName">
-               <property name="text">
-                <string>Name of detail:</string>
-               </property>
-              </widget>
-             </item>
-             <item row="1" column="1">
-              <widget class="QLineEdit" name="lineEditName">
-               <property name="text">
-                <string>Detail</string>
-               </property>
-               <property name="maxLength">
-                <number>30</number>
-               </property>
-               <property name="placeholderText">
-                <string>Name can't be empty</string>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </item>
-           <item>
-            <widget class="QGroupBox" name="groupBox_2">
-             <property name="title">
-              <string>Material/Cut number/Placement</string>
-             </property>
-             <layout class="QGridLayout" name="gridLayout_3">
-              <item row="1" column="0">
-               <widget class="QLabel" name="label_8">
-                <property name="text">
-                 <string>Cut number:</string>
-                </property>
-               </widget>
-              </item>
-              <item row="0" column="0" colspan="2">
-               <widget class="QLabel" name="label_7">
-                <property name="text">
-                 <string>Material type:</string>
-                </property>
-               </widget>
-              </item>
-              <item row="0" column="2" colspan="2">
-               <widget class="QComboBox" name="comboBoxMaterial">
-                <property name="toolTip">
-                 <string>You can choose one of the predefined materials or enter a new one</string>
-                </property>
-                <property name="editable">
-                 <bool>true</bool>
-                </property>
-               </widget>
-              </item>
-              <item row="1" column="2" colspan="2">
-               <widget class="QSpinBox" name="spinBoxCutNumber">
-                <property name="minimum">
-                 <number>1</number>
-                </property>
-                <property name="maximum">
-                 <number>1000</number>
-                </property>
-               </widget>
-              </item>
-              <item row="2" column="0">
-               <widget class="QLabel" name="label_9">
-                <property name="text">
-                 <string>Placement:</string>
-                </property>
-               </widget>
-              </item>
-              <item row="2" column="2" colspan="2">
-               <widget class="QComboBox" name="comboBoxPlacement"/>
-              </item>
-              <item row="3" column="0">
-               <widget class="QPushButton" name="pushButtonAdd">
-                <property name="text">
-                 <string>Add</string>
-                </property>
-               </widget>
-              </item>
-              <item row="3" column="1" colspan="2">
-               <widget class="QPushButton" name="pushButtonCancel">
-                <property name="text">
-                 <string>Cancel</string>
-                </property>
-               </widget>
-              </item>
-              <item row="3" column="3">
-               <widget class="QPushButton" name="pushButtonRemove">
-                <property name="text">
-                 <string>Remove</string>
-                </property>
-               </widget>
-              </item>
-             </layout>
-            </widget>
-           </item>
-           <item>
-            <layout class="QVBoxLayout" name="verticalLayout_6">
-             <item>
-              <widget class="QCheckBox" name="checkBoxDetail">
-               <property name="text">
-                <string>Detail label visible</string>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QCheckBox" name="checkBoxPattern">
-               <property name="text">
-                <string>Pattern label visible</string>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </item>
-          </layout>
-         </widget>
-         <widget class="QListWidget" name="listWidgetMCP">
-          <property name="minimumSize">
-           <size>
-            <width>180</width>
-            <height>0</height>
-           </size>
-          </property>
-          <property name="focusPolicy">
-           <enum>Qt::ClickFocus</enum>
-          </property>
-         </widget>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-     <widget class="QWidget" name="tab_3">
-      <property name="cursor">
-       <cursorShape>ArrowCursor</cursorShape>
-      </property>
-      <attribute name="title">
-       <string>Grainline</string>
-      </attribute>
-      <widget class="QWidget" name="horizontalLayoutWidget">
-       <property name="geometry">
-        <rect>
-         <x>10</x>
-         <y>10</y>
-         <width>541</width>
-         <height>41</height>
-        </rect>
-       </property>
-       <layout class="QHBoxLayout" name="horizontalLayout">
-        <item>
-         <widget class="QCheckBox" name="checkBoxGrainline">
-          <property name="text">
-           <string>Grainline visible</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </widget>
-      <widget class="QWidget" name="layoutWidget_2">
-       <property name="geometry">
-        <rect>
-         <x>10</x>
-         <y>60</y>
-         <width>541</width>
-         <height>41</height>
-        </rect>
-       </property>
-       <layout class="QHBoxLayout" name="horizontalLayout_11">
-        <item alignment="Qt::AlignLeft">
-         <widget class="QLabel" name="labelEditRot">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <property name="palette">
-           <palette>
-            <active>
-             <colorrole role="WindowText">
-              <brush brushstyle="SolidPattern">
-               <color alpha="255">
-                <red>255</red>
-                <green>0</green>
-                <blue>0</blue>
-               </color>
-              </brush>
-             </colorrole>
-            </active>
-            <inactive>
-             <colorrole role="WindowText">
-              <brush brushstyle="SolidPattern">
-               <color alpha="255">
-                <red>255</red>
-                <green>0</green>
-                <blue>0</blue>
-               </color>
-              </brush>
-             </colorrole>
-            </inactive>
-            <disabled>
-             <colorrole role="WindowText">
-              <brush brushstyle="SolidPattern">
-               <color alpha="255">
-                <red>159</red>
-                <green>158</green>
-                <blue>158</blue>
-               </color>
-              </brush>
-             </colorrole>
-            </disabled>
-           </palette>
-          </property>
-          <property name="text">
-           <string>Rotation:</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <spacer name="horizontalSpacer_4">
-          <property name="orientation">
-           <enum>Qt::Horizontal</enum>
-          </property>
-          <property name="sizeHint" stdset="0">
-           <size>
-            <width>40</width>
-            <height>20</height>
-           </size>
-          </property>
-         </spacer>
-        </item>
-        <item alignment="Qt::AlignRight">
-         <widget class="QToolButton" name="pushButtonRot">
-          <property name="toolTip">
-           <string>Formula wizard</string>
-          </property>
-          <property name="text">
-           <string notr="true">...</string>
-          </property>
-          <property name="icon">
-           <iconset resource="../../../vmisc/share/resources/icon.qrc">
-            <normaloff>:/icon/24x24/fx.png</normaloff>:/icon/24x24/fx.png</iconset>
-          </property>
-          <property name="iconSize">
-           <size>
-            <width>24</width>
-            <height>24</height>
-           </size>
-          </property>
-         </widget>
-        </item>
-        <item alignment="Qt::AlignRight">
-         <widget class="QLabel" name="labelEqual">
-          <property name="text">
-           <string/>
-          </property>
-          <property name="pixmap">
-           <pixmap resource="../../../vmisc/share/resources/icon.qrc">:/icon/24x24/equal.png</pixmap>
-          </property>
-         </widget>
-        </item>
-        <item alignment="Qt::AlignRight">
-         <widget class="QLabel" name="labelRot">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <property name="minimumSize">
-           <size>
-            <width>87</width>
-            <height>0</height>
-           </size>
-          </property>
-          <property name="baseSize">
-           <size>
-            <width>0</width>
-            <height>0</height>
-           </size>
-          </property>
-          <property name="toolTip">
-           <string>Value</string>
-          </property>
-          <property name="text">
-           <string notr="true">_</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </widget>
-      <widget class="QWidget" name="layoutWidget_3">
-       <property name="geometry">
-        <rect>
-         <x>10</x>
-         <y>110</y>
-         <width>541</width>
-         <height>41</height>
-        </rect>
-       </property>
-       <layout class="QHBoxLayout" name="horizontalLayout_12">
-        <item>
-         <widget class="QPlainTextEdit" name="lineEditRotFormula">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <property name="maximumSize">
-           <size>
-            <width>16777215</width>
-            <height>28</height>
-           </size>
-          </property>
-          <property name="toolTip">
-           <string>Calculation</string>
-          </property>
-          <property name="tabChangesFocus">
-           <bool>true</bool>
-          </property>
-          <property name="plainText">
-           <string notr="true"/>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QPushButton" name="pushButtonShowRot">
-          <property name="maximumSize">
-           <size>
-            <width>18</width>
-            <height>18</height>
-           </size>
-          </property>
-          <property name="sizeIncrement">
-           <size>
-            <width>0</width>
-            <height>0</height>
-           </size>
-          </property>
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show full calculation in message box&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string notr="true"/>
-          </property>
-          <property name="icon">
-           <iconset theme="go-down">
-            <normaloff/>
-           </iconset>
-          </property>
-          <property name="iconSize">
-           <size>
-            <width>16</width>
-            <height>16</height>
-           </size>
-          </property>
-          <property name="flat">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </widget>
-      <widget class="QWidget" name="layoutWidget_4">
-       <property name="geometry">
-        <rect>
-         <x>10</x>
-         <y>160</y>
-         <width>541</width>
-         <height>41</height>
-        </rect>
-       </property>
-       <layout class="QHBoxLayout" name="horizontalLayout_13">
-        <item alignment="Qt::AlignLeft">
-         <widget class="QLabel" name="labelEditLen">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <property name="palette">
-           <palette>
-            <active>
-             <colorrole role="WindowText">
-              <brush brushstyle="SolidPattern">
-               <color alpha="255">
-                <red>255</red>
-                <green>0</green>
-                <blue>0</blue>
-               </color>
-              </brush>
-             </colorrole>
-            </active>
-            <inactive>
-             <colorrole role="WindowText">
-              <brush brushstyle="SolidPattern">
-               <color alpha="255">
-                <red>255</red>
-                <green>0</green>
-                <blue>0</blue>
-               </color>
-              </brush>
-             </colorrole>
-            </inactive>
-            <disabled>
-             <colorrole role="WindowText">
-              <brush brushstyle="SolidPattern">
-               <color alpha="255">
-                <red>159</red>
-                <green>158</green>
-                <blue>158</blue>
-               </color>
-              </brush>
-             </colorrole>
-            </disabled>
-           </palette>
-          </property>
-          <property name="text">
-           <string>Length:</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <spacer name="horizontalSpacer_5">
-          <property name="orientation">
-           <enum>Qt::Horizontal</enum>
-          </property>
-          <property name="sizeHint" stdset="0">
-           <size>
-            <width>40</width>
-            <height>20</height>
-           </size>
-          </property>
-         </spacer>
-        </item>
-        <item alignment="Qt::AlignRight">
-         <widget class="QToolButton" name="pushButtonLen">
-          <property name="toolTip">
-           <string>Formula wizard</string>
-          </property>
-          <property name="text">
-           <string notr="true">...</string>
-          </property>
-          <property name="icon">
-           <iconset resource="../../../vmisc/share/resources/icon.qrc">
-            <normaloff>:/icon/24x24/fx.png</normaloff>:/icon/24x24/fx.png</iconset>
-          </property>
-          <property name="iconSize">
-           <size>
-            <width>24</width>
-            <height>24</height>
-           </size>
-          </property>
-         </widget>
-        </item>
-        <item alignment="Qt::AlignRight">
-         <widget class="QLabel" name="labelEqual_2">
-          <property name="text">
-           <string/>
-          </property>
-          <property name="pixmap">
-           <pixmap resource="../../../vmisc/share/resources/icon.qrc">:/icon/24x24/equal.png</pixmap>
-          </property>
-         </widget>
-        </item>
-        <item alignment="Qt::AlignRight">
-         <widget class="QLabel" name="labelLen">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <property name="minimumSize">
-           <size>
-            <width>87</width>
-            <height>0</height>
-           </size>
-          </property>
-          <property name="baseSize">
-           <size>
-            <width>0</width>
-            <height>0</height>
-           </size>
-          </property>
-          <property name="toolTip">
-           <string>Value</string>
-          </property>
-          <property name="text">
-           <string notr="true">_</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </widget>
-      <widget class="QWidget" name="layoutWidget_5">
-       <property name="geometry">
-        <rect>
-         <x>10</x>
-         <y>210</y>
-         <width>541</width>
-         <height>41</height>
-        </rect>
-       </property>
-       <layout class="QHBoxLayout" name="horizontalLayout_14">
-        <item>
-         <widget class="QPlainTextEdit" name="lineEditLenFormula">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <property name="maximumSize">
-           <size>
-            <width>16777215</width>
-            <height>28</height>
-           </size>
-          </property>
-          <property name="toolTip">
-           <string>Calculation</string>
-          </property>
-          <property name="tabChangesFocus">
-           <bool>true</bool>
-          </property>
-          <property name="plainText">
-           <string notr="true"/>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QPushButton" name="pushButtonShowLen">
-          <property name="maximumSize">
-           <size>
-            <width>18</width>
-            <height>18</height>
-           </size>
-          </property>
-          <property name="sizeIncrement">
-           <size>
-            <width>0</width>
-            <height>0</height>
-           </size>
-          </property>
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show full calculation in message box&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string notr="true"/>
-          </property>
-          <property name="icon">
-           <iconset theme="go-down">
-            <normaloff/>
-           </iconset>
-          </property>
-          <property name="iconSize">
-           <size>
-            <width>16</width>
-            <height>16</height>
-           </size>
-          </property>
-          <property name="flat">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </widget>
-      <widget class="QWidget" name="horizontalLayoutWidget_2">
-       <property name="geometry">
-        <rect>
-         <x>10</x>
-         <y>260</y>
-         <width>541</width>
-         <height>41</height>
-        </rect>
-       </property>
-       <layout class="QHBoxLayout" name="horizontalLayout_5">
-        <item>
-         <widget class="QLabel" name="labelEditLen_2">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <property name="palette">
-           <palette>
-            <active>
-             <colorrole role="WindowText">
-              <brush brushstyle="SolidPattern">
-               <color alpha="255">
-                <red>0</red>
-                <green>0</green>
-                <blue>0</blue>
-               </color>
-              </brush>
-             </colorrole>
-            </active>
-            <inactive>
-             <colorrole role="WindowText">
-              <brush brushstyle="SolidPattern">
-               <color alpha="255">
-                <red>0</red>
-                <green>0</green>
-                <blue>0</blue>
-               </color>
-              </brush>
-             </colorrole>
-            </inactive>
-            <disabled>
-             <colorrole role="WindowText">
-              <brush brushstyle="SolidPattern">
-               <color alpha="255">
-                <red>159</red>
-                <green>158</green>
-                <blue>158</blue>
-               </color>
-              </brush>
-             </colorrole>
-            </disabled>
-           </palette>
-          </property>
-          <property name="text">
-           <string>Arrows:</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QComboBox" name="comboBoxArrow"/>
-        </item>
-        <item>
-         <spacer name="horizontalSpacer_2">
-          <property name="orientation">
-           <enum>Qt::Horizontal</enum>
-          </property>
-          <property name="sizeHint" stdset="0">
-           <size>
-            <width>40</width>
-            <height>20</height>
-           </size>
-          </property>
-         </spacer>
-        </item>
-       </layout>
-      </widget>
-     </widget>
-    </widget>
-   </item>
-   <item>
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <tabstops>
-  <tabstop>lineEditName</tabstop>
-  <tabstop>comboBoxMaterial</tabstop>
-  <tabstop>spinBoxCutNumber</tabstop>
-  <tabstop>comboBoxPlacement</tabstop>
-  <tabstop>pushButtonAdd</tabstop>
-  <tabstop>pushButtonCancel</tabstop>
-  <tabstop>pushButtonRemove</tabstop>
-  <tabstop>toolButtonUp</tabstop>
-  <tabstop>listWidget</tabstop>
-  <tabstop>checkBoxClosed</tabstop>
-  <tabstop>toolButtonDelete</tabstop>
-  <tabstop>doubleSpinBoxBiasX</tabstop>
-  <tabstop>doubleSpinBoxBiasY</tabstop>
-  <tabstop>checkBoxReverse</tabstop>
-  <tabstop>checkBoxSeams</tabstop>
-  <tabstop>doubleSpinBoxSeams</tabstop>
-  <tabstop>toolButtonDown</tabstop>
-  <tabstop>checkBoxForbidFlipping</tabstop>
-  <tabstop>checkBoxDetail</tabstop>
-  <tabstop>checkBoxPattern</tabstop>
-  <tabstop>lineEditLetter</tabstop>
- </tabstops>
- <resources>
-  <include location="../../../vmisc/share/resources/icon.qrc"/>
- </resources>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>DialogDetail</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>DialogDetail</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
diff --git a/src/libs/vtools/dialogs/tools/dialogpiecepath.cpp b/src/libs/vtools/dialogs/tools/dialogpiecepath.cpp
new file mode 100644
index 000000000..c4ca47744
--- /dev/null
+++ b/src/libs/vtools/dialogs/tools/dialogpiecepath.cpp
@@ -0,0 +1,970 @@
+/************************************************************************
+ **
+ **  @file   dialogpiecepath.cpp
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   22 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "dialogpiecepath.h"
+#include "ui_dialogpiecepath.h"
+#include "../vpatterndb/vpiecenode.h"
+#include "visualization/path/vistoolpiecepath.h"
+#include "../../tools/vabstracttool.h"
+#include "../../tools/vtoolseamallowance.h"
+#include "../support/dialogeditwrongformula.h"
+
+#include <QMenu>
+#include <QTimer>
+
+//---------------------------------------------------------------------------------------------------------------------
+DialogPiecePath::DialogPiecePath(const VContainer *data, quint32 toolId, QWidget *parent)
+    : DialogTool(data, toolId, parent),
+      ui(new Ui::DialogPiecePath),
+      m_showMode(false),
+      m_saWidth(0),
+      m_timerWidth(nullptr),
+      m_timerWidthBefore(nullptr),
+      m_timerWidthAfter(nullptr),
+      m_formulaBaseWidth(0),
+      m_formulaBaseWidthBefore(0),
+      m_formulaBaseWidthAfter(0)
+{
+    ui->setupUi(this);
+    InitOkCancel(ui);
+
+    InitPathTab();
+    InitSeamAllowanceTab();
+
+    flagName = true;//We have default name of piece.
+    flagError = PathIsValid();
+    CheckState();
+
+    vis = new VisToolPiecePath(data);
+
+    ui->tabWidget->removeTab(1);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+DialogPiecePath::~DialogPiecePath()
+{
+    delete ui;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::EnbleShowMode(bool disable)
+{
+    m_showMode = disable;
+    ui->comboBoxType->setDisabled(m_showMode);
+    ui->comboBoxPiece->setDisabled(m_showMode);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::ChosenObject(quint32 id, const SceneObject &type)
+{
+    if (not prepare)
+    {
+        bool reverse = false;
+        if (QGuiApplication::keyboardModifiers() == Qt::ShiftModifier)
+        {
+            reverse = true;
+        }
+        if (id != GetLastId())
+        {
+            switch (type)
+            {
+                case SceneObject::Arc:
+                    NewItem(VPieceNode(id, Tool::NodeArc, reverse));
+                    break;
+                case SceneObject::Point:
+                    NewItem(VPieceNode(id, Tool::NodePoint));
+                    break;
+                case SceneObject::Spline:
+                    NewItem(VPieceNode(id, Tool::NodeSpline, reverse));
+                    break;
+                case SceneObject::SplinePath:
+                    NewItem(VPieceNode(id, Tool::NodeSplinePath, reverse));
+                    break;
+                case (SceneObject::Line):
+                case (SceneObject::Detail):
+                case (SceneObject::Unknown):
+                default:
+                    qDebug() << "Got wrong scene object. Ignore.";
+                    break;
+            }
+        }
+        else
+        {
+            if (ui->listWidget->count() > 1)
+            {
+                delete GetItemById(id);
+            }
+        }
+
+        ValidObjects(PathIsValid());
+
+        if (not m_showMode)
+        {
+            auto visPath = qobject_cast<VisToolPiecePath *>(vis);
+            SCASSERT(visPath != nullptr);
+            const VPiecePath p = CreatePath();
+            visPath->SetPath(p);
+
+            if (p.CountNodes() == 1)
+            {
+                emit ToolTip(tr("Select main path objects, <b>Shift</b> - reverse direction curve, "
+                                "<b>Enter</b> - finish creation"));
+
+                if (not qApp->getCurrentScene()->items().contains(visPath))
+                {
+                    visPath->VisualMode(NULL_ID);
+                }
+                else
+                {
+                    visPath->RefreshGeometry();
+                }
+            }
+            else
+            {
+                visPath->RefreshGeometry();
+            }
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::ShowDialog(bool click)
+{
+    if (click == false)
+    {
+        if (CreatePath().CountNodes() > 0)
+        {
+            emit ToolTip("");
+            prepare = true;
+
+            if (not m_showMode)
+            {
+                auto visPath = qobject_cast<VisToolPiecePath *>(vis);
+                SCASSERT(visPath != nullptr);
+                visPath->SetMode(Mode::Show);
+                visPath->RefreshGeometry();
+            }
+            setModal(true);
+            show();
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::SaveData()
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::CheckState()
+{
+    SCASSERT(bOk != nullptr);
+    bOk->setEnabled(flagName && flagError);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::ShowVisualization()
+{
+    AddVisualization<VisToolPiecePath>();
+
+    if (m_showMode)
+    {
+        VToolSeamAllowance *tool = qobject_cast<VToolSeamAllowance*>(VAbstractPattern::getTool(GetPieceId()));
+        SCASSERT(tool != nullptr);
+        auto visPath = qobject_cast<VisToolPiecePath *>(vis);
+        SCASSERT(visPath != nullptr);
+        visPath->setParentItem(tool);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::ShowContextMenu(const QPoint &pos)
+{
+    const int row = ui->listWidget->currentRow();
+    if (ui->listWidget->count() == 0 || row == -1 || row >= ui->listWidget->count())
+    {
+        return;
+    }
+
+    QMenu *menu = new QMenu(this);
+
+    QListWidgetItem *rowItem = ui->listWidget->item(row);
+    SCASSERT(rowItem != nullptr);
+    VPieceNode rowNode = qvariant_cast<VPieceNode>(rowItem->data(Qt::UserRole));
+
+    QAction *actionReverse = nullptr;
+    if (rowNode.GetTypeTool() != Tool::NodePoint)
+    {
+        actionReverse = menu->addAction(tr("Reverse"));
+        actionReverse->setCheckable(true);
+        actionReverse->setChecked(rowNode.GetReverse());
+    }
+
+    QAction *actionDelete = menu->addAction(QIcon::fromTheme("edit-delete"), tr("Delete"));
+
+    QAction *selectedAction = menu->exec(ui->listWidget->viewport()->mapToGlobal(pos));
+    if (selectedAction == actionDelete)
+    {
+        delete ui->listWidget->item(row);
+        ValidObjects(PathIsValid());
+    }
+    else if (rowNode.GetTypeTool() != Tool::NodePoint && selectedAction == actionReverse)
+    {
+        rowNode.SetReverse(not rowNode.GetReverse());
+        rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode));
+        rowItem->setText(GetNodeName(rowNode));
+        ValidObjects(PathIsValid());
+    }
+
+    ListChanged();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::ListChanged()
+{
+    if (not m_showMode)
+    {
+        auto visPath = qobject_cast<VisToolPiecePath *>(vis);
+        SCASSERT(visPath != nullptr);
+        visPath->SetPath(CreatePath());
+        visPath->RefreshGeometry();
+    }
+
+    InitNodesList();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::NameChanged()
+{
+    if (ui->lineEditName->text().isEmpty())
+    {
+        flagName = false;
+        ChangeColor(ui->labelName, Qt::red);
+    }
+    else
+    {
+        flagName = true;
+        ChangeColor(ui->labelName, okColor);
+    }
+    CheckState();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::NodeChanged(int index)
+{
+    ui->plainTextEditFormulaWidthBefore->setDisabled(true);
+    ui->toolButtonExprBefore->setDisabled(true);
+    ui->pushButtonDefBefore->setDisabled(true);
+
+    ui->plainTextEditFormulaWidthAfter->setDisabled(true);
+    ui->toolButtonExprAfter->setDisabled(true);
+    ui->pushButtonDefAfter->setDisabled(true);
+
+    ui->comboBoxAngle->setDisabled(true);
+
+    ui->comboBoxAngle->blockSignals(true);
+
+    if (index != -1)
+    {
+    #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+        const quint32 id = ui->comboBoxNodes->itemData(index).toUInt();
+    #else
+        const quint32 id = ui->comboBoxNodes->currentData().toUInt();
+    #endif
+        const VPiecePath path = CreatePath();
+        const int nodeIndex = path.indexOfNode(id);
+        if (nodeIndex != -1)
+        {
+            const VPieceNode &node = path.at(nodeIndex);
+
+            // Seam alowance before
+            ui->plainTextEditFormulaWidthBefore->setEnabled(true);
+            ui->toolButtonExprBefore->setEnabled(true);
+
+            QString w1Formula = node.GetFormulaSABefore();
+            if (w1Formula != currentSeamAllowance)
+            {
+                ui->pushButtonDefBefore->setEnabled(true);
+            }
+            if (w1Formula.length() > 80)// increase height if needed.
+            {
+                this->DeployWidthBeforeFormulaTextEdit();
+            }
+            w1Formula = qApp->TrVars()->FormulaToUser(w1Formula, qApp->Settings()->GetOsSeparator());
+            ui->plainTextEditFormulaWidthBefore->setPlainText(w1Formula);
+            MoveCursorToEnd(ui->plainTextEditFormulaWidthBefore);
+
+            // Seam alowance after
+            ui->plainTextEditFormulaWidthAfter->setEnabled(true);
+            ui->toolButtonExprAfter->setEnabled(true);
+
+            QString w2Formula = node.GetFormulaSAAfter();
+            if (w2Formula != currentSeamAllowance)
+            {
+                ui->pushButtonDefBefore->setEnabled(true);
+            }
+            if (w2Formula.length() > 80)// increase height if needed.
+            {
+                this->DeployWidthAfterFormulaTextEdit();
+            }
+            w2Formula = qApp->TrVars()->FormulaToUser(w2Formula, qApp->Settings()->GetOsSeparator());
+            ui->plainTextEditFormulaWidthAfter->setPlainText(w2Formula);
+            MoveCursorToEnd(ui->plainTextEditFormulaWidthAfter);
+
+            // Angle type
+            ui->comboBoxAngle->setEnabled(true);
+            const int index = ui->comboBoxAngle->findData(static_cast<unsigned char>(node.GetAngleType()));
+            if (index != -1)
+            {
+                ui->comboBoxAngle->setCurrentIndex(index);
+            }
+        }
+    }
+    else
+    {
+        ui->plainTextEditFormulaWidthBefore->setPlainText("");
+        ui->plainTextEditFormulaWidthAfter->setPlainText("");
+        ui->comboBoxAngle->setCurrentIndex(-1);
+    }
+
+    ui->comboBoxAngle->blockSignals(false);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::ReturnDefBefore()
+{
+    ui->plainTextEditFormulaWidthBefore->setPlainText(currentSeamAllowance);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::ReturnDefAfter()
+{
+    ui->plainTextEditFormulaWidthAfter->setPlainText(currentSeamAllowance);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::EvalWidth()
+{
+    labelEditFormula = ui->labelEditWidth;
+    const QString postfix = VDomDocument::UnitsToStr(qApp->patternUnit(), true);
+    const QString formula = ui->plainTextEditFormulaWidth->toPlainText();
+    m_saWidth = Eval(formula, flagFormula, ui->labelResultWidth, postfix, false, true);
+
+    if (m_saWidth >= 0)
+    {
+        VContainer *locData = const_cast<VContainer *> (data);
+        locData->AddVariable(currentSeamAllowance, new VIncrement(locData, currentSeamAllowance, 0, m_saWidth,
+                                                                  QString().setNum(m_saWidth), true,
+                                                                  tr("Current seam aloowance")));
+
+        EvalWidthBefore();
+        EvalWidthAfter();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::EvalWidthBefore()
+{
+    labelEditFormula = ui->labelEditBefore;
+    const QString postfix = VDomDocument::UnitsToStr(qApp->patternUnit(), true);
+    const QString formula = ui->plainTextEditFormulaWidthBefore->toPlainText();
+    bool flagFormula = false; // fake flag
+    Eval(formula, flagFormula, ui->labelResultBefore, postfix, false, true);
+
+    UpdateNodeSABefore(GetFormulaSAWidthBefore());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::EvalWidthAfter()
+{
+    labelEditFormula = ui->labelEditAfter;
+    const QString postfix = VDomDocument::UnitsToStr(qApp->patternUnit(), true);
+    const QString formula = ui->plainTextEditFormulaWidthAfter->toPlainText();
+    bool flagFormula = false; // fake flag
+    Eval(formula, flagFormula, ui->labelResultAfter, postfix, false, true);
+
+    UpdateNodeSABefore(GetFormulaSAWidthAfter());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::FXWidth()
+{
+    DialogEditWrongFormula *dialog = new DialogEditWrongFormula(data, toolId, this);
+    dialog->setWindowTitle(tr("Edit seam allowance width"));
+    dialog->SetFormula(GetFormulaSAWidth());
+    dialog->setCheckLessThanZero(true);
+    dialog->setPostfix(VDomDocument::UnitsToStr(qApp->patternUnit(), true));
+    if (dialog->exec() == QDialog::Accepted)
+    {
+        SetFormulaSAWidth(dialog->GetFormula());
+    }
+    delete dialog;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::FXWidthBefore()
+{
+    DialogEditWrongFormula *dialog = new DialogEditWrongFormula(data, toolId, this);
+    dialog->setWindowTitle(tr("Edit seam allowance width before"));
+    dialog->SetFormula(GetFormulaSAWidthBefore());
+    dialog->setCheckLessThanZero(true);
+    dialog->setPostfix(VDomDocument::UnitsToStr(qApp->patternUnit(), true));
+    if (dialog->exec() == QDialog::Accepted)
+    {
+        SetCurrentSABefore(dialog->GetFormula());
+    }
+    delete dialog;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::FXWidthAfter()
+{
+    DialogEditWrongFormula *dialog = new DialogEditWrongFormula(data, toolId, this);
+    dialog->setWindowTitle(tr("Edit seam allowance width after"));
+    dialog->SetFormula(GetFormulaSAWidthAfter());
+    dialog->setCheckLessThanZero(true);
+    dialog->setPostfix(VDomDocument::UnitsToStr(qApp->patternUnit(), true));
+    if (dialog->exec() == QDialog::Accepted)
+    {
+        SetCurrentSAAfter(dialog->GetFormula());
+    }
+    delete dialog;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::WidthChanged()
+{
+    labelEditFormula = ui->labelEditWidth;
+    labelResultCalculation = ui->labelResultWidth;
+    const QString postfix = VDomDocument::UnitsToStr(qApp->patternUnit(), true);
+    ValFormulaChanged(flagFormula, ui->plainTextEditFormulaWidth, m_timerWidth, postfix);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::WidthBeforeChanged()
+{
+    labelEditFormula = ui->labelEditBefore;
+    labelResultCalculation = ui->labelResultBefore;
+    const QString postfix = VDomDocument::UnitsToStr(qApp->patternUnit(), true);
+    bool flagFormula = false;
+    ValFormulaChanged(flagFormula, ui->plainTextEditFormulaWidthBefore, m_timerWidthBefore, postfix);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::WidthAfterChanged()
+{
+    labelEditFormula = ui->labelEditAfter;
+    labelResultCalculation = ui->labelResultAfter;
+    const QString postfix = VDomDocument::UnitsToStr(qApp->patternUnit(), true);
+    bool flagFormula = false;
+    ValFormulaChanged(flagFormula, ui->plainTextEditFormulaWidthAfter, m_timerWidthAfter, postfix);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::DeployWidthFormulaTextEdit()
+{
+    DeployFormula(ui->plainTextEditFormulaWidth, ui->pushButtonGrowWidth, m_formulaBaseWidth);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::DeployWidthBeforeFormulaTextEdit()
+{
+    DeployFormula(ui->plainTextEditFormulaWidthBefore, ui->pushButtonGrowWidthBefore, m_formulaBaseWidthBefore);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::DeployWidthAfterFormulaTextEdit()
+{
+    DeployFormula(ui->plainTextEditFormulaWidthAfter, ui->pushButtonGrowWidthAfter, m_formulaBaseWidthAfter);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::InitPathTab()
+{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
+    ui->lineEditName->setClearButtonEnabled(true);
+#endif
+
+    FillComboBoxTypeLine(ui->comboBoxPenType, VAbstractTool::LineStylesPics());
+
+    connect(ui->lineEditName, &QLineEdit::textChanged, this, &DialogPiecePath::NameChanged);
+
+    InitPathTypes();
+    connect(ui->comboBoxType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+            [this]()
+    {
+        ui->comboBoxPenType->setEnabled(GetType() == PiecePathType::InternalPath);
+        ValidObjects(PathIsValid());
+    });
+
+    ui->listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+    connect(ui->listWidget, &QListWidget::customContextMenuRequested, this, &DialogPiecePath::ShowContextMenu);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::InitSeamAllowanceTab()
+{
+    plainTextEditFormula = ui->plainTextEditFormulaWidth;
+    this->m_formulaBaseWidth = ui->plainTextEditFormulaWidth->height();
+    this->m_formulaBaseWidthBefore = ui->plainTextEditFormulaWidthBefore->height();
+    this->m_formulaBaseWidthAfter = ui->plainTextEditFormulaWidthAfter->height();
+
+    ui->plainTextEditFormulaWidth->installEventFilter(this);
+    ui->plainTextEditFormulaWidthBefore->installEventFilter(this);
+    ui->plainTextEditFormulaWidthAfter->installEventFilter(this);
+
+    m_timerWidth = new QTimer(this);
+    connect(m_timerWidth, &QTimer::timeout, this, &DialogPiecePath::EvalWidth);
+
+    m_timerWidthBefore = new QTimer(this);
+    connect(m_timerWidthBefore, &QTimer::timeout, this, &DialogPiecePath::EvalWidthBefore);
+
+    m_timerWidthAfter = new QTimer(this);
+    connect(m_timerWidthAfter, &QTimer::timeout, this, &DialogPiecePath::EvalWidthAfter);
+
+    // Default value for seam allowence is 1 cm. But pattern have different units, so just set 1 in dialog not enough.
+    m_saWidth = UnitConvertor(1, Unit::Cm, qApp->patternUnit());
+    ui->plainTextEditFormulaWidth->setPlainText(qApp->LocaleToString(m_saWidth));
+
+    InitNodesList();
+    connect(ui->comboBoxNodes, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+            &DialogPiecePath::NodeChanged);
+
+    connect(ui->pushButtonDefBefore, &QPushButton::clicked, this, &DialogPiecePath::ReturnDefBefore);
+    connect(ui->pushButtonDefAfter, &QPushButton::clicked, this, &DialogPiecePath::ReturnDefAfter);
+
+    InitNodeAngles(ui->comboBoxAngle);
+    connect(ui->comboBoxAngle, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+            &DialogPiecePath::NodeAngleChanged);
+
+    connect(ui->toolButtonExprWidth, &QPushButton::clicked, this, &DialogPiecePath::FXWidth);
+    connect(ui->toolButtonExprBefore, &QPushButton::clicked, this, &DialogPiecePath::FXWidthBefore);
+    connect(ui->toolButtonExprAfter, &QPushButton::clicked, this, &DialogPiecePath::FXWidthAfter);
+
+    connect(ui->plainTextEditFormulaWidth, &QPlainTextEdit::textChanged, this, &DialogPiecePath::WidthChanged);
+    connect(ui->plainTextEditFormulaWidthBefore, &QPlainTextEdit::textChanged, this,
+            &DialogPiecePath::WidthBeforeChanged);
+    connect(ui->plainTextEditFormulaWidthAfter, &QPlainTextEdit::textChanged, this,
+            &DialogPiecePath::WidthAfterChanged);
+
+    connect(ui->pushButtonGrowWidth, &QPushButton::clicked, this, &DialogPiecePath::DeployWidthFormulaTextEdit);
+    connect(ui->pushButtonGrowWidthBefore, &QPushButton::clicked,
+            this, &DialogPiecePath::DeployWidthBeforeFormulaTextEdit);
+    connect(ui->pushButtonGrowWidthAfter, &QPushButton::clicked, this,
+            &DialogPiecePath::DeployWidthAfterFormulaTextEdit);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::InitPathTypes()
+{
+    ui->comboBoxType->addItem(tr("Internal path"), static_cast<int>(PiecePathType::InternalPath));
+    ui->comboBoxType->addItem(tr("Custom seam allowance"), static_cast<int>(PiecePathType::CustomSeamAllowance));
+
+    ui->comboBoxPenType->setEnabled(GetType() == PiecePathType::InternalPath);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::InitNodesList()
+{
+#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+    const quint32 id = ui->comboBoxNodes->itemData(ui->comboBoxNodes->currentIndex()).toUInt();
+#else
+    const quint32 id = ui->comboBoxNodes->currentData().toUInt();
+#endif
+
+    ui->comboBoxNodes->blockSignals(true);
+    ui->comboBoxNodes->clear();
+
+    const VPiecePath path = CreatePath();
+
+    for (int i = 0; i < path.CountNodes(); ++i)
+    {
+        const VPieceNode node = path.at(i);
+        if (node.GetTypeTool() == Tool::NodePoint)
+        {
+            const QString name = GetNodeName(node);
+
+            ui->comboBoxNodes->addItem(name, node.GetId());
+        }
+    }
+    ui->comboBoxNodes->blockSignals(false);
+
+    const int index = ui->comboBoxNodes->findData(id);
+    if (index != -1)
+    {
+        ui->comboBoxNodes->setCurrentIndex(index);
+        NodeChanged(index);// Need in case combox index was not changed
+    }
+    else
+    {
+        ui->comboBoxNodes->count() > 0 ? NodeChanged(0) : NodeChanged(-1);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::NodeAngleChanged(int index)
+{
+    const int i = ui->comboBoxNodes->currentIndex();
+    if (i != -1 && index != -1)
+    {
+    #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+        const quint32 id = ui->comboBoxNodes->itemData(i).toUInt();
+    #else
+        const quint32 id = ui->comboBoxNodes->currentData().toUInt();
+    #endif
+
+        QListWidgetItem *rowItem = GetItemById(id);
+        if (rowItem)
+        {
+        #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+            const PieceNodeAngle angle = static_cast<PieceNodeAngle>(ui->comboBoxAngle->itemData(index).toUInt());
+        #else
+            const PieceNodeAngle angle = static_cast<PieceNodeAngle>(ui->comboBoxAngle->currentData().toUInt());
+        #endif
+
+            VPieceNode rowNode = qvariant_cast<VPieceNode>(rowItem->data(Qt::UserRole));
+            rowNode.SetAngleType(angle);
+            rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode));
+
+            ListChanged();
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath DialogPiecePath::GetPiecePath() const
+{
+    return CreatePath();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::SetPiecePath(const VPiecePath &path)
+{
+    ui->listWidget->clear();
+    for (int i = 0; i < path.CountNodes(); ++i)
+    {
+        NewItem(path.at(i));
+    }
+
+    SetType(path.GetType());
+    ui->lineEditName->setText(path.GetName());
+
+    VisToolPiecePath *visPath = qobject_cast<VisToolPiecePath *>(vis);
+    SCASSERT(visPath != nullptr);
+    visPath->SetPath(path);
+    SetPenType(path.GetPenType());
+
+    ValidObjects(PathIsValid());
+
+    ListChanged();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+PiecePathType DialogPiecePath::GetType() const
+{
+#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+    const PiecePathType type =
+            static_cast<PiecePathType>(ui->comboBoxType->itemData(ui->comboBoxType->currentIndex()).toInt());
+#else
+    const PiecePathType type = static_cast<PiecePathType>(ui->comboBoxType->currentData().toInt());
+#endif
+
+    return type;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::SetType(PiecePathType type)
+{
+    const qint32 index = ui->comboBoxType->findData(static_cast<int>(type));
+    if (index != -1)
+    {
+        ui->comboBoxType->setCurrentIndex(index);
+    }
+
+    ui->comboBoxPenType->setEnabled(type == PiecePathType::InternalPath);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+Qt::PenStyle DialogPiecePath::GetPenType() const
+{
+    return VAbstractTool::LineStyleToPenStyle(GetComboBoxCurrentData(ui->comboBoxPenType, TypeLineLine));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::SetPenType(const Qt::PenStyle &type)
+{
+    ChangeCurrentData(ui->comboBoxPenType, VAbstractTool::PenStyleToLineStyle(type));
+    vis->setLineStyle(type);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QListWidgetItem *DialogPiecePath::GetItemById(quint32 id)
+{
+    for (qint32 i = 0; i < ui->listWidget->count(); ++i)
+    {
+        QListWidgetItem *item = ui->listWidget->item(i);
+        const VPieceNode node = qvariant_cast<VPieceNode>(item->data(Qt::UserRole));
+
+        if (node.GetId() == id)
+        {
+            return item;
+        }
+    }
+    return nullptr;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+quint32 DialogPiecePath::GetLastId() const
+{
+    const int count = ui->listWidget->count();
+    if (count > 0)
+    {
+        QListWidgetItem *item = ui->listWidget->item(count-1);
+        const VPieceNode node = qvariant_cast<VPieceNode>(item->data(Qt::UserRole));
+        return node.GetId();
+    }
+    else
+    {
+        return NULL_ID;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::SetCurrentSABefore(const QString &formula)
+{
+    UpdateNodeSABefore(formula);
+    ListChanged();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::SetCurrentSAAfter(const QString &formula)
+{
+    UpdateNodeSAAfter(formula);
+    ListChanged();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::UpdateNodeSABefore(const QString &formula)
+{
+    const int index = ui->comboBoxNodes->currentIndex();
+    if (index != -1)
+    {
+    #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+        const quint32 id = ui->comboBoxNodes->itemData(index).toUInt();
+    #else
+        const quint32 id = ui->comboBoxNodes->currentData().toUInt();
+    #endif
+
+        QListWidgetItem *rowItem = GetItemById(id);
+        if (rowItem)
+        {
+            VPieceNode rowNode = qvariant_cast<VPieceNode>(rowItem->data(Qt::UserRole));
+            rowNode.SetFormulaSABefore(formula);
+            rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode));
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::UpdateNodeSAAfter(const QString &formula)
+{
+    const int index = ui->comboBoxNodes->currentIndex();
+    if (index != -1)
+    {
+    #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+        const quint32 id = ui->comboBoxNodes->itemData(index).toUInt();
+    #else
+        const quint32 id = ui->comboBoxNodes->currentData().toUInt();
+    #endif
+
+        QListWidgetItem *rowItem = GetItemById(id);
+        if (rowItem)
+        {
+            VPieceNode rowNode = qvariant_cast<VPieceNode>(rowItem->data(Qt::UserRole));
+            rowNode.SetFormulaSAAfter(formula);
+            rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode));
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::SetFormulaSAWidth(const QString &formula)
+{
+    const QString width = qApp->TrVars()->FormulaToUser(formula, qApp->Settings()->GetOsSeparator());
+    // increase height if needed.
+    if (width.length() > 80)
+    {
+        this->DeployWidthFormulaTextEdit();
+    }
+    ui->plainTextEditFormulaWidth->setPlainText(width);
+
+    VisToolPiecePath *path = qobject_cast<VisToolPiecePath *>(vis);
+    SCASSERT(path != nullptr)
+    path->SetPath(CreatePath());
+
+    MoveCursorToEnd(ui->plainTextEditFormulaWidth);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+quint32 DialogPiecePath::GetPieceId() const
+{
+    quint32 id = NULL_ID;
+
+    if (ui->comboBoxPiece->count() > 0)
+    {
+#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+    id = ui->comboBoxPiece->itemData(ui->comboBoxPiece->currentIndex()).toUInt();
+#else
+    id = ui->comboBoxPiece->currentData().toUInt();
+#endif
+    }
+
+    return id;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::SetPieceId(quint32 id)
+{
+    if (ui->comboBoxPiece->count() <= 0)
+    {
+        const VPiece piece = data->GetPiece(id);
+        ui->comboBoxPiece->addItem(piece.GetName(), id);
+    }
+    else
+    {
+        const qint32 index = ui->comboBoxPiece->findData(id);
+        if (index != -1)
+        {
+            ui->comboBoxType->setCurrentIndex(index);
+        }
+    }
+
+    ValidObjects(PathIsValid());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString DialogPiecePath::GetFormulaSAWidth() const
+{
+    QString width = ui->plainTextEditFormulaWidth->toPlainText();
+    width.replace("\n", " ");
+    return qApp->TrVars()->TryFormulaFromUser(width, qApp->Settings()->GetOsSeparator());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::SetPiecesList(const QVector<quint32> &list)
+{
+    for (int i=0; i < list.size(); ++i)
+    {
+        const VPiece piece = data->GetPiece(list.at(i));
+        ui->comboBoxPiece->addItem(piece.GetName(), list.at(i));
+    }
+    ValidObjects(PathIsValid());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath DialogPiecePath::CreatePath() const
+{
+    VPiecePath path;
+    for (qint32 i = 0; i < ui->listWidget->count(); ++i)
+    {
+        QListWidgetItem *item = ui->listWidget->item(i);
+        path.Append(qvariant_cast<VPieceNode>(item->data(Qt::UserRole)));
+    }
+
+    path.SetType(GetType());
+    path.SetName(ui->lineEditName->text());
+    path.SetPenType(GetType() == PiecePathType::InternalPath ? GetPenType() : Qt::SolidLine);
+
+    return path;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool DialogPiecePath::PathIsValid() const
+{
+    QString url = DialogWarningIcon();
+
+    if(CreatePath().PathPoints(data).count() < 2)
+    {
+        url += tr("You need more points!");
+        ui->helpLabel->setText(url);
+        return false;
+    }
+    else
+    {
+        if (GetType() == PiecePathType::CustomSeamAllowance && FirstPointEqualLast(ui->listWidget))
+        {
+            url += tr("First point of <b>custom seam allowance</b> cannot be equal to the last point!");
+            ui->helpLabel->setText(url);
+            return false;
+        }
+        else if (DoublePoints(ui->listWidget))
+        {
+            url += tr("You have double points!");
+            ui->helpLabel->setText(url);
+            return false;
+        }
+    }
+
+    if (not m_showMode && ui->comboBoxPiece->count() <= 0)
+    {
+        url += tr("List of objects is empty!");
+        ui->helpLabel->setText(url);
+        return false;
+    }
+
+    ui->helpLabel->setText(tr("Ready!"));
+    return true;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::ValidObjects(bool value)
+{
+    flagError = value;
+    CheckState();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogPiecePath::NewItem(const VPieceNode &node)
+{
+    NewNodeItem(ui->listWidget, node);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString DialogPiecePath::GetFormulaSAWidthBefore() const
+{
+    QString width = ui->plainTextEditFormulaWidthBefore->toPlainText();
+    width.replace("\n", " ");
+    return qApp->TrVars()->TryFormulaFromUser(width, qApp->Settings()->GetOsSeparator());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString DialogPiecePath::GetFormulaSAWidthAfter() const
+{
+    QString width = ui->plainTextEditFormulaWidthAfter->toPlainText();
+    width.replace("\n", " ");
+    return qApp->TrVars()->TryFormulaFromUser(width, qApp->Settings()->GetOsSeparator());
+}
diff --git a/src/libs/vtools/dialogs/tools/dialogpiecepath.h b/src/libs/vtools/dialogs/tools/dialogpiecepath.h
new file mode 100644
index 000000000..4739d8ea3
--- /dev/null
+++ b/src/libs/vtools/dialogs/tools/dialogpiecepath.h
@@ -0,0 +1,140 @@
+/************************************************************************
+ **
+ **  @file   dialogpiecepath.h
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   22 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef DIALOGPIECEPATH_H
+#define DIALOGPIECEPATH_H
+
+#include "dialogtool.h"
+
+namespace Ui
+{
+    class DialogPiecePath;
+}
+
+class DialogPiecePath : public DialogTool
+{
+    Q_OBJECT
+public:
+    explicit DialogPiecePath(const VContainer *data, quint32 toolId, QWidget *parent = nullptr);
+    virtual ~DialogPiecePath();
+
+    void EnbleShowMode(bool disable);
+
+    VPiecePath GetPiecePath() const;
+    void       SetPiecePath(const VPiecePath &path);
+
+    quint32 GetPieceId() const;
+    void    SetPieceId(quint32 id);
+
+    QString GetFormulaSAWidth() const;
+    void    SetFormulaSAWidth(const QString &formula);
+
+    virtual void SetPiecesList(const QVector<quint32> &list) Q_DECL_OVERRIDE;
+
+public slots:
+    virtual void ChosenObject(quint32 id, const SceneObject &type) Q_DECL_OVERRIDE;
+    virtual void ShowDialog(bool click) Q_DECL_OVERRIDE;
+
+protected:
+    /** @brief SaveData Put dialog data in local variables */
+    virtual void SaveData() Q_DECL_OVERRIDE;
+    virtual void CheckState() Q_DECL_OVERRIDE;
+    virtual void ShowVisualization() Q_DECL_OVERRIDE;
+
+private slots:
+    void ShowContextMenu(const QPoint &pos);
+    void ListChanged();
+    void NameChanged();
+    void NodeChanged(int index);
+    void ReturnDefBefore();
+    void ReturnDefAfter();
+
+    void EvalWidth();
+    void EvalWidthBefore();
+    void EvalWidthAfter();
+
+    void FXWidth();
+    void FXWidthBefore();
+    void FXWidthAfter();
+
+    void WidthChanged();
+    void WidthBeforeChanged();
+    void WidthAfterChanged();
+
+    void DeployWidthFormulaTextEdit();
+    void DeployWidthBeforeFormulaTextEdit();
+    void DeployWidthAfterFormulaTextEdit();
+
+private:
+    Q_DISABLE_COPY(DialogPiecePath)
+    Ui::DialogPiecePath *ui;
+    bool  m_showMode;
+    qreal m_saWidth;
+
+    QTimer *m_timerWidth;
+    QTimer *m_timerWidthBefore;
+    QTimer *m_timerWidthAfter;
+
+    int m_formulaBaseWidth;
+    int m_formulaBaseWidthBefore;
+    int m_formulaBaseWidthAfter;
+
+    void InitPathTab();
+    void InitSeamAllowanceTab();
+    void InitPathTypes();
+    void InitListPieces();
+    void InitNodesList();
+    void NodeAngleChanged(int index);
+
+    VPiecePath CreatePath() const;
+
+    bool PathIsValid() const;
+    void ValidObjects(bool value);
+    void NewItem(const VPieceNode &node);
+
+    PiecePathType GetType() const;
+    void          SetType(PiecePathType type);
+
+    Qt::PenStyle GetPenType() const;
+    void         SetPenType(const Qt::PenStyle &type);
+
+    QListWidgetItem *GetItemById(quint32 id);
+
+    quint32 GetLastId() const;
+
+    void SetCurrentSABefore(const QString &formula);
+    void SetCurrentSAAfter(const QString &formula);
+
+    void UpdateNodeSABefore(const QString &formula);
+    void UpdateNodeSAAfter(const QString &formula);
+
+    QString GetFormulaSAWidthBefore() const;
+    QString GetFormulaSAWidthAfter() const;
+};
+
+#endif // DIALOGPIECEPATH_H
diff --git a/src/libs/vtools/dialogs/tools/dialogpiecepath.ui b/src/libs/vtools/dialogs/tools/dialogpiecepath.ui
new file mode 100644
index 000000000..10d360ffd
--- /dev/null
+++ b/src/libs/vtools/dialogs/tools/dialogpiecepath.ui
@@ -0,0 +1,846 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DialogPiecePath</class>
+ <widget class="QDialog" name="DialogPiecePath">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>480</width>
+    <height>437</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Piece path tool</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="../../../vmisc/share/resources/icon.qrc">
+    <normaloff>:/icon/64x64/icon64x64.png</normaloff>:/icon/64x64/icon64x64.png</iconset>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <widget class="QTabWidget" name="tabWidget">
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="tabPath">
+      <attribute name="title">
+       <string>Path</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout">
+       <item>
+        <layout class="QFormLayout" name="formLayout">
+         <property name="fieldGrowthPolicy">
+          <enum>QFormLayout::ExpandingFieldsGrow</enum>
+         </property>
+         <item row="0" column="0">
+          <widget class="QLabel" name="labelName">
+           <property name="text">
+            <string>Name:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QLineEdit" name="lineEditName">
+           <property name="text">
+            <string>Unnamed path</string>
+           </property>
+           <property name="placeholderText">
+            <string>Create name for your path</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QLabel" name="labelType">
+           <property name="text">
+            <string>Type:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QComboBox" name="comboBoxType"/>
+         </item>
+         <item row="3" column="0">
+          <widget class="QLabel" name="labelPiece">
+           <property name="text">
+            <string>Piece:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="1">
+          <widget class="QComboBox" name="comboBoxPiece"/>
+         </item>
+         <item row="2" column="0">
+          <widget class="QLabel" name="labelPenType">
+           <property name="text">
+            <string>Type of pen:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="1">
+          <widget class="QComboBox" name="comboBoxPenType">
+           <property name="minimumSize">
+            <size>
+             <width>80</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="iconSize">
+            <size>
+             <width>80</width>
+             <height>14</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <widget class="QListWidget" name="listWidget">
+         <property name="dragDropMode">
+          <enum>QAbstractItemView::InternalMove</enum>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLabel" name="helpLabel">
+         <property name="text">
+          <string>Ready!</string>
+         </property>
+         <property name="textFormat">
+          <enum>Qt::RichText</enum>
+         </property>
+         <property name="scaledContents">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tabSeamAllowance">
+      <attribute name="title">
+       <string>Seam allowance</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_4">
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_4">
+         <item alignment="Qt::AlignLeft">
+          <widget class="QLabel" name="labelEditWidth">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="palette">
+            <palette>
+             <active>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>255</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </active>
+             <inactive>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>255</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </inactive>
+             <disabled>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>159</red>
+                 <green>158</green>
+                 <blue>158</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </disabled>
+            </palette>
+           </property>
+           <property name="text">
+            <string>Width:</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_2">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item alignment="Qt::AlignRight">
+          <widget class="QToolButton" name="toolButtonExprWidth">
+           <property name="enabled">
+            <bool>false</bool>
+           </property>
+           <property name="toolTip">
+            <string>Formula wizard</string>
+           </property>
+           <property name="text">
+            <string notr="true">...</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../../../vmisc/share/resources/icon.qrc">
+             <normaloff>:/icon/24x24/fx.png</normaloff>:/icon/24x24/fx.png</iconset>
+           </property>
+           <property name="iconSize">
+            <size>
+             <width>24</width>
+             <height>24</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item alignment="Qt::AlignRight">
+          <widget class="QLabel" name="label_2">
+           <property name="text">
+            <string/>
+           </property>
+           <property name="pixmap">
+            <pixmap resource="../../../vmisc/share/resources/icon.qrc">:/icon/24x24/equal.png</pixmap>
+           </property>
+          </widget>
+         </item>
+         <item alignment="Qt::AlignRight">
+          <widget class="QLabel" name="labelResultWidth">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>87</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>Value</string>
+           </property>
+           <property name="text">
+            <string notr="true">_</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_6">
+         <item>
+          <widget class="QPlainTextEdit" name="plainTextEditFormulaWidth">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>16777215</width>
+             <height>28</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>Calculation</string>
+           </property>
+           <property name="tabChangesFocus">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="pushButtonGrowWidth">
+           <property name="enabled">
+            <bool>false</bool>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>18</width>
+             <height>18</height>
+            </size>
+           </property>
+           <property name="sizeIncrement">
+            <size>
+             <width>0</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show full calculation in message box&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+           <property name="text">
+            <string notr="true"/>
+           </property>
+           <property name="icon">
+            <iconset theme="go-down">
+             <normaloff>.</normaloff>.</iconset>
+           </property>
+           <property name="iconSize">
+            <size>
+             <width>16</width>
+             <height>16</height>
+            </size>
+           </property>
+           <property name="flat">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBox">
+         <property name="title">
+          <string>Nodes</string>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_3">
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayout_5">
+            <item>
+             <widget class="QLabel" name="labelNode">
+              <property name="text">
+               <string>Node:</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QComboBox" name="comboBoxNodes">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayout_9">
+            <item alignment="Qt::AlignLeft">
+             <widget class="QLabel" name="labelEditBefore">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="palette">
+               <palette>
+                <active>
+                 <colorrole role="WindowText">
+                  <brush brushstyle="SolidPattern">
+                   <color alpha="255">
+                    <red>255</red>
+                    <green>0</green>
+                    <blue>0</blue>
+                   </color>
+                  </brush>
+                 </colorrole>
+                </active>
+                <inactive>
+                 <colorrole role="WindowText">
+                  <brush brushstyle="SolidPattern">
+                   <color alpha="255">
+                    <red>255</red>
+                    <green>0</green>
+                    <blue>0</blue>
+                   </color>
+                  </brush>
+                 </colorrole>
+                </inactive>
+                <disabled>
+                 <colorrole role="WindowText">
+                  <brush brushstyle="SolidPattern">
+                   <color alpha="255">
+                    <red>159</red>
+                    <green>158</green>
+                    <blue>158</blue>
+                   </color>
+                  </brush>
+                 </colorrole>
+                </disabled>
+               </palette>
+              </property>
+              <property name="text">
+               <string>Before:</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer_3">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QPushButton" name="pushButtonDefBefore">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+              <property name="toolTip">
+               <string>Return to default width</string>
+              </property>
+              <property name="text">
+               <string>Default</string>
+              </property>
+             </widget>
+            </item>
+            <item alignment="Qt::AlignRight">
+             <widget class="QToolButton" name="toolButtonExprBefore">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+              <property name="toolTip">
+               <string>Formula wizard</string>
+              </property>
+              <property name="text">
+               <string notr="true">...</string>
+              </property>
+              <property name="icon">
+               <iconset resource="../../../vmisc/share/resources/icon.qrc">
+                <normaloff>:/icon/24x24/fx.png</normaloff>:/icon/24x24/fx.png</iconset>
+              </property>
+              <property name="iconSize">
+               <size>
+                <width>24</width>
+                <height>24</height>
+               </size>
+              </property>
+             </widget>
+            </item>
+            <item alignment="Qt::AlignRight">
+             <widget class="QLabel" name="label_6">
+              <property name="text">
+               <string/>
+              </property>
+              <property name="pixmap">
+               <pixmap resource="../../../vmisc/share/resources/icon.qrc">:/icon/24x24/equal.png</pixmap>
+              </property>
+             </widget>
+            </item>
+            <item alignment="Qt::AlignRight">
+             <widget class="QLabel" name="labelResultBefore">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="minimumSize">
+               <size>
+                <width>87</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string>Value</string>
+              </property>
+              <property name="text">
+               <string notr="true">_</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayout_7">
+            <item>
+             <widget class="QPlainTextEdit" name="plainTextEditFormulaWidthBefore">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>16777215</width>
+                <height>28</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string>Calculation</string>
+              </property>
+              <property name="tabChangesFocus">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QPushButton" name="pushButtonGrowWidthBefore">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>18</width>
+                <height>18</height>
+               </size>
+              </property>
+              <property name="sizeIncrement">
+               <size>
+                <width>0</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show full calculation in message box&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+              </property>
+              <property name="text">
+               <string notr="true"/>
+              </property>
+              <property name="icon">
+               <iconset theme="go-down">
+                <normaloff>.</normaloff>.</iconset>
+              </property>
+              <property name="iconSize">
+               <size>
+                <width>16</width>
+                <height>16</height>
+               </size>
+              </property>
+              <property name="flat">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayout_16">
+            <item alignment="Qt::AlignLeft">
+             <widget class="QLabel" name="labelEditAfter">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="palette">
+               <palette>
+                <active>
+                 <colorrole role="WindowText">
+                  <brush brushstyle="SolidPattern">
+                   <color alpha="255">
+                    <red>255</red>
+                    <green>0</green>
+                    <blue>0</blue>
+                   </color>
+                  </brush>
+                 </colorrole>
+                </active>
+                <inactive>
+                 <colorrole role="WindowText">
+                  <brush brushstyle="SolidPattern">
+                   <color alpha="255">
+                    <red>255</red>
+                    <green>0</green>
+                    <blue>0</blue>
+                   </color>
+                  </brush>
+                 </colorrole>
+                </inactive>
+                <disabled>
+                 <colorrole role="WindowText">
+                  <brush brushstyle="SolidPattern">
+                   <color alpha="255">
+                    <red>159</red>
+                    <green>158</green>
+                    <blue>158</blue>
+                   </color>
+                  </brush>
+                 </colorrole>
+                </disabled>
+               </palette>
+              </property>
+              <property name="text">
+               <string>After:</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer_6">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QPushButton" name="pushButtonDefAfter">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+              <property name="toolTip">
+               <string>Return to default width</string>
+              </property>
+              <property name="text">
+               <string>Default</string>
+              </property>
+             </widget>
+            </item>
+            <item alignment="Qt::AlignRight">
+             <widget class="QToolButton" name="toolButtonExprAfter">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+              <property name="toolTip">
+               <string>Formula wizard</string>
+              </property>
+              <property name="text">
+               <string notr="true">...</string>
+              </property>
+              <property name="icon">
+               <iconset resource="../../../vmisc/share/resources/icon.qrc">
+                <normaloff>:/icon/24x24/fx.png</normaloff>:/icon/24x24/fx.png</iconset>
+              </property>
+              <property name="iconSize">
+               <size>
+                <width>24</width>
+                <height>24</height>
+               </size>
+              </property>
+             </widget>
+            </item>
+            <item alignment="Qt::AlignRight">
+             <widget class="QLabel" name="label_10">
+              <property name="text">
+               <string/>
+              </property>
+              <property name="pixmap">
+               <pixmap resource="../../../vmisc/share/resources/icon.qrc">:/icon/24x24/equal.png</pixmap>
+              </property>
+             </widget>
+            </item>
+            <item alignment="Qt::AlignRight">
+             <widget class="QLabel" name="labelResultAfter">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="minimumSize">
+               <size>
+                <width>87</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string>Value</string>
+              </property>
+              <property name="text">
+               <string notr="true">_</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayout_17">
+            <item>
+             <widget class="QPlainTextEdit" name="plainTextEditFormulaWidthAfter">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>16777215</width>
+                <height>28</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string>Calculation</string>
+              </property>
+              <property name="tabChangesFocus">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QPushButton" name="pushButtonGrowWidthAfter">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>18</width>
+                <height>18</height>
+               </size>
+              </property>
+              <property name="sizeIncrement">
+               <size>
+                <width>0</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show full calculation in message box&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+              </property>
+              <property name="text">
+               <string notr="true"/>
+              </property>
+              <property name="icon">
+               <iconset theme="go-down">
+                <normaloff>.</normaloff>.</iconset>
+              </property>
+              <property name="iconSize">
+               <size>
+                <width>16</width>
+                <height>16</height>
+               </size>
+              </property>
+              <property name="flat">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayout_2">
+            <item>
+             <widget class="QLabel" name="labelAngle">
+              <property name="text">
+               <string>Angle:</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QComboBox" name="comboBoxAngle">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer_4">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../../vmisc/share/resources/icon.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>DialogPiecePath</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>DialogPiecePath</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/src/libs/vtools/dialogs/tools/dialogseamallowance.cpp b/src/libs/vtools/dialogs/tools/dialogseamallowance.cpp
new file mode 100644
index 000000000..7ebc6f922
--- /dev/null
+++ b/src/libs/vtools/dialogs/tools/dialogseamallowance.cpp
@@ -0,0 +1,1769 @@
+/************************************************************************
+ **
+ **  @file   dialogseamallowance.cpp
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   3 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "dialogseamallowance.h"
+#include "ui_dialogseamallowance.h"
+#include "../vpatterndb/vpiecenode.h"
+#include "../vpatterndb/vpiecepath.h"
+#include "../vpatterndb/calculator.h"
+#include "visualization/path/vistoolpiece.h"
+#include "dialogpiecepath.h"
+#include "../../undocommands/savepiecepathoptions.h"
+#include "../support/dialogeditwrongformula.h"
+
+#include <QMenu>
+#include <QTimer>
+#include <QtNumeric>
+
+//---------------------------------------------------------------------------------------------------------------------
+DialogSeamAllowance::DialogSeamAllowance(const VContainer *data, const quint32 &toolId, QWidget *parent)
+    : DialogTool(data, toolId, parent),
+      ui(new Ui::DialogSeamAllowance),
+      applyAllowed(false),// By default disabled
+      m_bAddMode(true),
+      m_mx(0),
+      m_my(0),
+      m_dialog(),
+      m_qslMaterials(),
+      m_qslPlacements(),
+      m_conMCP(),
+      m_oldData(),
+      m_oldGeom(),
+      m_oldGrainline(),
+      m_iRotBaseHeight(0),
+      m_iLenBaseHeight(0),
+      m_formulaBaseWidth(0),
+      m_formulaBaseWidthBefore(0),
+      m_formulaBaseWidthAfter(0),
+      m_timerWidth(nullptr),
+      m_timerWidthBefore(nullptr),
+      m_timerWidthAfter(nullptr),
+      m_saWidth(0)
+{
+    ui->setupUi(this);
+
+    InitOkCancelApply(ui);
+    EnableApply(applyAllowed);
+
+    InitMainPathTab();
+    InitSeamAllowanceTab();
+    InitInternalPathsTab();
+    InitPatternPieceDataTab();
+    InitGrainlineTab();
+
+    flagName = true;//We have default name of piece.
+    ChangeColor(ui->labelEditName, okColor);
+    flagError = MainPathIsValid();
+    CheckState();
+
+    if (not applyAllowed)
+    {
+        vis = new VisToolPiece(data);
+    }
+
+    ui->tabWidget->setCurrentIndex(0);// Show always first tab active on start.
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+DialogSeamAllowance::~DialogSeamAllowance()
+{
+    VContainer *locData = const_cast<VContainer *> (data);
+    locData->RemoveVariable(currentSeamAllowance);
+
+    delete ui;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::EnableApply(bool enable)
+{
+    SCASSERT(bApply != nullptr);
+    bApply->setEnabled(enable);
+    applyAllowed = enable;
+    ui->tabSeamAllowance->setEnabled(applyAllowed);
+    ui->tabInternalPaths->setEnabled(applyAllowed);
+    ui->tabPatternPieceData->setEnabled(applyAllowed);
+    ui->tabGrainline->setEnabled(applyAllowed);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiece DialogSeamAllowance::GetPiece() const
+{
+    return CreatePiece();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::SetPiece(const VPiece &piece)
+{
+    ui->listWidgetMainPath->clear();
+    for (int i = 0; i < piece.GetPath().CountNodes(); ++i)
+    {
+        NewMainPathItem(piece.GetPath().at(i));
+    }
+
+    ui->listWidgetCustomSA->blockSignals(true);
+    ui->listWidgetCustomSA->clear();
+    const QVector<CustomSARecord> records = piece.GetCustomSARecords();
+    for (int i = 0; i < records.size(); ++i)
+    {
+        NewCustomSA(records.at(i));
+    }
+    ui->listWidgetCustomSA->blockSignals(false);
+
+    ui->listWidgetInternalPaths->clear();
+    const QVector<quint32> iPaths = piece.GetInternalPaths();
+    for (int i = 0; i < iPaths.size(); ++i)
+    {
+        NewInternalPath(iPaths.at(i));
+    }
+
+    ui->comboBoxStartPoint->blockSignals(true);
+    ui->comboBoxStartPoint->clear();
+    ui->comboBoxStartPoint->blockSignals(false);
+
+    ui->comboBoxEndPoint->blockSignals(true);
+    ui->comboBoxEndPoint->clear();
+    ui->comboBoxEndPoint->blockSignals(false);
+
+    CustomSAChanged(0);
+
+    ui->checkBoxForbidFlipping->setChecked(piece.IsForbidFlipping());
+    ui->checkBoxSeams->setChecked(piece.IsSeamAllowance());
+    ui->lineEditName->setText(piece.GetName());
+
+    ui->plainTextEditFormulaWidth->setPlainText(piece.GetFormulaSAWidth());
+    m_saWidth = piece.GetSAWidth();
+
+    m_mx = piece.GetMx();
+    m_my = piece.GetMy();
+
+    ui->lineEditLetter->setText(piece.GetPatternPieceData().GetLetter());
+    ui->checkBoxDetail->setChecked(piece.GetPatternPieceData().IsVisible());
+    ui->checkBoxPattern->setChecked(piece.GetPatternInfo().IsVisible());
+
+    m_conMCP.clear();
+    for (int i = 0; i < piece.GetPatternPieceData().GetMCPCount(); ++i)
+    {
+        m_conMCP << piece.GetPatternPieceData().GetMCP(i);
+    }
+
+    UpdateList();
+
+    ui->checkBoxGrainline->setChecked(piece.GetGrainlineGeometry().IsVisible());
+    ui->lineEditRotFormula->setPlainText(piece.GetGrainlineGeometry().GetRotation());
+    ui->lineEditLenFormula->setPlainText(piece.GetGrainlineGeometry().GetLength());
+    ui->comboBoxArrow->setCurrentIndex(int(piece.GetGrainlineGeometry().GetArrowType()));
+
+    m_oldData = piece.GetPatternPieceData();
+    m_oldGeom = piece.GetPatternInfo();
+    m_oldGrainline = piece.GetGrainlineGeometry();
+
+    ValidObjects(MainPathIsValid());
+    EnableGrainlineRotation();
+
+    ListChanged();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief ChoosedObject gets id and type of selected object. Save right data and ignore wrong.
+ * @param id id of objects (points, arcs, splines, spline paths)
+ * @param type type of object
+ */
+void DialogSeamAllowance::ChosenObject(quint32 id, const SceneObject &type)
+{
+    if (not prepare)
+    {
+        bool reverse = false;
+        if (QGuiApplication::keyboardModifiers() == Qt::ShiftModifier)
+        {
+            reverse = true;
+        }
+        if (id != GetLastId())
+        {
+            switch (type)
+            {
+                case SceneObject::Arc:
+                    NewMainPathItem(VPieceNode(id, Tool::NodeArc, reverse));
+                    break;
+                case SceneObject::Point:
+                    NewMainPathItem(VPieceNode(id, Tool::NodePoint));
+                    break;
+                case SceneObject::Spline:
+                    NewMainPathItem(VPieceNode(id, Tool::NodeSpline, reverse));
+                    break;
+                case SceneObject::SplinePath:
+                    NewMainPathItem(VPieceNode(id, Tool::NodeSplinePath, reverse));
+                    break;
+                case (SceneObject::Line):
+                case (SceneObject::Detail):
+                case (SceneObject::Unknown):
+                default:
+                    qDebug() << "Got wrong scene object. Ignore.";
+                    break;
+            }
+        }
+        else
+        {
+            if (ui->listWidgetMainPath->count() > 1)
+            {
+                delete GetItemById(id);
+            }
+        }
+
+        ValidObjects(MainPathIsValid());
+
+        if (not applyAllowed)
+        {
+            auto visPath = qobject_cast<VisToolPiece *>(vis);
+            SCASSERT(visPath != nullptr);
+            const VPiece p = CreatePiece();
+            visPath->SetPiece(p);
+
+            if (p.GetPath().CountNodes() == 1)
+            {
+                emit ToolTip(tr("Select main path objects clockwise, <b>Shift</b> - reverse direction curve, "
+                                "<b>Enter</b> - finish creation"));
+
+                if (not qApp->getCurrentScene()->items().contains(visPath))
+                {
+                    visPath->VisualMode(NULL_ID);
+                }
+                else
+                {
+                    visPath->RefreshGeometry();
+                }
+            }
+            else
+            {
+                visPath->RefreshGeometry();
+            }
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::ShowDialog(bool click)
+{
+    if (click == false)
+    {
+        emit ToolTip("");
+        prepare = true;
+
+        if (not applyAllowed)
+        {
+            auto visPath = qobject_cast<VisToolPiece *>(vis);
+            SCASSERT(visPath != nullptr);
+            visPath->SetMode(Mode::Show);
+            visPath->RefreshGeometry();
+        }
+
+        // Fix issue #526. Dialog Detail is not on top after selection second object on Mac.
+        setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
+        show();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::SaveData()
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::CheckState()
+{
+    SCASSERT(bOk != nullptr);
+    bOk->setEnabled(flagName && flagError && flagFormula);
+    // In case dialog hasn't apply button
+    if ( bApply != nullptr && applyAllowed)
+    {
+        bApply->setEnabled(bOk->isEnabled());
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::UpdateList()
+{
+    ui->listWidgetMCP->clear();
+    for (int i = 0; i < m_conMCP.count(); ++i)
+    {
+        MaterialCutPlacement mcp = m_conMCP.at(i);
+        QString qsText = tr("Cut %1 of %2%3").arg(mcp.m_iCutNumber);
+        if (mcp.m_eMaterial < MaterialType::mtUserDefined)
+        {
+            qsText = qsText.arg(m_qslMaterials[int(mcp.m_eMaterial)]);
+        }
+        else
+        {
+            qsText = qsText.arg(mcp.m_qsMaterialUserDef);
+        }
+        if (mcp.m_ePlacement == PlacementType::ptCutOnFold)
+        {
+            qsText = qsText.arg(QLatin1String(" ") + tr("on Fold"));
+        }
+        else
+        {
+            qsText = qsText.arg("");
+        }
+
+        ui->listWidgetMCP->addItem(qsText);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::AddUpdate()
+{
+    MaterialCutPlacement mcp;
+    QStringList qslUserMaterials = qApp->Settings()->GetUserDefinedMaterials();
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+    int i = ui->comboBoxMaterial->itemData(ui->comboBoxMaterial->currentIndex()).toInt();
+#else
+    int i = ui->comboBoxMaterial->currentData().toInt();
+#endif
+    QString qsMat = ui->comboBoxMaterial->currentText();
+    if (i < m_qslMaterials.count() && qsMat == m_qslMaterials[i])
+    {
+        mcp.m_eMaterial = MaterialType(i);
+        mcp.m_qsMaterialUserDef.clear();
+    }
+    else
+    {
+        mcp.m_eMaterial = MaterialType::mtUserDefined;
+        mcp.m_qsMaterialUserDef = qsMat;
+        // check if we have new user defined material
+        bool bFound = false;
+        for (int i = 0; i < qslUserMaterials.count() && bFound == false; ++i)
+        {
+            if (mcp.m_qsMaterialUserDef == qslUserMaterials[i])
+            {
+                bFound = true;
+            }
+        }
+        if (bFound == false)
+        {
+            qApp->Settings()->AddUserDefinedMaterial(mcp.m_qsMaterialUserDef);
+            qApp->Settings()->sync();
+            ui->comboBoxMaterial->addItem(mcp.m_qsMaterialUserDef, int(MaterialType::mtUserDefined));
+        }
+    }
+
+    mcp.m_iCutNumber = ui->spinBoxCutNumber->value();
+    mcp.m_ePlacement = PlacementType(ui->comboBoxPlacement->currentIndex());
+
+    if (m_bAddMode == true)
+    {
+        m_conMCP << mcp;
+    }
+    else
+    {
+        int iR = ui->listWidgetMCP->currentRow();
+        SCASSERT(iR >= 0)
+        m_conMCP[iR] = mcp;
+        SetAddMode();
+    }
+    UpdateList();
+    ClearFields();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::Cancel()
+{
+    ClearFields();
+    SetAddMode();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::Remove()
+{
+    int iR = ui->listWidgetMCP->currentRow();
+    SCASSERT(iR >= 0)
+    m_conMCP.removeAt(iR);
+    UpdateList();
+    ClearFields();
+    SetAddMode();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::NameDetailChanged()
+{
+    QLineEdit* edit = qobject_cast<QLineEdit*>(sender());
+    if (edit)
+    {
+        if (edit->text().isEmpty())
+        {
+            flagName = false;
+            ChangeColor(ui->labelEditName, Qt::red);
+            QIcon icon(":/icons/win.icon.theme/16x16/status/dialog-warning.png");
+            ui->tabWidget->setTabIcon(1, icon);
+        }
+        else
+        {
+            flagName = true;
+            ChangeColor(ui->labelEditName, okColor);
+            QIcon icon;
+            ui->tabWidget->setTabIcon(1, icon);
+        }
+    }
+    CheckState();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::MaterialChanged()
+{
+    ui->pushButtonAdd->setEnabled(ui->comboBoxMaterial->currentText().isEmpty() == false);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::ShowMainPathContextMenu(const QPoint &pos)
+{
+    const int row = ui->listWidgetMainPath->currentRow();
+    if (ui->listWidgetMainPath->count() == 0 || row == -1 || row >= ui->listWidgetMainPath->count())
+    {
+        return;
+    }
+
+    QMenu *menu = new QMenu(this);
+
+    QListWidgetItem *rowItem = ui->listWidgetMainPath->item(row);
+    SCASSERT(rowItem != nullptr);
+    VPieceNode rowNode = qvariant_cast<VPieceNode>(rowItem->data(Qt::UserRole));
+
+    QAction *actionReverse = nullptr;
+    if (rowNode.GetTypeTool() != Tool::NodePoint)
+    {
+        actionReverse = menu->addAction(tr("Reverse"));
+        actionReverse->setCheckable(true);
+        actionReverse->setChecked(rowNode.GetReverse());
+    }
+
+    QAction *actionDelete = menu->addAction(QIcon::fromTheme("edit-delete"), tr("Delete"));
+
+    QAction *selectedAction = menu->exec(ui->listWidgetMainPath->viewport()->mapToGlobal(pos));
+    if (selectedAction == actionDelete)
+    {
+        delete ui->listWidgetMainPath->item(row);
+        ValidObjects(MainPathIsValid());
+    }
+    else if (rowNode.GetTypeTool() != Tool::NodePoint && selectedAction == actionReverse)
+    {
+        rowNode.SetReverse(not rowNode.GetReverse());
+        rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode));
+        rowItem->setText(GetNodeName(rowNode));
+        ValidObjects(MainPathIsValid());
+    }
+
+    ListChanged();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::ShowCustomSAContextMenu(const QPoint &pos)
+{
+    const int row = ui->listWidgetCustomSA->currentRow();
+    if (ui->listWidgetCustomSA->count() == 0 || row == -1 || row >= ui->listWidgetCustomSA->count())
+    {
+        return;
+    }
+
+    QMenu *menu = new QMenu(this);
+    QAction *actionOption = menu->addAction(QIcon::fromTheme("preferences-other"), tr("Options"));
+
+    QListWidgetItem *rowItem = ui->listWidgetCustomSA->item(row);
+    SCASSERT(rowItem != nullptr);
+    CustomSARecord record = qvariant_cast<CustomSARecord>(rowItem->data(Qt::UserRole));
+
+    QAction *actionReverse = menu->addAction(tr("Reverse"));
+    actionReverse->setCheckable(true);
+    actionReverse->setChecked(record.reverse);
+
+    QAction *actionDelete = menu->addAction(QIcon::fromTheme("edit-delete"), tr("Delete"));
+
+    QAction *selectedAction = menu->exec(ui->listWidgetCustomSA->viewport()->mapToGlobal(pos));
+    if (selectedAction == actionDelete)
+    {
+        delete ui->listWidgetCustomSA->item(row);
+    }
+    else if (selectedAction == actionReverse)
+    {
+        record.reverse = not record.reverse;
+        rowItem->setData(Qt::UserRole, QVariant::fromValue(record));
+        rowItem->setText(GetPathName(record.path, record.reverse));
+    }
+    else if (selectedAction == actionOption)
+    {
+        auto *dialog = new DialogPiecePath(data, record.path, this);
+        dialog->SetPiecePath(data->GetPiecePath(record.path));
+        dialog->SetPieceId(toolId);
+        if (record.includeType == PiecePathIncludeType::AsMainPath)
+        {
+            dialog->SetFormulaSAWidth(GetFormulaSAWidth());
+        }
+        dialog->EnbleShowMode(true);
+        m_dialog = dialog;
+        m_dialog->setModal(true);
+        connect(m_dialog.data(), &DialogTool::DialogClosed, this, &DialogSeamAllowance::PathDialogClosed);
+        m_dialog->show();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::ShowInternalPathsContextMenu(const QPoint &pos)
+{
+    const int row = ui->listWidgetInternalPaths->currentRow();
+    if (ui->listWidgetInternalPaths->count() == 0 || row == -1 || row >= ui->listWidgetInternalPaths->count())
+    {
+        return;
+    }
+
+    QMenu *menu = new QMenu(this);
+    QAction *actionOption = menu->addAction(QIcon::fromTheme("preferences-other"), tr("Options"));
+    QAction *actionDelete = menu->addAction(QIcon::fromTheme("edit-delete"), tr("Delete"));
+
+    QAction *selectedAction = menu->exec(ui->listWidgetInternalPaths->viewport()->mapToGlobal(pos));
+    if (selectedAction == actionDelete)
+    {
+        delete ui->listWidgetInternalPaths->item(row);
+    }
+    else if (selectedAction == actionOption)
+    {
+        QListWidgetItem *rowItem = ui->listWidgetInternalPaths->item(row);
+        SCASSERT(rowItem != nullptr);
+        const quint32 pathId = qvariant_cast<quint32>(rowItem->data(Qt::UserRole));
+
+        auto *dialog = new DialogPiecePath(data, pathId, this);
+        dialog->SetPiecePath(data->GetPiecePath(pathId));
+        dialog->SetPieceId(toolId);
+        dialog->EnbleShowMode(true);
+        m_dialog = dialog;
+        m_dialog->setModal(true);
+        connect(m_dialog.data(), &DialogTool::DialogClosed, this, &DialogSeamAllowance::PathDialogClosed);
+        m_dialog->show();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::ListChanged()
+{
+    if (not applyAllowed)
+    {
+        auto visPath = qobject_cast<VisToolPiece *>(vis);
+        SCASSERT(visPath != nullptr);
+        visPath->SetPiece(CreatePiece());
+        visPath->RefreshGeometry();
+    }
+    InitNodesList();
+    CustomSAChanged(ui->listWidgetCustomSA->currentRow());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::EnableSeamAllowance(bool enable)
+{
+    ui->groupBoxAutomatic->setEnabled(enable);
+    ui->groupBoxCustom->setEnabled(enable);
+
+    if (enable)
+    {
+        InitNodesList();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::NodeChanged(int index)
+{
+    ui->plainTextEditFormulaWidthBefore->setDisabled(true);
+    ui->toolButtonExprBefore->setDisabled(true);
+    ui->pushButtonDefBefore->setDisabled(true);
+
+    ui->plainTextEditFormulaWidthAfter->setDisabled(true);
+    ui->toolButtonExprAfter->setDisabled(true);
+    ui->pushButtonDefAfter->setDisabled(true);
+
+    ui->comboBoxAngle->setDisabled(true);
+
+    ui->comboBoxAngle->blockSignals(true);
+
+    if (index != -1)
+    {
+    #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+        const quint32 id = ui->comboBoxNodes->itemData(index).toUInt();
+    #else
+        const quint32 id = ui->comboBoxNodes->currentData().toUInt();
+    #endif
+        const VPiece piece = CreatePiece();
+        const int nodeIndex = piece.GetPath().indexOfNode(id);
+        if (nodeIndex != -1)
+        {
+            const VPieceNode &node = piece.GetPath().at(nodeIndex);
+
+            // Seam alowance before
+            ui->plainTextEditFormulaWidthBefore->setEnabled(true);
+            ui->toolButtonExprBefore->setEnabled(true);
+
+            QString w1Formula = node.GetFormulaSABefore();
+            if (w1Formula != currentSeamAllowance)
+            {
+                ui->pushButtonDefBefore->setEnabled(true);
+            }
+            if (w1Formula.length() > 80)// increase height if needed.
+            {
+                this->DeployWidthBeforeFormulaTextEdit();
+            }
+            w1Formula = qApp->TrVars()->FormulaToUser(w1Formula, qApp->Settings()->GetOsSeparator());
+            ui->plainTextEditFormulaWidthBefore->setPlainText(w1Formula);
+            MoveCursorToEnd(ui->plainTextEditFormulaWidthBefore);
+
+            // Seam alowance after
+            ui->plainTextEditFormulaWidthAfter->setEnabled(true);
+            ui->toolButtonExprAfter->setEnabled(true);
+
+            QString w2Formula = node.GetFormulaSAAfter();
+            if (w2Formula != currentSeamAllowance)
+            {
+                ui->pushButtonDefAfter->setEnabled(true);
+            }
+            if (w2Formula.length() > 80)// increase height if needed.
+            {
+                this->DeployWidthAfterFormulaTextEdit();
+            }
+            w2Formula = qApp->TrVars()->FormulaToUser(w2Formula, qApp->Settings()->GetOsSeparator());
+            ui->plainTextEditFormulaWidthAfter->setPlainText(w2Formula);
+            MoveCursorToEnd(ui->plainTextEditFormulaWidthAfter);
+
+            // Angle type
+            ui->comboBoxAngle->setEnabled(true);
+            const int index = ui->comboBoxAngle->findData(static_cast<unsigned char>(node.GetAngleType()));
+            if (index != -1)
+            {
+                ui->comboBoxAngle->setCurrentIndex(index);
+            }
+        }
+    }
+    else
+    {
+        ui->plainTextEditFormulaWidthBefore->setPlainText("");
+        ui->plainTextEditFormulaWidthAfter->setPlainText("");
+        ui->comboBoxAngle->setCurrentIndex(-1);
+    }
+    ui->comboBoxAngle->blockSignals(false);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::CSAStartPointChanged(int index)
+{
+    const int row = ui->listWidgetCustomSA->currentRow();
+    if (ui->listWidgetCustomSA->count() == 0 || row == -1 || row >= ui->listWidgetCustomSA->count())
+    {
+        return;
+    }
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+    const quint32 startPoint = ui->comboBoxStartPoint->itemData(index).toUInt();
+#else
+    Q_UNUSED(index);
+    const quint32 startPoint = ui->comboBoxStartPoint->currentData().toUInt();
+#endif
+
+    QListWidgetItem *rowItem = ui->listWidgetCustomSA->item(row);
+    SCASSERT(rowItem != nullptr);
+    CustomSARecord record = qvariant_cast<CustomSARecord>(rowItem->data(Qt::UserRole));
+    record.startPoint = startPoint;
+    rowItem->setData(Qt::UserRole, QVariant::fromValue(record));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::CSAEndPointChanged(int index)
+{
+    const int row = ui->listWidgetCustomSA->currentRow();
+    if (ui->listWidgetCustomSA->count() == 0 || row == -1 || row >= ui->listWidgetCustomSA->count())
+    {
+        return;
+    }
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+    const quint32 endPoint = ui->comboBoxEndPoint->itemData(index).toUInt();
+#else
+    Q_UNUSED(index);
+    const quint32 endPoint = ui->comboBoxEndPoint->currentData().toUInt();
+#endif
+
+    QListWidgetItem *rowItem = ui->listWidgetCustomSA->item(row);
+    SCASSERT(rowItem != nullptr);
+    CustomSARecord record = qvariant_cast<CustomSARecord>(rowItem->data(Qt::UserRole));
+    record.endPoint = endPoint;
+    rowItem->setData(Qt::UserRole, QVariant::fromValue(record));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::CSAIncludeTypeChanged(int index)
+{
+    const int row = ui->listWidgetCustomSA->currentRow();
+    if (ui->listWidgetCustomSA->count() == 0 || row == -1 || row >= ui->listWidgetCustomSA->count())
+    {
+        return;
+    }
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+    const PiecePathIncludeType type =
+            static_cast<PiecePathIncludeType>(ui->comboBoxIncludeType->itemData(index).toUInt());
+#else
+    Q_UNUSED(index);
+    const PiecePathIncludeType type =
+            static_cast<PiecePathIncludeType>(ui->comboBoxIncludeType->currentData().toUInt());
+#endif
+
+    QListWidgetItem *rowItem = ui->listWidgetCustomSA->item(row);
+    SCASSERT(rowItem != nullptr);
+    CustomSARecord record = qvariant_cast<CustomSARecord>(rowItem->data(Qt::UserRole));
+    record.includeType = type;
+    rowItem->setData(Qt::UserRole, QVariant::fromValue(record));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::NodeAngleChanged(int index)
+{
+    const int i = ui->comboBoxNodes->currentIndex();
+    if (i != -1 && index != -1)
+    {
+    #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+        const quint32 id = ui->comboBoxNodes->itemData(i).toUInt();
+    #else
+        const quint32 id = ui->comboBoxNodes->currentData().toUInt();
+    #endif
+
+        QListWidgetItem *rowItem = GetItemById(id);
+        if (rowItem)
+        {
+        #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+            const PieceNodeAngle angle = static_cast<PieceNodeAngle>(ui->comboBoxAngle->itemData(index).toUInt());
+        #else
+            const PieceNodeAngle angle = static_cast<PieceNodeAngle>(ui->comboBoxAngle->currentData().toUInt());
+        #endif
+
+            VPieceNode rowNode = qvariant_cast<VPieceNode>(rowItem->data(Qt::UserRole));
+            rowNode.SetAngleType(angle);
+            rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode));
+
+            ListChanged();
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::ReturnDefBefore()
+{
+    ui->plainTextEditFormulaWidthBefore->setPlainText(currentSeamAllowance);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::ReturnDefAfter()
+{
+    ui->plainTextEditFormulaWidthAfter->setPlainText(currentSeamAllowance);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::CustomSAChanged(int row)
+{
+    if (ui->listWidgetCustomSA->count() == 0 || row == -1 || row >= ui->listWidgetCustomSA->count())
+    {
+        ui->comboBoxStartPoint->blockSignals(true);
+        ui->comboBoxStartPoint->clear();
+        ui->comboBoxStartPoint->blockSignals(false);
+
+        ui->comboBoxEndPoint->blockSignals(true);
+        ui->comboBoxEndPoint->clear();
+        ui->comboBoxEndPoint->blockSignals(false);
+
+        ui->comboBoxIncludeType->blockSignals(true);
+        ui->comboBoxIncludeType->clear();
+        ui->comboBoxIncludeType->blockSignals(false);
+        return;
+    }
+
+    const QListWidgetItem *item = ui->listWidgetCustomSA->item( row );
+    SCASSERT(item != nullptr);
+    const CustomSARecord record = qvariant_cast<CustomSARecord>(item->data(Qt::UserRole));
+
+    ui->comboBoxStartPoint->blockSignals(true);
+    InitCSAPoint(ui->comboBoxStartPoint);
+    {
+        const int index = ui->comboBoxStartPoint->findData(record.startPoint);
+        if (index != -1)
+        {
+            ui->comboBoxStartPoint->setCurrentIndex(index);
+        }
+    }
+    ui->comboBoxStartPoint->blockSignals(false);
+
+    ui->comboBoxEndPoint->blockSignals(true);
+    InitCSAPoint(ui->comboBoxEndPoint);
+    {
+        const int index = ui->comboBoxEndPoint->findData(record.endPoint);
+        if (index != -1)
+        {
+            ui->comboBoxEndPoint->setCurrentIndex(index);
+        }
+    }
+    ui->comboBoxEndPoint->blockSignals(false);
+
+    ui->comboBoxIncludeType->blockSignals(true);
+    InitSAIncludeType();
+    {
+        const int index = ui->comboBoxIncludeType->findData(static_cast<unsigned char>(record.includeType));
+        if (index != -1)
+        {
+            ui->comboBoxIncludeType->setCurrentIndex(index);
+        }
+    }
+    ui->comboBoxIncludeType->blockSignals(false);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::PathDialogClosed(int result)
+{
+    if (result == QDialog::Accepted)
+    {
+        SCASSERT(not m_dialog.isNull());
+        DialogPiecePath *dialogTool = qobject_cast<DialogPiecePath*>(m_dialog.data());
+        SCASSERT(dialogTool != nullptr);
+        try
+        {
+            const VPiecePath newPath = dialogTool->GetPiecePath();
+            const VPiecePath oldPath = data->GetPiecePath(dialogTool->GetToolId());
+
+            SavePiecePathOptions *saveCommand = new SavePiecePathOptions(oldPath, newPath, qApp->getCurrentDocument(),
+                                                                         const_cast<VContainer *>(data),
+                                                                         dialogTool->GetToolId());
+            qApp->getUndoStack()->push(saveCommand);
+            UpdateCurrentCustomSARecord();
+            UpdateCurrentInternalPathRecord();
+        }
+        catch (const VExceptionBadId &e)
+        {
+            qCritical("%s\n\n%s\n\n%s", qUtf8Printable(tr("Error. Can't save piece path.")),
+                       qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
+        }
+    }
+    delete m_dialog;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::UpdateValues()
+{
+    QPlainTextEdit* apleSender[2];
+    apleSender[0] = ui->lineEditRotFormula;
+    apleSender[1] = ui->lineEditLenFormula;
+    bool bFormulasOK = true;
+
+    for (int i = 0; i < 2; ++i)
+    {
+        QLabel* plbVal;
+        QLabel* plbText;
+        QString qsUnit;
+        if (i == 0)
+        {
+            plbVal = ui->labelRot;
+            plbText = ui->labelEditRot;
+            qsUnit = degreeSymbol;
+        }
+        else
+        {
+            plbVal = ui->labelLen;
+            plbText = ui->labelEditLen;
+            qsUnit = QLatin1String(" ") + VDomDocument::UnitsToStr(qApp->patternUnit());
+        }
+
+        plbVal->setToolTip(tr("Value"));
+
+        QString qsFormula = apleSender[i]->toPlainText().simplified();
+        Calculator cal;
+        QString qsVal;
+        try
+        {
+            qsFormula.replace("\n", " ");
+            qsFormula = qApp->TrVars()->FormulaFromUser(qsFormula, qApp->Settings()->GetOsSeparator());
+            qreal dVal;
+            dVal = cal.EvalFormula(data->PlainVariables(), qsFormula);
+            if (qIsInf(dVal) == true || qIsNaN(dVal) == true)
+            {
+                throw qmu::QmuParserError(tr("Infinite/undefined result"));
+            }
+            else if (i == 1 && dVal <= 0.0)
+            {
+                throw qmu::QmuParserError(tr("Length should be positive"));
+            }
+            else
+            {
+                qsVal.setNum(dVal, 'f', 2);
+                ChangeColor(plbText, okColor);
+            }
+        }
+        catch (qmu::QmuParserError &e)
+        {
+            qsVal.clear();
+            ChangeColor(plbText, Qt::red);
+            bFormulasOK = false;
+            plbVal->setToolTip(tr("Parser error: %1").arg(e.GetMsg()));
+        }
+
+        if (qsVal.isEmpty() == false)
+        {
+            qsVal += qsUnit;
+        }
+        plbVal->setText(qsVal);
+    }
+
+    bOk->setEnabled(bFormulasOK);
+    if (bFormulasOK == false)
+    {
+        QIcon icon(":/icons/win.icon.theme/16x16/status/dialog-warning.png");
+        ui->tabWidget->setTabIcon(ui->tabWidget->indexOf(ui->tabGrainline), icon);
+    }
+    else
+    {
+        ResetWarning();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::SetAddMode()
+{
+    ui->pushButtonAdd->setText(tr("Add"));
+    ui->pushButtonCancel->hide();
+    ui->pushButtonRemove->hide();
+    ui->listWidgetMCP->setCurrentRow(-1);
+    m_bAddMode = true;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::SetEditMode()
+{
+    int iR = ui->listWidgetMCP->currentRow();
+    // this method can be called by clicking on item or by update. In the latter case there is nothing else to do!
+    if (iR < 0 || iR >= m_conMCP.count())
+    {
+        return;
+    }
+
+    ui->pushButtonAdd->setText(tr("Update"));
+    ui->pushButtonCancel->show();
+    ui->pushButtonRemove->show();
+
+    MaterialCutPlacement mcp = m_conMCP.at(iR);
+    if (mcp.m_eMaterial == MaterialType::mtUserDefined)
+    {
+        int iRow = qApp->Settings()->GetUserDefinedMaterials().indexOf(mcp.m_qsMaterialUserDef);
+        if (iRow >= 0)
+        {
+            ui->comboBoxMaterial->setCurrentIndex(iRow + m_qslMaterials.count());
+        }
+        else
+        {
+            ui->comboBoxMaterial->setCurrentText(mcp.m_qsMaterialUserDef);
+        }
+    }
+    else
+    {
+        ui->comboBoxMaterial->setCurrentIndex(int(mcp.m_eMaterial));
+    }
+    ui->spinBoxCutNumber->setValue(mcp.m_iCutNumber);
+    ui->comboBoxPlacement->setCurrentIndex(int(mcp.m_ePlacement));
+
+    m_bAddMode = false;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::EnableGrainlineRotation()
+{
+    ui->lineEditRotFormula->setEnabled(ui->checkBoxGrainline->isChecked());
+    ui->lineEditLenFormula->setEnabled(ui->checkBoxGrainline->isChecked());
+    ui->pushButtonRot->setEnabled(ui->checkBoxGrainline->isChecked());
+    ui->pushButtonLen->setEnabled(ui->checkBoxGrainline->isChecked());
+    ui->pushButtonShowLen->setEnabled(ui->checkBoxGrainline->isChecked());
+    ui->pushButtonShowRot->setEnabled(ui->checkBoxGrainline->isChecked());
+
+    if (ui->checkBoxGrainline->isChecked() == true)
+    {
+        UpdateValues();
+    }
+    else
+    {
+        ChangeColor(ui->labelEditLen, okColor);
+        ChangeColor(ui->labelEditRot, okColor);
+        bOk->setEnabled(true);
+        ResetWarning();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::EditFormula()
+{
+    QPlainTextEdit* pleFormula;
+    bool bCheckZero;
+
+    if (sender() == ui->pushButtonLen)
+    {
+        pleFormula = ui->lineEditLenFormula;
+        bCheckZero = true;
+    }
+    else if (sender() == ui->pushButtonRot)
+    {
+        pleFormula = ui->lineEditRotFormula;
+        bCheckZero = false;
+    }
+    else
+    {
+        // should not get here!
+        return;
+    }
+
+    DialogEditWrongFormula dlg(data, NULL_ID, this);
+    dlg.SetFormula(pleFormula->toPlainText());
+    dlg.setCheckZero(bCheckZero);
+    if (dlg.exec() == QDialog::Accepted)
+    {
+        QString qsFormula = dlg.GetFormula();
+        qsFormula.replace("\n", " ");
+        pleFormula->setPlainText(qsFormula);
+        UpdateValues();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::DeployRotation()
+{
+    DeployFormula(ui->lineEditRotFormula, ui->pushButtonShowRot, m_iRotBaseHeight);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::DeployLength()
+{
+    DeployFormula(ui->lineEditLenFormula, ui->pushButtonShowLen, m_iLenBaseHeight);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::ResetWarning()
+{
+    QIcon icon;
+    ui->tabWidget->setTabIcon(ui->tabWidget->indexOf(ui->tabGrainline), icon);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::EvalWidth()
+{
+    labelEditFormula = ui->labelEditWidth;
+    const QString postfix = VDomDocument::UnitsToStr(qApp->patternUnit(), true);
+    const QString formula = ui->plainTextEditFormulaWidth->toPlainText();
+    m_saWidth = Eval(formula, flagFormula, ui->labelResultWidth, postfix, false, true);
+
+    if (m_saWidth >= 0)
+    {
+        VContainer *locData = const_cast<VContainer *> (data);
+        locData->AddVariable(currentSeamAllowance, new VIncrement(locData, currentSeamAllowance, 0, m_saWidth,
+                                                                  QString().setNum(m_saWidth), true,
+                                                                  tr("Current seam allowance")));
+
+        EvalWidthBefore();
+        EvalWidthAfter();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::EvalWidthBefore()
+{
+    labelEditFormula = ui->labelEditBefore;
+    const QString postfix = VDomDocument::UnitsToStr(qApp->patternUnit(), true);
+    const QString formula = ui->plainTextEditFormulaWidthBefore->toPlainText();
+    bool flagFormula = false; // fake flag
+    Eval(formula, flagFormula, ui->labelResultBefore, postfix, false, true);
+
+    UpdateNodeSABefore(GetFormulaSAWidthBefore());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::EvalWidthAfter()
+{
+    labelEditFormula = ui->labelEditAfter;
+    const QString postfix = VDomDocument::UnitsToStr(qApp->patternUnit(), true);
+    const QString formula = ui->plainTextEditFormulaWidthAfter->toPlainText();
+    bool flagFormula = false; // fake flag
+    Eval(formula, flagFormula, ui->labelResultAfter, postfix, false, true);
+
+    UpdateNodeSAAfter(GetFormulaSAWidthAfter());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::FXWidth()
+{
+    DialogEditWrongFormula *dialog = new DialogEditWrongFormula(data, toolId, this);
+    dialog->setWindowTitle(tr("Edit seam allowance width"));
+    dialog->SetFormula(GetFormulaSAWidth());
+    dialog->setCheckLessThanZero(true);
+    dialog->setPostfix(VDomDocument::UnitsToStr(qApp->patternUnit(), true));
+    if (dialog->exec() == QDialog::Accepted)
+    {
+        SetFormulaSAWidth(dialog->GetFormula());
+    }
+    delete dialog;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::FXWidthBefore()
+{
+    DialogEditWrongFormula *dialog = new DialogEditWrongFormula(data, toolId, this);
+    dialog->setWindowTitle(tr("Edit seam allowance width before"));
+    dialog->SetFormula(GetFormulaSAWidthBefore());
+    dialog->setCheckLessThanZero(true);
+    dialog->setPostfix(VDomDocument::UnitsToStr(qApp->patternUnit(), true));
+    if (dialog->exec() == QDialog::Accepted)
+    {
+        SetCurrentSABefore(dialog->GetFormula());
+    }
+    delete dialog;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::FXWidthAfter()
+{
+    DialogEditWrongFormula *dialog = new DialogEditWrongFormula(data, toolId, this);
+    dialog->setWindowTitle(tr("Edit seam allowance width after"));
+    dialog->SetFormula(GetFormulaSAWidthAfter());
+    dialog->setCheckLessThanZero(true);
+    dialog->setPostfix(VDomDocument::UnitsToStr(qApp->patternUnit(), true));
+    if (dialog->exec() == QDialog::Accepted)
+    {
+        SetCurrentSAAfter(dialog->GetFormula());
+    }
+    delete dialog;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::WidthChanged()
+{
+    labelEditFormula = ui->labelEditWidth;
+    labelResultCalculation = ui->labelResultWidth;
+    const QString postfix = VDomDocument::UnitsToStr(qApp->patternUnit(), true);
+    ValFormulaChanged(flagFormula, ui->plainTextEditFormulaWidth, m_timerWidth, postfix);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::WidthBeforeChanged()
+{
+    labelEditFormula = ui->labelEditBefore;
+    labelResultCalculation = ui->labelResultBefore;
+    const QString postfix = VDomDocument::UnitsToStr(qApp->patternUnit(), true);
+    bool flagFormula = false;
+    ValFormulaChanged(flagFormula, ui->plainTextEditFormulaWidthBefore, m_timerWidthBefore, postfix);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::WidthAfterChanged()
+{
+    labelEditFormula = ui->labelEditAfter;
+    labelResultCalculation = ui->labelResultAfter;
+    const QString postfix = VDomDocument::UnitsToStr(qApp->patternUnit(), true);
+    bool flagFormula = false;
+    ValFormulaChanged(flagFormula, ui->plainTextEditFormulaWidthAfter, m_timerWidthAfter, postfix);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::DeployWidthFormulaTextEdit()
+{
+    DeployFormula(ui->plainTextEditFormulaWidth, ui->pushButtonGrowWidth, m_formulaBaseWidth);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::DeployWidthBeforeFormulaTextEdit()
+{
+    DeployFormula(ui->plainTextEditFormulaWidthBefore, ui->pushButtonGrowWidthBefore, m_formulaBaseWidthBefore);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::DeployWidthAfterFormulaTextEdit()
+{
+    DeployFormula(ui->plainTextEditFormulaWidthAfter, ui->pushButtonGrowWidthAfter, m_formulaBaseWidthAfter);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiece DialogSeamAllowance::CreatePiece() const
+{
+    VPiece piece;
+    for (qint32 i = 0; i < ui->listWidgetMainPath->count(); ++i)
+    {
+        QListWidgetItem *item = ui->listWidgetMainPath->item(i);
+        piece.GetPath().Append(qvariant_cast<VPieceNode>(item->data(Qt::UserRole)));
+    }
+
+    QVector<CustomSARecord> records;
+    for (qint32 i = 0; i < ui->listWidgetCustomSA->count(); ++i)
+    {
+        QListWidgetItem *item = ui->listWidgetCustomSA->item(i);
+        records.append(qvariant_cast<CustomSARecord>(item->data(Qt::UserRole)));
+    }
+    piece.SetCustomSARecords(records);
+
+    QVector<quint32> iPaths;
+    for (qint32 i = 0; i < ui->listWidgetInternalPaths->count(); ++i)
+    {
+        QListWidgetItem *item = ui->listWidgetInternalPaths->item(i);
+        iPaths.append(qvariant_cast<quint32>(item->data(Qt::UserRole)));
+    }
+    piece.SetInternalPaths(iPaths);
+
+    piece.SetForbidFlipping(ui->checkBoxForbidFlipping->isChecked());
+    piece.SetSeamAllowance(ui->checkBoxSeams->isChecked());
+    piece.SetName(ui->lineEditName->text());
+    piece.SetMx(m_mx);
+    piece.SetMy(m_my);
+
+    QString width = ui->plainTextEditFormulaWidth->toPlainText();
+    width.replace("\n", " ");
+    piece.SetFormulaSAWidth(width, m_saWidth);
+
+    piece.GetPatternPieceData().SetLetter(ui->lineEditLetter->text());
+
+    for (int i = 0; i < m_conMCP.count(); ++i)
+    {
+        piece.GetPatternPieceData().Append(m_conMCP[i]);
+    }
+
+    piece.GetPatternPieceData().SetPos(m_oldData.GetPos());
+    piece.GetPatternPieceData().SetLabelWidth(m_oldData.GetLabelWidth());
+    piece.GetPatternPieceData().SetLabelHeight(m_oldData.GetLabelHeight());
+    piece.GetPatternPieceData().SetFontSize(m_oldData.GetFontSize());
+    piece.GetPatternPieceData().SetRotation(m_oldData.GetRotation());
+    piece.GetPatternPieceData().SetVisible(ui->checkBoxDetail->isChecked());
+
+    piece.GetPatternInfo() = m_oldGeom;
+    piece.GetPatternInfo().SetVisible(ui->checkBoxPattern->isChecked());
+
+    piece.GetGrainlineGeometry() = m_oldGrainline;
+    piece.GetGrainlineGeometry().SetVisible(ui->checkBoxGrainline->isChecked());
+    piece.GetGrainlineGeometry().SetRotation(ui->lineEditRotFormula->toPlainText());
+    piece.GetGrainlineGeometry().SetLength(ui->lineEditLenFormula->toPlainText());
+    piece.GetGrainlineGeometry().SetArrowType(VGrainlineGeometry::ArrowType(ui->comboBoxArrow->currentIndex()));
+
+    return piece;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::NewMainPathItem(const VPieceNode &node)
+{
+    NewNodeItem(ui->listWidgetMainPath, node);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::NewCustomSA(const CustomSARecord &record)
+{
+    if (record.path > NULL_ID)
+    {
+        const QString name = GetPathName(record.path, record.reverse);
+
+        QListWidgetItem *item = new QListWidgetItem(name);
+        item->setFont(QFont("Times", 12, QFont::Bold));
+        item->setData(Qt::UserRole, QVariant::fromValue(record));
+        ui->listWidgetCustomSA->addItem(item);
+        ui->listWidgetCustomSA->setCurrentRow(ui->listWidgetCustomSA->count()-1);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::NewInternalPath(quint32 path)
+{
+    if (path > NULL_ID)
+    {
+        const QString name = GetPathName(path);
+
+        QListWidgetItem *item = new QListWidgetItem(name);
+        item->setFont(QFont("Times", 12, QFont::Bold));
+        item->setData(Qt::UserRole, QVariant::fromValue(path));
+        ui->listWidgetInternalPaths->addItem(item);
+        ui->listWidgetInternalPaths->setCurrentRow(ui->listWidgetInternalPaths->count()-1);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString DialogSeamAllowance::GetPathName(quint32 path, bool reverse) const
+{
+    QString name;
+
+    if (path > NULL_ID)
+    {
+        name = data->GetPiecePath(path).GetName();
+
+        if (reverse)
+        {
+            name = QLatin1String("- ") + name;
+        }
+    }
+
+    return name;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool DialogSeamAllowance::MainPathIsValid() const
+{
+    QString url = DialogWarningIcon();
+
+    if(CreatePiece().MainPathPoints(data).count() < 3)
+    {
+        url += tr("You need more points!");
+        ui->helpLabel->setText(url);
+        return false;
+    }
+    else
+    {
+        if(not MainPathIsClockwise())
+        {
+            url += tr("You have to choose points in a clockwise direction!");
+            ui->helpLabel->setText(url);
+            return false;
+        }
+        if (FirstPointEqualLast(ui->listWidgetMainPath))
+        {
+            url += tr("First point cannot be equal to the last point!");
+            ui->helpLabel->setText(url);
+            return false;
+        }
+        else if (DoublePoints(ui->listWidgetMainPath))
+        {
+            url += tr("You have double points!");
+            ui->helpLabel->setText(url);
+            return false;
+        }
+    }
+    ui->helpLabel->setText(tr("Ready!"));
+    return true;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::ValidObjects(bool value)
+{
+    flagError = value;
+    CheckState();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool DialogSeamAllowance::MainPathIsClockwise() const
+{
+    const QVector<QPointF> points = CreatePiece().MainPathPoints(data);
+
+    if(points.count() < 3)
+    {
+        return false;
+    }
+
+    const qreal res = VPiece::SumTrapezoids(points);
+    if (res < 0)
+    {
+        return true;
+    }
+    return false;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::InitNodesList()
+{
+#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+    const quint32 id = ui->comboBoxNodes->itemData(ui->comboBoxNodes->currentIndex()).toUInt();
+#else
+    const quint32 id = ui->comboBoxNodes->currentData().toUInt();
+#endif
+
+    ui->comboBoxNodes->blockSignals(true);
+    ui->comboBoxNodes->clear();
+
+    const VPiece piece = CreatePiece();
+
+    for (int i = 0; i < piece.GetPath().CountNodes(); ++i)
+    {
+        const VPieceNode node = piece.GetPath().at(i);
+        if (node.GetTypeTool() == Tool::NodePoint)
+        {
+            const QString name = GetNodeName(node);
+
+            ui->comboBoxNodes->addItem(name, node.GetId());
+        }
+    }
+    ui->comboBoxNodes->blockSignals(false);
+
+    const int index = ui->comboBoxNodes->findData(id);
+    if (index != -1)
+    {
+        ui->comboBoxNodes->setCurrentIndex(index);
+        NodeChanged(index);// Need in case combox index was not changed
+    }
+    else
+    {
+        ui->comboBoxNodes->count() > 0 ? NodeChanged(0) : NodeChanged(-1);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QListWidgetItem *DialogSeamAllowance::GetItemById(quint32 id)
+{
+    for (qint32 i = 0; i < ui->listWidgetMainPath->count(); ++i)
+    {
+        QListWidgetItem *item = ui->listWidgetMainPath->item(i);
+        const VPieceNode node = qvariant_cast<VPieceNode>(item->data(Qt::UserRole));
+
+        if (node.GetId() == id)
+        {
+            return item;
+        }
+    }
+    return nullptr;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+quint32 DialogSeamAllowance::GetLastId() const
+{
+    const int count = ui->listWidgetMainPath->count();
+    if (count > 0)
+    {
+        QListWidgetItem *item = ui->listWidgetMainPath->item(count-1);
+        const VPieceNode node = qvariant_cast<VPieceNode>(item->data(Qt::UserRole));
+        return node.GetId();
+    }
+    else
+    {
+        return NULL_ID;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::SetCurrentSABefore(const QString &formula)
+{
+    UpdateNodeSABefore(formula);
+    ListChanged();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::SetCurrentSAAfter(const QString &formula)
+{
+    UpdateNodeSAAfter(formula);
+    ListChanged();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::UpdateNodeSABefore(const QString &formula)
+{
+    const int index = ui->comboBoxNodes->currentIndex();
+    if (index != -1)
+    {
+    #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+        const quint32 id = ui->comboBoxNodes->itemData(index).toUInt();
+    #else
+        const quint32 id = ui->comboBoxNodes->currentData().toUInt();
+    #endif
+
+        QListWidgetItem *rowItem = GetItemById(id);
+        if (rowItem)
+        {
+            VPieceNode rowNode = qvariant_cast<VPieceNode>(rowItem->data(Qt::UserRole));
+            rowNode.SetFormulaSABefore(formula);
+            rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode));
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::UpdateNodeSAAfter(const QString &formula)
+{
+    const int index = ui->comboBoxNodes->currentIndex();
+    if (index != -1)
+    {
+    #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
+        const quint32 id = ui->comboBoxNodes->itemData(index).toUInt();
+    #else
+        const quint32 id = ui->comboBoxNodes->currentData().toUInt();
+    #endif
+
+        QListWidgetItem *rowItem = GetItemById(id);
+        if (rowItem)
+        {
+            VPieceNode rowNode = qvariant_cast<VPieceNode>(rowItem->data(Qt::UserRole));
+            rowNode.SetFormulaSAAfter(formula);
+            rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode));
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::InitMainPathTab()
+{
+    ui->checkBoxForbidFlipping->setChecked(qApp->Settings()->GetForbidWorkpieceFlipping());
+
+    ui->listWidgetMainPath->setContextMenuPolicy(Qt::CustomContextMenu);
+    connect(ui->listWidgetMainPath, &QListWidget::customContextMenuRequested, this,
+            &DialogSeamAllowance::ShowMainPathContextMenu);
+    connect(ui->listWidgetMainPath->model(), &QAbstractItemModel::rowsMoved, this, &DialogSeamAllowance::ListChanged);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::InitSeamAllowanceTab()
+{
+    plainTextEditFormula = ui->plainTextEditFormulaWidth;
+    this->m_formulaBaseWidth = ui->plainTextEditFormulaWidth->height();
+    this->m_formulaBaseWidthBefore = ui->plainTextEditFormulaWidthBefore->height();
+    this->m_formulaBaseWidthAfter = ui->plainTextEditFormulaWidthAfter->height();
+
+    ui->plainTextEditFormulaWidth->installEventFilter(this);
+    ui->plainTextEditFormulaWidthBefore->installEventFilter(this);
+    ui->plainTextEditFormulaWidthAfter->installEventFilter(this);
+
+    m_timerWidth = new QTimer(this);
+    connect(m_timerWidth, &QTimer::timeout, this, &DialogSeamAllowance::EvalWidth);
+
+    m_timerWidthBefore = new QTimer(this);
+    connect(m_timerWidthBefore, &QTimer::timeout, this, &DialogSeamAllowance::EvalWidthBefore);
+
+    m_timerWidthAfter = new QTimer(this);
+    connect(m_timerWidthAfter, &QTimer::timeout, this, &DialogSeamAllowance::EvalWidthAfter);
+
+    connect(ui->checkBoxSeams, &QCheckBox::toggled, this, &DialogSeamAllowance::EnableSeamAllowance);
+
+    // Default value for seam allowence is 1 cm. But pattern have different units, so just set 1 in dialog not enough.
+    m_saWidth = UnitConvertor(1, Unit::Cm, qApp->patternUnit());
+    ui->plainTextEditFormulaWidth->setPlainText(qApp->LocaleToString(m_saWidth));
+
+    InitNodesList();
+    connect(ui->comboBoxNodes, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+            &DialogSeamAllowance::NodeChanged);
+
+    connect(ui->pushButtonDefBefore, &QPushButton::clicked, this, &DialogSeamAllowance::ReturnDefBefore);
+    connect(ui->pushButtonDefAfter, &QPushButton::clicked, this, &DialogSeamAllowance::ReturnDefAfter);
+
+    InitNodeAngles(ui->comboBoxAngle);
+    connect(ui->comboBoxAngle, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+            &DialogSeamAllowance::NodeAngleChanged);
+
+    ui->listWidgetCustomSA->setContextMenuPolicy(Qt::CustomContextMenu);
+    connect(ui->listWidgetCustomSA, &QListWidget::customContextMenuRequested, this,
+            &DialogSeamAllowance::ShowCustomSAContextMenu);
+    connect(ui->listWidgetCustomSA, &QListWidget::currentRowChanged, this, &DialogSeamAllowance::CustomSAChanged);
+    connect(ui->comboBoxStartPoint, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+            &DialogSeamAllowance::CSAStartPointChanged);
+    connect(ui->comboBoxEndPoint, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+            &DialogSeamAllowance::CSAEndPointChanged);
+    connect(ui->comboBoxIncludeType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+            &DialogSeamAllowance::CSAIncludeTypeChanged);
+
+    connect(ui->toolButtonExprWidth, &QPushButton::clicked, this, &DialogSeamAllowance::FXWidth);
+    connect(ui->toolButtonExprBefore, &QPushButton::clicked, this, &DialogSeamAllowance::FXWidthBefore);
+    connect(ui->toolButtonExprAfter, &QPushButton::clicked, this, &DialogSeamAllowance::FXWidthAfter);
+
+    connect(ui->plainTextEditFormulaWidth, &QPlainTextEdit::textChanged, this, &DialogSeamAllowance::WidthChanged);
+    connect(ui->plainTextEditFormulaWidthBefore, &QPlainTextEdit::textChanged, this,
+            &DialogSeamAllowance::WidthBeforeChanged);
+    connect(ui->plainTextEditFormulaWidthAfter, &QPlainTextEdit::textChanged, this,
+            &DialogSeamAllowance::WidthAfterChanged);
+
+    connect(ui->pushButtonGrowWidth, &QPushButton::clicked, this, &DialogSeamAllowance::DeployWidthFormulaTextEdit);
+    connect(ui->pushButtonGrowWidthBefore, &QPushButton::clicked,
+            this, &DialogSeamAllowance::DeployWidthBeforeFormulaTextEdit);
+    connect(ui->pushButtonGrowWidthAfter, &QPushButton::clicked, this,
+            &DialogSeamAllowance::DeployWidthAfterFormulaTextEdit);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::InitCSAPoint(QComboBox *box)
+{
+    SCASSERT(box != nullptr);
+    box->clear();
+    box->addItem(tr("Empty"), NULL_ID);
+
+    const VPiece piece = CreatePiece();
+
+    for (int i = 0; i < piece.GetPath().CountNodes(); ++i)
+    {
+        const VPieceNode &node = piece.GetPath().at(i);
+        if (node.GetTypeTool() == Tool::NodePoint)
+        {
+            const QString name = GetNodeName(node);
+            box->addItem(name, node.GetId());
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::InitSAIncludeType()
+{
+    ui->comboBoxIncludeType->clear();
+
+    ui->comboBoxIncludeType->addItem(tr("main path"), static_cast<unsigned char>(PiecePathIncludeType::AsMainPath));
+    ui->comboBoxIncludeType->addItem(tr("custom seam allowance"),
+                                     static_cast<unsigned char>(PiecePathIncludeType::AsCustomSA));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::InitInternalPathsTab()
+{
+    ui->listWidgetInternalPaths->setContextMenuPolicy(Qt::CustomContextMenu);
+    connect(ui->listWidgetInternalPaths, &QListWidget::customContextMenuRequested, this,
+            &DialogSeamAllowance::ShowInternalPathsContextMenu);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::InitPatternPieceDataTab()
+{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
+    ui->lineEditName->setClearButtonEnabled(true);
+    ui->lineEditLetter->setClearButtonEnabled(true);
+#endif
+
+    connect(ui->lineEditName, &QLineEdit::textChanged, this, &DialogSeamAllowance::NameDetailChanged);
+
+    m_qslMaterials << QApplication::translate("Detail", "Fabric", 0)
+                   << QApplication::translate("Detail", "Lining", 0)
+                   << QApplication::translate("Detail", "Interfacing", 0)
+                   << QApplication::translate("Detail", "Interlining", 0);
+
+    for (int i = 0; i < m_qslMaterials.count(); ++i)
+    {
+        ui->comboBoxMaterial->addItem(m_qslMaterials[i], i);
+    }
+
+    const QStringList qsl = qApp->Settings()->GetUserDefinedMaterials();
+    for (int i = 0; i < qsl.count(); ++i)
+    {
+        ui->comboBoxMaterial->addItem(qsl.at(i), int(MaterialType::mtUserDefined));
+    }
+
+    m_qslPlacements << tr("None") << tr("Cut on fold");
+    ui->comboBoxPlacement->addItems(m_qslPlacements);
+    ui->pushButtonRot->setIcon(QIcon("://icon/16x16/fx.png"));
+    ui->pushButtonLen->setIcon(QIcon("://icon/16x16/fx.png"));
+
+    connect(ui->pushButtonAdd, &QPushButton::clicked, this, &DialogSeamAllowance::AddUpdate);
+    connect(ui->pushButtonCancel, &QPushButton::clicked, this, &DialogSeamAllowance::Cancel);
+    connect(ui->pushButtonRemove, &QPushButton::clicked, this, &DialogSeamAllowance::Remove);
+    connect(ui->listWidgetMCP, &QListWidget::itemClicked, this, &DialogSeamAllowance::SetEditMode);
+    connect(ui->comboBoxMaterial, &QComboBox::currentTextChanged, this, &DialogSeamAllowance::MaterialChanged);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::InitGrainlineTab()
+{
+    connect(ui->checkBoxGrainline, &QCheckBox::toggled, this, &DialogSeamAllowance::EnableGrainlineRotation);
+    connect(ui->pushButtonRot, &QPushButton::clicked, this, &DialogSeamAllowance::EditFormula);
+    connect(ui->pushButtonLen, &QPushButton::clicked, this, &DialogSeamAllowance::EditFormula);
+    connect(ui->lineEditLenFormula, &QPlainTextEdit::textChanged, this, &DialogSeamAllowance::UpdateValues);
+    connect(ui->lineEditRotFormula, &QPlainTextEdit::textChanged, this, &DialogSeamAllowance::UpdateValues);
+
+    connect(ui->pushButtonShowRot, &QPushButton::clicked, this, &DialogSeamAllowance::DeployRotation);
+    connect(ui->pushButtonShowLen, &QPushButton::clicked, this, &DialogSeamAllowance::DeployLength);
+
+    SetAddMode();
+    EnableGrainlineRotation();
+
+    ui->comboBoxArrow->addItem(tr("Both"));
+    ui->comboBoxArrow->addItem(tr("Just front"));
+    ui->comboBoxArrow->addItem(tr("Just rear"));
+
+    m_iRotBaseHeight = ui->lineEditRotFormula->height();
+    m_iLenBaseHeight = ui->lineEditLenFormula->height();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString DialogSeamAllowance::GetFormulaSAWidth() const
+{
+    QString width = ui->plainTextEditFormulaWidth->toPlainText();
+    width.replace("\n", " ");
+    return qApp->TrVars()->TryFormulaFromUser(width, qApp->Settings()->GetOsSeparator());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::SetFormulaSAWidth(const QString &formula)
+{
+    const QString width = qApp->TrVars()->FormulaToUser(formula, qApp->Settings()->GetOsSeparator());
+    // increase height if needed.
+    if (width.length() > 80)
+    {
+        this->DeployWidthFormulaTextEdit();
+    }
+    ui->plainTextEditFormulaWidth->setPlainText(width);
+
+    VisToolPiece *path = qobject_cast<VisToolPiece *>(vis);
+    SCASSERT(path != nullptr)
+    const VPiece p = CreatePiece();
+    path->SetPiece(p);
+
+    MoveCursorToEnd(ui->plainTextEditFormulaWidth);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString DialogSeamAllowance::GetFormulaSAWidthBefore() const
+{
+    QString width = ui->plainTextEditFormulaWidthBefore->toPlainText();
+    width.replace("\n", " ");
+    return qApp->TrVars()->TryFormulaFromUser(width, qApp->Settings()->GetOsSeparator());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString DialogSeamAllowance::GetFormulaSAWidthAfter() const
+{
+    QString width = ui->plainTextEditFormulaWidthAfter->toPlainText();
+    width.replace("\n", " ");
+    return qApp->TrVars()->TryFormulaFromUser(width, qApp->Settings()->GetOsSeparator());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::UpdateCurrentCustomSARecord()
+{
+    const int row = ui->listWidgetCustomSA->currentRow();
+    if (ui->listWidgetCustomSA->count() == 0 || row == -1)
+    {
+        return;
+    }
+
+    QListWidgetItem *item = ui->listWidgetCustomSA->item(row);
+    SCASSERT(item != nullptr);
+    const CustomSARecord record = qvariant_cast<CustomSARecord>(item->data(Qt::UserRole));
+    item->setText(GetPathName(record.path, record.reverse));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::UpdateCurrentInternalPathRecord()
+{
+    const int row = ui->listWidgetInternalPaths->currentRow();
+    if (ui->listWidgetInternalPaths->count() == 0 || row == -1)
+    {
+        return;
+    }
+
+    QListWidgetItem *item = ui->listWidgetInternalPaths->item(row);
+    SCASSERT(item != nullptr);
+    const quint32 path = qvariant_cast<quint32>(item->data(Qt::UserRole));
+    item->setText(GetPathName(path));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogSeamAllowance::ClearFields()
+{
+    ui->comboBoxMaterial->setCurrentIndex(0);
+    ui->spinBoxCutNumber->setValue(0);
+    ui->comboBoxPlacement->setCurrentIndex(0);
+}
diff --git a/src/libs/vtools/dialogs/tools/dialogseamallowance.h b/src/libs/vtools/dialogs/tools/dialogseamallowance.h
new file mode 100644
index 000000000..ece3aff7a
--- /dev/null
+++ b/src/libs/vtools/dialogs/tools/dialogseamallowance.h
@@ -0,0 +1,185 @@
+/************************************************************************
+ **
+ **  @file   dialogseamallowance.h
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   3 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef DIALOGSEAMALLOWANCE_H
+#define DIALOGSEAMALLOWANCE_H
+
+#include "dialogtool.h"
+#include "../vpatterndb/vpiece.h"
+#include "../vpatterndb/vpatterninfogeometry.h"
+#include "../vpatterndb/vpatternpiecedata.h"
+#include "../vpatterndb/vgrainlinegeometry.h"
+
+namespace Ui
+{
+    class DialogSeamAllowance;
+}
+
+class DialogSeamAllowance : public DialogTool
+{
+    Q_OBJECT
+
+public:
+    DialogSeamAllowance(const VContainer *data, const quint32 &toolId, QWidget *parent = nullptr);
+    virtual ~DialogSeamAllowance();
+
+    void EnableApply(bool enable);
+
+    VPiece GetPiece() const;
+    void   SetPiece(const VPiece &m_piece);
+
+    QString GetFormulaSAWidth() const;
+
+public slots:
+    virtual void ChosenObject(quint32 id, const SceneObject &type) Q_DECL_OVERRIDE;
+    virtual void ShowDialog(bool click) Q_DECL_OVERRIDE;
+
+protected:
+    /** @brief SaveData Put dialog data in local variables */
+    virtual void SaveData() Q_DECL_OVERRIDE;
+    virtual void CheckState() Q_DECL_OVERRIDE;
+
+protected slots:
+    void UpdateList();
+    void AddUpdate();
+    void Cancel();
+    void Remove();
+
+private slots:
+    void NameDetailChanged();
+    void MaterialChanged();
+    void ShowMainPathContextMenu(const QPoint &pos);
+    void ShowCustomSAContextMenu(const QPoint &pos);
+    void ShowInternalPathsContextMenu(const QPoint &pos);
+
+    void ListChanged();
+    void EnableSeamAllowance(bool enable);
+    void NodeChanged(int index);
+    void CSAStartPointChanged(int index);
+    void CSAEndPointChanged(int index);
+    void CSAIncludeTypeChanged(int index);
+    void NodeAngleChanged(int index);
+    void ReturnDefBefore();
+    void ReturnDefAfter();
+    void CustomSAChanged(int row);
+    void PathDialogClosed(int result);
+
+    void UpdateValues();
+    void SetAddMode();
+    void SetEditMode();
+    void EnableGrainlineRotation();
+    void EditFormula();
+    void DeployRotation();
+    void DeployLength();
+    void ResetWarning();
+
+    void EvalWidth();
+    void EvalWidthBefore();
+    void EvalWidthAfter();
+
+    void FXWidth();
+    void FXWidthBefore();
+    void FXWidthAfter();
+
+    void WidthChanged();
+    void WidthBeforeChanged();
+    void WidthAfterChanged();
+
+    void DeployWidthFormulaTextEdit();
+    void DeployWidthBeforeFormulaTextEdit();
+    void DeployWidthAfterFormulaTextEdit();
+
+private:
+    Q_DISABLE_COPY(DialogSeamAllowance)
+
+    Ui::DialogSeamAllowance *ui;
+    bool   applyAllowed;
+    bool   m_bAddMode;
+    qreal  m_mx;
+    qreal  m_my;
+
+    QPointer<DialogTool> m_dialog;
+
+    QStringList      m_qslMaterials;
+    QStringList      m_qslPlacements;
+    // temporary container for Material/Cut/Placement 3-tuples
+    MCPContainer m_conMCP;
+
+    VPatternPieceData    m_oldData;
+    VPatternInfoGeometry m_oldGeom;
+    VGrainlineGeometry   m_oldGrainline;
+    int                  m_iRotBaseHeight;
+    int                  m_iLenBaseHeight;
+    int                  m_formulaBaseWidth;
+    int                  m_formulaBaseWidthBefore;
+    int                  m_formulaBaseWidthAfter;
+
+    QTimer *m_timerWidth;
+    QTimer *m_timerWidthBefore;
+    QTimer *m_timerWidthAfter;
+    qreal   m_saWidth;
+
+    VPiece CreatePiece() const;
+
+    void    NewMainPathItem(const VPieceNode &node);
+    void    NewCustomSA(const CustomSARecord &record);
+    void    NewInternalPath(quint32 path);
+    QString GetPathName(quint32 path, bool reverse = false) const;
+    bool    MainPathIsValid() const;
+    void    ValidObjects(bool value);
+    bool    MainPathIsClockwise() const;
+    void    UpdateCurrentCustomSARecord();
+    void    UpdateCurrentInternalPathRecord();
+    void    ClearFields();
+
+    QListWidgetItem *GetItemById(quint32 id);
+
+    quint32 GetLastId() const;
+
+    void SetCurrentSABefore(const QString &formula);
+    void SetCurrentSAAfter(const QString &formula);
+
+    void UpdateNodeSABefore(const QString &formula);
+    void UpdateNodeSAAfter(const QString &formula);
+
+    void InitMainPathTab();
+    void InitSeamAllowanceTab();
+    void InitNodesList();
+    void InitCSAPoint(QComboBox *box);
+    void InitSAIncludeType();
+    void InitInternalPathsTab();
+    void InitPatternPieceDataTab();
+    void InitGrainlineTab();
+
+    void SetFormulaSAWidth(const QString &formula);
+
+    QString GetFormulaSAWidthBefore() const;
+    QString GetFormulaSAWidthAfter() const;
+};
+
+#endif // DIALOGSEAMALLOWANCE_H
diff --git a/src/libs/vtools/dialogs/tools/dialogseamallowance.ui b/src/libs/vtools/dialogs/tools/dialogseamallowance.ui
new file mode 100644
index 000000000..315098dc5
--- /dev/null
+++ b/src/libs/vtools/dialogs/tools/dialogseamallowance.ui
@@ -0,0 +1,1581 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DialogSeamAllowance</class>
+ <widget class="QDialog" name="DialogSeamAllowance">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>521</width>
+    <height>611</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Seam allowance tool</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="../../../vmisc/share/resources/icon.qrc">
+    <normaloff>:/icon/64x64/icon64x64.png</normaloff>:/icon/64x64/icon64x64.png</iconset>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QTabWidget" name="tabWidget">
+     <property name="currentIndex">
+      <number>1</number>
+     </property>
+     <widget class="QWidget" name="tabMainPath">
+      <attribute name="title">
+       <string>Main path</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_2">
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_8">
+         <item>
+          <widget class="QLabel" name="label_3">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="text">
+            <string/>
+           </property>
+           <property name="pixmap">
+            <pixmap resource="../../../vmisc/share/resources/icon.qrc">:/icon/32x32/clockwise.png</pixmap>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLabel" name="label_4">
+           <property name="text">
+            <string>All objects in path should follow in clockwise direction.</string>
+           </property>
+           <property name="wordWrap">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <widget class="QCheckBox" name="checkBoxForbidFlipping">
+         <property name="toolTip">
+          <string>Forbid piece be mirrored in a layout.</string>
+         </property>
+         <property name="text">
+          <string>Forbid flipping</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QListWidget" name="listWidgetMainPath">
+         <property name="dragDropMode">
+          <enum>QAbstractItemView::InternalMove</enum>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLabel" name="helpLabel">
+         <property name="text">
+          <string>Ready!</string>
+         </property>
+         <property name="textFormat">
+          <enum>Qt::RichText</enum>
+         </property>
+         <property name="scaledContents">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tabSeamAllowance">
+      <attribute name="title">
+       <string>Seam allowance</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_11">
+       <item>
+        <widget class="QCheckBox" name="checkBoxSeams">
+         <property name="text">
+          <string>Seam allowance</string>
+         </property>
+         <property name="checked">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBoxAutomatic">
+         <property name="enabled">
+          <bool>false</bool>
+         </property>
+         <property name="title">
+          <string>Automatic</string>
+         </property>
+         <property name="flat">
+          <bool>false</bool>
+         </property>
+         <property name="checkable">
+          <bool>false</bool>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_5">
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayout_2">
+            <item alignment="Qt::AlignLeft">
+             <widget class="QLabel" name="labelEditWidth">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="palette">
+               <palette>
+                <active>
+                 <colorrole role="WindowText">
+                  <brush brushstyle="SolidPattern">
+                   <color alpha="255">
+                    <red>255</red>
+                    <green>0</green>
+                    <blue>0</blue>
+                   </color>
+                  </brush>
+                 </colorrole>
+                </active>
+                <inactive>
+                 <colorrole role="WindowText">
+                  <brush brushstyle="SolidPattern">
+                   <color alpha="255">
+                    <red>255</red>
+                    <green>0</green>
+                    <blue>0</blue>
+                   </color>
+                  </brush>
+                 </colorrole>
+                </inactive>
+                <disabled>
+                 <colorrole role="WindowText">
+                  <brush brushstyle="SolidPattern">
+                   <color alpha="255">
+                    <red>159</red>
+                    <green>158</green>
+                    <blue>158</blue>
+                   </color>
+                  </brush>
+                 </colorrole>
+                </disabled>
+               </palette>
+              </property>
+              <property name="text">
+               <string>Width:</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item alignment="Qt::AlignRight">
+             <widget class="QToolButton" name="toolButtonExprWidth">
+              <property name="toolTip">
+               <string>Formula wizard</string>
+              </property>
+              <property name="text">
+               <string notr="true">...</string>
+              </property>
+              <property name="icon">
+               <iconset resource="../../../vmisc/share/resources/icon.qrc">
+                <normaloff>:/icon/24x24/fx.png</normaloff>:/icon/24x24/fx.png</iconset>
+              </property>
+              <property name="iconSize">
+               <size>
+                <width>24</width>
+                <height>24</height>
+               </size>
+              </property>
+             </widget>
+            </item>
+            <item alignment="Qt::AlignRight">
+             <widget class="QLabel" name="label_2">
+              <property name="text">
+               <string/>
+              </property>
+              <property name="pixmap">
+               <pixmap resource="../../../vmisc/share/resources/icon.qrc">:/icon/24x24/equal.png</pixmap>
+              </property>
+             </widget>
+            </item>
+            <item alignment="Qt::AlignRight">
+             <widget class="QLabel" name="labelResultWidth">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="minimumSize">
+               <size>
+                <width>87</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string>Value</string>
+              </property>
+              <property name="text">
+               <string notr="true">_</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayout_6">
+            <item>
+             <widget class="QPlainTextEdit" name="plainTextEditFormulaWidth">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>16777215</width>
+                <height>28</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string>Calculation</string>
+              </property>
+              <property name="tabChangesFocus">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QPushButton" name="pushButtonGrowWidth">
+              <property name="maximumSize">
+               <size>
+                <width>18</width>
+                <height>18</height>
+               </size>
+              </property>
+              <property name="sizeIncrement">
+               <size>
+                <width>0</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="toolTip">
+               <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show full calculation in message box&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+              </property>
+              <property name="text">
+               <string notr="true"/>
+              </property>
+              <property name="icon">
+               <iconset theme="go-down">
+                <normaloff>.</normaloff>.</iconset>
+              </property>
+              <property name="iconSize">
+               <size>
+                <width>16</width>
+                <height>16</height>
+               </size>
+              </property>
+              <property name="flat">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <widget class="QGroupBox" name="groupBox">
+            <property name="title">
+             <string>Nodes</string>
+            </property>
+            <layout class="QVBoxLayout" name="verticalLayout_3">
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+             <item>
+              <layout class="QHBoxLayout" name="horizontalLayout_10">
+               <item>
+                <widget class="QLabel" name="labelNode">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="text">
+                  <string>Node:</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QComboBox" name="comboBoxNodes">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <spacer name="horizontalSpacer_7">
+                 <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                 </property>
+                 <property name="sizeHint" stdset="0">
+                  <size>
+                   <width>40</width>
+                   <height>20</height>
+                  </size>
+                 </property>
+                </spacer>
+               </item>
+              </layout>
+             </item>
+             <item>
+              <layout class="QHBoxLayout" name="horizontalLayout_9">
+               <item alignment="Qt::AlignLeft">
+                <widget class="QLabel" name="labelEditBefore">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="palette">
+                  <palette>
+                   <active>
+                    <colorrole role="WindowText">
+                     <brush brushstyle="SolidPattern">
+                      <color alpha="255">
+                       <red>255</red>
+                       <green>0</green>
+                       <blue>0</blue>
+                      </color>
+                     </brush>
+                    </colorrole>
+                   </active>
+                   <inactive>
+                    <colorrole role="WindowText">
+                     <brush brushstyle="SolidPattern">
+                      <color alpha="255">
+                       <red>255</red>
+                       <green>0</green>
+                       <blue>0</blue>
+                      </color>
+                     </brush>
+                    </colorrole>
+                   </inactive>
+                   <disabled>
+                    <colorrole role="WindowText">
+                     <brush brushstyle="SolidPattern">
+                      <color alpha="255">
+                       <red>159</red>
+                       <green>158</green>
+                       <blue>158</blue>
+                      </color>
+                     </brush>
+                    </colorrole>
+                   </disabled>
+                  </palette>
+                 </property>
+                 <property name="text">
+                  <string>Before:</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <spacer name="horizontalSpacer_3">
+                 <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                 </property>
+                 <property name="sizeHint" stdset="0">
+                  <size>
+                   <width>40</width>
+                   <height>20</height>
+                  </size>
+                 </property>
+                </spacer>
+               </item>
+               <item>
+                <widget class="QPushButton" name="pushButtonDefBefore">
+                 <property name="toolTip">
+                  <string>Return to default width</string>
+                 </property>
+                 <property name="text">
+                  <string>Default</string>
+                 </property>
+                </widget>
+               </item>
+               <item alignment="Qt::AlignRight">
+                <widget class="QToolButton" name="toolButtonExprBefore">
+                 <property name="toolTip">
+                  <string>Formula wizard</string>
+                 </property>
+                 <property name="text">
+                  <string notr="true">...</string>
+                 </property>
+                 <property name="icon">
+                  <iconset resource="../../../vmisc/share/resources/icon.qrc">
+                   <normaloff>:/icon/24x24/fx.png</normaloff>:/icon/24x24/fx.png</iconset>
+                 </property>
+                 <property name="iconSize">
+                  <size>
+                   <width>24</width>
+                   <height>24</height>
+                  </size>
+                 </property>
+                </widget>
+               </item>
+               <item alignment="Qt::AlignRight">
+                <widget class="QLabel" name="label_6">
+                 <property name="text">
+                  <string/>
+                 </property>
+                 <property name="pixmap">
+                  <pixmap resource="../../../vmisc/share/resources/icon.qrc">:/icon/24x24/equal.png</pixmap>
+                 </property>
+                </widget>
+               </item>
+               <item alignment="Qt::AlignRight">
+                <widget class="QLabel" name="labelResultBefore">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="minimumSize">
+                  <size>
+                   <width>87</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="toolTip">
+                  <string>Value</string>
+                 </property>
+                 <property name="text">
+                  <string notr="true">_</string>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+             <item>
+              <layout class="QHBoxLayout" name="horizontalLayout_7">
+               <item>
+                <widget class="QPlainTextEdit" name="plainTextEditFormulaWidthBefore">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="maximumSize">
+                  <size>
+                   <width>16777215</width>
+                   <height>28</height>
+                  </size>
+                 </property>
+                 <property name="toolTip">
+                  <string>Calculation</string>
+                 </property>
+                 <property name="tabChangesFocus">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QPushButton" name="pushButtonGrowWidthBefore">
+                 <property name="maximumSize">
+                  <size>
+                   <width>18</width>
+                   <height>18</height>
+                  </size>
+                 </property>
+                 <property name="sizeIncrement">
+                  <size>
+                   <width>0</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="toolTip">
+                  <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show full calculation in message box&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                 </property>
+                 <property name="text">
+                  <string notr="true"/>
+                 </property>
+                 <property name="icon">
+                  <iconset theme="go-down">
+                   <normaloff>.</normaloff>.</iconset>
+                 </property>
+                 <property name="iconSize">
+                  <size>
+                   <width>16</width>
+                   <height>16</height>
+                  </size>
+                 </property>
+                 <property name="flat">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+             <item>
+              <layout class="QHBoxLayout" name="horizontalLayout_16">
+               <item alignment="Qt::AlignLeft">
+                <widget class="QLabel" name="labelEditAfter">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="palette">
+                  <palette>
+                   <active>
+                    <colorrole role="WindowText">
+                     <brush brushstyle="SolidPattern">
+                      <color alpha="255">
+                       <red>255</red>
+                       <green>0</green>
+                       <blue>0</blue>
+                      </color>
+                     </brush>
+                    </colorrole>
+                   </active>
+                   <inactive>
+                    <colorrole role="WindowText">
+                     <brush brushstyle="SolidPattern">
+                      <color alpha="255">
+                       <red>255</red>
+                       <green>0</green>
+                       <blue>0</blue>
+                      </color>
+                     </brush>
+                    </colorrole>
+                   </inactive>
+                   <disabled>
+                    <colorrole role="WindowText">
+                     <brush brushstyle="SolidPattern">
+                      <color alpha="255">
+                       <red>159</red>
+                       <green>158</green>
+                       <blue>158</blue>
+                      </color>
+                     </brush>
+                    </colorrole>
+                   </disabled>
+                  </palette>
+                 </property>
+                 <property name="text">
+                  <string>After:</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <spacer name="horizontalSpacer_6">
+                 <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                 </property>
+                 <property name="sizeHint" stdset="0">
+                  <size>
+                   <width>40</width>
+                   <height>20</height>
+                  </size>
+                 </property>
+                </spacer>
+               </item>
+               <item>
+                <widget class="QPushButton" name="pushButtonDefAfter">
+                 <property name="toolTip">
+                  <string>Return to default width</string>
+                 </property>
+                 <property name="text">
+                  <string>Default</string>
+                 </property>
+                </widget>
+               </item>
+               <item alignment="Qt::AlignRight">
+                <widget class="QToolButton" name="toolButtonExprAfter">
+                 <property name="toolTip">
+                  <string>Formula wizard</string>
+                 </property>
+                 <property name="text">
+                  <string notr="true">...</string>
+                 </property>
+                 <property name="icon">
+                  <iconset resource="../../../vmisc/share/resources/icon.qrc">
+                   <normaloff>:/icon/24x24/fx.png</normaloff>:/icon/24x24/fx.png</iconset>
+                 </property>
+                 <property name="iconSize">
+                  <size>
+                   <width>24</width>
+                   <height>24</height>
+                  </size>
+                 </property>
+                </widget>
+               </item>
+               <item alignment="Qt::AlignRight">
+                <widget class="QLabel" name="label_10">
+                 <property name="text">
+                  <string/>
+                 </property>
+                 <property name="pixmap">
+                  <pixmap resource="../../../vmisc/share/resources/icon.qrc">:/icon/24x24/equal.png</pixmap>
+                 </property>
+                </widget>
+               </item>
+               <item alignment="Qt::AlignRight">
+                <widget class="QLabel" name="labelResultAfter">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="minimumSize">
+                  <size>
+                   <width>87</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="toolTip">
+                  <string>Value</string>
+                 </property>
+                 <property name="text">
+                  <string notr="true">_</string>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+             <item>
+              <layout class="QHBoxLayout" name="horizontalLayout_17">
+               <item>
+                <widget class="QPlainTextEdit" name="plainTextEditFormulaWidthAfter">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="maximumSize">
+                  <size>
+                   <width>16777215</width>
+                   <height>28</height>
+                  </size>
+                 </property>
+                 <property name="toolTip">
+                  <string>Calculation</string>
+                 </property>
+                 <property name="tabChangesFocus">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QPushButton" name="pushButtonGrowWidthAfter">
+                 <property name="maximumSize">
+                  <size>
+                   <width>18</width>
+                   <height>18</height>
+                  </size>
+                 </property>
+                 <property name="sizeIncrement">
+                  <size>
+                   <width>0</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="toolTip">
+                  <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show full calculation in message box&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                 </property>
+                 <property name="text">
+                  <string notr="true"/>
+                 </property>
+                 <property name="icon">
+                  <iconset theme="go-down">
+                   <normaloff>.</normaloff>.</iconset>
+                 </property>
+                 <property name="iconSize">
+                  <size>
+                   <width>16</width>
+                   <height>16</height>
+                  </size>
+                 </property>
+                 <property name="flat">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+             <item>
+              <layout class="QHBoxLayout" name="horizontalLayout_15">
+               <item>
+                <widget class="QLabel" name="labelAngle">
+                 <property name="text">
+                  <string>Angle:</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QComboBox" name="comboBoxAngle">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <spacer name="horizontalSpacer_8">
+                 <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                 </property>
+                 <property name="sizeHint" stdset="0">
+                  <size>
+                   <width>40</width>
+                   <height>20</height>
+                  </size>
+                 </property>
+                </spacer>
+               </item>
+              </layout>
+             </item>
+            </layout>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBoxCustom">
+         <property name="enabled">
+          <bool>false</bool>
+         </property>
+         <property name="title">
+          <string>Custom</string>
+         </property>
+         <property name="flat">
+          <bool>false</bool>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_4">
+          <property name="spacing">
+           <number>6</number>
+          </property>
+          <property name="topMargin">
+           <number>9</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QSplitter" name="splitter">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="opaqueResize">
+             <bool>true</bool>
+            </property>
+            <widget class="QWidget" name="layoutWidget">
+             <layout class="QFormLayout" name="formLayout_2">
+              <property name="fieldGrowthPolicy">
+               <enum>QFormLayout::ExpandingFieldsGrow</enum>
+              </property>
+              <property name="horizontalSpacing">
+               <number>6</number>
+              </property>
+              <item row="0" column="0">
+               <widget class="QLabel" name="labelStartPoint">
+                <property name="text">
+                 <string>Start point:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="0" column="1">
+               <widget class="QComboBox" name="comboBoxStartPoint"/>
+              </item>
+              <item row="1" column="0">
+               <widget class="QLabel" name="labelEndPoint">
+                <property name="text">
+                 <string>End point:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="1">
+               <widget class="QComboBox" name="comboBoxEndPoint"/>
+              </item>
+              <item row="2" column="0">
+               <widget class="QLabel" name="labelIncludeType">
+                <property name="text">
+                 <string>Include as:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="1">
+               <widget class="QComboBox" name="comboBoxIncludeType">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+            <widget class="QListWidget" name="listWidgetCustomSA">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="sizeIncrement">
+              <size>
+               <width>0</width>
+               <height>0</height>
+              </size>
+             </property>
+            </widget>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tabInternalPaths">
+      <attribute name="title">
+       <string>Internal paths</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_6">
+       <item>
+        <widget class="QListWidget" name="listWidgetInternalPaths">
+         <property name="dragDropMode">
+          <enum>QAbstractItemView::InternalMove</enum>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tabPatternPieceData">
+      <attribute name="title">
+       <string>Pattern piece data</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_9">
+       <item>
+        <widget class="QSplitter" name="splitter_2">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <widget class="QWidget" name="layoutWidget1">
+          <layout class="QVBoxLayout" name="verticalLayout_7">
+           <item>
+            <layout class="QFormLayout" name="formLayout_3">
+             <property name="fieldGrowthPolicy">
+              <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+             </property>
+             <item row="0" column="0">
+              <widget class="QLabel" name="label_5">
+               <property name="text">
+                <string>Letter:</string>
+               </property>
+              </widget>
+             </item>
+             <item row="0" column="1">
+              <widget class="QLineEdit" name="lineEditLetter">
+               <property name="maxLength">
+                <number>3</number>
+               </property>
+               <property name="placeholderText">
+                <string>Letter of pattern piece</string>
+               </property>
+              </widget>
+             </item>
+             <item row="1" column="0">
+              <widget class="QLabel" name="labelEditName">
+               <property name="text">
+                <string>Name of detail:</string>
+               </property>
+              </widget>
+             </item>
+             <item row="1" column="1">
+              <widget class="QLineEdit" name="lineEditName">
+               <property name="text">
+                <string>Detail</string>
+               </property>
+               <property name="maxLength">
+                <number>30</number>
+               </property>
+               <property name="placeholderText">
+                <string>Name can't be empty</string>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox_2">
+             <property name="title">
+              <string>Material/Cut number/Placement</string>
+             </property>
+             <layout class="QGridLayout" name="gridLayout_3">
+              <item row="1" column="0">
+               <widget class="QLabel" name="label_8">
+                <property name="text">
+                 <string>Cut number:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="0" column="0" colspan="2">
+               <widget class="QLabel" name="label_7">
+                <property name="text">
+                 <string>Material type:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="0" column="2" colspan="2">
+               <widget class="QComboBox" name="comboBoxMaterial">
+                <property name="toolTip">
+                 <string>You can choose one of the predefined materials or enter a new one</string>
+                </property>
+                <property name="editable">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="2" colspan="2">
+               <widget class="QSpinBox" name="spinBoxCutNumber">
+                <property name="minimum">
+                 <number>1</number>
+                </property>
+                <property name="maximum">
+                 <number>1000</number>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="0">
+               <widget class="QLabel" name="label_9">
+                <property name="text">
+                 <string>Placement:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="2" colspan="2">
+               <widget class="QComboBox" name="comboBoxPlacement"/>
+              </item>
+              <item row="3" column="0">
+               <widget class="QPushButton" name="pushButtonAdd">
+                <property name="text">
+                 <string>Add</string>
+                </property>
+               </widget>
+              </item>
+              <item row="3" column="1" colspan="2">
+               <widget class="QPushButton" name="pushButtonCancel">
+                <property name="text">
+                 <string>Cancel</string>
+                </property>
+               </widget>
+              </item>
+              <item row="3" column="3">
+               <widget class="QPushButton" name="pushButtonRemove">
+                <property name="text">
+                 <string>Remove</string>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <layout class="QVBoxLayout" name="verticalLayout_8">
+             <item>
+              <widget class="QCheckBox" name="checkBoxDetail">
+               <property name="text">
+                <string>Detail label visible</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QCheckBox" name="checkBoxPattern">
+               <property name="text">
+                <string>Pattern label visible</string>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+          </layout>
+         </widget>
+         <widget class="QListWidget" name="listWidgetMCP">
+          <property name="minimumSize">
+           <size>
+            <width>180</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="focusPolicy">
+           <enum>Qt::ClickFocus</enum>
+          </property>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tabGrainline">
+      <attribute name="title">
+       <string>Grainline</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_10">
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_4">
+         <item>
+          <widget class="QCheckBox" name="checkBoxGrainline">
+           <property name="text">
+            <string>Grainline visible</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_11">
+         <item alignment="Qt::AlignLeft">
+          <widget class="QLabel" name="labelEditRot">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="palette">
+            <palette>
+             <active>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>255</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </active>
+             <inactive>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>255</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </inactive>
+             <disabled>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>159</red>
+                 <green>158</green>
+                 <blue>158</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </disabled>
+            </palette>
+           </property>
+           <property name="text">
+            <string>Rotation:</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_4">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item alignment="Qt::AlignRight">
+          <widget class="QToolButton" name="pushButtonRot">
+           <property name="toolTip">
+            <string>Formula wizard</string>
+           </property>
+           <property name="text">
+            <string notr="true">...</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../../../vmisc/share/resources/icon.qrc">
+             <normaloff>:/icon/24x24/fx.png</normaloff>:/icon/24x24/fx.png</iconset>
+           </property>
+           <property name="iconSize">
+            <size>
+             <width>24</width>
+             <height>24</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item alignment="Qt::AlignRight">
+          <widget class="QLabel" name="labelEqual">
+           <property name="text">
+            <string/>
+           </property>
+           <property name="pixmap">
+            <pixmap resource="../../../vmisc/share/resources/icon.qrc">:/icon/24x24/equal.png</pixmap>
+           </property>
+          </widget>
+         </item>
+         <item alignment="Qt::AlignRight">
+          <widget class="QLabel" name="labelRot">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>87</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="baseSize">
+            <size>
+             <width>0</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>Value</string>
+           </property>
+           <property name="text">
+            <string notr="true">_</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_12">
+         <item>
+          <widget class="QPlainTextEdit" name="lineEditRotFormula">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>16777215</width>
+             <height>28</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>Calculation</string>
+           </property>
+           <property name="tabChangesFocus">
+            <bool>true</bool>
+           </property>
+           <property name="plainText">
+            <string notr="true"/>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="pushButtonShowRot">
+           <property name="maximumSize">
+            <size>
+             <width>18</width>
+             <height>18</height>
+            </size>
+           </property>
+           <property name="sizeIncrement">
+            <size>
+             <width>0</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show full calculation in message box&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+           <property name="text">
+            <string notr="true"/>
+           </property>
+           <property name="icon">
+            <iconset theme="go-down">
+             <normaloff>.</normaloff>.</iconset>
+           </property>
+           <property name="iconSize">
+            <size>
+             <width>16</width>
+             <height>16</height>
+            </size>
+           </property>
+           <property name="flat">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_13">
+         <item alignment="Qt::AlignLeft">
+          <widget class="QLabel" name="labelEditLen">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="palette">
+            <palette>
+             <active>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>255</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </active>
+             <inactive>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>255</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </inactive>
+             <disabled>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>159</red>
+                 <green>158</green>
+                 <blue>158</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </disabled>
+            </palette>
+           </property>
+           <property name="text">
+            <string>Length:</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_5">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item alignment="Qt::AlignRight">
+          <widget class="QToolButton" name="pushButtonLen">
+           <property name="toolTip">
+            <string>Formula wizard</string>
+           </property>
+           <property name="text">
+            <string notr="true">...</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../../../vmisc/share/resources/icon.qrc">
+             <normaloff>:/icon/24x24/fx.png</normaloff>:/icon/24x24/fx.png</iconset>
+           </property>
+           <property name="iconSize">
+            <size>
+             <width>24</width>
+             <height>24</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item alignment="Qt::AlignRight">
+          <widget class="QLabel" name="labelEqual_2">
+           <property name="text">
+            <string/>
+           </property>
+           <property name="pixmap">
+            <pixmap resource="../../../vmisc/share/resources/icon.qrc">:/icon/24x24/equal.png</pixmap>
+           </property>
+          </widget>
+         </item>
+         <item alignment="Qt::AlignRight">
+          <widget class="QLabel" name="labelLen">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>87</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="baseSize">
+            <size>
+             <width>0</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>Value</string>
+           </property>
+           <property name="text">
+            <string notr="true">_</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_14">
+         <item>
+          <widget class="QPlainTextEdit" name="lineEditLenFormula">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>16777215</width>
+             <height>28</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>Calculation</string>
+           </property>
+           <property name="tabChangesFocus">
+            <bool>true</bool>
+           </property>
+           <property name="plainText">
+            <string notr="true"/>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="pushButtonShowLen">
+           <property name="maximumSize">
+            <size>
+             <width>18</width>
+             <height>18</height>
+            </size>
+           </property>
+           <property name="sizeIncrement">
+            <size>
+             <width>0</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show full calculation in message box&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+           <property name="text">
+            <string notr="true"/>
+           </property>
+           <property name="icon">
+            <iconset theme="go-down">
+             <normaloff>.</normaloff>.</iconset>
+           </property>
+           <property name="iconSize">
+            <size>
+             <width>16</width>
+             <height>16</height>
+            </size>
+           </property>
+           <property name="flat">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_5">
+         <item>
+          <widget class="QLabel" name="labelEditLen_2">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="palette">
+            <palette>
+             <active>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>0</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </active>
+             <inactive>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>0</red>
+                 <green>0</green>
+                 <blue>0</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </inactive>
+             <disabled>
+              <colorrole role="WindowText">
+               <brush brushstyle="SolidPattern">
+                <color alpha="255">
+                 <red>159</red>
+                 <green>158</green>
+                 <blue>158</blue>
+                </color>
+               </brush>
+              </colorrole>
+             </disabled>
+            </palette>
+           </property>
+           <property name="text">
+            <string>Arrows:</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QComboBox" name="comboBoxArrow"/>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_2">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../../vmisc/share/resources/icon.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>DialogSeamAllowance</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>DialogSeamAllowance</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/src/libs/vtools/dialogs/tools/dialogtool.cpp b/src/libs/vtools/dialogs/tools/dialogtool.cpp
index 8dedd4752..b0d71b549 100644
--- a/src/libs/vtools/dialogs/tools/dialogtool.cpp
+++ b/src/libs/vtools/dialogs/tools/dialogtool.cpp
@@ -58,6 +58,7 @@
 #include <Qt>
 #include <QtDebug>
 #include <new>
+#include <QBuffer>
 
 #include "../ifc/xml/vdomdocument.h"
 #include "../qmuparser/qmudef.h"
@@ -66,6 +67,7 @@
 #include "../vpatterndb/calculator.h"
 #include "../vpatterndb/vcontainer.h"
 #include "../vpatterndb/vtranslatevars.h"
+#include "../vpatterndb/vpiecenode.h"
 #include "../../tools/vabstracttool.h"
 #include "../ifc/xml/vabstractpattern.h"
 #include "../vgeometry/vabstractcurve.h"
@@ -395,6 +397,128 @@ quint32 DialogTool::DNumber(const QString &baseName) const
     return num;
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+quint32 DialogTool::RowId(QListWidget *listWidget, int i)
+{
+    SCASSERT(listWidget != nullptr);
+    const QListWidgetItem *rowItem = listWidget->item(i);
+    SCASSERT(rowItem != nullptr);
+    const VPieceNode rowNode = qvariant_cast<VPieceNode>(rowItem->data(Qt::UserRole));
+    return rowNode.GetId();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool DialogTool::FirstPointEqualLast(QListWidget *listWidget)
+{
+    SCASSERT(listWidget != nullptr);
+    if (listWidget->count() > 1)
+    {
+        return RowId(listWidget, 0) == RowId(listWidget, listWidget->count()-1);
+    }
+    return false;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool DialogTool::DoublePoints(QListWidget *listWidget)
+{
+    SCASSERT(listWidget != nullptr);
+    for (int i=0, sz = listWidget->count()-1; i<sz; ++i)
+    {
+        if (RowId(listWidget, i) == RowId(listWidget, i+1))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString DialogTool::DialogWarningIcon()
+{
+    const QIcon icon = QIcon::fromTheme("dialog-warning",
+                                  QIcon(":/icons/win.icon.theme/16x16/status/dialog-warning.png"));
+
+    const QPixmap pixmap = icon.pixmap(QSize(16, 16));
+    QByteArray byteArray;
+    QBuffer buffer(&byteArray);
+    pixmap.save(&buffer, "PNG");
+    const QString url = QString("<img src=\"data:image/png;base64,") + byteArray.toBase64() + QLatin1String("\"/> ");
+    return url;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString DialogTool::GetNodeName(const VPieceNode &node) const
+{
+    const QSharedPointer<VGObject> obj = data->GeometricObject<VGObject>(node.GetId());
+    QString name = obj->name();
+
+    if (node.GetTypeTool() != Tool::NodePoint && node.GetReverse())
+    {
+        name = QLatin1String("- ") + name;
+    }
+
+    return name;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogTool::NewNodeItem(QListWidget *listWidget, const VPieceNode &node)
+{
+    SCASSERT(listWidget != nullptr);
+    SCASSERT(node.GetId() > NULL_ID);
+    QString name;
+    switch (node.GetTypeTool())
+    {
+        case (Tool::NodePoint):
+        case (Tool::NodeArc):
+        case (Tool::NodeSpline):
+        case (Tool::NodeSplinePath):
+        {
+            name = GetNodeName(node);
+            break;
+        }
+        default:
+            qDebug()<<"Got wrong tools. Ignore.";
+            return;
+    }
+
+    bool canAddNewPoint = false;
+
+    if(listWidget->count() == 0)
+    {
+        canAddNewPoint = true;
+    }
+    else
+    {
+        if(RowId(listWidget, listWidget->count()-1) != node.GetId())
+        {
+            canAddNewPoint = true;
+        }
+    }
+
+    if(canAddNewPoint)
+    {
+        QListWidgetItem *item = new QListWidgetItem(name);
+        item->setFont(QFont("Times", 12, QFont::Bold));
+        item->setData(Qt::UserRole, QVariant::fromValue(node));
+        listWidget->addItem(item);
+        listWidget->setCurrentRow(listWidget->count()-1);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void DialogTool::InitNodeAngles(QComboBox *box)
+{
+    SCASSERT(box != nullptr);
+    box->clear();
+
+    box->addItem(tr("by length"), static_cast<unsigned char>(PieceNodeAngle::ByLength));
+    box->addItem(tr("by points intersetions"), static_cast<unsigned char>(PieceNodeAngle::ByPointsIntersection));
+    box->addItem(tr("by first edge symmetry"), static_cast<unsigned char>(PieceNodeAngle::ByFirstEdgeSymmetry));
+    box->addItem(tr("by second edge symmetry"), static_cast<unsigned char>(PieceNodeAngle::BySecondEdgeSymmetry));
+    box->addItem(tr("by first edge right angle"), static_cast<unsigned char>(PieceNodeAngle::ByFirstEdgeRightAngle));
+    box->addItem(tr("by second edge right angle"), static_cast<unsigned char>(PieceNodeAngle::BySecondEdgeRightAngle));
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 bool DialogTool::IsSplinePath(const QSharedPointer<VGObject> &obj) const
 {
@@ -458,7 +582,7 @@ void DialogTool::ValFormulaChanged(bool &flag, QPlainTextEdit *edit, QTimer *tim
         return;
     }
     timer->setSingleShot(true);
-    timer->start(1000);
+    timer->start(300);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -470,13 +594,11 @@ void DialogTool::ValFormulaChanged(bool &flag, QPlainTextEdit *edit, QTimer *tim
  * @param postfix unit name
  * @param checkZero true - if formula can't be equal zero
  */
-qreal DialogTool::Eval(const QString &text, bool &flag, QLabel *label, const QString& postfix, bool checkZero)
+qreal DialogTool::Eval(const QString &text, bool &flag, QLabel *label, const QString& postfix, bool checkZero,
+                       bool checkLessThanZero)
 {
-    qDebug() << "Eval started";
     SCASSERT(label != nullptr)
-    qDebug() << "Label ok";
     SCASSERT(labelEditFormula != nullptr)
-    qDebug() << "lef ok";
 
     qreal result = INT_MIN;//Value can be 0, so use max imposible value
 
@@ -516,6 +638,13 @@ qreal DialogTool::Eval(const QString &text, bool &flag, QLabel *label, const QSt
                     label->setText(tr("Error") + " (" + postfix + ")");
                     label->setToolTip(tr("Value can't be 0"));
                 }
+                else if (checkLessThanZero && result < 0)
+                {
+                    flag = false;
+                    ChangeColor(labelEditFormula, Qt::red);
+                    label->setText(tr("Error") + " (" + postfix + ")");
+                    label->setToolTip(tr("Value can't be lass than 0"));
+                }
                 else
                 {
                     label->setText(qApp->LocaleToString(result) + " " +postfix);
@@ -966,6 +1095,12 @@ void DialogTool::Build(const Tool &type)
     Q_UNUSED(type)
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+void DialogTool::SetPiecesList(const QVector<quint32> &list)
+{
+    Q_UNUSED(list);
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 void DialogTool::SetAssociatedTool(VAbstractTool *tool)
 {
diff --git a/src/libs/vtools/dialogs/tools/dialogtool.h b/src/libs/vtools/dialogs/tools/dialogtool.h
index 81ac40462..460a28d18 100644
--- a/src/libs/vtools/dialogs/tools/dialogtool.h
+++ b/src/libs/vtools/dialogs/tools/dialogtool.h
@@ -95,6 +95,7 @@ public:
 
     virtual void     ShowDialog(bool click);
     virtual void     Build(const Tool &type);
+    virtual void     SetPiecesList(const QVector<quint32> &list);
 
     quint32          GetToolId() const;
     void             SetToolId(const quint32 &value);
@@ -230,7 +231,7 @@ protected:
     void             ValFormulaChanged(bool &flag, QPlainTextEdit *edit, QTimer * timer,
                                        const QString &postfix = QString());
     qreal            Eval(const QString &text, bool &flag, QLabel *label, const QString &postfix,
-                          bool checkZero = true);
+                          bool checkZero = true, bool checkLessThanZero = false);
 
     void             setCurrentPointId(QComboBox *box, const quint32 &value,
                                        FillComboBox rule = FillComboBox::NoChildren,
@@ -274,6 +275,16 @@ protected:
     void             MoveCursorToEnd(QPlainTextEdit *plainTextEdit);
     virtual bool     eventFilter(QObject *object, QEvent *event) Q_DECL_OVERRIDE;
     quint32          DNumber(const QString &baseName) const;
+
+    static quint32   RowId(QListWidget *listWidget, int i);
+    static bool      FirstPointEqualLast(QListWidget *listWidget);
+    static bool      DoublePoints(QListWidget *listWidget);
+    static QString   DialogWarningIcon();
+
+    QString          GetNodeName(const VPieceNode &node) const;
+    void             NewNodeItem(QListWidget *listWidget, const VPieceNode &node);
+
+    void             InitNodeAngles(QComboBox *box);
 private:
     void FillList(QComboBox *box, const QMap<QString, quint32> &list)const;
 
diff --git a/src/libs/vtools/dialogs/tools/dialoguniondetails.cpp b/src/libs/vtools/dialogs/tools/dialoguniondetails.cpp
index 0078616b1..8c54a9dee 100644
--- a/src/libs/vtools/dialogs/tools/dialoguniondetails.cpp
+++ b/src/libs/vtools/dialogs/tools/dialoguniondetails.cpp
@@ -33,7 +33,8 @@
 
 #include "../ifc/ifcdef.h"
 #include "../vpatterndb/vcontainer.h"
-#include "../vpatterndb/vdetail.h"
+#include "../vpatterndb/vpiece.h"
+#include "../vpatterndb/vpiecenode.h"
 #include "dialogtool.h"
 #include "ui_dialoguniondetails.h"
 
@@ -96,8 +97,8 @@ bool DialogUnionDetails::CheckObject(const quint32 &id, const quint32 &idDetail)
     {
         return false;
     }
-    const VDetail det = data->GetDetail(idDetail);
-    return det.Containes(id);
+    const VPiece det = data->GetPiece(idDetail);
+    return det.GetPath().Contains(id);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -107,8 +108,8 @@ bool DialogUnionDetails::CheckDetail(const quint32 &idDetail) const
     {
         return false;
     }
-    const VDetail det = data->GetDetail(idDetail);
-    if (det.CountNode() >= 3 && det.listNodePoint().size() >= 2)
+    const VPiece det = data->GetPiece(idDetail);
+    if (det.GetPath().CountNodes() >= 3 && det.GetPath().ListNodePoint().size() >= 2)
     {
         return true;
     }
@@ -166,11 +167,11 @@ void DialogUnionDetails::ChoosedDetail(const quint32 &id, const SceneObject &typ
                 emit ToolTip(tr("Select a unique point"));
                 return;
             }
-            VDetail d = data->GetDetail(idDetail);
-            if (d.OnEdge(p1, id))
+            VPiece d = data->GetPiece(idDetail);
+            if (d.GetPath().OnEdge(p1, id))
             {
                 p2 = id;
-                index = d.Edge(p1, p2);
+                index = d.GetPath().Edge(p1, p2);
                 ++numberD;
                 if (numberD > 1)
                 {
diff --git a/src/libs/vtools/tools/drawTools/vdrawtool.cpp b/src/libs/vtools/tools/drawTools/vdrawtool.cpp
index 4de01fb70..db85d3d0a 100644
--- a/src/libs/vtools/tools/drawTools/vdrawtool.cpp
+++ b/src/libs/vtools/tools/drawTools/vdrawtool.cpp
@@ -28,7 +28,6 @@
 
 #include "vdrawtool.h"
 
-#include <qnumeric.h>
 #include <QDialog>
 #include <QDomNode>
 #include <QMessageLogger>
@@ -41,10 +40,6 @@
 #include "../ifc/ifcdef.h"
 #include "../ifc/xml/vdomdocument.h"
 #include "../ifc/xml/vabstractpattern.h"
-#include "../ifc/exception/vexceptionundo.h"
-#include "../vpatterndb/calculator.h"
-#include "../../dialogs/support/dialogeditwrongformula.h"
-#include "../../dialogs/support/dialogundo.h"
 #include "../../undocommands/addtocalc.h"
 #include "../../undocommands/savetooloptions.h"
 #include "../qmuparser/qmuparsererror.h"
@@ -292,96 +287,6 @@ void VDrawTool::DetailsMode(bool mode)
     // Do nothing.
 }
 
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief CheckFormula check formula.
- *
- * Try calculate formula. If find error show dialog that allow user try fix formula. If user can't throw exception. In
- * successes case return result calculation and fixed formula string. If formula ok don't touch formula.
- *
- * @param toolId [in] tool's id.
- * @param formula [in|out] string with formula.
- * @param data [in] container with variables. Need for math parser.
- * @throw QmuParserError.
- * @return result of calculation formula.
- */
-qreal VDrawTool::CheckFormula(const quint32 &toolId, QString &formula, VContainer *data)
-{
-    SCASSERT(data != nullptr)
-    qreal result = 0;
-    try
-    {
-        QScopedPointer<Calculator> cal(new Calculator());
-        result = cal->EvalFormula(data->PlainVariables(), formula);
-
-        if (qIsInf(result) || qIsNaN(result))
-        {
-            qDebug() << "Invalid the formula value";
-            return 0;
-        }
-    }
-    catch (qmu::QmuParserError &e)
-    {
-        qDebug() << "\nMath parser error:\n"
-                 << "--------------------------------------\n"
-                 << "Message:     " << e.GetMsg()  << "\n"
-                 << "Expression:  " << e.GetExpr() << "\n"
-                 << "--------------------------------------";
-
-        if (qApp->IsAppInGUIMode())
-        {
-            QScopedPointer<DialogUndo> dialogUndo(new DialogUndo(qApp->getMainWindow()));
-            forever
-            {
-                if (dialogUndo->exec() == QDialog::Accepted)
-                {
-                    const UndoButton resultUndo = dialogUndo->Result();
-                    if (resultUndo == UndoButton::Fix)
-                    {
-                        auto *dialog = new DialogEditWrongFormula(data, toolId, qApp->getMainWindow());
-                        dialog->setWindowTitle(tr("Edit wrong formula"));
-                        dialog->SetFormula(formula);
-                        if (dialog->exec() == QDialog::Accepted)
-                        {
-                            formula = dialog->GetFormula();
-                            /* Need delete dialog here because parser in dialog don't allow use correct separator for
-                             * parsing here. */
-                            delete dialog;
-                            QScopedPointer<Calculator> cal1(new Calculator());
-                            result = cal1->EvalFormula(data->PlainVariables(), formula);
-
-                            if (qIsInf(result) || qIsNaN(result))
-                            {
-                                qDebug() << "Invalid the formula value";
-                                return 0;
-                            }
-
-                            break;
-                        }
-                        else
-                        {
-                            delete dialog;
-                        }
-                    }
-                    else
-                    {
-                        throw VExceptionUndo(QString("Undo wrong formula %1").arg(formula));
-                    }
-                }
-                else
-                {
-                    throw;
-                }
-            }
-        }
-        else
-        {
-            throw;
-        }
-    }
-    return result;
-}
-
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief AddToCalculation add tool to calculation tag in pattern file.
diff --git a/src/libs/vtools/tools/drawTools/vdrawtool.h b/src/libs/vtools/tools/drawTools/vdrawtool.h
index cbb1281aa..105e212e6 100644
--- a/src/libs/vtools/tools/drawTools/vdrawtool.h
+++ b/src/libs/vtools/tools/drawTools/vdrawtool.h
@@ -75,7 +75,6 @@ public:
     /** @brief setDialog set dialog when user want change tool option. */
     virtual void setDialog() {}
     virtual void DialogLinkDestroy();
-    static qreal CheckFormula(const quint32 &toolId, QString &formula, VContainer *data);
 
     QString      getLineType() const;
     virtual void SetTypeLine(const QString &value);
diff --git a/src/libs/vtools/tools/nodeDetails/nodedetails.h b/src/libs/vtools/tools/nodeDetails/nodedetails.h
index 8f9321212..918551ec5 100644
--- a/src/libs/vtools/tools/nodeDetails/nodedetails.h
+++ b/src/libs/vtools/tools/nodeDetails/nodedetails.h
@@ -34,5 +34,6 @@
 #include "vnodepoint.h"
 #include "vnodespline.h"
 #include "vnodesplinepath.h"
+#include "vtoolpiecepath.h"
 
 #endif // NODEDETAILS_H
diff --git a/src/libs/vtools/tools/nodeDetails/vabstractnode.cpp b/src/libs/vtools/tools/nodeDetails/vabstractnode.cpp
index 381509163..a8e2f433c 100644
--- a/src/libs/vtools/tools/nodeDetails/vabstractnode.cpp
+++ b/src/libs/vtools/tools/nodeDetails/vabstractnode.cpp
@@ -75,7 +75,7 @@ void VAbstractNode::ShowVisualization(bool show)
 //---------------------------------------------------------------------------------------------------------------------
 void VAbstractNode::incrementReferens()
 {
-    ++_referens;
+    VAbstractTool::incrementReferens();
     if (_referens == 1)
     {
         if (idTool != NULL_ID)
@@ -102,10 +102,7 @@ void VAbstractNode::incrementReferens()
  */
 void VAbstractNode::decrementReferens()
 {
-    if (_referens > 0)
-    {
-        --_referens;
-    }
+    VAbstractTool::decrementReferens();
     if (_referens == 0)
     {
         if (idTool != NULL_ID)
diff --git a/src/libs/vtools/tools/nodeDetails/vtoolpiecepath.cpp b/src/libs/vtools/tools/nodeDetails/vtoolpiecepath.cpp
new file mode 100644
index 000000000..0a3cb028c
--- /dev/null
+++ b/src/libs/vtools/tools/nodeDetails/vtoolpiecepath.cpp
@@ -0,0 +1,325 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   24 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "vtoolpiecepath.h"
+#include "../../dialogs/tools/dialogpiecepath.h"
+#include "../vpatterndb/vpiecepath.h"
+#include "../vpatterndb/vpiecenode.h"
+#include "../../undocommands/savepieceoptions.h"
+#include "../vtoolseamallowance.h"
+
+//---------------------------------------------------------------------------------------------------------------------
+VToolPiecePath *VToolPiecePath::Create(DialogTool *dialog, VMainGraphicsScene *scene, VAbstractPattern *doc,
+                                       VContainer *data)
+{
+    SCASSERT(dialog != nullptr);
+    DialogPiecePath *dialogTool = qobject_cast<DialogPiecePath*>(dialog);
+    SCASSERT(dialogTool != nullptr);
+    VPiecePath path = dialogTool->GetPiecePath();
+    const quint32 pieceId = dialogTool->GetPieceId();
+    qApp->getUndoStack()->beginMacro("add path");
+    path.SetNodes(PrepareNodes(path, scene, doc, data));
+
+    VToolPiecePath *pathTool = Create(0, path, pieceId, scene, doc, data, Document::FullParse, Source::FromGui);
+    return pathTool;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VToolPiecePath *VToolPiecePath::Create(quint32 _id, const VPiecePath &path, quint32 pieceId, VMainGraphicsScene *scene,
+                                       VAbstractPattern *doc, VContainer *data, const Document &parse,
+                                       const Source &typeCreation, const QString &drawName, const quint32 &idTool)
+{
+    quint32 id = _id;
+    if (typeCreation == Source::FromGui)
+    {
+        id = data->AddPiecePath(path);
+    }
+    else
+    {
+        data->UpdatePiecePath(id, path);
+        if (parse != Document::FullParse)
+        {
+            doc->UpdateToolData(id, data);
+        }
+    }
+
+    VAbstractTool::AddRecord(id, Tool::PiecePath, doc);
+    if (parse == Document::FullParse)
+    {
+        //TODO Need create garbage collector and remove all nodes, that we don't use.
+        //Better check garbage before each saving file. Check only modeling tags.
+        VToolPiecePath *pathTool = new VToolPiecePath(doc, data, id, pieceId, typeCreation, drawName, idTool, doc);
+
+        doc->AddTool(id, pathTool);
+        if (idTool != NULL_ID)
+        {
+            //Some nodes we don't show on scene. Tool that create this nodes must free memory.
+            VDataTool *tool = doc->getTool(idTool);
+            SCASSERT(tool != nullptr);
+            pathTool->setParent(tool);// Adopted by a tool
+        }
+        else
+        {
+            if (typeCreation == Source::FromGui && path.GetType() == PiecePathType::InternalPath)
+            { // Seam allowance tool already initializated and can't init the path
+                SCASSERT(pieceId > NULL_ID);
+                VToolSeamAllowance *saTool = qobject_cast<VToolSeamAllowance*>(doc->getTool(pieceId));
+                SCASSERT(saTool != nullptr);
+                pathTool->setParentItem(saTool);
+                pathTool->SetParentType(ParentType::Item);
+            }
+            else
+            {
+                // Try to prevent memory leak
+                scene->addItem(pathTool);// First adopted by scene
+                pathTool->hide();// If no one will use node, it will stay hidden
+                pathTool->SetParentType(ParentType::Scene);
+            }
+        }
+        return pathTool;
+    }
+    return nullptr;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString VToolPiecePath::getTagName() const
+{
+    return VAbstractPattern::TagPath;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::incrementReferens()
+{
+    VAbstractTool::incrementReferens();
+    if (_referens == 1)
+    {
+        if (idTool != NULL_ID)
+        {
+            doc->IncrementReferens(idTool);
+        }
+        else
+        {
+            IncrementNodes(VAbstractTool::data.GetPiecePath(id));
+        }
+        ShowNode();
+        QDomElement domElement = doc->elementById(id);
+        if (domElement.isElement())
+        {
+            doc->SetParametrUsage(domElement, AttrInUse, NodeUsage::InUse);
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::decrementReferens()
+{
+    VAbstractTool::decrementReferens();
+    if (_referens == 0)
+    {
+        if (idTool != NULL_ID)
+        {
+            doc->DecrementReferens(idTool);
+        }
+        else
+        {
+            DecrementNodes(VAbstractTool::data.GetPiecePath(id));
+        }
+        HideNode();
+        QDomElement domElement = doc->elementById(id);
+        if (domElement.isElement())
+        {
+            doc->SetParametrUsage(domElement, AttrInUse, NodeUsage::NotInUse);
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::AddAttributes(VAbstractPattern *doc, QDomElement &domElement, quint32 id, const VPiecePath &path)
+{
+    doc->SetAttribute(domElement, VDomDocument::AttrId, id);
+    doc->SetAttribute(domElement, AttrName, path.GetName());
+    doc->SetAttribute(domElement, AttrType, static_cast<int>(path.GetType()));
+    doc->SetAttribute(domElement, AttrTypeLine, PenStyleToLineStyle(path.GetPenType()));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::FullUpdateFromFile()
+{
+    RefreshGeometry();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::AllowHover(bool enabled)
+{
+    Q_UNUSED(enabled)
+    // do nothing
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::AllowSelecting(bool enabled)
+{
+    Q_UNUSED(enabled)
+    // do nothing
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::AddToFile()
+{
+    QDomElement domElement = doc->createElement(getTagName());
+    const VPiecePath path = VAbstractTool::data.GetPiecePath(id);
+
+    AddAttributes(doc, domElement, id, path);
+
+    if (idTool != NULL_ID)
+    {
+        doc->SetAttribute(domElement, AttrIdTool, idTool);
+    }
+
+    AddNodes(doc, domElement, path);
+
+    AddToModeling(domElement);
+
+    if (m_pieceId > NULL_ID)
+    {
+        const VPiece oldDet = VAbstractTool::data.GetPiece(m_pieceId);
+        VPiece newDet = oldDet;
+
+        if (path.GetType() == PiecePathType::InternalPath)
+        {
+            QVector<quint32> iPaths = newDet.GetInternalPaths();
+            iPaths.append(id);
+            newDet.SetInternalPaths(iPaths);
+        }
+        else if (path.GetType() == PiecePathType::CustomSeamAllowance)
+        {
+            CustomSARecord record;
+            record.path = id;
+
+            QVector<CustomSARecord> records = newDet.GetCustomSARecords();
+            records.append(record);
+            newDet.SetCustomSARecords(records);
+        }
+
+        SavePieceOptions *saveCommand = new SavePieceOptions(oldDet, newDet, doc, m_pieceId);
+        qApp->getUndoStack()->push(saveCommand);// First push then make a connect
+        VAbstractTool::data.UpdatePiece(m_pieceId, newDet);// Update piece because first save will not call lite update
+        connect(saveCommand, &SavePieceOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::RefreshDataInFile()
+{
+    QDomElement domElement = doc->elementById(id);
+    if (domElement.isElement())
+    {
+        if (idTool != NULL_ID)
+        {
+            doc->SetAttribute(domElement, AttrIdTool, idTool);
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::ShowNode()
+{
+    if (parentType != ParentType::Scene)
+    {
+        show();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::HideNode()
+{
+    hide();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::ToolCreation(const Source &typeCreation)
+{
+    if (typeCreation == Source::FromGui || typeCreation == Source::FromTool)
+    {
+        AddToFile();
+        if (typeCreation != Source::FromTool)
+        {
+            qApp->getUndoStack()->endMacro();
+        }
+    }
+    else
+    {
+        RefreshDataInFile();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VToolPiecePath::VToolPiecePath(VAbstractPattern *doc, VContainer *data, quint32 id, quint32 pieceId,
+                               const Source &typeCreation, const QString &drawName, const quint32 &idTool,
+                               QObject *qoParent, QGraphicsItem *parent)
+    :VAbstractNode(doc, data, id, 0, drawName, idTool, qoParent),
+      QGraphicsPathItem(parent),
+      m_pieceId(pieceId)
+{
+    IncrementNodes(VAbstractTool::data.GetPiecePath(id));
+    RefreshGeometry();
+    ToolCreation(typeCreation);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::RefreshGeometry()
+{
+    const VPiecePath path = VAbstractTool::data.GetPiecePath(id);
+    if (path.GetType() == PiecePathType::InternalPath)
+    {
+        QPainterPath p = path.PainterPath(this->getData());
+        p.setFillRule(Qt::OddEvenFill);
+
+        this->setPath(p);
+        QPen pen = this->pen();
+        pen.setStyle(path.GetPenType());
+        this->setPen(pen);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::IncrementNodes(const VPiecePath &path) const
+{
+    for (int i = 0; i < path.CountNodes(); ++i)
+    {
+        doc->IncrementReferens(VAbstractTool::data.GetGObject(path.at(i).GetId())->getIdTool());
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolPiecePath::DecrementNodes(const VPiecePath &path) const
+{
+    for (int i = 0; i < path.CountNodes(); ++i)
+    {
+        doc->DecrementReferens(VAbstractTool::data.GetGObject(path.at(i).GetId())->getIdTool());
+    }
+}
diff --git a/src/libs/vtools/tools/nodeDetails/vtoolpiecepath.h b/src/libs/vtools/tools/nodeDetails/vtoolpiecepath.h
new file mode 100644
index 000000000..2b1f4fca8
--- /dev/null
+++ b/src/libs/vtools/tools/nodeDetails/vtoolpiecepath.h
@@ -0,0 +1,82 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   24 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VTOOLPIECEPATH_H
+#define VTOOLPIECEPATH_H
+
+#include <QtGlobal>
+
+#include "vabstractnode.h"
+
+class DialogTool;
+
+class VToolPiecePath : public VAbstractNode, public QGraphicsPathItem
+{
+    Q_OBJECT
+public:
+    static VToolPiecePath* Create(DialogTool *dialog, VMainGraphicsScene *scene, VAbstractPattern *doc,
+                                  VContainer *data);
+    static VToolPiecePath *Create(quint32 _id, const VPiecePath &path, quint32 pieceId, VMainGraphicsScene *scene,
+                                  VAbstractPattern *doc, VContainer *data, const Document &parse,
+                                  const Source &typeCreation, const QString &drawName = QString(),
+                                  const quint32 &idTool = 0);
+
+    virtual int  type() const Q_DECL_OVERRIDE {return Type;}
+    enum { Type = UserType + static_cast<int>(Tool::PiecePath)};
+    virtual QString getTagName() const Q_DECL_OVERRIDE;
+
+    virtual void incrementReferens() Q_DECL_OVERRIDE;
+    virtual void decrementReferens() Q_DECL_OVERRIDE;
+
+    static void AddAttributes(VAbstractPattern *doc, QDomElement &domElement, quint32 id, const VPiecePath &path);
+public slots:
+    virtual void FullUpdateFromFile () Q_DECL_OVERRIDE;
+    virtual void AllowHover(bool enabled) Q_DECL_OVERRIDE;
+    virtual void AllowSelecting(bool enabled) Q_DECL_OVERRIDE;
+protected:
+    virtual void AddToFile() Q_DECL_OVERRIDE;
+    virtual void RefreshDataInFile() Q_DECL_OVERRIDE;
+    virtual void ShowNode() Q_DECL_OVERRIDE;
+    virtual void HideNode() Q_DECL_OVERRIDE;
+    virtual void ToolCreation(const Source &typeCreation) Q_DECL_OVERRIDE;
+private:
+    Q_DISABLE_COPY(VToolPiecePath)
+
+    quint32 m_pieceId;
+
+    VToolPiecePath(VAbstractPattern *doc, VContainer *data, quint32 id, quint32 pieceId,  const Source &typeCreation,
+                   const QString &drawName = QString(), const quint32 &idTool = 0, QObject *qoParent = nullptr,
+                   QGraphicsItem * parent = nullptr );
+
+    void RefreshGeometry();
+
+    void IncrementNodes(const VPiecePath &path) const;
+    void DecrementNodes(const VPiecePath &path) const;
+};
+
+#endif // VTOOLPIECEPATH_H
diff --git a/src/libs/vtools/tools/tools.pri b/src/libs/vtools/tools/tools.pri
index b1a63e83b..2b755c117 100644
--- a/src/libs/vtools/tools/tools.pri
+++ b/src/libs/vtools/tools/tools.pri
@@ -2,7 +2,6 @@
 # This need for corect working file translations.pro
 
 HEADERS += \
-    $$PWD/vtooldetail.h \
     $$PWD/vdatatool.h \
     $$PWD/vabstracttool.h \
     $$PWD/tools.h \
@@ -51,18 +50,17 @@ HEADERS += \
     $$PWD/drawTools/toolcurve/vtoolcubicbezier.h \
     $$PWD/drawTools/toolcurve/vtoolcubicbezierpath.h \
     $$PWD/drawTools/operation/vtoolrotation.h \
-    $$PWD/vtextgraphicsitem.h \
-    $$PWD/vgrainlineitem.h \
     $$PWD/drawTools/operation/flipping/vtoolflippingbyline.h \
     $$PWD/drawTools/operation/vabstractoperation.h \
     $$PWD/drawTools/operation/flipping/vtoolflippingbyaxis.h \
     $$PWD/drawTools/operation/flipping/vabstractflipping.h \
     $$PWD/drawTools/operation/vtoolmove.h \
     $$PWD/drawTools/toolcurve/vtoolellipticalarc.h \
-    $$PWD/nodeDetails/vnodeellipticalarc.h
+    $$PWD/nodeDetails/vnodeellipticalarc.h \
+    $$PWD/vtoolseamallowance.h \
+    $$PWD/nodeDetails/vtoolpiecepath.h
 
 SOURCES += \
-    $$PWD/vtooldetail.cpp \
     $$PWD/vdatatool.cpp \
     $$PWD/vabstracttool.cpp \
     $$PWD/drawTools/toolpoint/toolsinglepoint/vtooltriangle.cpp \
@@ -108,12 +106,12 @@ SOURCES += \
     $$PWD/drawTools/toolcurve/vtoolcubicbezier.cpp \
     $$PWD/drawTools/toolcurve/vtoolcubicbezierpath.cpp \
     $$PWD/drawTools/operation/vtoolrotation.cpp \
-    $$PWD/vtextgraphicsitem.cpp \
-    $$PWD/vgrainlineitem.cpp \
     $$PWD/drawTools/operation/flipping/vtoolflippingbyline.cpp \
     $$PWD/drawTools/operation/vabstractoperation.cpp \
     $$PWD/drawTools/operation/flipping/vtoolflippingbyaxis.cpp \
     $$PWD/drawTools/operation/flipping/vabstractflipping.cpp \
     $$PWD/drawTools/operation/vtoolmove.cpp \
     $$PWD/drawTools/toolcurve/vtoolellipticalarc.cpp \
-    $$PWD/nodeDetails/vnodeellipticalarc.cpp
+    $$PWD/nodeDetails/vnodeellipticalarc.cpp \
+    $$PWD/vtoolseamallowance.cpp \
+    $$PWD/nodeDetails/vtoolpiecepath.cpp
diff --git a/src/libs/vtools/tools/vabstracttool.cpp b/src/libs/vtools/tools/vabstracttool.cpp
index f15c3232b..7cd873b5f 100644
--- a/src/libs/vtools/tools/vabstracttool.cpp
+++ b/src/libs/vtools/tools/vabstracttool.cpp
@@ -52,21 +52,32 @@
 #include <QUndoStack>
 #include <QVector>
 #include <new>
+#include <qnumeric.h>
 
 #include "../vgeometry/vpointf.h"
 #include "../vpropertyexplorer/checkablemessagebox.h"
 #include "../vwidgets/vmaingraphicsview.h"
 #include "../ifc/exception/vexception.h"
+#include "../ifc/exception/vexceptionundo.h"
 #include "../ifc/xml/vtoolrecord.h"
 #include "../undocommands/deltool.h"
 #include "../vgeometry/../ifc/ifcdef.h"
 #include "../vgeometry/vgeometrydef.h"
 #include "../vgeometry/vgobject.h"
+#include "../vgeometry/vcubicbezier.h"
+#include "../vgeometry/vcubicbezierpath.h"
+#include "../vgeometry/vsplinepath.h"
+#include "../vgeometry/varc.h"
+#include "../vgeometry/vellipticalarc.h"
 #include "../vmisc/vcommonsettings.h"
 #include "../vmisc/logging.h"
 #include "../vpatterndb/vcontainer.h"
+#include "../vpatterndb/vpiecenode.h"
+#include "../vpatterndb/calculator.h"
 #include "../vwidgets/vgraphicssimpletextitem.h"
-#include "vdatatool.h"
+#include "nodeDetails/nodedetails.h"
+#include "../dialogs/support/dialogundo.h"
+#include "../dialogs/support/dialogeditwrongformula.h"
 
 class QGraphicsEllipseItem;
 class QGraphicsLineItem;
@@ -74,6 +85,51 @@ template <class T> class QSharedPointer;
 
 const QString VAbstractTool::AttrInUse = QStringLiteral("inUse");
 
+namespace
+{
+//---------------------------------------------------------------------------------------------------------------------
+template<typename T>
+/**
+ * @brief CreateNode create new node for detail.
+ * @param data container.
+ * @param id id parent object.
+ * @return id for new object.
+ */
+quint32 CreateNode(VContainer *data, quint32 id)
+{
+    //We can't use exist object. Need create new.
+    T *node = new T(*data->GeometricObject<T>(id).data());
+    node->setMode(Draw::Modeling);
+    return data->AddGObject(node);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+quint32 CreateNodeSpline(VContainer *data, quint32 id)
+{
+    if (data->GetGObject(id)->getType() == GOType::Spline)
+    {
+        return CreateNode<VSpline>(data, id);
+    }
+    else
+    {
+        return CreateNode<VCubicBezier>(data, id);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+quint32 CreateNodeSplinePath(VContainer *data, quint32 id)
+{
+    if (data->GetGObject(id)->getType() == GOType::SplinePath)
+    {
+        return CreateNode<VSplinePath>(data, id);
+    }
+    else
+    {
+        return CreateNode<VCubicBezierPath>(data, id);
+    }
+}
+}//static functions
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief VAbstractTool container.
@@ -101,6 +157,96 @@ VAbstractTool::~VAbstractTool()
     }
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief CheckFormula check formula.
+ *
+ * Try calculate formula. If find error show dialog that allow user try fix formula. If user can't throw exception. In
+ * successes case return result calculation and fixed formula string. If formula ok don't touch formula.
+ *
+ * @param toolId [in] tool's id.
+ * @param formula [in|out] string with formula.
+ * @param data [in] container with variables. Need for math parser.
+ * @throw QmuParserError.
+ * @return result of calculation formula.
+ */
+qreal VAbstractTool::CheckFormula(const quint32 &toolId, QString &formula, VContainer *data)
+{
+    SCASSERT(data != nullptr)
+    qreal result = 0;
+    try
+    {
+        QScopedPointer<Calculator> cal(new Calculator());
+        result = cal->EvalFormula(data->PlainVariables(), formula);
+
+        if (qIsInf(result) || qIsNaN(result))
+        {
+            qDebug() << "Invalid the formula value";
+            return 0;
+        }
+    }
+    catch (qmu::QmuParserError &e)
+    {
+        qDebug() << "\nMath parser error:\n"
+                 << "--------------------------------------\n"
+                 << "Message:     " << e.GetMsg()  << "\n"
+                 << "Expression:  " << e.GetExpr() << "\n"
+                 << "--------------------------------------";
+
+        if (qApp->IsAppInGUIMode())
+        {
+            QScopedPointer<DialogUndo> dialogUndo(new DialogUndo(qApp->getMainWindow()));
+            forever
+            {
+                if (dialogUndo->exec() == QDialog::Accepted)
+                {
+                    const UndoButton resultUndo = dialogUndo->Result();
+                    if (resultUndo == UndoButton::Fix)
+                    {
+                        auto *dialog = new DialogEditWrongFormula(data, toolId, qApp->getMainWindow());
+                        dialog->setWindowTitle(tr("Edit wrong formula"));
+                        dialog->SetFormula(formula);
+                        if (dialog->exec() == QDialog::Accepted)
+                        {
+                            formula = dialog->GetFormula();
+                            /* Need delete dialog here because parser in dialog don't allow use correct separator for
+                             * parsing here. */
+                            delete dialog;
+                            QScopedPointer<Calculator> cal1(new Calculator());
+                            result = cal1->EvalFormula(data->PlainVariables(), formula);
+
+                            if (qIsInf(result) || qIsNaN(result))
+                            {
+                                qDebug() << "Invalid the formula value";
+                                return 0;
+                            }
+
+                            break;
+                        }
+                        else
+                        {
+                            delete dialog;
+                        }
+                    }
+                    else
+                    {
+                        throw VExceptionUndo(QString("Undo wrong formula %1").arg(formula));
+                    }
+                }
+                else
+                {
+                    throw;
+                }
+            }
+        }
+        else
+        {
+            throw;
+        }
+    }
+    return result;
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief DeleteTool full delete object form scene and file.
@@ -188,6 +334,35 @@ Qt::PenStyle VAbstractTool::LineStyleToPenStyle(const QString &typeLine)
     }
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+QString VAbstractTool::PenStyleToLineStyle(Qt::PenStyle penStyle)
+{
+    QT_WARNING_PUSH
+    QT_WARNING_DISABLE_GCC("-Wswitch-default")
+
+    switch (penStyle)
+    {
+        case Qt::NoPen:
+            return TypeLineNone;
+        case Qt::DashLine:
+            return TypeLineDashLine;
+        case Qt::DotLine:
+            return TypeLineDotLine;
+        case Qt::DashDotLine:
+            return TypeLineDashDotLine;
+        case Qt::DashDotDotLine:
+            return TypeLineDashDotDotLine;
+        case Qt::SolidLine:
+        case Qt::CustomDashLine:
+        default:
+            break;
+    }
+
+    QT_WARNING_POP
+
+    return TypeLineLine;
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 QMap<QString, QIcon> VAbstractTool::LineStylesPics()
 {
@@ -385,6 +560,26 @@ void VAbstractTool::AddRecord(const quint32 id, const Tool &toolType, VAbstractP
     }
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+void VAbstractTool::AddNodes(VAbstractPattern *doc, QDomElement &domElement, const VPiecePath &path)
+{
+    if (path.CountNodes() > 0)
+    {
+        QDomElement nodesElement = doc->createElement(VAbstractPattern::TagNodes);
+        for (int i = 0; i < path.CountNodes(); ++i)
+        {
+            AddNode(doc, nodesElement, path.at(i));
+        }
+        domElement.appendChild(nodesElement);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VAbstractTool::AddNodes(VAbstractPattern *doc, QDomElement &domElement, const VPiece &piece)
+{
+    AddNodes(doc, domElement, piece.GetPath());
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief RefreshLine refresh line to label on scene.
@@ -421,3 +616,104 @@ void VAbstractTool::RefreshLine(QGraphicsEllipseItem *point, VGraphicsSimpleText
         lineName->setVisible(false);
     }
 }
+
+//---------------------------------------------------------------------------------------------------------------------
+QDomElement VAbstractTool::AddSANode(VAbstractPattern *doc, const QString &tagName, const VPieceNode &node)
+{
+    QDomElement nod = doc->createElement(tagName);
+
+    doc->SetAttribute(nod, AttrIdObject, node.GetId());
+
+    const Tool type = node.GetTypeTool();
+    if (type != Tool::NodePoint)
+    {
+        doc->SetAttribute(nod, VAbstractPattern::AttrNodeReverse, static_cast<quint8>(node.GetReverse()));
+    }
+    else
+    {
+        if (node.GetFormulaSABefore() != currentSeamAllowance)
+        {
+            doc->SetAttribute(nod, VAbstractPattern::AttrSABefore, node.GetFormulaSABefore());
+        }
+
+        if (node.GetFormulaSAAfter() != currentSeamAllowance)
+        {
+            doc->SetAttribute(nod, VAbstractPattern::AttrSAAfter, node.GetFormulaSAAfter());
+        }
+    }
+
+    switch (type)
+    {
+        case (Tool::NodeArc):
+            doc->SetAttribute(nod, AttrType, VAbstractPattern::NodeArc);
+            break;
+        case (Tool::NodePoint):
+            doc->SetAttribute(nod, AttrType, VAbstractPattern::NodePoint);
+            break;
+        case (Tool::NodeSpline):
+            doc->SetAttribute(nod, AttrType, VAbstractPattern::NodeSpline);
+            break;
+        case (Tool::NodeSplinePath):
+            doc->SetAttribute(nod, AttrType, VAbstractPattern::NodeSplinePath);
+            break;
+        default:
+            qDebug()<<"May be wrong tool type!!! Ignoring."<<Q_FUNC_INFO;
+            break;
+    }
+
+    const unsigned char angleType = static_cast<unsigned char>(node.GetAngleType());
+
+    if (angleType > 0)
+    {
+        doc->SetAttribute(nod, AttrAngle, angleType);
+    }
+
+    return nod;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VAbstractTool::AddNode(VAbstractPattern *doc, QDomElement &domElement, const VPieceNode &node)
+{
+    domElement.appendChild(AddSANode(doc, VAbstractPattern::TagNode, node));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VPieceNode> VAbstractTool::PrepareNodes(const VPiecePath &path, VMainGraphicsScene *scene,
+                                                VAbstractPattern *doc, VContainer *data)
+{
+    QVector<VPieceNode> nodes;
+    for (int i = 0; i< path.CountNodes(); ++i)
+    {
+        quint32 id = 0;
+        VPieceNode nodeD = path.at(i);
+        switch (nodeD.GetTypeTool())
+        {
+            case (Tool::NodePoint):
+                id = CreateNode<VPointF>(data, nodeD.GetId());
+                VNodePoint::Create(doc, data, scene, id, nodeD.GetId(), Document::FullParse, Source::FromGui);
+                break;
+            case (Tool::NodeArc):
+                id = CreateNode<VArc>(data, nodeD.GetId());
+                VNodeArc::Create(doc, data, id, nodeD.GetId(), Document::FullParse, Source::FromGui);
+                break;
+            case (Tool::NodeElArc):
+                id = CreateNode<VEllipticalArc>(data, nodeD.GetId());
+                VNodeEllipticalArc::Create(doc, data, id, nodeD.GetId(), Document::FullParse, Source::FromGui);
+                break;
+            case (Tool::NodeSpline):
+                id = CreateNodeSpline(data, nodeD.GetId());
+                VNodeSpline::Create(doc, data, id, nodeD.GetId(), Document::FullParse, Source::FromGui);
+                break;
+            case (Tool::NodeSplinePath):
+                id = CreateNodeSplinePath(data, nodeD.GetId());
+                VNodeSplinePath::Create(doc, data, id, nodeD.GetId(), Document::FullParse, Source::FromGui);
+                break;
+            default:
+                qDebug()<<"May be wrong tool type!!! Ignoring."<<Q_FUNC_INFO;
+                break;
+        }
+        nodeD.SetId(id);
+        nodes.append(nodeD);
+    }
+    return nodes;
+}
diff --git a/src/libs/vtools/tools/vabstracttool.h b/src/libs/vtools/tools/vabstracttool.h
index 5c8b22102..e4bec6a15 100644
--- a/src/libs/vtools/tools/vabstracttool.h
+++ b/src/libs/vtools/tools/vabstracttool.h
@@ -73,14 +73,19 @@ public:
 
     static const QString AttrInUse;
 
+    static qreal CheckFormula(const quint32 &toolId, QString &formula, VContainer *data);
+
     static const QStringList    StylesList();
     static Qt::PenStyle         LineStyleToPenStyle(const QString &typeLine);
+    static QString              PenStyleToLineStyle(Qt::PenStyle penStyle);
     static QMap<QString, QIcon> LineStylesPics();
 
     static const QStringList      Colors();
     static QMap<QString, QString> ColorsList();
 
-    static void             AddRecord(const quint32 id, const Tool &toolType, VAbstractPattern *doc);
+    static void AddRecord(const quint32 id, const Tool &toolType, VAbstractPattern *doc);
+    static void AddNodes(VAbstractPattern *doc, QDomElement &domElement, const VPiecePath &path);
+    static void AddNodes(VAbstractPattern *doc, QDomElement &domElement, const VPiece &piece);
 
     const VContainer        *getData() const;
 
@@ -144,10 +149,16 @@ protected:
     void AddVisualization();
 
     virtual void SetVisualization()=0;
-    void ToolCreation(const Source &typeCreation);
+    virtual void ToolCreation(const Source &typeCreation);
 
-    static void RefreshLine(QGraphicsEllipseItem *point, VGraphicsSimpleTextItem *namePoint, QGraphicsLineItem *lineName,
-                            const qreal radius);
+    static void RefreshLine(QGraphicsEllipseItem *point, VGraphicsSimpleTextItem *namePoint,
+                            QGraphicsLineItem *lineName, const qreal radius);
+
+    static QDomElement AddSANode(VAbstractPattern *doc, const QString &tagName, const VPieceNode &node);
+    static void        AddNode(VAbstractPattern *doc, QDomElement &domElement, const VPieceNode &node);
+
+    static QVector<VPieceNode> PrepareNodes(const VPiecePath &path, VMainGraphicsScene *scene, VAbstractPattern *doc,
+                                            VContainer *data);
 private:
     Q_DISABLE_COPY(VAbstractTool)
 };
diff --git a/src/libs/vtools/tools/vgrainlineitem.h b/src/libs/vtools/tools/vgrainlineitem.h
deleted file mode 100644
index 41ea59eb5..000000000
--- a/src/libs/vtools/tools/vgrainlineitem.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/************************************************************************
- **
- **  @file   vgrainlineitem.h
- **  @author Bojan Kverh
- **  @date   September 10, 2016
- **
- **  @brief
- **  @copyright
- **  This source code is part of the Valentine project, a pattern making
- **  program, whose allow create and modeling patterns of clothing.
- **  Copyright (C) 2013-2015 Valentina project
- **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
- **
- *************************************************************************/
-
-#ifndef VGRAINLINEITEM_H
-#define VGRAINLINEITEM_H
-
-#include <QGraphicsObject>
-
-#include "../vpatterndb/vgrainlinegeometry.h"
-
-class QGraphicsObject;
-class QPainter;
-class QStyleOptionGraphicsItem;
-class QWidget;
-
-class VGrainlineItem : public QGraphicsObject
-{
-    Q_OBJECT
-
-    enum Mode {
-        mNormal,
-        mMove,
-        mResize,
-        mRotate
-    };
-
-public:
-    explicit VGrainlineItem(QGraphicsItem* pParent = nullptr);
-    virtual ~VGrainlineItem();
-
-    void                    paint(QPainter* pP, const QStyleOptionGraphicsItem* pOption, QWidget* pWidget);
-    void                    UpdateGeometry(const QPointF& ptPos, qreal dRotation, qreal dLength,
-                                           VGrainlineGeometry::ArrowType eAT);
-
-    QRectF                  boundingRect() const;
-    void                    Reset();
-    bool                    IsIdle() const;
-    bool                    IsContained(const QPointF &pt, qreal dRot, qreal &dX, qreal &dY) const;
-    void                    SetScale(qreal dScale);
-
-protected:
-    void                    mousePressEvent(QGraphicsSceneMouseEvent* pME);
-    void                    mouseMoveEvent(QGraphicsSceneMouseEvent* pME);
-    void                    mouseReleaseEvent(QGraphicsSceneMouseEvent* pME);
-    void                    UpdateBox();
-    void                    UpdateRectangle();
-
-    qreal                   GetAngle(const QPointF& pt) const;
-    QPointF                 Rotate(const QPointF& pt, const QPointF& ptCenter, qreal dAng) const;
-    QPointF                 GetInsideCorner(int i, qreal dDist) const;
-
-signals:
-    void                    SignalMoved(const QPointF& ptPos);
-    void                    SignalResized(qreal dLength);
-    void                    SignalRotated(qreal dRot, const QPointF& ptNewPos);
-
-private:
-    Mode                            m_eMode;
-    bool                            m_bReleased;
-    qreal                           m_dRotation;
-    qreal                           m_dStartRotation;
-    qreal                           m_dLength;
-    QRectF                          m_rectBoundingBox;
-    QPolygonF                       m_polyBound;
-    QPointF                         m_ptStartPos;
-    QPointF                         m_ptStartMove;
-    qreal                           m_dScale;
-    QPolygonF                       m_polyResize;
-    qreal                           m_dStartLength;
-    QPointF                         m_ptStart;
-    QPointF                         m_ptFinish;
-    QPointF                         m_ptCenter;
-    QPointF                         m_ptRotCenter;
-    qreal                           m_dAngle;
-    VGrainlineGeometry::ArrowType   m_eArrowType;
-};
-
-#endif // VGRAINLINEITEM_H
diff --git a/src/libs/vtools/tools/vtextgraphicsitem.h b/src/libs/vtools/tools/vtextgraphicsitem.h
deleted file mode 100644
index 923b91ac2..000000000
--- a/src/libs/vtools/tools/vtextgraphicsitem.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/************************************************************************
- **
- **  @file   vtextgraphicsitem.h
- **  @author Bojan Kverh
- **  @date   June 16, 2016
- **
- **  @brief
- **  @copyright
- **  This source code is part of the Valentine project, a pattern making
- **  program, whose allow create and modeling patterns of clothing.
- **  Copyright (C) 2013-2015 Valentina project
- **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
- **
- *************************************************************************/
-
-#ifndef VTEXTGRAPHICSITEM_H
-#define VTEXTGRAPHICSITEM_H
-
-#include <QFont>
-#include <QGraphicsObject>
-#include <QList>
-#include <QMetaObject>
-#include <QObject>
-#include <QPointF>
-#include <QRectF>
-#include <QSizeF>
-#include <QString>
-#include <QtGlobal>
-
-#include "../vlayout/vtextmanager.h"
-
-class QFont;
-class QGraphicsItem;
-class QGraphicsSceneHoverEvent;
-class QGraphicsSceneMouseEvent;
-class QPainter;
-class QPointF;
-class QRectF;
-class QStyleOptionGraphicsItem;
-class QWidget;
-class VAbstractPattern;
-class VPatternPieceData;
-
-/**
- * @brief The VTextGraphicsItem class. This class implements text graphics item,
- * which can be dragged around, resized and rotated within the parent item. The text font
- * size will be automatically updated, so that the entire text will fit into the item.
- */
-class VTextGraphicsItem : public QGraphicsObject
-{
-    Q_OBJECT
-
-    enum Mode {
-        mNormal,
-        mMove,
-        mResize,
-        mRotate
-    };
-
-public:
-    explicit VTextGraphicsItem(QGraphicsItem* pParent = nullptr);
-    virtual ~VTextGraphicsItem();
-
-    void                SetFont(const QFont& fnt);
-    virtual void        paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
-                              QWidget *widget) Q_DECL_OVERRIDE;
-
-    void                Reset();
-    bool                IsIdle() const;
-
-    int                 GetFontSize() const;
-    virtual QRectF      boundingRect() const Q_DECL_OVERRIDE;
-    void                AddLine(const TextLine& tl);
-    void                Clear();
-    void                SetSize(qreal fW, qreal fH);
-    void                Update();
-    bool                IsContained(QRectF rectBB, qreal dRot, qreal& dX, qreal& dY) const;
-    void                UpdateData(const QString& qsName, const VPatternPieceData& data);
-    void                UpdateData(const VAbstractPattern* pDoc, qreal dSize, qreal dHeight);
-    int                 GetTextLines() const;
-
-protected:
-    virtual void        mousePressEvent(QGraphicsSceneMouseEvent* pME) Q_DECL_OVERRIDE;
-    virtual void        mouseMoveEvent(QGraphicsSceneMouseEvent* pME) Q_DECL_OVERRIDE;
-    virtual void        mouseReleaseEvent(QGraphicsSceneMouseEvent* pME) Q_DECL_OVERRIDE;
-    virtual void        hoverMoveEvent(QGraphicsSceneHoverEvent* pHE) Q_DECL_OVERRIDE;
-    virtual void        hoverLeaveEvent(QGraphicsSceneHoverEvent* pHE) Q_DECL_OVERRIDE;
-    void                UpdateBox();
-    void                CorrectLabel();
-
-    double              GetAngle(QPointF pt) const;
-
-signals:
-    void                SignalMoved(const QPointF& ptPos);
-    void                SignalResized(qreal iTW, int iFontSize);
-    void                SignalRotated(qreal dAng);
-    void                SignalShrink();
-
-private:
-    Mode                m_eMode;
-    bool                m_bReleased;
-    QPointF             m_ptStartPos;
-    QPointF             m_ptStart;
-    QPointF             m_ptRotCenter;
-    QSizeF              m_szStart;
-    double              m_dRotation;
-    double              m_dAngle;
-    QRectF              m_rectResize;
-    QRectF              m_rectBoundingBox;
-    VTextManager        m_tm;
-
-    QRectF              GetBoundingRect(QRectF rectBB, qreal dRot) const;
-};
-
-#endif // VTEXTGRAPHICSITEM_H
diff --git a/src/libs/vtools/tools/vtooldetail.cpp b/src/libs/vtools/tools/vtooldetail.cpp
deleted file mode 100644
index c5b2313e9..000000000
--- a/src/libs/vtools/tools/vtooldetail.cpp
+++ /dev/null
@@ -1,1330 +0,0 @@
-/************************************************************************
- **
- **  @file   vtooldetail.cpp
- **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   November 15, 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
- **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
- **
- *************************************************************************/
-
-#include "vtooldetail.h"
-
-#include <QAction>
-#include <QBrush>
-#include <QDialog>
-#include <QDomElement>
-#include <QEvent>
-#include <QFlags>
-#include <QFont>
-#include <QGraphicsItem>
-#include <QGraphicsScene>
-#include <QGraphicsSceneContextMenuEvent>
-#include <QGraphicsSceneMouseEvent>
-#include <QGraphicsView>
-#include <QHash>
-#include <QIcon>
-#include <QKeyEvent>
-#include <QList>
-#include <QMenu>
-#include <QMessageBox>
-#include <QMessageLogger>
-#include <QPainter>
-#include <QPainterPath>
-#include <QPen>
-#include <QPoint>
-#include <QPointF>
-#include <QPolygonF>
-#include <QRectF>
-#include <QSharedPointer>
-#include <QStaticStringData>
-#include <QString>
-#include <QStringData>
-#include <QStringDataPtr>
-#include <QStringList>
-#include <QUndoStack>
-#include <QVariant>
-#include <Qt>
-#include <QtDebug>
-#include <new>
-
-#include "../dialogs/tools/dialogdetail.h"
-#include "../dialogs/tools/dialogtool.h"
-#include "../ifc/exception/vexception.h"
-#include "../ifc/xml/vdomdocument.h"
-#include "../ifc/xml/vabstractpattern.h"
-#include "../ifc/ifcdef.h"
-#include "../undocommands/adddet.h"
-#include "../undocommands/deletedetail.h"
-#include "../undocommands/movedetail.h"
-#include "../undocommands/savedetailoptions.h"
-#include "../undocommands/toggledetailinlayout.h"
-#include "../vgeometry/varc.h"
-#include "../vgeometry/vellipticalarc.h"
-#include "../vgeometry/vcubicbezier.h"
-#include "../vgeometry/vcubicbezierpath.h"
-#include "../vgeometry/vgeometrydef.h"
-#include "../vgeometry/vgobject.h"
-#include "../vgeometry/vpointf.h"
-#include "../vgeometry/vspline.h"
-#include "../vgeometry/vsplinepath.h"
-#include "../vmisc/vabstractapplication.h"
-#include "../vpatterndb/vcontainer.h"
-#include "../vpatterndb/vdetail.h"
-#include "../vpatterndb/vpatterninfogeometry.h"
-#include "../vpatterndb/vpatternpiecedata.h"
-#include "../vpatterndb/calculator.h"
-#include "../vmisc/def.h"
-#include "../vwidgets/vmaingraphicsscene.h"
-#include "../vwidgets/vmaingraphicsview.h"
-#include "../vwidgets/vnobrushscalepathitem.h"
-#include "../tools/vtooldetail.h"
-#include "vabstracttool.h"
-#include "nodeDetails/vabstractnode.h"
-#include "nodeDetails/vnodearc.h"
-#include "nodeDetails/vnodeellipticalarc.h"
-#include "nodeDetails/vnodepoint.h"
-#include "nodeDetails/vnodespline.h"
-#include "nodeDetails/vnodesplinepath.h"
-#include "vtextgraphicsitem.h"
-#include "vnodedetail.h"
-
-class QDomElement;
-class QGraphicsSceneContextMenuEvent;
-class QGraphicsSceneHoverEvent;
-class QGraphicsSceneMouseEvent;
-class QKeyEvent;
-class QStyleOptionGraphicsItem;
-class QWidget;
-class VDataTool;
-
-const QString VToolDetail::TagNode            = QStringLiteral("node");
-
-const QString VToolDetail::AttrSupplement     = QStringLiteral("supplement");
-const QString VToolDetail::AttrClosed         = QStringLiteral("closed");
-const QString VToolDetail::AttrForbidFlipping = QStringLiteral("forbidFlipping");
-const QString VToolDetail::AttrWidth          = QStringLiteral("width");
-const QString VToolDetail::AttrHeight         = QStringLiteral("height");
-const QString VToolDetail::AttrNodeType       = QStringLiteral("nodeType");
-const QString VToolDetail::AttrReverse        = QStringLiteral("reverse");
-const QString VToolDetail::AttrFont           = QStringLiteral("fontSize");
-const QString VToolDetail::AttrRotation       = QStringLiteral("rotation");
-
-const QString VToolDetail::NodeTypeContour    = QStringLiteral("Contour");
-const QString VToolDetail::NodeTypeModeling   = QStringLiteral("Modeling");
-
-const QString VToolDetail::NodeArc            = QStringLiteral("NodeArc");
-const QString VToolDetail::NodeElArc          = QStringLiteral("NodeElArc");
-const QString VToolDetail::NodePoint          = QStringLiteral("NodePoint");
-const QString VToolDetail::NodeSpline         = QStringLiteral("NodeSpline");
-const QString VToolDetail::NodeSplinePath     = QStringLiteral("NodeSplinePath");
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VToolDetail constructor.
- * @param doc dom document container
- * @param data container with variables
- * @param id object id in container
- * @param typeCreation way we create this tool.
- * @param scene pointer to scene.
- * @param parent parent object
- */
-VToolDetail::VToolDetail(VAbstractPattern *doc, VContainer *data, const quint32 &id, const Source &typeCreation,
-                         VMainGraphicsScene *scene, const QString &drawName, QGraphicsItem *parent)
-    :VAbstractTool(doc, data, id), VNoBrushScalePathItem(parent), dialog(nullptr), sceneDetails(scene),
-      drawName(drawName), seamAllowance(new VNoBrushScalePathItem(this)), dataLabel(new VTextGraphicsItem(this)),
-      patternInfo(new VTextGraphicsItem(this)), grainLine(new VGrainlineItem(this))
-{
-    VDetail detail = data->GetDetail(id);
-    for (int i = 0; i< detail.CountNode(); ++i)
-    {
-        switch (detail.at(i).getTypeTool())
-        {
-            case (Tool::NodePoint):
-            {
-                VNodePoint *tool = InitTool<VNodePoint>(scene, detail.at(i));
-                connect(tool, &VNodePoint::ShowContextMenu, this, &VToolDetail::contextMenuEvent);
-                break;
-            }
-            case (Tool::NodeArc):
-            case (Tool::NodeElArc):
-            case (Tool::NodeSpline):
-            case (Tool::NodeSplinePath):
-                doc->IncrementReferens(detail.at(i).getId());
-                break;
-            default:
-                qDebug()<<"Get wrong tool type. Ignore.";
-                break;
-        }
-    }
-    this->setFlag(QGraphicsItem::ItemIsMovable, true);
-    this->setFlag(QGraphicsItem::ItemIsSelectable, true);
-    RefreshGeometry();
-
-    this->setBrush(QBrush(Qt::Dense7Pattern));
-    seamAllowance->setBrush(QBrush(Qt::FDiagPattern));
-
-    this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
-    this->setFlag(QGraphicsItem::ItemIsFocusable, true);// For keyboard input focus
-
-    connect(scene, &VMainGraphicsScene::EnableToolMove, this, &VToolDetail::EnableToolMove);
-    connect(scene, &VMainGraphicsScene::ItemClicked, this, &VToolDetail::ResetChildren);
-    if (typeCreation == Source::FromGui || typeCreation == Source::FromTool)
-    {
-        AddToFile();
-        if (typeCreation != Source::FromTool)
-        {
-            qApp->getUndoStack()->endMacro();
-        }
-    }
-    setAcceptHoverEvents(true);
-
-    connect(dataLabel, &VTextGraphicsItem::SignalMoved, this, &VToolDetail::SaveMoveDetail);
-    connect(dataLabel, &VTextGraphicsItem::SignalResized, this, &VToolDetail::SaveResizeDetail);
-    connect(dataLabel, &VTextGraphicsItem::SignalRotated, this, &VToolDetail::SaveRotationDetail);
-
-    connect(patternInfo, &VTextGraphicsItem::SignalMoved, this, &VToolDetail::SaveMovePattern);
-    connect(patternInfo, &VTextGraphicsItem::SignalResized, this, &VToolDetail::SaveResizePattern);
-    connect(patternInfo, &VTextGraphicsItem::SignalRotated, this, &VToolDetail::SaveRotationPattern);
-
-    connect(grainLine, &VGrainlineItem::SignalMoved, this, &VToolDetail::SaveMoveGrainline);
-    connect(grainLine, &VGrainlineItem::SignalResized, this, &VToolDetail::SaveResizeGrainline);
-    connect(grainLine, &VGrainlineItem::SignalRotated, this, &VToolDetail::SaveRotateGrainline);
-
-    connect(doc, &VAbstractPattern::patternChanged, this, &VToolDetail::UpdatePatternInfo);
-    connect(doc, &VAbstractPattern::CheckLayout, this, &VToolDetail::UpdateLabel);
-    connect(doc, &VAbstractPattern::CheckLayout, this, &VToolDetail::UpdatePatternInfo);
-    connect(doc, &VAbstractPattern::CheckLayout, this, &VToolDetail::UpdateGrainline);
-
-    connect(sceneDetails, &VMainGraphicsScene::DimensionsChanged, this, &VToolDetail::UpdateLabel);
-    connect(sceneDetails, &VMainGraphicsScene::DimensionsChanged, this, &VToolDetail::UpdatePatternInfo);
-    connect(sceneDetails, &VMainGraphicsScene::LanguageChanged, this, &VToolDetail::retranslateUi);
-
-    UpdateLabel();
-    UpdatePatternInfo();
-    UpdateGrainline();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-VToolDetail::~VToolDetail()
-{
-    delete dialog;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief setDialog set dialog when user want change tool option.
- */
-void VToolDetail::setDialog()
-{
-    SCASSERT(dialog != nullptr)
-    DialogDetail *dialogTool = qobject_cast<DialogDetail*>(dialog);
-    SCASSERT(dialogTool != nullptr)
-    dialogTool->setDetail(VAbstractTool::data.GetDetail(id));
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief Create help create tool from GUI.
- * @param dialog dialog.
- * @param scene pointer to scene.
- * @param doc dom document container.
- * @param data container with variables.
- */
-void VToolDetail::Create(DialogTool *dialog, VMainGraphicsScene *scene, VAbstractPattern *doc, VContainer *data)
-{
-    SCASSERT(dialog != nullptr)
-    DialogDetail *dialogTool = qobject_cast<DialogDetail*>(dialog);
-    SCASSERT(dialogTool != nullptr)
-    VDetail detail = dialogTool->getDetail();
-    VDetail det;
-    qApp->getUndoStack()->beginMacro("add detail");
-    for (int i = 0; i< detail.CountNode(); ++i)
-    {
-        quint32 id = 0;
-        const VNodeDetail &nodeD = detail.at(i);
-        switch (nodeD.getTypeTool())
-        {
-            case (Tool::NodePoint):
-            {
-                id = CreateNode<VPointF>(data, nodeD.getId());
-                VNodePoint::Create(doc, data, scene, id, nodeD.getId(), Document::FullParse, Source::FromGui);
-            }
-            break;
-            case (Tool::NodeArc):
-            {
-                id = CreateNode<VArc>(data, nodeD.getId());
-                VNodeArc::Create(doc, data, id, nodeD.getId(), Document::FullParse, Source::FromGui);
-            }
-            break;
-            case (Tool::NodeElArc):
-            {
-                id = CreateNode<VEllipticalArc>(data, nodeD.getId());
-                VNodeEllipticalArc::Create(doc, data, id, nodeD.getId(), Document::FullParse, Source::FromGui);
-            }
-            break;
-            case (Tool::NodeSpline):
-            {
-                const auto obj = data->GetGObject(nodeD.getId());
-                if (obj->getType() == GOType::Spline)
-                {
-                    id = CreateNode<VSpline>(data, nodeD.getId());
-                }
-                else
-                {
-                    id = CreateNode<VCubicBezier>(data, nodeD.getId());
-                }
-                VNodeSpline::Create(doc, data, id, nodeD.getId(), Document::FullParse, Source::FromGui);
-            }
-            break;
-            case (Tool::NodeSplinePath):
-            {
-                const auto obj = data->GetGObject(nodeD.getId());
-                if (obj->getType() == GOType::SplinePath)
-                {
-                    id = CreateNode<VSplinePath>(data, nodeD.getId());
-                }
-                else
-                {
-                    id = CreateNode<VCubicBezierPath>(data, nodeD.getId());
-                }
-                VNodeSplinePath::Create(doc, data, id, nodeD.getId(), Document::FullParse, Source::FromGui);
-            }
-            break;
-            default:
-                qDebug()<<"May be wrong tool type!!! Ignoring."<<Q_FUNC_INFO;
-                break;
-        }
-        VNodeDetail node(id, nodeD.getTypeTool(), NodeDetail::Contour, nodeD.getMx(), nodeD.getMy(),
-                         nodeD.getReverse());
-        det.append(node);
-    }
-    det.setName(detail.getName());
-    det.setWidth(detail.getWidth());
-    det.setClosed(detail.getClosed());
-    det.setSeamAllowance(detail.getSeamAllowance());
-    det.setForbidFlipping(detail.getForbidFlipping());
-    det.SetPatternPieceData(detail.GetPatternPieceData());
-    det.SetPatternInfo(detail.GetPatternInfo());
-    Create(0, det, scene, doc, data, Document::FullParse, Source::FromGui);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief Create help create tool.
- * @param _id tool id, 0 if tool doesn't exist yet.
- * @param newDetail detail what we want show.
- * @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.
- */
-void VToolDetail::Create(const quint32 &_id, const VDetail &newDetail, VMainGraphicsScene *scene, VAbstractPattern *doc,
-                         VContainer *data, const Document &parse, const Source &typeCreation, const QString &drawName)
-{
-    quint32 id = _id;
-    if (typeCreation == Source::FromGui || typeCreation == Source::FromTool)
-    {
-        id = data->AddDetail(newDetail);
-    }
-    else
-    {
-        data->UpdateDetail(id, newDetail);
-        if (parse != Document::FullParse)
-        {
-            doc->UpdateToolData(id, data);
-        }
-    }
-    VAbstractTool::AddRecord(id, Tool::Detail, doc);
-    if (parse == Document::FullParse)
-    {
-        VToolDetail *detail = new VToolDetail(doc, data, id, typeCreation, scene, drawName);
-        scene->addItem(detail);
-        connect(detail, &VToolDetail::ChoosedTool, scene, &VMainGraphicsScene::ChoosedItem);
-        connect(scene, &VMainGraphicsScene::EnableDetailItemHover, detail, &VToolDetail::AllowHover);
-        connect(scene, &VMainGraphicsScene::EnableDetailItemSelection, detail, &VToolDetail::AllowSelecting);
-        connect(scene, &VMainGraphicsScene::HighlightDetail, detail, &VToolDetail::Highlight);
-        doc->AddTool(id, detail);
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief Remove full delete detail.
- */
-void VToolDetail::Remove(bool ask)
-{
-    try
-    {
-        DeleteTool(ask);
-    }
-    catch(const VExceptionToolWasDeleted &e)
-    {
-        Q_UNUSED(e)
-        return;//Leave this method immediately!!!
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief FullUpdateFromFile update tool data form file.
- */
-void VToolDetail::FullUpdateFromFile()
-{
-    RefreshGeometry();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief FullUpdateFromGuiOk refresh tool data after change in options.
- * @param result keep result working dialog.
- */
-void VToolDetail::FullUpdateFromGuiOk(int result)
-{
-    if (result == QDialog::Accepted)
-    {
-        SCASSERT(dialog != nullptr)
-        DialogDetail *dialogTool = qobject_cast<DialogDetail*>(dialog);
-        SCASSERT(dialogTool != nullptr)
-        const VDetail newDet = dialogTool->getDetail();
-        const VDetail oldDet = VAbstractTool::data.GetDetail(id);
-
-        qDebug() << "VToolDetail Position" << newDet.GetPatternPieceData().GetPos();
-        SaveDetailOptions *saveCommand = new SaveDetailOptions(oldDet, newDet, doc, id, this->scene());
-        connect(saveCommand, &SaveDetailOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
-        qApp->getUndoStack()->push(saveCommand);
-        UpdateLabel();
-    }
-    delete dialog;
-    dialog = nullptr;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VToolDetail::paint draws a bounding box around detail, if one of its text or grainline items is not idle.
- */
-void VToolDetail::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
-{
-    if (scene()->views().count() > 0)
-    {
-        const QPoint pt0 = scene()->views().at(0)->mapFromScene(0, 0);
-        const QPoint pt = scene()->views().at(0)->mapFromScene(0, 100);
-
-        const QPoint p = pt - pt0;
-
-#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
-        const qreal dScale = qSqrt(QPoint::dotProduct(p, p));
-#else
-        const qreal dScale = qSqrt(p.x() * p.x() + p.y() * p.y());
-#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
-        grainLine->SetScale(100/dScale);
-        //qDebug() << "SCALE" << dScale << 10/dScale;
-    }
-
-    if (dataLabel->IsIdle() == false || patternInfo->IsIdle() == false || grainLine->IsIdle() == false)
-    {
-        painter->save();
-        painter->setPen(QPen(Qt::black, 3, Qt::DashLine));
-        painter->drawRect(boundingRect().adjusted(1, 1, -1, -1));
-        painter->restore();
-    }
-    VNoBrushScalePathItem::paint(painter, option, widget);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief AddToFile add tag with informations about tool into file.
- */
-void VToolDetail::AddToFile()
-{
-    const VDetail detail = VAbstractTool::data.GetDetail(id);
-    QDomElement domElement = doc->createElement(getTagName());
-
-    doc->SetAttribute(domElement, VDomDocument::AttrId, id);
-    doc->SetAttribute(domElement, AttrName, detail.getName());
-    doc->SetAttribute(domElement, AttrMx, qApp->fromPixel(detail.getMx()));
-    doc->SetAttribute(domElement, AttrMy, qApp->fromPixel(detail.getMy()));
-    doc->SetAttribute(domElement, AttrSupplement, static_cast<quint8>(detail.getSeamAllowance()));
-    doc->SetAttribute(domElement, AttrClosed, static_cast<quint8>(detail.getClosed()));
-    doc->SetAttribute(domElement, AttrWidth, detail.getWidth());
-    doc->SetAttribute(domElement, AttrForbidFlipping, static_cast<quint8>(detail.getForbidFlipping()));
-
-    // detail data
-    QDomElement domData = doc->createElement(VAbstractPattern::TagData);
-    const VPatternPieceData& data = detail.GetPatternPieceData();
-    doc->SetAttribute(domData, VAbstractPattern::AttrLetter, data.GetLetter());
-    doc->SetAttribute(domData, VAbstractPattern::AttrVisible, data.IsVisible() == true? trueStr : falseStr);
-    doc->SetAttribute(domData, AttrMx, data.GetPos().x());
-    doc->SetAttribute(domData, AttrMy, data.GetPos().y());
-    doc->SetAttribute(domData, AttrWidth, data.GetLabelWidth());
-    doc->SetAttribute(domData, AttrHeight, data.GetLabelHeight());
-    doc->SetAttribute(domData, AttrFont, data.GetFontSize());
-    doc->SetAttribute(domData, AttrRotation, data.GetRotation());
-
-    for (int i = 0; i < data.GetMCPCount(); ++i)
-    {
-        MaterialCutPlacement mcp = data.GetMCP(i);
-        QDomElement domMCP = doc->createElement(VAbstractPattern::TagMCP);
-        doc->SetAttribute(domMCP, VAbstractPattern::AttrMaterial, int(mcp.m_eMaterial));
-        if (mcp.m_eMaterial == MaterialType::mtUserDefined)
-        {
-            doc->SetAttribute(domMCP, VAbstractPattern::AttrUserDefined, mcp.m_qsMaterialUserDef);
-        }
-        doc->SetAttribute(domMCP, VAbstractPattern::AttrCutNumber, mcp.m_iCutNumber);
-        doc->SetAttribute(domMCP, VAbstractPattern::AttrPlacement, int(mcp.m_ePlacement));
-        domData.appendChild(domMCP);
-    }
-    domElement.appendChild(domData);
-
-    // pattern info
-    domData = doc->createElement(VAbstractPattern::TagPatternInfo);
-    const VPatternInfoGeometry& geom = detail.GetPatternInfo();
-    doc->SetAttribute(domData, VAbstractPattern::AttrVisible, geom.IsVisible() == true? trueStr : falseStr);
-    doc->SetAttribute(domData, AttrMx, geom.GetPos().x());
-    doc->SetAttribute(domData, AttrMy, geom.GetPos().y());
-    doc->SetAttribute(domData, AttrWidth, geom.GetLabelWidth());
-    doc->SetAttribute(domData, AttrHeight, geom.GetLabelHeight());
-    doc->SetAttribute(domData, AttrFont, geom.GetFontSize());
-    doc->SetAttribute(domData, AttrRotation, geom.GetRotation());
-    domElement.appendChild(domData);
-
-    // grainline
-    domData = doc->createElement(VAbstractPattern::TagGrainline);
-    const VGrainlineGeometry& glGeom = detail.GetGrainlineGeometry();
-    doc->SetAttribute(domData, VAbstractPattern::AttrVisible, glGeom.IsVisible() == true? trueStr : falseStr);
-    doc->SetAttribute(domData, AttrMx, glGeom.GetPos().x());
-    doc->SetAttribute(domData, AttrMy, glGeom.GetPos().y());
-    doc->SetAttribute(domData, AttrLength, glGeom.GetLength());
-    doc->SetAttribute(domData, AttrRotation, glGeom.GetRotation());
-    doc->SetAttribute(domData, VAbstractPattern::AttrArrows, int(glGeom.GetArrowType()));
-    qDebug() << "XML ROTATION" << glGeom.GetRotation();
-
-    // nodes
-    for (int i = 0; i < detail.CountNode(); ++i)
-    {
-       AddNode(doc, domElement, detail.at(i));
-    }
-
-    AddDet *addDet = new AddDet(domElement, doc, detail, drawName);
-    connect(addDet, &AddDet::NeedFullParsing, doc, &VAbstractPattern::NeedFullParsing);
-    qApp->getUndoStack()->push(addDet);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief RefreshDataInFile refresh attributes in file. If attributes don't exist create them.
- */
-void VToolDetail::RefreshDataInFile()
-{
-    QDomElement domElement = doc->elementById(id);
-    if (domElement.isElement())
-    {
-        VDetail det = VAbstractTool::data.GetDetail(id);
-        doc->SetAttribute(domElement, AttrName, det.getName());
-        doc->SetAttribute(domElement, AttrSupplement, QString().setNum(static_cast<quint8>(det.getSeamAllowance())));
-        doc->SetAttribute(domElement, AttrClosed, QString().setNum(static_cast<quint8>(det.getClosed())));
-        doc->SetAttribute(domElement, AttrWidth, QString().setNum(det.getWidth()));
-        doc->RemoveAllChildren(domElement);
-
-        // detail data
-        QDomElement domData = doc->createElement(VAbstractPattern::TagData);
-        const VPatternPieceData& data = det.GetPatternPieceData();
-        doc->SetAttribute(domData, VAbstractPattern::AttrLetter, data.GetLetter());
-        doc->SetAttribute(domData, VAbstractPattern::AttrVisible, data.IsVisible() == true? trueStr : falseStr);
-        doc->SetAttribute(domData, AttrMx, data.GetPos().x());
-        doc->SetAttribute(domData, AttrMy, data.GetPos().y());
-        doc->SetAttribute(domData, AttrWidth, data.GetLabelWidth());
-        doc->SetAttribute(domData, AttrHeight, data.GetLabelHeight());
-        doc->SetAttribute(domData, AttrFont, data.GetFontSize());
-        doc->SetAttribute(domData, AttrRotation, data.GetRotation());
-
-        for (int i = 0; i < data.GetMCPCount(); ++i)
-        {
-            MaterialCutPlacement mcp = data.GetMCP(i);
-            QDomElement domMCP = doc->createElement(VAbstractPattern::TagMCP);
-            doc->SetAttribute(domMCP, VAbstractPattern::AttrMaterial, int(mcp.m_eMaterial));
-            if (mcp.m_eMaterial == MaterialType::mtUserDefined)
-            {
-                doc->SetAttribute(domMCP, VAbstractPattern::AttrUserDefined, mcp.m_qsMaterialUserDef);
-            }
-            else
-            {
-                domMCP.removeAttribute(VAbstractPattern::AttrUserDefined);
-            }
-            doc->SetAttribute(domMCP, VAbstractPattern::AttrCutNumber, mcp.m_iCutNumber);
-            doc->SetAttribute(domMCP, VAbstractPattern::AttrPlacement, int(mcp.m_ePlacement));
-            domData.appendChild(domMCP);
-        }
-        domElement.appendChild(domData);
-
-        // pattern info
-        domData = doc->createElement(VAbstractPattern::TagPatternInfo);
-        const VPatternInfoGeometry& geom = det.GetPatternInfo();
-        doc->SetAttribute(domData, VAbstractPattern::AttrVisible, geom.IsVisible() == true? trueStr : falseStr);
-        doc->SetAttribute(domData, AttrMx, geom.GetPos().x());
-        doc->SetAttribute(domData, AttrMy, geom.GetPos().y());
-        doc->SetAttribute(domData, AttrWidth, geom.GetLabelWidth());
-        doc->SetAttribute(domData, AttrHeight, geom.GetLabelHeight());
-        doc->SetAttribute(domData, AttrFont, geom.GetFontSize());
-        doc->SetAttribute(domData, AttrRotation, geom.GetRotation());
-
-        // grainline
-        domData = doc->createElement(VAbstractPattern::TagGrainline);
-        const VGrainlineGeometry& glGeom = det.GetGrainlineGeometry();
-        doc->SetAttribute(domData, VAbstractPattern::AttrVisible, glGeom.IsVisible() == true? trueStr : falseStr);
-        doc->SetAttribute(domData, AttrMx, glGeom.GetPos().x());
-        doc->SetAttribute(domData, AttrMy, glGeom.GetPos().y());
-        doc->SetAttribute(domData, AttrLength, glGeom.GetLength());
-        doc->SetAttribute(domData, AttrRotation, glGeom.GetRotation());
-        doc->SetAttribute(domData, VAbstractPattern::AttrArrows, int(glGeom.GetArrowType()));
-
-        // nodes
-        for (int i = 0; i < det.CountNode(); ++i)
-        {
-           AddNode(doc, domElement, det.at(i));
-        }
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief itemChange handle detail change.
- * @param change change
- * @param value value
- * @return new value.
- */
-QVariant VToolDetail::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
-{
-    if (change == ItemPositionChange && scene())
-    {
-            // Each time we move something we call recalculation scene rect. In some cases this can cause moving
-            // objects positions. And this cause infinite redrawing. That's why we wait the finish of saving the last move.
-            static bool changeFinished = true;
-            if (changeFinished)
-            {
-               changeFinished = false;
-
-               // value - this is new position.
-               const QPointF newPos = value.toPointF();
-
-               MoveDetail *moveDet = new MoveDetail(doc, newPos.x(), newPos.y(), id, scene());
-               connect(moveDet, &MoveDetail::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
-               qApp->getUndoStack()->push(moveDet);
-
-               const QList<QGraphicsView *> viewList = scene()->views();
-               if (not viewList.isEmpty())
-               {
-                   if (QGraphicsView *view = viewList.at(0))
-                   {
-                       const int xmargin = 50;
-                       const int ymargin = 50;
-
-                       const QRectF viewRect = VMainGraphicsView::SceneVisibleArea(view);
-                       const QRectF itemRect = mapToScene(boundingRect()|childrenBoundingRect()).boundingRect();
-
-                       // If item's rect is bigger than view's rect ensureVisible works very unstable.
-                       if (itemRect.height() + 2*ymargin < viewRect.height() &&
-                           itemRect.width() + 2*xmargin < viewRect.width())
-                       {
-                            view->ensureVisible(itemRect, xmargin, ymargin);
-                       }
-                       else
-                       {
-                           // Ensure visible only small rect around a cursor
-                           VMainGraphicsScene *currentScene = qobject_cast<VMainGraphicsScene *>(scene());
-                           SCASSERT(currentScene)
-                           const QPointF cursorPosition = currentScene->getScenePos();
-                           view->ensureVisible(QRectF(cursorPosition.x()-5, cursorPosition.y()-5, 10, 10));
-                       }
-                   }
-               }
-               // Don't forget to update geometry, because first change never call full parse
-               RefreshGeometry();
-               changeFinished = true;
-        }
-    }
-
-    if (change == QGraphicsItem::ItemSelectedChange)
-    {
-        if (value == true)
-        {
-            // do stuff if selected
-            this->setFocus();
-        }
-        else
-        {
-            // do stuff if not selected
-        }
-    }
-
-    return VNoBrushScalePathItem::itemChange(change, value);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief keyReleaseEvent handle key release events.
- * @param event key release event.
- */
-void VToolDetail::keyReleaseEvent(QKeyEvent *event)
-{
-    switch (event->key())
-    {
-        case Qt::Key_Delete:
-            try
-            {
-                DeleteTool();
-            }
-            catch(const VExceptionToolWasDeleted &e)
-            {
-                Q_UNUSED(e)
-                return;//Leave this method immediately!!!
-            }
-            break;
-        default:
-            break;
-    }
-    VNoBrushScalePathItem::keyReleaseEvent ( event );
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::mousePressEvent(QGraphicsSceneMouseEvent *event)
-{
-    // Special for not selectable item first need to call standard mousePressEvent then accept event
-    VNoBrushScalePathItem::mousePressEvent(event);
-
-    // Somehow clicking on notselectable object do not clean previous selections.
-    if (not (flags() & ItemIsSelectable) && scene())
-    {
-        scene()->clearSelection();
-    }
-
-    if (flags() & QGraphicsItem::ItemIsMovable)
-    {
-        if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
-        {
-            SetOverrideCursor(cursorArrowCloseHand, 1, 1);
-        }
-    }
-
-    if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
-    {
-        doc->SelectedDetail(id);
-        emit ChoosedTool(id, SceneObject::Detail);
-    }
-
-    event->accept();// Special for not selectable item first need to call standard mousePressEvent then accept event
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief mouseReleaseEvent handle mouse release events.
- * @param event mouse release event.
- */
-void VToolDetail::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
-{
-    if (event->button() == Qt::LeftButton)
-    {
-        //Disable cursor-arrow-closehand
-        RestoreOverrideCursor(cursorArrowCloseHand);
-    }
-    VNoBrushScalePathItem::mouseReleaseEvent(event);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
-{
-    Q_UNUSED(event)
-    if (flags() & QGraphicsItem::ItemIsMovable)
-    {
-        SetOverrideCursor(cursorArrowOpenHand, 1, 1);
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
-{
-    Q_UNUSED(event)
-    if (flags() & QGraphicsItem::ItemIsMovable)
-    {
-        SetOverrideCursor(cursorArrowOpenHand, 1, 1);
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
-{
-    Q_UNUSED(event)
-    //Disable cursor-arrow-openhand
-    if (flags() & QGraphicsItem::ItemIsMovable)
-    {
-        RestoreOverrideCursor(cursorArrowOpenHand);
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief contextMenuEvent handle context menu events.
- * @param event context menu event.
- */
-void VToolDetail::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
-{
-    QMenu menu;
-    QAction *actionOption = menu.addAction(QIcon::fromTheme("preferences-other"), tr("Options"));
-
-    QAction *inLayoutOption = menu.addAction(tr("In layout"));
-    inLayoutOption->setCheckable(true);
-    const VDetail detail = VAbstractTool::data.GetDetail(id);
-    inLayoutOption->setChecked(detail.IsInLayout());
-
-    QAction *actionRemove = menu.addAction(QIcon::fromTheme("edit-delete"), tr("Delete"));
-    _referens > 1 ? actionRemove->setEnabled(false) : actionRemove->setEnabled(true);
-
-    QAction *selectedAction = menu.exec(event->screenPos());
-    if (selectedAction == actionOption)
-    {
-        dialog = new DialogDetail(getData(), id, qApp->getMainWindow());
-        dialog->setModal(true);
-        connect(qobject_cast< VMainGraphicsScene * >(this->scene()), &VMainGraphicsScene::ChoosedObject,
-                dialog, &DialogTool::ChosenObject);
-        connect(dialog, &DialogTool::DialogClosed, this, &VToolDetail::FullUpdateFromGuiOk);
-        setDialog();
-        dialog->show();
-    }
-    else if (selectedAction == inLayoutOption)
-    {
-        ToggleDetailInLayout *togglePrint = new ToggleDetailInLayout(id, selectedAction->isChecked(),
-                                                                     &(VAbstractTool::data), doc);
-        connect(togglePrint, &ToggleDetailInLayout::UpdateList, doc, &VAbstractPattern::CheckInLayoutList);
-        qApp->getUndoStack()->push(togglePrint);
-    }
-    else if (selectedAction == actionRemove)
-    {
-        try
-        {
-            DeleteTool();
-        }
-        catch(const VExceptionToolWasDeleted &e)
-        {
-            Q_UNUSED(e)
-            return;//Leave this method immediately!!!
-        }
-        return; //Leave this method immediately after call!!!
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief UpdateLabel updates the text label, making it just big enough for the text to fit it
- */
-void VToolDetail::UpdateLabel()
-{
-    const VDetail detail = VAbstractTool::data.GetDetail(id);
-    const VPatternPieceData& data = detail.GetPatternPieceData();
-
-    if (data.IsVisible() == true)
-    {
-        QFont fnt = qApp->font();
-        {
-            const int iFS = data.GetFontSize();
-            iFS < MIN_FONT_SIZE ? fnt.setPixelSize(MIN_FONT_SIZE) : fnt.setPixelSize(iFS);
-        }
-        dataLabel->SetFont(fnt);
-        dataLabel->SetSize(data.GetLabelWidth(), data.GetLabelHeight());
-        dataLabel->UpdateData(detail.getName(), data);
-        QPointF pt = data.GetPos();
-        QRectF rectBB;
-        rectBB.setTopLeft(pt);
-        rectBB.setWidth(dataLabel->boundingRect().width());
-        rectBB.setHeight(dataLabel->boundingRect().height());
-        qreal dX;
-        qreal dY;
-        if (dataLabel->IsContained(rectBB, data.GetRotation(), dX, dY) == false)
-        {
-            pt.setX(pt.x() + dX);
-            pt.setY(pt.y() + dY);
-        }
-
-        dataLabel->setPos(pt);
-        dataLabel->setRotation(data.GetRotation());
-        dataLabel->Update();
-        dataLabel->show();
-    }
-    else
-    {
-        dataLabel->hide();
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief UpdatePatternInfo updates the pattern info label
- */
-void VToolDetail::UpdatePatternInfo()
-{
-    const VDetail detail = VAbstractTool::data.GetDetail(id);
-    const VPatternInfoGeometry& geom = detail.GetPatternInfo();
-
-    if (geom.IsVisible() == true)
-    {
-        QFont fnt = qApp->font();
-        int iFS = geom.GetFontSize();
-        if (iFS < MIN_FONT_SIZE)
-        {
-            iFS = MIN_FONT_SIZE;
-        }
-        fnt.setPixelSize(iFS);
-        patternInfo->SetFont(fnt);
-        patternInfo->SetSize(geom.GetLabelWidth(), geom.GetLabelHeight());
-        patternInfo->UpdateData(doc, getData()->size(), getData()->height());
-
-        QPointF pt = geom.GetPos();
-        QRectF rectBB;
-        rectBB.setTopLeft(pt);
-        rectBB.setWidth(patternInfo->boundingRect().width());
-        rectBB.setHeight(patternInfo->boundingRect().height());
-        qreal dX;
-        qreal dY;
-        if (patternInfo->IsContained(rectBB, geom.GetRotation(), dX, dY) == false)
-        {
-            pt.setX(pt.x() + dX);
-            pt.setY(pt.y() + dY);
-        }
-
-        patternInfo->setPos(pt);
-        patternInfo->setRotation(geom.GetRotation());
-        patternInfo->Update();
-        if (patternInfo->GetTextLines() > 0)
-        {
-            patternInfo->show();
-        }
-        else
-        {
-            patternInfo->hide();
-        }
-    }
-    else
-    {
-        patternInfo->hide();
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VToolDetail::UpdateGrainline updates the grain line item
- */
-void VToolDetail::UpdateGrainline()
-{
-    const VDetail detail = VAbstractTool::data.GetDetail(id);
-    const VGrainlineGeometry& geom = detail.GetGrainlineGeometry();
-
-    if (geom.IsVisible() == true)
-    {
-        qreal dRotation;
-        qreal dLength;
-        try
-        {
-            QString qsFormula;
-            qsFormula = geom.GetRotation().replace("\n", " ");
-            qsFormula = qApp->TrVars()->FormulaFromUser(qsFormula, qApp->Settings()->GetOsSeparator());
-
-            Calculator cal1;
-            dRotation = cal1.EvalFormula(VDataTool::data.PlainVariables(), qsFormula);
-
-            qsFormula = geom.GetLength().replace("\n", " ");
-            qsFormula = qApp->TrVars()->FormulaFromUser(qsFormula, qApp->Settings()->GetOsSeparator());
-            Calculator cal2;
-            dLength = cal2.EvalFormula(VDataTool::data.PlainVariables(), qsFormula);
-        }
-        catch(...)
-        {
-            grainLine->hide();
-            return;
-        }
-
-        grainLine->UpdateGeometry(geom.GetPos(), dRotation, ToPixel(dLength, *VDataTool::data.GetPatternUnit()),
-                                  geom.GetArrowType());
-        grainLine->show();
-    }
-    else
-    {
-        grainLine->hide();
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief SaveMoveDetail saves the move detail operation to the undo stack
- */
-void VToolDetail::SaveMoveDetail(const QPointF& ptPos)
-{
-    VDetail oldDet = VAbstractTool::data.GetDetail(id);
-    VDetail newDet = oldDet;
-    newDet.GetPatternPieceData().SetPos(ptPos);
-    newDet.GetPatternPieceData().SetLabelWidth(dataLabel->boundingRect().width());
-    newDet.GetPatternPieceData().SetLabelHeight(dataLabel->boundingRect().height());
-    newDet.GetPatternPieceData().SetFontSize(dataLabel->GetFontSize());
-    newDet.GetPatternPieceData().SetRotation(dataLabel->rotation());
-
-    SaveDetailOptions* moveCommand = new SaveDetailOptions(oldDet, newDet, doc, id, this->scene());
-    moveCommand->setText(tr("move pattern piece label"));
-    connect(moveCommand, &SaveDetailOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
-    qApp->getUndoStack()->push(moveCommand);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief SaveResizeDetail saves the resize detail label operation to the undo stack
- */
-void VToolDetail::SaveResizeDetail(qreal dLabelW, int iFontSize)
-{
-    VDetail oldDet = VAbstractTool::data.GetDetail(id);
-    VDetail newDet = oldDet;
-    newDet.GetPatternPieceData().SetLabelWidth(dLabelW);
-    newDet.GetPatternPieceData().SetLabelHeight(dataLabel->boundingRect().height());
-    newDet.GetPatternPieceData().SetFontSize(iFontSize);
-    newDet.GetPatternPieceData().SetRotation(dataLabel->rotation());
-    SaveDetailOptions* resizeCommand = new SaveDetailOptions(oldDet, newDet, doc, id, this->scene());
-    resizeCommand->setText(tr("resize pattern piece label"));
-    connect(resizeCommand, &SaveDetailOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
-    qApp->getUndoStack()->push(resizeCommand);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief SaveRotationDetail saves the rotation detail label operation to the undo stack
- */
-void VToolDetail::SaveRotationDetail(qreal dRot)
-{
-    VDetail oldDet = VAbstractTool::data.GetDetail(id);
-    VDetail newDet = oldDet;
-    newDet.GetPatternPieceData().SetPos(dataLabel->pos());
-    newDet.GetPatternPieceData().SetLabelWidth(dataLabel->boundingRect().width());
-    newDet.GetPatternPieceData().SetLabelHeight(dataLabel->boundingRect().height());
-    newDet.GetPatternPieceData().SetFontSize(dataLabel->GetFontSize());
-    newDet.GetPatternPieceData().SetRotation(dRot);
-
-    SaveDetailOptions* rotateCommand = new SaveDetailOptions(oldDet, newDet, doc, id, this->scene());
-    rotateCommand->setText(tr("rotate pattern piece label"));
-    connect(rotateCommand, &SaveDetailOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
-    qApp->getUndoStack()->push(rotateCommand);
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief SaveMovePattern saves the pattern label position
- */
-void VToolDetail::SaveMovePattern(const QPointF &ptPos)
-{
-    VDetail oldDet = VAbstractTool::data.GetDetail(id);
-    VDetail newDet = oldDet;
-    newDet.GetPatternInfo().SetPos(ptPos);
-    newDet.GetPatternInfo().SetLabelWidth(patternInfo->boundingRect().width());
-    newDet.GetPatternInfo().SetLabelHeight(patternInfo->boundingRect().height());
-    newDet.GetPatternInfo().SetFontSize(patternInfo->GetFontSize());
-    newDet.GetPatternInfo().SetRotation(patternInfo->rotation());
-
-    SaveDetailOptions* moveCommand = new SaveDetailOptions(oldDet, newDet, doc, id, this->scene());
-    moveCommand->setText(tr("move pattern info label"));
-    connect(moveCommand, &SaveDetailOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
-    qApp->getUndoStack()->push(moveCommand);
-
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief: SaveResizePattern saves the pattern label width and font size
- */
-void VToolDetail::SaveResizePattern(qreal dLabelW, int iFontSize)
-{
-    VDetail oldDet = VAbstractTool::data.GetDetail(id);
-    VDetail newDet = oldDet;
-    newDet.GetPatternInfo().SetLabelWidth(dLabelW);
-    newDet.GetPatternInfo().SetLabelHeight(patternInfo->boundingRect().height());
-    newDet.GetPatternInfo().SetFontSize(iFontSize);
-    newDet.GetPatternInfo().SetRotation(patternInfo->rotation());
-    SaveDetailOptions* resizeCommand = new SaveDetailOptions(oldDet, newDet, doc, id, this->scene());
-    resizeCommand->setText(tr("resize pattern info label"));
-    connect(resizeCommand, &SaveDetailOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
-    qApp->getUndoStack()->push(resizeCommand);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::SaveRotationPattern(qreal dRot)
-{
-    VDetail oldDet = VAbstractTool::data.GetDetail(id);
-    VDetail newDet = oldDet;
-    newDet.GetPatternInfo().SetPos(patternInfo->pos());
-    newDet.GetPatternInfo().SetLabelWidth(patternInfo->boundingRect().width());
-    newDet.GetPatternInfo().SetLabelHeight(patternInfo->boundingRect().height());
-    newDet.GetPatternInfo().SetFontSize(patternInfo->GetFontSize());
-    newDet.GetPatternInfo().SetRotation(dRot);
-
-    SaveDetailOptions* rotateCommand = new SaveDetailOptions(oldDet, newDet, doc, id, this->scene());
-    rotateCommand->setText(tr("rotate pattern info label"));
-    connect(rotateCommand, &SaveDetailOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
-    qApp->getUndoStack()->push(rotateCommand);
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::SaveMoveGrainline(const QPointF& ptPos)
-{
-    VDetail oldDet = VAbstractTool::data.GetDetail(id);
-    VDetail newDet = oldDet;
-    newDet.GetGrainlineGeometry().SetPos(ptPos);
-    qDebug() << "******* new grainline pos" << ptPos;
-
-    SaveDetailOptions* moveCommand = new SaveDetailOptions(oldDet, newDet, doc, id, this->scene());
-    moveCommand->setText(tr("move grainline"));
-    connect(moveCommand, &SaveDetailOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
-    qApp->getUndoStack()->push(moveCommand);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::SaveResizeGrainline(qreal dLength)
-{
-    VDetail oldDet = VAbstractTool::data.GetDetail(id);
-    VDetail newDet = oldDet;
-
-    dLength = FromPixel(dLength, *VDataTool::data.GetPatternUnit());
-    newDet.GetGrainlineGeometry().SetLength(qApp->LocaleToString(dLength));
-    SaveDetailOptions* resizeCommand = new SaveDetailOptions(oldDet, newDet, doc, id, this->scene());
-    resizeCommand->setText(tr("resize grainline"));
-    connect(resizeCommand, &SaveDetailOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
-    qApp->getUndoStack()->push(resizeCommand);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::SaveRotateGrainline(qreal dRot, const QPointF& ptPos)
-{
-    VDetail oldDet = VAbstractTool::data.GetDetail(id);
-    VDetail newDet = oldDet;
-
-    dRot = qRadiansToDegrees(dRot);
-    newDet.GetGrainlineGeometry().SetRotation(qApp->LocaleToString(dRot));
-    newDet.GetGrainlineGeometry().SetPos(ptPos);
-    SaveDetailOptions* rotateCommand = new SaveDetailOptions(oldDet, newDet, doc, id, this->scene());
-    rotateCommand->setText(tr("rotate grainline"));
-    connect(rotateCommand, &SaveDetailOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
-    qApp->getUndoStack()->push(rotateCommand);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief AddNode add node to the file.
- * @param domElement tag in xml tree.
- * @param node node of detail.
- */
-void VToolDetail::AddNode(VAbstractPattern *doc, QDomElement &domElement, const VNodeDetail &node)
-{
-    QDomElement nod = doc->createElement(TagNode);
-
-    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);
-    }
-    else
-    {
-        doc->SetAttribute(nod, AttrNodeType, NodeTypeModeling);
-    }
-    switch (node.getTypeTool())
-    {
-        case (Tool::NodeArc):
-            doc->SetAttribute(nod, AttrType, NodeArc);
-            break;
-        case (Tool::NodeElArc):
-            doc->SetAttribute(nod, AttrType, NodeElArc);
-            break;
-        case (Tool::NodePoint):
-            doc->SetAttribute(nod, AttrType, NodePoint);
-            break;
-        case (Tool::NodeSpline):
-            doc->SetAttribute(nod, AttrType, NodeSpline);
-            break;
-        case (Tool::NodeSplinePath):
-            doc->SetAttribute(nod, AttrType, NodeSplinePath);
-            break;
-        default:
-            qDebug()<<"May be wrong tool type!!! Ignoring."<<Q_FUNC_INFO;
-            break;
-    }
-    domElement.appendChild(nod);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QString VToolDetail::getTagName() const
-{
-    return VAbstractPattern::TagDetail;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::ShowVisualization(bool show)
-{
-    Q_UNUSED(show)
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::GroupVisibility(quint32 object, bool visible)
-{
-    Q_UNUSED(object)
-    Q_UNUSED(visible)
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief RefreshGeometry refresh item on scene.
- */
-void VToolDetail::RefreshGeometry()
-{
-    this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
-
-    const VDetail detail = VAbstractTool::data.GetDetail(id);
-    QPainterPath mainPath = detail.ContourPath(this->getData());
-    this->setPath(mainPath);
-    this->setPos(detail.getMx(), detail.getMy());
-
-    if (detail.getSeamAllowance())
-    {
-        mainPath.addPath(detail.SeamAllowancePath(this->getData()));
-        mainPath.setFillRule(Qt::OddEvenFill);
-        seamAllowance->setPath(mainPath);
-    }
-    else
-    {
-        seamAllowance->setPath(QPainterPath());
-    }
-
-    this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::DeleteTool(bool ask)
-{
-    QScopedPointer<DeleteDetail> delDet(new DeleteDetail(doc, id, VAbstractTool::data.GetDetail(id)));
-    if (ask)
-    {
-        if (ConfirmDeletion() == QMessageBox::No)
-        {
-            return;
-        }
-        /* If UnionDetails tool delete detail no need emit FullParsing.*/
-        connect(delDet.data(), &DeleteDetail::NeedFullParsing, doc, &VAbstractPattern::NeedFullParsing);
-    }
-    qApp->getUndoStack()->push(delDet.take());
-
-    // Throw exception, this will help prevent case when we forget to immediately quit function.
-    VExceptionToolWasDeleted e("Tool was used after deleting.");
-    throw e;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-template <typename Tool>
-//cppcheck-suppress unusedFunction
-Tool* VToolDetail::InitTool(VMainGraphicsScene *scene, const VNodeDetail &node)
-{
-    QHash<quint32, VDataTool*>* tools = doc->getTools();
-    SCASSERT(tools != nullptr)
-    Tool *tool = qobject_cast<Tool*>(tools->value(node.getId()));
-    SCASSERT(tool != nullptr)
-    connect(tool, &Tool::ChoosedTool, scene, &VMainGraphicsScene::ChoosedItem);
-    tool->setParentItem(this);
-    tool->SetParentType(ParentType::Item);
-    doc->IncrementReferens(node.getId());
-    return tool;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::EnableToolMove(bool move)
-{
-    setFlag(QGraphicsItem::ItemIsMovable, move);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::AllowHover(bool enabled)
-{
-    setAcceptHoverEvents(enabled);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::AllowSelecting(bool enabled)
-{
-    setFlag(QGraphicsItem::ItemIsSelectable, enabled);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::ResetChildren(QGraphicsItem *pItem)
-{
-    const VDetail detail = VAbstractTool::data.GetDetail(id);
-    VTextGraphicsItem* pVGI = dynamic_cast<VTextGraphicsItem*>(pItem);
-    if (pVGI != dataLabel)
-    {
-        if (detail.GetPatternPieceData().IsVisible())
-        {
-            dataLabel->Reset();
-        }
-    }
-    if (pVGI != patternInfo)
-    {
-        if (detail.GetPatternInfo().IsVisible())
-        {
-            patternInfo->Reset();
-        }
-    }
-    VGrainlineItem* pGLI = dynamic_cast<VGrainlineItem*>(pItem);
-    if (pGLI != grainLine)
-    {
-        if (detail.GetGrainlineGeometry().IsVisible())
-        {
-            grainLine->Reset();
-        }
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::UpdateAll()
-{
-    sceneDetails->update();
-    update();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::retranslateUi()
-{
-    UpdateLabel();
-    UpdatePatternInfo();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolDetail::Highlight(quint32 id)
-{
-    setSelected(this->id == id);
-}
diff --git a/src/libs/vtools/tools/vtooldetail.h b/src/libs/vtools/tools/vtooldetail.h
deleted file mode 100644
index d46b144e6..000000000
--- a/src/libs/vtools/tools/vtooldetail.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/************************************************************************
- **
- **  @file   vtooldetail.h
- **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   November 15, 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
- **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
- **
- *************************************************************************/
-
-#ifndef VTOOLDETAIL_H
-#define VTOOLDETAIL_H
-
-#include <qcompilerdetection.h>
-#include <QObject>
-#include <QtGlobal>
-
-#include "../vwidgets/vnobrushscalepathitem.h"
-#include "vabstracttool.h"
-#include "vtextgraphicsitem.h"
-#include "vgrainlineitem.h"
-
-class VMainGraphicsScene;
-class DialogTool;
-
-/**
- * @brief The VToolDetail class for working with detail.
- */
-class VToolDetail: public VAbstractTool, public VNoBrushScalePathItem
-{
-    Q_OBJECT
-public:
-    ~VToolDetail();
-
-    virtual void       setDialog();
-    template<typename T>
-    /**
-     * @brief CreateNode create new node for detail.
-     * @param data container.
-     * @param id id parent object.
-     * @return id for new object.
-     */
-    static quint32 CreateNode(VContainer *data, const quint32 &id)
-    {
-        //We can't use exist object. Need create new.
-        T *node = new T(*data->GeometricObject<T>(id).data());
-        node->setMode(Draw::Modeling);
-        return data->AddGObject(node);
-    }
-
-    static void        Create(DialogTool *dialog, VMainGraphicsScene *scene, VAbstractPattern *doc, VContainer *data);
-    static void        Create(const quint32 &_id, const VDetail &newDetail, VMainGraphicsScene  *scene,
-                              VAbstractPattern *doc, VContainer *data, const Document &parse,
-                              const Source &typeCreation, const QString &drawName = QString());
-    static const QString TagNode;
-    static const QString AttrSupplement;
-    static const QString AttrClosed;
-    static const QString AttrForbidFlipping;
-    static const QString AttrWidth;
-    static const QString AttrHeight;
-    static const QString AttrNodeType;
-    static const QString AttrReverse;
-    static const QString AttrFont;
-    static const QString AttrRotation;
-    static const QString NodeTypeContour;
-    static const QString NodeTypeModeling;
-    static const QString NodeArc;
-    static const QString NodeElArc;
-    static const QString NodePoint;
-    static const QString NodeSpline;
-    static const QString NodeSplinePath;
-    void               Remove(bool ask);
-    static void        AddNode(VAbstractPattern *doc, QDomElement &domElement, const VNodeDetail &node);
-    virtual int        type() const Q_DECL_OVERRIDE {return Type;}
-    enum { Type = UserType + static_cast<int>(Tool::Detail)};
-    virtual QString    getTagName() const Q_DECL_OVERRIDE;
-    virtual void       ShowVisualization(bool show) Q_DECL_OVERRIDE;
-    virtual void       GroupVisibility(quint32 object, bool visible) Q_DECL_OVERRIDE;
-public slots:
-    virtual void       FullUpdateFromFile () Q_DECL_OVERRIDE;
-    virtual void       FullUpdateFromGuiOk(int result);
-    void               EnableToolMove(bool move);
-    virtual void       AllowHover(bool enabled) Q_DECL_OVERRIDE;
-    virtual void       AllowSelecting(bool enabled) Q_DECL_OVERRIDE;
-    virtual void       ResetChildren(QGraphicsItem* pItem);
-    virtual void       UpdateAll();
-    virtual void       retranslateUi();
-    void               Highlight(quint32 id);
-protected:
-    virtual void       paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
-                             QWidget *widget) Q_DECL_OVERRIDE;
-    virtual void       AddToFile () Q_DECL_OVERRIDE;
-    virtual void       RefreshDataInFile() Q_DECL_OVERRIDE;
-    virtual QVariant   itemChange ( GraphicsItemChange change, const QVariant &value ) Q_DECL_OVERRIDE;
-    virtual void       mousePressEvent( QGraphicsSceneMouseEvent * event) Q_DECL_OVERRIDE;
-    virtual void       mouseReleaseEvent ( QGraphicsSceneMouseEvent * event ) Q_DECL_OVERRIDE;
-    virtual void       hoverMoveEvent( QGraphicsSceneHoverEvent * event ) Q_DECL_OVERRIDE;
-    virtual void       hoverEnterEvent ( QGraphicsSceneHoverEvent * event ) Q_DECL_OVERRIDE;
-    virtual void       hoverLeaveEvent ( QGraphicsSceneHoverEvent * event ) Q_DECL_OVERRIDE;
-    virtual void       contextMenuEvent ( QGraphicsSceneContextMenuEvent * event ) Q_DECL_OVERRIDE;
-    virtual void       keyReleaseEvent(QKeyEvent * event) Q_DECL_OVERRIDE;
-    virtual void       SetVisualization() Q_DECL_OVERRIDE {}
-
-protected slots:
-    virtual void       UpdateLabel();
-    virtual void       UpdatePatternInfo();
-    virtual void       UpdateGrainline();
-    virtual void       SaveMoveDetail(const QPointF &ptPos);
-    virtual void       SaveResizeDetail(qreal dLabelW, int iFontSize);
-    virtual void       SaveRotationDetail(qreal dRot);
-    virtual void       SaveMovePattern(const QPointF& ptPos);
-    virtual void       SaveResizePattern(qreal dLabelW, int iFontSize);
-    virtual void       SaveRotationPattern(qreal dRot);
-    virtual void       SaveMoveGrainline(const QPointF& ptPos);
-    virtual void       SaveResizeGrainline(qreal dLength);
-    virtual void       SaveRotateGrainline(qreal dRot, const QPointF& ptPos);
-
-private:
-    Q_DISABLE_COPY(VToolDetail)
-    /** @brief dialog dialog options. */
-    DialogTool                  *dialog;
-
-    /** @brief sceneDetails pointer to the scene. */
-    VMainGraphicsScene          *sceneDetails;
-    QString                      drawName;
-
-    VNoBrushScalePathItem       *seamAllowance;
-    VTextGraphicsItem           *dataLabel;
-    VTextGraphicsItem           *patternInfo;
-    VGrainlineItem              *grainLine;
-
-    VToolDetail(VAbstractPattern *doc, VContainer *data, const quint32 &id, const Source &typeCreation,
-                VMainGraphicsScene *scene, const QString &drawName, QGraphicsItem * parent = nullptr);
-
-    void               RefreshGeometry ();
-    template <typename Tool>
-    /**
-     * @brief InitTool initial node item on scene
-     * @param scene pointer to scene.
-     * @param node node of detail.
-     */
-    Tool*              InitTool(VMainGraphicsScene *scene, const VNodeDetail &node);
-    virtual void       DeleteTool(bool ask = true) Q_DECL_OVERRIDE;
-};
-
-#endif // VTOOLDETAIL_H
diff --git a/src/libs/vtools/tools/vtoolseamallowance.cpp b/src/libs/vtools/tools/vtoolseamallowance.cpp
new file mode 100644
index 000000000..7a13ae281
--- /dev/null
+++ b/src/libs/vtools/tools/vtoolseamallowance.cpp
@@ -0,0 +1,1211 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   6 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "vtoolseamallowance.h"
+#include "../dialogs/tools/dialogseamallowance.h"
+#include "../vpatterndb/vpiecenode.h"
+#include "../vpatterndb/vpiecepath.h"
+#include "../vpatterndb/calculator.h"
+#include "../vpatterndb/vpatterninfogeometry.h"
+#include "../vpatterndb/vpatternpiecedata.h"
+#include "nodeDetails/vnodearc.h"
+#include "nodeDetails/vnodeellipticalarc.h"
+#include "nodeDetails/vnodepoint.h"
+#include "nodeDetails/vnodespline.h"
+#include "nodeDetails/vnodesplinepath.h"
+#include "nodeDetails/vtoolpiecepath.h"
+#include "../vgeometry/varc.h"
+#include "../vgeometry/vellipticalarc.h"
+#include "../vgeometry/vcubicbezier.h"
+#include "../vgeometry/vcubicbezierpath.h"
+#include "../vgeometry/vpointf.h"
+#include "../vgeometry/vspline.h"
+#include "../vgeometry/vsplinepath.h"
+#include "../ifc/xml/vpatternconverter.h"
+#include "../undocommands/addpiece.h"
+#include "../undocommands/deletepiece.h"
+#include "../undocommands/movepiece.h"
+#include "../undocommands/savepieceoptions.h"
+#include "../undocommands/togglepieceinlayout.h"
+#include "../vwidgets/vmaingraphicsview.h"
+#include "../vwidgets/vnobrushscalepathitem.h"
+
+#include <QGraphicsSceneMouseEvent>
+#include <QGraphicsView>
+#include <QKeyEvent>
+#include <QMenu>
+#include <QMessageBox>
+
+// Current version of seam allowance tag nned for backward compatibility
+const quint8 VToolSeamAllowance::pieceVersion = 2;
+
+const QString VToolSeamAllowance::TagCSA     = QStringLiteral("csa");
+const QString VToolSeamAllowance::TagRecord  = QStringLiteral("record");
+const QString VToolSeamAllowance::TagIPaths  = QStringLiteral("iPaths");
+
+const QString VToolSeamAllowance::AttrVersion        = QStringLiteral("version");
+const QString VToolSeamAllowance::AttrForbidFlipping = QStringLiteral("forbidFlipping");
+const QString VToolSeamAllowance::AttrSeamAllowance  = QStringLiteral("seamAllowance");
+const QString VToolSeamAllowance::AttrHeight         = QStringLiteral("height");
+const QString VToolSeamAllowance::AttrUnited         = QStringLiteral("united");
+const QString VToolSeamAllowance::AttrFont           = QStringLiteral("fontSize");
+
+//---------------------------------------------------------------------------------------------------------------------
+VToolSeamAllowance::~VToolSeamAllowance()
+{
+    delete m_dialog;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VToolSeamAllowance *VToolSeamAllowance::Create(DialogTool *dialog, VMainGraphicsScene *scene, VAbstractPattern *doc,
+                                               VContainer *data)
+{
+    SCASSERT(dialog != nullptr);
+    DialogSeamAllowance *dialogTool = qobject_cast<DialogSeamAllowance*>(dialog);
+    SCASSERT(dialogTool != nullptr);
+    VPiece detail = dialogTool->GetPiece();
+    QString width = detail.GetFormulaSAWidth();
+    qApp->getUndoStack()->beginMacro("add detail");
+    detail.GetPath().SetNodes(PrepareNodes(detail.GetPath(), scene, doc, data));
+
+    VToolSeamAllowance *piece = Create(0, detail, width, scene, doc, data, Document::FullParse, Source::FromGui);
+
+    if (piece != nullptr)
+    {
+        piece->m_dialog = dialogTool;
+    }
+    return piece;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VToolSeamAllowance *VToolSeamAllowance::Create(quint32 id, VPiece newPiece, QString &width, VMainGraphicsScene *scene,
+                                               VAbstractPattern *doc, VContainer *data, const Document &parse,
+                                               const Source &typeCreation, const QString &drawName)
+{
+    if (typeCreation == Source::FromGui || typeCreation == Source::FromTool)
+    {
+        data->AddVariable(currentSeamAllowance, new VIncrement(data, currentSeamAllowance, 0, newPiece.GetSAWidth(),
+                                                               width, true, tr("Current seam allowance")));
+        id = data->AddPiece(newPiece);
+    }
+    else
+    {
+        const qreal calcWidth = CheckFormula(id, width, data);
+        newPiece.SetFormulaSAWidth(width, calcWidth);
+
+        data->AddVariable(currentSeamAllowance, new VIncrement(data, currentSeamAllowance, 0, calcWidth,
+                                                               width, true, tr("Current seam allowance")));
+
+        data->UpdatePiece(id, newPiece);
+        if (parse != Document::FullParse)
+        {
+            doc->UpdateToolData(id, data);
+        }
+    }
+    VAbstractTool::AddRecord(id, Tool::Piece, doc);
+    VToolSeamAllowance *piece = nullptr;
+    if (parse == Document::FullParse)
+    {
+        piece = new VToolSeamAllowance(doc, data, id, typeCreation, scene, drawName);
+        scene->addItem(piece);
+        connect(piece, &VToolSeamAllowance::ChoosedTool, scene, &VMainGraphicsScene::ChoosedItem);
+        connect(scene, &VMainGraphicsScene::EnableDetailItemHover, piece, &VToolSeamAllowance::AllowHover);
+        connect(scene, &VMainGraphicsScene::EnableDetailItemSelection, piece, &VToolSeamAllowance::AllowSelecting);
+        connect(scene, &VMainGraphicsScene::HighlightDetail, piece, &VToolSeamAllowance::Highlight);
+        doc->AddTool(id, piece);
+    }
+    //Very important to delete it. Only this tool need this special variable.
+    data->RemoveVariable(currentLength);
+    return piece;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::Remove(bool ask)
+{
+    try
+    {
+        DeleteTool(ask);
+    }
+    catch(const VExceptionToolWasDeleted &e)
+    {
+        Q_UNUSED(e);
+        return;//Leave this method immediately!!!
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::AddAttributes(VAbstractPattern *doc, QDomElement &domElement, quint32 id, const VPiece &piece)
+{
+    SCASSERT(doc != nullptr);
+
+    doc->SetAttribute(domElement, VDomDocument::AttrId, id);
+    doc->SetAttribute(domElement, AttrName, piece.GetName());
+    doc->SetAttribute(domElement, AttrVersion, QString().setNum(pieceVersion));
+    doc->SetAttribute(domElement, AttrMx, qApp->fromPixel(piece.GetMx()));
+    doc->SetAttribute(domElement, AttrMy, qApp->fromPixel(piece.GetMy()));
+    doc->SetAttribute(domElement, AttrInLayout, piece.IsInLayout());
+    doc->SetAttribute(domElement, AttrForbidFlipping, piece.IsForbidFlipping());
+    doc->SetAttribute(domElement, AttrSeamAllowance, piece.IsSeamAllowance());
+    doc->SetAttribute(domElement, VAbstractPattern::AttrWidth, piece.GetFormulaSAWidth());
+    doc->SetAttribute(domElement, AttrUnited, piece.IsUnited());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::AddCSARecord(VAbstractPattern *doc, QDomElement &domElement, const CustomSARecord &record)
+{
+    QDomElement recordNode = doc->createElement(VToolSeamAllowance::TagRecord);
+
+    doc->SetAttribute(recordNode, VAbstractPattern::AttrStart, record.startPoint);
+    doc->SetAttribute(recordNode, VAbstractPattern::AttrPath, record.path);
+    doc->SetAttribute(recordNode, VAbstractPattern::AttrEnd, record.endPoint);
+    doc->SetAttribute(recordNode, VAbstractPattern::AttrNodeReverse, record.reverse);
+    doc->SetAttribute(recordNode, VAbstractPattern::AttrIncludeAs, static_cast<unsigned int>(record.includeType));
+
+    domElement.appendChild(recordNode);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::AddCSARecords(VAbstractPattern *doc, QDomElement &domElement,
+                                       const QVector<CustomSARecord> &records)
+{
+    if (records.size() > 0)
+    {
+        QDomElement csaRecordsElement = doc->createElement(VToolSeamAllowance::TagCSA);
+        for (int i = 0; i < records.size(); ++i)
+        {
+            AddCSARecord(doc, csaRecordsElement, records.at(i));
+        }
+        domElement.appendChild(csaRecordsElement);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::AddInternalPaths(VAbstractPattern *doc, QDomElement &domElement, const QVector<quint32> &paths)
+{
+    if (paths.size() > 0)
+    {
+        QDomElement iPathsElement = doc->createElement(VToolSeamAllowance::TagIPaths);
+        for (int i = 0; i < paths.size(); ++i)
+        {
+            QDomElement recordNode = doc->createElement(VToolSeamAllowance::TagRecord);
+            doc->SetAttribute(recordNode, VAbstractPattern::AttrPath, paths.at(i));
+            iPathsElement.appendChild(recordNode);
+        }
+        domElement.appendChild(iPathsElement);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::AddPatternPieceData(VAbstractPattern *doc, QDomElement &domElement, const VPiece &piece)
+{
+    QDomElement domData = doc->createElement(VAbstractPattern::TagData);
+    const VPatternPieceData& data = piece.GetPatternPieceData();
+    doc->SetAttribute(domData, VAbstractPattern::AttrLetter, data.GetLetter());
+    doc->SetAttribute(domData, VAbstractPattern::AttrVisible, data.IsVisible() == true? trueStr : falseStr);
+    doc->SetAttribute(domData, AttrMx, data.GetPos().x());
+    doc->SetAttribute(domData, AttrMy, data.GetPos().y());
+    doc->SetAttribute(domData, VAbstractPattern::AttrWidth, data.GetLabelWidth());
+    doc->SetAttribute(domData, AttrHeight, data.GetLabelHeight());
+    doc->SetAttribute(domData, AttrFont, data.GetFontSize());
+    doc->SetAttribute(domData, VAbstractPattern::AttrRotation, data.GetRotation());
+
+    for (int i = 0; i < data.GetMCPCount(); ++i)
+    {
+        const MaterialCutPlacement mcp = data.GetMCP(i);
+        QDomElement domMCP = doc->createElement(VAbstractPattern::TagMCP);
+        doc->SetAttribute(domMCP, VAbstractPattern::AttrMaterial, int(mcp.m_eMaterial));
+        if (mcp.m_eMaterial == MaterialType::mtUserDefined)
+        {
+            doc->SetAttribute(domMCP, VAbstractPattern::AttrUserDefined, mcp.m_qsMaterialUserDef);
+        }
+        doc->SetAttribute(domMCP, VAbstractPattern::AttrCutNumber, mcp.m_iCutNumber);
+        doc->SetAttribute(domMCP, VAbstractPattern::AttrPlacement, int(mcp.m_ePlacement));
+        domData.appendChild(domMCP);
+    }
+    domElement.appendChild(domData);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::AddPatternInfo(VAbstractPattern *doc, QDomElement &domElement, const VPiece &piece)
+{
+    QDomElement domData = doc->createElement(VAbstractPattern::TagPatternInfo);
+    const VPatternInfoGeometry& geom = piece.GetPatternInfo();
+    doc->SetAttribute(domData, VAbstractPattern::AttrVisible, geom.IsVisible() == true ? trueStr : falseStr);
+    doc->SetAttribute(domData, AttrMx, geom.GetPos().x());
+    doc->SetAttribute(domData, AttrMy, geom.GetPos().y());
+    doc->SetAttribute(domData, VAbstractPattern::AttrWidth, geom.GetLabelWidth());
+    doc->SetAttribute(domData, AttrHeight, geom.GetLabelHeight());
+    doc->SetAttribute(domData, AttrFont, geom.GetFontSize());
+    doc->SetAttribute(domData, VAbstractPattern::AttrRotation, geom.GetRotation());
+    domElement.appendChild(domData);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::AddGrainline(VAbstractPattern *doc, QDomElement &domElement, const VPiece &piece)
+{
+    // grainline
+    QDomElement domData = doc->createElement(VAbstractPattern::TagGrainline);
+    const VGrainlineGeometry& glGeom = piece.GetGrainlineGeometry();
+    doc->SetAttribute(domData, VAbstractPattern::AttrVisible, glGeom.IsVisible() == true ? trueStr : falseStr);
+    doc->SetAttribute(domData, AttrMx, glGeom.GetPos().x());
+    doc->SetAttribute(domData, AttrMy, glGeom.GetPos().y());
+    doc->SetAttribute(domData, AttrLength, glGeom.GetLength());
+    doc->SetAttribute(domData, VAbstractPattern::AttrRotation, glGeom.GetRotation());
+    doc->SetAttribute(domData, VAbstractPattern::AttrArrows, int(glGeom.GetArrowType()));
+    domElement.appendChild(domData);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString VToolSeamAllowance::getTagName() const
+{
+    return VAbstractPattern::TagDetail;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::ShowVisualization(bool show)
+{
+    Q_UNUSED(show)
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::GroupVisibility(quint32 object, bool visible)
+{
+    Q_UNUSED(object);
+    Q_UNUSED(visible);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::FullUpdateFromFile()
+{
+    RefreshGeometry();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::FullUpdateFromGuiOk(int result)
+{
+    if (result == QDialog::Accepted)
+    {
+        SaveDialogChange();
+    }
+    delete m_dialog;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::FullUpdateFromGuiApply()
+{
+    SaveDialogChange();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::EnableToolMove(bool move)
+{
+    setFlag(QGraphicsItem::ItemIsMovable, move);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::AllowHover(bool enabled)
+{
+    setAcceptHoverEvents(enabled);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::AllowSelecting(bool enabled)
+{
+    setFlag(QGraphicsItem::ItemIsSelectable, enabled);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::ResetChildren(QGraphicsItem *pItem)
+{
+    const VPiece detail = VAbstractTool::data.GetPiece(id);
+    VTextGraphicsItem* pVGI = qgraphicsitem_cast<VTextGraphicsItem*>(pItem);
+    if (pVGI != m_dataLabel)
+    {
+        if (detail.GetPatternPieceData().IsVisible())
+        {
+            m_dataLabel->Reset();
+        }
+    }
+    if (pVGI != m_patternInfo)
+    {
+        if (detail.GetPatternInfo().IsVisible())
+        {
+            m_patternInfo->Reset();
+        }
+    }
+    VGrainlineItem* pGLI = qgraphicsitem_cast<VGrainlineItem*>(pItem);
+    if (pGLI != m_grainLine)
+    {
+        if (detail.GetGrainlineGeometry().IsVisible())
+        {
+            m_grainLine->Reset();
+        }
+    }
+
+    update();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::UpdateAll()
+{
+    m_sceneDetails->update();
+    update();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::retranslateUi()
+{
+    UpdateLabel();
+    UpdatePatternInfo();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::Highlight(quint32 id)
+{
+    setSelected(this->id == id);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief UpdateLabel updates the text label, making it just big enough for the text to fit it
+ */
+void VToolSeamAllowance::UpdateLabel()
+{
+    const VPiece detail = VAbstractTool::data.GetPiece(id);
+    const VPatternPieceData& data = detail.GetPatternPieceData();
+
+    if (data.IsVisible() == true)
+    {
+        QFont fnt = qApp->font();
+        {
+            const int iFS = data.GetFontSize();
+            iFS < MIN_FONT_SIZE ? fnt.setPixelSize(MIN_FONT_SIZE) : fnt.setPixelSize(iFS);
+        }
+        m_dataLabel->SetFont(fnt);
+        m_dataLabel->SetSize(data.GetLabelWidth(), data.GetLabelHeight());
+        m_dataLabel->UpdateData(detail.GetName(), data);
+        QPointF pt = data.GetPos();
+        QRectF rectBB;
+        rectBB.setTopLeft(pt);
+        rectBB.setWidth(m_dataLabel->boundingRect().width());
+        rectBB.setHeight(m_dataLabel->boundingRect().height());
+        qreal dX;
+        qreal dY;
+        if (m_dataLabel->IsContained(rectBB, data.GetRotation(), dX, dY) == false)
+        {
+            pt.setX(pt.x() + dX);
+            pt.setY(pt.y() + dY);
+        }
+
+        m_dataLabel->setPos(pt);
+        m_dataLabel->setRotation(data.GetRotation());
+        m_dataLabel->Update();
+        m_dataLabel->show();
+    }
+    else
+    {
+        m_dataLabel->hide();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief UpdatePatternInfo updates the pattern info label
+ */
+void VToolSeamAllowance::UpdatePatternInfo()
+{
+    const VPiece detail = VAbstractTool::data.GetPiece(id);
+    const VPatternInfoGeometry& geom = detail.GetPatternInfo();
+
+    if (geom.IsVisible() == true)
+    {
+        QFont fnt = qApp->font();
+        int iFS = geom.GetFontSize();
+        if (iFS < MIN_FONT_SIZE)
+        {
+            iFS = MIN_FONT_SIZE;
+        }
+        fnt.setPixelSize(iFS);
+        m_patternInfo->SetFont(fnt);
+        m_patternInfo->SetSize(geom.GetLabelWidth(), geom.GetLabelHeight());
+        m_patternInfo->UpdateData(doc, getData()->size(), getData()->height());
+
+        QPointF pt = geom.GetPos();
+        QRectF rectBB;
+        rectBB.setTopLeft(pt);
+        rectBB.setWidth(m_patternInfo->boundingRect().width());
+        rectBB.setHeight(m_patternInfo->boundingRect().height());
+        qreal dX;
+        qreal dY;
+        if (m_patternInfo->IsContained(rectBB, geom.GetRotation(), dX, dY) == false)
+        {
+            pt.setX(pt.x() + dX);
+            pt.setY(pt.y() + dY);
+        }
+
+        m_patternInfo->setPos(pt);
+        m_patternInfo->setRotation(geom.GetRotation());
+        m_patternInfo->Update();
+        m_patternInfo->GetTextLines() > 0 ? m_patternInfo->show() : m_patternInfo->hide();
+    }
+    else
+    {
+        m_patternInfo->hide();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief VToolDetail::UpdateGrainline updates the grain line item
+ */
+void VToolSeamAllowance::UpdateGrainline()
+{
+    const VPiece detail = VAbstractTool::data.GetPiece(id);
+    const VGrainlineGeometry& geom = detail.GetGrainlineGeometry();
+
+    if (geom.IsVisible() == true)
+    {
+        qreal dRotation;
+        qreal dLength;
+        try
+        {
+            QString qsFormula;
+            qsFormula = geom.GetRotation().replace("\n", " ");
+            qsFormula = qApp->TrVars()->FormulaFromUser(qsFormula, qApp->Settings()->GetOsSeparator());
+
+            Calculator cal1;
+            dRotation = cal1.EvalFormula(VDataTool::data.PlainVariables(), qsFormula);
+
+            qsFormula = geom.GetLength().replace("\n", " ");
+            qsFormula = qApp->TrVars()->FormulaFromUser(qsFormula, qApp->Settings()->GetOsSeparator());
+            Calculator cal2;
+            dLength = cal2.EvalFormula(VDataTool::data.PlainVariables(), qsFormula);
+        }
+        catch(...)
+        {
+            m_grainLine->hide();
+            return;
+        }
+
+        m_grainLine->UpdateGeometry(geom.GetPos(), dRotation, ToPixel(dLength, *VDataTool::data.GetPatternUnit()),
+                                    geom.GetArrowType());
+        m_grainLine->show();
+    }
+    else
+    {
+        m_grainLine->hide();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief SaveMoveDetail saves the move detail operation to the undo stack
+ */
+void VToolSeamAllowance::SaveMoveDetail(const QPointF& ptPos)
+{
+    VPiece oldDet = VAbstractTool::data.GetPiece(id);
+    VPiece newDet = oldDet;
+    newDet.GetPatternPieceData().SetPos(ptPos);
+    newDet.GetPatternPieceData().SetLabelWidth(m_dataLabel->boundingRect().width());
+    newDet.GetPatternPieceData().SetLabelHeight(m_dataLabel->boundingRect().height());
+    newDet.GetPatternPieceData().SetFontSize(m_dataLabel->GetFontSize());
+    newDet.GetPatternPieceData().SetRotation(m_dataLabel->rotation());
+
+    SavePieceOptions* moveCommand = new SavePieceOptions(oldDet, newDet, doc, id);
+    moveCommand->setText(tr("move pattern piece label"));
+    connect(moveCommand, &SavePieceOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
+    qApp->getUndoStack()->push(moveCommand);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief SaveResizeDetail saves the resize detail label operation to the undo stack
+ */
+void VToolSeamAllowance::SaveResizeDetail(qreal dLabelW, int iFontSize)
+{
+    VPiece oldDet = VAbstractTool::data.GetPiece(id);
+    VPiece newDet = oldDet;
+    newDet.GetPatternPieceData().SetLabelWidth(dLabelW);
+    newDet.GetPatternPieceData().SetLabelHeight(m_dataLabel->boundingRect().height());
+    newDet.GetPatternPieceData().SetFontSize(iFontSize);
+    newDet.GetPatternPieceData().SetRotation(m_dataLabel->rotation());
+    SavePieceOptions* resizeCommand = new SavePieceOptions(oldDet, newDet, doc, id);
+    resizeCommand->setText(tr("resize pattern piece label"));
+    connect(resizeCommand, &SavePieceOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
+    qApp->getUndoStack()->push(resizeCommand);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief SaveRotationDetail saves the rotation detail label operation to the undo stack
+ */
+void VToolSeamAllowance::SaveRotationDetail(qreal dRot)
+{
+    VPiece oldDet = VAbstractTool::data.GetPiece(id);
+    VPiece newDet = oldDet;
+    newDet.GetPatternPieceData().SetPos(m_dataLabel->pos());
+    newDet.GetPatternPieceData().SetLabelWidth(m_dataLabel->boundingRect().width());
+    newDet.GetPatternPieceData().SetLabelHeight(m_dataLabel->boundingRect().height());
+    newDet.GetPatternPieceData().SetFontSize(m_dataLabel->GetFontSize());
+    newDet.GetPatternPieceData().SetRotation(dRot);
+
+    SavePieceOptions* rotateCommand = new SavePieceOptions(oldDet, newDet, doc, id);
+    rotateCommand->setText(tr("rotate pattern piece label"));
+    connect(rotateCommand, &SavePieceOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
+    qApp->getUndoStack()->push(rotateCommand);
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief SaveMovePattern saves the pattern label position
+ */
+void VToolSeamAllowance::SaveMovePattern(const QPointF &ptPos)
+{
+    VPiece oldDet = VAbstractTool::data.GetPiece(id);
+    VPiece newDet = oldDet;
+    newDet.GetPatternInfo().SetPos(ptPos);
+    newDet.GetPatternInfo().SetLabelWidth(m_patternInfo->boundingRect().width());
+    newDet.GetPatternInfo().SetLabelHeight(m_patternInfo->boundingRect().height());
+    newDet.GetPatternInfo().SetFontSize(m_patternInfo->GetFontSize());
+    newDet.GetPatternInfo().SetRotation(m_patternInfo->rotation());
+
+    SavePieceOptions* moveCommand = new SavePieceOptions(oldDet, newDet, doc, id);
+    moveCommand->setText(tr("move pattern info label"));
+    connect(moveCommand, &SavePieceOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
+    qApp->getUndoStack()->push(moveCommand);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief: SaveResizePattern saves the pattern label width and font size
+ */
+void VToolSeamAllowance::SaveResizePattern(qreal dLabelW, int iFontSize)
+{
+    VPiece oldDet = VAbstractTool::data.GetPiece(id);
+    VPiece newDet = oldDet;
+    newDet.GetPatternInfo().SetLabelWidth(dLabelW);
+    newDet.GetPatternInfo().SetLabelHeight(m_patternInfo->boundingRect().height());
+    newDet.GetPatternInfo().SetFontSize(iFontSize);
+    newDet.GetPatternInfo().SetRotation(m_patternInfo->rotation());
+    SavePieceOptions* resizeCommand = new SavePieceOptions(oldDet, newDet, doc, id);
+    resizeCommand->setText(tr("resize pattern info label"));
+    connect(resizeCommand, &SavePieceOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
+    qApp->getUndoStack()->push(resizeCommand);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::SaveRotationPattern(qreal dRot)
+{
+    VPiece oldDet = VAbstractTool::data.GetPiece(id);
+    VPiece newDet = oldDet;
+    newDet.GetPatternInfo().SetPos(m_patternInfo->pos());
+    newDet.GetPatternInfo().SetLabelWidth(m_patternInfo->boundingRect().width());
+    newDet.GetPatternInfo().SetLabelHeight(m_patternInfo->boundingRect().height());
+    newDet.GetPatternInfo().SetFontSize(m_patternInfo->GetFontSize());
+    newDet.GetPatternInfo().SetRotation(dRot);
+
+    SavePieceOptions* rotateCommand = new SavePieceOptions(oldDet, newDet, doc, id);
+    rotateCommand->setText(tr("rotate pattern info label"));
+    connect(rotateCommand, &SavePieceOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
+    qApp->getUndoStack()->push(rotateCommand);
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::SaveMoveGrainline(const QPointF& ptPos)
+{
+    VPiece oldDet = VAbstractTool::data.GetPiece(id);
+    VPiece newDet = oldDet;
+    newDet.GetGrainlineGeometry().SetPos(ptPos);
+    qDebug() << "******* new grainline pos" << ptPos;
+
+    SavePieceOptions* moveCommand = new SavePieceOptions(oldDet, newDet, doc, id);
+    moveCommand->setText(tr("move grainline"));
+    connect(moveCommand, &SavePieceOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
+    qApp->getUndoStack()->push(moveCommand);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::SaveResizeGrainline(qreal dLength)
+{
+    VPiece oldDet = VAbstractTool::data.GetPiece(id);
+    VPiece newDet = oldDet;
+
+    dLength = FromPixel(dLength, *VDataTool::data.GetPatternUnit());
+    newDet.GetGrainlineGeometry().SetLength(qApp->LocaleToString(dLength));
+    SavePieceOptions* resizeCommand = new SavePieceOptions(oldDet, newDet, doc, id);
+    resizeCommand->setText(tr("resize grainline"));
+    connect(resizeCommand, &SavePieceOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
+    qApp->getUndoStack()->push(resizeCommand);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::SaveRotateGrainline(qreal dRot, const QPointF& ptPos)
+{
+    VPiece oldDet = VAbstractTool::data.GetPiece(id);
+    VPiece newDet = oldDet;
+
+    dRot = qRadiansToDegrees(dRot);
+    newDet.GetGrainlineGeometry().SetRotation(qApp->LocaleToString(dRot));
+    newDet.GetGrainlineGeometry().SetPos(ptPos);
+    SavePieceOptions* rotateCommand = new SavePieceOptions(oldDet, newDet, doc, id);
+    rotateCommand->setText(tr("rotate grainline"));
+    connect(rotateCommand, &SavePieceOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
+    qApp->getUndoStack()->push(rotateCommand);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief VToolDetail::paint draws a bounding box around detail, if one of its text or grainline items is not idle.
+ */
+void VToolSeamAllowance::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+    if (scene()->views().count() > 0)
+    {
+        const QPoint pt0 = scene()->views().at(0)->mapFromScene(0, 0);
+        const QPoint pt = scene()->views().at(0)->mapFromScene(0, 100);
+
+        const QPoint p = pt - pt0;
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
+        const qreal dScale = qSqrt(QPoint::dotProduct(p, p));
+#else
+        const qreal dScale = qSqrt(p.x() * p.x() + p.y() * p.y());
+#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
+        m_grainLine->SetScale(100/dScale);
+    }
+
+    if (m_dataLabel->IsIdle() == false || m_patternInfo->IsIdle() == false || m_grainLine->IsIdle() == false)
+    {
+        painter->save();
+        painter->setPen(QPen(Qt::black, 3, Qt::DashLine));
+        painter->drawRect(boundingRect().adjusted(1, 1, -1, -1));
+        painter->restore();
+    }
+    QGraphicsPathItem::paint(painter, option, widget);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::AddToFile()
+{
+    const VPiece piece = VAbstractTool::data.GetPiece(id);
+
+    QDomElement domElement = doc->createElement(getTagName());
+
+    AddAttributes(doc, domElement, id, piece);
+    AddPatternPieceData(doc, domElement, piece);
+    AddPatternInfo(doc, domElement, piece);
+    AddGrainline(doc, domElement, piece);
+
+    // nodes
+    AddNodes(doc, domElement, piece);
+    //custom seam allowance
+    AddCSARecords(doc, domElement, piece.GetCustomSARecords());
+    AddInternalPaths(doc, domElement, piece.GetInternalPaths());
+
+    AddPiece *addDet = new AddPiece(domElement, doc, piece, m_drawName);
+    connect(addDet, &AddPiece::NeedFullParsing, doc, &VAbstractPattern::NeedFullParsing);
+    qApp->getUndoStack()->push(addDet);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::RefreshDataInFile()
+{
+    QDomElement domElement = doc->elementById(id);
+    if (domElement.isElement())
+    {
+        // Refresh only parts that we possibly need to update
+        {
+            // TODO. Delete if minimal supported version is 0.4.0
+            Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 4, 0),
+                              "Time to refactor the code.");
+
+            const uint version = doc->GetParametrUInt(domElement, VToolSeamAllowance::AttrVersion, "1");
+            if (version == 1)
+            {
+                const VPiece piece = VAbstractTool::data.GetPiece(id);
+
+                doc->SetAttribute(domElement, AttrVersion, QString().setNum(pieceVersion));
+
+                doc->RemoveAllChildren(domElement);//Very important to clear before rewrite
+                AddPatternPieceData(doc, domElement, piece);
+                AddPatternInfo(doc, domElement, piece);
+                AddGrainline(doc, domElement, piece);
+                AddNodes(doc, domElement, piece);
+                AddCSARecords(doc, domElement, piece.GetCustomSARecords());
+                AddInternalPaths(doc, domElement, piece.GetInternalPaths());
+            }
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVariant VToolSeamAllowance::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
+{
+    if (change == ItemPositionChange && scene())
+    {
+        // Each time we move something we call recalculation scene rect. In some cases this can cause moving
+        // objects positions. And this cause infinite redrawing. That's why we wait the finish of saving the last move.
+        static bool changeFinished = true;
+        if (changeFinished)
+        {
+            changeFinished = false;
+
+            // value - this is new position.
+            const QPointF newPos = value.toPointF();
+
+            MovePiece *moveDet = new MovePiece(doc, newPos.x(), newPos.y(), id, scene());
+            connect(moveDet, &MovePiece::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
+            qApp->getUndoStack()->push(moveDet);
+
+            const QList<QGraphicsView *> viewList = scene()->views();
+            if (not viewList.isEmpty())
+            {
+                if (QGraphicsView *view = viewList.at(0))
+                {
+                    const int xmargin = 50;
+                    const int ymargin = 50;
+
+                    const QRectF viewRect = VMainGraphicsView::SceneVisibleArea(view);
+                    const QRectF itemRect = mapToScene(boundingRect()|childrenBoundingRect()).boundingRect();
+
+                    // If item's rect is bigger than view's rect ensureVisible works very unstable.
+                    if (itemRect.height() + 2*ymargin < viewRect.height() &&
+                        itemRect.width() + 2*xmargin < viewRect.width())
+                    {
+                        view->ensureVisible(itemRect, xmargin, ymargin);
+                    }
+                    else
+                    {
+                        // Ensure visible only small rect around a cursor
+                        VMainGraphicsScene *currentScene = qobject_cast<VMainGraphicsScene *>(scene());
+                        SCASSERT(currentScene);
+                        const QPointF cursorPosition = currentScene->getScenePos();
+                        view->ensureVisible(QRectF(cursorPosition.x()-5, cursorPosition.y()-5, 10, 10));
+                    }
+                }
+            }
+            // Don't forget to update geometry, because first change never call full parse
+            VPiece detail = VAbstractTool::data.GetPiece(id);
+            detail.SetMx(newPos.x());
+            detail.SetMy(newPos.y());
+            VAbstractTool::data.UpdatePiece(id, detail);
+
+            RefreshGeometry();
+            changeFinished = true;
+        }
+    }
+
+    if (change == QGraphicsItem::ItemSelectedChange)
+    {
+        if (value == true)
+        {
+            // do stuff if selected
+            this->setFocus();
+        }
+        else
+        {
+            // do stuff if not selected
+        }
+    }
+
+    return QGraphicsPathItem::itemChange(change, value);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+    // Special for not selectable item first need to call standard mousePressEvent then accept event
+    QGraphicsPathItem::mousePressEvent(event);
+
+    // Somehow clicking on notselectable object do not clean previous selections.
+    if (not (flags() & ItemIsSelectable) && scene())
+    {
+        scene()->clearSelection();
+    }
+
+    if (flags() & QGraphicsItem::ItemIsMovable)
+    {
+        if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
+        {
+            SetOverrideCursor(cursorArrowCloseHand, 1, 1);
+        }
+    }
+
+    if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
+    {
+        doc->SelectedDetail(id);
+        emit ChoosedTool(id, SceneObject::Detail);
+    }
+
+    event->accept();// Special for not selectable item first need to call standard mousePressEvent then accept event
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+    if (event->button() == Qt::LeftButton)
+    {
+        //Disable cursor-arrow-closehand
+        RestoreOverrideCursor(cursorArrowCloseHand);
+    }
+    QGraphicsPathItem::mouseReleaseEvent(event);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+    Q_UNUSED(event);
+    if (flags() & QGraphicsItem::ItemIsMovable)
+    {
+        SetOverrideCursor(cursorArrowOpenHand, 1, 1);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+    Q_UNUSED(event);
+    if (flags() & QGraphicsItem::ItemIsMovable)
+    {
+        SetOverrideCursor(cursorArrowOpenHand, 1, 1);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+    Q_UNUSED(event);
+    //Disable cursor-arrow-openhand
+    if (flags() & QGraphicsItem::ItemIsMovable)
+    {
+        RestoreOverrideCursor(cursorArrowOpenHand);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
+{
+    QMenu menu;
+    QAction *actionOption = menu.addAction(QIcon::fromTheme("preferences-other"), tr("Options"));
+
+    QAction *inLayoutOption = menu.addAction(tr("In layout"));
+    inLayoutOption->setCheckable(true);
+    const VPiece detail = VAbstractTool::data.GetPiece(id);
+    inLayoutOption->setChecked(detail.IsInLayout());
+
+    QAction *actionRemove = menu.addAction(QIcon::fromTheme("edit-delete"), tr("Delete"));
+    _referens > 1 ? actionRemove->setEnabled(false) : actionRemove->setEnabled(true);
+
+    QAction *selectedAction = menu.exec(event->screenPos());
+    if (selectedAction == actionOption)
+    {
+        auto *dialog = new DialogSeamAllowance(getData(), id, qApp->getMainWindow());
+        dialog->EnableApply(true);
+        m_dialog = dialog;
+        m_dialog->setModal(true);
+        connect(m_dialog.data(), &DialogTool::DialogClosed, this, &VToolSeamAllowance::FullUpdateFromGuiOk);
+        connect(m_dialog.data(), &DialogTool::DialogApplied, this, &VToolSeamAllowance::FullUpdateFromGuiApply);
+        SetDialog();
+        m_dialog->show();
+    }
+    else if (selectedAction == inLayoutOption)
+    {
+        TogglePieceInLayout *togglePrint = new TogglePieceInLayout(id, selectedAction->isChecked(),
+                                                                   &(VAbstractTool::data), doc);
+        connect(togglePrint, &TogglePieceInLayout::UpdateList, doc, &VAbstractPattern::CheckInLayoutList);
+        qApp->getUndoStack()->push(togglePrint);
+    }
+    else if (selectedAction == actionRemove)
+    {
+        try
+        {
+            DeleteTool();
+        }
+        catch(const VExceptionToolWasDeleted &e)
+        {
+            Q_UNUSED(e);
+            return;//Leave this method immediately!!!
+        }
+        return; //Leave this method immediately after call!!!
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::keyReleaseEvent(QKeyEvent *event)
+{
+    switch (event->key())
+    {
+        case Qt::Key_Delete:
+            try
+            {
+                DeleteTool();
+            }
+            catch(const VExceptionToolWasDeleted &e)
+            {
+                Q_UNUSED(e);
+                return;//Leave this method immediately!!!
+            }
+            break;
+        default:
+            break;
+    }
+
+    QGraphicsPathItem::keyReleaseEvent ( event );
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::SetDialog()
+{
+    SCASSERT(not m_dialog.isNull());
+    DialogSeamAllowance *dialogTool = qobject_cast<DialogSeamAllowance*>(m_dialog);
+    SCASSERT(dialogTool != nullptr);
+    dialogTool->SetPiece(VAbstractTool::data.GetPiece(id));
+    dialogTool->EnableApply(true);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VToolSeamAllowance::VToolSeamAllowance(VAbstractPattern *doc, VContainer *data, const quint32 &id,
+                                       const Source &typeCreation, VMainGraphicsScene *scene,
+                                       const QString &drawName, QGraphicsItem *parent)
+    : VAbstractTool(doc, data, id),
+      QGraphicsPathItem(parent),
+      m_dialog(),
+      m_sceneDetails(scene),
+      m_drawName(drawName),
+      m_seamAllowance(new VNoBrushScalePathItem(this)),
+      m_dataLabel(new VTextGraphicsItem(this)),
+      m_patternInfo(new VTextGraphicsItem(this)),
+      m_grainLine(new VGrainlineItem(this))
+{
+    VPiece detail = data->GetPiece(id);
+    InitNodes(detail, scene);
+    InitCSAPaths(detail);
+    InitInternalPaths(detail);
+    this->setFlag(QGraphicsItem::ItemIsMovable, true);
+    this->setFlag(QGraphicsItem::ItemIsSelectable, true);
+    RefreshGeometry();
+
+    m_seamAllowance->setBrush(QBrush(Qt::FDiagPattern));
+
+    this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
+    this->setFlag(QGraphicsItem::ItemIsFocusable, true);// For keyboard input focus
+
+    connect(scene, &VMainGraphicsScene::EnableToolMove, this, &VToolSeamAllowance::EnableToolMove);
+    connect(scene, &VMainGraphicsScene::ItemClicked, this, &VToolSeamAllowance::ResetChildren);
+    ToolCreation(typeCreation);
+    setAcceptHoverEvents(true);
+
+    connect(m_dataLabel, &VTextGraphicsItem::SignalMoved, this, &VToolSeamAllowance::SaveMoveDetail);
+    connect(m_dataLabel, &VTextGraphicsItem::SignalResized, this, &VToolSeamAllowance::SaveResizeDetail);
+    connect(m_dataLabel, &VTextGraphicsItem::SignalRotated, this, &VToolSeamAllowance::SaveRotationDetail);
+
+    connect(m_patternInfo, &VTextGraphicsItem::SignalMoved, this, &VToolSeamAllowance::SaveMovePattern);
+    connect(m_patternInfo, &VTextGraphicsItem::SignalResized, this, &VToolSeamAllowance::SaveResizePattern);
+    connect(m_patternInfo, &VTextGraphicsItem::SignalRotated, this, &VToolSeamAllowance::SaveRotationPattern);
+
+    connect(m_grainLine, &VGrainlineItem::SignalMoved, this, &VToolSeamAllowance::SaveMoveGrainline);
+    connect(m_grainLine, &VGrainlineItem::SignalResized, this, &VToolSeamAllowance::SaveResizeGrainline);
+    connect(m_grainLine, &VGrainlineItem::SignalRotated, this, &VToolSeamAllowance::SaveRotateGrainline);
+
+    connect(doc, &VAbstractPattern::patternChanged, this, &VToolSeamAllowance::UpdatePatternInfo);
+    connect(doc, &VAbstractPattern::CheckLayout, this, &VToolSeamAllowance::UpdateLabel);
+    connect(doc, &VAbstractPattern::CheckLayout, this, &VToolSeamAllowance::UpdatePatternInfo);
+    connect(doc, &VAbstractPattern::CheckLayout, this, &VToolSeamAllowance::UpdateGrainline);
+
+    connect(m_sceneDetails, &VMainGraphicsScene::DimensionsChanged, this, &VToolSeamAllowance::UpdateLabel);
+    connect(m_sceneDetails, &VMainGraphicsScene::DimensionsChanged, this, &VToolSeamAllowance::UpdatePatternInfo);
+    connect(m_sceneDetails, &VMainGraphicsScene::LanguageChanged, this, &VToolSeamAllowance::retranslateUi);
+
+    UpdateLabel();
+    UpdatePatternInfo();
+    UpdateGrainline();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::RefreshGeometry()
+{
+    this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
+
+    const VPiece detail = VAbstractTool::data.GetPiece(id);
+    QPainterPath mainPath = detail.MainPathPath(this->getData());
+    this->setPath(mainPath);
+    this->setPos(detail.GetMx(), detail.GetMy());
+
+    if (detail.IsSeamAllowance())
+    {
+        mainPath.addPath(detail.SeamAllowancePath(this->getData()));
+        mainPath.setFillRule(Qt::OddEvenFill);
+        m_seamAllowance->setPath(mainPath);
+    }
+    else
+    {
+        m_seamAllowance->setPath(QPainterPath());
+    }
+
+    this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::SaveDialogChange()
+{
+    SCASSERT(not m_dialog.isNull());
+    DialogSeamAllowance *dialogTool = qobject_cast<DialogSeamAllowance*>(m_dialog.data());
+    SCASSERT(dialogTool != nullptr);
+    const VPiece newDet = dialogTool->GetPiece();
+    const VPiece oldDet = VAbstractTool::data.GetPiece(id);
+
+    SavePieceOptions *saveCommand = new SavePieceOptions(oldDet, newDet, doc, id);
+    connect(saveCommand, &SavePieceOptions::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
+    qApp->getUndoStack()->push(saveCommand);
+    UpdateLabel();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::InitNodes(const VPiece &detail, VMainGraphicsScene *scene)
+{
+    for (int i = 0; i< detail.GetPath().CountNodes(); ++i)
+    {
+        switch (detail.GetPath().at(i).GetTypeTool())
+        {
+            case (Tool::NodePoint):
+            {
+                VNodePoint *tool = InitTool<VNodePoint>(scene, detail.GetPath().at(i).GetId());
+                connect(tool, &VNodePoint::ShowContextMenu, this, &VToolSeamAllowance::contextMenuEvent);
+                break;
+            }
+            case (Tool::NodeArc):
+            case (Tool::NodeElArc):
+            case (Tool::NodeSpline):
+            case (Tool::NodeSplinePath):
+                doc->IncrementReferens(VAbstractTool::data.GetGObject(detail.GetPath().at(i).GetId())->getIdTool());
+                break;
+            default:
+                qDebug()<<"Get wrong tool type. Ignore.";
+                break;
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::InitCSAPaths(const VPiece &detail)
+{
+    QVector<CustomSARecord> records = detail.GetCustomSARecords();
+    for (int i = 0; i < records.size(); ++i)
+    {
+        doc->IncrementReferens(records.at(i).path);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::InitInternalPaths(const VPiece &detail)
+{
+    QVector<quint32> records = detail.GetInternalPaths();
+    for (int i = 0; i < records.size(); ++i)
+    {
+        VToolPiecePath *tool = qobject_cast<VToolPiecePath*>(doc->getTool(records.at(i)));
+        SCASSERT(tool != nullptr);
+        tool->setParentItem(this);
+        tool->SetParentType(ParentType::Item);
+        tool->show();
+        doc->IncrementReferens(records.at(i));
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::DeleteTool(bool ask)
+{
+    DeletePiece *delDet = new DeletePiece(doc, id, VAbstractTool::data.GetPiece(id));
+    if (ask)
+    {
+        if (ConfirmDeletion() == QMessageBox::No)
+        {
+            return;
+        }
+        /* If UnionDetails tool delete detail no need emit FullParsing.*/
+        connect(delDet, &DeletePiece::NeedFullParsing, doc, &VAbstractPattern::NeedFullParsing);
+    }
+
+    // If UnionDetails tool delete the detail this object will be deleted only after full parse.
+    // Deleting inside UnionDetails cause crash.
+    // Because this object should be inactive from no one we disconnect all signals that may cause a crash
+    // KEEP THIS LIST ACTUALL!!!
+    disconnect(doc, 0, this, 0);
+    if (QGraphicsScene *toolScene = scene())
+    {
+        disconnect(toolScene, 0, this, 0);
+    }
+    disconnect(m_dataLabel, 0, this, 0);
+    disconnect(m_patternInfo, 0, this, 0);
+    disconnect(m_grainLine, 0, this, 0);
+    disconnect(m_sceneDetails, 0, this, 0);
+
+    hide();// User shouldn't see this object
+
+    qApp->getUndoStack()->push(delDet);
+
+    // Throw exception, this will help prevent case when we forget to immediately quit function.
+    VExceptionToolWasDeleted e("Tool was used after deleting.");
+    throw e;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolSeamAllowance::ToolCreation(const Source &typeCreation)
+{
+    if (typeCreation == Source::FromGui || typeCreation == Source::FromTool)
+    {
+        AddToFile();
+        if (typeCreation != Source::FromTool)
+        {
+            qApp->getUndoStack()->endMacro();
+        }
+    }
+    else
+    {
+        RefreshDataInFile();
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+template <typename Tool>
+/**
+ * @brief InitTool initial node item on scene
+ * @param scene pointer to scene.
+ * @param toolId if of tool object.
+ */
+Tool *VToolSeamAllowance::InitTool(VMainGraphicsScene *scene, quint32 toolId)
+{
+    Tool *tool = qobject_cast<Tool*>(doc->getTool(toolId));
+    SCASSERT(tool != nullptr);
+    connect(tool, &Tool::ChoosedTool, scene, &VMainGraphicsScene::ChoosedItem);
+    tool->setParentItem(this);
+    tool->SetParentType(ParentType::Item);
+    doc->IncrementReferens(toolId);
+    return tool;
+}
diff --git a/src/libs/vtools/tools/vtoolseamallowance.h b/src/libs/vtools/tools/vtoolseamallowance.h
new file mode 100644
index 000000000..304936fd3
--- /dev/null
+++ b/src/libs/vtools/tools/vtoolseamallowance.h
@@ -0,0 +1,159 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   6 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VTOOLSEAMALLOWANCE_H
+#define VTOOLSEAMALLOWANCE_H
+
+#include <QtGlobal>
+#include <qcompilerdetection.h>
+#include <QObject>
+#include <QGraphicsPathItem>
+
+#include "vabstracttool.h"
+#include "../vwidgets/vtextgraphicsitem.h"
+#include "../vwidgets/vgrainlineitem.h"
+
+class VMainGraphicsScene;
+class DialogTool;
+class VPiece;
+class VNoBrushScalePathItem;
+
+class VToolSeamAllowance : public VAbstractTool, public QGraphicsPathItem
+{
+    Q_OBJECT
+public:
+    virtual ~VToolSeamAllowance();
+
+    static VToolSeamAllowance* Create(DialogTool *m_dialog, VMainGraphicsScene *scene, VAbstractPattern *doc,
+                                      VContainer *data);
+    static VToolSeamAllowance* Create(quint32 id, VPiece newPiece, QString &width, VMainGraphicsScene *scene,
+                                      VAbstractPattern *doc, VContainer *data, const Document &parse,
+                                      const Source &typeCreation, const QString &m_drawName = QString());
+
+    static const quint8 pieceVersion;
+
+    static const QString TagCSA;
+    static const QString TagRecord;
+    static const QString TagIPaths;
+
+    static const QString AttrVersion;
+    static const QString AttrForbidFlipping;
+    static const QString AttrSeamAllowance;
+    static const QString AttrHeight;
+    static const QString AttrUnited;
+    static const QString AttrFont;
+
+    void Remove(bool ask);
+
+    static void AddAttributes(VAbstractPattern *doc, QDomElement &domElement, quint32 id, const VPiece &piece);
+    static void AddCSARecord(VAbstractPattern *doc, QDomElement &domElement, const CustomSARecord &record);
+    static void AddCSARecords(VAbstractPattern *doc, QDomElement &domElement, const QVector<CustomSARecord> &records);
+    static void AddInternalPaths(VAbstractPattern *doc, QDomElement &domElement, const QVector<quint32> &paths);
+    static void AddPatternPieceData(VAbstractPattern *doc, QDomElement &domElement, const VPiece &piece);
+    static void AddPatternInfo(VAbstractPattern *doc, QDomElement &domElement, const VPiece &piece);
+    static void AddGrainline(VAbstractPattern *doc, QDomElement &domElement, const VPiece &piece);
+
+    virtual int        type() const Q_DECL_OVERRIDE {return Type;}
+    enum { Type = UserType + static_cast<int>(Tool::Piece)};
+
+    virtual QString    getTagName() const Q_DECL_OVERRIDE;
+    virtual void       ShowVisualization(bool show) Q_DECL_OVERRIDE;
+    virtual void       GroupVisibility(quint32 object, bool visible) Q_DECL_OVERRIDE;
+public slots:
+    virtual void FullUpdateFromFile () Q_DECL_OVERRIDE;
+    virtual void FullUpdateFromGuiOk(int result);
+    void         FullUpdateFromGuiApply();
+    void         EnableToolMove(bool move);
+    virtual void AllowHover(bool enabled) Q_DECL_OVERRIDE;
+    virtual void AllowSelecting(bool enabled) Q_DECL_OVERRIDE;
+    virtual void ResetChildren(QGraphicsItem* pItem);
+    virtual void UpdateAll();
+    virtual void retranslateUi();
+    void         Highlight(quint32 id);
+protected slots:
+    virtual void UpdateLabel();
+    virtual void UpdatePatternInfo();
+    virtual void UpdateGrainline();
+    virtual void SaveMoveDetail(const QPointF &ptPos);
+    virtual void SaveResizeDetail(qreal dLabelW, int iFontSize);
+    virtual void SaveRotationDetail(qreal dRot);
+    virtual void SaveMovePattern(const QPointF& ptPos);
+    virtual void SaveResizePattern(qreal dLabelW, int iFontSize);
+    virtual void SaveRotationPattern(qreal dRot);
+    virtual void SaveMoveGrainline(const QPointF& ptPos);
+    virtual void SaveResizeGrainline(qreal dLength);
+    virtual void SaveRotateGrainline(qreal dRot, const QPointF& ptPos);
+protected:
+    virtual void       paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+                             QWidget *widget) Q_DECL_OVERRIDE;
+    virtual void       AddToFile () Q_DECL_OVERRIDE;
+    virtual void       RefreshDataInFile() Q_DECL_OVERRIDE;
+    virtual QVariant   itemChange ( GraphicsItemChange change, const QVariant &value ) Q_DECL_OVERRIDE;
+    virtual void       mousePressEvent( QGraphicsSceneMouseEvent * event) Q_DECL_OVERRIDE;
+    virtual void       mouseReleaseEvent ( QGraphicsSceneMouseEvent * event ) Q_DECL_OVERRIDE;
+    virtual void       hoverMoveEvent( QGraphicsSceneHoverEvent * event ) Q_DECL_OVERRIDE;
+    virtual void       hoverEnterEvent ( QGraphicsSceneHoverEvent * event ) Q_DECL_OVERRIDE;
+    virtual void       hoverLeaveEvent ( QGraphicsSceneHoverEvent * event ) Q_DECL_OVERRIDE;
+    virtual void       contextMenuEvent ( QGraphicsSceneContextMenuEvent * event ) Q_DECL_OVERRIDE;
+    virtual void       keyReleaseEvent(QKeyEvent * event) Q_DECL_OVERRIDE;
+    virtual void       SetVisualization() Q_DECL_OVERRIDE {}
+    virtual void       DeleteTool(bool ask = true) Q_DECL_OVERRIDE;
+    virtual void       ToolCreation(const Source &typeCreation) Q_DECL_OVERRIDE;
+
+private:
+    Q_DISABLE_COPY(VToolSeamAllowance)
+
+    /** @brief dialog dialog options. */
+    QPointer<DialogTool> m_dialog;
+
+    /** @brief sceneDetails pointer to the scene. */
+    VMainGraphicsScene *m_sceneDetails;
+    QString             m_drawName;
+
+    VNoBrushScalePathItem *m_seamAllowance;
+    VTextGraphicsItem     *m_dataLabel;
+    VTextGraphicsItem     *m_patternInfo;
+    VGrainlineItem        *m_grainLine;
+
+    void SetDialog();
+
+    VToolSeamAllowance(VAbstractPattern *doc, VContainer *data, const quint32 &id, const Source &typeCreation,
+                       VMainGraphicsScene *scene, const QString &m_drawName, QGraphicsItem * parent = nullptr);
+
+    void RefreshGeometry();
+    void SaveDialogChange();
+
+    void InitNodes(const VPiece &detail, VMainGraphicsScene *scene);
+    void InitCSAPaths(const VPiece &detail);
+    void InitInternalPaths(const VPiece &detail);
+
+    template <typename Tool>
+    Tool*              InitTool(VMainGraphicsScene *scene, quint32 toolId);
+};
+
+#endif // VTOOLSEAMALLOWANCE_H
diff --git a/src/libs/vtools/tools/vtooluniondetails.cpp b/src/libs/vtools/tools/vtooluniondetails.cpp
index fc1b961ef..b2ebddbfc 100644
--- a/src/libs/vtools/tools/vtooluniondetails.cpp
+++ b/src/libs/vtools/tools/vtooluniondetails.cpp
@@ -58,15 +58,18 @@
 #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 "nodeDetails/vtoolpiecepath.h"
 #include "vdatatool.h"
 #include "vnodedetail.h"
-#include "vtooldetail.h"
+#include "vtoolseamallowance.h"
 
 class QDomElement;
 class QDomNode;
@@ -92,1045 +95,115 @@ Q_LOGGING_CATEGORY(vToolUnion, "v.toolUnion")
 
 QT_WARNING_POP
 
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VToolUnionDetails costructor.
- * @param doc dom document container.
- * @param data dom document container.
- * @param id object id in container.
- * @param d1 first detail.
- * @param d2 second detail.
- * @param indexD1 index edge in first detail.
- * @param indexD2 index edge in second detail.
- * @param typeCreation way we create this tool.
- * @param parent parent object.
- */
-VToolUnionDetails::VToolUnionDetails(VAbstractPattern *doc, VContainer *data, const quint32 &id, const VDetail &d1,
-                                     const VDetail &d2, const quint32 &indexD1, const quint32 &indexD2,
-                                     const Source &typeCreation, const QString &drawName, QObject *parent)
-    :VAbstractTool(doc, data, id, parent), d1(d1), d2(d2), indexD1(indexD1), indexD2(indexD2), drawName(drawName)
+namespace
 {
-    _referens = 0;
-    ToolCreation(typeCreation);
-}
-
 //---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief AddToNewDetail create united detail adding one node per time.
- * @param doc dom document container.
- * @param data container with variables.
- * @param newDetail united detail.
- * @param det detail what we union.
- * @param i index node in detail.
- * @param idTool id tool union details.
- * @param children list of children
- * @param drawName name of pattern piece
- * @param dx bias node x axis.
- * @param dy bias node y axis.
- * @param pRotate point rotation.
- * @param angle angle rotation.
- */
-void VToolUnionDetails::AddToNewDetail(VMainGraphicsScene *scene, VAbstractPattern *doc,
-                                       VContainer *data, VDetail &newDetail, const VDetail &det, const int &i,
-                                       const quint32 &idTool, QVector<quint32> &children, const QString &drawName,
-                                       const qreal &dx, const qreal &dy, const quint32 &pRotate, const qreal &angle)
+VPiecePath GetPiecePath(int piece, VAbstractPattern *doc, quint32 id)
 {
-    quint32 id = 0, idObject = 0;
-    switch (det.at(i).getTypeTool())
+    const QDomElement tool = doc->elementById(id);
+    if (tool.isNull())
     {
-        case (Tool::NodePoint):
+        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 && i+1 == piece)
         {
-            VPointF *point = new VPointF(*data->GeometricObject<VPointF>(det.at(i).getId()));
-            point->setMode(Draw::Modeling);
-
-            if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
+            const QDomNodeList detList = element.childNodes();
+            for (qint32 j = 0; j < detList.size(); ++j)
             {
-                BiasRotatePoint(point, dx, dy, *data->GeometricObject<VPointF>(pRotate), angle);
-            }
-
-            idObject = data->AddGObject(point);
-            children.append(idObject);
-            VPointF *point1 = new VPointF(*point);
-            point1->setMode(Draw::Modeling);
-            id = data->AddGObject(point1);
-            VNodePoint::Create(doc, data, scene, id, idObject, Document::FullParse, Source::FromGui, drawName, idTool);
-        }
-        break;
-        case (Tool::NodeArc):
-        {
-            const QSharedPointer<VArc> arc = data->GeometricObject<VArc>(det.at(i).getId());
-            VPointF p1 = VPointF(arc->GetP1(), "A", 0, 0);
-            VPointF p2 = VPointF(arc->GetP2(), "A", 0, 0);
-            VPointF *center = new VPointF(arc->GetCenter());
-
-            if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
-            {
-                const QPointF p = *data->GeometricObject<VPointF>(pRotate);
-
-                BiasRotatePoint(&p1, dx, dy, p, angle);
-                BiasRotatePoint(&p2, dx, dy, p, angle);
-                BiasRotatePoint(center, dx, dy, p, angle);
-            }
-
-            QLineF l1(*center, p1);
-            QLineF l2(*center, p2);
-            center->setMode(Draw::Modeling);
-            quint32 idCenter = data->AddGObject(center);
-            Q_UNUSED(idCenter)
-            VArc *arc1 = new VArc(*center, arc->GetRadius(), arc->GetFormulaRadius(), l1.angle(),
-                                  QString().setNum(l1.angle()), l2.angle(), QString().setNum(l2.angle()));
-            arc1->setMode(Draw::Modeling);
-            idObject = data->AddGObject(arc1);
-            children.append(idObject);
-
-            VArc *arc2 = new VArc(*arc1);
-            arc2->setMode(Draw::Modeling);
-            id = data->AddGObject(arc2);
-
-            VNodeArc::Create(doc, data, id, idObject, Document::FullParse, Source::FromGui, drawName, idTool);
-        }
-        break;
-        case (Tool::NodeElArc):
-        {
-            const QSharedPointer<VEllipticalArc> arc = data->GeometricObject<VEllipticalArc>(det.at(i).getId());
-            VPointF p1 = VPointF(arc->GetP1(), "A", 0, 0);
-            VPointF p2 = VPointF(arc->GetP2(), "A", 0, 0);
-            VPointF *center = new VPointF(arc->GetCenter());
-
-            if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
-            {
-                const QPointF p = *data->GeometricObject<VPointF>(pRotate);
-
-                BiasRotatePoint(&p1, dx, dy, p, angle);
-                BiasRotatePoint(&p2, dx, dy, p, angle);
-                BiasRotatePoint(center, dx, dy, p, angle);
-            }
-
-            QLineF l1(*center, p1);
-            QLineF l2(*center, p2);
-            center->setMode(Draw::Modeling);
-            quint32 idCenter = data->AddGObject(center);
-            Q_UNUSED(idCenter)
-            VEllipticalArc *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);
-            idObject = data->AddGObject(arc1);
-            children.append(idObject);
-
-            VEllipticalArc *arc2 = new VEllipticalArc(*arc1);
-            arc2->setMode(Draw::Modeling);
-            id = data->AddGObject(arc2);
-
-            VNodeEllipticalArc::Create(doc, data, id, idObject, Document::FullParse, Source::FromGui, drawName, idTool);
-        }
-        break;
-        case (Tool::NodeSpline):
-        {
-            const QSharedPointer<VAbstractCubicBezier> spline =
-                    data->GeometricObject<VAbstractCubicBezier>(det.at(i).getId());
-
-            QScopedPointer<VPointF> p1(new VPointF(spline->GetP1()));
-            VPointF p2 = VPointF(spline->GetP2());
-            VPointF p3 = VPointF(spline->GetP3());
-            QScopedPointer<VPointF> p4(new VPointF(spline->GetP4()));
-
-            if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
-            {
-                const QPointF p = *data->GeometricObject<VPointF>(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);
-            idObject = data->AddGObject(spl);
-            children.append(idObject);
-
-            VSpline *spl1 = new VSpline(*spl);
-            spl1->setMode(Draw::Modeling);
-            id = data->AddGObject(spl1);
-            VNodeSpline::Create(doc, data, id, idObject, Document::FullParse, Source::FromGui, drawName, idTool);
-        }
-        break;
-        case (Tool::NodeSplinePath):
-        {
-            VSplinePath *path = new VSplinePath();
-            path->setMode(Draw::Modeling);
-            const QSharedPointer<VAbstractCubicBezierPath> splinePath =
-                    data->GeometricObject<VAbstractCubicBezierPath>(det.at(i).getId());
-            for (qint32 i = 1; i <= splinePath->CountSubSpl(); ++i)
-            {
-                const VSpline spline = splinePath->GetSpline(i);
-
-                VPointF *p1 = new VPointF(spline.GetP1());
-                VPointF p2 = VPointF(spline.GetP2());
-                VPointF p3 = VPointF(spline.GetP3());
-                VPointF *p4 = new VPointF(spline.GetP4());
-                if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
+                const QDomElement element = detList.at(j).toElement();
+                if (not element.isNull() && element.tagName() == VAbstractPattern::TagNodes)
                 {
-                    const QPointF p = *data->GeometricObject<VPointF>(pRotate);
-
-                    BiasRotatePoint(p1, dx, dy, p, angle);
-                    BiasRotatePoint(&p2, dx, dy, p, angle);
-                    BiasRotatePoint(&p3, dx, dy, p, angle);
-                    BiasRotatePoint(p4, 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));
-
-                delete p4;
-                delete p1;
-            }
-            idObject = data->AddGObject(path);
-            children.append(idObject);
-
-            VSplinePath *path1 = new VSplinePath(*path);
-            path1->setMode(Draw::Modeling);
-            id = data->AddGObject(path1);
-            VNodeSplinePath::Create(doc, data, id, idObject, Document::FullParse, Source::FromGui, drawName, idTool);
-        }
-        break;
-        default:
-            qDebug()<<"May be wrong tool type!!! Ignoring."<<Q_FUNC_INFO;
-            break;
-    }
-    newDetail.append(VNodeDetail(id, det.at(i).getTypeTool(), NodeDetail::Contour, 0, 0, det.at(i).getReverse()));
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief UpdatePoints update data for united details.
- * @param data container with variables.
- * @param det detail what we union.
- * @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 VToolUnionDetails::UpdatePoints(VContainer *data, const VDetail &det, const int &i,
-                                     QVector<quint32> &children, const qreal &dx, const qreal &dy,
-                                     const quint32 &pRotate,
-                                     const qreal &angle)
-{
-    switch (det.at(i).getTypeTool())
-    {
-        case (Tool::NodePoint):
-        {
-            VPointF *point = new VPointF(*data->GeometricObject<VPointF>(det.at(i).getId()));
-            point->setMode(Draw::Modeling);
-            if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
-            {
-                BiasRotatePoint(point, dx, dy, *data->GeometricObject<VPointF>(pRotate), angle);
-            }
-            data->UpdateGObject(TakeNextId(children), point);
-        }
-        break;
-        case (Tool::NodeArc):
-        {
-            const QSharedPointer<VArc> arc = data->GeometricObject<VArc>(det.at(i).getId());
-            VPointF p1 = VPointF(arc->GetP1());
-            VPointF p2 = VPointF(arc->GetP2());
-            QScopedPointer<VPointF> center(new VPointF(arc->GetCenter()));
-
-            if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
-            {
-                const QPointF p = *data->GeometricObject<VPointF>(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);
-
-            VArc *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);
-        }
-        break;
-        case (Tool::NodeElArc):
-        {
-            const QSharedPointer<VEllipticalArc> arc = data->GeometricObject<VEllipticalArc>(det.at(i).getId());
-            VPointF p1 = VPointF(arc->GetP1());
-            VPointF p2 = VPointF(arc->GetP2());
-            QScopedPointer<VPointF> center(new VPointF(arc->GetCenter()));
-
-            if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
-            {
-                const QPointF p = *data->GeometricObject<VPointF>(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);
-
-            VEllipticalArc *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);
-        }
-        break;
-        case (Tool::NodeSpline):
-        {
-            const QSharedPointer<VAbstractCubicBezier> spline =
-                    data->GeometricObject<VAbstractCubicBezier>(det.at(i).getId());
-
-            QScopedPointer<VPointF> p1(new VPointF(spline->GetP1()));
-            VPointF p2 = VPointF(spline->GetP2());
-            VPointF p3 = VPointF(spline->GetP3());
-            QScopedPointer<VPointF> p4(new VPointF(spline->GetP4()));
-
-            if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
-            {
-                const QPointF p = *data->GeometricObject<VPointF>(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);
-            data->UpdateGObject(TakeNextId(children), spl);
-        }
-        break;
-        case (Tool::NodeSplinePath):
-        {
-            VSplinePath *path = new VSplinePath();
-            path->setMode(Draw::Modeling);
-            const QSharedPointer<VAbstractCubicBezierPath> splinePath =
-                    data->GeometricObject<VAbstractCubicBezierPath>(det.at(i).getId());
-            SCASSERT(splinePath != nullptr)
-            for (qint32 i = 1; i <= splinePath->CountSubSpl(); ++i)
-            {
-                const VSpline spline = splinePath->GetSpline(i);
-
-                QScopedPointer<VPointF> p1(new VPointF(spline.GetP1()));
-                VPointF p2 = VPointF(spline.GetP2());
-                VPointF p3 = VPointF(spline.GetP3());
-                QScopedPointer<VPointF> p4(new VPointF(spline.GetP4()));
-
-                if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
-                {
-                    const QPointF p = *data->GeometricObject<VPointF>(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);
-        }
-        break;
-        default:
-            qDebug()<<"May be wrong tool type!!! Ignoring."<<Q_FUNC_INFO;
-            break;
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @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 VToolUnionDetails::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());
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QString VToolUnionDetails::getTagName() const
-{
-    return VAbstractPattern::TagTools;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolUnionDetails::ShowVisualization(bool show)
-{
-    Q_UNUSED(show)
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolUnionDetails::incrementReferens()
-{
-    ++_referens;
-    if (_referens == 1)
-    {
-        IncrementReferences(d1);
-        IncrementReferences(d2);
-
-        QDomElement domElement = doc->elementById(id);
-        if (domElement.isElement())
-        {
-            doc->SetParametrUsage(domElement, AttrInUse, NodeUsage::InUse);
-        }
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolUnionDetails::decrementReferens()
-{
-    if (_referens > 0)
-    {
-        --_referens;
-    }
-    if (_referens == 0)
-    {
-        DecrementReferences(d1);
-        DecrementReferences(d2);
-
-        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)
-    DialogUnionDetails *dialogTool = qobject_cast<DialogUnionDetails*>(dialog);
-    SCASSERT(dialogTool != nullptr)
-    VDetail d1 = data->GetDetail(dialogTool->getD1());
-    VDetail d2 = data->GetDetail(dialogTool->getD2());
-    quint32 indexD1 = static_cast<quint32>(dialogTool->getIndexD1());
-    quint32 indexD2 = static_cast<quint32>(dialogTool->getIndexD2());
-    const bool retainPieces = dialogTool->RetainPieces();
-    qApp->getUndoStack()->beginMacro(tr("union details"));
-    VToolUnionDetails* tool = Create(0, d1, d2, dialogTool->getD1(), dialogTool->getD2(), indexD1, indexD2, scene,
-                                     doc, data, Document::FullParse, Source::FromGui, retainPieces);
-    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 VDetail &d1, const VDetail &d2,
-                                             const quint32 &d1id, const quint32 &d2id, const quint32 &indexD1,
-                                             const quint32 &indexD2, VMainGraphicsScene *scene, VAbstractPattern *doc,
-                                             VContainer *data, const Document &parse, const Source &typeCreation,
-                                             bool retainPieces)
-{
-    VToolUnionDetails *unionDetails = nullptr;
-    quint32 id = _id;
-    QString drawName;
-    if (typeCreation == Source::FromGui)
-    {
-        id = data->getNextId();
-        drawName = DrawName(doc, d1id, d2id);
-        SCASSERT(not drawName.isEmpty())
-    }
-    else
-    {
-        if (parse != Document::FullParse)
-        {
-            doc->UpdateToolData(id, data);
-        }
-    }
-
-    //First add tool to file
-    VAbstractTool::AddRecord(id, Tool::UnionDetails, doc);
-    if (parse == Document::FullParse)
-    {
-        //Scene doesn't show this tool, so doc will destroy this object.
-        unionDetails = new VToolUnionDetails(doc, data, id, d1, d2, indexD1, indexD2, typeCreation, drawName, doc);
-        doc->AddTool(id, unionDetails);
-        // Unfortunatelly doc will destroy all objects only in the end, but we should delete them before each FullParse
-        doc->AddToolOnRemove(unionDetails);
-    }
-    //Then create new details
-    VNodeDetail det1p1;
-    VNodeDetail det1p2;
-    d1.NodeOnEdge(indexD1, det1p1, det1p2);
-    Q_UNUSED(det1p2)
-
-    VPointF point1;
-    VPointF point2;
-    PointsOnEdge(d1, indexD1, point1, point2, data);
-
-    VPointF point3;
-    VPointF point4;
-    PointsOnEdge(d2, indexD2, point3, point4, data);
-
-    const qreal dx = point1.x() - point4.x();
-    const qreal 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);
-
-    const qreal angle = p4p3.angleTo(p1p2);
-    qint32 pointsD2 = 0; //Keeps number points the second detail, what we have already added.
-
-    const qint32 countNodeD1 = d1.RemoveEdge(indexD1).CountNode();
-    const qint32 countNodeD2 = d2.RemoveEdge(indexD2).CountNode();
-
-    if (typeCreation == Source::FromGui)
-    {
-        qint32 i = 0;
-        VDetail newDetail;
-        QVector<quint32> children;
-        do
-        {
-            AddToNewDetail(scene, doc, data, newDetail, d1.RemoveEdge(indexD1), i, id, children, drawName);
-            ++i;
-            if (i > d1.indexOfNode(det1p1.getId()) && pointsD2 < countNodeD2-1)
-            {
-                qint32 j = 0;
-                FindIndexJ(pointsD2, d2, indexD2, j);
-                do
-                {
-                    if (j >= countNodeD2)
-                    {
-                        j=0;
-                    }
-                    AddToNewDetail(scene, doc, data, newDetail, d2.RemoveEdge(indexD2), j, id, children, drawName,
-                                   dx, dy, det1p1.getId(), angle);
-                    ++pointsD2;
-                    ++j;
-                } while (pointsD2 < countNodeD2-1);
-            }
-        } while (i < countNodeD1);
-
-        newDetail.setName(tr("United detail"));
-        newDetail.setWidth(d1.getWidth());
-        newDetail.setMx(d1.getMx());
-        newDetail.setMy(d1.getMy());
-        VToolDetail::Create(0, newDetail, scene, doc, data, parse, Source::FromTool, drawName);
-        QHash<quint32, VDataTool*>* tools = doc->getTools();
-        SCASSERT(tools != nullptr)
-
-        if (not retainPieces)
-        {
-            {
-                VToolDetail *toolDet = qobject_cast<VToolDetail*>(tools->value(d1id));
-                SCASSERT(toolDet != nullptr)
-                bool ask = false;
-                toolDet->Remove(ask);
-            }
-
-            {
-                VToolDetail *toolDet = qobject_cast<VToolDetail*>(tools->value(d2id));
-                SCASSERT(toolDet != nullptr)
-                const bool ask = false;
-                toolDet->Remove(ask);
-            }
-        }
-
-        SCASSERT(not children.isEmpty())
-        SaveChildren(doc, id, children);
-    }
-    else
-    {
-        QVector<quint32> children = AllChildren(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;
-                do
-                {
-                    UpdatePoints(data, d1.RemoveEdge(indexD1), i, children);
-                    ++i;
-                    if (i > d1.indexOfNode(det1p1.getId()) && pointsD2 < countNodeD2-1)
-                    {
-                        VDetail d2REdge = d2.RemoveEdge(indexD2);
-                        qint32 j = 0;
-                        FindIndexJ(pointsD2, d2, indexD2, j);
-                        do
-                        {
-                            if (j >= countNodeD2)
-                            {
-                                j=0;
-                            }
-                            UpdatePoints(data, d2REdge, j, children, dx, dy, det1p1.getId(), angle);
-                            ++pointsD2;
-                            ++j;
-                        } while (pointsD2 < countNodeD2-1);
-                    }
-                } while (i<countNodeD1);
-            }
-            else // remove if min version is 0.3.2
-            {
-                qint32 i = 0;
-                do
-                {
-                    ++i;
-                    if (i > d1.indexOfNode(det1p1.getId()))
-                    {
-                        const int childrenCount = children.size();
-                        VDetail d2REdge = d2.RemoveEdge(indexD2);
-                        qint32 j = 0;
-                        FindIndexJ(pointsD2, d2, indexD2, j);
-                        do
-                        {
-                            if (j >= countNodeD2)
-                            {
-                                j=0;
-                            }
-                            UpdatePoints(data, d2REdge, j, children, dx, dy, det1p1.getId(), angle);
-                            ++pointsD2;
-                            ++j;
-                        } while (pointsD2 < childrenCount);
-                        break;
-                    }
-                } while (i<countNodeD1);
-            }
-        }
-    }
-    return unionDetails;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolUnionDetails::PointsOnEdge(const VDetail &d, const quint32 &index, VPointF &p1, VPointF &p2, VContainer *data)
-{
-    VNodeDetail det2p1;
-    VNodeDetail det2p2;
-    d.NodeOnEdge(index, det2p1, det2p2);
-    p1 = VPointF(*data->GeometricObject<VPointF>(det2p1.getId()));
-    p2 = VPointF(*data->GeometricObject<VPointF>(det2p2.getId()));
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VToolUnionDetails::FindIndexJ(const qint32 &pointsD2, const VDetail &d2, const quint32 &indexD2, qint32 &j)
-{
-    if (pointsD2 == 0)
-    {
-        VNodeDetail node1;
-        VNodeDetail node2;
-        d2.NodeOnEdge(indexD2, node1, node2);
-        const VDetail removedD2 = d2.RemoveEdge(indexD2);
-        const int k = removedD2.indexOfNode(node2.getId());
-        SCASSERT(k != -1)
-        if (k == removedD2.CountNode()-1)
-        {//We have last node in detail, we wil begin from 0
-            j = 0;
-        }
-        else
-        {// Continue from next node
-            j = k+1;
-        }
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief GetDetailFromFile parse detail from file.
- * @param doc dom document container.
- * @param domElement tag in xml tree.
- * @return detail stored in file.
- */
-QVector<VDetail> VToolUnionDetails::GetDetailFromFile(VAbstractPattern *doc, const QDomElement &domElement)
-{
-    QVector<VDetail> vector;
-    QDomNodeList detailList = domElement.childNodes();
-    qint32 num = detailList.size();
-    for (qint32 i = 0; i < num; ++i)
-    {
-        QDomElement element = detailList.at(i).toElement();
-        if (element.isNull() == false)
-        {
-            if (element.tagName() == VToolUnionDetails::TagDetail)
-            {
-                VDetail d;
-                QDomNodeList nodeList = element.childNodes();
-                qint32 num = nodeList.size();
-                for (qint32 j = 0; j < num; ++j)
-                {
-                    QDomElement element = nodeList.at(j).toElement();
-                    if (element.isNull() == false)
-                    {
-                        if (element.tagName() == VToolUnionDetails::TagNode)
-                        {
-                            quint32 id = doc->GetParametrUInt(element, AttrIdObject, NULL_ID_STR);
-                            qreal mx = qApp->toPixel(doc->GetParametrDouble(element, AttrMx, "0.0"));
-                            qreal my = qApp->toPixel(doc->GetParametrDouble(element, 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");
-                            if (t == QLatin1String("NodePoint"))
-                            {
-                                tool = Tool::NodePoint;
-                            }
-                            else if (t == QLatin1String("NodeArc"))
-                            {
-                                tool = Tool::NodeArc;
-                            }
-                            else if (t == QLatin1String("NodeElArc"))
-                            {
-                                tool = Tool::NodeElArc;
-                            }
-                            else if (t == QLatin1String("NodeSpline"))
-                            {
-                                tool = Tool::NodeSpline;
-                            }
-                            else if (t == QLatin1String("NodeSplinePath"))
-                            {
-                                tool = Tool::NodeSplinePath;
-                            }
-                            d.append(VNodeDetail(id, tool, nodeType, mx, my, reversed));
-                        }
-                    }
-                }
-                vector.append(d);
-            }
-        }
-    }
-    return vector;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @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, d1);
-    AddDetail(domElement, d2);
-
-    AddToModeling(domElement);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief RefreshDataInFile refresh attributes in file. If attributes don't exist create them.
- */
-void VToolUnionDetails::RefreshDataInFile()
-{
-    QDomElement domElement = doc->elementById(id);
-    if (domElement.isElement())
-    {
-        doc->SetAttribute(domElement, AttrIndexD1, indexD1);
-        doc->SetAttribute(domElement, AttrIndexD2, indexD2);
-
-        QDomNode domNode = domElement.firstChild();
-        domNode = UpdateDetail(domNode, d1);
-        UpdateDetail(domNode, d2);
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief AddDetail add detail to xml file.
- * @param domElement tag in xml tree.
- * @param d detail.
- */
-void VToolUnionDetails::AddDetail(QDomElement &domElement, VDetail &d)
-{
-    QDomElement det = doc->createElement(TagDetail);
-
-    for (int i = 0; i < d.CountNode(); ++i)
-    {
-        AddNode(det, d.at(i));
-    }
-
-    domElement.appendChild(det);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief AddNode add node to xml file.
- * @param domElement tag in xml tree.
- * @param node node.
- */
-void VToolUnionDetails::AddNode(QDomElement &domElement, const VNodeDetail &node)
-{
-    //Right now method similar to method in class VToolDetail.
-    VToolDetail::AddNode(doc, domElement, node);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief UpdateDetail update detail in xml tree.
- * @param domNode dom node.
- * @param d detail.
- * @return return next detail tag in xml tree if exist.
- */
-QDomNode VToolUnionDetails::UpdateDetail(const QDomNode &domNode, const VDetail &d)
-{
-    //QDomNode domNode = domElement.firstChild();
-    while (domNode.isNull() == false)
-    {
-        if (domNode.isElement())
-        {
-            QDomElement domElement = domNode.toElement();
-            if (domElement.isNull() == false)
-            {
-                if (domElement.tagName() == VToolUnionDetails::TagDetail)
-                {
-                    VDomDocument::RemoveAllChildren(domElement);//delete all nodes in detail
-                    for (int i = 0; i < d.CountNode(); ++i)
-                    {
-                        AddNode(domElement, d.at(i));//rewrite nodes of detail
-                    }
-                    break;
+                    return VAbstractPattern::ParsePieceNodes(element);
                 }
             }
         }
     }
-    return domNode.nextSibling();
+
+    return VPiecePath();
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief AddToModeling add tool to xml tree.
- * @param domElement tag in xml tree.
- */
-void VToolUnionDetails::AddToModeling(const QDomElement &domElement)
+VPiecePath GetPiece1MainPath(VAbstractPattern *doc, quint32 id)
 {
-    QDomElement modeling = doc->GetDraw(drawName).firstChildElement(VAbstractPattern::TagModeling);
-    if (not modeling.isNull())
-    {
-        modeling.appendChild(domElement);
-    }
-    else
-    {
-        qCDebug(vToolUnion, "Can't find tag %s.", qUtf8Printable(VAbstractPattern::TagModeling));
-        return;
-    }
+    return GetPiecePath(1, doc, id);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VToolUnionDetails::IncrementReferences(const VDetail &d) const
+VPiecePath GetPiece2MainPath(VAbstractPattern *doc, quint32 id)
 {
-    for (int i = 0; i < d.CountNode(); ++i)
+    return GetPiecePath(2, doc, id);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<CustomSARecord> GetPiece2CSAPaths(VAbstractPattern *doc, quint32 id)
+{
+    const QDomElement tool = doc->elementById(id);
+    if (tool.isNull())
     {
-        switch (d.at(i).getTypeTool())
+        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 && i+1 == 2)
         {
-            case (Tool::NodePoint):
+            const QDomNodeList detList = element.childNodes();
+            for (qint32 j = 0; j < detList.size(); ++j)
             {
-                const auto point = VAbstractTool::data.GeometricObject<VPointF>(d.at(i).getId());
-                doc->IncrementReferens(point->getIdTool());
-                break;
+                const QDomElement element = detList.at(j).toElement();
+                if (not element.isNull() && element.tagName() == VToolSeamAllowance::TagCSA)
+                {
+                    return VAbstractPattern::ParsePieceCSARecords(element);
+                }
             }
-            case (Tool::NodeArc):
-            case (Tool::NodeElArc):
-            case (Tool::NodeSpline):
-            case (Tool::NodeSplinePath):
-                doc->IncrementReferens(d.at(i).getId());
-                break;
-            default:
-                qDebug()<<"Get wrong tool type. Ignore.";
-                break;
         }
     }
+
+    return QVector<CustomSARecord>();
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VToolUnionDetails::DecrementReferences(const VDetail &d) const
+QVector<quint32> GetPiece2InternalPaths(VAbstractPattern *doc, quint32 id)
 {
-    for (int i = 0; i < d.CountNode(); ++i)
+    const QDomElement tool = doc->elementById(id);
+    if (tool.isNull())
     {
-        switch (d.at(i).getTypeTool())
+        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 && i+1 == 2)
         {
-            case (Tool::NodePoint):
+            const QDomNodeList detList = element.childNodes();
+            for (qint32 j = 0; j < detList.size(); ++j)
             {
-                const auto point = VAbstractTool::data.GeometricObject<VPointF>(d.at(i).getId());
-                doc->DecrementReferens(point->getIdTool());
-                break;
+                const QDomElement element = detList.at(j).toElement();
+                if (not element.isNull() && element.tagName() == VToolSeamAllowance::TagIPaths)
+                {
+                    return VAbstractPattern::ParsePieceInternalPaths(element);
+                }
             }
-            case (Tool::NodeArc):
-            case (Tool::NodeElArc):
-            case (Tool::NodeSpline):
-            case (Tool::NodeSplinePath):
-                doc->DecrementReferens(d.at(i).getId());
-                break;
-            default:
-                qDebug()<<"Get wrong tool type. Ignore.";
-                break;
         }
     }
+
+    return QVector<quint32>();
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VToolUnionDetails::SaveChildren(VAbstractPattern *doc, quint32 id, const QVector<quint32> &children)
-{
-    QDomElement toolUnion = doc->elementById(id);
-    if (toolUnion.isNull())
-    {
-        return;
-    }
-
-    QDomElement tagChildren = doc->createElement(TagChildren);
-
-    for (int i=0; i<children.size(); ++i)
-    {
-        QDomElement tagChild = doc->createElement(TagChild);
-        tagChild.appendChild(doc->createTextNode(QString().setNum(children.at(i))));
-        tagChildren.appendChild(tagChild);
-    }
-
-    toolUnion.appendChild(tagChildren);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<quint32> VToolUnionDetails::AllChildren(VAbstractPattern *doc, quint32 id)
-{
-    const QDomElement toolUnion = doc->elementById(id);
-    if (toolUnion.isNull())
-    {
-        return QVector<quint32>();
-    }
-
-    const QDomElement tagChildren = toolUnion.firstChildElement(TagChildren);
-    if (tagChildren.isNull())
-    {
-        return QVector<quint32>();
-    }
-
-    QVector<quint32> childrenId;
-    const QDomNodeList listChildren = tagChildren.elementsByTagName(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 VToolUnionDetails::TakeNextId(QVector<quint32> &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;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QString VToolUnionDetails::DrawName(VAbstractPattern *doc, quint32 d1id, quint32 d2id)
+QString DrawName(VAbstractPattern *doc, quint32 d1id, quint32 d2id)
 {
     const QDomElement detail1 = doc->elementById(d1id);
     if (detail1.isNull())
@@ -1196,3 +269,1269 @@ QString VToolUnionDetails::DrawName(VAbstractPattern *doc, quint32 d1id, quint32
         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, qreal dx, qreal dy, const QPointF &pRotate, 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 VPiecePath &path, quint32 index, VPointF &p1, VPointF &p2, VContainer *data)
+{
+    VPieceNode det2p1;
+    VPieceNode det2p2;
+    path.NodeOnEdge(index, det2p1, det2p2);
+    p1 = VPointF(*data->GeometricObject<VPointF>(det2p1.GetId()));
+    p2 = VPointF(*data->GeometricObject<VPointF>(det2p2.GetId()));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void UnionInitParameters(const VToolUnionDetailsInitData &initData, const VPiecePath &d1Path, const VPiecePath &d2Path,
+                         VPieceNode &det1p1, qreal &dx, qreal &dy, qreal &angle)
+{
+    VPieceNode det1p2;
+    d1Path.NodeOnEdge(initData.indexD1, det1p1, det1p2);
+    Q_UNUSED(det1p2)
+
+    VPointF point1;
+    VPointF point2;
+    PointsOnEdge(d1Path, initData.indexD1, point1, point2, initData.data);
+
+    VPointF point3;
+    VPointF point4;
+    PointsOnEdge(d2Path, 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<quint32> &children, const QString &drawName, qreal dx, qreal dy,
+                     quint32 pRotate, qreal angle)
+{
+    QScopedPointer<VPointF> point(new VPointF(*initData.data->GeometricObject<VPointF>(node.GetId())));
+    point->setMode(Draw::Modeling);
+
+    if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
+    {
+        BiasRotatePoint(point.data(), dx, dy, *initData.data->GeometricObject<VPointF>(pRotate), angle);
+    }
+
+    QScopedPointer<VPointF> 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<quint32> &children, const QString &drawName, qreal dx, qreal dy,
+                   quint32 pRotate, qreal angle)
+{
+    const QSharedPointer<VArc> arc = initData.data->GeometricObject<VArc>(node.GetId());
+    VPointF p1 = VPointF(arc->GetP1(), "A", 0, 0);
+    VPointF p2 = VPointF(arc->GetP2(), "A", 0, 0);
+    QScopedPointer<VPointF> center(new VPointF(arc->GetCenter()));
+
+    if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
+    {
+        const QPointF p = *initData.data->GeometricObject<VPointF>(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<VArc> arc1(new VArc(*tmpCenter, arc->GetRadius(), arc->GetFormulaRadius(), l1.angle(),
+                                       QString().setNum(l1.angle()), l2.angle(), QString().setNum(l2.angle())));
+    arc1->setMode(Draw::Modeling);
+
+    QScopedPointer<VArc>arc2(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<quint32> &children, const QString &drawName, qreal dx, qreal dy,
+                     quint32 pRotate, qreal angle)
+{
+    const QSharedPointer<VEllipticalArc> arc = initData.data->GeometricObject<VEllipticalArc>(node.GetId());
+    VPointF p1 = VPointF(arc->GetP1(), "A", 0, 0);
+    VPointF p2 = VPointF(arc->GetP2(), "A", 0, 0);
+    QScopedPointer<VPointF> center(new VPointF(arc->GetCenter()));
+
+    if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
+    {
+        const QPointF p = *initData.data->GeometricObject<VPointF>(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<VEllipticalArc> 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<VEllipticalArc> 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<quint32> &children, const QString &drawName, qreal dx, qreal dy,
+                      quint32 pRotate, qreal angle)
+{
+    const QSharedPointer<VAbstractCubicBezier> spline =
+            initData.data->GeometricObject<VAbstractCubicBezier>(node.GetId());
+
+    QScopedPointer<VPointF> p1(new VPointF(spline->GetP1()));
+    VPointF p2 = VPointF(spline->GetP2());
+    VPointF p3 = VPointF(spline->GetP3());
+    QScopedPointer<VPointF> p4(new VPointF(spline->GetP4()));
+
+    if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
+    {
+        const QPointF p = *initData.data->GeometricObject<VPointF>(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<quint32> &children, const QString &drawName, qreal dx, qreal dy,
+                          quint32 pRotate, qreal angle)
+{
+    QScopedPointer<VSplinePath> path(new VSplinePath());
+    path->setMode(Draw::Modeling);
+    const QSharedPointer<VAbstractCubicBezierPath> splinePath =
+            initData.data->GeometricObject<VAbstractCubicBezierPath>(node.GetId());
+    for (qint32 i = 1; i <= splinePath->CountSubSpl(); ++i)
+    {
+        const VSpline spline = splinePath->GetSpline(i);
+
+        QScopedPointer<VPointF> p1(new VPointF(spline.GetP1()));
+        VPointF p2 = VPointF(spline.GetP2());
+        VPointF p3 = VPointF(spline.GetP3());
+        QScopedPointer<VPointF> p4(new VPointF(spline.GetP4()));
+        if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
+        {
+            const QPointF p = *initData.data->GeometricObject<VPointF>(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<VSplinePath> 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 AddNodeToNewPath(const VToolUnionDetailsInitData &initData, VPiecePath &newPath, const VPieceNode &node,
+                      quint32 idTool, QVector<quint32> &children, const QString &drawName, qreal dx = 0, qreal dy = 0,
+                      quint32 pRotate = NULL_ID, qreal angle = 0);
+
+void AddNodeToNewPath(const VToolUnionDetailsInitData &initData, VPiecePath &newPath, const VPieceNode &node,
+                      quint32 idTool, QVector<quint32> &children, const QString &drawName, qreal dx, qreal dy,
+                      quint32 pRotate, qreal angle)
+{
+    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 = AddNodeSpline(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."<<Q_FUNC_INFO;
+            break;
+    }
+    newPath.Append(VPieceNode(id, node.GetTypeTool(), node.GetReverse()));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void FindIndexJ(qint32 pointsD2, const VPiecePath &d2Path, quint32 indexD2, qint32 &j)
+{
+    if (pointsD2 == 0)
+    {
+        VPieceNode node1;
+        VPieceNode node2;
+        d2Path.NodeOnEdge(indexD2, node1, node2);
+        const VPiecePath removedD2 = d2Path.RemoveEdge(indexD2);
+        const int k = removedD2.indexOfNode(node2.GetId());
+        SCASSERT(k != -1)
+        if (k == removedD2.CountNodes()-1)
+        {//We have last node in detail, we wil begin from 0
+            j = 0;
+        }
+        else
+        {// Continue from next node
+            j = k+1;
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QDomElement GetTagChildren(VAbstractPattern *doc, quint32 id)
+{
+    QDomElement toolUnion = doc->elementById(id);
+    if (toolUnion.isNull())
+    {
+        VException e(QString("Can't get tool by id='%1'.").arg(id));
+        throw e;
+    }
+
+    QDomElement tagChildren = toolUnion.firstChildElement(VToolUnionDetails::TagChildren);
+
+    if (tagChildren.isNull())
+    {
+        tagChildren = doc->createElement(VToolUnionDetails::TagChildren);
+        toolUnion.appendChild(tagChildren);
+    }
+
+    return tagChildren;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void SaveChildren(VAbstractPattern *doc, quint32 id, QDomElement section, const QVector<quint32> &children)
+{
+    for (int i=0; i<children.size(); ++i)
+    {
+        QDomElement tagChild = doc->createElement(VToolUnionDetails::TagChild);
+        tagChild.appendChild(doc->createTextNode(QString().setNum(children.at(i))));
+        section.appendChild(tagChild);
+    }
+
+    GetTagChildren(doc, id).appendChild(section);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void SaveNodesChildren(VAbstractPattern *doc, quint32 id, const QVector<quint32> &children)
+{
+    SaveChildren(doc, id, doc->createElement(VAbstractPattern::TagNodes), children);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void SaveCSAChildren(VAbstractPattern *doc, quint32 id, const QVector<quint32> &children)
+{
+    SaveChildren(doc, id, doc->createElement(VToolSeamAllowance::TagCSA), children);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void SaveInternalPathsChildren(VAbstractPattern *doc, quint32 id, const QVector<quint32> &children)
+{
+    SaveChildren(doc, id, doc->createElement(VToolSeamAllowance::TagIPaths), children);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<quint32> GetChildren(VAbstractPattern *doc, quint32 id, const QString &tagName)
+{
+    const QDomElement toolUnion = doc->elementById(id);
+    if (toolUnion.isNull())
+    {
+        return QVector<quint32>();
+    }
+
+    const QDomElement tagChildren = toolUnion.firstChildElement(VToolUnionDetails::TagChildren);
+    if (tagChildren.isNull())
+    {
+        return QVector<quint32>();
+    }
+
+    const QDomElement tagNodes = tagChildren.firstChildElement(tagName);
+    if (tagNodes.isNull())
+    {
+        return QVector<quint32>();
+    }
+
+    QVector<quint32> 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;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<quint32> GetNodesChildren(VAbstractPattern *doc, quint32 id)
+{
+    return GetChildren(doc, id, VAbstractPattern::TagNodes);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<quint32> GetCSAChildren(VAbstractPattern *doc, quint32 id)
+{
+    return GetChildren(doc, id, VToolSeamAllowance::TagCSA);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<quint32> GetInternalPathsChildren(VAbstractPattern *doc, quint32 id)
+{
+    return GetChildren(doc, id, VToolSeamAllowance::TagIPaths);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+quint32 TakeNextId(QVector<quint32> &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<quint32> &children, qreal dx, qreal dy,
+                     quint32 pRotate, qreal angle)
+{
+    QScopedPointer<VPointF> point(new VPointF(*data->GeometricObject<VPointF>(node.GetId())));
+    point->setMode(Draw::Modeling);
+    if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
+    {
+        BiasRotatePoint(point.data(), dx, dy, *data->GeometricObject<VPointF>(pRotate), angle);
+    }
+    data->UpdateGObject(TakeNextId(children), point.take());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void UpdateNodeArc(VContainer *data, const VPieceNode &node, QVector<quint32> &children, qreal dx, qreal dy,
+                   quint32 pRotate, qreal angle)
+{
+    const QSharedPointer<VArc> arc = data->GeometricObject<VArc>(node.GetId());
+    VPointF p1 = VPointF(arc->GetP1());
+    VPointF p2 = VPointF(arc->GetP2());
+    QScopedPointer<VPointF> center(new VPointF(arc->GetCenter()));
+
+    if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
+    {
+        const QPointF p = *data->GeometricObject<VPointF>(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<VArc> 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<quint32> &children, qreal dx, qreal dy,
+                     quint32 pRotate, qreal angle)
+{
+    const QSharedPointer<VEllipticalArc> arc = data->GeometricObject<VEllipticalArc>(node.GetId());
+    VPointF p1 = VPointF(arc->GetP1());
+    VPointF p2 = VPointF(arc->GetP2());
+    QScopedPointer<VPointF> center(new VPointF(arc->GetCenter()));
+
+    if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
+    {
+        const QPointF p = *data->GeometricObject<VPointF>(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<VEllipticalArc> 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<quint32> &children, qreal dx, qreal dy,
+                      quint32 pRotate, qreal angle)
+{
+    const QSharedPointer<VAbstractCubicBezier> spline =
+            data->GeometricObject<VAbstractCubicBezier>(node.GetId());
+
+    QScopedPointer<VPointF> p1(new VPointF(spline->GetP1()));
+    VPointF p2 = VPointF(spline->GetP2());
+    VPointF p3 = VPointF(spline->GetP3());
+    QScopedPointer<VPointF> p4(new VPointF(spline->GetP4()));
+
+    if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
+    {
+        const QPointF p = *data->GeometricObject<VPointF>(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<VSpline> spl(new VSpline(*p1, p2, p3, *p4, 0, Draw::Modeling));
+    data->UpdateGObject(TakeNextId(children), spl.take());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void UpdateNodeSplinePath(VContainer *data, const VPieceNode &node, QVector<quint32> &children, qreal dx, qreal dy,
+                          quint32 pRotate, qreal angle)
+{
+    QScopedPointer<VSplinePath> path(new VSplinePath());
+    path->setMode(Draw::Modeling);
+    const QSharedPointer<VAbstractCubicBezierPath> splinePath =
+            data->GeometricObject<VAbstractCubicBezierPath>(node.GetId());
+    SCASSERT(splinePath != nullptr)
+    for (qint32 i = 1; i <= splinePath->CountSubSpl(); ++i)
+    {
+        const VSpline spline = splinePath->GetSpline(i);
+
+        QScopedPointer<VPointF> p1(new VPointF(spline.GetP1()));
+        VPointF p2 = VPointF(spline.GetP2());
+        VPointF p3 = VPointF(spline.GetP3());
+        QScopedPointer<VPointF> p4(new VPointF(spline.GetP4()));
+
+        if (not qFuzzyIsNull(dx) || not qFuzzyIsNull(dy) || pRotate != NULL_ID)
+        {
+            const QPointF p = *data->GeometricObject<VPointF>(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 UpdatePathNode(VContainer *data, const VPieceNode &node, QVector<quint32> &children,
+                 qreal dx = 0, qreal dy = 0, quint32 pRotate = NULL_ID, qreal angle = 0);
+void UpdatePathNode(VContainer *data, const VPieceNode &node, QVector<quint32> &children, qreal dx, qreal dy,
+                 quint32 pRotate, qreal angle)
+{
+    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."<<Q_FUNC_INFO;
+            break;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void CreateUnitedNodes(VPiece &newDetail, const VPiece &d1, const VPiece &d2, quint32 id, const QString &drawName,
+                       const VToolUnionDetailsInitData &initData, qreal dx, qreal dy, quint32 pRotate, qreal angle)
+{
+    const VPiecePath d1Path = d1.GetPath().RemoveEdge(initData.indexD1);
+    const VPiecePath d2Path = d2.GetPath().RemoveEdge(initData.indexD2);
+
+    const qint32 countNodeD1 = d1Path.CountNodes();
+    const qint32 countNodeD2 = d2Path.CountNodes();
+
+    qint32 pointsD2 = 0; //Keeps number points the second detail, what we have already added.
+    qint32 i = 0;
+    QVector<quint32> children;
+    VPiecePath newPath;
+    const int det1P1Index = d1.GetPath().indexOfNode(pRotate);
+    do
+    {
+        AddNodeToNewPath(initData, newPath, d1Path.at(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;
+                }
+                AddNodeToNewPath(initData, newPath, d2Path.at(j), id, children, drawName, dx, dy, pRotate, angle);
+                ++pointsD2;
+                ++j;
+            } while (pointsD2 < countNodeD2-1);
+        }
+    } while (i < countNodeD1);
+
+    newDetail.SetPath(newPath);
+
+    SCASSERT(not children.isEmpty())
+    SaveNodesChildren(initData.doc, id, children);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void CreateUnitedDetailCSA(VPiece &newDetail, const VPiece &d, QVector<quint32> &children, quint32 id,
+                           const QString &drawName, const VToolUnionDetailsInitData &initData, qreal dx, qreal dy,
+                           quint32 pRotate, qreal angle)
+{
+    QVector<CustomSARecord> newList = newDetail.GetCustomSARecords();
+    const QVector<CustomSARecord> oldList = d.GetCustomSARecords();
+    QVector<quint32> nodeChildren;
+    for(int i=0; i < oldList.size(); ++i)
+    {
+        CustomSARecord record = oldList.at(i);
+        const VPiecePath path = initData.data->GetPiecePath(record.path);
+        VPiecePath newPath = path;
+        newPath.Clear();//Clear nodes
+        for (int i=0; i < path.CountNodes(); ++i)
+        {
+            AddNodeToNewPath(initData, newPath, path.at(i), id, nodeChildren, drawName, dx, dy, pRotate, angle);
+        }
+        const quint32 idPath = initData.data->AddPiecePath(newPath);
+        VToolPiecePath::Create(idPath, newPath, NULL_ID, initData.scene, initData.doc, initData.data, initData.parse,
+                               Source::FromTool, drawName, id);
+        record.path = idPath;
+        newList.append(record);
+        nodeChildren.prepend(idPath);
+    }
+    children += nodeChildren;
+    newDetail.SetCustomSARecords(newList);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void CreateUnitedCSA(VPiece &newDetail, const VPiece &d1, const VPiece &d2, quint32 id, const QString &drawName,
+                     const VToolUnionDetailsInitData &initData, qreal dx, qreal dy, quint32 pRotate, qreal angle)
+{
+    const QVector<CustomSARecord> d1Records = d1.GetCustomSARecords();
+    for (int i = 0; i < d1Records.size(); ++i)
+    {
+        newDetail.AppendCustomSARecord(d1Records.at(i));
+    }
+
+    QVector<quint32> children;
+    CreateUnitedDetailCSA(newDetail, d2, children, id, drawName, initData, dx, dy, pRotate, angle);
+
+    SCASSERT(not children.isEmpty())
+    SaveCSAChildren(initData.doc, id, children);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void CreateUnitedDetailInternalPaths(VPiece &newDetail, const VPiece &d, QVector<quint32> &children, quint32 id,
+                                     const QString &drawName, const VToolUnionDetailsInitData &initData, qreal dx,
+                                     qreal dy, quint32 pRotate, qreal angle)
+{
+    QVector<quint32> newList = newDetail.GetInternalPaths();
+    const QVector<quint32> oldList = d.GetInternalPaths();
+    QVector<quint32> nodeChildren;
+    for(int i=0; i < oldList.size(); ++i)
+    {
+        const VPiecePath path = initData.data->GetPiecePath(oldList.at(i));
+        VPiecePath newPath = path;
+        newPath.Clear();//Clear nodes
+
+        for (int i=0; i < path.CountNodes(); ++i)
+        {
+            AddNodeToNewPath(initData, newPath, path.at(i), id, nodeChildren, drawName, dx, dy, pRotate, angle);
+        }
+        const quint32 idPath = initData.data->AddPiecePath(newPath);
+        VToolPiecePath::Create(idPath, newPath, NULL_ID, initData.scene, initData.doc, initData.data, initData.parse,
+                               Source::FromTool, drawName, id);
+        newList.append(idPath);
+        nodeChildren.prepend(idPath);
+    }
+    children += nodeChildren;
+    newDetail.SetInternalPaths(newList);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void CreateUnitedInternalPaths(VPiece &newDetail, const VPiece &d1, const VPiece &d2, quint32 id,
+                               const QString &drawName, const VToolUnionDetailsInitData &initData, qreal dx, qreal dy,
+                               quint32 pRotate, qreal angle)
+{
+    const QVector<quint32> d1Internal = d1.GetInternalPaths();
+    for (int i = 0; i < d1Internal.size(); ++i)
+    {
+        newDetail.AppendInternalPath(d1Internal.at(i));
+    }
+
+    QVector<quint32> children;
+    CreateUnitedDetailInternalPaths(newDetail, d2, children, id, drawName, initData, dx, dy, pRotate, angle);
+
+    SCASSERT(not children.isEmpty())
+    SaveInternalPathsChildren(initData.doc, id, children);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void UpdateUnitedNodes(quint32 id, const VToolUnionDetailsInitData &initData, qreal dx, qreal dy, quint32 pRotate,
+                       qreal angle)
+{
+    const VPiecePath d1Path = GetPiece1MainPath(initData.doc, id);
+    const VPiecePath d1REPath = d1Path.RemoveEdge(initData.indexD1);
+
+    const VPiecePath d2Path = GetPiece2MainPath(initData.doc, id);
+    const VPiecePath d2REPath = d2Path.RemoveEdge(initData.indexD2);
+
+    const qint32 countNodeD1 = d1REPath.CountNodes();
+    const qint32 countNodeD2 = d2REPath.CountNodes();
+
+    QVector<quint32> 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 pointsD2 = 0; //Keeps number points the second detail, what we have already added.
+            qint32 i = 0;
+            const int indexOfNode = d1Path.indexOfNode(pRotate);
+            do
+            {
+                UpdatePathNode(initData.data, d1REPath.at(i), children);
+                ++i;
+                if (i > indexOfNode && pointsD2 < countNodeD2-1)
+                {
+                    qint32 j = 0;
+                    FindIndexJ(pointsD2, d2Path, initData.indexD2, j);
+                    do
+                    {
+                        if (j >= countNodeD2)
+                        {
+                            j=0;
+                        }
+                        UpdatePathNode(initData.data, d2REPath.at(j), children, dx, dy, pRotate, angle);
+                        ++pointsD2;
+                        ++j;
+                    } while (pointsD2 < countNodeD2-1);
+                }
+            } while (i<countNodeD1);
+        }
+        else // remove if min version is 0.3.2
+        {
+            qint32 pointsD2 = 0; //Keeps number points the second detail, what we have already added.
+            qint32 i = 0;
+            const int indexOfNode = d1Path.indexOfNode(pRotate);
+            do
+            {
+                ++i;
+                if (i > indexOfNode)
+                {
+                    const int childrenCount = children.size();
+                    qint32 j = 0;
+                    FindIndexJ(pointsD2, d2Path, initData.indexD2, j);
+                    do
+                    {
+                        if (j >= countNodeD2)
+                        {
+                            j=0;
+                        }
+                        UpdatePathNode(initData.data, d2REPath.at(j), children, dx, dy, pRotate, angle);
+                        ++pointsD2;
+                        ++j;
+                    } while (pointsD2 < childrenCount);
+                    break;
+                }
+            } while (i<countNodeD1);
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void UpdateUnitedDetailPaths(const VToolUnionDetailsInitData &initData, qreal dx, qreal dy, quint32 pRotate,
+                             qreal angle, const QVector<quint32> &records, QVector<quint32> children)
+{
+    for (int i=0; i < records.size(); ++i)
+    {
+        const VPiecePath path = initData.data->GetPiecePath(records.at(i));
+        const quint32 updatedId = TakeNextId(children);
+
+        VPiecePath updatedPath(path);
+        updatedPath.Clear();
+
+        for (int j=0; j < path.CountNodes(); ++j)
+        {
+            const VPieceNode &node = path.at(j);
+            const quint32 id = TakeNextId(children);
+            updatedPath.Append(VPieceNode(id, node.GetTypeTool(), node.GetReverse()));
+            QVector<quint32> nodeChildren = {id};
+            UpdatePathNode(initData.data, path.at(j), nodeChildren, dx, dy, pRotate, angle);
+        }
+        initData.data->UpdatePiecePath(updatedId, updatedPath);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void UpdateUnitedDetailCSA(quint32 id, const VToolUnionDetailsInitData &initData, qreal dx, qreal dy, quint32 pRotate,
+                           qreal angle, const QVector<CustomSARecord> &records)
+{
+    QVector<quint32> idRecords;
+    for (int i = 0; i < records.size(); ++i)
+    {
+        idRecords.append(records.at(i).path);
+    }
+    UpdateUnitedDetailPaths(initData, dx, dy, pRotate, angle, idRecords, GetCSAChildren(initData.doc, id));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void UpdateUnitedDetailInternalPaths(quint32 id, const VToolUnionDetailsInitData &initData, qreal dx, qreal dy,
+                                     quint32 pRotate, qreal angle, const QVector<quint32> &records)
+{
+    UpdateUnitedDetailPaths(initData, dx, dy, pRotate, angle, records, GetInternalPathsChildren(initData.doc, id));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void CreateUnitedDetail(quint32 id, const VToolUnionDetailsInitData &initData, qreal dx, qreal dy, quint32 pRotate,
+                        qreal angle)
+{
+    const QString drawName = DrawName(initData.doc, initData.d1id, initData.d2id);
+    SCASSERT(not drawName.isEmpty())
+
+    const VPiece d1 = initData.data->GetPiece(initData.d1id);
+    const VPiece d2 = initData.data->GetPiece(initData.d2id);
+
+    VPiece newDetail;
+
+    CreateUnitedNodes(newDetail, d1, d2, id, drawName, initData, dx, dy, pRotate, angle);
+    CreateUnitedCSA(newDetail, d1, d2, id, drawName, initData, dx, dy, pRotate, angle);
+    CreateUnitedInternalPaths(newDetail, d1, d2, id, drawName, initData, dx, dy, pRotate, angle);
+
+    newDetail.SetName(QObject::tr("United detail"));
+    QString formulaSAWidth = d1.GetFormulaSAWidth();
+    newDetail.SetFormulaSAWidth(formulaSAWidth, d1.GetSAWidth());
+    newDetail.SetMx(d1.GetMx());
+    newDetail.SetMy(d1.GetMy());
+    newDetail.SetUnited(true);
+    VToolSeamAllowance::Create(0, newDetail, formulaSAWidth, initData.scene, initData.doc, initData.data,
+                               initData.parse, Source::FromTool, drawName);
+
+    auto RemoveDetail = [initData](quint32 id)
+    {
+        VToolSeamAllowance *toolDet = qobject_cast<VToolSeamAllowance*>(initData.doc->getTool(id));
+        SCASSERT(toolDet != nullptr);
+        bool ask = false;
+        toolDet->Remove(ask);
+        // We do not call full parse, so will need more to do more cleaning than usually
+        initData.doc->RemoveTool(id);
+        initData.data->RemovePiece(id);
+    };
+
+    if (not initData.retainPieces)
+    {
+        RemoveDetail(initData.d1id);
+        RemoveDetail(initData.d2id);
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void UpdateUnitedDetail(quint32 id, const VToolUnionDetailsInitData &initData, qreal dx, qreal dy, quint32 pRotate,
+                        qreal angle)
+{
+    UpdateUnitedNodes(id, initData, dx, dy, pRotate, angle);
+    UpdateUnitedDetailCSA(id, initData, dx, dy, pRotate, angle, GetPiece2CSAPaths(initData.doc, id));
+    UpdateUnitedDetailInternalPaths(id, initData, dx, dy, pRotate, angle, GetPiece2InternalPaths(initData.doc, id));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void UniteDetails(quint32 id, const VToolUnionDetailsInitData &initData)
+{
+    VPieceNode det1p1;
+    qreal dx = 0;
+    qreal dy = 0;
+    qreal angle = 0;
+
+    if (initData.typeCreation == Source::FromGui)
+    {
+        const VPiece d1 = initData.data->GetPiece(initData.d1id);
+        const VPiece d2 = initData.data->GetPiece(initData.d2id);
+        UnionInitParameters(initData, d1.GetPath(), d2.GetPath(), det1p1, dx, dy, angle);
+        CreateUnitedDetail(id, initData, dx, dy, det1p1.GetId(), angle);
+    }
+    else
+    {
+        const VPiecePath d1Path = GetPiece1MainPath(initData.doc, id);
+        const VPiecePath d2Path = GetPiece2MainPath(initData.doc, id);
+        UnionInitParameters(initData, d1Path, d2Path, det1p1, dx, dy, angle);
+        UpdateUnitedDetail(id, initData, dx, dy, det1p1.GetId(), angle);
+    }
+}
+} // static functions
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief VToolUnionDetails costructor.
+ * @param id object id in container.
+ * @param initData global init data.
+ * @param parent parent object.
+ */
+VToolUnionDetails::VToolUnionDetails(quint32 id, const VToolUnionDetailsInitData &initData,
+                                     QObject *parent)
+    : VAbstractTool(initData.doc, initData.data, id, parent),
+      d1id(initData.d1id),
+      d2id(initData.d2id),
+      indexD1(initData.indexD1),
+      indexD2(initData.indexD2)
+{
+    _referens = 0;
+    ToolCreation(initData.typeCreation);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QString VToolUnionDetails::getTagName() const
+{
+    return VAbstractPattern::TagTools;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolUnionDetails::ShowVisualization(bool show)
+{
+    Q_UNUSED(show)
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VToolUnionDetails::incrementReferens()
+{
+    VDataTool::incrementReferens();
+    if (_referens == 1)
+    {
+        const QVector<quint32> 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<quint32> 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<DialogUnionDetails*>(dialog);
+    SCASSERT(dialogTool != nullptr)
+
+    VToolUnionDetailsInitData initData;
+    initData.d1id = dialogTool->getD1();
+    initData.d2id = dialogTool->getD2();
+    initData.indexD1 = static_cast<quint32>(dialogTool->getIndexD1());
+    initData.indexD2 = static_cast<quint32>(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<quint32> VToolUnionDetails::GetReferenceObjects() const
+{
+    QVector<quint32> 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 += ReferenceObjects(element, TagNode, AttrIdObject);
+                            break;
+                        case 1://VToolSeamAllowance::TagCSA
+                        case 2://VToolSeamAllowance::TagIPaths
+                            list += ReferenceObjects(element, VToolSeamAllowance::TagRecord,
+                                                     VAbstractPattern::AttrPath);
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
+        }
+    }
+    return list;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<quint32> VToolUnionDetails::ReferenceObjects(const QDomElement &root, const QString &tag,
+                                                     const QString &attribute) const
+{
+    QVector<quint32> objects;
+
+    const QDomNodeList list = root.childNodes();
+    for (qint32 i = 0; i < list.size(); ++i)
+    {
+        const QDomElement element = list.at(i).toElement();
+        if (not element.isNull() && element.tagName() == tag)
+        {
+            const quint32 id = doc->GetParametrUInt(element, attribute, NULL_ID_STR);
+            if (id > NULL_ID)
+            {
+                objects.append(id);
+            }
+        }
+    }
+
+    return objects;
+}
diff --git a/src/libs/vtools/tools/vtooluniondetails.h b/src/libs/vtools/tools/vtooluniondetails.h
index fae483cda..a0d652bbe 100644
--- a/src/libs/vtools/tools/vtooluniondetails.h
+++ b/src/libs/vtools/tools/vtooluniondetails.h
@@ -43,7 +43,7 @@
 #include "../ifc/xml/vabstractpattern.h"
 #include "../vmisc/def.h"
 #include "vabstracttool.h"
-#include "vdetail.h"
+#include "../vpatterndb/vpiece.h"
 
 class DialogTool;
 class QDomElement;
@@ -51,9 +51,35 @@ class QDomNode;
 class QPointF;
 class VContainer;
 class VMainGraphicsScene;
-class VNodeDetail;
 class VPointF;
 
+struct VToolUnionDetailsInitData
+{
+    VToolUnionDetailsInitData()
+        : d1id(NULL_ID),
+          d2id(NULL_ID),
+          indexD1(NULL_ID),
+          indexD2(NULL_ID),
+          scene(nullptr),
+          doc(nullptr),
+          data(nullptr),
+          parse(Document::FullParse),
+          typeCreation(Source::FromFile),
+          retainPieces(false)
+    {}
+
+    quint32 d1id;
+    quint32 d2id;
+    quint32 indexD1;
+    quint32 indexD2;
+    VMainGraphicsScene *scene;
+    VAbstractPattern *doc;
+    VContainer *data;
+    Document parse;
+    Source typeCreation;
+    bool retainPieces;
+};
+
 /**
  * @brief The VToolUnionDetails class tool union details.
  */
@@ -67,15 +93,7 @@ public:
     virtual void setDialog() {}
     static VToolUnionDetails *Create(DialogTool *dialog, VMainGraphicsScene *scene, VAbstractPattern *doc,
                                      VContainer *data);
-    static VToolUnionDetails *Create(const quint32 _id, const VDetail &d1,  const VDetail &d2, const quint32 &d1id,
-                                     const quint32 &d2id, const quint32 &indexD1, const quint32 &indexD2,
-                                     VMainGraphicsScene *scene, VAbstractPattern *doc, VContainer *data,
-                                     const Document &parse,
-                                     const Source &typeCreation,
-                                     bool retainPieces = false);
-    static void  PointsOnEdge(const VDetail &d, const quint32 &index, VPointF &p1, VPointF &p2, VContainer *data);
-    static void  FindIndexJ(const qint32 &pointsD2, const VDetail &d2, const quint32 &indexD2, qint32 &j);
-    static QVector<VDetail> GetDetailFromFile(VAbstractPattern *doc, const QDomElement &domElement);
+    static VToolUnionDetails *Create(const quint32 _id, const VToolUnionDetailsInitData &initData);
 
     static const QString ToolType;
     static const QString TagDetail;
@@ -88,15 +106,7 @@ public:
     static const QString AttrNodeType;
     static const QString NodeTypeContour;
     static const QString NodeTypeModeling;
-    static void  AddToNewDetail(VMainGraphicsScene *scene, VAbstractPattern *doc, VContainer *data,
-                                VDetail &newDetail, const VDetail &det, const int &i, const quint32 &idTool,
-                                QVector<quint32> &children, const QString &drawName, const qreal &dx = 0,
-                                const qreal &dy = 0, const quint32 &pRotate = NULL_ID, const qreal &angle = 0);
-    static void  UpdatePoints(VContainer *data, const VDetail &det, const int &i,
-                              QVector<quint32> &children, const qreal &dx = 0, const qreal &dy = 0,
-                              const quint32 &pRotate = NULL_ID, const qreal &angle = 0);
-    static void  BiasRotatePoint(VPointF *point, const qreal &dx, const qreal &dy, const QPointF &pRotate,
-                                 const qreal &angle);
+
     virtual QString getTagName() const Q_DECL_OVERRIDE;
     virtual void ShowVisualization(bool show) Q_DECL_OVERRIDE;
     virtual void incrementReferens() Q_DECL_OVERRIDE;
@@ -115,35 +125,24 @@ protected:
     virtual void SetVisualization() Q_DECL_OVERRIDE {}
 private:
     Q_DISABLE_COPY(VToolUnionDetails)
-    /** @brief d1 first detail. */
-    VDetail      d1;
+    /** @brief d1 first detail id. */
+    quint32 d1id;
 
-    /** @brief d2 second detail. */
-    VDetail      d2;
+    /** @brief d2 second detail id. */
+    quint32 d2id;
 
     /** @brief indexD1 index edge in first detail. */
-    quint32      indexD1;
+    quint32 indexD1;
 
     /** @brief indexD2 index edge in second detail. */
-    quint32      indexD2;
+    quint32 indexD2;
 
-    QString      drawName;
+    VToolUnionDetails(quint32 id, const VToolUnionDetailsInitData &initData, QObject *parent = nullptr);
 
-    VToolUnionDetails(VAbstractPattern *doc, VContainer *data, const quint32 &id, const VDetail &d1, const VDetail &d2,
-                      const quint32 &indexD1, const quint32 &indexD2, const Source &typeCreation,
-                      const QString &drawName, QObject *parent = nullptr);
-
-    void         AddDetail(QDomElement &domElement, VDetail &d);
-    void         AddNode(QDomElement &domElement, const VNodeDetail &node);
-    QDomNode     UpdateDetail(const QDomNode &domNode, const VDetail &d);
-    void         AddToModeling(const QDomElement &domElement);
-    void         IncrementReferences(const VDetail &d) const;
-    void         DecrementReferences(const VDetail &d) const;
-
-    static void             SaveChildren(VAbstractPattern *doc, quint32 id, const QVector<quint32> &children);
-    static QVector<quint32> AllChildren(VAbstractPattern *doc, quint32 id);
-    static quint32          TakeNextId(QVector<quint32> &children);
-    static QString          DrawName(VAbstractPattern *doc, quint32 d1id, quint32 d2id);
+    void             AddDetail(QDomElement &domElement, const VPiece &d) const;
+    void             AddToModeling(const QDomElement &domElement);
+    QVector<quint32> GetReferenceObjects() const;
+    QVector<quint32> ReferenceObjects(const QDomElement &root, const QString &tag, const QString &attribute) const;
 };
 
 #endif // VTOOLUNIONDETAILS_H
diff --git a/src/libs/vtools/undocommands/adddet.cpp b/src/libs/vtools/undocommands/addpiece.cpp
similarity index 77%
rename from src/libs/vtools/undocommands/adddet.cpp
rename to src/libs/vtools/undocommands/addpiece.cpp
index c2b9d4efe..9f4ccc2ff 100644
--- a/src/libs/vtools/undocommands/adddet.cpp
+++ b/src/libs/vtools/undocommands/addpiece.cpp
@@ -1,14 +1,14 @@
 /************************************************************************
  **
- **  @file   adddet.cpp
+ **  @file
  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   15 6, 2014
+ **  @date   6 11, 2016
  **
  **  @brief
  **  @copyright
  **  This source code is part of the Valentine project, a pattern making
  **  program, whose allow create and modeling patterns of clothing.
- **  Copyright (C) 2013-2015 Valentina project
+ **  Copyright (C) 2016 Valentina project
  **  <https://bitbucket.org/dismine/valentina> All Rights Reserved.
  **
  **  Valentina is free software: you can redistribute it and/or modify
@@ -26,34 +26,27 @@
  **
  *************************************************************************/
 
-#include "adddet.h"
-
-#include <QByteArray>
-#include <QDomNode>
-
-#include "../ifc/xml/vabstractpattern.h"
-#include "../vmisc/logging.h"
-#include "vundocommand.h"
-
-class QDomElement;
-class QUndoCommand;
+#include "addpiece.h"
+#include "../vpatterndb/vpiecenode.h"
+#include "../vpatterndb/vpiecepath.h"
 
 //---------------------------------------------------------------------------------------------------------------------
-AddDet::AddDet(const QDomElement &xml, VAbstractPattern *doc, const VDetail &detail, const QString &drawName,
-               QUndoCommand *parent)
-    : VUndoCommand(xml, doc, parent), detail(detail), drawName(drawName)
+AddPiece::AddPiece(const QDomElement &xml, VAbstractPattern *doc, const VPiece &detail, const QString &drawName,
+                   QUndoCommand *parent)
+    : VUndoCommand(xml, doc, parent),
+      m_detail(detail),
+      m_drawName(drawName)
 {
     setText(tr("add detail"));
     nodeId = doc->GetParametrId(xml);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-AddDet::~AddDet()
+AddPiece::~AddPiece()
 {}
 
 //---------------------------------------------------------------------------------------------------------------------
-// cppcheck-suppress unusedFunction
-void AddDet::undo()
+void AddPiece::undo()
 {
     qCDebug(vUndo, "Undo.");
 
@@ -69,7 +62,9 @@ void AddDet::undo()
                 return;
             }
 
-            DecrementReferences(detail.getNodes());
+            DecrementReferences(m_detail.GetPath().GetNodes());
+            DecrementReferences(m_detail.GetCustomSARecords());
+            DecrementReferences(m_detail.GetInternalPaths());
         }
         else
         {
@@ -86,8 +81,7 @@ void AddDet::undo()
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-// cppcheck-suppress unusedFunction
-void AddDet::redo()
+void AddPiece::redo()
 {
     qCDebug(vUndo, "Redo.");
 
@@ -105,16 +99,16 @@ void AddDet::redo()
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QDomElement AddDet::GetDetailsSection() const
+QDomElement AddPiece::GetDetailsSection() const
 {
     QDomElement details;
-    if (drawName.isEmpty())
+    if (m_drawName.isEmpty())
     {
         doc->GetActivNodeElement(VAbstractPattern::TagDetails, details);
     }
     else
     {
-        details = doc->GetDraw(drawName).firstChildElement(VAbstractPattern::TagDetails);
+        details = doc->GetDraw(m_drawName).firstChildElement(VAbstractPattern::TagDetails);
     }
     return details;
 }
diff --git a/src/libs/vtools/undocommands/adddet.h b/src/libs/vtools/undocommands/addpiece.h
similarity index 76%
rename from src/libs/vtools/undocommands/adddet.h
rename to src/libs/vtools/undocommands/addpiece.h
index a6583cf6e..f04c6c7a6 100644
--- a/src/libs/vtools/undocommands/adddet.h
+++ b/src/libs/vtools/undocommands/addpiece.h
@@ -1,14 +1,14 @@
 /************************************************************************
  **
- **  @file   adddet.h
+ **  @file
  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   15 6, 2014
+ **  @date   6 11, 2016
  **
  **  @brief
  **  @copyright
  **  This source code is part of the Valentine project, a pattern making
  **  program, whose allow create and modeling patterns of clothing.
- **  Copyright (C) 2013-2015 Valentina project
+ **  Copyright (C) 2016 Valentina project
  **  <https://bitbucket.org/dismine/valentina> All Rights Reserved.
  **
  **  Valentina is free software: you can redistribute it and/or modify
@@ -26,8 +26,8 @@
  **
  *************************************************************************/
 
-#ifndef ADDDET_H
-#define ADDDET_H
+#ifndef ADDPIECE_H
+#define ADDPIECE_H
 
 #include <qcompilerdetection.h>
 #include <QDomElement>
@@ -36,31 +36,34 @@
 #include <QString>
 #include <QtGlobal>
 
-#include "../tools/vtooldetail.h"
-#include "vdetail.h"
+#include "../tools/vtoolseamallowance.h"
+#include "vpiece.h"
 #include "vundocommand.h"
 
 class QDomElement;
 class QUndoCommand;
 class VAbstractPattern;
 
-class AddDet : public VUndoCommand
+
+class AddPiece : public VUndoCommand
 {
     Q_OBJECT
 public:
-    AddDet(const QDomElement &xml, VAbstractPattern *doc, const VDetail &detail, const QString &drawName = QString(),
-           QUndoCommand *parent = 0);
-    virtual ~AddDet() Q_DECL_OVERRIDE;
+    AddPiece(const QDomElement &xml, VAbstractPattern *doc, const VPiece &detail, const QString &drawName = QString(),
+             QUndoCommand *parent = nullptr);
+    virtual ~AddPiece();
+
     // cppcheck-suppress unusedFunction
     virtual void undo() Q_DECL_OVERRIDE;
     // cppcheck-suppress unusedFunction
     virtual void redo() Q_DECL_OVERRIDE;
 private:
-    Q_DISABLE_COPY(AddDet)
-    VDetail detail;
-    QString drawName;
+    Q_DISABLE_COPY(AddPiece)
+
+    VPiece m_detail;
+    QString m_drawName;
 
     QDomElement GetDetailsSection() const;
 };
 
-#endif // ADDDET_H
+#endif // ADDPIECE_H
diff --git a/src/libs/vtools/undocommands/deletedetail.cpp b/src/libs/vtools/undocommands/deletepiece.cpp
similarity index 73%
rename from src/libs/vtools/undocommands/deletedetail.cpp
rename to src/libs/vtools/undocommands/deletepiece.cpp
index a9f375b26..fba723c2f 100644
--- a/src/libs/vtools/undocommands/deletedetail.cpp
+++ b/src/libs/vtools/undocommands/deletepiece.cpp
@@ -1,14 +1,14 @@
 /************************************************************************
  **
- **  @file   deletedetail.cpp
+ **  @file
  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   16 6, 2014
+ **  @date   9 11, 2016
  **
  **  @brief
  **  @copyright
  **  This source code is part of the Valentine project, a pattern making
  **  program, whose allow create and modeling patterns of clothing.
- **  Copyright (C) 2013-2015 Valentina project
+ **  Copyright (C) 2016 Valentina project
  **  <https://bitbucket.org/dismine/valentina> All Rights Reserved.
  **
  **  Valentina is free software: you can redistribute it and/or modify
@@ -26,12 +26,11 @@
  **
  *************************************************************************/
 
-#include "deletedetail.h"
+#include "deletepiece.h"
 
 #include <QDomElement>
 #include <QHash>
 
-#include "../tools/vtooldetail.h"
 #include "../ifc/ifcdef.h"
 #include "../ifc/xml/vabstractpattern.h"
 #include "../ifc/xml/vdomdocument.h"
@@ -39,12 +38,17 @@
 #include "../vmisc/def.h"
 #include "../tools/vdatatool.h"
 #include "vundocommand.h"
+#include "../vpatterndb/vpiecenode.h"
+#include "../vpatterndb/vpiecepath.h"
 
 class QUndoCommand;
 
 //---------------------------------------------------------------------------------------------------------------------
-DeleteDetail::DeleteDetail(VAbstractPattern *doc, quint32 id, const VDetail &detail, QUndoCommand *parent)
-    : VUndoCommand(QDomElement(), doc, parent), parentNode(QDomNode()), siblingId(NULL_ID), detail(detail)
+DeletePiece::DeletePiece(VAbstractPattern *doc, quint32 id, const VPiece &detail, QUndoCommand *parent)
+    : VUndoCommand(QDomElement(), doc, parent),
+      m_parentNode(),
+      m_siblingId(NULL_ID),
+      m_detail(detail)
 {
     setText(tr("delete tool"));
     nodeId = id;
@@ -52,16 +56,16 @@ DeleteDetail::DeleteDetail(VAbstractPattern *doc, quint32 id, const VDetail &det
     if (domElement.isElement())
     {
         xml = domElement.cloneNode().toElement();
-        parentNode = domElement.parentNode();
+        m_parentNode = domElement.parentNode();
         QDomNode previousDetail = domElement.previousSibling();
         if (previousDetail.isNull())
         {
-            siblingId = NULL_ID;
+            m_siblingId = NULL_ID;
         }
         else
         {
             // Better save id of previous detail instead of reference to node.
-            siblingId = doc->GetParametrUInt(previousDetail.toElement(), VAbstractPattern::AttrId, NULL_ID_STR);
+            m_siblingId = doc->GetParametrUInt(previousDetail.toElement(), VAbstractPattern::AttrId, NULL_ID_STR);
         }
     }
     else
@@ -72,37 +76,37 @@ DeleteDetail::DeleteDetail(VAbstractPattern *doc, quint32 id, const VDetail &det
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-DeleteDetail::~DeleteDetail()
+DeletePiece::~DeletePiece()
 {}
 
 //---------------------------------------------------------------------------------------------------------------------
-void DeleteDetail::undo()
+void DeletePiece::undo()
 {
     qCDebug(vUndo, "Undo.");
 
-    UndoDeleteAfterSibling(parentNode, siblingId);
+    UndoDeleteAfterSibling(m_parentNode, m_siblingId);
     emit NeedFullParsing();
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void DeleteDetail::redo()
+void DeletePiece::redo()
 {
     qCDebug(vUndo, "Redo.");
 
     QDomElement domElement = doc->elementById(nodeId);
     if (domElement.isElement())
     {
-        parentNode.removeChild(domElement);
+        m_parentNode.removeChild(domElement);
 
         // UnionDetails delete two old details and create one new.
         // So when UnionDetail delete detail we can't use FullParsing. So we hide detail on scene directly.
-        QHash<quint32, VDataTool*>* tools = doc->getTools();
-        SCASSERT(tools != nullptr)
-        VToolDetail *toolDet = qobject_cast<VToolDetail*>(tools->value(nodeId));
-        SCASSERT(toolDet != nullptr)
+        VToolSeamAllowance *toolDet = qobject_cast<VToolSeamAllowance*>(doc->getTool(nodeId));
+        SCASSERT(toolDet != nullptr);
         toolDet->hide();
 
-        DecrementReferences(detail.getNodes());
+        DecrementReferences(m_detail.GetPath().GetNodes());
+        DecrementReferences(m_detail.GetCustomSARecords());
+        DecrementReferences(m_detail.GetInternalPaths());
         emit NeedFullParsing(); // Doesn't work when UnionDetail delete detail.
     }
     else
diff --git a/src/libs/vtools/undocommands/deletedetail.h b/src/libs/vtools/undocommands/deletepiece.h
similarity index 68%
rename from src/libs/vtools/undocommands/deletedetail.h
rename to src/libs/vtools/undocommands/deletepiece.h
index abbe30b7e..b06a77613 100644
--- a/src/libs/vtools/undocommands/deletedetail.h
+++ b/src/libs/vtools/undocommands/deletepiece.h
@@ -1,14 +1,14 @@
 /************************************************************************
  **
- **  @file   deletedetail.h
+ **  @file
  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   16 6, 2014
+ **  @date   9 11, 2016
  **
  **  @brief
  **  @copyright
  **  This source code is part of the Valentine project, a pattern making
  **  program, whose allow create and modeling patterns of clothing.
- **  Copyright (C) 2013-2015 Valentina project
+ **  Copyright (C) 2016 Valentina project
  **  <https://bitbucket.org/dismine/valentina> All Rights Reserved.
  **
  **  Valentina is free software: you can redistribute it and/or modify
@@ -26,37 +26,34 @@
  **
  *************************************************************************/
 
-#ifndef DELETEDETAIL_H
-#define DELETEDETAIL_H
+#ifndef DELETEPIECE_H
+#define DELETEPIECE_H
 
-#include <qcompilerdetection.h>
-#include <QDomNode>
-#include <QMetaObject>
-#include <QObject>
-#include <QString>
 #include <QtGlobal>
 
-#include "../tools/vtooldetail.h"
-#include "vdetail.h"
+#include "../tools/vtoolseamallowance.h"
+#include "vpiece.h"
 #include "vundocommand.h"
 
 class QGraphicsItem;
 class QUndoCommand;
 class VAbstractPattern;
 
-class DeleteDetail : public VUndoCommand
+class DeletePiece : public VUndoCommand
 {
     Q_OBJECT
 public:
-    DeleteDetail(VAbstractPattern *doc, quint32 id, const VDetail &detail, QUndoCommand *parent = 0);
-    virtual ~DeleteDetail() Q_DECL_OVERRIDE;
+    DeletePiece(VAbstractPattern *doc, quint32 id, const VPiece &m_detail, QUndoCommand *parent = nullptr);
+    virtual ~DeletePiece();
+
     virtual void undo() Q_DECL_OVERRIDE;
     virtual void redo() Q_DECL_OVERRIDE;
 private:
-    Q_DISABLE_COPY(DeleteDetail)
-    QDomNode parentNode;
-    quint32 siblingId;
-    VDetail detail;
+    Q_DISABLE_COPY(DeletePiece)
+
+    QDomNode m_parentNode;
+    quint32  m_siblingId;
+    VPiece   m_detail;
 };
 
-#endif // DELETEDETAIL_H
+#endif // DELETEPIECE_H
diff --git a/src/libs/vtools/undocommands/movedetail.cpp b/src/libs/vtools/undocommands/movepiece.cpp
similarity index 77%
rename from src/libs/vtools/undocommands/movedetail.cpp
rename to src/libs/vtools/undocommands/movepiece.cpp
index 333c331a0..ac5b324ac 100644
--- a/src/libs/vtools/undocommands/movedetail.cpp
+++ b/src/libs/vtools/undocommands/movepiece.cpp
@@ -26,7 +26,7 @@
  **
  *************************************************************************/
 
-#include "movedetail.h"
+#include "movepiece.h"
 
 #include <QDomElement>
 
@@ -42,9 +42,14 @@ class QDomElement;
 class QUndoCommand;
 
 //---------------------------------------------------------------------------------------------------------------------
-MoveDetail::MoveDetail(VAbstractPattern *doc, const double &x, const double &y, const quint32 &id,
-                       QGraphicsScene *scene, QUndoCommand *parent)
-    : VUndoCommand(QDomElement(), doc, parent), oldX(0.0), oldY(0.0), newX(x), newY(y), scene(scene)
+MovePiece::MovePiece(VAbstractPattern *doc, const double &x, const double &y, const quint32 &id,
+                     QGraphicsScene *scene, QUndoCommand *parent)
+    : VUndoCommand(QDomElement(), doc, parent),
+      m_oldX(0.0),
+      m_oldY(0.0),
+      m_newX(x),
+      m_newY(y),
+      m_scene(scene)
 {
     setText(QObject::tr("move detail"));
     nodeId = id;
@@ -53,8 +58,8 @@ MoveDetail::MoveDetail(VAbstractPattern *doc, const double &x, const double &y,
     QDomElement domElement = doc->elementById(id);
     if (domElement.isElement())
     {
-        oldX = qApp->toPixel(doc->GetParametrDouble(domElement, AttrMx, "0.0"));
-        oldY = qApp->toPixel(doc->GetParametrDouble(domElement, AttrMy, "0.0"));
+        m_oldX = qApp->toPixel(doc->GetParametrDouble(domElement, AttrMx, "0.0"));
+        m_oldY = qApp->toPixel(doc->GetParametrDouble(domElement, AttrMy, "0.0"));
     }
     else
     {
@@ -64,18 +69,18 @@ MoveDetail::MoveDetail(VAbstractPattern *doc, const double &x, const double &y,
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-MoveDetail::~MoveDetail()
+MovePiece::~MovePiece()
 {}
 
 //---------------------------------------------------------------------------------------------------------------------
-void MoveDetail::undo()
+void MovePiece::undo()
 {
     qCDebug(vUndo, "Undo.");
 
     QDomElement domElement = doc->elementById(nodeId);
     if (domElement.isElement())
     {
-        SaveCoordinates(domElement, oldX, oldY);
+        SaveCoordinates(domElement, m_oldX, m_oldY);
 
         emit NeedLiteParsing(Document::LiteParse);
     }
@@ -87,14 +92,14 @@ void MoveDetail::undo()
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void MoveDetail::redo()
+void MovePiece::redo()
 {
     qCDebug(vUndo, "Redo.");
 
     QDomElement domElement = doc->elementById(nodeId);
     if (domElement.isElement())
     {
-        SaveCoordinates(domElement, newX, newY);
+        SaveCoordinates(domElement, m_newX, m_newY);
 
         if (redoFlag)
         {
@@ -102,7 +107,7 @@ void MoveDetail::redo()
         }
         else
         {
-            VMainGraphicsView::NewSceneRect(scene, qApp->getSceneView());
+            VMainGraphicsView::NewSceneRect(m_scene, qApp->getSceneView());
         }
         redoFlag = true;
     }
@@ -115,9 +120,9 @@ void MoveDetail::redo()
 
 //---------------------------------------------------------------------------------------------------------------------
 // cppcheck-suppress unusedFunction
-bool MoveDetail::mergeWith(const QUndoCommand *command)
+bool MovePiece::mergeWith(const QUndoCommand *command)
 {
-    const MoveDetail *moveCommand = static_cast<const MoveDetail *>(command);
+    const MovePiece *moveCommand = static_cast<const MovePiece *>(command);
     SCASSERT(moveCommand != nullptr)
     const quint32 id = moveCommand->getDetId();
 
@@ -126,19 +131,19 @@ bool MoveDetail::mergeWith(const QUndoCommand *command)
         return false;
     }
 
-    newX = moveCommand->getNewX();
-    newY = moveCommand->getNewY();
+    m_newX = moveCommand->getNewX();
+    m_newY = moveCommand->getNewY();
     return true;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-int MoveDetail::id() const
+int MovePiece::id() const
 {
-    return static_cast<int>(UndoCommand::MoveDetail);
+    return static_cast<int>(UndoCommand::MovePiece);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void MoveDetail::SaveCoordinates(QDomElement &domElement, double x, double y)
+void MovePiece::SaveCoordinates(QDomElement &domElement, double x, double y)
 {
     doc->SetAttribute(domElement, AttrMx, QString().setNum(qApp->fromPixel(x)));
     doc->SetAttribute(domElement, AttrMy, QString().setNum(qApp->fromPixel(y)));
diff --git a/src/libs/vtools/undocommands/movedetail.h b/src/libs/vtools/undocommands/movepiece.h
similarity index 78%
rename from src/libs/vtools/undocommands/movedetail.h
rename to src/libs/vtools/undocommands/movepiece.h
index 37c0d1db2..95d0b5535 100644
--- a/src/libs/vtools/undocommands/movedetail.h
+++ b/src/libs/vtools/undocommands/movepiece.h
@@ -42,13 +42,14 @@ class QGraphicsScene;
 class QUndoCommand;
 class VAbstractPattern;
 
-class MoveDetail : public VUndoCommand
+class MovePiece : public VUndoCommand
 {
     Q_OBJECT
 public:
-    MoveDetail(VAbstractPattern *doc, const double &x, const double &y, const quint32 &id, QGraphicsScene *scene,
-               QUndoCommand *parent = 0);
-    virtual ~MoveDetail() Q_DECL_OVERRIDE;
+    MovePiece(VAbstractPattern *doc, const double &x, const double &y, const quint32 &id, QGraphicsScene *scene,
+               QUndoCommand *parent = nullptr);
+    virtual ~MovePiece();
+
     virtual void undo() Q_DECL_OVERRIDE;
     virtual void redo() Q_DECL_OVERRIDE;
     // cppcheck-suppress unusedFunction
@@ -58,31 +59,33 @@ public:
     double       getNewX() const;
     double       getNewY() const;
 private:
-    Q_DISABLE_COPY(MoveDetail)
-    double   oldX;
-    double   oldY;
-    double   newX;
-    double   newY;
-    QGraphicsScene *scene;
-    void         SaveCoordinates(QDomElement &domElement, double x, double y);
+    Q_DISABLE_COPY(MovePiece)
+
+    double          m_oldX;
+    double          m_oldY;
+    double          m_newX;
+    double          m_newY;
+    QGraphicsScene *m_scene;
+
+    void SaveCoordinates(QDomElement &domElement, double x, double y);
 };
 
 //---------------------------------------------------------------------------------------------------------------------
-inline quint32 MoveDetail::getDetId() const
+inline quint32 MovePiece::getDetId() const
 {
     return nodeId;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-inline double MoveDetail::getNewX() const
+inline double MovePiece::getNewX() const
 {
-    return newX;
+    return m_newX;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-inline double MoveDetail::getNewY() const
+inline double MovePiece::getNewY() const
 {
-    return newY;
+    return m_newY;
 }
 
 #endif // MOVEDETAIL_H
diff --git a/src/libs/vtools/undocommands/savedetailoptions.cpp b/src/libs/vtools/undocommands/savedetailoptions.cpp
deleted file mode 100644
index fa8ae38e9..000000000
--- a/src/libs/vtools/undocommands/savedetailoptions.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/************************************************************************
- **
- **  @file   savedetailoptions.cpp
- **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   12 6, 2014
- **
- **  @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
- **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
- **
- *************************************************************************/
-
-#include "savedetailoptions.h"
-
-#include <QDomElement>
-#include <QPointF>
-#include <QUndoCommand>
-#include <QDebug>
-
-#include "../ifc/xml/vabstractpattern.h"
-#include "../ifc/ifcdef.h"
-#include "../vmisc/logging.h"
-#include "../vmisc/def.h"
-#include "../vpatterndb/vpatterninfogeometry.h"
-#include "../vpatterndb/vpatternpiecedata.h"
-#include "../vpatterndb/vgrainlinegeometry.h"
-#include "../tools/vtooldetail.h"
-#include "vundocommand.h"
-
-class QDomElement;
-class QUndoCommand;
-
-//---------------------------------------------------------------------------------------------------------------------
-SaveDetailOptions::SaveDetailOptions(const VDetail &oldDet, const VDetail &newDet, VAbstractPattern *doc,
-                                     const quint32 &id, QGraphicsScene *scene, QUndoCommand *parent)
-    : VUndoCommand(QDomElement(), doc, parent), oldDet(oldDet), newDet(newDet), scene(scene)
-{
-    setText(tr("save detail option"));
-    nodeId = id;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-SaveDetailOptions::~SaveDetailOptions()
-{}
-
-//---------------------------------------------------------------------------------------------------------------------
-void SaveDetailOptions::undo()
-{
-    qCDebug(vUndo, "Undo.");
-
-    QDomElement domElement = doc->elementById(nodeId);
-    if (domElement.isElement())
-    {
-        SaveDet(domElement, oldDet);
-        doc->RemoveAllChildren(domElement);
-        SavePatternPieceData(domElement, oldDet);
-        SavePatternInfo(domElement, oldDet);
-        SaveGrainline(domElement, oldDet);
-
-        for (int i = 0; i < oldDet.CountNode(); ++i)
-        {
-           VToolDetail::AddNode(doc, domElement, oldDet.at(i));
-        }
-        IncrementReferences(oldDet.Missing(newDet));
-        emit NeedLiteParsing(Document::LiteParse);
-    }
-    else
-    {
-        qCDebug(vUndo, "Can't find detail with id = %u.", nodeId);
-        return;
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void SaveDetailOptions::redo()
-{
-    qCDebug(vUndo, "Redo.");
-
-    QDomElement domElement = doc->elementById(nodeId);
-    if (domElement.isElement())
-    {
-        SaveDet(domElement, newDet);
-        doc->RemoveAllChildren(domElement);
-        SavePatternPieceData(domElement, newDet);
-        SavePatternInfo(domElement, newDet);
-        SaveGrainline(domElement, newDet);
-
-        for (int i = 0; i < newDet.CountNode(); ++i)
-        {
-           VToolDetail::AddNode(doc, domElement, newDet.at(i));
-        }
-
-        DecrementReferences(oldDet.Missing(newDet));
-        emit NeedLiteParsing(Document::LiteParse);
-    }
-    else
-    {
-        qCDebug(vUndo, "Can't find detail with id = %u.", nodeId);
-        return;
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-bool SaveDetailOptions::mergeWith(const QUndoCommand *command)
-{
-    const SaveDetailOptions *saveCommand = static_cast<const SaveDetailOptions *>(command);
-    SCASSERT(saveCommand != nullptr)
-    const quint32 id = saveCommand->getDetId();
-
-    if (id != nodeId || text() != command->text())
-    {
-        return false;
-    }
-
-    newDet = saveCommand->getNewDet();
-    return true;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-int SaveDetailOptions::id() const
-{
-    return static_cast<int>(UndoCommand::SaveDetailOptions);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void SaveDetailOptions::SaveDet(QDomElement &domElement, const VDetail &det)
-{
-    doc->SetAttribute(domElement, AttrName, det.getName());
-    doc->SetAttribute(domElement, VToolDetail::AttrSupplement, QString().setNum(det.getSeamAllowance()));
-    doc->SetAttribute(domElement, VToolDetail::AttrClosed, QString().setNum(det.getClosed()));
-    doc->SetAttribute(domElement, VToolDetail::AttrWidth, QString().setNum(det.getWidth()));
-    doc->SetAttribute(domElement, VToolDetail::AttrForbidFlipping, QString().setNum(det.getForbidFlipping()));
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void SaveDetailOptions::SavePatternPieceData(QDomElement &domElement, const VDetail &det)
-{
-    QDomElement domData = doc->createElement(VAbstractPattern::TagData);
-    const VPatternPieceData& data = det.GetPatternPieceData();
-    doc->SetAttribute(domData, VAbstractPattern::AttrLetter, data.GetLetter());
-    doc->SetAttribute(domData, VAbstractPattern::AttrVisible, data.IsVisible() == true? trueStr : falseStr);
-    doc->SetAttribute(domData, AttrMx, data.GetPos().x());
-    doc->SetAttribute(domData, AttrMy, data.GetPos().y());
-    doc->SetAttribute(domData, VToolDetail::AttrWidth, data.GetLabelWidth());
-    doc->SetAttribute(domData, VToolDetail::AttrHeight, data.GetLabelHeight());
-    doc->SetAttribute(domData, VToolDetail::AttrFont, data.GetFontSize());
-    doc->SetAttribute(domData, VToolDetail::AttrRotation, data.GetRotation());
-
-    for (int i = 0; i < data.GetMCPCount(); ++i)
-    {
-        MaterialCutPlacement mcp = data.GetMCP(i);
-        QDomElement domMCP = doc->createElement(VAbstractPattern::TagMCP);
-        doc->SetAttribute(domMCP, VAbstractPattern::AttrMaterial, int(mcp.m_eMaterial));
-        if (mcp.m_eMaterial == MaterialType::mtUserDefined)
-        {
-            qDebug() << "USER DEFINED MATERIAL";
-            doc->SetAttribute(domMCP, VAbstractPattern::AttrUserDefined, mcp.m_qsMaterialUserDef);
-        }
-        else
-        {
-            qDebug() << "PREDEFINED MATERIAL";
-            domMCP.removeAttribute(VAbstractPattern::AttrUserDefined);
-        }
-        doc->SetAttribute(domMCP, VAbstractPattern::AttrCutNumber, mcp.m_iCutNumber);
-        doc->SetAttribute(domMCP, VAbstractPattern::AttrPlacement, int(mcp.m_ePlacement));
-        domData.appendChild(domMCP);
-    }
-    domElement.appendChild(domData);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void SaveDetailOptions::SavePatternInfo(QDomElement &domElement, const VDetail &det)
-{
-    QDomElement domData = doc->createElement(VAbstractPattern::TagPatternInfo);
-    const VPatternInfoGeometry& data = det.GetPatternInfo();
-    doc->SetAttribute(domData, VAbstractPattern::AttrVisible, data.IsVisible() == true? trueStr : falseStr);
-    doc->SetAttribute(domData, AttrMx, data.GetPos().x());
-    doc->SetAttribute(domData, AttrMy, data.GetPos().y());
-    doc->SetAttribute(domData, VToolDetail::AttrWidth, data.GetLabelWidth());
-    doc->SetAttribute(domData, VToolDetail::AttrHeight, data.GetLabelHeight());
-    doc->SetAttribute(domData, VToolDetail::AttrFont, data.GetFontSize());
-    doc->SetAttribute(domData, VToolDetail::AttrRotation, data.GetRotation());
-
-    domElement.appendChild(domData);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void SaveDetailOptions::SaveGrainline(QDomElement &domElement, const VDetail &det)
-{
-    QDomElement domData = doc->createElement(VAbstractPattern::TagGrainline);
-    const VGrainlineGeometry& glGeom = det.GetGrainlineGeometry();
-    doc->SetAttribute(domData, VAbstractPattern::AttrVisible, glGeom.IsVisible() == true? trueStr : falseStr);
-    doc->SetAttribute(domData, AttrMx, glGeom.GetPos().x());
-    doc->SetAttribute(domData, AttrMy, glGeom.GetPos().y());
-    doc->SetAttribute(domData, AttrLength, glGeom.GetLength());
-    doc->SetAttribute(domData, VToolDetail::AttrRotation, glGeom.GetRotation());
-    doc->SetAttribute(domData, VAbstractPattern::AttrArrows, int(glGeom.GetArrowType()));
-
-    domElement.appendChild(domData);
-}
diff --git a/src/libs/vtools/undocommands/savepieceoptions.cpp b/src/libs/vtools/undocommands/savepieceoptions.cpp
new file mode 100644
index 000000000..daeef8aab
--- /dev/null
+++ b/src/libs/vtools/undocommands/savepieceoptions.cpp
@@ -0,0 +1,144 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   9 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "savepieceoptions.h"
+
+#include <QDomElement>
+#include <QPointF>
+#include <QUndoCommand>
+#include <QDebug>
+
+#include "../ifc/xml/vabstractpattern.h"
+#include "../ifc/ifcdef.h"
+#include "../vmisc/logging.h"
+#include "../vmisc/def.h"
+#include "../vpatterndb/vpiecenode.h"
+#include "../vpatterndb/vpatterninfogeometry.h"
+#include "../vpatterndb/vpatternpiecedata.h"
+#include "../vpatterndb/vgrainlinegeometry.h"
+#include "../tools/vtoolseamallowance.h"
+#include "vundocommand.h"
+
+class QDomElement;
+class QUndoCommand;
+
+//---------------------------------------------------------------------------------------------------------------------
+SavePieceOptions::SavePieceOptions(const VPiece &oldDet, const VPiece &newDet, VAbstractPattern *doc, quint32 id,
+                                   QUndoCommand *parent)
+    : VUndoCommand(QDomElement(), doc, parent),
+      m_oldDet(oldDet),
+      m_newDet(newDet)
+{
+    setText(tr("save detail option"));
+    nodeId = id;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+SavePieceOptions::~SavePieceOptions()
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+void SavePieceOptions::undo()
+{
+    qCDebug(vUndo, "Undo.");
+
+    QDomElement domElement = doc->elementById(nodeId);
+    if (domElement.isElement())
+    {
+        VToolSeamAllowance::AddAttributes(doc, domElement, nodeId, m_oldDet);
+        doc->RemoveAllChildren(domElement);//Very important to clear before rewrite
+        VToolSeamAllowance::AddPatternPieceData(doc, domElement, m_oldDet);
+        VToolSeamAllowance::AddPatternInfo(doc, domElement, m_oldDet);
+        VToolSeamAllowance::AddGrainline(doc, domElement, m_oldDet);
+        VToolSeamAllowance::AddNodes(doc, domElement, m_oldDet);
+        VToolSeamAllowance::AddCSARecords(doc, domElement, m_oldDet.GetCustomSARecords());
+        VToolSeamAllowance::AddInternalPaths(doc, domElement, m_oldDet.GetInternalPaths());
+
+        IncrementReferences(m_oldDet.MissingNodes(m_newDet));
+        IncrementReferences(m_oldDet.MissingCSAPath(m_newDet));
+        IncrementReferences(m_oldDet.MissingInternalPaths(m_newDet));
+        emit NeedLiteParsing(Document::LiteParse);
+    }
+    else
+    {
+        qCDebug(vUndo, "Can't find detail with id = %u.", nodeId);
+        return;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void SavePieceOptions::redo()
+{
+    qCDebug(vUndo, "Redo.");
+
+    QDomElement domElement = doc->elementById(nodeId);
+    if (domElement.isElement())
+    {
+        VToolSeamAllowance::AddAttributes(doc, domElement, nodeId, m_newDet);
+        doc->RemoveAllChildren(domElement);//Very important to clear before rewrite
+        VToolSeamAllowance::AddPatternPieceData(doc, domElement, m_newDet);
+        VToolSeamAllowance::AddPatternInfo(doc, domElement, m_newDet);
+        VToolSeamAllowance::AddGrainline(doc, domElement, m_newDet);
+        VToolSeamAllowance::AddNodes(doc, domElement, m_newDet);
+        VToolSeamAllowance::AddCSARecords(doc, domElement, m_newDet.GetCustomSARecords());
+        VToolSeamAllowance::AddInternalPaths(doc, domElement, m_newDet.GetInternalPaths());
+
+        DecrementReferences(m_oldDet.MissingNodes(m_newDet));
+        DecrementReferences(m_oldDet.MissingCSAPath(m_newDet));
+        DecrementReferences(m_oldDet.MissingInternalPaths(m_newDet));
+
+        emit NeedLiteParsing(Document::LiteParse);
+    }
+    else
+    {
+        qCDebug(vUndo, "Can't find detail with id = %u.", nodeId);
+        return;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool SavePieceOptions::mergeWith(const QUndoCommand *command)
+{
+    const SavePieceOptions *saveCommand = static_cast<const SavePieceOptions *>(command);
+    SCASSERT(saveCommand != nullptr);
+    const quint32 id = saveCommand->DetId();
+
+    if (id != nodeId)
+    {
+        return false;
+    }
+
+    m_newDet = saveCommand->NewDet();
+    return true;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+int SavePieceOptions::id() const
+{
+    return static_cast<int>(UndoCommand::SavePieceOptions);
+}
diff --git a/src/libs/vtools/undocommands/savedetailoptions.h b/src/libs/vtools/undocommands/savepieceoptions.h
similarity index 56%
rename from src/libs/vtools/undocommands/savedetailoptions.h
rename to src/libs/vtools/undocommands/savepieceoptions.h
index 5b4cbc058..dd4b7f8cb 100644
--- a/src/libs/vtools/undocommands/savedetailoptions.h
+++ b/src/libs/vtools/undocommands/savepieceoptions.h
@@ -1,14 +1,14 @@
 /************************************************************************
  **
- **  @file   savedetailoptions.h
+ **  @file
  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   12 6, 2014
+ **  @date   9 11, 2016
  **
  **  @brief
  **  @copyright
  **  This source code is part of the Valentine project, a pattern making
  **  program, whose allow create and modeling patterns of clothing.
- **  Copyright (C) 2013-2015 Valentina project
+ **  Copyright (C) 2016 Valentina project
  **  <https://bitbucket.org/dismine/valentina> All Rights Reserved.
  **
  **  Valentina is free software: you can redistribute it and/or modify
@@ -26,58 +26,47 @@
  **
  *************************************************************************/
 
-#ifndef SAVEDETAILOPTIONS_H
-#define SAVEDETAILOPTIONS_H
+#ifndef SAVEPIECEOPTIONS_H
+#define SAVEPIECEOPTIONS_H
 
-#include <qcompilerdetection.h>
-#include <QMetaObject>
-#include <QObject>
-#include <QString>
 #include <QtGlobal>
 
-#include "../tools/vtooldetail.h"
-#include "vdetail.h"
+#include "vpiece.h"
 #include "vundocommand.h"
 
-class QDomElement;
-class QGraphicsScene;
 class QUndoCommand;
 class VAbstractPattern;
 
-class SaveDetailOptions : public VUndoCommand
+class SavePieceOptions : public VUndoCommand
 {
-    Q_OBJECT
 public:
-    SaveDetailOptions(const VDetail &oldDet, const VDetail &newDet, VAbstractPattern *doc, const quint32 &id,
-                      QGraphicsScene *scene, QUndoCommand *parent = 0);
-    virtual ~SaveDetailOptions() Q_DECL_OVERRIDE;
+    SavePieceOptions(const VPiece &m_oldDet, const VPiece &m_newDet, VAbstractPattern *doc, quint32 id,
+                     QUndoCommand *parent = nullptr);
+    virtual ~SavePieceOptions();
+
     virtual void undo() Q_DECL_OVERRIDE;
     virtual void redo() Q_DECL_OVERRIDE;
     virtual bool mergeWith(const QUndoCommand *command) Q_DECL_OVERRIDE;
     virtual int  id() const Q_DECL_OVERRIDE;
-    quint32      getDetId() const;
-    VDetail      getNewDet() const;
+    quint32      DetId() const;
+    VPiece       NewDet() const;
 private:
-    Q_DISABLE_COPY(SaveDetailOptions)
-    const VDetail oldDet;
-    VDetail       newDet;
-    QGraphicsScene *scene;
-    void         SaveDet(QDomElement &domElement, const VDetail &det);
-    void         SavePatternPieceData(QDomElement &domElement, const VDetail &det);
-    void         SavePatternInfo(QDomElement &domElement, const VDetail &det);
-    void         SaveGrainline(QDomElement &domElement, const VDetail &det);
+    Q_DISABLE_COPY(SavePieceOptions)
+
+    const VPiece    m_oldDet;
+    VPiece          m_newDet;
 };
 
 //---------------------------------------------------------------------------------------------------------------------
-inline quint32 SaveDetailOptions::getDetId() const
+inline quint32 SavePieceOptions::DetId() const
 {
     return nodeId;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-inline VDetail SaveDetailOptions::getNewDet() const
+inline VPiece SavePieceOptions::NewDet() const
 {
-    return newDet;
+    return m_newDet;
 }
 
-#endif // SAVEDETAILOPTIONS_H
+#endif // SAVEPIECEOPTIONS_H
diff --git a/src/libs/vtools/undocommands/savepiecepathoptions.cpp b/src/libs/vtools/undocommands/savepiecepathoptions.cpp
new file mode 100644
index 000000000..0c1520d76
--- /dev/null
+++ b/src/libs/vtools/undocommands/savepiecepathoptions.cpp
@@ -0,0 +1,139 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   26 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "savepiecepathoptions.h"
+
+#include <QDomElement>
+#include <QUndoCommand>
+#include <QDebug>
+
+#include "../ifc/xml/vabstractpattern.h"
+#include "../vmisc/logging.h"
+#include "../tools/nodeDetails/vtoolpiecepath.h"
+
+class QDomElement;
+class QUndoCommand;
+
+//---------------------------------------------------------------------------------------------------------------------
+SavePiecePathOptions::SavePiecePathOptions(const VPiecePath &oldPath, const VPiecePath &newPath,
+                                           VAbstractPattern *doc, VContainer *data, quint32 id,
+                                           QUndoCommand *parent)
+    : VUndoCommand(QDomElement(), doc, parent),
+      m_oldPath(oldPath),
+      m_newPath(newPath),
+      m_data(data)
+{
+    setText(tr("save path options"));
+    nodeId = id;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+SavePiecePathOptions::~SavePiecePathOptions()
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+void SavePiecePathOptions::undo()
+{
+    qCDebug(vUndo, "Undo.");
+
+    QDomElement domElement = doc->elementById(nodeId);
+    if (domElement.isElement())
+    {
+        VToolPiecePath::AddAttributes(doc, domElement, nodeId, m_oldPath);
+        doc->RemoveAllChildren(domElement);//Very important to clear before rewrite
+        VToolPiecePath::AddNodes(doc, domElement, m_oldPath);
+
+        IncrementReferences(m_oldPath.MissingNodes(m_newPath));
+
+        SCASSERT(m_data);
+        m_data->UpdatePiecePath(nodeId, m_oldPath);
+    }
+    else
+    {
+        qCDebug(vUndo, "Can't find path with id = %u.", nodeId);
+        return;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void SavePiecePathOptions::redo()
+{
+    qCDebug(vUndo, "Redo.");
+
+    QDomElement domElement = doc->elementById(nodeId);
+    if (domElement.isElement())
+    {
+        VToolPiecePath::AddAttributes(doc, domElement, nodeId, m_newPath);
+        doc->RemoveAllChildren(domElement);//Very important to clear before rewrite
+        VToolPiecePath::AddNodes(doc, domElement, m_newPath);
+
+        DecrementReferences(m_oldPath.MissingNodes(m_newPath));
+
+        SCASSERT(m_data);
+        m_data->UpdatePiecePath(nodeId, m_newPath);
+    }
+    else
+    {
+        qCDebug(vUndo, "Can't find path with id = %u.", nodeId);
+        return;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool SavePiecePathOptions::mergeWith(const QUndoCommand *command)
+{
+    const SavePiecePathOptions *saveCommand = static_cast<const SavePiecePathOptions *>(command);
+    SCASSERT(saveCommand != nullptr);
+    const quint32 id = saveCommand->PathId();
+
+    if (id != nodeId)
+    {
+        return false;
+    }
+
+    m_newPath = saveCommand->NewPath();
+    return true;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+int SavePiecePathOptions::id() const
+{
+    return static_cast<int>(UndoCommand::SavePiecePathOptions);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+quint32 SavePiecePathOptions::PathId() const
+{
+    return nodeId;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPiecePath SavePiecePathOptions::NewPath() const
+{
+    return m_newPath;
+}
diff --git a/src/libs/vtools/undocommands/savepiecepathoptions.h b/src/libs/vtools/undocommands/savepiecepathoptions.h
new file mode 100644
index 000000000..f869df012
--- /dev/null
+++ b/src/libs/vtools/undocommands/savepiecepathoptions.h
@@ -0,0 +1,62 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   26 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef SAVEPIECEPATHOPTIONS_H
+#define SAVEPIECEPATHOPTIONS_H
+
+#include <QtGlobal>
+
+#include "../vpatterndb/vpiecepath.h"
+#include "vundocommand.h"
+
+class QUndoCommand;
+class VAbstractPattern;
+
+class SavePiecePathOptions : public VUndoCommand
+{
+public:
+    SavePiecePathOptions(const VPiecePath &oldPath, const VPiecePath &newPath, VAbstractPattern *doc,
+                         VContainer *data, quint32 id, QUndoCommand *parent = nullptr);
+    virtual ~SavePiecePathOptions();
+
+    virtual void undo() Q_DECL_OVERRIDE;
+    virtual void redo() Q_DECL_OVERRIDE;
+    virtual bool mergeWith(const QUndoCommand *command) Q_DECL_OVERRIDE;
+    virtual int  id() const Q_DECL_OVERRIDE;
+    quint32      PathId() const;
+    VPiecePath   NewPath() const;
+private:
+    Q_DISABLE_COPY(SavePiecePathOptions)
+
+    const VPiecePath m_oldPath;
+    VPiecePath       m_newPath;
+
+    VContainer *m_data;
+};
+
+#endif // SAVEPIECEPATHOPTIONS_H
diff --git a/src/libs/vtools/undocommands/toggledetailinlayout.cpp b/src/libs/vtools/undocommands/togglepieceinlayout.cpp
similarity index 83%
rename from src/libs/vtools/undocommands/toggledetailinlayout.cpp
rename to src/libs/vtools/undocommands/togglepieceinlayout.cpp
index 88aa7daf2..7a3b65016 100644
--- a/src/libs/vtools/undocommands/toggledetailinlayout.cpp
+++ b/src/libs/vtools/undocommands/togglepieceinlayout.cpp
@@ -26,7 +26,7 @@
  **
  *************************************************************************/
 
-#include "toggledetailinlayout.h"
+#include "togglepieceinlayout.h"
 
 #include <QDomElement>
 #include <QHash>
@@ -38,30 +38,30 @@
 #include "../vmisc/def.h"
 #include "../vmisc/logging.h"
 #include "../vpatterndb/vcontainer.h"
-#include "../vpatterndb/vdetail.h"
+#include "../vpatterndb/vpiece.h"
 #include "vundocommand.h"
 
 class QUndoCommand;
 
 //---------------------------------------------------------------------------------------------------------------------
-ToggleDetailInLayout::ToggleDetailInLayout(quint32 id, bool state, VContainer *data, VAbstractPattern *doc,
+TogglePieceInLayout::TogglePieceInLayout(quint32 id, bool state, VContainer *data, VAbstractPattern *doc,
                                            QUndoCommand *parent)
     : VUndoCommand(QDomElement(), doc, parent),
       m_id(id),
       m_data(data),
-      m_oldState(m_data->DataDetails()->value(m_id).IsInLayout()),
+      m_oldState(m_data->DataPieces()->value(m_id).IsInLayout()),
       m_newState(state)
 {
     setText(tr("detail in layout list"));
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-ToggleDetailInLayout::~ToggleDetailInLayout()
+TogglePieceInLayout::~TogglePieceInLayout()
 {
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void ToggleDetailInLayout::undo()
+void TogglePieceInLayout::undo()
 {
     qCDebug(vUndo, "ToggleDetailInLayout::undo().");
 
@@ -72,7 +72,7 @@ void ToggleDetailInLayout::undo()
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void ToggleDetailInLayout::redo()
+void TogglePieceInLayout::redo()
 {
     qCDebug(vUndo, "ToggleDetailInLayout::redo().");
 
@@ -83,25 +83,25 @@ void ToggleDetailInLayout::redo()
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-int ToggleDetailInLayout::id() const
+int TogglePieceInLayout::id() const
 {
-    return static_cast<int>(UndoCommand::ToggleDetailInLayout);
+    return static_cast<int>(UndoCommand::TogglePieceInLayout);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-quint32 ToggleDetailInLayout::getDetId() const
+quint32 TogglePieceInLayout::getDetId() const
 {
     return m_id;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-bool ToggleDetailInLayout::getNewState() const
+bool TogglePieceInLayout::getNewState() const
 {
     return m_newState;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void ToggleDetailInLayout::Do(bool state)
+void TogglePieceInLayout::Do(bool state)
 {
     QDomElement detail = doc->elementById(m_id);
     if (detail.isElement())
@@ -115,9 +115,9 @@ void ToggleDetailInLayout::Do(bool state)
             detail.removeAttribute(AttrInLayout);
         }
 
-        VDetail det = m_data->DataDetails()->value(m_id);
+        VPiece det = m_data->DataPieces()->value(m_id);
         det.SetInLayout(state);
-        m_data->UpdateDetail(m_id, det);
+        m_data->UpdatePiece(m_id, det);
         emit UpdateList();
     }
     else
diff --git a/src/libs/vtools/undocommands/toggledetailinlayout.h b/src/libs/vtools/undocommands/togglepieceinlayout.h
similarity index 87%
rename from src/libs/vtools/undocommands/toggledetailinlayout.h
rename to src/libs/vtools/undocommands/togglepieceinlayout.h
index 9ba65da8c..d4879968e 100644
--- a/src/libs/vtools/undocommands/toggledetailinlayout.h
+++ b/src/libs/vtools/undocommands/togglepieceinlayout.h
@@ -41,13 +41,13 @@ class QUndoCommand;
 class VAbstractPattern;
 class VContainer;
 
-class ToggleDetailInLayout : public VUndoCommand
+class TogglePieceInLayout : public VUndoCommand
 {
     Q_OBJECT
 public:
-    ToggleDetailInLayout(quint32 id, bool state, VContainer *data, VAbstractPattern *doc,
-                         QUndoCommand *parent = nullptr);
-    virtual ~ToggleDetailInLayout();
+    TogglePieceInLayout(quint32 id, bool state, VContainer *data, VAbstractPattern *doc,
+                        QUndoCommand *parent = nullptr);
+    virtual ~TogglePieceInLayout();
     virtual void undo() Q_DECL_OVERRIDE;
     virtual void redo() Q_DECL_OVERRIDE;
     virtual int  id() const Q_DECL_OVERRIDE;
@@ -57,7 +57,7 @@ public:
 signals:
     void UpdateList();
 private:
-    Q_DISABLE_COPY(ToggleDetailInLayout)
+    Q_DISABLE_COPY(TogglePieceInLayout)
     quint32     m_id;
     VContainer *m_data;
     bool        m_oldState;
diff --git a/src/libs/vtools/undocommands/undocommands.pri b/src/libs/vtools/undocommands/undocommands.pri
index 216944bb2..b77b22ae9 100644
--- a/src/libs/vtools/undocommands/undocommands.pri
+++ b/src/libs/vtools/undocommands/undocommands.pri
@@ -8,13 +8,9 @@ HEADERS += \
     $$PWD/movespline.h \
     $$PWD/movesplinepath.h \
     $$PWD/savetooloptions.h \
-    $$PWD/savedetailoptions.h \
-    $$PWD/movedetail.h \
     $$PWD/deltool.h \
     $$PWD/deletepatternpiece.h \
     $$PWD/adddetnode.h \
-    $$PWD/adddet.h \
-    $$PWD/deletedetail.h \
     $$PWD/vundocommand.h \
     $$PWD/renamepp.h \
     $$PWD/label/movelabel.h \
@@ -22,8 +18,13 @@ HEADERS += \
     $$PWD/addgroup.h \
     $$PWD/delgroup.h \
     $$PWD/label/moveabstractlabel.h \
-    $$PWD/toggledetailinlayout.h \
-    $$PWD/label/operationmovelabel.h
+    $$PWD/label/operationmovelabel.h \
+    $$PWD/addpiece.h \
+    $$PWD/deletepiece.h \
+    $$PWD/movepiece.h \
+    $$PWD/savepieceoptions.h \
+    $$PWD/togglepieceinlayout.h \
+    $$PWD/savepiecepathoptions.h
 
 SOURCES += \
     $$PWD/addtocalc.cpp \
@@ -32,13 +33,9 @@ SOURCES += \
     $$PWD/movespline.cpp \
     $$PWD/movesplinepath.cpp \
     $$PWD/savetooloptions.cpp \
-    $$PWD/savedetailoptions.cpp \
-    $$PWD/movedetail.cpp \
     $$PWD/deltool.cpp \
     $$PWD/deletepatternpiece.cpp \
     $$PWD/adddetnode.cpp \
-    $$PWD/adddet.cpp \
-    $$PWD/deletedetail.cpp \
     $$PWD/vundocommand.cpp \
     $$PWD/renamepp.cpp \
     $$PWD/label/movelabel.cpp \
@@ -46,5 +43,10 @@ SOURCES += \
     $$PWD/addgroup.cpp \
     $$PWD/delgroup.cpp \
     $$PWD/label/moveabstractlabel.cpp \
-    $$PWD/toggledetailinlayout.cpp \
-    $$PWD/label/operationmovelabel.cpp
+    $$PWD/label/operationmovelabel.cpp \
+    $$PWD/addpiece.cpp \
+    $$PWD/deletepiece.cpp \
+    $$PWD/movepiece.cpp \
+    $$PWD/savepieceoptions.cpp \
+    $$PWD/togglepieceinlayout.cpp \
+    $$PWD/savepiecepathoptions.cpp
diff --git a/src/libs/vtools/undocommands/vundocommand.cpp b/src/libs/vtools/undocommands/vundocommand.cpp
index 2e52a502c..cd430d377 100644
--- a/src/libs/vtools/undocommands/vundocommand.cpp
+++ b/src/libs/vtools/undocommands/vundocommand.cpp
@@ -33,6 +33,7 @@
 #include "../ifc/ifcdef.h"
 #include "../vmisc/def.h"
 #include "../vpatterndb/vnodedetail.h"
+#include "../vpatterndb/vpiecenode.h"
 
 class QDomElement;
 class QDomNode;
@@ -76,19 +77,71 @@ void VUndoCommand::UndoDeleteAfterSibling(QDomNode &parentNode, const quint32 &s
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VUndoCommand::IncrementReferences(const QVector<VNodeDetail> &nodes) const
+void VUndoCommand::IncrementReferences(const QVector<quint32> &nodes) const
 {
     for (qint32 i = 0; i < nodes.size(); ++i)
     {
-        doc->IncrementReferens(nodes.at(i).getId());
+        doc->IncrementReferens(nodes.at(i));
     }
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void VUndoCommand::DecrementReferences(const QVector<VNodeDetail> &nodes) const
+void VUndoCommand::DecrementReferences(const QVector<quint32> &nodes) const
 {
     for (qint32 i = 0; i < nodes.size(); ++i)
     {
-        doc->DecrementReferens(nodes.at(i).getId());
+        doc->DecrementReferens(nodes.at(i));
     }
 }
+
+//---------------------------------------------------------------------------------------------------------------------
+void VUndoCommand::IncrementReferences(const QVector<CustomSARecord> &nodes) const
+{
+    QVector<quint32> n;
+
+    for (qint32 i = 0; i < nodes.size(); ++i)
+    {
+        n.append(nodes.at(i).path);
+    }
+
+    IncrementReferences(n);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VUndoCommand::DecrementReferences(const QVector<CustomSARecord> &nodes) const
+{
+    QVector<quint32> n;
+
+    for (qint32 i = 0; i < nodes.size(); ++i)
+    {
+        n.append(nodes.at(i).path);
+    }
+
+    DecrementReferences(n);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VUndoCommand::IncrementReferences(const QVector<VPieceNode> &nodes) const
+{
+    QVector<quint32> n;
+
+    for (qint32 i = 0; i < nodes.size(); ++i)
+    {
+        n.append(nodes.at(i).GetId());
+    }
+
+    IncrementReferences(n);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VUndoCommand::DecrementReferences(const QVector<VPieceNode> &nodes) const
+{
+    QVector<quint32> n;
+
+    for (qint32 i = 0; i < nodes.size(); ++i)
+    {
+        n.append(nodes.at(i).GetId());
+    }
+
+    DecrementReferences(n);
+}
diff --git a/src/libs/vtools/undocommands/vundocommand.h b/src/libs/vtools/undocommands/vundocommand.h
index 31cd57570..58f5c1d32 100644
--- a/src/libs/vtools/undocommands/vundocommand.h
+++ b/src/libs/vtools/undocommands/vundocommand.h
@@ -54,17 +54,19 @@ enum class UndoCommand: char { AddPatternPiece,
                                MoveSPoint,
                                SaveToolOptions,
                                SaveDetailOptions,
-                               MoveDetail,
+                               SavePieceOptions,
+                               SavePiecePathOptions,
+                               MovePiece,
                                DeleteTool,
                                DeletePatternPiece,
                                RenamePP,
                                MoveLabel,
                                MoveDoubleLabel,
                                RotationMoveLabel,
-                               ToggleDetailInLayout
+                               TogglePieceInLayout
                              };
 
-class VNodeDetail;
+class VPieceNode;
 class VPattern;
 
 class VUndoCommand : public QObject, public QUndoCommand
@@ -85,8 +87,14 @@ protected:
     virtual void RedoFullParsing();
     void         UndoDeleteAfterSibling(QDomNode &parentNode, const quint32 &siblingId) const;
 
-    void         IncrementReferences(const QVector<VNodeDetail> &nodes) const;
-    void         DecrementReferences(const QVector<VNodeDetail> &nodes) const;
+    void         IncrementReferences(const QVector<quint32> &nodes) const;
+    void         DecrementReferences(const QVector<quint32> &nodes) const;
+
+    void         IncrementReferences(const QVector<CustomSARecord> &nodes) const;
+    void         DecrementReferences(const QVector<CustomSARecord> &nodes) const;
+
+    void         IncrementReferences(const QVector<VPieceNode> &nodes) const;
+    void         DecrementReferences(const QVector<VPieceNode> &nodes) const;
 private:
     Q_DISABLE_COPY(VUndoCommand)
 };
diff --git a/src/libs/vtools/visualization/line/operation/visoperation.cpp b/src/libs/vtools/visualization/line/operation/visoperation.cpp
index 4cc52b06e..a9566bb1d 100644
--- a/src/libs/vtools/visualization/line/operation/visoperation.cpp
+++ b/src/libs/vtools/visualization/line/operation/visoperation.cpp
@@ -78,17 +78,7 @@ void VisOperation::VisualMode(const quint32 &pointId)
 //---------------------------------------------------------------------------------------------------------------------
 QGraphicsEllipseItem *VisOperation::GetPoint(quint32 i, const QColor &color)
 {
-    if (not points.isEmpty() && static_cast<quint32>(points.size() - 1) >= i)
-    {
-        return points.at(static_cast<int>(i));
-    }
-    else
-    {
-        auto point = InitPoint(color, this);
-        points.append(point);
-        return point;
-    }
-    return nullptr;
+    return GetPointItem(Visualization::data, factor, points, i, color, this);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
diff --git a/src/libs/vtools/visualization/path/vistoolpiece.cpp b/src/libs/vtools/visualization/path/vistoolpiece.cpp
new file mode 100644
index 000000000..8895dacaa
--- /dev/null
+++ b/src/libs/vtools/visualization/path/vistoolpiece.cpp
@@ -0,0 +1,111 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   5 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "vistoolpiece.h"
+#include "../vpatterndb/vpiecepath.h"
+#include "../vgeometry/vpointf.h"
+
+//---------------------------------------------------------------------------------------------------------------------
+VisToolPiece::VisToolPiece(const VContainer *data, QGraphicsItem *parent)
+    : VisPath(data, parent),
+      m_points(),
+      m_line1(nullptr),
+      m_line2(nullptr),
+      m_piece()
+{
+    m_line1 = InitItem<QGraphicsLineItem>(supportColor, this);
+    m_line2 = InitItem<QGraphicsLineItem>(supportColor, this);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VisToolPiece::~VisToolPiece()
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VisToolPiece::RefreshGeometry()
+{
+    HideAllItems();
+
+    if (m_piece.GetPath().CountNodes() > 0)
+    {
+        DrawPath(this, m_piece.MainPathPath(Visualization::data), mainColor, Qt::SolidLine, Qt::RoundCap);
+
+        const QVector<VPointF> nodes = m_piece.MainPathNodePoints(Visualization::data);
+
+        for (int i = 0; i < nodes.size(); ++i)
+        {
+            QGraphicsEllipseItem *point = GetPoint(static_cast<quint32>(i), supportColor);
+            DrawPoint(point, nodes.at(i).toQPointF(), supportColor);
+        }
+
+        if (mode == Mode::Creation)
+        {
+            const QVector<QPointF> points = m_piece.MainPathPoints(Visualization::data);
+            DrawLine(m_line1, QLineF(points.first(), Visualization::scenePos), supportColor, Qt::DashLine);
+
+            if (points.size() > 1)
+            {
+                DrawLine(m_line2, QLineF(points.last(), Visualization::scenePos), supportColor, Qt::DashLine);
+            }
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VisToolPiece::SetPiece(const VPiece &piece)
+{
+    m_piece = piece;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QGraphicsEllipseItem *VisToolPiece::GetPoint(quint32 i, const QColor &color)
+{
+    return GetPointItem(Visualization::data, factor, m_points, i, color, this);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VisToolPiece::HideAllItems()
+{
+    if (m_line1)
+    {
+        m_line1->setVisible(false);
+    }
+
+    if (m_line2)
+    {
+        m_line2->setVisible(false);
+    }
+
+    for (int i=0; i < m_points.size(); ++i)
+    {
+        if (QGraphicsEllipseItem *item = m_points.at(i))
+        {
+            item->setVisible(false);
+        }
+    }
+}
diff --git a/src/libs/vtools/visualization/path/vistoolpiece.h b/src/libs/vtools/visualization/path/vistoolpiece.h
new file mode 100644
index 000000000..a9071d5e4
--- /dev/null
+++ b/src/libs/vtools/visualization/path/vistoolpiece.h
@@ -0,0 +1,62 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   5 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VISTOOLPIECE_H
+#define VISTOOLPIECE_H
+
+#include <QtCore/QObject>
+#include <QtGlobal>
+
+#include "vispath.h"
+#include "../vpatterndb/vpiece.h"
+
+class VisToolPiece : public VisPath
+{
+    Q_OBJECT
+public:
+    VisToolPiece(const VContainer *data, QGraphicsItem *parent = nullptr);
+    virtual ~VisToolPiece();
+
+    virtual void RefreshGeometry() Q_DECL_OVERRIDE;
+    void         SetPiece(const VPiece &piece);
+    virtual int  type() const Q_DECL_OVERRIDE {return Type;}
+    enum { Type = UserType + static_cast<int>(Vis::ToolPiece)};
+private:
+    Q_DISABLE_COPY(VisToolPiece)
+    QVector<QGraphicsEllipseItem *> m_points;
+
+    QGraphicsLineItem *m_line1;
+    QGraphicsLineItem *m_line2;
+    VPiece m_piece;
+
+    QGraphicsEllipseItem* GetPoint(quint32 i, const QColor &color);
+
+    void HideAllItems();
+};
+
+#endif // VISTOOLPIECE_H
diff --git a/src/libs/vtools/visualization/path/vistoolpiecepath.cpp b/src/libs/vtools/visualization/path/vistoolpiecepath.cpp
new file mode 100644
index 000000000..a5e294f2a
--- /dev/null
+++ b/src/libs/vtools/visualization/path/vistoolpiecepath.cpp
@@ -0,0 +1,126 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   22 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "vistoolpiecepath.h"
+#include "../vwidgets/vsimplepoint.h"
+#include "../vgeometry/vpointf.h"
+
+#include <QGraphicsSceneMouseEvent>
+
+//---------------------------------------------------------------------------------------------------------------------
+VisToolPiecePath::VisToolPiecePath(const VContainer *data, QGraphicsItem *parent)
+    : VisPath(data, parent),
+      m_points(),
+      m_line(nullptr),
+      m_path()
+{
+    m_line = InitItem<QGraphicsLineItem>(supportColor, this);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VisToolPiecePath::~VisToolPiecePath()
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VisToolPiecePath::RefreshGeometry()
+{
+    HideAllItems();
+
+    if (m_path.CountNodes() > 0)
+    {
+        DrawPath(this, m_path.PainterPath(Visualization::data), mainColor, Qt::SolidLine, Qt::RoundCap);
+
+        const QVector<VPointF> nodes = m_path.PathNodePoints(Visualization::data);
+
+        for (int i = 0; i < nodes.size(); ++i)
+        {
+            VSimplePoint *point = GetPoint(static_cast<quint32>(i), supportColor);
+            point->SetOnlyPoint(mode == Mode::Creation);
+            point->RefreshGeometry(nodes.at(i));
+            point->setVisible(true);
+        }
+
+        if (mode == Mode::Creation)
+        {
+            const QVector<QPointF> points = m_path.PathPoints(Visualization::data);
+            if (points.size() > 0)
+            {
+                DrawLine(m_line, QLineF(points.last(), Visualization::scenePos), supportColor, Qt::DashLine);
+            }
+        }
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VisToolPiecePath::SetPath(const VPiecePath &path)
+{
+    m_path = path;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VisToolPiecePath::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+    event->ignore();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VSimplePoint *VisToolPiecePath::GetPoint(quint32 i, const QColor &color)
+{
+    if (not m_points.isEmpty() && static_cast<quint32>(m_points.size() - 1) >= i)
+    {
+        return m_points.at(static_cast<int>(i));
+    }
+    else
+    {
+        VSimplePoint *point = new VSimplePoint(NULL_ID, color, *Visualization::data->GetPatternUnit(), &factor);
+        point->SetPointHighlight(true);
+        point->setParentItem(this);
+        point->SetVisualizationMode(true);
+        m_points.append(point);
+
+        return point;
+    }
+    return nullptr;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VisToolPiecePath::HideAllItems()
+{
+    if (m_line)
+    {
+        m_line->setVisible(false);
+    }
+
+    for (int i=0; i < m_points.size(); ++i)
+    {
+        if (QGraphicsEllipseItem *item = m_points.at(i))
+        {
+            item->setVisible(false);
+        }
+    }
+}
diff --git a/src/libs/vtools/visualization/path/vistoolpiecepath.h b/src/libs/vtools/visualization/path/vistoolpiecepath.h
new file mode 100644
index 000000000..591561059
--- /dev/null
+++ b/src/libs/vtools/visualization/path/vistoolpiecepath.h
@@ -0,0 +1,68 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   22 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VISTOOLPIECEPATH_H
+#define VISTOOLPIECEPATH_H
+
+#include <QtCore/QObject>
+#include <QtGlobal>
+
+#include "vispath.h"
+#include "../vpatterndb/vpiecepath.h"
+
+class VSimplePoint;
+
+class VisToolPiecePath : public VisPath
+{
+    Q_OBJECT
+public:
+    VisToolPiecePath(const VContainer *data, QGraphicsItem *parent = nullptr);
+    virtual ~VisToolPiecePath();
+
+    virtual void RefreshGeometry() Q_DECL_OVERRIDE;
+    void         SetPath(const VPiecePath &piece);
+    virtual int  type() const Q_DECL_OVERRIDE {return Type;}
+    enum { Type = UserType + static_cast<int>(Vis::ToolPiecePath)};
+
+protected:
+    virtual void mousePressEvent( QGraphicsSceneMouseEvent * event ) Q_DECL_OVERRIDE;
+
+private:
+    Q_DISABLE_COPY(VisToolPiecePath)
+    QVector<VSimplePoint *> m_points;
+
+    QGraphicsLineItem *m_line;
+
+    VPiecePath m_path;
+
+    VSimplePoint *GetPoint(quint32 i, const QColor &color);
+
+    void HideAllItems();
+};
+
+#endif // VISTOOLPIECEPATH_H
diff --git a/src/libs/vtools/visualization/visualization.cpp b/src/libs/vtools/visualization/visualization.cpp
index d6bd123e7..c20ece212 100644
--- a/src/libs/vtools/visualization/visualization.cpp
+++ b/src/libs/vtools/visualization/visualization.cpp
@@ -141,20 +141,11 @@ void Visualization::MousePos(const QPointF &scenePos)
 //---------------------------------------------------------------------------------------------------------------------
 QGraphicsEllipseItem *Visualization::InitPoint(const QColor &color, QGraphicsItem *parent, qreal z) const
 {
-    QGraphicsEllipseItem *point = new QGraphicsEllipseItem(parent);
-    point->setZValue(1);
-    point->setBrush(QBrush(Qt::NoBrush));
-    point->setPen(QPen(color, qApp->toPixel(WidthMainLine(*Visualization::data->GetPatternUnit()))/factor));
-    point->setRect(PointRect(ToPixel(DefPointRadius/*mm*/, Unit::Mm)));
-    point->setPos(QPointF());
-    point->setFlags(QGraphicsItem::ItemStacksBehindParent);
-    point->setZValue(z);
-    point->setVisible(false);
-    return point;
+    return InitPointItem(Visualization::data, factor, color, parent, z);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-QRectF Visualization::PointRect(const qreal &radius) const
+QRectF Visualization::PointRect(qreal radius)
 {
     QRectF rec = QRectF(0, 0, radius*2, radius*2);
     rec.translate(-rec.center().x(), -rec.center().y());
@@ -236,6 +227,39 @@ void Visualization::DrawPath(QGraphicsPathItem *pathItem, const QPainterPath &pa
     pathItem->setVisible(true);
 }
 
+//---------------------------------------------------------------------------------------------------------------------
+QGraphicsEllipseItem *Visualization::GetPointItem(const VContainer *data, qreal factor,
+                                                  QVector<QGraphicsEllipseItem *> &points, quint32 i,
+                                                  const QColor &color, QGraphicsItem *parent)
+{
+    if (not points.isEmpty() && static_cast<quint32>(points.size() - 1) >= i)
+    {
+        return points.at(static_cast<int>(i));
+    }
+    else
+    {
+        auto point = InitPointItem(data, factor, color, parent);
+        points.append(point);
+        return point;
+    }
+    return nullptr;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QGraphicsEllipseItem *Visualization::InitPointItem(const VContainer *data, qreal factor, const QColor &color,
+                                                   QGraphicsItem *parent, qreal z)
+{
+    QGraphicsEllipseItem *point = new QGraphicsEllipseItem(parent);
+    point->setZValue(1);
+    point->setBrush(QBrush(Qt::NoBrush));
+    point->setPen(QPen(color, qApp->toPixel(WidthMainLine(*data->GetPatternUnit()))/factor));
+    point->setRect(PointRect(ToPixel(DefPointRadius/*mm*/, Unit::Mm)));
+    point->setPos(QPointF());
+    point->setFlags(QGraphicsItem::ItemStacksBehindParent);
+    point->setZValue(z);
+    point->setVisible(false);
+    return point;
+}
 
 //---------------------------------------------------------------------------------------------------------------------
 Mode Visualization::GetMode() const
diff --git a/src/libs/vtools/visualization/visualization.h b/src/libs/vtools/visualization/visualization.h
index 13124732b..15b2d0ee3 100644
--- a/src/libs/vtools/visualization/visualization.h
+++ b/src/libs/vtools/visualization/visualization.h
@@ -84,7 +84,6 @@ protected:
     virtual void AddOnScene()=0;
 
     QGraphicsEllipseItem *InitPoint(const QColor &color, QGraphicsItem *parent, qreal z = 0) const;
-    QRectF       PointRect(const qreal &radius) const;
     void         DrawPoint(QGraphicsEllipseItem *point, const QPointF &pos, const QColor &color,
                            Qt::PenStyle style = Qt::SolidLine);
     virtual void DrawLine(QGraphicsLineItem *lineItem, const QLineF &line, const QColor &color,
@@ -97,8 +96,16 @@ protected:
 
     template <class Item>
     Item         *InitItem(const QColor &color, QGraphicsItem *parent);
+
+    static QRectF                PointRect(qreal radius);
+    static QGraphicsEllipseItem* GetPointItem(const VContainer *data, qreal factor,
+                                              QVector<QGraphicsEllipseItem *> &points, quint32 i, const QColor &color,
+                                              QGraphicsItem *parent);
 private:
     Q_DISABLE_COPY(Visualization)
+
+    static QGraphicsEllipseItem* InitPointItem(const VContainer *data, qreal factor, const QColor &color,
+                                               QGraphicsItem *parent, qreal z = 0);
 };
 
 //---------------------------------------------------------------------------------------------------------------------
diff --git a/src/libs/vtools/visualization/visualization.pri b/src/libs/vtools/visualization/visualization.pri
index 5a02ea230..6231eacf9 100644
--- a/src/libs/vtools/visualization/visualization.pri
+++ b/src/libs/vtools/visualization/visualization.pri
@@ -1,80 +1,84 @@
-# ADD TO EACH PATH $$PWD VARIABLE!!!!!!
-# This need for corect working file translations.pro
-
-HEADERS += \
-    $$PWD/visualization.h \
-    $$PWD/line/visline.h \
-    $$PWD/line/vistoolline.h \
-    $$PWD/line/vistoolendline.h \
-    $$PWD/line/vistoolalongline.h \
-    $$PWD/line/vistoolbisector.h \
-    $$PWD/line/vistoolshoulderpoint.h \
-    $$PWD/line/vistoolnormal.h \
-    $$PWD/line/vistoolheight.h \
-    $$PWD/line/vistoolpointofintersection.h \
-    $$PWD/line/vistooltriangle.h \
-    $$PWD/line/vistoolpointofcontact.h \
-    $$PWD/line/vistoollineintersect.h \
-    $$PWD/line/vistoollineintersectaxis.h \
-    $$PWD/line/vistooltruedarts.h \
-    $$PWD/line/vistoolcurveintersectaxis.h \
-    $$PWD/line/vistoolpointofintersectionarcs.h \
-    $$PWD/line/vistoolpointofintersectioncircles.h \
-    $$PWD/line/vistoolpointfromcircleandtangent.h \
-    $$PWD/line/vistoolpointfromarcandtangent.h \
-    $$PWD/line/operation/vistoolrotation.h \
-    $$PWD/line/operation/vistoolflippingbyline.h \
-    $$PWD/path/vispath.h \
-    $$PWD/path/vistoolarc.h \
-    $$PWD/path/vistoolcutarc.h \
-    $$PWD/path/vistoolspline.h \
-    $$PWD/path/vistoolcutspline.h \
-    $$PWD/path/vistoolsplinepath.h \
-    $$PWD/path/vistoolcutsplinepath.h \
-    $$PWD/path/vistoolarcwithlength.h \
-    $$PWD/path/vistoolpointofintersectioncurves.h \
-    $$PWD/path/vistoolcubicbezier.h \
-    $$PWD/path/vistoolcubicbezierpath.h \
-    $$PWD/line/operation/visoperation.h \
-    $$PWD/line/operation/vistoolflippingbyaxis.h \
-    $$PWD/line/operation/vistoolmove.h \
-    $$PWD/path/vistoolellipticalarc.h
-
-SOURCES += \
-    $$PWD/visualization.cpp \
-    $$PWD/line/visline.cpp \
-    $$PWD/line/vistoolline.cpp \
-    $$PWD/line/vistoolendline.cpp \
-    $$PWD/line/vistoolalongline.cpp \
-    $$PWD/line/vistoolbisector.cpp \
-    $$PWD/line/vistoolshoulderpoint.cpp \
-    $$PWD/line/vistoolnormal.cpp \
-    $$PWD/line/vistoolheight.cpp \
-    $$PWD/line/vistoolpointofintersection.cpp \
-    $$PWD/line/vistooltriangle.cpp \
-    $$PWD/line/vistoolpointofcontact.cpp \
-    $$PWD/line/vistoollineintersect.cpp \
-    $$PWD/line/vistoollineintersectaxis.cpp \
-    $$PWD/line/vistooltruedarts.cpp \
-    $$PWD/line/vistoolcurveintersectaxis.cpp \
-    $$PWD/line/vistoolpointofintersectionarcs.cpp \
-    $$PWD/line/vistoolpointofintersectioncircles.cpp \
-    $$PWD/line/vistoolpointfromcircleandtangent.cpp \
-    $$PWD/line/vistoolpointfromarcandtangent.cpp \
-    $$PWD/line/operation/vistoolrotation.cpp \
-    $$PWD/line/operation/vistoolflippingbyline.cpp \
-    $$PWD/path/vispath.cpp \
-    $$PWD/path/vistoolarc.cpp \
-    $$PWD/path/vistoolcutarc.cpp \
-    $$PWD/path/vistoolspline.cpp \
-    $$PWD/path/vistoolcutspline.cpp \
-    $$PWD/path/vistoolsplinepath.cpp \
-    $$PWD/path/vistoolcutsplinepath.cpp \
-    $$PWD/path/vistoolarcwithlength.cpp \
-    $$PWD/path/vistoolpointofintersectioncurves.cpp \
-    $$PWD/path/vistoolcubicbezier.cpp \
-    $$PWD/path/vistoolcubicbezierpath.cpp \
-    $$PWD/line/operation/visoperation.cpp \
-    $$PWD/line/operation/vistoolflippingbyaxis.cpp \
-    $$PWD/line/operation/vistoolmove.cpp \
-    $$PWD/path/vistoolellipticalarc.cpp
+# ADD TO EACH PATH $$PWD VARIABLE!!!!!!
+# This need for corect working file translations.pro
+
+HEADERS += \
+    $$PWD/visualization.h \
+    $$PWD/line/visline.h \
+    $$PWD/line/vistoolline.h \
+    $$PWD/line/vistoolendline.h \
+    $$PWD/line/vistoolalongline.h \
+    $$PWD/line/vistoolbisector.h \
+    $$PWD/line/vistoolshoulderpoint.h \
+    $$PWD/line/vistoolnormal.h \
+    $$PWD/line/vistoolheight.h \
+    $$PWD/line/vistoolpointofintersection.h \
+    $$PWD/line/vistooltriangle.h \
+    $$PWD/line/vistoolpointofcontact.h \
+    $$PWD/line/vistoollineintersect.h \
+    $$PWD/line/vistoollineintersectaxis.h \
+    $$PWD/line/vistooltruedarts.h \
+    $$PWD/line/vistoolcurveintersectaxis.h \
+    $$PWD/line/vistoolpointofintersectionarcs.h \
+    $$PWD/line/vistoolpointofintersectioncircles.h \
+    $$PWD/line/vistoolpointfromcircleandtangent.h \
+    $$PWD/line/vistoolpointfromarcandtangent.h \
+    $$PWD/line/operation/vistoolrotation.h \
+    $$PWD/line/operation/vistoolflippingbyline.h \
+    $$PWD/path/vispath.h \
+    $$PWD/path/vistoolarc.h \
+    $$PWD/path/vistoolcutarc.h \
+    $$PWD/path/vistoolspline.h \
+    $$PWD/path/vistoolcutspline.h \
+    $$PWD/path/vistoolsplinepath.h \
+    $$PWD/path/vistoolcutsplinepath.h \
+    $$PWD/path/vistoolarcwithlength.h \
+    $$PWD/path/vistoolpointofintersectioncurves.h \
+    $$PWD/path/vistoolcubicbezier.h \
+    $$PWD/path/vistoolcubicbezierpath.h \
+    $$PWD/line/operation/visoperation.h \
+    $$PWD/line/operation/vistoolflippingbyaxis.h \
+    $$PWD/line/operation/vistoolmove.h \
+    $$PWD/path/vistoolellipticalarc.h \
+    $$PWD/path/vistoolpiece.h \
+    $$PWD/path/vistoolpiecepath.h
+
+SOURCES += \
+    $$PWD/visualization.cpp \
+    $$PWD/line/visline.cpp \
+    $$PWD/line/vistoolline.cpp \
+    $$PWD/line/vistoolendline.cpp \
+    $$PWD/line/vistoolalongline.cpp \
+    $$PWD/line/vistoolbisector.cpp \
+    $$PWD/line/vistoolshoulderpoint.cpp \
+    $$PWD/line/vistoolnormal.cpp \
+    $$PWD/line/vistoolheight.cpp \
+    $$PWD/line/vistoolpointofintersection.cpp \
+    $$PWD/line/vistooltriangle.cpp \
+    $$PWD/line/vistoolpointofcontact.cpp \
+    $$PWD/line/vistoollineintersect.cpp \
+    $$PWD/line/vistoollineintersectaxis.cpp \
+    $$PWD/line/vistooltruedarts.cpp \
+    $$PWD/line/vistoolcurveintersectaxis.cpp \
+    $$PWD/line/vistoolpointofintersectionarcs.cpp \
+    $$PWD/line/vistoolpointofintersectioncircles.cpp \
+    $$PWD/line/vistoolpointfromcircleandtangent.cpp \
+    $$PWD/line/vistoolpointfromarcandtangent.cpp \
+    $$PWD/line/operation/vistoolrotation.cpp \
+    $$PWD/line/operation/vistoolflippingbyline.cpp \
+    $$PWD/path/vispath.cpp \
+    $$PWD/path/vistoolarc.cpp \
+    $$PWD/path/vistoolcutarc.cpp \
+    $$PWD/path/vistoolspline.cpp \
+    $$PWD/path/vistoolcutspline.cpp \
+    $$PWD/path/vistoolsplinepath.cpp \
+    $$PWD/path/vistoolcutsplinepath.cpp \
+    $$PWD/path/vistoolarcwithlength.cpp \
+    $$PWD/path/vistoolpointofintersectioncurves.cpp \
+    $$PWD/path/vistoolcubicbezier.cpp \
+    $$PWD/path/vistoolcubicbezierpath.cpp \
+    $$PWD/line/operation/visoperation.cpp \
+    $$PWD/line/operation/vistoolflippingbyaxis.cpp \
+    $$PWD/line/operation/vistoolmove.cpp \
+    $$PWD/path/vistoolellipticalarc.cpp \
+    $$PWD/path/vistoolpiece.cpp \
+    $$PWD/path/vistoolpiecepath.cpp
diff --git a/src/libs/vtools/tools/vgrainlineitem.cpp b/src/libs/vwidgets/vgrainlineitem.cpp
similarity index 89%
rename from src/libs/vtools/tools/vgrainlineitem.cpp
rename to src/libs/vwidgets/vgrainlineitem.cpp
index 4fea3b503..954216651 100644
--- a/src/libs/vtools/tools/vgrainlineitem.cpp
+++ b/src/libs/vwidgets/vgrainlineitem.cpp
@@ -44,7 +44,6 @@
 #define RESIZE_RECT_SIZE                10
 #define ROTATE_CIRC_R                   7
 #define ACTIVE_Z                        10
-#define INACTIVE_Z                      5
 
 //---------------------------------------------------------------------------------------------------------------------
 /**
@@ -52,13 +51,10 @@
  * @param pParent pointer to the parent item
  */
 VGrainlineItem::VGrainlineItem(QGraphicsItem* pParent)
-    : QGraphicsObject(pParent),
-      m_eMode(VGrainlineItem::mNormal),
-      m_bReleased(false),
+    : VPieceItem(pParent),
       m_dRotation(0),
       m_dStartRotation(0),
       m_dLength(0),
-      m_rectBoundingBox(),
       m_polyBound(),
       m_ptStartPos(),
       m_ptStartMove(),
@@ -68,12 +64,10 @@ VGrainlineItem::VGrainlineItem(QGraphicsItem* pParent)
       m_ptStart(),
       m_ptFinish(),
       m_ptCenter(),
-      m_ptRotCenter(),
       m_dAngle(0),
       m_eArrowType(VGrainlineGeometry::atBoth)
 {
-    m_rectBoundingBox.setTopLeft(QPointF(0, 0));
-    setAcceptHoverEvents(true);
+    m_inactiveZ = 5;
     Reset();
     UpdateRectangle();
 }
@@ -211,39 +205,7 @@ void VGrainlineItem::UpdateGeometry(const QPointF& ptPos, qreal dRotation, qreal
     m_eArrowType = eAT;
 
     UpdateRectangle();
-    UpdateBox();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VGrainlineItem::boundingRect returns the bounding rect around the grainline
- * @return bounding rect
- */
-QRectF VGrainlineItem::boundingRect() const
-{
-    return m_rectBoundingBox;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VGrainlineItem::Reset resets the item parameters.
- */
-void VGrainlineItem::Reset()
-{
-    m_bReleased = false;
-    m_eMode = mNormal;
-    setZValue(INACTIVE_Z);
-    UpdateBox();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VGrainlineItem::IsIdle returns the idle flag.
- * @return true, if item mode is normal and false otherwise.
- */
-bool VGrainlineItem::IsIdle() const
-{
-    return m_eMode == mNormal;
+    Update();
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -318,7 +280,7 @@ void VGrainlineItem::SetScale(qreal dScale)
 {
     m_dScale = dScale;
     UpdateRectangle();
-    UpdateBox();
+    Update();
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -355,7 +317,7 @@ void VGrainlineItem::mousePressEvent(QGraphicsSceneMouseEvent* pME)
             SetOverrideCursor(cursorArrowCloseHand, 1, 1);
         }
         setZValue(ACTIVE_Z);
-        UpdateBox();
+        Update();
     }
 }
 
@@ -378,7 +340,7 @@ void VGrainlineItem::mouseMoveEvent(QGraphicsSceneMouseEvent* pME)
             pt.setY(pt.y() + dY);
         }
         setPos(pt);
-        UpdateBox();
+        Update();
     }
     else if (m_eMode == mResize)
     {
@@ -395,7 +357,7 @@ void VGrainlineItem::mouseMoveEvent(QGraphicsSceneMouseEvent* pME)
             m_dLength = dPrevLen;
         }
         UpdateRectangle();
-        UpdateBox();
+        Update();
     }
     else if (m_eMode == mRotate)
     {
@@ -419,7 +381,7 @@ void VGrainlineItem::mouseMoveEvent(QGraphicsSceneMouseEvent* pME)
             setPos(ptNewPos);
             m_dRotation = m_dStartRotation + dAng;
             UpdateRectangle();
-            UpdateBox();
+            Update();
         }
     }
 }
@@ -454,7 +416,7 @@ void VGrainlineItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* pME)
                 if (m_bReleased == true)
                 {
                     m_eMode = mRotate;
-                    UpdateBox();
+                    Update();
                 }
             }
             else
@@ -467,7 +429,7 @@ void VGrainlineItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* pME)
                 {
                     emit SignalResized(m_dLength);
                 }
-                UpdateBox();
+                Update();
             }
         }
         else
@@ -480,7 +442,7 @@ void VGrainlineItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* pME)
             {
                 emit SignalRotated(m_dRotation, m_ptStart);
             }
-            UpdateBox();
+            Update();
         }
         m_bReleased = true;
     }
@@ -490,7 +452,7 @@ void VGrainlineItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* pME)
 /**
  * @brief VGrainlineItem::UpdateBox updates the item
  */
-void VGrainlineItem::UpdateBox()
+void VGrainlineItem::Update()
 {
     update(m_rectBoundingBox);
 }
@@ -549,28 +511,6 @@ void VGrainlineItem::UpdateRectangle()
     prepareGeometryChange();
 }
 
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VGrainlineItem::GetAngle calculates the angle between the line, which goes from
- * rotation center to pt and x axis
- * @param pt point of interest
- * @return the angle between line from rotation center and point of interest and x axis
- */
-qreal VGrainlineItem::GetAngle(const QPointF& pt) const
-{
-    double dX = pt.x() - m_ptRotCenter.x();
-    double dY = pt.y() - m_ptRotCenter.y();
-
-    if (fabs(dX) < 1 && fabs(dY) < 1)
-    {
-        return 0;
-    }
-    else
-    {
-        return qAtan2(-dY, dX);
-    }
-}
-
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief VGrainlineItem::Rotate rotates point pt around ptCenter by angle dAng [rad]
diff --git a/src/libs/vwidgets/vgrainlineitem.h b/src/libs/vwidgets/vgrainlineitem.h
new file mode 100644
index 000000000..7f4217d54
--- /dev/null
+++ b/src/libs/vwidgets/vgrainlineitem.h
@@ -0,0 +1,86 @@
+/************************************************************************
+ **
+ **  @file   vgrainlineitem.h
+ **  @author Bojan Kverh
+ **  @date   September 10, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2013-2015 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VGRAINLINEITEM_H
+#define VGRAINLINEITEM_H
+
+#include "vpieceitem.h"
+#include "../vpatterndb/vgrainlinegeometry.h"
+
+class QGraphicsObject;
+class QPainter;
+class QStyleOptionGraphicsItem;
+class QWidget;
+
+class VGrainlineItem : public VPieceItem
+{
+    Q_OBJECT
+public:
+    explicit VGrainlineItem(QGraphicsItem* pParent = nullptr);
+    virtual ~VGrainlineItem();
+
+    virtual void paint(QPainter* pP, const QStyleOptionGraphicsItem* pOption, QWidget* pWidget) Q_DECL_OVERRIDE;
+    void         UpdateGeometry(const QPointF& ptPos, qreal dRotation, qreal dLength,
+                                VGrainlineGeometry::ArrowType eAT);
+
+    bool IsContained(const QPointF &pt, qreal dRot, qreal &dX, qreal &dY) const;
+    void SetScale(qreal dScale);
+
+signals:
+    void SignalResized(qreal dLength);
+    void SignalRotated(qreal dRot, const QPointF& ptNewPos);
+
+protected:
+    virtual void mousePressEvent(QGraphicsSceneMouseEvent* pME) Q_DECL_OVERRIDE;
+    virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* pME) Q_DECL_OVERRIDE;
+    virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* pME) Q_DECL_OVERRIDE;
+    virtual void Update() Q_DECL_OVERRIDE;
+    void         UpdateRectangle();
+
+    QPointF Rotate(const QPointF& pt, const QPointF& ptCenter, qreal dAng) const;
+    QPointF GetInsideCorner(int i, qreal dDist) const;
+
+private:
+    Q_DISABLE_COPY(VGrainlineItem)
+    qreal                         m_dRotation;
+    qreal                         m_dStartRotation;
+    qreal                         m_dLength;
+    QPolygonF                     m_polyBound;
+    QPointF                       m_ptStartPos;
+    QPointF                       m_ptStartMove;
+    qreal                         m_dScale;
+    QPolygonF                     m_polyResize;
+    qreal                         m_dStartLength;
+    QPointF                       m_ptStart;
+    QPointF                       m_ptFinish;
+    QPointF                       m_ptCenter;
+    qreal                         m_dAngle;
+    VGrainlineGeometry::ArrowType m_eArrowType;
+};
+
+#endif // VGRAINLINEITEM_H
diff --git a/src/libs/vwidgets/vmaingraphicsscene.cpp b/src/libs/vwidgets/vmaingraphicsscene.cpp
index 8bae83fbe..f87a1648a 100644
--- a/src/libs/vwidgets/vmaingraphicsscene.cpp
+++ b/src/libs/vwidgets/vmaingraphicsscene.cpp
@@ -51,8 +51,13 @@ class QRectF;
 /**
  * @brief VMainGraphicsScene default constructor.
  */
-VMainGraphicsScene::VMainGraphicsScene()
-    :QGraphicsScene(), horScrollBar(0), verScrollBar(0), scaleFactor(1), _transform(QTransform()), scenePos(QPointF()),
+VMainGraphicsScene::VMainGraphicsScene(QObject *parent)
+    : QGraphicsScene(parent),
+      horScrollBar(0),
+      verScrollBar(0),
+      scaleFactor(1),
+      _transform(QTransform()),
+      scenePos(QPointF()),
       origins()
 {}
 
diff --git a/src/libs/vwidgets/vmaingraphicsscene.h b/src/libs/vwidgets/vmaingraphicsscene.h
index 5cf079636..fc581bd1e 100644
--- a/src/libs/vwidgets/vmaingraphicsscene.h
+++ b/src/libs/vwidgets/vmaingraphicsscene.h
@@ -54,7 +54,7 @@ class VMainGraphicsScene : public QGraphicsScene
 {
     Q_OBJECT
 public:
-    VMainGraphicsScene();
+    explicit VMainGraphicsScene(QObject *parent = nullptr);
     explicit VMainGraphicsScene(const QRectF & sceneRect, QObject * parent = nullptr);
     qint32        getHorScrollBar() const;
     void          setHorScrollBar(const qint32 &value);
diff --git a/src/libs/vwidgets/vpieceitem.cpp b/src/libs/vwidgets/vpieceitem.cpp
new file mode 100644
index 000000000..f7f969fed
--- /dev/null
+++ b/src/libs/vwidgets/vpieceitem.cpp
@@ -0,0 +1,108 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   18 1, 2017
+ **
+ **  @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) 2017 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "vpieceitem.h"
+#include "../vmisc/vmath.h"
+
+#include <QGraphicsScene>
+
+//---------------------------------------------------------------------------------------------------------------------
+VPieceItem::VPieceItem(QGraphicsItem *pParent)
+    : QGraphicsObject(pParent),
+      m_rectBoundingBox(),
+      m_eMode(VPieceItem::mNormal),
+      m_bReleased(false),
+      m_ptRotCenter(),
+      m_inactiveZ(1)
+{
+    m_rectBoundingBox.setTopLeft(QPointF(0, 0));
+    setAcceptHoverEvents(true);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPieceItem::~VPieceItem()
+{
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief boundingRect returns the item bounding box
+ * @return item bounding box
+ */
+QRectF VPieceItem::boundingRect() const
+{
+    return m_rectBoundingBox;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief Reset resets the item, putting the mode and z coordinate to normal and redraws it
+ */
+void VPieceItem::Reset()
+{
+    if (QGraphicsScene *toolScene = scene())
+    {
+        toolScene->clearSelection();
+    }
+    m_eMode = mNormal;
+    m_bReleased = false;
+    Update();
+    setZValue(m_inactiveZ);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief IsIdle returns the idle flag.
+ * @return true, if item mode is normal and false otherwise.
+ */
+bool VPieceItem::IsIdle() const
+{
+    return m_eMode == mNormal;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief GetAngle calculates the angle between the line, which goes from rotation center to pt and x axis
+ * @param pt point of interest
+ * @return the angle between line from rotation center and point of interest and x axis
+ */
+double VPieceItem::GetAngle(const QPointF &pt) const
+{
+    const double dX = pt.x() - m_ptRotCenter.x();
+    const double dY = pt.y() - m_ptRotCenter.y();
+
+    if (fabs(dX) < 1 && fabs(dY) < 1)
+    {
+        return 0;
+    }
+    else
+    {
+        return qAtan2(dY, dX);
+    }
+}
+
diff --git a/src/libs/vwidgets/vpieceitem.h b/src/libs/vwidgets/vpieceitem.h
new file mode 100644
index 000000000..7b3306044
--- /dev/null
+++ b/src/libs/vwidgets/vpieceitem.h
@@ -0,0 +1,73 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   18 1, 2017
+ **
+ **  @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) 2017 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VPIECEITEM_H
+#define VPIECEITEM_H
+
+#include <QtCore/qglobal.h>
+#include <QGraphicsObject>
+
+class VPieceItem : public QGraphicsObject
+{
+    Q_OBJECT
+public:
+    explicit VPieceItem(QGraphicsItem* pParent = nullptr);
+    virtual ~VPieceItem();
+
+    virtual QRectF boundingRect() const Q_DECL_OVERRIDE;
+
+    virtual void Update() =0;
+
+    void Reset();
+    bool IsIdle() const;
+
+    double GetAngle(const QPointF &pt) const;
+
+signals:
+    void SignalMoved(const QPointF &ptPos);
+
+protected:
+    enum Mode
+    {
+        mNormal,
+        mMove,
+        mResize,
+        mRotate
+    };
+    QRectF  m_rectBoundingBox;
+    Mode    m_eMode;
+    bool    m_bReleased;
+    QPointF m_ptRotCenter;
+
+    qreal m_inactiveZ;
+
+private:
+    Q_DISABLE_COPY(VPieceItem)
+};
+
+#endif // VPIECEITEM_H
diff --git a/src/libs/vwidgets/vsimplepoint.cpp b/src/libs/vwidgets/vsimplepoint.cpp
index 676dbcf48..8d1980e3a 100644
--- a/src/libs/vwidgets/vsimplepoint.cpp
+++ b/src/libs/vwidgets/vsimplepoint.cpp
@@ -53,8 +53,14 @@ class QKeyEvent;
 
 //---------------------------------------------------------------------------------------------------------------------
 VSimplePoint::VSimplePoint(quint32 id, const QColor &currentColor, Unit patternUnit, qreal *factor, QObject *parent)
-    :VAbstractSimple(id, currentColor, patternUnit, factor, parent), QGraphicsEllipseItem(),
-      radius(ToPixel(DefPointRadius/*mm*/, Unit::Mm)), namePoint(nullptr), lineName(nullptr)
+    : VAbstractSimple(id, currentColor, patternUnit, factor, parent),
+      QGraphicsEllipseItem(),
+      radius(ToPixel(DefPointRadius/*mm*/, Unit::Mm)),
+      namePoint(nullptr),
+      lineName(nullptr),
+      m_onlyPoint(false),
+      m_isHighlight(false),
+      m_visualizationMode(false)
 {
     namePoint = new VGraphicsSimpleTextItem(this);
     connect(namePoint, &VGraphicsSimpleTextItem::ShowContextMenu, this, &VSimplePoint::ContextMenu);
@@ -64,7 +70,7 @@ VSimplePoint::VSimplePoint(quint32 id, const QColor &currentColor, Unit patternU
     connect(namePoint, &VGraphicsSimpleTextItem::NameChangePosition, this, &VSimplePoint::ChangedPosition);
     lineName = new QGraphicsLineItem(this);
     this->setBrush(QBrush(Qt::NoBrush));
-    SetPen(this, currentColor, WidthHairLine(patternUnit));
+    SetPen(this, currentColor, m_isHighlight ? WidthMainLine(patternUnit) : WidthHairLine(patternUnit));
     this->setAcceptHoverEvents(true);
     this->setFlag(QGraphicsItem::ItemIsFocusable, true);// For keyboard input focus
 }
@@ -73,6 +79,39 @@ VSimplePoint::VSimplePoint(quint32 id, const QColor &currentColor, Unit patternU
 VSimplePoint::~VSimplePoint()
 {}
 
+//---------------------------------------------------------------------------------------------------------------------
+void VSimplePoint::SetOnlyPoint(bool value)
+{
+    m_onlyPoint = value;
+    namePoint->setVisible(not m_onlyPoint);
+    lineName->setVisible(not m_onlyPoint);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VSimplePoint::IsOnlyPoint() const
+{
+    return m_onlyPoint;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VSimplePoint::SetVisualizationMode(bool value)
+{
+    m_visualizationMode = value;
+    this->setFlag(QGraphicsItem::ItemIsFocusable, not m_visualizationMode);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool VSimplePoint::IsVisualizationMode() const
+{
+    return m_visualizationMode;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VSimplePoint::SetPointHighlight(bool value)
+{
+    m_isHighlight = value;
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 void VSimplePoint::RefreshLine()
 {
@@ -106,7 +145,7 @@ void VSimplePoint::RefreshLine()
 void VSimplePoint::RefreshGeometry(const VPointF &point)
 {
     this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
-    SetPen(this, currentColor, WidthHairLine(patternUnit));
+    SetPen(this, currentColor, m_isHighlight ? WidthMainLine(patternUnit) : WidthHairLine(patternUnit));
     QRectF rec = QRectF(0, 0, radius*2, radius*2);
     rec.translate(-rec.center().x(), -rec.center().y());
     this->setRect(rec);
@@ -127,7 +166,7 @@ void VSimplePoint::RefreshGeometry(const VPointF &point)
 void VSimplePoint::SetEnabled(bool enabled)
 {
     VAbstractSimple::SetEnabled(enabled);
-    SetPen(this, currentColor, WidthHairLine(patternUnit));
+    SetPen(this, currentColor, m_isHighlight ? WidthMainLine(patternUnit) : WidthHairLine(patternUnit));
     SetPen(lineName, Qt::black, WidthHairLine(patternUnit));
     namePoint->setEnabled(enabled);
 }
@@ -184,24 +223,31 @@ void VSimplePoint::ChangedPosition(const QPointF &pos)
 //---------------------------------------------------------------------------------------------------------------------
 void VSimplePoint::mousePressEvent(QGraphicsSceneMouseEvent *event)
 {
-    // Special for not selectable item first need to call standard mousePressEvent then accept event
-    QGraphicsEllipseItem::mousePressEvent(event);
-
-    // Somehow clicking on notselectable object do not clean previous selections.
-    if (not (flags() & ItemIsSelectable) && scene())
+    if (m_visualizationMode)
     {
-        scene()->clearSelection();
-    }
-
-    if (selectionType == SelectionType::ByMouseRelease)
-    {
-        event->accept();// Special for not selectable item first need to call standard mousePressEvent then accept event
+        event->ignore();
     }
     else
     {
-        if (event->button() == Qt::LeftButton)
+        // Special for not selectable item first need to call standard mousePressEvent then accept event
+        QGraphicsEllipseItem::mousePressEvent(event);
+
+        // Somehow clicking on notselectable object do not clean previous selections.
+        if (not (flags() & ItemIsSelectable) && scene())
         {
-            emit Choosed(id);
+            scene()->clearSelection();
+        }
+
+        if (selectionType == SelectionType::ByMouseRelease)
+        {// Special for not selectable item first need to call standard mousePressEvent then accept event
+            event->accept();
+        }
+        else
+        {
+            if (event->button() == Qt::LeftButton)
+            {
+                emit Choosed(id);
+            }
         }
     }
 }
@@ -209,14 +255,17 @@ void VSimplePoint::mousePressEvent(QGraphicsSceneMouseEvent *event)
 //---------------------------------------------------------------------------------------------------------------------
 void VSimplePoint::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
 {
-    if (selectionType == SelectionType::ByMouseRelease)
+    if (not m_visualizationMode)
     {
-        if (event->button() == Qt::LeftButton)
+        if (selectionType == SelectionType::ByMouseRelease)
         {
-            emit Choosed(id);
+            if (event->button() == Qt::LeftButton)
+            {
+                emit Choosed(id);
+            }
         }
+        QGraphicsEllipseItem::mouseReleaseEvent(event);
     }
-    QGraphicsEllipseItem::mouseReleaseEvent(event);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
diff --git a/src/libs/vwidgets/vsimplepoint.h b/src/libs/vwidgets/vsimplepoint.h
index 009f914e0..7378f5362 100644
--- a/src/libs/vwidgets/vsimplepoint.h
+++ b/src/libs/vwidgets/vsimplepoint.h
@@ -62,6 +62,14 @@ public:
     virtual int  type() const Q_DECL_OVERRIDE {return Type;}
     enum { Type = UserType + static_cast<int>(Vis::SimplePoint)};
 
+    void SetOnlyPoint(bool value);
+    bool IsOnlyPoint() const;
+
+    void SetVisualizationMode(bool value);
+    bool IsVisualizationMode() const;
+
+    void SetPointHighlight(bool value);
+
     void RefreshLine();
     void RefreshGeometry(const VPointF &point);
     virtual void SetEnabled(bool enabled) Q_DECL_OVERRIDE;
@@ -104,6 +112,10 @@ private:
 
     /** @brief lineName line what we see if label moved too away from point. */
     QGraphicsLineItem       *lineName;
+
+    bool m_onlyPoint;
+    bool m_isHighlight;
+    bool m_visualizationMode;
 };
 
 #endif // VSIMPLEPOINT_H
diff --git a/src/libs/vtools/tools/vtextgraphicsitem.cpp b/src/libs/vwidgets/vtextgraphicsitem.cpp
similarity index 90%
rename from src/libs/vtools/tools/vtextgraphicsitem.cpp
rename to src/libs/vwidgets/vtextgraphicsitem.cpp
index d9b815266..c423a04b8 100644
--- a/src/libs/vtools/tools/vtextgraphicsitem.cpp
+++ b/src/libs/vwidgets/vtextgraphicsitem.cpp
@@ -55,32 +55,85 @@ const qreal rotateCircle = (2./*mm*/ / 25.4) * PrintDPI;
 #define ROTATE_ARC                  50
 const qreal minW = (4./*mm*/ / 25.4) * PrintDPI + resizeSquare;
 const qreal minH = (4./*mm*/ / 25.4) * PrintDPI + resizeSquare;
-#define INACTIVE_Z                  2
 #define ACTIVE_Z                    10
 
+namespace
+{
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief GetBoundingRect calculates the bounding box around rectBB rectangle, rotated around its center by dRot degrees
+ * @param rectBB rectangle of interest
+ * @param dRot rectangle rotation
+ * @return bounding box around rectBB rotated by dRot
+ */
+QRectF GetBoundingRect(QRectF rectBB, qreal dRot)
+{
+    QPointF apt[4] = { rectBB.topLeft(), rectBB.topRight(), rectBB.bottomLeft(), rectBB.bottomRight() };
+    QPointF ptCenter = rectBB.center();
+
+    qreal dX1 = 0;
+    qreal dX2 = 0;
+    qreal dY1 = 0;
+    qreal dY2 = 0;
+
+    double dAng = qDegreesToRadians(dRot);
+    for (int i = 0; i < 4; ++i)
+    {
+        QPointF pt = apt[i] - ptCenter;
+        qreal dX = pt.x()*cos(dAng) + pt.y()*sin(dAng);
+        qreal dY = -pt.x()*sin(dAng) + pt.y()*cos(dAng);
+
+        if (i == 0)
+        {
+            dX1 = dX2 = dX;
+            dY1 = dY2 = dY;
+        }
+        else
+        {
+            if (dX < dX1)
+            {
+                dX1 = dX;
+            }
+            else if (dX > dX2)
+            {
+                dX2 = dX;
+            }
+            if (dY < dY1)
+            {
+                dY1 = dY;
+            }
+            else if (dY > dY2)
+            {
+                dY2 = dY;
+            }
+        }
+    }
+    QRectF rect;
+    rect.setTopLeft(ptCenter + QPointF(dX1, dY1));
+    rect.setWidth(dX2 - dX1);
+    rect.setHeight(dY2 - dY1);
+    return rect;
+}
+}//static functions
+
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief VTextGraphicsItem::VTextGraphicsItem constructor
  * @param pParent pointer to the parent item
  */
 VTextGraphicsItem::VTextGraphicsItem(QGraphicsItem* pParent)
-    : QGraphicsObject(pParent),
-      m_eMode(VTextGraphicsItem::mNormal),
-      m_bReleased(false),
+    : VPieceItem(pParent),
       m_ptStartPos(),
       m_ptStart(),
-      m_ptRotCenter(),
       m_szStart(),
       m_dRotation(0),
       m_dAngle(0),
       m_rectResize(),
-      m_rectBoundingBox(),
       m_tm()
 {
-    m_rectBoundingBox.setTopLeft(QPointF(0, 0));
+    m_inactiveZ = 2;
     SetSize(minW, minH);
-    setZValue(INACTIVE_Z);
-    setAcceptHoverEvents(true);
+    setZValue(m_inactiveZ);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -195,28 +248,6 @@ void VTextGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem
     }
 }
 
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VTextGraphicsItem::Reset resets the item, putting the mode and z coordinate to normal and redraws it
- */
-void VTextGraphicsItem::Reset()
-{
-    m_eMode = mNormal;
-    m_bReleased = false;
-    Update();
-    setZValue(INACTIVE_Z);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VTextGraphicsItem::IsIdle checks if the item is in normal mode.
- * @return true, if item is in normal mode and false otherwise.
- */
-bool VTextGraphicsItem::IsIdle() const
-{
-    return m_eMode == mNormal;
-}
-
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief VTextGraphicsItem::AddLine adds a line of text to the label list.
@@ -369,16 +400,6 @@ int VTextGraphicsItem::GetFontSize() const
     return m_tm.GetFont().pixelSize();
 }
 
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VTextGraphicsItem::boundingRect returns the label bounding box
- * @return label bounding box
- */
-QRectF VTextGraphicsItem::boundingRect() const
-{
-    return m_rectBoundingBox;
-}
-
 //---------------------------------------------------------------------------------------------------------------------
 /**
  * @brief VTextGraphicsItem::mousePressEvent handles left button mouse press events
@@ -612,82 +633,3 @@ void VTextGraphicsItem::CorrectLabel()
     m_tm.FitFontSize(m_rectBoundingBox.width(), m_rectBoundingBox.height());
     UpdateBox();
 }
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VTextGraphicsItem::GetAngle calculates the angle between the line, which goes from
- * rotation center to pt and x axis
- * @param pt point of interest
- * @return the angle between line from rotation center and point of interest and x axis
- */
-double VTextGraphicsItem::GetAngle(QPointF pt) const
-{
-    double dX = pt.x() - m_ptRotCenter.x();
-    double dY = pt.y() - m_ptRotCenter.y();
-
-    if (fabs(dX) < 1 && fabs(dY) < 1)
-    {
-        return 0;
-    }
-    else
-    {
-        return qAtan2(dY, dX);
-    }
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-/**
- * @brief VTextGraphicsItem::GetBoundingRect calculates the bounding box
- *  around rectBB rectangle, rotated around its center by dRot degrees
- * @param rectBB rectangle of interest
- * @param dRot rectangle rotation
- * @return bounding box around rectBB rotated by dRot
- */
-QRectF VTextGraphicsItem::GetBoundingRect(QRectF rectBB, qreal dRot) const
-{
-    QPointF apt[4] = { rectBB.topLeft(), rectBB.topRight(), rectBB.bottomLeft(), rectBB.bottomRight() };
-    QPointF ptCenter = rectBB.center();
-
-    qreal dX1 = 0;
-    qreal dX2 = 0;
-    qreal dY1 = 0;
-    qreal dY2 = 0;
-
-    double dAng = qDegreesToRadians(dRot);
-    for (int i = 0; i < 4; ++i)
-    {
-        QPointF pt = apt[i] - ptCenter;
-        qreal dX = pt.x()*cos(dAng) + pt.y()*sin(dAng);
-        qreal dY = -pt.x()*sin(dAng) + pt.y()*cos(dAng);
-
-        if (i == 0)
-        {
-            dX1 = dX2 = dX;
-            dY1 = dY2 = dY;
-        }
-        else
-        {
-            if (dX < dX1)
-            {
-                dX1 = dX;
-            }
-            else if (dX > dX2)
-            {
-                dX2 = dX;
-            }
-            if (dY < dY1)
-            {
-                dY1 = dY;
-            }
-            else if (dY > dY2)
-            {
-                dY2 = dY;
-            }
-        }
-    }
-    QRectF rect;
-    rect.setTopLeft(ptCenter + QPointF(dX1, dY1));
-    rect.setWidth(dX2 - dX1);
-    rect.setHeight(dY2 - dY1);
-    return rect;
-}
diff --git a/src/libs/vwidgets/vtextgraphicsitem.h b/src/libs/vwidgets/vtextgraphicsitem.h
new file mode 100644
index 000000000..1748ddc9c
--- /dev/null
+++ b/src/libs/vwidgets/vtextgraphicsitem.h
@@ -0,0 +1,109 @@
+/************************************************************************
+ **
+ **  @file   vtextgraphicsitem.h
+ **  @author Bojan Kverh
+ **  @date   June 16, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2013-2015 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#ifndef VTEXTGRAPHICSITEM_H
+#define VTEXTGRAPHICSITEM_H
+
+#include <QFont>
+#include <QGraphicsObject>
+#include <QList>
+#include <QMetaObject>
+#include <QObject>
+#include <QPointF>
+#include <QRectF>
+#include <QSizeF>
+#include <QString>
+#include <QtGlobal>
+
+#include "vpieceitem.h"
+#include "../vlayout/vtextmanager.h"
+
+class QFont;
+class QGraphicsItem;
+class QGraphicsSceneHoverEvent;
+class QGraphicsSceneMouseEvent;
+class QPainter;
+class QPointF;
+class QRectF;
+class QStyleOptionGraphicsItem;
+class QWidget;
+class VAbstractPattern;
+class VPatternPieceData;
+
+/**
+ * @brief The VTextGraphicsItem class. This class implements text graphics item,
+ * which can be dragged around, resized and rotated within the parent item. The text font
+ * size will be automatically updated, so that the entire text will fit into the item.
+ */
+class VTextGraphicsItem : public VPieceItem
+{
+    Q_OBJECT
+public:
+    explicit VTextGraphicsItem(QGraphicsItem* pParent = nullptr);
+    virtual ~VTextGraphicsItem();
+
+    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) Q_DECL_OVERRIDE;
+    virtual void Update() Q_DECL_OVERRIDE;
+
+    void SetFont(const QFont& fnt);
+    int  GetFontSize() const;
+    void AddLine(const TextLine& tl);
+    void Clear();
+    void SetSize(qreal fW, qreal fH);
+    bool IsContained(QRectF rectBB, qreal dRot, qreal& dX, qreal& dY) const;
+    void UpdateData(const QString& qsName, const VPatternPieceData& data);
+    void UpdateData(const VAbstractPattern* pDoc, qreal dSize, qreal dHeight);
+    int  GetTextLines() const;
+
+protected:
+    virtual void mousePressEvent(QGraphicsSceneMouseEvent* pME) Q_DECL_OVERRIDE;
+    virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* pME) Q_DECL_OVERRIDE;
+    virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* pME) Q_DECL_OVERRIDE;
+    virtual void hoverMoveEvent(QGraphicsSceneHoverEvent* pHE) Q_DECL_OVERRIDE;
+    virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* pHE) Q_DECL_OVERRIDE;
+
+    void UpdateBox();
+    void CorrectLabel();
+
+signals:
+    void SignalResized(qreal iTW, int iFontSize);
+    void SignalRotated(qreal dAng);
+    void SignalShrink();
+
+private:
+    Q_DISABLE_COPY(VTextGraphicsItem)
+    QPointF      m_ptStartPos;
+    QPointF      m_ptStart;
+    QSizeF       m_szStart;
+    double       m_dRotation;
+    double       m_dAngle;
+    QRectF       m_rectResize;
+    VTextManager m_tm;
+};
+
+#endif // VTEXTGRAPHICSITEM_H
diff --git a/src/libs/vwidgets/vwidgets.pri b/src/libs/vwidgets/vwidgets.pri
index 042607eb2..1f3219b8f 100644
--- a/src/libs/vwidgets/vwidgets.pri
+++ b/src/libs/vwidgets/vwidgets.pri
@@ -11,7 +11,10 @@ SOURCES += \
     $$PWD/vabstractsimple.cpp \
     $$PWD/vnobrushscalepathitem.cpp \
     $$PWD/vsimplecurve.cpp \
-    $$PWD/vabstractmainwindow.cpp
+    $$PWD/vabstractmainwindow.cpp \
+    $$PWD/vtextgraphicsitem.cpp \
+    $$PWD/vgrainlineitem.cpp \
+    $$PWD/vpieceitem.cpp
 
 win32-msvc*:SOURCES += $$PWD/stable.cpp
 
@@ -26,4 +29,7 @@ HEADERS += \
     $$PWD/vabstractsimple.h \
     $$PWD/vnobrushscalepathitem.h \
     $$PWD/vsimplecurve.h \
-    $$PWD/vabstractmainwindow.h
+    $$PWD/vabstractmainwindow.h \
+    $$PWD/vtextgraphicsitem.h \
+    $$PWD/vgrainlineitem.h \
+    $$PWD/vpieceitem.h
diff --git a/src/test/TranslationsTest/tst_buitinregexp.cpp b/src/test/TranslationsTest/tst_buitinregexp.cpp
index 60a2b30e3..1ae953068 100644
--- a/src/test/TranslationsTest/tst_buitinregexp.cpp
+++ b/src/test/TranslationsTest/tst_buitinregexp.cpp
@@ -138,6 +138,7 @@ void TST_BuitInRegExp::TestCheckUnderlineExists_data()
     data.insert(angle2SplPath, false);
     data.insert(seg_, true);
     data.insert(currentLength, false);
+    data.insert(currentSeamAllowance, false);
     data.insert(c1LengthSpl_, true);
     data.insert(c2LengthSpl_, true);
     data.insert(c1LengthSplPath, false);
diff --git a/src/test/ValentinaTest/ValentinaTest.pro b/src/test/ValentinaTest/ValentinaTest.pro
index d4aab2df2..0427cb402 100644
--- a/src/test/ValentinaTest/ValentinaTest.pro
+++ b/src/test/ValentinaTest/ValentinaTest.pro
@@ -36,7 +36,6 @@ DEFINES += SRCDIR=\\\"$$PWD/\\\"
 SOURCES += \
     qttestmainlambda.cpp \
     tst_vposter.cpp \
-    tst_vabstractdetail.cpp \
     tst_vspline.cpp \
     tst_nameregexp.cpp \
     tst_vlayoutdetail.cpp \
@@ -46,7 +45,7 @@ SOURCES += \
     tst_vlockguard.cpp \
     tst_misc.cpp \
     tst_vcommandline.cpp \
-    tst_vdetail.cpp \
+    tst_vpiece.cpp \
     tst_vabstractcurve.cpp \
     tst_findpoint.cpp \
     tst_vellipticalarc.cpp \
@@ -55,13 +54,13 @@ SOURCES += \
     tst_vsplinepath.cpp \
     tst_vpointf.cpp \
     tst_readval.cpp \
-    tst_vtranslatevars.cpp
+    tst_vtranslatevars.cpp \
+    tst_vabstractpiece.cpp
 
 win32-msvc*:SOURCES += stable.cpp
 
 HEADERS += \
     tst_vposter.h \
-    tst_vabstractdetail.h \
     tst_vspline.h \
     tst_nameregexp.h \
     tst_vlayoutdetail.h \
@@ -72,7 +71,7 @@ HEADERS += \
     tst_vlockguard.h \
     tst_misc.h \
     tst_vcommandline.h \
-    tst_vdetail.h \
+    tst_vpiece.h \
     tst_vabstractcurve.h \
     tst_findpoint.h \
     tst_vellipticalarc.h \
@@ -81,7 +80,8 @@ HEADERS += \
     tst_vsplinepath.h \
     tst_vpointf.h \
     tst_readval.h \
-    tst_vtranslatevars.h
+    tst_vtranslatevars.h \
+    tst_vabstractpiece.h
 
 # Set using ccache. Function enable_ccache() defined in common.pri.
 $$enable_ccache()
diff --git a/src/test/ValentinaTest/qttestmainlambda.cpp b/src/test/ValentinaTest/qttestmainlambda.cpp
index 60997e2ee..8a3537b56 100644
--- a/src/test/ValentinaTest/qttestmainlambda.cpp
+++ b/src/test/ValentinaTest/qttestmainlambda.cpp
@@ -29,7 +29,7 @@
 #include <QtTest>
 
 #include "tst_vposter.h"
-#include "tst_vabstractdetail.h"
+#include "tst_vabstractpiece.h"
 #include "tst_vspline.h"
 #include "tst_nameregexp.h"
 #include "tst_vlayoutdetail.h"
@@ -40,7 +40,7 @@
 #include "tst_vlockguard.h"
 #include "tst_misc.h"
 #include "tst_vcommandline.h"
-#include "tst_vdetail.h"
+#include "tst_vpiece.h"
 #include "tst_findpoint.h"
 #include "tst_vabstractcurve.h"
 #include "tst_vcubicbezierpath.h"
@@ -67,9 +67,9 @@ int main(int argc, char** argv)
     };
 
     ASSERT_TEST(new TST_FindPoint());
-    ASSERT_TEST(new TST_VDetail());
+    ASSERT_TEST(new TST_VPiece());
     ASSERT_TEST(new TST_VPoster());
-    ASSERT_TEST(new TST_VAbstractDetail());
+    ASSERT_TEST(new TST_VAbstractPiece());
     ASSERT_TEST(new TST_VSpline());
     ASSERT_TEST(new TST_VSplinePath());
     ASSERT_TEST(new TST_NameRegExp());
diff --git a/src/test/ValentinaTest/tst_vabstractcurve.cpp b/src/test/ValentinaTest/tst_vabstractcurve.cpp
index 3b5c04da5..0ce69d462 100644
--- a/src/test/ValentinaTest/tst_vabstractcurve.cpp
+++ b/src/test/ValentinaTest/tst_vabstractcurve.cpp
@@ -113,3 +113,76 @@ void TST_VAbstractCurve::GetSegmentPoints_issue458()
     // Begin comparison
     Comparison(points, origPoints);
 }
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractCurve::IsPointOnCurve_data() const
+{
+    QTest::addColumn<QVector<QPointF>>("points");
+    QTest::addColumn<QPointF>("point");
+    QTest::addColumn<bool>("expectedResult");
+
+
+    QVector<QPointF> points;
+    points << QPointF(714.5704733515146, 229.44783247230293);
+    points << QPointF(713.2432059361518, 236.799577781511);
+    points << QPointF(709.8892587314249, 252.1363394689535);
+    points << QPointF(703.6056072956214, 276.4001729111941);
+    points << QPointF(687.7559494358588, 329.1513838344773);
+    points << QPointF(670.3756426535148, 387.2408887452223);
+    points << QPointF(662.3317449567428, 417.643760273044);
+    points << QPointF(657.4471488294345, 438.31881594794856);
+    points << QPointF(653.1084257285696, 459.2974181766972);
+    points << QPointF(649.4426552757304, 480.5376973511262);
+    points << QPointF(646.5769170924987, 501.9977838630714);
+    points << QPointF(644.6382908004568, 523.6358081043691);
+    points << QPointF(644.1029291338583, 534.5132598425197);
+    points << QPointF(644.1029291338583, 534.5132598425197);
+    points << QPointF(643.4592698551749, 551.9888717674471);
+    points << QPointF(642.9134698671897, 584.1776423714557);
+    points << QPointF(643.1914832622404, 613.2382010061506);
+    points << QPointF(644.2199668178571, 639.3780275889782);
+    points << QPointF(645.9255773115714, 662.8046020373845);
+    points << QPointF(648.2349715209137, 683.7254042688159);
+    points << QPointF(651.0748062234152, 702.3479142007185);
+    points << QPointF(654.3717381966065, 718.8796117505387);
+    points << QPointF(658.0524242180187, 733.5279768357226);
+    points << QPointF(662.0435210651824, 746.5004893737165);
+    points << QPointF(666.2716855156286, 758.0046292819667);
+    points << QPointF(670.6635743468883, 768.2478764779191);
+    points << QPointF(677.400406718071, 781.7952098705392);
+    points << QPointF(686.2864119958404, 797.2061069980141);
+    points << QPointF(690.4766621750516, 804.2970071162871);
+    points << QPointF(690.4766621750516, 804.2970071162871);
+    points << QPointF(692.7921674626707, 808.1521079045636);
+    points << QPointF(697.7183992280718, 815.2245015705212);
+    points << QPointF(702.9886930214004, 821.5595818277402);
+    points << QPointF(708.5917117312482, 827.1885221028615);
+    points << QPointF(714.5161182462067, 832.1424958225257);
+    points << QPointF(720.750575454867, 836.4526764133732);
+    points << QPointF(727.2837462458206, 840.1502373020446);
+    points << QPointF(734.1042935076591, 843.2663519151808);
+    points << QPointF(741.200880128974, 845.8321936794223);
+    points << QPointF(748.5621689983566, 847.8789360214096);
+    points << QPointF(756.1768230043983, 849.4377523677833);
+    points << QPointF(764.0335050356908, 850.5398161451842);
+    points << QPointF(772.1208779808252, 851.2163007802526);
+    points << QPointF(780.4276047283932, 851.4983796996295);
+    points << QPointF(793.250306920113, 851.2897382511853);
+    points << QPointF(802.0871811023624, 850.6707401574804);
+
+    QPointF point(652.5169278885382, 462.6106569368444);
+
+    // See file collection/bug/pointOnCurve.val
+    QTest::newRow("Point on curve") << points << point << true;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractCurve::IsPointOnCurve() const
+{
+    QFETCH(QVector<QPointF>, points);
+    QFETCH(QPointF, point);
+    QFETCH(bool, expectedResult);
+
+    bool result = VAbstractCurve::IsPointOnCurve(points, point);
+    QCOMPARE(result, expectedResult);
+}
diff --git a/src/test/ValentinaTest/tst_vabstractcurve.h b/src/test/ValentinaTest/tst_vabstractcurve.h
index 7ffd2d773..565b995f2 100644
--- a/src/test/ValentinaTest/tst_vabstractcurve.h
+++ b/src/test/ValentinaTest/tst_vabstractcurve.h
@@ -39,7 +39,8 @@ public:
 
 private slots:
     void GetSegmentPoints_issue458();
-
+    void IsPointOnCurve_data() const;
+    void IsPointOnCurve() const;
 };
 
 #endif // TST_VABSTRACTCURVE_H
diff --git a/src/test/ValentinaTest/tst_vabstractdetail.cpp b/src/test/ValentinaTest/tst_vabstractdetail.cpp
deleted file mode 100644
index 9a900dc89..000000000
--- a/src/test/ValentinaTest/tst_vabstractdetail.cpp
+++ /dev/null
@@ -1,1386 +0,0 @@
-/************************************************************************
- **
- **  @file   tst_vabstractdetail.cpp
- **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   16 4, 2015
- **
- **  @brief
- **  @copyright
- **  This source code is part of the Valentine project, a pattern making
- **  program, whose allow create and modeling patterns of clothing.
- **  Copyright (C) 2015 Valentina project
- **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
- **
- *************************************************************************/
-
-#include "tst_vabstractdetail.h"
-#include "../vlayout/vabstractdetail.h"
-
-#include <QPointF>
-#include <QVector>
-
-#include <QtTest>
-
-//---------------------------------------------------------------------------------------------------------------------
-TST_VAbstractDetail::TST_VAbstractDetail(QObject *parent)
-    :AbstractTest(parent)
-{
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::EquidistantRemoveLoop_data()
-{
-    QTest::addColumn<QVector<QPointF>>("points");
-    QTest::addColumn<int>("eqv");
-    QTest::addColumn<qreal>("width");
-    QTest::addColumn<QVector<QPointF>>("ekvOrig");
-
-    // These are two real cases where equdistant has loop.
-    // See issue #298. Segmented Curve isn't selected in Seam Allowance tool.
-    // https://bitbucket.org/dismine/valentina/issue/298/segmented-curve-isnt-selected-in-seam
-    // Code should clean loops in path.
-    QTest::newRow("Issue 298. Case1") << InputPointsIssue298Case1()
-                                      << static_cast<int>(EquidistantType::CloseEquidistant)
-                                      << 75.5906 // seam allowance width
-                                      << OutputPointsIssue298Case1();
-
-    QTest::newRow("Issue 298. Case2") << InputPointsIssue298Case2()
-                                      << static_cast<int>(EquidistantType::CloseEquidistant)
-                                      << 37.7953 // seam allowance width
-                                      << OutputPointsIssue298Case2();
-
-    // See issue #548. Bug Detail tool. Case when seam allowance is wrong.
-    // https://bitbucket.org/dismine/valentina/issues/548/bug-detail-tool-case-when-seam-allowance
-    // Files: Steampunk_trousers.val and marie.vit
-    // Actually buggy detail see in file src/app/share/collection/bugs/Steampunk_trousers_issue_#548.val
-    // Code should clean loops in path.
-    QTest::newRow("Issue 548. Case1") << InputPointsIssue548Case1()
-                                      << static_cast<int>(EquidistantType::CloseEquidistant)
-                                      << 11.338582677165354 // seam allowance width (0.3 cm)
-                                      << OutputPointsIssue548Case1();
-
-    QTest::newRow("Issue 548. Case2") << InputPointsIssue548Case2()
-                                      << static_cast<int>(EquidistantType::CloseEquidistant)
-                                      << 37.795275590551185 // seam allowance width (1.0 cm)
-                                      << OutputPointsIssue548Case2();
-
-    QTest::newRow("Issue 548. Case3") << InputPointsIssue548Case3()
-                                      << static_cast<int>(EquidistantType::CloseEquidistant)
-                                      << 75.59055118110237 // seam allowance width (2.0 cm)
-                                      << OutputPointsIssue548Case3();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-// cppcheck-suppress unusedFunction
-void TST_VAbstractDetail::EquidistantRemoveLoop() const
-{
-    QFETCH(QVector<QPointF>, points);
-    QFETCH(int, eqv);
-    QFETCH(qreal, width);
-    QFETCH(QVector<QPointF>, ekvOrig);
-
-    const QVector<QPointF> ekv = VAbstractDetail::Equidistant(points, static_cast<EquidistantType>(eqv), width);
-
-    // Begin comparison
-    Comparison(ekv, ekvOrig);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::SumTrapezoids() const
-{
-    // Case3 checks that the method 'SumTrapezoids' returns negative value for three clockwise allocated points
-    // Case4 checks that the method 'SumTrapezoids' returns positive value for three counterclock-wise allocated points
-    // Case5 checks that the method 'SumTrapezoids' returns 0 for one point
-    Case3();
-    Case4();
-    Case5();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::PathRemoveLoop_data() const
-{
-    QTest::addColumn<QVector<QPointF>>("path");
-    QTest::addColumn<QVector<QPointF>>("expect");
-
-    QVector<QPointF> path;
-    path << QPointF(10, 10);
-    path << QPointF(20, 10);
-    path << QPointF(20, 20);
-    path << QPointF(10, 20);
-    path << QPointF(10, 10);
-    QTest::newRow("Correct closed a path (four unique points)") << path << path;
-
-#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
-    path.remove(path.size() - 1);
-#else
-    path.removeLast();
-#endif
-    QTest::newRow("Correct unclosed a path (four unique points)") << path << path;
-
-    path.clear();
-    path << QPointF(0, 10);
-    path << QPointF(10, 10);
-    path << QPointF(20, 10);
-    path << QPointF(20, 20);
-    path << QPointF(10, 20);
-    path << QPointF(0, 20);
-    path << QPointF(0, 10);
-    QTest::newRow("Correct closed a path (six unique points)") << path << path;
-
-#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
-    path.remove(path.size() - 1);
-#else
-    path.removeLast();
-#endif
-    QTest::newRow("Correct unclosed a path (six unique points)") << path << path;
-
-    path.clear();
-    path << QPointF(20, 10);
-    path << QPointF(20, 20);
-    path << QPointF(10, 10);
-    path << QPointF(10, 20);
-    path << QPointF(20, 10);
-
-    QVector<QPointF> res;
-    res << QPointF(20, 10);
-    res << QPointF(20, 20);
-    res << QPointF(15, 15);
-    res << QPointF(20, 10);
-    QTest::newRow("One loop, closed a path (four unique points)") << path << res;
-
-#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
-    path.remove(path.size() - 1);
-    res.remove(res.size() - 1);
-#else
-    path.removeLast();
-    res.removeLast();
-#endif
-    QTest::newRow("One loop, unclosed a path (four unique points)") << path << res;
-
-    path.clear();
-    path << QPointF(20, 10);
-    path << QPointF(20, 20);
-    path << QPointF(10, 10);
-    path << QPointF(0, 20);
-    path << QPointF(0, 10);
-    path << QPointF(10, 20);
-    path << QPointF(20, 10);
-
-    res.clear();
-    res << QPointF(20, 10);
-    res << QPointF(20, 20);
-    res << QPointF(15, 15);
-    res << QPointF(20, 10);
-    QTest::newRow("Two loops, closed a path (six unique points)") << path << res;
-
-#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
-    path.remove(path.size() - 1);
-    res.remove(res.size() - 1);
-#else
-    path.removeLast();
-    res.removeLast();
-#endif
-    QTest::newRow("Two loops, unclosed a path (six unique points)") << path << res;
-
-    path.clear();
-    path << QPointF(20, 10);
-    path << QPointF(20, 20);
-    path << QPointF(10, 10);
-    path << QPointF(0, 10);
-    path << QPointF(0, 20);
-    path << QPointF(10, 20);
-    path << QPointF(20, 10);
-
-    res.clear();
-    res << QPointF(20, 10);
-    res << QPointF(20, 20);
-    res << QPointF(15, 15);
-    res << QPointF(20, 10);
-    QTest::newRow("One loop, the first loop, closed a path (six unique points)") << path << res;
-
-#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
-    path.remove(path.size() - 1);
-    res.remove(res.size() - 1);
-#else
-    path.removeLast();
-    res.removeLast();
-#endif
-    QTest::newRow("One loop, the first loop, unclosed a path (six unique points)") << path << res;
-
-    path.clear();
-    path << QPointF(20, 10);
-    path << QPointF(20, 20);
-    path << QPointF(10, 20);
-    path << QPointF(0, 10);
-    path << QPointF(0, 20);
-    path << QPointF(10, 10);
-    path << QPointF(20, 10);
-
-    res.clear();
-    res << QPointF(20, 10);
-    res << QPointF(20, 20);
-    res << QPointF(10, 20);
-    res << QPointF(5, 15);
-    res << QPointF(10, 10);
-    res << QPointF(20, 10);
-    QTest::newRow("One loop, the second loop, closed a path (six unique points)") << path << res;
-
-#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
-    path.remove(path.size() - 1);
-    res.remove(res.size() - 1);
-#else
-    path.removeLast();
-    res.removeLast();
-#endif
-    QTest::newRow("One loop, the second loop, unclosed a path (six unique points)") << path << res;
-
-    path.clear();
-    path << QPointF(20, 10);
-    path << QPointF(20, 20);
-    path << QPointF(10, 20);
-    path << QPointF(20, 15);
-    path << QPointF(10, 10);
-    path << QPointF(20, 10);
-    QTest::newRow("Correct closed a path, point on line (four unique points)") << path << path;
-
-#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
-    path.remove(path.size() - 1);
-#else
-    path.removeLast();
-#endif
-    QTest::newRow("Corect unclosed a path, point on line (four unique points)") << path << path;
-
-    path.clear();
-    path << QPointF(20, 10);
-    path << QPointF(10, 15);
-    path << QPointF(20, 20);
-    path << QPointF(10, 20);
-    path << QPointF(0, 20);
-    path << QPointF(10, 15);
-    path << QPointF(0, 10);
-    path << QPointF(10, 10);
-    path << QPointF(20, 10);
-
-    QTest::newRow("Correct closed a path, point on line (six unique points)") << path << path;
-
-#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
-    path.remove(path.size() - 1);
-#else
-    path.removeLast();
-#endif
-    QTest::newRow("Corect unclosed a path, point on line (six unique points)") << path << path;
-
-    path.clear();
-    path << QPointF(100.96979100571033, 1797.6153764073072);
-    path << QPointF(168.3888427659865, 1807.2395034187866);
-    path << QPointF(206.78076137364403, 1812.2910842036706);
-    path << QPointF(239.1630793382262, 1815.951361623424);
-    path << QPointF(267.5320085054171, 1818.4827543754482);
-    path << QPointF(293.9502505847841, 1820.144031725603);
-    path << QPointF(320.48133946750147, 1821.175819320443);
-    path << QPointF(364.5960626489172, 1822.0507669842166);
-    path << QPointF(400.66867742260206, 1822.488188976378);
-    path << QPointF(623.3126833308274, 1822.488188976378);
-    path << QPointF(653.5489038032683, 2162.6456692913384);
-    path << QPointF(570.545584385708, 2162.6456692913384);
-    path << QPointF(600.7818048581489, 1822.488188976378);
-    path << QPointF(1001.3385826771654, 1822.488188976378);
-    path << QPointF(1001.3385826771654, 2680.44094488189);
-    path << QPointF(-22.11646613738226, 2680.44094488189);
-    path << QPointF(100.96979100571033, 1797.6153764073072);
-
-    res.clear();
-    res << QPointF(100.96979100571033, 1797.6153764073072);
-    res << QPointF(168.3888427659865, 1807.2395034187866);
-    res << QPointF(206.78076137364403, 1812.2910842036706);
-    res << QPointF(239.1630793382262, 1815.951361623424);
-    res << QPointF(267.5320085054171, 1818.4827543754482);
-    res << QPointF(293.9502505847841, 1820.144031725603);
-    res << QPointF(320.48133946750147, 1821.175819320443);
-    res << QPointF(364.5960626489172, 1822.0507669842166);
-    res << QPointF(400.66867742260206, 1822.488188976378);
-    res << QPointF(1001.3385826771654, 1822.488188976378);
-    res << QPointF(1001.3385826771654, 2680.44094488189);
-    res << QPointF(-22.11646613738226, 2680.44094488189);
-    res << QPointF(100.96979100571033, 1797.6153764073072);
-
-    // See the file "collection/bugs/Issue_#493.val"
-    QTest::newRow("Test case issue #493") << path << res;
-
-    path.clear();
-    path << QPointF(-685.2149804319953, -3568.7982439212556);
-    path << QPointF(-700.7415523087261, -3623.900571239949);
-    path << QPointF(-675.4694480627154, -3639.3631430823175);
-    path << QPointF(-684.7497934439581, -3631.3546395862268);
-    path << QPointF(-683.1356602239256, -3633.2868478418427);
-    path << QPointF(-686.8764821039574, -3627.927414863926);
-    path << QPointF(-684.7670104817863, -3631.587853202178);
-    path << QPointF(-682.2386030572435, -3636.8469922361573);
-    path << QPointF(-676.4708011186385, -3650.307478525872);
-    path << QPointF(-666.3050989871189, -3676.5286567894937);
-    path << QPointF(-654.0449409043066, -3710.198553447806);
-    path << QPointF(-640.1333287371614, -3750.0101920374505);
-    path << QPointF(-617.0729873733014, -3818.3303697354913);
-    path << QPointF(-583.8128392515604, -3920.9726624886944);
-    path << QPointF(-550.5307668482033, -4027.6970214479597);
-    path << QPointF(-527.4164674104215, -4104.7034088569535);
-    path << QPointF(-513.4302533332675, -4152.73879565781);
-    path << QPointF(-501.0373006826446, -4196.767296675345);
-    path << QPointF(-490.59311078227046, -4235.660899517831);
-    path << QPointF(-477.25724163384456, -4288.293444470835);
-    path << QPointF(-405.3839593893572, -4272.013803282615);
-    path << QPointF(-545.9786893428341, -3568.830152982464);
-    path << QPointF(-685.2149804319953, -3568.7982439212556);
-
-    res.clear();
-    res << QPointF(-685.2149804319953, -3568.7982439212556);
-    res << QPointF(-700.7415523087261, -3623.900571239949);
-    res << QPointF(-683.3457668881176, -3634.5440688767967);
-    res << QPointF(-682.2386030572435, -3636.8469922361573);
-    res << QPointF(-676.4708011186385, -3650.307478525872);
-    res << QPointF(-666.3050989871189, -3676.5286567894937);
-    res << QPointF(-654.0449409043066, -3710.198553447806);
-    res << QPointF(-640.1333287371614, -3750.0101920374505);
-    res << QPointF(-617.0729873733014, -3818.3303697354913);
-    res << QPointF(-583.8128392515604, -3920.9726624886944);
-    res << QPointF(-550.5307668482033, -4027.6970214479597);
-    res << QPointF(-527.4164674104215, -4104.7034088569535);
-    res << QPointF(-513.4302533332675, -4152.73879565781);
-    res << QPointF(-501.0373006826446, -4196.767296675345);
-    res << QPointF(-490.59311078227046, -4235.660899517831);
-    res << QPointF(-477.25724163384456, -4288.293444470835);
-    res << QPointF(-405.3839593893572, -4272.013803282615);
-    res << QPointF(-545.9786893428341, -3568.830152982464);
-    res << QPointF(-685.2149804319953, -3568.7982439212556);
-
-    // See the file "collection/bugs/Issue_#515.val"
-    // Check a seam allowance path.
-    // The curve that causes the issue is the first in the list.
-    QTest::newRow("Test case issue #515. Big loop in seam allowance path.") << path << res;
-
-    path.clear();
-    path << QPointF(-449.6699112298347, -4243.2921010175705);
-    path << QPointF(-576.966638263205, -3606.6183279948636);
-    path << QPointF(-656.9465284876832, -3606.6183279948636);
-    path << QPointF(-656.5996104603414, -3606.6000783462687);
-    path << QPointF(-655.7439133016985, -3607.1236310612317);
-    path << QPointF(-654.129780081666, -3609.0558393168476);
-    path << QPointF(-651.3154902471701, -3613.939306009108);
-    path << QPointF(-647.8207651830382, -3621.2084054506768);
-    path << QPointF(-641.4701586077349, -3636.0289997859454);
-    path << QPointF(-630.9244502073004, -3663.23035747934);
-    path << QPointF(-618.4465305467888, -3697.4982896415795);
-    path << QPointF(-604.3873016966293, -3737.732371148936);
-    path << QPointF(-581.1891087215608, -3806.460957656939);
-    path << QPointF(-547.7936207285052, -3909.520915257629);
-    path << QPointF(-514.3891332445846, -4016.6378180116963);
-    path << QPointF(-491.17181635142833, -4093.9874129706236);
-    path << QPointF(-477.094588519539, -4142.335384784734);
-    path << QPointF(-464.5941701318652, -4186.745679830414);
-    path << QPointF(-454.0214632588362, -4226.117872983938);
-
-    res.clear();
-    res << QPointF(-449.6699112298347, -4243.2921010175705);
-    res << QPointF(-576.966638263205, -3606.6183279948636);
-    res << QPointF(-656.5697831440032, -3606.6183279948636);
-    res << QPointF(-655.7439133016985, -3607.1236310612317);
-    res << QPointF(-654.129780081666, -3609.0558393168476);
-    res << QPointF(-651.3154902471701, -3613.939306009108);
-    res << QPointF(-647.8207651830382, -3621.2084054506768);
-    res << QPointF(-641.4701586077349, -3636.0289997859454);
-    res << QPointF(-630.9244502073004, -3663.23035747934);
-    res << QPointF(-618.4465305467888, -3697.4982896415795);
-    res << QPointF(-604.3873016966293, -3737.732371148936);
-    res << QPointF(-581.1891087215608, -3806.460957656939);
-    res << QPointF(-547.7936207285052, -3909.520915257629);
-    res << QPointF(-514.3891332445846, -4016.6378180116963);
-    res << QPointF(-491.17181635142833, -4093.9874129706236);
-    res << QPointF(-477.094588519539, -4142.335384784734);
-    res << QPointF(-464.5941701318652, -4186.745679830414);
-    res << QPointF(-454.0214632588362, -4226.117872983938);
-
-    // See the file "collection/bugs/Issue_#515.val"
-    // Check a seam allowance path.
-    // The curve that causes the issue is the last in the list.
-    QTest::newRow("Test case issue #515. Small loop in seam allowance path.") << path << res;
-
-    path.clear();
-    path << QPointF(1229.6503937007876, 937.6667716535435);
-    path << QPointF(203.08931117793543, 937.6667716535435);
-    path << QPointF(459.7677349767701, -2166.704563141019);
-    path << QPointF(1229.6503937007876, -1990.077167189857);
-    path << QPointF(1229.6503937007876, -555.2466141732282);
-    path << QPointF(920.1053824527112, -555.2466141732282);
-    path << QPointF(887.034516310979, -63.90803149606281);
-    path << QPointF(816.3607592795726, -63.908031496062826);
-    path << QPointF(780.7580397937137, -592.8627210002539);
-    path << QPointF(816.0241340748559, -1202.917917917055);
-    path << QPointF(887.3711415156957, -1202.917917917055);
-    path << QPointF(920.4420076574283, -630.8371653543306);
-    path << QPointF(1229.6503937007876, -630.8371653543306);
-    path << QPointF(1229.6503937007876, 937.6667716535435);
-
-    res.clear();
-    res << QPointF(1229.6503937007876, 937.6667716535435);
-    res << QPointF(203.08931117793543, 937.6667716535435);
-    res << QPointF(459.7677349767702, -2166.704563141019);
-    res << QPointF(1229.6503937007876, -1990.077167189857);
-    res << QPointF(1229.6503937007876, 937.6667716535435);
-
-    // See the file "collection/bugs/Issue_#603.val"
-    // Point H1 is first in the list
-    QTest::newRow("Test issue 603.") << path << res;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::PathRemoveLoop() const
-{
-    QFETCH(QVector<QPointF>, path);
-    QFETCH(QVector<QPointF>, expect);
-
-    QVector<QPointF> res = VAbstractDetail::CheckLoops(path);
-    Comparison(res, expect);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::PathLoopsCase_data() const
-{
-    QTest::addColumn<QVector<QPointF>>("path");
-    QTest::addColumn<QVector<QPointF>>("expect");
-
-    QVector<QPointF> path;
-    path << QPointF(61.86670866141733, 446.92270866141735);
-    path << QPointF(650.6504606788366, 473.2192016666484);
-    path << QPointF(649.4426552757304, 480.5376973511262);
-    path << QPointF(646.5769170924987, 501.9977838630714);
-    path << QPointF(644.6382908004568, 523.6358081043691);
-    path << QPointF(643.4592698551749, 551.9888717674471);
-    path << QPointF(642.9134698671897, 584.1776423714557);
-    path << QPointF(643.1914832622404, 613.2382010061506);
-    path << QPointF(644.2199668178571, 639.3780275889782);
-    path << QPointF(645.9255773115714, 662.8046020373845);
-    path << QPointF(648.2349715209137, 683.7254042688159);
-    path << QPointF(651.0748062234152, 702.3479142007185);
-    path << QPointF(654.3717381966065, 718.8796117505387);
-    path << QPointF(658.0524242180187, 733.5279768357226);
-    path << QPointF(662.0435210651824, 746.5004893737165);
-    path << QPointF(666.2716855156286, 758.0046292819667);
-    path << QPointF(670.6635743468883, 768.2478764779191);
-    path << QPointF(677.400406718071, 781.7952098705392);
-    path << QPointF(691.6740007010135, 806.2608114022295);
-    path << QPointF(694.5877745571677, 810.2150054671212);
-    path << QPointF(699.9560352035193, 816.1706553153153);
-    path << QPointF(708.9007628091615, 824.0594196166176);
-    path << QPointF(719.3794725391945, 831.7499791040799);
-    path << QPointF(730.9568541500198, 839.0942359684872);
-    path << QPointF(743.1975973980386, 845.9440924006244);
-    path << QPointF(755.6663920396528, 852.1514505912763);
-    path << QPointF(767.9279278312633, 857.568212731228);
-    path << QPointF(779.5468945292718, 862.046281011264);
-    path << QPointF(790.0879818900794, 865.4375576221694);
-    path << QPointF(799.115879670088, 867.5939447547289);
-    path << QPointF(804.5608128209333, 868.2650594004886);
-    path << QPointF(807.5317661719646, 868.2782441618697);
-    path << QPointF(809.8795601157717, 867.8994015359809);
-    path << QPointF(811.5497808719051, 867.1100192966705);
-    path << QPointF(812.4880146599148, 865.8915852177861);
-    path << QPointF(812.6398476993509, 864.2255870731761);
-    path << QPointF(811.9508662097637, 862.0935126366886);
-    path << QPointF(810.3666564107034, 859.4768496821717);
-    path << QPointF(806.3216663321919, 854.66911491981);
-    path << QPointF(802.0871811023624, 850.6707401574804);
-    path << QPointF(799.4598981526765, 850.6707401574804);
-    path << QPointF(802.0871811023624, 1653.9337322834645);
-    path << QPointF(61.86670866141733, 1653.9337322834645);
-
-    QVector<QPointF> res;
-    res << QPointF(61.86670866141733, 446.92270866141735);
-    res << QPointF(650.6504606788366, 473.2192016666484);
-    res << QPointF(649.4426552757304, 480.5376973511262);
-    res << QPointF(646.5769170924987, 501.9977838630714);
-    res << QPointF(644.6382908004568, 523.6358081043691);
-    res << QPointF(643.4592698551749, 551.9888717674471);
-    res << QPointF(642.9134698671897, 584.1776423714557);
-    res << QPointF(643.1914832622404, 613.2382010061506);
-    res << QPointF(644.2199668178571, 639.3780275889782);
-    res << QPointF(645.9255773115714, 662.8046020373845);
-    res << QPointF(648.2349715209137, 683.7254042688159);
-    res << QPointF(651.0748062234152, 702.3479142007185);
-    res << QPointF(654.3717381966065, 718.8796117505387);
-    res << QPointF(658.0524242180187, 733.5279768357226);
-    res << QPointF(662.0435210651824, 746.5004893737165);
-    res << QPointF(666.2716855156286, 758.0046292819667);
-    res << QPointF(670.6635743468883, 768.2478764779191);
-    res << QPointF(677.400406718071, 781.7952098705392);
-    res << QPointF(691.6740007010135, 806.2608114022295);
-    res << QPointF(694.5877745571677, 810.2150054671212);
-    res << QPointF(699.9560352035193, 816.1706553153153);
-    res << QPointF(708.9007628091615, 824.0594196166176);
-    res << QPointF(719.3794725391945, 831.7499791040799);
-    res << QPointF(730.9568541500198, 839.0942359684872);
-    res << QPointF(743.1975973980386, 845.9440924006244);
-    res << QPointF(755.6663920396528, 852.1514505912763);
-    res << QPointF(767.9279278312633, 857.568212731228);
-    res << QPointF(779.5468945292718, 862.046281011264);
-    res << QPointF(790.0879818900794, 865.4375576221694);
-    res << QPointF(799.115879670088, 867.5939447547289);
-    res << QPointF(799.5154110117976, 867.6431889469776);
-    res << QPointF(802.0871811023624, 1653.9337322834645);
-    res << QPointF(61.86670866141733, 1653.9337322834645);
-
-    // See file "collection/bugs/Issue_#609_case1.val"
-    // Clear a main path. Bound intersection. External loop. Outside a loop. Start point Ф1.
-    QTest::newRow("Issue 609. Case1a") << path << res;
-
-    path.clear();
-    path << QPointF(-365.68188649000314, -2143.126579528016);
-    path << QPointF(-195.75487873249062, -2116.7935769656237);
-    path << QPointF(-195.75487873249062, -1836.0319480765759);
-    path << QPointF(-233.39027086052477, -1838.4849618976993);
-    path << QPointF(-231.15080237392075, -1855.5915146519483);
-    path << QPointF(-225.84473077299972, -1889.4811404382626);
-    path << QPointF(-219.39861487985402, -1922.986407729537);
-    path << QPointF(-211.6695159016421, -1955.9990283342697);
-    path << QPointF(-204.87723909172885, -1980.439660924953);
-    path << QPointF(-199.87970909142098, -1996.6270828437923);
-    path << QPointF(-194.48099536000245, -2012.6451713592935);
-    path << QPointF(-188.65032933731845, -2028.5246588116781);
-    path << QPointF(-182.36812965707693, -2044.2602109802488);
-    path << QPointF(-175.61499879935675, -2059.8462252736344);
-    path << QPointF(-168.3717693169516, -2075.2768492268588);
-    path << QPointF(-160.6424572210866, -2090.5008865466684);
-    path << QPointF(-150.22847685877994, -2109.7385074212525);
-    path << QPointF(194.23861004296444, -2056.3576305273214);
-    path << QPointF(302.4787663409577, -1301.003761061316);
-    path << QPointF(279.86810151275455, -1288.330749878147);
-    path << QPointF(-641.7062267185897, -2051.118466118487);
-    path << QPointF(-365.68188649000314, -2143.126579528016);
-
-    res.clear();
-    res << QPointF(-365.68188649000314, -2143.126579528016);
-    res << QPointF(-195.75487873249062, -2116.7935769656237);
-    res << QPointF(-195.75487873249062, -2008.8655346469059);
-    res << QPointF(-194.48099536000245, -2012.6451713592935);
-    res << QPointF(-188.65032933731845, -2028.5246588116781);
-    res << QPointF(-182.36812965707693, -2044.2602109802488);
-    res << QPointF(-175.61499879935675, -2059.8462252736344);
-    res << QPointF(-168.3717693169516, -2075.2768492268588);
-    res << QPointF(-160.6424572210866, -2090.5008865466684);
-    res << QPointF(-150.22847685877994, -2109.7385074212525);
-    res << QPointF(194.23861004296444, -2056.3576305273214);
-    res << QPointF(302.4787663409577, -1301.003761061316);
-    res << QPointF(279.86810151275455, -1288.330749878147);
-    res << QPointF(-641.7062267185897, -2051.118466118487);
-    res << QPointF(-365.68188649000314, -2143.126579528016);
-
-    // See file "collection/bugs/Issue_#609_case2.val"
-    // Clear an equdistant. Bound intersection. Internal loop. Outside a loop. Start point А2.
-    QTest::newRow("Issue 609. Case2b") << path << res;
-
-    path.clear();
-    path << QPointF(0, 10);
-    path << QPointF(5, 10);
-    path << QPointF(2.5, 15);
-    path << QPointF(7.5, 15);
-    path << QPointF(5, 10);
-    path << QPointF(10, 10);
-    path << QPointF(10, 20);
-    path << QPointF(0, 20);
-    path << QPointF(0, 10);
-
-    QTest::newRow("Internal loop. Valid case.") << path << path;
-
-    path.clear();
-    path << QPointF(0, 10);
-    path << QPointF(5, 10);
-    path << QPointF(7.5, 15);
-    path << QPointF(2.5, 15);
-    path << QPointF(5, 10);
-    path << QPointF(10, 10);
-    path << QPointF(10, 20);
-    path << QPointF(0, 20);
-    path << QPointF(0, 10);
-
-    res.clear();
-    res << QPointF(0, 10);
-    res << QPointF(10, 10);
-    res << QPointF(10, 20);
-    res << QPointF(0, 20);
-    res << QPointF(0, 10);
-
-    QTest::newRow("Internal loop. Invalid case.") << path << res;
-
-    path.clear();
-    path << QPointF(0, 10);
-    path << QPointF(5, 10);
-    path << QPointF(0, 0);
-    path << QPointF(10, 0);
-    path << QPointF(5, 10);
-    path << QPointF(10, 10);
-    path << QPointF(10, 20);
-    path << QPointF(0, 20);
-    path << QPointF(0, 10);
-
-    QTest::newRow("External loop. Valid case.") << path << path;
-
-    path.clear();
-    path << QPointF(0, 10);
-    path << QPointF(5, 10);
-    path << QPointF(10, 0);
-    path << QPointF(0, 0);
-    path << QPointF(5, 10);
-    path << QPointF(10, 10);
-    path << QPointF(10, 20);
-    path << QPointF(0, 20);
-    path << QPointF(0, 10);
-
-    res.clear();
-    res << QPointF(0, 10);
-    res << QPointF(10, 10);
-    res << QPointF(10, 20);
-    res << QPointF(0, 20);
-    res << QPointF(0, 10);
-
-    QTest::newRow("External loop. Invalid case.") << path << res;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::PathLoopsCase() const
-{
-    QFETCH(QVector<QPointF>, path);
-    QFETCH(QVector<QPointF>, expect);
-
-    const QVector<QPointF> res = VAbstractDetail::CheckLoops(path);
-    Comparison(res, expect);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::BrokenDetailEquidistant_data() const
-{
-    QTest::addColumn<QVector<QPointF>>("points");
-    QTest::addColumn<int>("eqv");
-    QTest::addColumn<qreal>("width");
-    QTest::addColumn<QVector<QPointF>>("ekvOrig");
-
-    // For more details see the file "collection/bugs/GAVAUDAN Laure - corsage - figure 4.val".
-    // We will test only one detail. The second require too accurate data that we cannot get from debuger.
-    // The test check an open equdistant of correct detail.
-    QVector<QPointF> points;// Input points.
-    points.append(QPointF(787.5835464566929, 1701.3138897637796));
-    points.append(QPointF(938.7646488188976, 1701.3138897637796));
-    points.append(QPointF(928.6149958683911, 1732.4440719866434));
-    points.append(QPointF(910.0209091217698, 1792.3369853889722));
-    points.append(QPointF(893.3643262819251, 1849.7845131987456));
-    points.append(QPointF(878.5244039283091, 1905.2261617043234));
-    points.append(QPointF(865.3802986403739, 1959.101437194065));
-    points.append(QPointF(863.9366982685195, 1965.6834024491068));
-    points.append(QPointF(852.8936778444679, 1919.6965437838999));
-    points.append(QPointF(837.0628180560684, 1860.2846653184251));
-    points.append(QPointF(819.0677656132684, 1798.6758641921479));
-    points.append(QPointF(798.7585839758027, 1734.54810216256));
-    points.append(QPointF(787.5835464566929, 1701.3138897637796));
-
-    EquidistantType eqv = EquidistantType::OpenEquidistant; // Open path
-    qreal width = 37.795275590551185; // seam allowance width
-
-    QVector<QPointF> ekvOrig;
-    ekvOrig.append(QPointF(774.8748468280837, 1663.5186141732283));
-    ekvOrig.append(QPointF(990.8407795072413, 1663.5186141732283));
-    ekvOrig.append(QPointF(964.6314912875667, 1743.9055911653147));
-    ekvOrig.append(QPointF(946.2221157804494, 1803.203536155223));
-    ekvOrig.append(QPointF(929.7733291125676, 1859.9343877726233));
-    ekvOrig.append(QPointF(915.1430746962241, 1914.5927211230298));
-    ekvOrig.append(QPointF(902.2033544443959, 1967.630259856634));
-    ekvOrig.append(QPointF(894.4064781634931, 2003.1794116713015));
-    ekvOrig.append(QPointF(834.213891302752, 2003.7742535883901));
-    ekvOrig.append(QPointF(816.2523103379473, 1928.9761772004185));
-    ekvOrig.append(QPointF(800.6574884611877, 1870.4501290629887));
-    ekvOrig.append(QPointF(782.9077417718742, 1809.6811695225983));
-    ekvOrig.append(QPointF(786.7126382487066, 1698.723835966227));
-
-    QTest::newRow("GAVAUDAN Laure.") << points << static_cast<int>(eqv) << width << ekvOrig;
-
-    points.clear();
-    points.append(QPointF(97.33089106412862, -223.03306117556497));
-    points.append(QPointF(990.7494050554426, 2.819093995045));
-    points.append(QPointF(908.3966357321774, 379.5839357215547));
-    points.append(QPointF(-135.41154226686143, 697.6417881399819));
-
-    eqv = EquidistantType::OpenEquidistant;
-    width = 11.338582677165354;
-
-    ekvOrig.clear();
-    ekvOrig.append(QPointF(100.10981413873267, -234.02583351343978));
-    ekvOrig.append(QPointF(1004.1704360325447, -5.483401649771952));
-    ekvOrig.append(QPointF(918.0553412376563, 388.4941212347381));
-    ekvOrig.append(QPointF(-138.65807550610091, 710.4843173601864));
-
-    // See the file "collection/bugs/Issue_#604.val" (since 0.5.0)
-    QTest::newRow("Issue #604.") << points << static_cast<int>(eqv) << width << ekvOrig;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::BrokenDetailEquidistant() const
-{
-    QFETCH(QVector<QPointF>, points);
-    QFETCH(int, eqv);
-    QFETCH(qreal, width);
-    QFETCH(QVector<QPointF>, ekvOrig);
-
-    const QVector<QPointF> ekv = VAbstractDetail::Equidistant(points, static_cast<EquidistantType>(eqv),
-                                                              width);// Take result
-
-    // Begin comparison
-    Comparison(ekv, ekvOrig);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::CorrectEquidistantPoints_data() const
-{
-    // See file zigzag.val
-    QTest::addColumn<QVector<QPointF>>("points");
-    QTest::addColumn<QVector<QPointF>>("expect");
-    QTest::addColumn<bool>("removeFirstAndLast");
-
-    QVector<QPointF> points;
-    points.append(QPointF(-741.7894588053705, 1065.7336503858917));
-    points.append(QPointF(-759.696551643576, -115.81420543069257));
-    points.append(QPointF(-278.17249953019325, -217.1037453126913));
-    points.append(QPointF(-244.64654130659474, 1077.9548221866635));
-    points.append(QPointF(-741.7894588053705, 1065.7336503858917));
-
-    QVector<QPointF> expect;
-    expect.append(QPointF(-741.7894588053705, 1065.7336503858917));
-    expect.append(QPointF(-759.696551643576, -115.81420543069257));
-    expect.append(QPointF(-278.17249953019325, -217.1037453126913));
-    expect.append(QPointF(-244.64654130659474, 1077.9548221866635));
-    expect.append(QPointF(-741.7894588053705, 1065.7336503858917));
-
-    QTest::newRow("Closed seam allowance. Last point equal first.") << points << expect << false;
-
-    points.clear();
-    points.append(QPointF(-704.5489521643801, 1028.8424328418016));
-    points.append(QPointF(-721.4335720065426, -85.24049234531904));
-    points.append(QPointF(-707.7852899705758, 755.7064514429209));
-    points.append(QPointF(-721.4335720065426, -85.24049234531904));
-    points.append(QPointF(-314.78124296268265, -170.7806167067443));
-    points.append(QPointF(-283.4579031023758, 1039.1940357173805));
-
-    expect.clear();
-    expect.append(QPointF(-704.5489521643801, 1028.8424328418016));
-    expect.append(QPointF(-721.4335720065426, -85.24049234531904));
-    expect.append(QPointF(-314.78124296268265, -170.7806167067443));
-    expect.append(QPointF(-283.4579031023758, 1039.1940357173805));
-
-    QTest::newRow("Clearing bad main path.") << points << expect << true;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::CorrectEquidistantPoints() const
-{
-    QFETCH(QVector<QPointF>, points);
-    QFETCH(QVector<QPointF>, expect);
-    QFETCH(bool, removeFirstAndLast);
-
-    const QVector<QPointF> res = VAbstractDetail::CorrectEquidistantPoints(points, removeFirstAndLast);
-
-    // Begin comparison
-    Comparison(res, expect);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::TestCorrectEquidistantPoints_data()
-{
-    QTest::addColumn<QVector<QPointF>>("before");
-    QTest::addColumn<QVector<QPointF>>("expect");
-
-    QVector<QPointF> before;
-    before << QPointF(30.0, 39.999874015748034);
-    before << QPointF(785.9055118110236, 39.999874015748034);
-    before << QPointF(785.9055118110236, 3819.527433070866);
-    before << QPointF(483.54330708661416, 3819.527433070866);
-    before << QPointF(483.54330708661416, 1929.763653543307);
-    before << QPointF(407.9527559055629, 984.8817637795973);
-    before << QPointF(407.9527559055118, 1929.763653543307);
-    before << QPointF(407.9527559055118, 3819.527433070866);
-    before << QPointF(30.0, 3819.527433070866);
-
-    QVector<QPointF> expect;
-    expect << QPointF(30.0, 39.999874015748034);
-    expect << QPointF(785.9055118110236, 39.999874015748034);
-    expect << QPointF(785.9055118110236, 3819.527433070866);
-    expect << QPointF(483.54330708661416, 3819.527433070866);
-    expect << QPointF(483.54330708661416, 1929.763653543307);
-    expect << QPointF(407.9527559055629, 984.8817637795973);
-    expect << QPointF(407.9527559055118, 3819.527433070866);
-    expect << QPointF(30.0, 3819.527433070866);
-
-    QTest::newRow("Test case issue #548") << before << expect;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::TestCorrectEquidistantPoints() const
-{
-    QFETCH(QVector<QPointF>, before);
-    QFETCH(QVector<QPointF>, expect);
-
-    QVector<QPointF> after = VAbstractDetail::CorrectEquidistantPoints(before);
-    Comparison(after, expect);
-}
-
-#ifndef Q_OS_WIN
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::PossibleInfiniteClearLoops_data() const
-{
-    QTest::addColumn<QVector<QPointF>>("path");
-    QTest::addColumn<QVector<QPointF>>("expect");
-
-    QVector<QPointF> path;
-    path << QPointF(-670.6449010946802, 4046.36220472441);
-    path << QPointF(-1025.9051277126944, 4046.36220472441);
-    path << QPointF(-1026.4460203880594, 4010.5247429150854);
-    path << QPointF(-1027.2972172274538, 3924.202328582098);
-    path << QPointF(-1028.1383921346433, 3768.5948526129496);
-    path << QPointF(-1028.5065585022217, 3521.575730066707);
-    path << QPointF(-1028.2712136539103, 3252.2436039362233);
-    path << QPointF(-1027.2910122410117, 2850.1024469719814);
-    path << QPointF(-1025.9446023682538, 2439.350819630564);
-    path << QPointF(-1025.8983315247287, 2338.629525677473);
-    path << QPointF(-1025.3536572186458, 2309.970015878699);
-    path << QPointF(-1024.2100836932389, 2281.714612342931);
-    path << QPointF(-1022.5102766116828, 2253.846781520112);
-    path << QPointF(-1020.2969016371525, 2226.349989860186);
-    path << QPointF(-1017.6126244328227, 2199.207703813094);
-    path << QPointF(-1014.5001106618688, 2172.403389828782);
-    path << QPointF(-1011.0020259874652, 2145.9205143571917);
-    path << QPointF(-1005.1601480132764, 2106.7277181407126);
-    path << QPointF(-996.3625412018714, 2055.4921956731814);
-    path << QPointF(-986.7906327138169, 2005.2448233555149);
-    path << QPointF(-976.785747854512, 1955.8533327872588);
-    path << QPointF(-961.6606968634906, 1883.0158867454916);
-    path << QPointF(-947.5864881030896, 1811.4914675744105);
-    path << QPointF(-939.2629508127773, 1764.2008199992524);
-    path << QPointF(-933.8852659113251, 1728.8707137815559);
-    path << QPointF(-930.742733377741, 1705.3464944792456);
-    path << QPointF(-928.0252775410311, 1681.829576238578);
-    path << QPointF(-925.7755640643697, 1658.3034255094963);
-    path << QPointF(-924.036258610932, 1634.7515087419433);
-    path << QPointF(-922.850026843893, 1611.1572923858625);
-    path << QPointF(-922.2595344264276, 1587.504242891197);
-    path << QPointF(-922.3074470217107, 1563.7758267078902);
-    path << QPointF(-922.613405031688, 1551.8740157480315);
-    path << QPointF(-960.4086806222392, 841.3228346456693);
-    path << QPointF(-954.9336313684444, 841.5464781141166);
-    path << QPointF(-944.0363771538431, 841.3102753632543);
-    path << QPointF(-933.2160856340209, 840.291423017261);
-    path << QPointF(-922.4878118569704, 838.5316299985567);
-    path << QPointF(-911.8666108706839, 836.0726052295611);
-    path << QPointF(-901.3675377231535, 832.9560576326933);
-    path << QPointF(-891.005647462372, 829.2236961303737);
-    path << QPointF(-880.7959951363317, 824.9172296450213);
-    path << QPointF(-870.7536357930251, 820.0783670990559);
-    path << QPointF(-860.893624480444, 814.7488174148973);
-    path << QPointF(-851.2310162465817, 808.9702895149649);
-    path << QPointF(-841.7808661394299, 802.7844923216785);
-    path << QPointF(-832.5582292069812, 796.2331347574575);
-    path << QPointF(-823.578160497228, 789.3579257447218);
-    path << QPointF(-810.5607800373014, 778.5565764202543);
-    path << QPointF(-794.2367125298769, 763.3635567727296);
-    path << QPointF(-779.1539087770976, 747.6258919346988);
-    path << QPointF(-765.4328091629026, 731.6772532855191);
-    path << QPointF(-753.193854071231, 715.8513122045474);
-    path << QPointF(-742.557483886022, 700.4817400711408);
-    path << QPointF(-733.644138991215, 685.9022082646563);
-    path << QPointF(-726.5742597707488, 672.446388164451);
-    path << QPointF(-721.4682866085625, 660.447951149882);
-    path << QPointF(-718.6229063234249, 651.1532303788147);
-    path << QPointF(-716.6036430255488, 642.9038041285014);
-    path << QPointF(-714.137568179324, 630.1235656609365);
-    path << QPointF(-711.8605525364693, 612.2344502588126);
-    path << QPointF(-710.4560555432737, 593.4222205889721);
-    path << QPointF(-709.4234847119759, 563.5940176156308);
-    path << QPointF(-708.952111561728, 520.4666582691573);
-    path << QPointF(-708.4401766852314, 497.3858267716535);
-    path << QPointF(-400.92922424489655, 469.03937007874015);
-    path << QPointF(-708.4401766852314, 440.6929133858268);
-    path << QPointF(-708.7078446526739, 341.66122584661264);
-    path << QPointF(-709.3427685457568, 299.60322373665383);
-    path << QPointF(-710.6909230403871, 257.048095841136);
-    path << QPointF(-713.0251717477311, 214.57984397612822);
-    path << QPointF(-715.632864794307, 183.1716335401434);
-    path << QPointF(-717.7953694429818, 162.55016633308693);
-    path << QPointF(-720.3578834261159, 142.27891915519677);
-    path << QPointF(-723.3545146951046, 122.43089223348173);
-    path << QPointF(-725.0465030138121, 112.71059563115871);
-    path << QPointF(-219.59055118110237, -35.52755905511811);
-    path << QPointF(-218.99352387527398, -33.21125072212394);
-    path << QPointF(-217.35724543521775, -28.699086141666157);
-    path << QPointF(-215.20035586903225, -24.33136255454731);
-    path << QPointF(-212.53403014110648, -20.10796717265881);
-    path << QPointF(-209.36944321582945, -16.02878720789205);
-    path << QPointF(-205.71777005759026, -12.093709872138447);
-    path << QPointF(-201.59018563077785, -8.302622377289406);
-    path << QPointF(-196.99786489978123, -4.65541193523633);
-    path << QPointF(-189.3170483291933, 0.5638303631539586);
-    path << QPointF(-177.47808861476295, 6.996342387787443);
-    path << QPointF(-163.981333042598, 12.855376387191757);
-    path << QPointF(-148.91618132781048, 18.141834666235646);
-    path << QPointF(-132.37203318551252, 22.856619529787864);
-    path << QPointF(-114.43828833081622, 27.00063328271716);
-    path << QPointF(-95.20434647883366, 30.574778229892296);
-    path << QPointF(-74.75960734467688, 33.57995667618201);
-    path << QPointF(-53.193470643458, 36.01707092645505);
-    path << QPointF(-30.595336090289106, 37.887023285580185);
-    path << QPointF(-7.0546034002822875, 39.19071605842615);
-    path << QPointF(17.339327711450373, 39.929051549861704);
-    path << QPointF(29.858267716535437, 40.06299212598426);
-    path << QPointF(-45.73228346456693, 1589.6692913385828);
-    path << QPointF(-45.73228346456693, 4046.36220472441);
-    path << QPointF(-297.70078740157487, 4046.36220472441);
-    path << QPointF(-297.70078740157487, 2118.8031496062995);
-    path << QPointF(-222.1102362204725, 1589.6692913385828);
-    path << QPointF(-297.70078740157487, 1060.535433070866);
-    path << QPointF(-373.2913385826772, 1589.6692913385828);
-    path << QPointF(-297.70078740157487, 2118.8031496062995);
-    path << QPointF(-297.70078740157487, 4046.36220472441);
-    path << QPointF(-670.6449010946802, 4046.36220472441);
-    path << QPointF(-670.6449010946802, 2024.3149606299214);
-    path << QPointF(-622.7555214134819, 1570.7716535433071);
-    path << QPointF(-670.6449010946802, 1117.2283464566929);
-    path << QPointF(-718.5342807758785, 1570.7716535433071);
-    path << QPointF(-670.6449010946802, 2024.3149606299214);
-
-    QVector<QPointF> expect;
-    expect << QPointF(-670.6449010946802, 4046.36220472441);
-    expect << QPointF(-670.6449010946802, 4046.36220472441);
-    expect << QPointF(-670.6449010946802, 2024.3149606299214);
-    expect << QPointF(-670.6449010946802, 2024.3149606299214);
-    expect << QPointF(-670.6449010946802, 2024.3149606299214);
-
-    // See the file "collection/bugs/possible_inf_loop.val"
-    QTest::newRow("Possible infinite loop") << path << expect;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::PossibleInfiniteClearLoops() const
-{
-    QFETCH(QVector<QPointF>, path);
-    QFETCH(QVector<QPointF>, expect);
-
-    QVector<QPointF> res = VAbstractDetail::CheckLoops(path);
-    Comparison(res, expect);
-}
-#endif //#ifndef Q_OS_WIN
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::Case3() const
-{
-    const QVector<QPointF> points = InputPointsCase3(); // Input points.
-
-    const qreal result = VAbstractDetail::SumTrapezoids(points);
-    QVERIFY(result < 0);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::Case4() const
-{
-    const QVector<QPointF> points = InputPointsCase4(); // Input points.
-
-    const qreal result = VAbstractDetail::SumTrapezoids(points);
-    QVERIFY(result > 0);
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void TST_VAbstractDetail::Case5() const
-{
-    const QVector<QPointF> points = InputPointsCase5(); // Input points.
-
-    const qreal result = VAbstractDetail::SumTrapezoids(points);
-    QVERIFY(qFuzzyIsNull(result));
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::InputPointsIssue298Case1() const
-{
-    QVector<QPointF> points;
-
-    points += QPointF(35, 39.9999);
-    points += QPointF(412.953, 39.9999);
-    points += QPointF(417.135, 417.929);
-    points += QPointF(417.135, 417.929);
-    points += QPointF(408.797, 405.589);
-    points += QPointF(390.909, 377.669);
-    points += QPointF(362.315, 330.86);
-    points += QPointF(323.075, 264.247);
-    points += QPointF(286.15, 201.448);
-    points += QPointF(262.477, 162.745);
-    points += QPointF(249.22, 142.455);
-    points += QPointF(241.092, 131.261);
-    points += QPointF(236.545, 125.75);
-    points += QPointF(232.808, 122.058);
-    points += QPointF(230.6, 120.629);
-    points += QPointF(229.393, 120.277);
-    points += QPointF(228.421, 120.456);
-    points += QPointF(227.69, 121.185);
-    points += QPointF(227.033, 123.272);
-    points += QPointF(227.112, 128.232);
-    points += QPointF(228.29, 135.699);
-    points += QPointF(230.625, 145.81);
-    points += QPointF(234.173, 158.703);
-    points += QPointF(241.73, 183.168);
-    points += QPointF(248.796, 204.144);
-    points += QPointF(248.796, 204.144);
-    points += QPointF(251.528, 212.406);
-    points += QPointF(255.482, 227.075);
-    points += QPointF(257.717, 239.591);
-    points += QPointF(258.279, 247.554);
-    points += QPointF(258.203, 252.278);
-    points += QPointF(257.756, 256.51);
-    points += QPointF(256.949, 260.264);
-    points += QPointF(255.795, 263.547);
-    points += QPointF(254.308, 266.372);
-    points += QPointF(252.501, 268.749);
-    points += QPointF(250.385, 270.688);
-    points += QPointF(247.974, 272.201);
-    points += QPointF(245.281, 273.296);
-    points += QPointF(242.319, 273.986);
-    points += QPointF(239.1, 274.28);
-    points += QPointF(233.846, 274.05);
-    points += QPointF(226.022, 272.393);
-    points += QPointF(217.402, 269.345);
-    points += QPointF(208.09, 264.991);
-    points += QPointF(198.186, 259.414);
-    points += QPointF(187.795, 252.7);
-    points += QPointF(177.019, 244.933);
-    points += QPointF(165.96, 236.197);
-    points += QPointF(154.721, 226.576);
-    points += QPointF(143.405, 216.157);
-    points += QPointF(132.113, 205.022);
-    points += QPointF(120.95, 193.257);
-    points += QPointF(110.017, 180.946);
-    points += QPointF(99.4167, 168.174);
-    points += QPointF(89.2522, 155.024);
-    points += QPointF(79.626, 141.582);
-    points += QPointF(70.6405, 127.933);
-    points += QPointF(62.3985, 114.16);
-    points += QPointF(55.0025, 100.348);
-    points += QPointF(48.5551, 86.5823);
-    points += QPointF(43.159, 72.9466);
-    points += QPointF(38.9167, 59.5258);
-    points += QPointF(35.9309, 46.4042);
-    points += QPointF(35, 39.9999);
-
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::OutputPointsIssue298Case1() const
-{
-    QVector<QPointF> points;
-    points += QPointF(-52.3724798442221, -35.5907);
-    points += QPointF(487.7117748779425, -35.5907);
-    points += QPointF(493.3432017362585, 473.32371517914754);
-    points += QPointF(385.98559977345093, 506.8445742667132);
-    points += QPointF(345.64704646524604, 447.1446764706891);
-    points += QPointF(326.82411403464874, 417.76541252489994);
-    points += QPointF(297.4844355409708, 369.73572061014266);
-    points += QPointF(280.35686644039447, 340.63425704493835);
-    points += QPointF(268.2336759982877, 345.56366422433183);
-    points += QPointF(254.38869069377708, 348.78886336684104);
-    points += QPointF(240.8928242225697, 350.0214774527481);
-    points += QPointF(224.29748398011193, 349.2949970081793);
-    points += QPointF(205.50330859478322, 345.31468660256957);
-    points += QPointF(188.72568121178054, 339.38217984347546);
-    points += QPointF(173.487571907339, 332.2573164509149);
-    points += QPointF(159.09346043909582, 324.15190856941325);
-    points += QPointF(145.1562378134811, 315.1465661857729);
-    points += QPointF(131.46917217609203, 305.28136213922494);
-    points += QPointF(117.9345600633141, 294.589765121662);
-    points += QPointF(104.5254725457231, 283.11108988305153);
-    points += QPointF(91.25156649455745, 270.88938370179534);
-    points += QPointF(78.14294517511125, 257.9630200468154);
-    points += QPointF(65.25722328495372, 244.3823949426573);
-    points += QPointF(52.65759889494496, 230.19470850111355);
-    points += QPointF(40.412239584772514, 215.4406233233806);
-    points += QPointF(28.600027181043494, 200.15894757848054);
-    points += QPointF(17.304913602921047, 184.38648111018338);
-    points += QPointF(6.6105681133211736, 168.14173996194046);
-    points += QPointF(-3.3897319816688407, 151.43048866270516);
-    points += QPointF(-12.592267484961765, 134.24479093805914);
-    points += QPointF(-20.880547263016442, 116.54866956498358);
-    points += QPointF(-28.111192294561146, 98.27715746242171);
-    points += QPointF(-34.098213657706594, 79.33681465062016);
-    points += QPointF(-38.441724866417594, 60.24852451858777);
-    points += QPointF(-52.3724798442221, -35.5907);
-
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::InputPointsIssue298Case2() const
-{
-    QVector<QPointF> points;
-
-    points += QPointF(35, 39.9999);
-    points += QPointF(35, 39.9999);
-    points += QPointF(35.9309, 46.4042);
-    points += QPointF(38.9167, 59.5258);
-    points += QPointF(43.159, 72.9466);
-    points += QPointF(48.5551, 86.5823);
-    points += QPointF(55.0025, 100.348);
-    points += QPointF(62.3985, 114.16);
-    points += QPointF(70.6405, 127.933);
-    points += QPointF(79.626, 141.582);
-    points += QPointF(89.2522, 155.024);
-    points += QPointF(99.4167, 168.174);
-    points += QPointF(110.017, 180.946);
-    points += QPointF(120.95, 193.257);
-    points += QPointF(132.113, 205.022);
-    points += QPointF(143.405, 216.157);
-    points += QPointF(154.721, 226.576);
-    points += QPointF(165.96, 236.197);
-    points += QPointF(177.019, 244.933);
-    points += QPointF(187.795, 252.7);
-    points += QPointF(198.186, 259.414);
-    points += QPointF(208.09, 264.991);
-    points += QPointF(217.402, 269.345);
-    points += QPointF(226.022, 272.393);
-    points += QPointF(233.846, 274.05);
-    points += QPointF(239.1, 274.28);
-    points += QPointF(242.319, 273.986);
-    points += QPointF(245.281, 273.296);
-    points += QPointF(247.974, 272.201);
-    points += QPointF(250.385, 270.688);
-    points += QPointF(252.501, 268.749);
-    points += QPointF(254.308, 266.372);
-    points += QPointF(255.795, 263.547);
-    points += QPointF(256.949, 260.264);
-    points += QPointF(257.756, 256.51);
-    points += QPointF(258.203, 252.278);
-    points += QPointF(258.279, 247.554);
-    points += QPointF(257.717, 239.591);
-    points += QPointF(255.482, 227.075);
-    points += QPointF(251.528, 212.406);
-    points += QPointF(248.796, 204.144);
-    points += QPointF(248.796, 204.144);
-    points += QPointF(241.73, 183.168);
-    points += QPointF(234.173, 158.703);
-    points += QPointF(230.625, 145.81);
-    points += QPointF(228.29, 135.699);
-    points += QPointF(227.112, 128.232);
-    points += QPointF(227.033, 123.272);
-    points += QPointF(227.69, 121.185);
-    points += QPointF(228.421, 120.456);
-    points += QPointF(229.393, 120.277);
-    points += QPointF(230.6, 120.629);
-    points += QPointF(232.808, 122.058);
-    points += QPointF(236.545, 125.75);
-    points += QPointF(241.092, 131.261);
-    points += QPointF(249.22, 142.455);
-    points += QPointF(262.477, 162.745);
-    points += QPointF(286.15, 201.448);
-    points += QPointF(323.075, 264.247);
-    points += QPointF(362.315, 330.86);
-    points += QPointF(390.909, 377.669);
-    points += QPointF(408.797, 405.589);
-    points += QPointF(417.135, 417.929);
-    points += QPointF(417.135, 417.929);
-    points += QPointF(35, 417.953);
-
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::OutputPointsIssue298Case2() const
-{
-    QVector<QPointF> points;
-
-    points += QPointF(-2.7952999999999975, 4.8384699505981095);
-    points += QPointF(67.34448942068963, -0.23248582689164274);
-    points += QPointF(73.11721243320879, 39.48203774070609);
-    points += QPointF(75.42415682885321, 49.62029267468959);
-    points += QPointF(78.79409614728041, 60.281321268788744);
-    points += QPointF(83.27292363150828, 71.59911521750833);
-    points += QPointF(88.79988374248082, 83.39960453097031);
-    points += QPointF(95.2926159908344, 95.5247556686474);
-    points += QPointF(102.65546594334339, 107.82863001903641);
-    points += QPointF(110.78654319853989, 120.17975944490887);
-    points += QPointF(119.5782864094781, 132.4565262107595);
-    points += QPointF(128.91893020761376, 144.54068833830968);
-    points += QPointF(138.69670055252752, 156.3216457494432);
-    points += QPointF(148.79638835752286, 167.69430252867102);
-    points += QPointF(159.09802741244354, 178.55148997659143);
-    points += QPointF(169.48171675272164, 188.79080814910267);
-    points += QPointF(179.81876372713828, 198.30845505847407);
-    points += QPointF(189.9727199683426, 207.00061743916868);
-    points += QPointF(199.7939139119543, 214.75881893038778);
-    points += QPointF(209.1143810932559, 221.476716907111);
-    points += QPointF(216.03386663545683, 225.9476461661168);
-    points += QPointF(215.3306509043856, 223.3387762725701);
-    points += QPointF(205.75073516810195, 194.75155680967347);
-    points += QPointF(197.88802785264718, 169.29686123304236);
-    points += QPointF(193.97579117825833, 155.08026950731082);
-    points += QPointF(191.1640933645057, 142.90507610480435);
-    points += QPointF(189.3638602852325, 131.49392126360493);
-    points += QPointF(189.14507682295456, 117.75764312564759);
-    points += QPointF(194.42693552963567, 100.97950138920423);
-    points += QPointF(210.03879336533757, 85.41035725481989);
-    points += QPointF(231.36634627769158, 81.48275234606332);
-    points += QPointF(246.4916615881645, 85.89378050620131);
-    points += QPointF(256.60614755001956, 92.43979519799973);
-    points += QPointF(264.4750900046005, 100.21398185636762);
-    points += QPointF(270.9888544453203, 108.1087159300009);
-    points += QPointF(280.35077918473866, 121.00209505562212);
-    points += QPointF(294.42535276480356, 142.5434013797918);
-    points += QPointF(318.5597512322288, 182.00074197391842);
-    points += QPointF(394.73028222951507, 311.42213969492946);
-    points += QPointF(422.9514429826756, 357.62079373755);
-    points += QPointF(440.37197676737753, 384.8111617646563);
-    points += QPointF(488.2841719585649, 455.71983154868764);
-    points += QPointF(-2.795300000000013, 455.7506738094777);
-    points += QPointF(-2.7952999999999975, 4.8384699505981095);
-
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::InputPointsIssue548Case1() const
-{
-    QVector<QPointF> points;
-
-    points += QPointF(236.97989607468364, 65.89325192030674);
-    points += QPointF(198.93409106041895, 172.04876297154925);
-    points += QPointF(260.32251114299453, 75.38027418944861);
-    points += QPointF(324.54110236213444, 101.48031496062993);
-    points += QPointF(29.858267716535437, 300.85039370078744);
-    points += QPointF(99.86433649395013, 10.166060970128015);
-
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::OutputPointsIssue548Case1() const
-{
-    QVector<QPointF> points;
-
-    points += QPointF(251.32210577118798, 59.48301432799721);
-    points += QPointF(243.9841262159756, 79.95746530820585);
-    points += QPointF(255.82424817748586, 61.31279754390509);
-    points += QPointF(348.48337789725855, 98.9717841021069);
-    points += QPointF(29.780382054543473, 314.59289909613994);
-    points += QPointF(17.01672179602679, 305.7450049304056);
-    points += QPointF(91.92616539550944, -5.299480329501037);
-    points += QPointF(251.32210577118798, 59.48301432799721);
-
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::InputPointsIssue548Case2() const
-{
-    QVector<QPointF> points;
-    points << QPointF(99.86433649395013, 10.166060970128015);
-    points << QPointF(236.97989607468364, 65.89325192030674);
-    points << QPointF(198.93409106041895, 172.04876297154925);
-    points << QPointF(260.32251114299453, 75.38027418944861);
-    points << QPointF(324.54110236213444, 101.48031496062993);
-    points << QPointF(29.858267716535437, 300.85039370078744);
-
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::OutputPointsIssue548Case2() const
-{
-    QVector<QPointF> points;
-    points << QPointF(73.40376616581447, -41.38574336196901);
-    points << QPointF(245.32830125796568, 28.488685370970344);
-    points << QPointF(245.32830125796573, 28.488685370970277);
-    points << QPointF(404.3486874792147, 93.11854543221973);
-    points << QPointF(29.598648843228922, 346.6587450186291);
-    points << QPointF(-12.946885351826726, 317.1657644661815);
-    points << QPointF(73.40376616581447, -41.38574336196901);
-
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::InputPointsIssue548Case3() const
-{
-    QVector<QPointF> points;
-
-    points += QPointF(99.86433649395013, 10.166060970128015);
-    points += QPointF(236.97989607468364, 65.89325192030674);
-    points += QPointF(198.93409106041895, 172.04876297154925);
-    points += QPointF(260.32251114299453, 75.38027418944861);
-    points += QPointF(324.54110236213444, 101.48031496062993);
-    points += QPointF(29.858267716535437, 300.85039370078744);
-
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::OutputPointsIssue548Case3() const
-{
-    QVector<QPointF> points;
-
-    points += QPointF(46.94319583767885, -92.9375476940661);
-#if QT_VERSION < QT_VERSION_CHECK(5, 3, 0)
-    points += QPointF(234.2633962639462, -16.805935717278903);
-#else
-    points += QPointF(238.798634936, -14.9627013515);
-#endif
-    points += QPointF(484.15627259629446, 84.75677590380938);
-    points += QPointF(29.339029969922702, 392.46709633647066);
-    points += QPointF(-55.75203842018885, 333.48113523157537);
-    points += QPointF(46.94319583767885, -92.9375476940661);
-
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::InputPointsCase3() const
-{
-    QVector<QPointF> points;
-
-    points += QPointF(35, 35);
-    points += QPointF(50, 50);
-    points += QPointF(15, 50);
-
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::InputPointsCase4() const
-{
-    QVector<QPointF> points;
-
-    points += QPointF(15, 15);
-    points += QPointF(15, 50);
-    points += QPointF(50, 50);
-
-    return points;
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-QVector<QPointF> TST_VAbstractDetail::InputPointsCase5() const
-{
-    QVector<QPointF> points;
-
-    points += QPointF(35, 35);
-
-    return points;
-}
diff --git a/src/test/ValentinaTest/tst_vabstractpiece.cpp b/src/test/ValentinaTest/tst_vabstractpiece.cpp
new file mode 100644
index 000000000..6705e500e
--- /dev/null
+++ b/src/test/ValentinaTest/tst_vabstractpiece.cpp
@@ -0,0 +1,3161 @@
+/************************************************************************
+ **
+ **  @file
+ **  @author Roman Telezhynskyi <dismine(at)gmail.com>
+ **  @date   17 11, 2016
+ **
+ **  @brief
+ **  @copyright
+ **  This source code is part of the Valentine project, a pattern making
+ **  program, whose allow create and modeling patterns of clothing.
+ **  Copyright (C) 2016 Valentina project
+ **  <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
+ **
+ *************************************************************************/
+
+#include "tst_vabstractpiece.h"
+#include "../vlayout/vabstractpiece.h"
+
+#include <QPointF>
+#include <QVector>
+
+#include <QtTest>
+
+//---------------------------------------------------------------------------------------------------------------------
+TST_VAbstractPiece::TST_VAbstractPiece(QObject *parent)
+    : AbstractTest(parent)
+{}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::EquidistantRemoveLoop_data()
+{
+    QTest::addColumn<QVector<VSAPoint>>("points");
+    QTest::addColumn<qreal>("width");
+    QTest::addColumn<QVector<QPointF>>("ekvOrig");
+
+    // See file src/app/share/collection/test/seamtest1.val
+    QTest::newRow("Seam test 1") << InputPointsCase1()
+                                 << 37.795275590551185 // seam allowance width
+                                 << OutputPointsCase1();
+
+    // See file src/app/share/collection/test/seamtest2.val
+    QTest::newRow("Seam test 2") << InputPointsCase2()
+                                 << 37.795275590551185 // seam allowance width
+                                 << OutputPointsCase2();
+
+    // See file src/app/share/collection/test/seamtest3.val
+    QTest::newRow("Seam test 3") << InputPointsCase3()
+                                 << 37.795275590551185 // seam allowance width
+                                 << OutputPointsCase3();
+
+    // These are two real cases where equdistant has loop.
+    // See issue #298. Segmented Curve isn't selected in Seam Allowance tool.
+    // https://bitbucket.org/dismine/valentina/issue/298/segmented-curve-isnt-selected-in-seam
+    // Code should clean loops in path.
+    QTest::newRow("Issue 298. Case1") << InputPointsIssue298Case1()
+                                      << 75.5906 // seam allowance width
+                                      << OutputPointsIssue298Case1();
+
+    QTest::newRow("Issue 298. Case2") << InputPointsIssue298Case2()
+                                      << 37.7953 // seam allowance width
+                                      << OutputPointsIssue298Case2();
+
+    // See issue #548. Bug Detail tool. Case when seam allowance is wrong.
+    // https://bitbucket.org/dismine/valentina/issues/548/bug-detail-tool-case-when-seam-allowance
+    // Files: Steampunk_trousers.val and marie.vit
+    // Actually buggy detail see in file src/app/share/collection/bugs/Steampunk_trousers_issue_#548.val
+    // Code should clean loops in path.
+    QTest::newRow("Issue 548. Case1") << InputPointsIssue548Case1()
+                                      << 11.338582677165354 // seam allowance width (0.3 cm)
+                                      << OutputPointsIssue548Case1();
+
+    QTest::newRow("Issue 548. Case2") << InputPointsIssue548Case2()
+                                      << 37.795275590551185 // seam allowance width (1.0 cm)
+                                      << OutputPointsIssue548Case2();
+
+    QTest::newRow("Issue 548. Case3") << InputPointsIssue548Case3()
+                                      << 75.59055118110237 // seam allowance width (2.0 cm)
+                                      << OutputPointsIssue548Case3();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::EquidistantRemoveLoop() const
+{
+    QFETCH(QVector<VSAPoint>, points);
+    QFETCH(qreal, width);
+    QFETCH(QVector<QPointF>, ekvOrig);
+
+    const QVector<QPointF> ekv = VAbstractPiece::Equidistant(points, width);
+
+    // Begin comparison
+    Comparison(ekv, ekvOrig);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VSAPoint> TST_VAbstractPiece::InputPointsCase1() const
+{
+
+    QVector<VSAPoint> points;
+
+    VSAPoint p = VSAPoint(30.0, 894.8030236220472);
+    p.SetSAAfter(0);
+    p.SetSABefore(75.59055118110237);
+    points.append(p);
+
+    p = VSAPoint(30.0, 39.999874015748034);
+    //////p.SetSAAfter(-1);
+    p.SetSABefore(0);
+    points.append(p);
+
+    p = VSAPoint(30.0, 39.999874015748034);
+    //////p.SetSAAfter(-1);
+    p.SetSABefore(0);
+    points.append(p);
+
+    p = VSAPoint(47.64159471849116, 39.94788491648882);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(76.58589406160007, 39.22029871626823);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(96.8510955083063, 38.214779786537555);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(117.72526111352542, 36.63514697516433);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(139.00155591749595, 34.36192982961571);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(160.47314496045635, 31.27565789735886);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(181.9331932826451, 27.25686072586095);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(203.17486592430072, 22.18606786258914);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(223.99132792566166, 15.943808855010598);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(239.1756066691363, 10.378329140641144);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(249.07102191481937, 6.266596479372291);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(258.7437898355629, 1.7947951524770347);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(268.16805606139667, -3.0520086466112275);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(277.3179662223507, -8.2887487244591);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(286.16766594845456, -13.93035888763319);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(294.69130086973814, -19.991772942700095);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(302.86301661623133, -26.48792469622643);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(310.6569588179638, -33.433747954778795);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(318.04727310496537, -40.84417652492378);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(325.00810510726603, -48.73414421322801);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(331.51360045489537, -57.118584826258086);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(334.56692913385825, -61.522435695538036);
+    p.SetSAAfter(0);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(334.56692913385825, -61.522435695538036);
+    p.SetSAAfter(0);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(519.4465667350105, -36.01405338211436);
+    //////p.SetSAAfter(-1);
+    p.SetSABefore(0);
+    points.append(p);
+
+    p = VSAPoint(460.3937007874016, 342.36207874015753);
+    //////p.SetSAAfter(-1);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(620.5290071875437, -5.50631876178551);
+    p.SetSAAfter(0);
+    //////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(944.2945933263424, 136.63905516701567);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(0);
+    points.append(p);
+
+    p = VSAPoint(944.2945933263424, 136.63905516701567);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(0);
+    points.append(p);
+
+    p = VSAPoint(937.525981220313, 150.5000566598672);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(924.7444201119979, 177.43472401968558);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(912.8425448338431, 203.43742191080565);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(901.7902332810357, 228.52240953585334);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(891.5573633487625, 252.7039460974546);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(882.1138129322104, 275.99629079823535);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(869.2733175133695, 309.4054580978942);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(854.7606685168345, 350.82610676604395);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(842.8630996965477, 388.94665363817853);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(833.3396342140044, 423.88117233530545);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(825.9492952306994, 455.7437364784321);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(820.4511059081283, 484.6484196885659);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(816.6040894077858, 510.7092955867147);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(814.1672688911672, 534.0404377938855);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(812.8996675197675, 554.7559199310863);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(812.5603084550817, 572.9698156193242);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(812.9082148586052, 588.7961984796068);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(814.1809574610598, 608.5715133604979);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(815.1968503937007, 618.5825511811024);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(815.1968503937007, 618.5825511811024);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(815.7375399808675, 623.4475087782134);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(817.2456173381056, 633.4974833757362);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(819.2665464515061, 643.8914388413946);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(821.8012316951542, 654.584830268716);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(824.8505774431355, 665.5331127512278);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(828.4154880695357, 676.6917413824576);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(832.4968679484402, 688.0161712559327);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(837.0956214539344, 699.4618574651809);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(842.212652960104, 710.9842551037295);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(847.8488668410344, 722.5388192651058);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(854.0051674708111, 734.0810050428374);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(860.6824592235198, 745.5662675304518);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(867.8816464732456, 756.9500618214765);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(875.6036335940746, 768.187843009439);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(883.8493249600917, 779.2350661878667);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(892.6196249453828, 790.0471864502871);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(901.9154379240335, 800.5796588902277);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(911.7376682701291, 810.7879386012161);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(922.0872203577552, 820.6274806767794);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(932.9649985609971, 830.0537402104453);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(944.3719072539405, 839.0221722957415);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(956.3088508106711, 847.4882320261951);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(968.776733605274, 855.4073744953336);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(981.7764600118351, 862.7350547966848);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(995.3089344044396, 869.4267280237759);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(1009.3750611571733, 875.4378492701345);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(1023.9757446441214, 880.7238736292878);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(1039.1118892393697, 885.2402561947638);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(1054.784399317004, 888.9424520600894);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(1070.994179251109, 891.7859163187926);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(1087.7421334157707, 893.7261040644007);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(1105.0291661850742, 894.7184703904409);
+    p.SetSAAfter(188.97637795275591);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(1113.8976377952758, 894.8030236220472);
+    p.SetSAAfter(0);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    p = VSAPoint(1113.8976377952758, 894.8030236220472);
+    p.SetSAAfter(0);
+    p.SetSABefore(188.97637795275591);
+    points.append(p);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> TST_VAbstractPiece::OutputPointsCase1() const
+{
+    QVector<QPointF> points;
+
+    points += QPointF(30.00000000000004, 970.3929479721926);
+    points += QPointF(30.0, 2.204434307474013);
+    points += QPointF(47.110950439162494, 2.154008996440882);
+    points += QPointF(75.17428353484098, 1.4485680510386028);
+    points += QPointF(94.48820285018608, 0.4902498458165696);
+    points += QPointF(114.29080866669788, -1.0082936883322242);
+    points += QPointF(134.30369213200785, -3.146524533710341);
+    points += QPointF(154.30324182399514, -6.0212092507409025);
+    points += QPointF(174.06202812984606, -9.721413151776975);
+    points += QPointF(193.35089649585723, -14.32603434620921);
+    points += QPointF(212.04908234619523, -19.93308318294329);
+    points += QPointF(225.4146962614004, -24.83196935145066);
+    points += QPointF(233.88383173589082, -28.35105572413872);
+    points += QPointF(242.16354279128632, -32.17883523742874);
+    points += QPointF(250.12919225691988, -36.27548734456109);
+    points += QPointF(257.76141086050376, -40.64361165848513);
+    points += QPointF(265.0438386703493, -45.28609897626606);
+    points += QPointF(271.9635110924753, -50.20688688697322);
+    points += QPointF(278.5110730948284, -55.4119084151831);
+    points += QPointF(284.68071875165725, -60.91018735939974);
+    points += QPointF(290.46975730117975, -66.71498198586181);
+    points += QPointF(295.87773947883056, -72.84482460043537);
+    points += QPointF(301.0311752209645, -79.48669791277798);
+    points += QPointF(292.5914051639158, -67.31392104851938);
+    points += QPointF(556.8930273120665, -30.847456102511416);
+    points += QPointF(539.6101141051189, 79.89131577778163);
+    points += QPointF(585.9167315845334, -20.702420721823447);
+    points += QPointF(1117.4712505569892, 212.6701769158142);
+    points += QPointF(1107.8013393916237, 232.47256047676322);
+    points += QPointF(1096.0328222042483, 257.2724337531229);
+    points += QPointF(1085.2347243947604, 280.86364678273935);
+    points += QPointF(1075.284743777034, 303.4467181585846);
+    points += QPointF(1066.1500107021461, 325.033221582634);
+    points += QPointF(1057.8916931702825, 345.40221101096097);
+    points += QPointF(1046.6844069650929, 374.5619971088514);
+    points += QPointF(1034.1843603449327, 410.2384638595294);
+    points += QPointF(1024.281900134066, 441.9665592645446);
+    points += QPointF(1016.6128103198599, 470.0987514791772);
+    points += QPointF(1010.8915481272591, 494.7652903217387);
+    points += QPointF(1006.8300406648394, 516.1171535751373);
+    points += QPointF(1004.140951447517, 534.3338730421456);
+    points += QPointF(1002.5429209641061, 549.6340874837038);
+    points += QPointF(1001.7684597861733, 562.2905401031172);
+    points += QPointF(1001.5753826870504, 572.6532694631434);
+    points += QPointF(1001.7511114738644, 580.6472328726268);
+    points += QPointF(1002.5244573746393, 592.6631414076071);
+    points += QPointF(1011.1831553003773, 625.860901250618);
+    points += QPointF(1013.5469326629959, 631.1835932583286);
+    points += QPointF(1016.1978697144372, 636.6181674061058);
+    points += QPointF(1019.1173567112357, 642.0917891993197);
+    points += QPointF(1022.283791807397, 647.5382096308747);
+    points += QPointF(1025.6730034935645, 652.8974380139866);
+    points += QPointF(1029.258679857382, 658.1156604426072);
+    points += QPointF(1033.0128662502555, 663.1453581470851);
+    points += QPointF(1036.906587776057, 667.9455799725583);
+    points += QPointF(1040.910648783598, 672.4823173517011);
+    points += QPointF(1044.9966554234593, 676.7289189086724);
+    points += QPointF(1049.138296281844, 680.666466074281);
+    points += QPointF(1053.3128972071952, 684.2840128781046);
+    points += QPointF(1057.5032369521043, 687.5785757108713);
+    points += QPointF(1061.6995688685456, 690.5547476668297);
+    points += QPointF(1065.9017414956827, 693.2238137995831);
+    points += QPointF(1070.1212524492987, 695.6022659553563);
+    points += QPointF(1074.3830151134682, 697.7096649640421);
+    points += QPointF(1078.7265805419665, 699.565875909043);
+    points += QPointF(1083.206554246492, 701.1878034134409);
+    points += QPointF(1087.8919933013688, 702.5858632116882);
+    points += QPointF(1092.8646688655851, 703.7605199081748);
+    points += QPointF(1098.2162239125396, 704.699271425244);
+    points += QPointF(1104.0444208482252, 705.3744462055462);
+    points += QPointF(1304.758494368609, 711.4626979457951);
+    points += QPointF(1293.9429531218987, 1089.1048479381132);
+    points += QPointF(30.00000000000004, 970.3929479721926);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VSAPoint> TST_VAbstractPiece::InputPointsCase2() const
+{
+
+    QVector<VSAPoint> points;
+
+    VSAPoint p = VSAPoint(30.0, 39.999874015748034);
+    ////p.SetSAAfter(-1);
+    ////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(407.9527559055118, 39.999874015748034);
+    ////p.SetSAAfter(-1);
+    ////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(407.9527559055118, 228.97625196850396);
+    ////p.SetSAAfter(-1);
+    ////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(407.9527559055118, 228.97625196850396);
+    ////p.SetSAAfter(-1);
+    ////p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(403.3769166670402, 231.4465511704684);
+    p.SetSAAfter(37.803178025111038);
+    p.SetSABefore(37.803178025111038);
+    points.append(p);
+
+    p = VSAPoint(394.1607984354165, 235.58132461572228);
+    p.SetSAAfter(37.818528535007879);
+    p.SetSABefore(37.818528535007879);
+    points.append(p);
+
+    p = VSAPoint(384.8923171505302, 238.7905285112787);
+    p.SetSAAfter(37.833434086432739);
+    p.SetSABefore(37.833434086432739);
+    points.append(p);
+
+    p = VSAPoint(375.59921131499664, 241.12018552459608);
+    p.SetSAAfter(37.847993627262561);
+    p.SetSABefore(37.847993627262561);
+    points.append(p);
+
+    p = VSAPoint(366.3092194314313, 242.61631832313287);
+    p.SetSAAfter(37.862293350550544);
+    p.SetSABefore(37.862293350550544);
+    points.append(p);
+
+    p = VSAPoint(357.0500800024495, 243.3249495743475);
+    p.SetSAAfter(37.876405426208798);
+    p.SetSABefore(37.876405426208798);
+    points.append(p);
+
+    p = VSAPoint(347.8495315306667, 243.2921019456984);
+    p.SetSAAfter(37.890387402651413);
+    p.SetSABefore(37.890387402651413);
+    points.append(p);
+
+    p = VSAPoint(338.73531251869827, 242.56379810464406);
+    p.SetSAAfter(37.904282247411182);
+    p.SetSABefore(37.904282247411182);
+    points.append(p);
+
+    p = VSAPoint(329.7351614691596, 241.18606071864286);
+    p.SetSAAfter(37.91811891950119);
+    p.SetSABefore(37.91811891950119);
+    points.append(p);
+
+    p = VSAPoint(320.876816884666, 239.20491245515328);
+    p.SetSAAfter(37.931913327979281);
+    p.SetSABefore(37.931913327979281);
+    points.append(p);
+
+    p = VSAPoint(312.18801726783295, 236.6663759816338);
+    p.SetSAAfter(37.945669528152067);
+    p.SetSABefore(37.945669528152067);
+    points.append(p);
+
+    p = VSAPoint(303.6965011212758, 233.61647396554275);
+    p.SetSAAfter(37.959381027682795);
+    p.SetSABefore(37.959381027682795);
+    points.append(p);
+
+    p = VSAPoint(295.43000694760997, 230.10122907433865);
+    p.SetSAAfter(37.973032106608528);
+    p.SetSABefore(37.973032106608528);
+    points.append(p);
+
+    p = VSAPoint(287.41627324945074, 226.16666397547993);
+    p.SetSAAfter(37.986599088053786);
+    p.SetSABefore(37.986599088053786);
+    points.append(p);
+
+    p = VSAPoint(279.6830385294136, 221.85880133642502);
+    p.SetSAAfter(38.000051524725791);
+    p.SetSABefore(38.000051524725791);
+    points.append(p);
+
+    p = VSAPoint(272.2580412901139, 217.2236638246324);
+    p.SetSAAfter(38.013353288194111);
+    p.SetSABefore(38.013353288194111);
+    points.append(p);
+
+    p = VSAPoint(265.16902003416703, 212.3072741075605);
+    p.SetSAAfter(38.026463563868212);
+    p.SetSABefore(38.026463563868212);
+    points.append(p);
+
+    p = VSAPoint(258.44371326418843, 207.15565485266765);
+    p.SetSAAfter(38.03933776597485);
+    p.SetSABefore(38.03933776597485);
+    points.append(p);
+
+    p = VSAPoint(252.1098594827934, 201.81482872741242);
+    p.SetSAAfter(38.051928395587325);
+    p.SetSABefore(38.051928395587325);
+    points.append(p);
+
+    p = VSAPoint(246.19519719259745, 196.33081839925325);
+    p.SetSAAfter(38.064185872874937);
+    p.SetSABefore(38.064185872874937);
+    points.append(p);
+
+    p = VSAPoint(240.72746489621585, 190.74964653564848);
+    p.SetSAAfter(38.076059384395691);
+    p.SetSABefore(38.076059384395691);
+    points.append(p);
+
+    p = VSAPoint(235.73440109626404, 185.11733580405664);
+    p.SetSAAfter(38.087497800100167);
+    p.SetSABefore(38.087497800100167);
+    points.append(p);
+
+    p = VSAPoint(231.24374429535737, 179.47990887193612);
+    p.SetSAAfter(38.098450736467157);
+    p.SetSABefore(38.098450736467157);
+    points.append(p);
+
+    p = VSAPoint(227.2832329961113, 173.88338840674544);
+    p.SetSAAfter(38.108869877607624);
+    p.SetSABefore(38.108869877607624);
+    points.append(p);
+
+    p = VSAPoint(223.88060570114112, 168.37379707594295);
+    p.SetSAAfter(38.118710724548052);
+    p.SetSABefore(38.118710724548052);
+    points.append(p);
+
+    p = VSAPoint(221.06360091306237, 162.99715754698713);
+    p.SetSAAfter(38.127935039089436);
+    p.SetSABefore(38.127935039089436);
+    points.append(p);
+
+    p = VSAPoint(218.8599571344903, 157.79949248733644);
+    p.SetSAAfter(38.136514404353001);
+    p.SetSABefore(38.136514404353001);
+    points.append(p);
+
+    p = VSAPoint(217.2974128680403, 152.82682456444928);
+    p.SetSAAfter(38.144435562325597);
+    p.SetSABefore(38.144435562325597);
+    points.append(p);
+
+    p = VSAPoint(216.40370661632784, 148.12517644578412);
+    p.SetSAAfter(38.15170849722444);
+    p.SetSABefore(38.15170849722444);
+    points.append(p);
+
+    p = VSAPoint(216.20657688196826, 143.7405707987994);
+    p.SetSAAfter(38.158378424653918);
+    p.SetSABefore(38.158378424653918);
+    points.append(p);
+
+    p = VSAPoint(216.7337621675769, 139.71903029095353);
+    p.SetSAAfter(38.164542166418755);
+    p.SetSABefore(38.164542166418755);
+    points.append(p);
+
+    p = VSAPoint(218.01300097576927, 136.10657758970495);
+    p.SetSAAfter(38.17036598425517);
+    p.SetSABefore(38.17036598425517);
+    points.append(p);
+
+    p = VSAPoint(218.97637795275608, 134.48806299212646);
+    p.SetSAAfter(38.173228346456696);
+    p.SetSABefore(38.173228346456696);
+    points.append(p);
+
+    p = VSAPoint(218.97637795275608, 134.48806299212646);
+    p.SetSAAfter(38.173228346456696);
+    p.SetSABefore(38.173228346456696);
+    points.append(p);
+
+    p = VSAPoint(218.97637795275608, 134.48806299212646);
+    p.SetSAAfter(38.173228346456696);
+    p.SetSABefore(38.173228346456696);
+    points.append(p);
+
+    p = VSAPoint(217.1202289172026, 137.73030103616844);
+    p.SetSAAfter(38.167995197589178);
+    p.SetSABefore(38.167995197589178);
+    points.append(p);
+
+    p = VSAPoint(212.6973363405255, 143.4397404435662);
+    p.SetSAAfter(38.157878743288215);
+    p.SetSABefore(38.157878743288215);
+    points.append(p);
+
+    p = VSAPoint(207.48487786706698, 148.24866810991395);
+    p.SetSAAfter(38.147944713012919);
+    p.SetSABefore(38.147944713012919);
+    points.append(p);
+
+    p = VSAPoint(201.55301739671896, 152.18989767496004);
+    p.SetSAAfter(38.137968823998783);
+    p.SetSABefore(38.137968823998783);
+    points.append(p);
+
+    p = VSAPoint(194.9719188293733, 155.29624277845284);
+    p.SetSAAfter(38.127775030254007);
+    p.SetSABefore(38.127775030254007);
+    points.append(p);
+
+    p = VSAPoint(187.81174606492203, 157.6005170601407);
+    p.SetSAAfter(38.117238836985599);
+    p.SetSABefore(38.117238836985599);
+    points.append(p);
+
+    p = VSAPoint(180.14266300325704, 159.13553415977202);
+    p.SetSAAfter(38.106283289982827);
+    p.SetSABefore(38.106283289982827);
+    points.append(p);
+
+    p = VSAPoint(172.0348335442702, 159.93410771709506);
+    p.SetSAAfter(38.094871286509886);
+    p.SetSABefore(38.094871286509886);
+    points.append(p);
+
+    p = VSAPoint(163.55842158785353, 160.02905137185826);
+    p.SetSAAfter(38.082997200945435);
+    p.SetSABefore(38.082997200945435);
+    points.append(p);
+
+    p = VSAPoint(154.78359103389897, 159.4531787638099);
+    p.SetSAAfter(38.070679409075119);
+    p.SetSABefore(38.070679409075119);
+    points.append(p);
+
+    p = VSAPoint(145.78050578229832, 158.23930353269841);
+    p.SetSAAfter(38.057954219352141);
+    p.SetSABefore(38.057954219352141);
+    points.append(p);
+
+    p = VSAPoint(136.61932973294367, 156.42023931827214);
+    p.SetSAAfter(38.044871166362007);
+    p.SetSABefore(38.044871166362007);
+    points.append(p);
+
+    p = VSAPoint(127.37022678572683, 154.0287997602794);
+    p.SetSAAfter(38.031489421641503);
+    p.SetSABefore(38.031489421641503);
+    points.append(p);
+
+    p = VSAPoint(118.10336084053982, 151.09779849846862);
+    p.SetSAAfter(38.017875048227786);
+    p.SetSABefore(38.017875048227786);
+    points.append(p);
+
+    p = VSAPoint(108.88889579727454, 147.66004917258803);
+    p.SetSAAfter(38.00409885919936);
+    p.SetSABefore(38.00409885919936);
+    points.append(p);
+
+    p = VSAPoint(99.79699555582292, 143.7483654223861);
+    p.SetSAAfter(37.990234686678903);
+    p.SetSABefore(37.990234686678903);
+    points.append(p);
+
+    p = VSAPoint(90.8978240160769, 139.3955608876111);
+    p.SetSAAfter(37.976357907221328);
+    p.SetSABefore(37.976357907221328);
+    points.append(p);
+
+    p = VSAPoint(82.26154507792839, 134.63444920801146);
+    p.SetSAAfter(37.962544096747962);
+    p.SetSABefore(37.962544096747962);
+    points.append(p);
+
+    p = VSAPoint(73.95832264126932, 129.49784402333552);
+    p.SetSAAfter(37.94886770258455);
+    p.SetSABefore(37.94886770258455);
+    points.append(p);
+
+    p = VSAPoint(66.05832060599164, 124.01855897333157);
+    p.SetSAAfter(37.935400622146403);
+    p.SetSABefore(37.935400622146403);
+    points.append(p);
+
+    p = VSAPoint(58.63170287198729, 118.22940769774803);
+    p.SetSAAfter(37.922210567500777);
+    p.SetSABefore(37.922210567500777);
+    points.append(p);
+
+    p = VSAPoint(51.74863333914817, 112.16320383633325);
+    p.SetSAAfter(37.90935907207141);
+    p.SetSABefore(37.90935907207141);
+    points.append(p);
+
+    p = VSAPoint(45.47927590736623, 105.85276102883554);
+    p.SetSAAfter(37.896898960241472);
+    p.SetSABefore(37.896898960241472);
+    points.append(p);
+
+    p = VSAPoint(39.8937944765334, 99.33089291500332);
+    p.SetSAAfter(37.884871055952601);
+    p.SetSABefore(37.884871055952601);
+    points.append(p);
+
+    p = VSAPoint(35.062352946541615, 92.63041313458488);
+    p.SetSAAfter(37.873299866072891);
+    p.SetSABefore(37.873299866072891);
+    points.append(p);
+
+    p = VSAPoint(31.055115217282804, 85.78413532732864);
+    p.SetSAAfter(37.86218797621639);
+    p.SetSABefore(37.86218797621639);
+    points.append(p);
+
+    p = VSAPoint(27.94224518864889, 78.82487313298289);
+    p.SetSAAfter(37.851509027526909);
+    p.SetSABefore(37.851509027526909);
+    points.append(p);
+
+    p = VSAPoint(25.793906760531815, 71.78544019129603);
+    p.SetSAAfter(37.841199561247805);
+    p.SetSABefore(37.841199561247805);
+    points.append(p);
+
+    p = VSAPoint(24.68026383282351, 64.69865014201642);
+    p.SetSAAfter(37.831150915024352);
+    p.SetSABefore(37.831150915024352);
+    points.append(p);
+
+    p = VSAPoint(24.671480305415898, 57.597316624892386);
+    p.SetSAAfter(37.821203708860601);
+    p.SetSABefore(37.821203708860601);
+    points.append(p);
+
+    p = VSAPoint(25.837720078200917, 50.514253279672296);
+    p.SetSAAfter(37.811148513024627);
+    p.SetSABefore(37.811148513024627);
+    points.append(p);
+
+    p = VSAPoint(28.2491470510705, 43.48227374610451);
+    p.SetSAAfter(37.800735391906976);
+    p.SetSABefore(37.800735391906976);
+    points.append(p);
+
+    p = VSAPoint(30.0, 39.999874015748034);
+    ////p.SetSAAfter(-1);
+    ////p.SetSABefore(-1);
+    points.append(p);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> TST_VAbstractPiece::OutputPointsCase2() const
+{
+    QVector<QPointF> points;
+
+    points += QPointF(6.735602739585184, 2.204598425196849);
+    points += QPointF(445.748031496063, 2.204598425196849);
+    points += QPointF(445.748031496063, 251.48446223243934);
+    points += QPointF(420.1672505436216, 265.34467354701);
+    points += QPointF(408.16868834563587, 270.74969811280204);
+    points += QPointF(395.75743565485675, 275.06821746196044);
+    points += QPointF(383.28015968092507, 278.216263983686);
+    points += QPointF(370.8288026520235, 280.2409452967658);
+    points += QPointF(358.4874104434599, 281.2043381226534);
+    points += QPointF(346.3281093878975, 281.1794055890767);
+    points += QPointF(334.4094715702431, 280.2452307190486);
+    points += QPointF(322.77695514341303, 278.48262025768446);
+    points += QPointF(311.46472096401544, 275.97070996938834);
+    points += QPointF(300.4980766475991, 272.78475431818316);
+    points += QPointF(289.8959627998986, 268.994968265893);
+    points += QPointF(279.67312801429796, 264.6661417252929);
+    points += QPointF(269.84184205634284, 259.8577269753623);
+    points += QPointF(260.4131332789275, 254.62414553625888);
+    points += QPointF(251.39760921382512, 249.0151257350064);
+    points += QPointF(242.80594716150756, 243.07593816151942);
+    points += QPointF(234.64914462550888, 236.84743207794344);
+    points += QPointF(226.93861367892654, 230.36578881474733);
+    points += QPointF(219.6862008839008, 223.6618981488572);
+    points += QPointF(212.90422632696564, 216.76022967199233);
+    points += QPointF(206.60567695694368, 209.67701009653408);
+    points += QPointF(200.8047886617048, 202.41742546763192);
+    points += QPointF(195.51846445950318, 194.97144814919497);
+    points += QPointF(195.49646472111115, 194.93594659378365);
+    points += QPointF(185.71068181674897, 196.88038239808796);
+    points += QPointF(174.06579870156523, 198.0108674081686);
+    points += QPointF(162.4698365016369, 198.12450807507133);
+    points += QPointF(150.93599464376967, 197.35134057907845);
+    points += QPointF(139.4731688630524, 195.78946993073865);
+    points += QPointF(128.09385198069478, 193.51339391764853);
+    points += QPointF(116.81695231109029, 190.58079085562875);
+    points += QPointF(105.66811291289228, 187.03735678012447);
+    points += QPointF(94.6789709925457, 182.91996300992662);
+    points += QPointF(83.88608373098256, 178.2585220934185);
+    points += QPointF(73.32986575781915, 173.07687844159756);
+    points += QPointF(63.05370660182625, 167.39293026852914);
+    points += QPointF(53.10337911388009, 161.21809122399117);
+    points += QPointF(43.52687054865665, 154.55612780781823);
+    points += QPointF(34.37485617471233, 147.40137397927876);
+    points += QPointF(25.702201154685437, 139.73635741878132);
+    points += QPointF(17.571137619050678, 131.52904674063026);
+    points += QPointF(10.057109595108484, 122.7304016692299);
+    points += QPointF(3.2585649313074336, 113.27395345986065);
+    points += QPointF(-2.688329688884947, 103.08109119247632);
+    points += QPointF(-7.591302782642628, 92.07847647311537);
+    points += QPointF(-11.187498579572614, 80.23547322967522);
+    points += QPointF(-13.151329717912063, 67.62324223181253);
+    points += QPointF(-13.149175120030888, 54.474729701833986);
+    points += QPointF(-10.94337542157982, 41.194055939258014);
+    points += QPointF(-6.654890183208465, 28.745230608885407);
+    points += QPointF(6.735602739585184, 2.204598425196849);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VSAPoint> TST_VAbstractPiece::InputPointsCase3() const
+{
+    QVector<VSAPoint> points;
+
+    VSAPoint p = VSAPoint(30.0, 39.999874015748034);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(407.9527559055118, 39.999874015748034);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(407.9527559055118, 228.97625196850396);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(407.9527559055118, 228.97625196850396);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(406.33770829042953, 232.38064611626584);
+    p.SetSAAfter(37.381380099110068);
+    p.SetSABefore(37.381380099110068);
+    points.append(p);
+
+    p = VSAPoint(402.870644734503, 238.5569810399819);
+    p.SetSAAfter(36.603370955765051);
+    p.SetSABefore(36.603370955765051);
+    points.append(p);
+
+    p = VSAPoint(399.14591058639644, 243.99520937172397);
+    p.SetSAAfter(35.879339211886929);
+    p.SetSABefore(35.879339211886929);
+    points.append(p);
+
+    p = VSAPoint(395.19316295581496, 248.71848383837556);
+    p.SetSAAfter(35.202813177025682);
+    p.SetSABefore(35.202813177025682);
+    points.append(p);
+
+    p = VSAPoint(391.04205895246355, 252.7499571668203);
+    p.SetSAAfter(34.56719781657663);
+    p.SetSABefore(34.56719781657663);
+    points.append(p);
+
+    p = VSAPoint(386.72225568604733, 256.1127820839417);
+    p.SetSAAfter(33.965870279175178);
+    p.SetSABefore(33.965870279175178);
+    points.append(p);
+
+    p = VSAPoint(382.2634102662714, 258.8301113166233);
+    p.SetSAAfter(33.392312673818843);
+    p.SetSABefore(33.392312673818843);
+    points.append(p);
+
+    p = VSAPoint(377.6951798028408, 260.9250975917487);
+    p.SetSAAfter(32.840273714828662);
+    p.SetSABefore(32.840273714828662);
+    points.append(p);
+
+    p = VSAPoint(373.0472214054606, 262.4208936362013);
+    p.SetSAAfter(32.303940879158468);
+    p.SetSABefore(32.303940879158468);
+    points.append(p);
+
+    p = VSAPoint(368.34919218383584, 263.34065217686486);
+    p.SetSAAfter(31.778098176885351);
+    p.SetSABefore(31.778098176885351);
+    points.append(p);
+
+    p = VSAPoint(363.6307492476716, 263.7075259406228);
+    p.SetSAAfter(31.25824538248542);
+    p.SetSABefore(31.25824538248542);
+    points.append(p);
+
+    p = VSAPoint(358.921549706673, 263.5446676543588);
+    p.SetSAAfter(30.740662987580134);
+    p.SetSABefore(30.740662987580134);
+    points.append(p);
+
+    p = VSAPoint(354.251250670545, 262.87523004495625);
+    p.SetSAAfter(30.222419479548449);
+    p.SetSABefore(30.222419479548449);
+    points.append(p);
+
+    p = VSAPoint(349.6495092489928, 261.72236583929885);
+    p.SetSAAfter(29.701328542831337);
+    p.SetSABefore(29.701328542831337);
+    points.append(p);
+
+    p = VSAPoint(345.1459825517213, 260.1092277642701);
+    p.SetSAAfter(29.175869934623716);
+    p.SetSABefore(29.175869934623716);
+    points.append(p);
+
+    p = VSAPoint(340.7703276884358, 258.0589685467535);
+    p.SetSAAfter(28.645088729374258);
+    p.SetSABefore(28.645088729374258);
+    points.append(p);
+
+    p = VSAPoint(336.5522017688411, 255.59474091363262);
+    p.SetSAAfter(28.108485094878901);
+    p.SetSABefore(28.108485094878901);
+    points.append(p);
+
+    p = VSAPoint(332.52126190264244, 252.73969759179104);
+    p.SetSAAfter(27.565902911541084);
+    p.SetSABefore(27.565902911541084);
+    points.append(p);
+
+    p = VSAPoint(328.7071651995449, 249.51699130811238);
+    p.SetSAAfter(27.017421899167815);
+    p.SetSABefore(27.017421899167815);
+    points.append(p);
+
+    p = VSAPoint(325.1395687692534, 245.94977478948007);
+    p.SetSAAfter(26.463255170503039);
+    p.SetSABefore(26.463255170503039);
+    points.append(p);
+
+    p = VSAPoint(321.84812972147313, 242.06120076277773);
+    p.SetSAAfter(25.903652411137717);
+    p.SetSABefore(25.903652411137717);
+    points.append(p);
+
+    p = VSAPoint(318.86250516590917, 237.87442195488893);
+    p.SetSAAfter(25.338808050829666);
+    p.SetSABefore(25.338808050829666);
+    points.append(p);
+
+    p = VSAPoint(316.2123522122665, 233.4125910926972);
+    p.SetSAAfter(24.768773642603289);
+    p.SetSABefore(24.768773642603289);
+    points.append(p);
+
+    p = VSAPoint(313.9273279702502, 228.69886090308609);
+    p.SetSAAfter(24.19337403613525);
+    p.SetSABefore(24.19337403613525);
+    points.append(p);
+
+    p = VSAPoint(312.03708954956545, 223.75638411293914);
+    p.SetSAAfter(23.612127698143627);
+    p.SetSABefore(23.612127698143627);
+    points.append(p);
+
+    p = VSAPoint(310.57129405991714, 218.60831344913998);
+    p.SetSAAfter(23.024172586797707);
+    p.SetSABefore(23.024172586797707);
+    points.append(p);
+
+    p = VSAPoint(309.55959861101053, 213.27780163857204);
+    p.SetSAAfter(22.42820018785644);
+    p.SetSABefore(22.42820018785644);
+    points.append(p);
+
+    p = VSAPoint(309.03166031255046, 207.788001408119);
+    p.SetSAAfter(21.822401444747854);
+    p.SetSABefore(21.822401444747854);
+    points.append(p);
+
+    p = VSAPoint(309.01713627424215, 202.1620654846643);
+    p.SetSAAfter(21.204429040574471);
+    p.SetSABefore(21.204429040574471);
+    points.append(p);
+
+    p = VSAPoint(309.5456836057906, 196.42314659509157);
+    p.SetSAAfter(20.57138043760828);
+    p.SetSABefore(20.57138043760828);
+    points.append(p);
+
+    p = VSAPoint(310.64695941690104, 190.59439746628436);
+    p.SetSAAfter(19.919804940549692);
+    p.SetSABefore(19.919804940549692);
+    points.append(p);
+
+    p = VSAPoint(312.35062081727835, 184.6989708251262);
+    p.SetSAAfter(19.24573577317911);
+    p.SetSABefore(19.24573577317911);
+    points.append(p);
+
+    p = VSAPoint(313.4645669291343, 181.73215748031558);
+    p.SetSAAfter(18.897637795275593);
+    p.SetSABefore(18.897637795275593);
+    points.append(p);
+
+    p = VSAPoint(313.4645669291343, 181.73215748031558);
+    p.SetSAAfter(18.897637795275593);
+    p.SetSABefore(18.897637795275593);
+    points.append(p);
+
+    p = VSAPoint(313.4645669291343, 181.73215748031558);
+    p.SetSAAfter(18.897637795275593);
+    p.SetSABefore(18.897637795275593);
+    points.append(p);
+
+    p = VSAPoint(313.4645669291343, 181.73215748031558);
+    p.SetSAAfter(18.897637795275593);
+    p.SetSABefore(18.897637795275593);
+    points.append(p);
+
+    p = VSAPoint(313.4645669291343, 181.73215748031558);
+    p.SetSAAfter(18.897637795275593);
+    p.SetSABefore(18.897637795275593);
+    points.append(p);
+
+    p = VSAPoint(313.4645669291343, 181.73215748031558);
+    p.SetSAAfter(18.897637795275593);
+    p.SetSABefore(18.897637795275593);
+    points.append(p);
+
+    p = VSAPoint(313.4645669291343, 181.73215748031558);
+    p.SetSAAfter(18.897637795275593);
+    p.SetSABefore(18.897637795275593);
+    points.append(p);
+
+    p = VSAPoint(315.0998723566189, 177.44976641127198);
+    p.SetSAAfter(19.446824166328746);
+    p.SetSABefore(19.446824166328746);
+    points.append(p);
+
+    p = VSAPoint(317.6731184586346, 169.45847196043132);
+    p.SetSAAfter(20.452631980165769);
+    p.SetSABefore(20.452631980165769);
+    points.append(p);
+
+    p = VSAPoint(319.4487651643931, 162.13409856250706);
+    p.SetSAAfter(21.355546141728666);
+    p.SetSABefore(21.355546141728666);
+    points.append(p);
+
+    p = VSAPoint(320.470410593102, 155.4530193599665);
+    p.SetSAAfter(22.165276674578177);
+    p.SetSABefore(22.165276674578177);
+    points.append(p);
+
+    p = VSAPoint(320.78165286396893, 149.39160749527696);
+    p.SetSAAfter(22.892420458564697);
+    p.SetSABefore(22.892420458564697);
+    points.append(p);
+
+    p = VSAPoint(320.4260900962016, 143.92623611090573);
+    p.SetSAAfter(23.548583135932272);
+    p.SetSABefore(23.548583135932272);
+    points.append(p);
+
+    p = VSAPoint(319.44732040900783, 139.03327834932014);
+    p.SetSAAfter(24.146396878545747);
+    p.SetSABefore(24.146396878545747);
+    points.append(p);
+
+    p = VSAPoint(317.88894192159495, 134.68910735298743);
+    p.SetSAAfter(24.699324443869902);
+    p.SetSABefore(24.699324443869902);
+    points.append(p);
+
+    p = VSAPoint(315.79455275317093, 130.870096264375);
+    p.SetSAAfter(25.221147659605332);
+    p.SetSABefore(25.221147659605332);
+    points.append(p);
+
+    p = VSAPoint(313.2077510229431, 127.55261822595011);
+    p.SetSAAfter(25.725143604791594);
+    p.SetSABefore(25.725143604791594);
+    points.append(p);
+
+    p = VSAPoint(310.1721348501194, 124.71304638018006);
+    p.SetSAAfter(26.223136485113741);
+    p.SetSABefore(26.223136485113741);
+    points.append(p);
+
+    p = VSAPoint(306.73130235390744, 122.32775386953216);
+    p.SetSAAfter(26.724730852906816);
+    p.SetSABefore(26.724730852906816);
+    points.append(p);
+
+    p = VSAPoint(302.9288516535148, 120.3731138364737);
+    p.SetSAAfter(27.236947738833074);
+    p.SetSABefore(27.236947738833074);
+    points.append(p);
+
+    p = VSAPoint(298.80838086814924, 118.82549942347202);
+    p.SetSAAfter(27.764271724915222);
+    p.SetSABefore(27.764271724915222);
+    points.append(p);
+
+    p = VSAPoint(294.41348811701835, 117.66128377299438);
+    p.SetSAAfter(28.308962477298437);
+    p.SetSABefore(28.308962477298437);
+    points.append(p);
+
+    p = VSAPoint(289.7877715193297, 116.85684002750813);
+    p.SetSAAfter(28.871463995346204);
+    p.SetSABefore(28.871463995346204);
+    points.append(p);
+
+    p = VSAPoint(282.5270013648352, 116.23547488513984);
+    p.SetSAAfter(29.744519639698659);
+    p.SetSABefore(29.744519639698659);
+    points.append(p);
+
+    p = VSAPoint(272.4138025206039, 116.50169653372318);
+    p.SetSAAfter(30.956550523683344);
+    p.SetSABefore(30.956550523683344);
+    points.append(p);
+
+    p = VSAPoint(262.16207443587984, 117.7817223666835);
+    p.SetSAAfter(32.194294958045219);
+    p.SetSABefore(32.194294958045219);
+    points.append(p);
+
+    p = VSAPoint(252.12060206432426, 119.88653752375922);
+    p.SetSAAfter(33.423457501774081);
+    p.SetSABefore(33.423457501774081);
+    points.append(p);
+
+    p = VSAPoint(242.63817035959835, 122.62712714468876);
+    p.SetSAAfter(34.605995611034089);
+    p.SetSABefore(34.605995611034089);
+    points.append(p);
+
+    p = VSAPoint(234.06356427536352, 125.81447636921058);
+    p.SetSAAfter(35.70195258686585);
+    p.SetSABefore(35.70195258686585);
+    points.append(p);
+
+    p = VSAPoint(226.74556876528095, 129.25957033706317);
+    p.SetSAAfter(36.670979260736637);
+    p.SetSABefore(36.670979260736637);
+    points.append(p);
+
+    p = VSAPoint(221.03296878301197, 132.77339418798488);
+    p.SetSAAfter(37.474483357433364);
+    p.SetSABefore(37.474483357433364);
+    points.append(p);
+
+    p = VSAPoint(218.97637795275608, 134.48806299212646);
+    p.SetSAAfter(37.795275590551185);
+    p.SetSABefore(37.795275590551185);
+    points.append(p);
+
+    p = VSAPoint(218.97637795275608, 134.48806299212646);
+    p.SetSAAfter(37.795275590551185);
+    p.SetSABefore(37.795275590551185);
+    points.append(p);
+
+    p = VSAPoint(218.97637795275608, 134.48806299212646);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(218.97637795275608, 134.48806299212646);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(218.97637795275608, 134.48806299212646);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(218.97637795275608, 134.48806299212646);
+    p.SetSAAfter(37.795275590551185);
+    p.SetSABefore(37.795275590551185);
+    points.append(p);
+
+    p = VSAPoint(218.97637795275608, 134.48806299212646);
+    p.SetSAAfter(37.795275590551185);
+    p.SetSABefore(37.795275590551185);
+    points.append(p);
+
+    p = VSAPoint(214.11186185064025, 138.80795875858354);
+    p.SetSAAfter(36.653502722568419);
+    p.SetSABefore(36.653502722568419);
+    points.append(p);
+
+    p = VSAPoint(205.18536816471078, 146.02812964687715);
+    p.SetSAAfter(34.638570080274732);
+    p.SetSABefore(34.638570080274732);
+    points.append(p);
+
+    p = VSAPoint(197.17461091794695, 151.63888788459965);
+    p.SetSAAfter(32.922124316374287);
+    p.SetSABefore(32.922124316374287);
+    points.append(p);
+
+    p = VSAPoint(190.02702368501878, 155.74482471949955);
+    p.SetSAAfter(31.475467886854414);
+    p.SetSABefore(31.475467886854414);
+    points.append(p);
+
+    p = VSAPoint(183.69004004059613, 158.45053139932526);
+    p.SetSAAfter(30.266183845834068);
+    p.SetSABefore(30.266183845834068);
+    points.append(p);
+
+    p = VSAPoint(178.11109355934906, 159.86059917182507);
+    p.SetSAAfter(29.256280085066027);
+    p.SetSABefore(29.256280085066027);
+    points.append(p);
+
+    p = VSAPoint(173.23761781594754, 160.07961928474754);
+    p.SetSAAfter(28.400113855274189);
+    p.SetSABefore(28.400113855274189);
+    points.append(p);
+
+    p = VSAPoint(169.01704638506152, 159.21218298584108);
+    p.SetSAAfter(27.643914239586497);
+    p.SetSABefore(27.643914239586497);
+    points.append(p);
+
+    p = VSAPoint(165.396812841361, 157.36288152285397);
+    p.SetSAAfter(26.930461655777069);
+    p.SetSABefore(26.930461655777069);
+    points.append(p);
+
+    p = VSAPoint(162.32435075951594, 154.63630614353477);
+    p.SetSAAfter(26.20953145720112);
+    p.SetSABefore(26.20953145720112);
+    points.append(p);
+
+    p = VSAPoint(159.7470937141963, 151.13704809563185);
+    p.SetSAAfter(25.44681460859611);
+    p.SetSABefore(25.44681460859611);
+    points.append(p);
+
+    p = VSAPoint(157.61247528007215, 146.96969862689363);
+    p.SetSAAfter(24.625073374270738);
+    p.SetSABefore(24.625073374270738);
+    points.append(p);
+
+    p = VSAPoint(155.86792903181333, 142.23884898506853);
+    p.SetSAAfter(23.740148635253075);
+    p.SetSABefore(23.740148635253075);
+    points.append(p);
+
+    p = VSAPoint(154.46088854408993, 137.049090417905);
+    p.SetSAAfter(22.796456338245449);
+    p.SetSABefore(22.796456338245449);
+    points.append(p);
+
+    p = VSAPoint(152.84240084594785, 128.65747053734566);
+    p.SetSAAfter(21.296571460906105);
+    p.SetSABefore(21.296571460906105);
+    points.append(p);
+
+    p = VSAPoint(150.86615884353574, 110.74781740906135);
+    p.SetSAAfter(18.134320368513631);
+    p.SetSABefore(18.134320368513631);
+    points.append(p);
+
+    p = VSAPoint(149.37382105332603, 94.00159365355543);
+    p.SetSAAfter(15.183683963183684);
+    p.SetSABefore(15.183683963183684);
+    points.append(p);
+
+    p = VSAPoint(147.90386548781373, 84.77492816049366);
+    p.SetSAAfter(13.543967770207646);
+    p.SetSABefore(13.543967770207646);
+    points.append(p);
+
+    p = VSAPoint(146.22482573007983, 79.58685396281504);
+    p.SetSAAfter(12.586956110891197);
+    p.SetSABefore(12.586956110891197);
+    points.append(p);
+
+    p = VSAPoint(144.767673193039, 77.0483056159666);
+    p.SetSAAfter(12.073257080584666);
+    p.SetSABefore(12.073257080584666);
+    points.append(p);
+
+    p = VSAPoint(142.9646628872432, 75.4105345645091);
+    p.SetSAAfter(11.645769545279848);
+    p.SetSABefore(11.645769545279848);
+    points.append(p);
+
+    p = VSAPoint(140.76322838736246, 74.77813205619103);
+    p.SetSAAfter(11.243788560650403);
+    p.SetSABefore(11.243788560650403);
+    points.append(p);
+
+    p = VSAPoint(138.11080326806675, 75.25568933876076);
+    p.SetSAAfter(10.77079881073082);
+    p.SetSABefore(10.77079881073082);
+    points.append(p);
+
+    p = VSAPoint(134.95482110402602, 76.94779765996674);
+    p.SetSAAfter(10.142330100270035);
+    p.SetSABefore(10.142330100270035);
+    points.append(p);
+
+    p = VSAPoint(131.24271546991025, 79.95904826755734);
+    p.SetSAAfter(9.3034514353721871);
+    p.SetSABefore(9.3034514353721871);
+    points.append(p);
+
+    p = VSAPoint(126.92191994038947, 84.39403240928104);
+    p.SetSAAfter(8.216780859744869);
+    p.SetSABefore(8.216780859744869);
+    points.append(p);
+
+    p = VSAPoint(124.4881889763782, 87.24396850393732);
+    p.SetSAAfter(7.559055118110237);
+    p.SetSABefore(7.559055118110237);
+    points.append(p);
+
+    p = VSAPoint(124.4881889763782, 87.24396850393732);
+    p.SetSAAfter(7.559055118110237);
+    p.SetSABefore(7.559055118110237);
+    points.append(p);
+
+    p = VSAPoint(124.4881889763782, 87.24396850393732);
+    //p.SetSAAfter(-1);
+    p.SetSABefore(7.559055118110237);
+    points.append(p);
+
+    p = VSAPoint(124.4881889763782, 87.24396850393732);
+    //p.SetSAAfter(-1);
+    p.SetSABefore(7.559055118110237);
+    points.append(p);
+
+    p = VSAPoint(124.4881889763782, 87.24396850393732);
+    //p.SetSAAfter(-1);
+    p.SetSABefore(7.559055118110237);
+    points.append(p);
+
+    p = VSAPoint(124.4881889763782, 87.24396850393732);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(124.4881889763782, 87.24396850393732);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(121.4053345233613, 90.85541892105327);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(115.36650087404239, 97.1700051724747);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(109.48439793077911, 102.44240810316538);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(103.76400391356904, 106.72573235606063);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(98.2102970424097, 110.0730825740958);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(92.8282555372987, 112.53756340020624);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(87.62285761823352, 114.17227947732721);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(82.59908150521179, 115.03033544839411);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(77.76190541823104, 115.16483595634224);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(73.11630757728881, 114.62888564410696);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(68.66726620238268, 113.47558915462355);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(64.41975951351019, 111.7580511308274);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(60.3787657306689, 109.52937621565376);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(56.54926307385639, 106.84266905203805);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(52.93622976307019, 103.75103428291555);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(49.54464401830785, 100.30757655122164);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(44.854132804201555, 94.62627097468447);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(39.45938535079082, 86.2656734510919);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(35.040036121431584, 77.45366765004954);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(31.635910876104337, 68.61509071504);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(29.28683537478949, 60.17477978954592);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(28.03263537746753, 52.55757201704999);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(27.913136644118886, 46.188304541034846);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(28.62975536807624, 42.54811226326452);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(29.458368599363588, 40.697718569632514);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    p = VSAPoint(30.0, 39.999874015748034);
+    //p.SetSAAfter(-1);
+    //p.SetSABefore(-1);
+    points.append(p);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> TST_VAbstractPiece::OutputPointsCase3() const
+{
+    QVector<QPointF> points;
+
+    points += QPointF(11.491153250328935, 2.204598425196849);
+    points += QPointF(445.748031496063, 2.204598425196849);
+    points += QPointF(445.748031496063, 239.25772323190495);
+    points += QPointF(437.3011718875349, 252.9620940028659);
+    points += QPointF(431.5210396453687, 261.04286502132345);
+    points += QPointF(425.0742362286929, 268.54423500057675);
+    points += QPointF(418.11166285006243, 275.22268157509825);
+    points += QPointF(410.66293904201643, 281.0200956238725);
+    points += QPointF(402.78657384181963, 285.87157614021027);
+    points += QPointF(394.5732042205309, 289.71737969963584);
+    points += QPointF(386.1419584708077, 292.51680859777775);
+    points += QPointF(377.62937764888807, 294.2596521460023);
+    points += QPointF(369.17363576502424, 294.9709765895621);
+    points += QPointF(360.89908762820056, 294.7076951308071);
+    points += QPointF(352.90578450956633, 293.54885121734077);
+    points += QPointF(345.2659401705694, 291.58363457828597);
+    points += QPointF(338.02638381419206, 288.9008829382743);
+    points += QPointF(331.214452254774, 285.58206377611566);
+    points += QPointF(324.8447893417784, 281.69791760615396);
+    points += QPointF(318.92540323684557, 277.307901893045);
+    points += QPointF(313.4622927999198, 272.4613294067597);
+    points += QPointF(308.4626029358523, 267.199302528306);
+    points += QPointF(303.93656720661477, 261.5568795640949);
+    points += QPointF(299.8985555961715, 255.5651950634023);
+    points += QPointF(296.3674859139379, 249.25344082283073);
+    points += QPointF(293.36675891047514, 242.65070430384247);
+    points += QPointF(290.9237823363554, 235.7876787648548);
+    points += QPointF(289.0690799250026, 228.6982245333719);
+    points += QPointF(287.8349531366277, 221.42069049439027);
+    points += QPointF(287.2536910795491, 213.9988201772971);
+    points += QPointF(287.3554164994589, 206.48200110960104);
+    points += QPointF(288.165803158891, 198.9246157503596);
+    points += QPointF(289.7040578703973, 191.38436170566055);
+    points += QPointF(291.98164916416846, 183.91963819443603);
+    points += QPointF(293.700387439861, 179.7469098237058);
+    points += QPointF(296.5884693392089, 171.49219190163677);
+    points += QPointF(297.59693481965496, 166.31235205234043);
+    points += QPointF(298.2857333094973, 160.53208953533525);
+    points += QPointF(298.43819035278193, 155.84335424804448);
+    points += QPointF(298.1940021729857, 152.25436961670644);
+    points += QPointF(297.7243212024687, 149.73346552056378);
+    points += QPointF(289.51401190033005, 145.54903057599236);
+    points += QPointF(285.1770288005626, 145.6959639947203);
+    points += QPointF(278.3617236899766, 146.6950293230864);
+    points += QPointF(271.14652259400714, 148.48714038237037);
+    points += QPointF(263.9194864200908, 150.92917578435245);
+    points += QPointF(257.2170705229372, 153.76755541765795);
+    points += QPointF(251.60582957396716, 156.6541701343772);
+    points += QPointF(247.78435692308207, 159.04593361720316);
+    points += QPointF(241.3885876220272, 164.12014968959915);
+    points += QPointF(236.47226924439926, 167.68896212834986);
+    points += QPointF(220.7012128062336, 176.43583903855628);
+    points += QPointF(209.5894888372958, 181.6299305429989);
+    points += QPointF(198.8701621522812, 185.51474135189684);
+    points += QPointF(188.2122212804039, 188.0080506184889);
+    points += QPointF(177.3148127107667, 188.81408257358973);
+    points += QPointF(166.19194469464537, 187.37324105698534);
+    points += QPointF(155.57420181410697, 183.17620217869953);
+    points += QPointF(146.72912660379956, 176.5077748886884);
+    points += QPointF(140.4165418057526, 168.5601760939351);
+    points += QPointF(136.398647544906, 160.4725908270882);
+    points += QPointF(134.00844184248987, 152.736031987575);
+    points += QPointF(132.67609691771358, 145.39573210082384);
+    points += QPointF(132.02477039749073, 138.2597894386109);
+    points += QPointF(131.93387537548404, 132.84913141002448);
+    points += QPointF(124.89904457045232, 138.11668139199287);
+    points += QPointF(115.8895831399309, 143.54689645077573);
+    points += QPointF(106.4111230253516, 147.88716086368487);
+    points += QPointF(96.50699490577813, 150.99747783054613);
+    points += QPointF(86.32454442321412, 152.7366302609282);
+    points += QPointF(76.11298204383012, 153.0205687205323);
+    points += QPointF(66.1751535607697, 151.8740677833447);
+    points += QPointF(56.79043276012441, 149.44132674047353);
+    points += QPointF(48.150859730789605, 145.94779600016403);
+    points += QPointF(40.340747704632996, 141.64039002708367);
+    points += QPointF(33.35598458760446, 136.7400113658245);
+    points += QPointF(27.139387101639755, 131.42053399597268);
+    points += QPointF(21.454249077112927, 125.64844566928473);
+    points += QPointF(14.297732218982075, 116.98023078208763);
+    points += QPointF(6.592092174102573, 105.03828991585031);
+    points += QPointF(0.43109819620648937, 92.75351406859683);
+    points += QPointF(-4.287700865002457, 80.50147704363812);
+    points += QPointF(-7.673598677574605, 68.33582707450634);
+    points += QPointF(-9.704701735666333, 56.0002075290815);
+    points += QPointF(-9.95133102840429, 42.85489720779573);
+    points += QPointF(-7.622895431362345, 31.027194419301413);
+    points += QPointF(-3.18150493921823, 21.10903158131186);
+    points += QPointF(11.491153250328935, 2.204598425196849);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::SumTrapezoids() const
+{
+    // Case3 checks that the method 'SumTrapezoids' returns negative value for three clockwise allocated points
+    // Case4 checks that the method 'SumTrapezoids' returns positive value for three counterclock-wise allocated points
+    // Case5 checks that the method 'SumTrapezoids' returns 0 for one point
+    Case3();
+    Case4();
+    Case5();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::PathRemoveLoop_data() const
+{
+    QTest::addColumn<QVector<QPointF>>("path");
+    QTest::addColumn<QVector<QPointF>>("expect");
+
+    QVector<QPointF> path;
+    path << QPointF(10, 10);
+    path << QPointF(20, 10);
+    path << QPointF(20, 20);
+    path << QPointF(10, 20);
+    path << QPointF(10, 10);
+    QTest::newRow("Correct closed a path (four unique points)") << path << path;
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
+    path.remove(path.size() - 1);
+#else
+    path.removeLast();
+#endif
+    QTest::newRow("Correct unclosed a path (four unique points)") << path << path;
+
+    path.clear();
+    path << QPointF(0, 10);
+    path << QPointF(10, 10);
+    path << QPointF(20, 10);
+    path << QPointF(20, 20);
+    path << QPointF(10, 20);
+    path << QPointF(0, 20);
+    path << QPointF(0, 10);
+    QTest::newRow("Correct closed a path (six unique points)") << path << path;
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
+    path.remove(path.size() - 1);
+#else
+    path.removeLast();
+#endif
+    QTest::newRow("Correct unclosed a path (six unique points)") << path << path;
+
+    path.clear();
+    path << QPointF(20, 10);
+    path << QPointF(20, 20);
+    path << QPointF(10, 10);
+    path << QPointF(10, 20);
+    path << QPointF(20, 10);
+
+    QVector<QPointF> res;
+    res << QPointF(20, 10);
+    res << QPointF(20, 20);
+    res << QPointF(15, 15);
+    res << QPointF(20, 10);
+    QTest::newRow("One loop, closed a path (four unique points)") << path << res;
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
+    path.remove(path.size() - 1);
+    res.remove(res.size() - 1);
+#else
+    path.removeLast();
+    res.removeLast();
+#endif
+    QTest::newRow("One loop, unclosed a path (four unique points)") << path << res;
+
+    path.clear();
+    path << QPointF(20, 10);
+    path << QPointF(20, 20);
+    path << QPointF(10, 10);
+    path << QPointF(0, 20);
+    path << QPointF(0, 10);
+    path << QPointF(10, 20);
+    path << QPointF(20, 10);
+
+    res.clear();
+    res << QPointF(20, 10);
+    res << QPointF(20, 20);
+    res << QPointF(15, 15);
+    res << QPointF(20, 10);
+    QTest::newRow("Two loops, closed a path (six unique points)") << path << res;
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
+    path.remove(path.size() - 1);
+    res.remove(res.size() - 1);
+#else
+    path.removeLast();
+    res.removeLast();
+#endif
+    QTest::newRow("Two loops, unclosed a path (six unique points)") << path << res;
+
+    path.clear();
+    path << QPointF(20, 10);
+    path << QPointF(20, 20);
+    path << QPointF(10, 10);
+    path << QPointF(0, 10);
+    path << QPointF(0, 20);
+    path << QPointF(10, 20);
+    path << QPointF(20, 10);
+
+    res.clear();
+    res << QPointF(20, 10);
+    res << QPointF(20, 20);
+    res << QPointF(15, 15);
+    res << QPointF(20, 10);
+    QTest::newRow("One loop, the first loop, closed a path (six unique points)") << path << res;
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
+    path.remove(path.size() - 1);
+    res.remove(res.size() - 1);
+#else
+    path.removeLast();
+    res.removeLast();
+#endif
+    QTest::newRow("One loop, the first loop, unclosed a path (six unique points)") << path << res;
+
+    path.clear();
+    path << QPointF(20, 10);
+    path << QPointF(20, 20);
+    path << QPointF(10, 20);
+    path << QPointF(0, 10);
+    path << QPointF(0, 20);
+    path << QPointF(10, 10);
+    path << QPointF(20, 10);
+
+    res.clear();
+    res << QPointF(20, 10);
+    res << QPointF(20, 20);
+    res << QPointF(10, 20);
+    res << QPointF(5, 15);
+    res << QPointF(10, 10);
+    res << QPointF(20, 10);
+    QTest::newRow("One loop, the second loop, closed a path (six unique points)") << path << res;
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
+    path.remove(path.size() - 1);
+    res.remove(res.size() - 1);
+#else
+    path.removeLast();
+    res.removeLast();
+#endif
+    QTest::newRow("One loop, the second loop, unclosed a path (six unique points)") << path << res;
+
+    path.clear();
+    path << QPointF(20, 10);
+    path << QPointF(20, 20);
+    path << QPointF(10, 20);
+    path << QPointF(20, 15);
+    path << QPointF(10, 10);
+    path << QPointF(20, 10);
+    QTest::newRow("Correct closed a path, point on line (four unique points)") << path << path;
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
+    path.remove(path.size() - 1);
+#else
+    path.removeLast();
+#endif
+    QTest::newRow("Corect unclosed a path, point on line (four unique points)") << path << path;
+
+    path.clear();
+    path << QPointF(20, 10);
+    path << QPointF(10, 15);
+    path << QPointF(20, 20);
+    path << QPointF(10, 20);
+    path << QPointF(0, 20);
+    path << QPointF(10, 15);
+    path << QPointF(0, 10);
+    path << QPointF(10, 10);
+    path << QPointF(20, 10);
+
+    QTest::newRow("Correct closed a path, point on line (six unique points)") << path << path;
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
+    path.remove(path.size() - 1);
+#else
+    path.removeLast();
+#endif
+    QTest::newRow("Corect unclosed a path, point on line (six unique points)") << path << path;
+
+    path.clear();
+    path << QPointF(100.96979100571033, 1797.6153764073072);
+    path << QPointF(168.3888427659865, 1807.2395034187866);
+    path << QPointF(206.78076137364403, 1812.2910842036706);
+    path << QPointF(239.1630793382262, 1815.951361623424);
+    path << QPointF(267.5320085054171, 1818.4827543754482);
+    path << QPointF(293.9502505847841, 1820.144031725603);
+    path << QPointF(320.48133946750147, 1821.175819320443);
+    path << QPointF(364.5960626489172, 1822.0507669842166);
+    path << QPointF(400.66867742260206, 1822.488188976378);
+    path << QPointF(623.3126833308274, 1822.488188976378);
+    path << QPointF(653.5489038032683, 2162.6456692913384);
+    path << QPointF(570.545584385708, 2162.6456692913384);
+    path << QPointF(600.7818048581489, 1822.488188976378);
+    path << QPointF(1001.3385826771654, 1822.488188976378);
+    path << QPointF(1001.3385826771654, 2680.44094488189);
+    path << QPointF(-22.11646613738226, 2680.44094488189);
+    path << QPointF(100.96979100571033, 1797.6153764073072);
+
+    res.clear();
+    res << QPointF(100.96979100571033, 1797.6153764073072);
+    res << QPointF(168.3888427659865, 1807.2395034187866);
+    res << QPointF(206.78076137364403, 1812.2910842036706);
+    res << QPointF(239.1630793382262, 1815.951361623424);
+    res << QPointF(267.5320085054171, 1818.4827543754482);
+    res << QPointF(293.9502505847841, 1820.144031725603);
+    res << QPointF(320.48133946750147, 1821.175819320443);
+    res << QPointF(364.5960626489172, 1822.0507669842166);
+    res << QPointF(400.66867742260206, 1822.488188976378);
+    res << QPointF(1001.3385826771654, 1822.488188976378);
+    res << QPointF(1001.3385826771654, 2680.44094488189);
+    res << QPointF(-22.11646613738226, 2680.44094488189);
+    res << QPointF(100.96979100571033, 1797.6153764073072);
+
+    // See the file "collection/bugs/Issue_#493.val"
+    QTest::newRow("Test case issue #493") << path << res;
+
+    path.clear();
+    path << QPointF(-685.2149804319953, -3568.7982439212556);
+    path << QPointF(-700.7415523087261, -3623.900571239949);
+    path << QPointF(-675.4694480627154, -3639.3631430823175);
+    path << QPointF(-684.7497934439581, -3631.3546395862268);
+    path << QPointF(-683.1356602239256, -3633.2868478418427);
+    path << QPointF(-686.8764821039574, -3627.927414863926);
+    path << QPointF(-684.7670104817863, -3631.587853202178);
+    path << QPointF(-682.2386030572435, -3636.8469922361573);
+    path << QPointF(-676.4708011186385, -3650.307478525872);
+    path << QPointF(-666.3050989871189, -3676.5286567894937);
+    path << QPointF(-654.0449409043066, -3710.198553447806);
+    path << QPointF(-640.1333287371614, -3750.0101920374505);
+    path << QPointF(-617.0729873733014, -3818.3303697354913);
+    path << QPointF(-583.8128392515604, -3920.9726624886944);
+    path << QPointF(-550.5307668482033, -4027.6970214479597);
+    path << QPointF(-527.4164674104215, -4104.7034088569535);
+    path << QPointF(-513.4302533332675, -4152.73879565781);
+    path << QPointF(-501.0373006826446, -4196.767296675345);
+    path << QPointF(-490.59311078227046, -4235.660899517831);
+    path << QPointF(-477.25724163384456, -4288.293444470835);
+    path << QPointF(-405.3839593893572, -4272.013803282615);
+    path << QPointF(-545.9786893428341, -3568.830152982464);
+    path << QPointF(-685.2149804319953, -3568.7982439212556);
+
+    res.clear();
+    res << QPointF(-685.2149804319953, -3568.7982439212556);
+    res << QPointF(-700.7415523087261, -3623.900571239949);
+    res << QPointF(-683.3457668881176, -3634.5440688767967);
+    res << QPointF(-682.2386030572435, -3636.8469922361573);
+    res << QPointF(-676.4708011186385, -3650.307478525872);
+    res << QPointF(-666.3050989871189, -3676.5286567894937);
+    res << QPointF(-654.0449409043066, -3710.198553447806);
+    res << QPointF(-640.1333287371614, -3750.0101920374505);
+    res << QPointF(-617.0729873733014, -3818.3303697354913);
+    res << QPointF(-583.8128392515604, -3920.9726624886944);
+    res << QPointF(-550.5307668482033, -4027.6970214479597);
+    res << QPointF(-527.4164674104215, -4104.7034088569535);
+    res << QPointF(-513.4302533332675, -4152.73879565781);
+    res << QPointF(-501.0373006826446, -4196.767296675345);
+    res << QPointF(-490.59311078227046, -4235.660899517831);
+    res << QPointF(-477.25724163384456, -4288.293444470835);
+    res << QPointF(-405.3839593893572, -4272.013803282615);
+    res << QPointF(-545.9786893428341, -3568.830152982464);
+    res << QPointF(-685.2149804319953, -3568.7982439212556);
+
+    // See the file "collection/bugs/Issue_#515.val"
+    // Check a seam allowance path.
+    // The curve that causes the issue is the first in the list.
+    QTest::newRow("Test case issue #515. Big loop in seam allowance path.") << path << res;
+
+    path.clear();
+    path << QPointF(-449.6699112298347, -4243.2921010175705);
+    path << QPointF(-576.966638263205, -3606.6183279948636);
+    path << QPointF(-656.9465284876832, -3606.6183279948636);
+    path << QPointF(-656.5996104603414, -3606.6000783462687);
+    path << QPointF(-655.7439133016985, -3607.1236310612317);
+    path << QPointF(-654.129780081666, -3609.0558393168476);
+    path << QPointF(-651.3154902471701, -3613.939306009108);
+    path << QPointF(-647.8207651830382, -3621.2084054506768);
+    path << QPointF(-641.4701586077349, -3636.0289997859454);
+    path << QPointF(-630.9244502073004, -3663.23035747934);
+    path << QPointF(-618.4465305467888, -3697.4982896415795);
+    path << QPointF(-604.3873016966293, -3737.732371148936);
+    path << QPointF(-581.1891087215608, -3806.460957656939);
+    path << QPointF(-547.7936207285052, -3909.520915257629);
+    path << QPointF(-514.3891332445846, -4016.6378180116963);
+    path << QPointF(-491.17181635142833, -4093.9874129706236);
+    path << QPointF(-477.094588519539, -4142.335384784734);
+    path << QPointF(-464.5941701318652, -4186.745679830414);
+    path << QPointF(-454.0214632588362, -4226.117872983938);
+
+    res.clear();
+    res << QPointF(-449.6699112298347, -4243.2921010175705);
+    res << QPointF(-576.966638263205, -3606.6183279948636);
+    res << QPointF(-656.5697831440032, -3606.6183279948636);
+    res << QPointF(-655.7439133016985, -3607.1236310612317);
+    res << QPointF(-654.129780081666, -3609.0558393168476);
+    res << QPointF(-651.3154902471701, -3613.939306009108);
+    res << QPointF(-647.8207651830382, -3621.2084054506768);
+    res << QPointF(-641.4701586077349, -3636.0289997859454);
+    res << QPointF(-630.9244502073004, -3663.23035747934);
+    res << QPointF(-618.4465305467888, -3697.4982896415795);
+    res << QPointF(-604.3873016966293, -3737.732371148936);
+    res << QPointF(-581.1891087215608, -3806.460957656939);
+    res << QPointF(-547.7936207285052, -3909.520915257629);
+    res << QPointF(-514.3891332445846, -4016.6378180116963);
+    res << QPointF(-491.17181635142833, -4093.9874129706236);
+    res << QPointF(-477.094588519539, -4142.335384784734);
+    res << QPointF(-464.5941701318652, -4186.745679830414);
+    res << QPointF(-454.0214632588362, -4226.117872983938);
+
+    // See the file "collection/bugs/Issue_#515.val"
+    // Check a seam allowance path.
+    // The curve that causes the issue is the last in the list.
+    QTest::newRow("Test case issue #515. Small loop in seam allowance path.") << path << res;
+
+    path.clear();
+    path << QPointF(1229.6503937007876, 937.6667716535435);
+    path << QPointF(203.08931117793543, 937.6667716535435);
+    path << QPointF(459.7677349767701, -2166.704563141019);
+    path << QPointF(1229.6503937007876, -1990.077167189857);
+    path << QPointF(1229.6503937007876, -555.2466141732282);
+    path << QPointF(920.1053824527112, -555.2466141732282);
+    path << QPointF(887.034516310979, -63.90803149606281);
+    path << QPointF(816.3607592795726, -63.908031496062826);
+    path << QPointF(780.7580397937137, -592.8627210002539);
+    path << QPointF(816.0241340748559, -1202.917917917055);
+    path << QPointF(887.3711415156957, -1202.917917917055);
+    path << QPointF(920.4420076574283, -630.8371653543306);
+    path << QPointF(1229.6503937007876, -630.8371653543306);
+    path << QPointF(1229.6503937007876, 937.6667716535435);
+
+    res.clear();
+    res << QPointF(1229.6503937007876, 937.6667716535435);
+    res << QPointF(203.08931117793543, 937.6667716535435);
+    res << QPointF(459.7677349767702, -2166.704563141019);
+    res << QPointF(1229.6503937007876, -1990.077167189857);
+    res << QPointF(1229.6503937007876, 937.6667716535435);
+
+    // See the file "collection/bugs/Issue_#603.val"
+    // Point H1 is first in the list
+    QTest::newRow("Test issue 603.") << path << res;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::PathRemoveLoop() const
+{
+    QFETCH(QVector<QPointF>, path);
+    QFETCH(QVector<QPointF>, expect);
+
+    QVector<QPointF> res = VAbstractPiece::CheckLoops(path);
+    Comparison(res, expect);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::PathLoopsCase_data() const
+{
+    QTest::addColumn<QVector<QPointF>>("path");
+    QTest::addColumn<QVector<QPointF>>("expect");
+
+    QVector<QPointF> path;
+    path << QPointF(61.86670866141733, 446.92270866141735);
+    path << QPointF(650.6504606788366, 473.2192016666484);
+    path << QPointF(649.4426552757304, 480.5376973511262);
+    path << QPointF(646.5769170924987, 501.9977838630714);
+    path << QPointF(644.6382908004568, 523.6358081043691);
+    path << QPointF(643.4592698551749, 551.9888717674471);
+    path << QPointF(642.9134698671897, 584.1776423714557);
+    path << QPointF(643.1914832622404, 613.2382010061506);
+    path << QPointF(644.2199668178571, 639.3780275889782);
+    path << QPointF(645.9255773115714, 662.8046020373845);
+    path << QPointF(648.2349715209137, 683.7254042688159);
+    path << QPointF(651.0748062234152, 702.3479142007185);
+    path << QPointF(654.3717381966065, 718.8796117505387);
+    path << QPointF(658.0524242180187, 733.5279768357226);
+    path << QPointF(662.0435210651824, 746.5004893737165);
+    path << QPointF(666.2716855156286, 758.0046292819667);
+    path << QPointF(670.6635743468883, 768.2478764779191);
+    path << QPointF(677.400406718071, 781.7952098705392);
+    path << QPointF(691.6740007010135, 806.2608114022295);
+    path << QPointF(694.5877745571677, 810.2150054671212);
+    path << QPointF(699.9560352035193, 816.1706553153153);
+    path << QPointF(708.9007628091615, 824.0594196166176);
+    path << QPointF(719.3794725391945, 831.7499791040799);
+    path << QPointF(730.9568541500198, 839.0942359684872);
+    path << QPointF(743.1975973980386, 845.9440924006244);
+    path << QPointF(755.6663920396528, 852.1514505912763);
+    path << QPointF(767.9279278312633, 857.568212731228);
+    path << QPointF(779.5468945292718, 862.046281011264);
+    path << QPointF(790.0879818900794, 865.4375576221694);
+    path << QPointF(799.115879670088, 867.5939447547289);
+    path << QPointF(804.5608128209333, 868.2650594004886);
+    path << QPointF(807.5317661719646, 868.2782441618697);
+    path << QPointF(809.8795601157717, 867.8994015359809);
+    path << QPointF(811.5497808719051, 867.1100192966705);
+    path << QPointF(812.4880146599148, 865.8915852177861);
+    path << QPointF(812.6398476993509, 864.2255870731761);
+    path << QPointF(811.9508662097637, 862.0935126366886);
+    path << QPointF(810.3666564107034, 859.4768496821717);
+    path << QPointF(806.3216663321919, 854.66911491981);
+    path << QPointF(802.0871811023624, 850.6707401574804);
+    path << QPointF(799.4598981526765, 850.6707401574804);
+    path << QPointF(802.0871811023624, 1653.9337322834645);
+    path << QPointF(61.86670866141733, 1653.9337322834645);
+
+    QVector<QPointF> res;
+    res << QPointF(61.86670866141733, 446.92270866141735);
+    res << QPointF(650.6504606788366, 473.2192016666484);
+    res << QPointF(649.4426552757304, 480.5376973511262);
+    res << QPointF(646.5769170924987, 501.9977838630714);
+    res << QPointF(644.6382908004568, 523.6358081043691);
+    res << QPointF(643.4592698551749, 551.9888717674471);
+    res << QPointF(642.9134698671897, 584.1776423714557);
+    res << QPointF(643.1914832622404, 613.2382010061506);
+    res << QPointF(644.2199668178571, 639.3780275889782);
+    res << QPointF(645.9255773115714, 662.8046020373845);
+    res << QPointF(648.2349715209137, 683.7254042688159);
+    res << QPointF(651.0748062234152, 702.3479142007185);
+    res << QPointF(654.3717381966065, 718.8796117505387);
+    res << QPointF(658.0524242180187, 733.5279768357226);
+    res << QPointF(662.0435210651824, 746.5004893737165);
+    res << QPointF(666.2716855156286, 758.0046292819667);
+    res << QPointF(670.6635743468883, 768.2478764779191);
+    res << QPointF(677.400406718071, 781.7952098705392);
+    res << QPointF(691.6740007010135, 806.2608114022295);
+    res << QPointF(694.5877745571677, 810.2150054671212);
+    res << QPointF(699.9560352035193, 816.1706553153153);
+    res << QPointF(708.9007628091615, 824.0594196166176);
+    res << QPointF(719.3794725391945, 831.7499791040799);
+    res << QPointF(730.9568541500198, 839.0942359684872);
+    res << QPointF(743.1975973980386, 845.9440924006244);
+    res << QPointF(755.6663920396528, 852.1514505912763);
+    res << QPointF(767.9279278312633, 857.568212731228);
+    res << QPointF(779.5468945292718, 862.046281011264);
+    res << QPointF(790.0879818900794, 865.4375576221694);
+    res << QPointF(799.115879670088, 867.5939447547289);
+    res << QPointF(799.5154110117976, 867.6431889469776);
+    res << QPointF(802.0871811023624, 1653.9337322834645);
+    res << QPointF(61.86670866141733, 1653.9337322834645);
+
+    // See file "collection/bugs/Issue_#609_case1.val"
+    // Clear a main path. Bound intersection. External loop. Outside a loop. Start point Ф1.
+    QTest::newRow("Issue 609. Case1a") << path << res;
+
+    path.clear();
+    path << QPointF(-365.68188649000314, -2143.126579528016);
+    path << QPointF(-195.75487873249062, -2116.7935769656237);
+    path << QPointF(-195.75487873249062, -1836.0319480765759);
+    path << QPointF(-233.39027086052477, -1838.4849618976993);
+    path << QPointF(-231.15080237392075, -1855.5915146519483);
+    path << QPointF(-225.84473077299972, -1889.4811404382626);
+    path << QPointF(-219.39861487985402, -1922.986407729537);
+    path << QPointF(-211.6695159016421, -1955.9990283342697);
+    path << QPointF(-204.87723909172885, -1980.439660924953);
+    path << QPointF(-199.87970909142098, -1996.6270828437923);
+    path << QPointF(-194.48099536000245, -2012.6451713592935);
+    path << QPointF(-188.65032933731845, -2028.5246588116781);
+    path << QPointF(-182.36812965707693, -2044.2602109802488);
+    path << QPointF(-175.61499879935675, -2059.8462252736344);
+    path << QPointF(-168.3717693169516, -2075.2768492268588);
+    path << QPointF(-160.6424572210866, -2090.5008865466684);
+    path << QPointF(-150.22847685877994, -2109.7385074212525);
+    path << QPointF(194.23861004296444, -2056.3576305273214);
+    path << QPointF(302.4787663409577, -1301.003761061316);
+    path << QPointF(279.86810151275455, -1288.330749878147);
+    path << QPointF(-641.7062267185897, -2051.118466118487);
+    path << QPointF(-365.68188649000314, -2143.126579528016);
+
+    res.clear();
+    res << QPointF(-365.68188649000314, -2143.126579528016);
+    res << QPointF(-195.75487873249062, -2116.7935769656237);
+    res << QPointF(-195.75487873249062, -2008.8655346469059);
+    res << QPointF(-194.48099536000245, -2012.6451713592935);
+    res << QPointF(-188.65032933731845, -2028.5246588116781);
+    res << QPointF(-182.36812965707693, -2044.2602109802488);
+    res << QPointF(-175.61499879935675, -2059.8462252736344);
+    res << QPointF(-168.3717693169516, -2075.2768492268588);
+    res << QPointF(-160.6424572210866, -2090.5008865466684);
+    res << QPointF(-150.22847685877994, -2109.7385074212525);
+    res << QPointF(194.23861004296444, -2056.3576305273214);
+    res << QPointF(302.4787663409577, -1301.003761061316);
+    res << QPointF(279.86810151275455, -1288.330749878147);
+    res << QPointF(-641.7062267185897, -2051.118466118487);
+    res << QPointF(-365.68188649000314, -2143.126579528016);
+
+    // See file "collection/bugs/Issue_#609_case2.val"
+    // Clear an equdistant. Bound intersection. Internal loop. Outside a loop. Start point А2.
+    QTest::newRow("Issue 609. Case2b") << path << res;
+
+    path.clear();
+    path << QPointF(0, 10);
+    path << QPointF(5, 10);
+    path << QPointF(2.5, 15);
+    path << QPointF(7.5, 15);
+    path << QPointF(5, 10);
+    path << QPointF(10, 10);
+    path << QPointF(10, 20);
+    path << QPointF(0, 20);
+    path << QPointF(0, 10);
+
+    QTest::newRow("Internal loop. Valid case.") << path << path;
+
+    path.clear();
+    path << QPointF(0, 10);
+    path << QPointF(5, 10);
+    path << QPointF(7.5, 15);
+    path << QPointF(2.5, 15);
+    path << QPointF(5, 10);
+    path << QPointF(10, 10);
+    path << QPointF(10, 20);
+    path << QPointF(0, 20);
+    path << QPointF(0, 10);
+
+    res.clear();
+    res << QPointF(0, 10);
+    res << QPointF(10, 10);
+    res << QPointF(10, 20);
+    res << QPointF(0, 20);
+    res << QPointF(0, 10);
+
+    QTest::newRow("Internal loop. Invalid case.") << path << res;
+
+    path.clear();
+    path << QPointF(0, 10);
+    path << QPointF(5, 10);
+    path << QPointF(0, 0);
+    path << QPointF(10, 0);
+    path << QPointF(5, 10);
+    path << QPointF(10, 10);
+    path << QPointF(10, 20);
+    path << QPointF(0, 20);
+    path << QPointF(0, 10);
+
+    QTest::newRow("External loop. Valid case.") << path << path;
+
+    path.clear();
+    path << QPointF(0, 10);
+    path << QPointF(5, 10);
+    path << QPointF(10, 0);
+    path << QPointF(0, 0);
+    path << QPointF(5, 10);
+    path << QPointF(10, 10);
+    path << QPointF(10, 20);
+    path << QPointF(0, 20);
+    path << QPointF(0, 10);
+
+    res.clear();
+    res << QPointF(0, 10);
+    res << QPointF(10, 10);
+    res << QPointF(10, 20);
+    res << QPointF(0, 20);
+    res << QPointF(0, 10);
+
+    QTest::newRow("External loop. Invalid case.") << path << res;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::PathLoopsCase() const
+{
+    QFETCH(QVector<QPointF>, path);
+    QFETCH(QVector<QPointF>, expect);
+
+    const QVector<QPointF> res = VAbstractPiece::CheckLoops(path);
+    Comparison(res, expect);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::BrokenDetailEquidistant_data() const
+{
+    QTest::addColumn<QVector<VSAPoint>>("points");
+    QTest::addColumn<qreal>("width");
+    QTest::addColumn<QVector<QPointF>>("ekvOrig");
+
+    // For more details see the file "collection/bugs/GAVAUDAN Laure - corsage - figure 4.val".
+    // We will test only one detail. The second require too accurate data that we cannot get from debuger.
+    // The test check an open equdistant of correct detail.
+    QVector<VSAPoint> points;// Input points.
+
+    qreal width = 37.795275590551185; // seam allowance width
+
+    VSAPoint point = VSAPoint(787.5835464566929, 1701.3138897637796);
+    point.SetSAAfter(width);
+    point.SetSABefore(0);
+    points.append(point);
+
+    point = VSAPoint(863.1740976377953, 1701.3138897637796);
+    point.SetSAAfter(width);
+    point.SetSAAfter(width);
+    points.append(point);
+
+    points.append(VSAPoint(938.7646488188976, 1701.3138897637796));
+    points.append(VSAPoint(928.6149944255945, 1732.4440762118775));
+    points.append(VSAPoint(910.0209054382323, 1792.3369946802652));
+    points.append(VSAPoint(893.3643210561819, 1849.7845240486258));
+    points.append(VSAPoint(878.5243977752426, 1905.2261712206746));
+    points.append(VSAPoint(865.3802920912136, 1959.1014431001254));
+    points.append(VSAPoint(853.8111604998944, 2011.8498465906928));
+    points.append(VSAPoint(843.6961594970844, 2063.910888596092));
+    points.append(VSAPoint(834.9144455785826, 2115.7240760200366));
+    points.append(VSAPoint(827.3451752401882, 2167.7289157662426));
+    points.append(VSAPoint(820.8675049777007, 2220.364914738423));
+    points.append(VSAPoint(815.3605912869193, 2274.0715798402925));
+    points.append(VSAPoint(810.703590663643, 2329.2884179755656));
+    points.append(VSAPoint(806.7756596036716, 2386.454936047957));
+    points.append(VSAPoint(803.455954602804, 2446.0106409611817));
+    points.append(VSAPoint(800.6236321568394, 2508.395039618954));
+    points.append(VSAPoint(798.1578487615775, 2574.047638924988));
+    points.append(VSAPoint(797.0323653543306, 2608.4005039370077));
+    points.append(VSAPoint(929.3158299212598, 2608.4005039370077));
+    points.append(VSAPoint(927.9285659612306, 2548.9599884455793));
+    points.append(VSAPoint(925.157717598664, 2463.8329634071292));
+    points.append(VSAPoint(922.7222742526749, 2408.6782012856274));
+    points.append(VSAPoint(919.6220036804666, 2354.5469017384876));
+    points.append(VSAPoint(915.706969354324, 2301.1170261784787));
+    points.append(VSAPoint(910.8272347465313, 2248.066536018368));
+    points.append(VSAPoint(904.8328633293736, 2195.073392670922));
+    points.append(VSAPoint(897.5739185751353, 2141.8155575489095));
+    points.append(VSAPoint(888.9004639561011, 2087.9709920650976));
+    points.append(VSAPoint(878.6625629445558, 2033.2176576322527));
+    points.append(VSAPoint(866.7102790127839, 1977.233515663143));
+    points.append(VSAPoint(852.8936756330698, 1919.696527570536));
+    points.append(VSAPoint(837.0628162776984, 1860.284654767199));
+    points.append(VSAPoint(819.0677644189545, 1798.675858665899));
+    points.append(VSAPoint(798.7585835291225, 1734.548100679404));
+    points.append(VSAPoint(787.5835464566929, 1701.3138897637796));
+
+    point = VSAPoint(797.0323653543306, 2608.4005039370077);
+    point.SetSAAfter(0);
+    point.SetSABefore(width);
+    points.append(point);
+
+    QVector<QPointF> ekvOrig;
+    ekvOrig.append(QPointF(735.0001191244485, 1663.5186141732283));
+    ekvOrig.append(QPointF(990.8407796109454, 1663.5186141732283));
+    ekvOrig.append(QPointF(964.6314897747087, 1743.9055956070622));
+    ekvOrig.append(QPointF(946.222111945205, 1803.203545947388));
+    ekvOrig.append(QPointF(929.7733236875301, 1859.9343993344141));
+    ekvOrig.append(QPointF(915.1430683369846, 1914.5927314447797));
+    ekvOrig.append(QPointF(902.2033477151627, 1967.6302665424967));
+    ekvOrig.append(QPointF(890.8261161082305, 2019.5037195040304));
+    ekvOrig.append(QPointF(880.8841829577946, 2070.673996127427));
+    ekvOrig.append(QPointF(872.2520522462703, 2121.604624314014));
+    ekvOrig.append(QPointF(864.8064761358401, 2172.759620123457));
+    ekvOrig.append(QPointF(864.2562272534083, 2177.2308109121955));
+    ekvOrig.append(QPointF(860.1867773842832, 2147.3738416825267));
+    ekvOrig.append(QPointF(851.6617474319463, 2094.450692409028));
+    ekvOrig.append(QPointF(841.5996933370075, 2040.6378051462616));
+    ekvOrig.append(QPointF(829.8479530577714, 1985.5930036729653));
+    ekvOrig.append(QPointF(816.2523082919595, 1928.9761616385213));
+    ekvOrig.append(QPointF(800.6574868367429, 1870.4501190599349));
+    ekvOrig.append(QPointF(782.9077406929495, 1809.6811643713463));
+    ekvOrig.append(QPointF(762.8278965797896, 1746.2775544138444));
+    ekvOrig.append(QPointF(735.0001191244485, 1663.5186141732283));
+
+    QTest::newRow("GAVAUDAN Laure.") << points << width << ekvOrig;
+
+    width = 11.338582677165354;
+
+    points.clear();
+    point = VSAPoint(97.33089106412862, -223.03306117556497);
+    point.SetSAAfter(width);
+    point.SetSABefore(0);
+    points.append(point);
+
+    point = VSAPoint(990.7494050554426, 2.819093995045);
+    point.SetSAAfter(width);
+    point.SetSABefore(width);
+    points.append(point);
+
+    point = VSAPoint(908.3966357321774, 379.5839357215547);
+    point.SetSAAfter(width);
+    point.SetSABefore(width);
+    points.append(point);
+
+    point = VSAPoint(-135.41154226686143, 697.6417881399819);
+    point.SetSAAfter(0);
+    point.SetSABefore(width);
+    points.append(point);
+
+    ekvOrig.clear();
+    ekvOrig.append(QPointF(100.10981413873267, -234.02583351343978));
+    ekvOrig.append(QPointF(1004.1704360325447, -5.483401649771952));
+    ekvOrig.append(QPointF(918.0553412376563, 388.4941212347381));
+    ekvOrig.append(QPointF(-138.65807550610091, 710.4843173601864));
+    ekvOrig.append(QPointF(100.10981413873267, -234.02583351343978));
+
+    // See the file "collection/bugs/Issue_#604.val" (since 0.5.0)
+    QTest::newRow("Issue #604.") << points << width << ekvOrig;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::BrokenDetailEquidistant() const
+{
+    QFETCH(QVector<VSAPoint>, points);
+    QFETCH(qreal, width);
+    QFETCH(QVector<QPointF>, ekvOrig);
+
+    const QVector<QPointF> ekv = VAbstractPiece::Equidistant(points, width);// Take result
+
+    // Begin comparison
+    Comparison(ekv, ekvOrig);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::CorrectEquidistantPoints_data() const
+{
+    // See file zigzag.val
+    QTest::addColumn<QVector<QPointF>>("points");
+    QTest::addColumn<QVector<QPointF>>("expect");
+    QTest::addColumn<bool>("removeFirstAndLast");
+
+    QVector<QPointF> points;
+    points.append(QPointF(-741.7894588053705, 1065.7336503858917));
+    points.append(QPointF(-759.696551643576, -115.81420543069257));
+    points.append(QPointF(-278.17249953019325, -217.1037453126913));
+    points.append(QPointF(-244.64654130659474, 1077.9548221866635));
+    points.append(QPointF(-741.7894588053705, 1065.7336503858917));
+
+    QVector<QPointF> expect;
+    expect.append(QPointF(-741.7894588053705, 1065.7336503858917));
+    expect.append(QPointF(-759.696551643576, -115.81420543069257));
+    expect.append(QPointF(-278.17249953019325, -217.1037453126913));
+    expect.append(QPointF(-244.64654130659474, 1077.9548221866635));
+    expect.append(QPointF(-741.7894588053705, 1065.7336503858917));
+
+    QTest::newRow("Closed seam allowance. Last point equal first.") << points << expect << false;
+
+    points.clear();
+    points.append(QPointF(-704.5489521643801, 1028.8424328418016));
+    points.append(QPointF(-721.4335720065426, -85.24049234531904));
+    points.append(QPointF(-707.7852899705758, 755.7064514429209));
+    points.append(QPointF(-721.4335720065426, -85.24049234531904));
+    points.append(QPointF(-314.78124296268265, -170.7806167067443));
+    points.append(QPointF(-283.4579031023758, 1039.1940357173805));
+
+    expect.clear();
+    expect.append(QPointF(-704.5489521643801, 1028.8424328418016));
+    expect.append(QPointF(-721.4335720065426, -85.24049234531904));
+    expect.append(QPointF(-314.78124296268265, -170.7806167067443));
+    expect.append(QPointF(-283.4579031023758, 1039.1940357173805));
+
+    QTest::newRow("Clearing bad main path.") << points << expect << true;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::CorrectEquidistantPoints() const
+{
+    QFETCH(QVector<QPointF>, points);
+    QFETCH(QVector<QPointF>, expect);
+    QFETCH(bool, removeFirstAndLast);
+
+    const QVector<QPointF> res = VAbstractPiece::CorrectEquidistantPoints(points, removeFirstAndLast);
+
+    // Begin comparison
+    Comparison(res, expect);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::TestCorrectEquidistantPoints_data()
+{
+    QTest::addColumn<QVector<QPointF>>("before");
+    QTest::addColumn<QVector<QPointF>>("expect");
+
+    QVector<QPointF> before;
+    before << QPointF(30.0, 39.999874015748034);
+    before << QPointF(785.9055118110236, 39.999874015748034);
+    before << QPointF(785.9055118110236, 3819.527433070866);
+    before << QPointF(483.54330708661416, 3819.527433070866);
+    before << QPointF(483.54330708661416, 1929.763653543307);
+    before << QPointF(407.9527559055629, 984.8817637795973);
+    before << QPointF(407.9527559055118, 1929.763653543307);
+    before << QPointF(407.9527559055118, 3819.527433070866);
+    before << QPointF(30.0, 3819.527433070866);
+
+    QVector<QPointF> expect;
+    expect << QPointF(30.0, 39.999874015748034);
+    expect << QPointF(785.9055118110236, 39.999874015748034);
+    expect << QPointF(785.9055118110236, 3819.527433070866);
+    expect << QPointF(483.54330708661416, 3819.527433070866);
+    expect << QPointF(483.54330708661416, 1929.763653543307);
+    expect << QPointF(407.9527559055629, 984.8817637795973);
+    expect << QPointF(407.9527559055118, 3819.527433070866);
+    expect << QPointF(30.0, 3819.527433070866);
+
+    QTest::newRow("Test case issue #548") << before << expect;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::TestCorrectEquidistantPoints() const
+{
+    QFETCH(QVector<QPointF>, before);
+    QFETCH(QVector<QPointF>, expect);
+
+    QVector<QPointF> after = VAbstractPiece::CorrectEquidistantPoints(before);
+    Comparison(after, expect);
+}
+
+#ifndef Q_OS_WIN
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::PossibleInfiniteClearLoops_data() const
+{
+    QTest::addColumn<QVector<QPointF>>("path");
+    QTest::addColumn<QVector<QPointF>>("expect");
+
+    QVector<QPointF> path;
+    path << QPointF(-670.6449010946802, 4046.36220472441);
+    path << QPointF(-1025.9051277126944, 4046.36220472441);
+    path << QPointF(-1026.4460203880594, 4010.5247429150854);
+    path << QPointF(-1027.2972172274538, 3924.202328582098);
+    path << QPointF(-1028.1383921346433, 3768.5948526129496);
+    path << QPointF(-1028.5065585022217, 3521.575730066707);
+    path << QPointF(-1028.2712136539103, 3252.2436039362233);
+    path << QPointF(-1027.2910122410117, 2850.1024469719814);
+    path << QPointF(-1025.9446023682538, 2439.350819630564);
+    path << QPointF(-1025.8983315247287, 2338.629525677473);
+    path << QPointF(-1025.3536572186458, 2309.970015878699);
+    path << QPointF(-1024.2100836932389, 2281.714612342931);
+    path << QPointF(-1022.5102766116828, 2253.846781520112);
+    path << QPointF(-1020.2969016371525, 2226.349989860186);
+    path << QPointF(-1017.6126244328227, 2199.207703813094);
+    path << QPointF(-1014.5001106618688, 2172.403389828782);
+    path << QPointF(-1011.0020259874652, 2145.9205143571917);
+    path << QPointF(-1005.1601480132764, 2106.7277181407126);
+    path << QPointF(-996.3625412018714, 2055.4921956731814);
+    path << QPointF(-986.7906327138169, 2005.2448233555149);
+    path << QPointF(-976.785747854512, 1955.8533327872588);
+    path << QPointF(-961.6606968634906, 1883.0158867454916);
+    path << QPointF(-947.5864881030896, 1811.4914675744105);
+    path << QPointF(-939.2629508127773, 1764.2008199992524);
+    path << QPointF(-933.8852659113251, 1728.8707137815559);
+    path << QPointF(-930.742733377741, 1705.3464944792456);
+    path << QPointF(-928.0252775410311, 1681.829576238578);
+    path << QPointF(-925.7755640643697, 1658.3034255094963);
+    path << QPointF(-924.036258610932, 1634.7515087419433);
+    path << QPointF(-922.850026843893, 1611.1572923858625);
+    path << QPointF(-922.2595344264276, 1587.504242891197);
+    path << QPointF(-922.3074470217107, 1563.7758267078902);
+    path << QPointF(-922.613405031688, 1551.8740157480315);
+    path << QPointF(-960.4086806222392, 841.3228346456693);
+    path << QPointF(-954.9336313684444, 841.5464781141166);
+    path << QPointF(-944.0363771538431, 841.3102753632543);
+    path << QPointF(-933.2160856340209, 840.291423017261);
+    path << QPointF(-922.4878118569704, 838.5316299985567);
+    path << QPointF(-911.8666108706839, 836.0726052295611);
+    path << QPointF(-901.3675377231535, 832.9560576326933);
+    path << QPointF(-891.005647462372, 829.2236961303737);
+    path << QPointF(-880.7959951363317, 824.9172296450213);
+    path << QPointF(-870.7536357930251, 820.0783670990559);
+    path << QPointF(-860.893624480444, 814.7488174148973);
+    path << QPointF(-851.2310162465817, 808.9702895149649);
+    path << QPointF(-841.7808661394299, 802.7844923216785);
+    path << QPointF(-832.5582292069812, 796.2331347574575);
+    path << QPointF(-823.578160497228, 789.3579257447218);
+    path << QPointF(-810.5607800373014, 778.5565764202543);
+    path << QPointF(-794.2367125298769, 763.3635567727296);
+    path << QPointF(-779.1539087770976, 747.6258919346988);
+    path << QPointF(-765.4328091629026, 731.6772532855191);
+    path << QPointF(-753.193854071231, 715.8513122045474);
+    path << QPointF(-742.557483886022, 700.4817400711408);
+    path << QPointF(-733.644138991215, 685.9022082646563);
+    path << QPointF(-726.5742597707488, 672.446388164451);
+    path << QPointF(-721.4682866085625, 660.447951149882);
+    path << QPointF(-718.6229063234249, 651.1532303788147);
+    path << QPointF(-716.6036430255488, 642.9038041285014);
+    path << QPointF(-714.137568179324, 630.1235656609365);
+    path << QPointF(-711.8605525364693, 612.2344502588126);
+    path << QPointF(-710.4560555432737, 593.4222205889721);
+    path << QPointF(-709.4234847119759, 563.5940176156308);
+    path << QPointF(-708.952111561728, 520.4666582691573);
+    path << QPointF(-708.4401766852314, 497.3858267716535);
+    path << QPointF(-400.92922424489655, 469.03937007874015);
+    path << QPointF(-708.4401766852314, 440.6929133858268);
+    path << QPointF(-708.7078446526739, 341.66122584661264);
+    path << QPointF(-709.3427685457568, 299.60322373665383);
+    path << QPointF(-710.6909230403871, 257.048095841136);
+    path << QPointF(-713.0251717477311, 214.57984397612822);
+    path << QPointF(-715.632864794307, 183.1716335401434);
+    path << QPointF(-717.7953694429818, 162.55016633308693);
+    path << QPointF(-720.3578834261159, 142.27891915519677);
+    path << QPointF(-723.3545146951046, 122.43089223348173);
+    path << QPointF(-725.0465030138121, 112.71059563115871);
+    path << QPointF(-219.59055118110237, -35.52755905511811);
+    path << QPointF(-218.99352387527398, -33.21125072212394);
+    path << QPointF(-217.35724543521775, -28.699086141666157);
+    path << QPointF(-215.20035586903225, -24.33136255454731);
+    path << QPointF(-212.53403014110648, -20.10796717265881);
+    path << QPointF(-209.36944321582945, -16.02878720789205);
+    path << QPointF(-205.71777005759026, -12.093709872138447);
+    path << QPointF(-201.59018563077785, -8.302622377289406);
+    path << QPointF(-196.99786489978123, -4.65541193523633);
+    path << QPointF(-189.3170483291933, 0.5638303631539586);
+    path << QPointF(-177.47808861476295, 6.996342387787443);
+    path << QPointF(-163.981333042598, 12.855376387191757);
+    path << QPointF(-148.91618132781048, 18.141834666235646);
+    path << QPointF(-132.37203318551252, 22.856619529787864);
+    path << QPointF(-114.43828833081622, 27.00063328271716);
+    path << QPointF(-95.20434647883366, 30.574778229892296);
+    path << QPointF(-74.75960734467688, 33.57995667618201);
+    path << QPointF(-53.193470643458, 36.01707092645505);
+    path << QPointF(-30.595336090289106, 37.887023285580185);
+    path << QPointF(-7.0546034002822875, 39.19071605842615);
+    path << QPointF(17.339327711450373, 39.929051549861704);
+    path << QPointF(29.858267716535437, 40.06299212598426);
+    path << QPointF(-45.73228346456693, 1589.6692913385828);
+    path << QPointF(-45.73228346456693, 4046.36220472441);
+    path << QPointF(-297.70078740157487, 4046.36220472441);
+    path << QPointF(-297.70078740157487, 2118.8031496062995);
+    path << QPointF(-222.1102362204725, 1589.6692913385828);
+    path << QPointF(-297.70078740157487, 1060.535433070866);
+    path << QPointF(-373.2913385826772, 1589.6692913385828);
+    path << QPointF(-297.70078740157487, 2118.8031496062995);
+    path << QPointF(-297.70078740157487, 4046.36220472441);
+    path << QPointF(-670.6449010946802, 4046.36220472441);
+    path << QPointF(-670.6449010946802, 2024.3149606299214);
+    path << QPointF(-622.7555214134819, 1570.7716535433071);
+    path << QPointF(-670.6449010946802, 1117.2283464566929);
+    path << QPointF(-718.5342807758785, 1570.7716535433071);
+    path << QPointF(-670.6449010946802, 2024.3149606299214);
+
+    QVector<QPointF> expect;
+    expect << QPointF(-670.6449010946802, 4046.36220472441);
+    expect << QPointF(-670.6449010946802, 4046.36220472441);
+    expect << QPointF(-670.6449010946802, 2024.3149606299214);
+    expect << QPointF(-670.6449010946802, 2024.3149606299214);
+    expect << QPointF(-670.6449010946802, 2024.3149606299214);
+
+    // See the file "collection/bugs/possible_inf_loop.val"
+    QTest::newRow("Possible infinite loop") << path << expect;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::PossibleInfiniteClearLoops() const
+{
+    QFETCH(QVector<QPointF>, path);
+    QFETCH(QVector<QPointF>, expect);
+
+    QVector<QPointF> res = VAbstractPiece::CheckLoops(path);
+    Comparison(res, expect);
+}
+#endif //#ifndef Q_OS_WIN
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::Case3() const
+{
+    const QVector<QPointF> points = InputPointsCase3a(); // Input points.
+
+    const qreal result = VAbstractPiece::SumTrapezoids(points);
+    QVERIFY(result < 0);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::Case4() const
+{
+    const QVector<QPointF> points = InputPointsCase4a(); // Input points.
+
+    const qreal result = VAbstractPiece::SumTrapezoids(points);
+    QVERIFY(result > 0);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void TST_VAbstractPiece::Case5() const
+{
+    const QVector<QPointF> points = InputPointsCase5a(); // Input points.
+
+    const qreal result = VAbstractPiece::SumTrapezoids(points);
+    QVERIFY(qFuzzyIsNull(result));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VSAPoint> TST_VAbstractPiece::InputPointsIssue298Case1() const
+{
+    QVector<VSAPoint> points;
+
+    points += VSAPoint(35, 39.9999);
+    points += VSAPoint(412.953, 39.9999);
+    points += VSAPoint(417.135, 417.929);
+    points += VSAPoint(417.135, 417.929);
+    points += VSAPoint(408.797, 405.589);
+    points += VSAPoint(390.909, 377.669);
+    points += VSAPoint(362.315, 330.86);
+    points += VSAPoint(323.075, 264.247);
+    points += VSAPoint(286.15, 201.448);
+    points += VSAPoint(262.477, 162.745);
+    points += VSAPoint(249.22, 142.455);
+    points += VSAPoint(241.092, 131.261);
+    points += VSAPoint(236.545, 125.75);
+    points += VSAPoint(232.808, 122.058);
+    points += VSAPoint(230.6, 120.629);
+    points += VSAPoint(229.393, 120.277);
+    points += VSAPoint(228.421, 120.456);
+    points += VSAPoint(227.69, 121.185);
+    points += VSAPoint(227.033, 123.272);
+    points += VSAPoint(227.112, 128.232);
+    points += VSAPoint(228.29, 135.699);
+    points += VSAPoint(230.625, 145.81);
+    points += VSAPoint(234.173, 158.703);
+    points += VSAPoint(241.73, 183.168);
+    points += VSAPoint(248.796, 204.144);
+    points += VSAPoint(248.796, 204.144);
+    points += VSAPoint(251.528, 212.406);
+    points += VSAPoint(255.482, 227.075);
+    points += VSAPoint(257.717, 239.591);
+    points += VSAPoint(258.279, 247.554);
+    points += VSAPoint(258.203, 252.278);
+    points += VSAPoint(257.756, 256.51);
+    points += VSAPoint(256.949, 260.264);
+    points += VSAPoint(255.795, 263.547);
+    points += VSAPoint(254.308, 266.372);
+    points += VSAPoint(252.501, 268.749);
+    points += VSAPoint(250.385, 270.688);
+    points += VSAPoint(247.974, 272.201);
+    points += VSAPoint(245.281, 273.296);
+    points += VSAPoint(242.319, 273.986);
+    points += VSAPoint(239.1, 274.28);
+    points += VSAPoint(233.846, 274.05);
+    points += VSAPoint(226.022, 272.393);
+    points += VSAPoint(217.402, 269.345);
+    points += VSAPoint(208.09, 264.991);
+    points += VSAPoint(198.186, 259.414);
+    points += VSAPoint(187.795, 252.7);
+    points += VSAPoint(177.019, 244.933);
+    points += VSAPoint(165.96, 236.197);
+    points += VSAPoint(154.721, 226.576);
+    points += VSAPoint(143.405, 216.157);
+    points += VSAPoint(132.113, 205.022);
+    points += VSAPoint(120.95, 193.257);
+    points += VSAPoint(110.017, 180.946);
+    points += VSAPoint(99.4167, 168.174);
+    points += VSAPoint(89.2522, 155.024);
+    points += VSAPoint(79.626, 141.582);
+    points += VSAPoint(70.6405, 127.933);
+    points += VSAPoint(62.3985, 114.16);
+    points += VSAPoint(55.0025, 100.348);
+    points += VSAPoint(48.5551, 86.5823);
+    points += VSAPoint(43.159, 72.9466);
+    points += VSAPoint(38.9167, 59.5258);
+    points += VSAPoint(35.9309, 46.4042);
+    points += VSAPoint(35, 39.9999);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> TST_VAbstractPiece::OutputPointsIssue298Case1() const
+{
+    QVector<QPointF> points;
+    points += QPointF(-52.3724798442221, -35.5907);
+    points += QPointF(487.7117748779425, -35.5907);
+    points += QPointF(493.3432017362585, 473.32371517914754);
+    points += QPointF(385.98559977345093, 506.8445742667132);
+    points += QPointF(345.64704646524604, 447.1446764706891);
+    points += QPointF(326.82411403464874, 417.76541252489994);
+    points += QPointF(297.4844355409708, 369.73572061014266);
+    points += QPointF(280.35686644039447, 340.63425704493835);
+    points += QPointF(268.2336759982877, 345.56366422433183);
+    points += QPointF(254.38869069377708, 348.78886336684104);
+    points += QPointF(240.8928242225697, 350.0214774527481);
+    points += QPointF(224.29748398011193, 349.2949970081793);
+    points += QPointF(205.50330859478322, 345.31468660256957);
+    points += QPointF(188.72568121178054, 339.38217984347546);
+    points += QPointF(173.487571907339, 332.2573164509149);
+    points += QPointF(159.09346043909582, 324.15190856941325);
+    points += QPointF(145.1562378134811, 315.1465661857729);
+    points += QPointF(131.46917217609203, 305.28136213922494);
+    points += QPointF(117.9345600633141, 294.589765121662);
+    points += QPointF(104.5254725457231, 283.11108988305153);
+    points += QPointF(91.25156649455745, 270.88938370179534);
+    points += QPointF(78.14294517511125, 257.9630200468154);
+    points += QPointF(65.25722328495372, 244.3823949426573);
+    points += QPointF(52.65759889494496, 230.19470850111355);
+    points += QPointF(40.412239584772514, 215.4406233233806);
+    points += QPointF(28.600027181043494, 200.15894757848054);
+    points += QPointF(17.304913602921047, 184.38648111018338);
+    points += QPointF(6.6105681133211736, 168.14173996194046);
+    points += QPointF(-3.3897319816688407, 151.43048866270516);
+    points += QPointF(-12.592267484961765, 134.24479093805914);
+    points += QPointF(-20.880547263016442, 116.54866956498358);
+    points += QPointF(-28.111192294561146, 98.27715746242171);
+    points += QPointF(-34.098213657706594, 79.33681465062016);
+    points += QPointF(-38.441724866417594, 60.24852451858777);
+    points += QPointF(-52.3724798442221, -35.5907);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VSAPoint> TST_VAbstractPiece::InputPointsIssue298Case2() const
+{
+    QVector<VSAPoint> points;
+
+    points += VSAPoint(35, 39.9999);
+    points += VSAPoint(35, 39.9999);
+    points += VSAPoint(35.9309, 46.4042);
+    points += VSAPoint(38.9167, 59.5258);
+    points += VSAPoint(43.159, 72.9466);
+    points += VSAPoint(48.5551, 86.5823);
+    points += VSAPoint(55.0025, 100.348);
+    points += VSAPoint(62.3985, 114.16);
+    points += VSAPoint(70.6405, 127.933);
+    points += VSAPoint(79.626, 141.582);
+    points += VSAPoint(89.2522, 155.024);
+    points += VSAPoint(99.4167, 168.174);
+    points += VSAPoint(110.017, 180.946);
+    points += VSAPoint(120.95, 193.257);
+    points += VSAPoint(132.113, 205.022);
+    points += VSAPoint(143.405, 216.157);
+    points += VSAPoint(154.721, 226.576);
+    points += VSAPoint(165.96, 236.197);
+    points += VSAPoint(177.019, 244.933);
+    points += VSAPoint(187.795, 252.7);
+    points += VSAPoint(198.186, 259.414);
+    points += VSAPoint(208.09, 264.991);
+    points += VSAPoint(217.402, 269.345);
+    points += VSAPoint(226.022, 272.393);
+    points += VSAPoint(233.846, 274.05);
+    points += VSAPoint(239.1, 274.28);
+    points += VSAPoint(242.319, 273.986);
+    points += VSAPoint(245.281, 273.296);
+    points += VSAPoint(247.974, 272.201);
+    points += VSAPoint(250.385, 270.688);
+    points += VSAPoint(252.501, 268.749);
+    points += VSAPoint(254.308, 266.372);
+    points += VSAPoint(255.795, 263.547);
+    points += VSAPoint(256.949, 260.264);
+    points += VSAPoint(257.756, 256.51);
+    points += VSAPoint(258.203, 252.278);
+    points += VSAPoint(258.279, 247.554);
+    points += VSAPoint(257.717, 239.591);
+    points += VSAPoint(255.482, 227.075);
+    points += VSAPoint(251.528, 212.406);
+    points += VSAPoint(248.796, 204.144);
+    points += VSAPoint(248.796, 204.144);
+    points += VSAPoint(241.73, 183.168);
+    points += VSAPoint(234.173, 158.703);
+    points += VSAPoint(230.625, 145.81);
+    points += VSAPoint(228.29, 135.699);
+    points += VSAPoint(227.112, 128.232);
+    points += VSAPoint(227.033, 123.272);
+    points += VSAPoint(227.69, 121.185);
+    points += VSAPoint(228.421, 120.456);
+    points += VSAPoint(229.393, 120.277);
+    points += VSAPoint(230.6, 120.629);
+    points += VSAPoint(232.808, 122.058);
+    points += VSAPoint(236.545, 125.75);
+    points += VSAPoint(241.092, 131.261);
+    points += VSAPoint(249.22, 142.455);
+    points += VSAPoint(262.477, 162.745);
+    points += VSAPoint(286.15, 201.448);
+    points += VSAPoint(323.075, 264.247);
+    points += VSAPoint(362.315, 330.86);
+    points += VSAPoint(390.909, 377.669);
+    points += VSAPoint(408.797, 405.589);
+    points += VSAPoint(417.135, 417.929);
+    points += VSAPoint(417.135, 417.929);
+    points += VSAPoint(35, 417.953);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> TST_VAbstractPiece::OutputPointsIssue298Case2() const
+{
+    QVector<QPointF> points;
+
+    points += QPointF(-2.7952999999999975, 4.8384699505981095);
+    points += QPointF(67.34448942068963, -0.23248582689164274);
+    points += QPointF(73.11721243320879, 39.48203774070609);
+    points += QPointF(75.42415682885321, 49.62029267468959);
+    points += QPointF(78.79409614728041, 60.281321268788744);
+    points += QPointF(83.27292363150828, 71.59911521750833);
+    points += QPointF(88.79988374248082, 83.39960453097031);
+    points += QPointF(95.2926159908344, 95.5247556686474);
+    points += QPointF(102.65546594334339, 107.82863001903641);
+    points += QPointF(110.78654319853989, 120.17975944490887);
+    points += QPointF(119.5782864094781, 132.4565262107595);
+    points += QPointF(128.91893020761376, 144.54068833830968);
+    points += QPointF(138.69670055252752, 156.3216457494432);
+    points += QPointF(148.79638835752286, 167.69430252867102);
+    points += QPointF(159.09802741244354, 178.55148997659143);
+    points += QPointF(169.48171675272164, 188.79080814910267);
+    points += QPointF(179.81876372713828, 198.30845505847407);
+    points += QPointF(189.9727199683426, 207.00061743916868);
+    points += QPointF(199.7939139119543, 214.75881893038778);
+    points += QPointF(209.1143810932559, 221.476716907111);
+    points += QPointF(216.03386663545683, 225.9476461661168);
+    points += QPointF(215.3306509043856, 223.3387762725701);
+    points += QPointF(205.75073516810195, 194.75155680967347);
+    points += QPointF(197.88802785264718, 169.29686123304236);
+    points += QPointF(193.97579117825833, 155.08026950731082);
+    points += QPointF(191.1640933645057, 142.90507610480435);
+    points += QPointF(189.3638602852325, 131.49392126360493);
+    points += QPointF(189.14507682295456, 117.75764312564759);
+    points += QPointF(194.42693552963567, 100.97950138920423);
+    points += QPointF(210.03879336533757, 85.41035725481989);
+    points += QPointF(231.36634627769158, 81.48275234606332);
+    points += QPointF(246.4916615881645, 85.89378050620131);
+    points += QPointF(256.60614755001956, 92.43979519799973);
+    points += QPointF(264.4750900046005, 100.21398185636762);
+    points += QPointF(270.9888544453203, 108.1087159300009);
+    points += QPointF(280.35077918473866, 121.00209505562212);
+    points += QPointF(294.42535276480356, 142.5434013797918);
+    points += QPointF(318.5597512322288, 182.00074197391842);
+    points += QPointF(394.73028222951507, 311.42213969492946);
+    points += QPointF(422.9514429826756, 357.62079373755);
+    points += QPointF(440.37197676737753, 384.8111617646563);
+    points += QPointF(488.2841719585649, 455.71983154868764);
+    points += QPointF(-2.795300000000013, 455.7506738094777);
+    points += QPointF(-2.7952999999999975, 4.8384699505981095);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VSAPoint> TST_VAbstractPiece::InputPointsIssue548Case1() const
+{
+    QVector<VSAPoint> points;
+
+    points += VSAPoint(236.97989607468364, 65.89325192030674);
+    points += VSAPoint(198.93409106041895, 172.04876297154925);
+    points += VSAPoint(260.32251114299453, 75.38027418944861);
+    points += VSAPoint(324.54110236213444, 101.48031496062993);
+    points += VSAPoint(29.858267716535437, 300.85039370078744);
+    points += VSAPoint(99.86433649395013, 10.166060970128015);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> TST_VAbstractPiece::OutputPointsIssue548Case1() const
+{
+    QVector<QPointF> points;
+
+    points += QPointF(251.32210577118798, 59.48301432799721);
+    points += QPointF(243.9841262159756, 79.95746530820585);
+    points += QPointF(255.82424817748586, 61.31279754390509);
+    points += QPointF(348.48337789725855, 98.9717841021069);
+    points += QPointF(29.780382054543473, 314.59289909613994);
+    points += QPointF(17.01672179602679, 305.7450049304056);
+    points += QPointF(91.92616539550944, -5.299480329501037);
+    points += QPointF(251.32210577118798, 59.48301432799721);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VSAPoint> TST_VAbstractPiece::InputPointsIssue548Case2() const
+{
+    QVector<VSAPoint> points;
+    points << VSAPoint(99.86433649395013, 10.166060970128015);
+    points << VSAPoint(236.97989607468364, 65.89325192030674);
+    points << VSAPoint(198.93409106041895, 172.04876297154925);
+    points << VSAPoint(260.32251114299453, 75.38027418944861);
+    points << VSAPoint(324.54110236213444, 101.48031496062993);
+    points << VSAPoint(29.858267716535437, 300.85039370078744);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> TST_VAbstractPiece::OutputPointsIssue548Case2() const
+{
+    QVector<QPointF> points;
+    points << QPointF(73.40376616581447, -41.38574336196901);
+    points << QPointF(404.3486874792147, 93.11854543221973);
+    points << QPointF(29.59864884322894, 346.6587450186291);
+    points << QPointF(-12.946885351826726, 317.1657644661815);
+    points << QPointF(73.40376616581447, -41.38574336196901);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<VSAPoint> TST_VAbstractPiece::InputPointsIssue548Case3() const
+{
+    QVector<VSAPoint> points;
+
+    points += VSAPoint(99.86433649395013, 10.166060970128015);
+    points += VSAPoint(236.97989607468364, 65.89325192030674);
+    points += VSAPoint(198.93409106041895, 172.04876297154925);
+    points += VSAPoint(260.32251114299453, 75.38027418944861);
+    points += VSAPoint(324.54110236213444, 101.48031496062993);
+    points += VSAPoint(29.858267716535437, 300.85039370078744);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> TST_VAbstractPiece::OutputPointsIssue548Case3() const
+{
+    QVector<QPointF> points;
+
+    points += QPointF(46.94319583767885, -92.9375476940661);
+    points += QPointF(484.15627259629446, 84.75677590380938);
+    points += QPointF(29.339029969922702, 392.46709633647066);
+    points += QPointF(-55.75203842018885, 333.48113523157537);
+    points += QPointF(46.94319583767885, -92.9375476940661);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> TST_VAbstractPiece::InputPointsCase3a() const
+{
+    QVector<QPointF> points;
+
+    points += QPointF(35, 35);
+    points += QPointF(50, 50);
+    points += QPointF(15, 50);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> TST_VAbstractPiece::InputPointsCase4a() const
+{
+    QVector<QPointF> points;
+
+    points += QPointF(15, 15);
+    points += QPointF(15, 50);
+    points += QPointF(50, 50);
+
+    return points;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector<QPointF> TST_VAbstractPiece::InputPointsCase5a() const
+{
+    QVector<QPointF> points;
+
+    points += QPointF(35, 35);
+
+    return points;
+}
diff --git a/src/test/ValentinaTest/tst_vabstractdetail.h b/src/test/ValentinaTest/tst_vabstractpiece.h
similarity index 68%
rename from src/test/ValentinaTest/tst_vabstractdetail.h
rename to src/test/ValentinaTest/tst_vabstractpiece.h
index 3ae4094dd..d46f53f6b 100644
--- a/src/test/ValentinaTest/tst_vabstractdetail.h
+++ b/src/test/ValentinaTest/tst_vabstractpiece.h
@@ -1,14 +1,14 @@
 /************************************************************************
  **
- **  @file   tst_vabstractdetail.h
+ **  @file
  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
- **  @date   16 4, 2015
+ **  @date   17 11, 2016
  **
  **  @brief
  **  @copyright
  **  This source code is part of the Valentine project, a pattern making
  **  program, whose allow create and modeling patterns of clothing.
- **  Copyright (C) 2015 Valentina project
+ **  Copyright (C) 2016 Valentina project
  **  <https://bitbucket.org/dismine/valentina> All Rights Reserved.
  **
  **  Valentina is free software: you can redistribute it and/or modify
@@ -26,18 +26,18 @@
  **
  *************************************************************************/
 
-#ifndef TST_VABSTRACTDETAIL_H
-#define TST_VABSTRACTDETAIL_H
+#ifndef TST_VABSTRACTPIECE_H
+#define TST_VABSTRACTPIECE_H
 
 #include "../vmisc/abstracttest.h"
 
-class TST_VAbstractDetail : public AbstractTest
+class VSAPoint;
+
+class TST_VAbstractPiece : public AbstractTest
 {
     Q_OBJECT
 public:
-    explicit TST_VAbstractDetail(QObject *parent = nullptr);
-
-signals:
+    explicit TST_VAbstractPiece(QObject *parent = nullptr);
 
 private slots:
     void EquidistantRemoveLoop_data();
@@ -59,29 +59,37 @@ private slots:
 #endif
 
 private:
+    QVector<VSAPoint> InputPointsCase1() const;
+    QVector<QPointF>  OutputPointsCase1() const;
+
+    QVector<VSAPoint> InputPointsCase2() const;
+    QVector<QPointF>  OutputPointsCase2() const;
+
+    QVector<VSAPoint> InputPointsCase3() const;
+    QVector<QPointF>  OutputPointsCase3() const;
+
     void Case3() const;
     void Case4() const;
     void Case5() const;
 
-    QVector<QPointF> InputPointsIssue298Case1() const;
+    QVector<VSAPoint> InputPointsIssue298Case1() const;
     QVector<QPointF> OutputPointsIssue298Case1() const;
 
-    QVector<QPointF> InputPointsIssue298Case2() const;
+    QVector<VSAPoint> InputPointsIssue298Case2() const;
     QVector<QPointF> OutputPointsIssue298Case2() const;
 
-    QVector<QPointF> InputPointsIssue548Case1() const;
+    QVector<VSAPoint> InputPointsIssue548Case1() const;
     QVector<QPointF> OutputPointsIssue548Case1() const;
 
-    QVector<QPointF> InputPointsIssue548Case2() const;
+    QVector<VSAPoint> InputPointsIssue548Case2() const;
     QVector<QPointF> OutputPointsIssue548Case2() const;
 
-    QVector<QPointF> InputPointsIssue548Case3() const;
+    QVector<VSAPoint> InputPointsIssue548Case3() const;
     QVector<QPointF> OutputPointsIssue548Case3() const;
 
-    QVector<QPointF> InputPointsCase3() const;
-    QVector<QPointF> InputPointsCase4() const;
-    QVector<QPointF> InputPointsCase5() const;
-
+    QVector<QPointF> InputPointsCase3a() const;
+    QVector<QPointF> InputPointsCase4a() const;
+    QVector<QPointF> InputPointsCase5a() const;
 };
 
-#endif // TST_VABSTRACTDETAIL_H
+#endif // TST_VABSTRACTPIECE_H
diff --git a/src/test/ValentinaTest/tst_varc.cpp b/src/test/ValentinaTest/tst_varc.cpp
index 207050c34..20d35574b 100644
--- a/src/test/ValentinaTest/tst_varc.cpp
+++ b/src/test/ValentinaTest/tst_varc.cpp
@@ -28,7 +28,7 @@
 
 #include "tst_varc.h"
 #include "../vgeometry/varc.h"
-#include "../vlayout/vabstractdetail.h"
+#include "../vlayout/vabstractpiece.h"
 #include "../vmisc/logging.h"
 
 #include <QtTest>
@@ -203,7 +203,7 @@ void TST_VArc::TestGetPoints()
         }
 
         // calculated square
-        const qreal cSquare = qAbs(VAbstractDetail::SumTrapezoids(points)/2.0);
+        const qreal cSquare = qAbs(VAbstractPiece::SumTrapezoids(points)/2.0);
         const qreal value = qAbs(gSquere - cSquare);
         const QString errorMsg =
                 QString("Broken the second rule. Interpolation has too big computing error. Error ='%1'.").arg(value);
diff --git a/src/test/ValentinaTest/tst_vellipticalarc.cpp b/src/test/ValentinaTest/tst_vellipticalarc.cpp
index 5abd8b583..794af45ef 100644
--- a/src/test/ValentinaTest/tst_vellipticalarc.cpp
+++ b/src/test/ValentinaTest/tst_vellipticalarc.cpp
@@ -28,7 +28,7 @@
 
 #include "tst_vellipticalarc.h"
 #include "../vgeometry/vellipticalarc.h"
-#include "../vlayout/vabstractdetail.h"
+#include "../vlayout/vabstractpiece.h"
 #include "../vmisc/logging.h"
 
 #include <QtGlobal>
@@ -372,7 +372,7 @@ void TST_VEllipticalArc::TestGetPoints3()
     {// calculated full ellipse square
         const qreal ellipseSquare = M_PI * radius1 * radius2;
         const qreal epsSquare = ellipseSquare * 0.5 / 100; // computing error 0.5 % from origin squere
-        const qreal arcSquare = qAbs(VAbstractDetail::SumTrapezoids(points)/2.0);
+        const qreal arcSquare = qAbs(VAbstractPiece::SumTrapezoids(points)/2.0);
         const qreal diffSquare = qAbs(ellipseSquare - arcSquare);
         const QString errorMsg1 = QString("Broken the second rule. Interpolation has too big computing error. "
                                           "Difference ='%1' bigger than eps = '%2'.").arg(diffSquare).arg(epsSquare);
diff --git a/src/test/ValentinaTest/tst_vlayoutdetail.cpp b/src/test/ValentinaTest/tst_vlayoutdetail.cpp
index cf29172ef..f440e813a 100644
--- a/src/test/ValentinaTest/tst_vlayoutdetail.cpp
+++ b/src/test/ValentinaTest/tst_vlayoutdetail.cpp
@@ -27,7 +27,7 @@
  *************************************************************************/
 
 #include "tst_vlayoutdetail.h"
-#include "../vlayout/vlayoutdetail.h"
+#include "../vlayout/vlayoutpiece.h"
 
 #include <QtDebug>
 
@@ -56,7 +56,7 @@ void TST_VLayoutDetail::Case1() const
     // See issue #304. Layout appears different than my pattern.
     // https://bitbucket.org/dismine/valentina/issue/304/layout-appears-different-than-my-pattern
 
-    VLayoutDetail det = VLayoutDetail();
+    VLayoutPiece det = VLayoutPiece();
     det.SetCountourPoints(InputPointsCase1());
 
     // Begin comparison
@@ -118,7 +118,7 @@ QVector<QPointF> TST_VLayoutDetail::OutputPointsCase1() const //-V524
 //---------------------------------------------------------------------------------------------------------------------
 void TST_VLayoutDetail::Case2() const
 {
-    VLayoutDetail det = VLayoutDetail();
+    VLayoutPiece det = VLayoutPiece();
     det.SetCountourPoints(InputPointsCase2());
 
     // Begin comparison
@@ -159,7 +159,7 @@ QVector<QPointF> TST_VLayoutDetail::OutputPointsCase2() const
 //---------------------------------------------------------------------------------------------------------------------
 void TST_VLayoutDetail::Case3() const
 {
-    VLayoutDetail det = VLayoutDetail();
+    VLayoutPiece det = VLayoutPiece();
     det.SetCountourPoints(InputPointsCase3());
 
     // Begin comparison
diff --git a/src/test/ValentinaTest/tst_vdetail.cpp b/src/test/ValentinaTest/tst_vpiece.cpp
similarity index 87%
rename from src/test/ValentinaTest/tst_vdetail.cpp
rename to src/test/ValentinaTest/tst_vpiece.cpp
index 486ec5ea5..3e0927e40 100644
--- a/src/test/ValentinaTest/tst_vdetail.cpp
+++ b/src/test/ValentinaTest/tst_vpiece.cpp
@@ -26,20 +26,23 @@
  **
  *************************************************************************/
 
-#include "tst_vdetail.h"
+#include "tst_vpiece.h"
 #include "../vpatterndb/vcontainer.h"
+#include "../vpatterndb/vpiece.h"
+#include "../vpatterndb/vpiecenode.h"
+#include "../vpatterndb/vpiecepath.h"
 #include "../vgeometry/vsplinepath.h"
 
 #include <QtTest>
 
 //---------------------------------------------------------------------------------------------------------------------
-TST_VDetail::TST_VDetail(QObject *parent)
+TST_VPiece::TST_VPiece(QObject *parent)
     :AbstractTest(parent)
 {
 }
 
 //---------------------------------------------------------------------------------------------------------------------
-void TST_VDetail::ClearLoop()
+void TST_VPiece::ClearLoop()
 {
     // Input data taken from real case
     // See file <root>/src/app/share/collection/jacketМ6_30-110.val
@@ -86,15 +89,17 @@ void TST_VDetail::ClearLoop()
     data->UpdateGObject(310, new VPointF(802.08718110236236, 1653.9337322834645, "Н5", 5.0000125984251973,
                                          9.9999874015748045));
 
-    VDetail detail;
-    detail.setSeamAllowance(true);
-    detail.setWidth(7);
-    detail.setClosed(false);
-    detail.append(VNodeDetail(304, Tool::NodePoint, NodeDetail::Contour));
-    detail.append(VNodeDetail(307, Tool::NodePoint, NodeDetail::Contour));
-    detail.append(VNodeDetail(308, Tool::NodeSplinePath, NodeDetail::Contour));
-    detail.append(VNodeDetail(309, Tool::NodePoint, NodeDetail::Contour));
-    detail.append(VNodeDetail(310, Tool::NodePoint, NodeDetail::Contour));
+    VPiece detail;
+    detail.SetSeamAllowance(true);
+    detail.SetSAWidth(7);
+    detail.GetPath().Append(VPieceNode(304, Tool::NodePoint));
+    detail.GetPath().Append(VPieceNode(307, Tool::NodePoint));
+    detail.GetPath().Append(VPieceNode(308, Tool::NodeSplinePath));
+    detail.GetPath().Append(VPieceNode(309, Tool::NodePoint));
+    detail.GetPath().Append(VPieceNode(310, Tool::NodePoint));
+    // Closed
+    detail.GetPath()[0].SetFormulaSABefore("0");
+    detail.GetPath()[detail.GetPath().CountNodes()-1].SetFormulaSAAfter("0");
 
     const QVector<QPointF> pointsEkv = detail.SeamAllowancePoints(data);
 
@@ -129,8 +134,9 @@ void TST_VDetail::ClearLoop()
     origPoints.append(QPointF(773.6735265709667, 824.7970381873482));
     origPoints.append(QPointF(780.6615727577812, 825.0343457026618));
     origPoints.append(QPointF(792.1099959092389, 824.8480813766124));
-    origPoints.append(QPointF(825.8245486890017, 822.4865245986581));
+    origPoints.append(QPointF(826.0032661558732, 877.1274330708662));
     origPoints.append(QPointF(828.6858753986579, 1697.305833468011));
+    origPoints.append(QPointF(42.46405659601934, 415.2845470563871));
 
     // Begin comparison
     Comparison(pointsEkv, origPoints);
diff --git a/src/test/ValentinaTest/tst_vdetail.h b/src/test/ValentinaTest/tst_vpiece.h
similarity index 91%
rename from src/test/ValentinaTest/tst_vdetail.h
rename to src/test/ValentinaTest/tst_vpiece.h
index ef7034caa..d2b8898b0 100644
--- a/src/test/ValentinaTest/tst_vdetail.h
+++ b/src/test/ValentinaTest/tst_vpiece.h
@@ -31,17 +31,17 @@
 
 #include "../vmisc/abstracttest.h"
 
-class TST_VDetail : public AbstractTest
+class TST_VPiece : public AbstractTest
 {
     Q_OBJECT
 public:
-    explicit TST_VDetail(QObject *parent = nullptr);
+    explicit TST_VPiece(QObject *parent = nullptr);
 
 private slots:
     void ClearLoop();
 
 private:
-    Q_DISABLE_COPY(TST_VDetail)
+    Q_DISABLE_COPY(TST_VPiece)
 };
 
 #endif // TST_VDETAIL_H