diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt index 00db25d4cd..91331038e8 100644 --- a/src/Mod/Path/CMakeLists.txt +++ b/src/Mod/Path/CMakeLists.txt @@ -146,8 +146,9 @@ SET(PathScripts_SRCS SET(Generator_SRCS Generators/drill_generator.py - Generators/rotation_generator.py Generators/helix_generator.py + Generators/rotation_generator.py + Generators/threadmilling_generator.py Generators/toolchange_generator.py ) @@ -242,6 +243,7 @@ SET(PathTests_SRCS PathTests/TestPathStock.py PathTests/TestPathToolChangeGenerator.py PathTests/TestPathThreadMilling.py + PathTests/TestPathThreadMillingGenerator.py PathTests/TestPathTool.py PathTests/TestPathToolBit.py PathTests/TestPathToolController.py @@ -270,8 +272,13 @@ SET(Path_Images ) SET(PathData_Threads - Data/Threads/metric-internal.csv - Data/Threads/imperial-internal.csv + Data/Threads/imperial-external-2A.csv + Data/Threads/imperial-external-3A.csv + Data/Threads/imperial-internal-2B.csv + Data/Threads/imperial-internal-3B.csv + Data/Threads/metric-external-4G6G.csv + Data/Threads/metric-external-6G.csv + Data/Threads/metric-internal-6H.csv ) SET(Path_Data diff --git a/src/Mod/Path/Data/Threads/imperial-external-2A.csv b/src/Mod/Path/Data/Threads/imperial-external-2A.csv new file mode 100644 index 0000000000..c93db9c34e --- /dev/null +++ b/src/Mod/Path/Data/Threads/imperial-external-2A.csv @@ -0,0 +1,53 @@ +name,tpi,class,dNominal,dMajorMax,dMajorMin,dPitchMax,dPitchMin,dMinorMax,dMinorMin +0-80,80,2A,0.0600,0.0595,0.0563,0.0514,0.0496,0.0442,0.0419 +1-64,64,2A,0.0730,0.0724,0.0686,0.0623,0.0603,0.0532,0.0507 +1-72,72,2A,0.0730,0.0724,0.0689,0.0634,0.0615,0.0554,0.0530 +2-56,56,2A,0.0860,0.0854,0.0813,0.0738,0.0717,0.0635,0.0607 +2-64,64,2A,0.0860,0.0854,0.0816,0.0753,0.0733,0.0662,0.0637 +3-48,48,2A,0.0990,0.0983,0.0938,0.0848,0.0825,0.0727,0.0697 +3-56,56,2A,0.0990,0.0983,0.0942,0.0867,0.0845,0.0764,0.0735 +4-40,40,2A,0.1120,0.1112,0.1061,0.0950,0.0925,0.0805,0.0771 +4-48,48,2A,0.1120,0.1113,0.1068,0.0978,0.0954,0.0857,0.0826 +5-40,40,2A,0.1250,0.1242,0.1191,0.1080,0.1054,0.0935,0.0900 +5-44,44,2A,0.1250,0.1243,0.1195,0.1095,0.1070,0.0964,0.0930 +6-32,32,2A,0.1380,0.1372,0.1312,0.1169,0.1141,0.0989,0.0949 +6-40,40,2A,0.1380,0.1372,0.1321,0.1210,0.1184,0.1065,0.1030 +8-32,32,2A,0.1640,0.1631,0.1571,0.1428,0.1399,0.1248,0.1207 +8-36,36,2A,0.1640,0.1632,0.1577,0.1452,0.1424,0.1291,0.1253 +10-24,24,2A,0.1900,0.1890,0.1818,0.1619,0.1586,0.1379,0.1329 +10-32,32,2A,0.1900,0.1891,0.1831,0.1688,0.1658,0.1508,0.1466 +1/4-20,20,2A,0.2500,0.2489,0.2408,0.2164,0.2127,0.1876,0.1819 +1/4-28,28,2A,0.2500,0.2490,0.2425,0.2258,0.2225,0.2052,0.2005 +5/16-18,18,2A,0.3125,0.3113,0.3026,0.2752,0.2712,0.2431,0.2370 +5/16-24,24,2A,0.3125,0.3114,0.3042,0.2843,0.2806,0.2603,0.2549 +3/8-16,16,2A,0.3750,0.3737,0.3643,0.3331,0.3287,0.2970,0.2902 +3/8-24,24,2A,0.3750,0.3739,0.3667,0.3468,0.3430,0.3228,0.3173 +7/16-14,14,2A,0.4375,0.4361,0.4258,0.3897,0.3850,0.3485,0.3410 +7/16-20,20,2A,0.4375,0.4362,0.4281,0.4037,0.3995,0.3749,0.3687 +1/2-13,13,2A,0.5000,0.4985,0.4876,0.4485,0.4435,0.4041,0.3961 +1/2-20,20,2A,0.5000,0.4987,0.4906,0.4662,0.4619,0.4374,0.4311 +9/16-12,12,2A,0.5625,0.5609,0.5495,0.5068,0.5016,0.4617,0.4503 +9/16-14,14,2A,0.5625,0.5510,0.5507,0.5146,0.5096,0.4760,0.4751 +9/16-16,16,2A,0.5625,0.5611,0.5517,0.5205,0.5158,0.4866,0.4773 +9/16-18,18,2A,0.5625,0.5611,0.5524,0.5250,0.5205,0.4950,0.4863 +9/16-20,20,2A,0.5625,0.5612,0.5531,0.5287,0.5245,0.5017,0.4937 +9/16-24,24,2A,0.5625,0.5613,0.5541,0.5342,0.5303,0.5117,0.5046 +9/16-32,32,2A,0.5625,0.5615,0.5555,0.5412,0.5377,0.5243,0.5185 +5/8-11,11,2A,0.6250,0.6234,0.6113,0.5644,0.5589,0.5119,0.5030 +5/8-18,18,2A,0.6250,0.6236,0.6149,0.5875,0.5828,0.5554,0.5486 +3/4-10,10,2A,0.7500,0.7482,0.7353,0.6832,0.6773,0.6255,0.6157 +3/4-16,16,2A,0.7500,0.7485,0.7391,0.7079,0.7029,0.6718,0.6644 +7/8-9,9,2A,0.8750,0.8731,0.8592,0.8009,0.7946,0.7368,0.7262 +7/8-14,14,2A,0.8750,0.8734,0.8631,0.8270,0.8216,0.7858,0.7776 +1-8,8,2A,1.0000,0.9980,0.9830,0.9168,0.9100,0.8446,0.8330 +1-12,12,2A,1.0000,0.9982,0.9868,0.9441,0.9382,0.8960,0.8869 +1-1/8-7,7,2A,1.1250,1.1228,1.1064,1.0300,1.0228,0.9475,0.9348 +1-1/8-12,12,2A,1.1250,1.1232,1.1118,1.0691,1.0631,1.0210,1.0118 +1-1/4-7,7,2A,1.2500,1.2478,1.2314,1.1550,1.1476,1.0725,1.0596 +1-1/4-12,12,2A,1.2500,1.2482,1.2368,1.1941,1.1879,1.1460,1.1366 +1-3/8-6,6,2A,1.3750,1.3726,1.3544,1.2643,1.2563,1.1681,1.1536 +1-3/8-12,12,2A,1.3750,1.3731,1.3617,1.3190,1.3127,1.2709,1.2614 +1-1/2-6,6,2A,1.5000,1.4976,1.4794,1.3893,1.3812,1.2931,1.2785 +1-1/2-12,12,2A,1.5000,1.4981,1.4867,1.4440,1.4376,1.3959,1.3863 +1-3/4-5,5,2A,1.7500,1.7473,1.7268,1.6174,1.6085,1.5019,1.4854 +2-6,6,2A,2.0000,1.9971,1.9751,1.8528,1.8433,1.7245,1.7065 diff --git a/src/Mod/Path/Data/Threads/imperial-external-3A.csv b/src/Mod/Path/Data/Threads/imperial-external-3A.csv new file mode 100644 index 0000000000..7771286826 --- /dev/null +++ b/src/Mod/Path/Data/Threads/imperial-external-3A.csv @@ -0,0 +1,42 @@ +name,tpi,class,dNominal,dMajorMax,dMajorMin,dPitchMax,dPitchMin,dMinorMax,dMinorMin +0-80,80,3A,0.0600,0.0600,0.0568,0.0519,0.0506,0.0447,0.0429 +1-64,64,3A,0.0730,0.0730,0.0692,0.0629,0.0614,0.0538,0.0518 +1-72,72,3A,0.0730,0.0730,0.0695,0.0640,0.0626,0.0560,0.0541 +2-56,56,3A,0.0860,0.0860,0.0819,0.0744,0.0728,0.0641,0.0618 +2-64,64,3A,0.0860,0.0860,0.0822,0.0759,0.0744,0.0668,0.0648 +3-48,48,3A,0.0990,0.0990,0.0945,0.0855,0.0838,0.0734,0.0710 +3-56,56,3A,0.0990,0.0990,0.0949,0.0874,0.0858,0.0771,0.0748 +4-40,40,3A,0.1120,0.1120,0.1069,0.0958,0.0939,0.0813,0.0785 +4-48,48,3A,0.1120,0.1120,0.1075,0.0985,0.0967,0.0864,0.0839 +5-40,40,3A,0.1250,0.1250,0.1199,0.1088,0.1069,0.0943,0.0915 +5-44,44,3A,0.1250,0.1250,0.1202,0.1102,0.1083,0.0971,0.0943 +6-32,32,3A,0.1380,0.1380,0.1320,0.1177,0.1156,0.0997,0.0964 +6-40,40,3A,0.1380,0.1380,0.1329,0.1218,0.1198,0.1073,0.1044 +8-32,32,3A,0.1640,0.1640,0.1580,0.1437,0.1415,0.1257,0.1223 +8-36,36,3A,0.1640,0.1640,0.1585,0.1460,0.1439,0.1299,0.1268 +10-24,24,3A,0.1900,0.1900,0.1828,0.1629,0.1604,0.1389,0.1347 +10-32,32,3A,0.1900,0.1900,0.1840,0.1697,0.1674,0.1517,0.1482 +1/4-20,20,3A,0.2500,0.2500,0.2419,0.2175,0.2147,0.1887,0.1839 +1/4-28,28,3A,0.2500,0.2500,0.2435,0.2268,0.2243,0.2062,0.2023 +5/16-18,18,3A,0.3125,0.3125,0.3038,0.2764,0.2734,0.2443,0.2392 +5/16-24,24,3A,0.3125,0.3125,0.3053,0.2854,0.2827,0.2614,0.2570 +3/8-16,16,3A,0.3750,0.3750,0.3656,0.3344,0.3311,0.2983,0.2926 +3/8-24,24,3A,0.3750,0.3750,0.3678,0.3479,0.3450,0.3239,0.3193 +7/16-14,14,3A,0.4375,0.4375,0.4272,0.3911,0.3876,0.3499,0.3436 +7/16-20,20,3A,0.4375,0.4375,0.4294,0.4050,0.4019,0.3762,0.3711 +1/2-13,13,3A,0.5000,0.5000,0.4891,0.4500,0.4463,0.4056,0.3989 +1/2-20,20,3A,0.5000,0.5000,0.4919,0.4675,0.4643,0.4387,0.4335 +9/16-12,12,3A,0.5625,0.5609,0.5495,0.5068,0.5016,0.4617,0.4503 +9/16-16,16,3A,0.5625,0.5625,0.5531,0.5219,0.5184,0.4880,0.4799 +9/16-18,18,3A,0.5625,0.5625,0.5538,0.5264,0.5230,0.4964,0.4888 +9/16-20,20,3A,0.5625,0.5625,0.5544,0.5300,0.5268,0.5030,0.4960 +9/16-24,24,3A,0.5625,0.5625,0.5553,0.5354,0.5325,0.5129,0.5068 +9/16-32,32,3A,0.5625,0.5625,0.5565,0.5422,0.5396,0.5253,0.5204 +5/8-11,11,3A,0.6250,0.6250,0.6129,0.5660,0.5619,0.5135,0.5060 +5/8-18,18,3A,0.6250,0.6250,0.6163,0.5889,0.5854,0.5568,0.5512 +3/4-10,10,3A,0.7500,0.7500,0.7371,0.6850,0.6806,0.6273,0.6190 +3/4-16,16,3A,0.7500,0.7500,0.7406,0.7094,0.7056,0.6733,0.6671 +7/8-9,9,3A,0.8750,0.8750,0.8611,0.8028,0.7981,0.7387,0.7297 +7/8-14,14,3A,0.8750,0.8750,0.8647,0.8286,0.8245,0.7874,0.7805 +1-8,8,3A,1.0000,1.0000,0.9850,0.9188,0.9137,0.8466,0.8367 +1-12,12,3A,1.0000,1.0000,0.9886,0.9459,0.9415,0.8978,0.8902 diff --git a/src/Mod/Path/Data/Threads/imperial-internal.csv b/src/Mod/Path/Data/Threads/imperial-internal-2B.csv similarity index 56% rename from src/Mod/Path/Data/Threads/imperial-internal.csv rename to src/Mod/Path/Data/Threads/imperial-internal-2B.csv index 9a171490d9..458731c950 100644 --- a/src/Mod/Path/Data/Threads/imperial-internal.csv +++ b/src/Mod/Path/Data/Threads/imperial-internal-2B.csv @@ -1,74 +1,39 @@ name,tpi,class,dMinorMin,dMinorMax,dPitchMin,dPitchMax,dMajorMin,dMajorMax 0-80,80,2B,0.0465,0.0514,0.0519,0.0542,0.06,0.0633 -0-80,80,3B,0.0465,0.0514,0.0519,0.0536,0.06,0.0626 1-64,64,2B,0.0561,0.0623,0.0629,0.0655,0.073,0.0768 -1-64,64,3B,0.0561,0.0623,0.0629,0.0648,0.073,0.076 1-72,72,2B,0.058,0.0635,0.064,0.0665,0.073,0.0766 -1-72,72,3B,0.058,0.0635,0.064,0.0659,0.073,0.0759 2-56,56,2B,0.0667,0.0737,0.0744,0.0772,0.086,0.0901 -2-56,56,3B,0.0667,0.0737,0.0744,0.0765,0.086,0.0893 2-64,64,2B,0.0691,0.0753,0.0759,0.0786,0.086,0.0899 -2-64,64,3B,0.0691,0.0753,0.0759,0.0779,0.086,0.0891 3-48,48,2B,0.0764,0.0845,0.0855,0.0885,0.099,0.1035 -3-48,48,3B,0.0764,0.0845,0.0855,0.0877,0.099,0.1026 3-56,56,2B,0.0797,0.0865,0.0874,0.0902,0.099,0.1032 -3-56,56,3B,0.0797,0.0865,0.0874,0.0895,0.099,0.1024 4-40,40,2B,0.0849,0.0939,0.0958,0.0991,0.112,0.1170 -4-40,40,3B,0.0849,0.0939,0.0958,0.0982,0.112,0.116 4-48,48,2B,0.0894,0.0968,0.0985,0.1016,0.112,0.1167 -4-48,48,3B,0.0894,0.0968,0.0985,0.1008,0.112,0.1158 5-40,40,2B,0.0979,0.1062,0.1088,0.1121,0.125,0.1301 -5-40,40,3B,0.0979,0.1062,0.1088,0.1113,0.125,0.1292 5-44,44,2B,0.1004,0.1079,0.1102,0.1134,0.125,0.1299 -5-44,44,3B,0.1004,0.1079,0.1102,0.1126,0.125,0.129 6-32,32,2B,0.104,0.114,0.1177,0.1214,0.138,0.1438 -6-32,32,3B,0.104,0.114,0.1177,0.1204,0.138,0.1426 6-40,40,2B,0.111,0.119,0.1218,0.1252,0.138,0.1433 -6-40,40,3B,0.111,0.1186,0.1218,0.1243,0.138,0.1422 8-32,32,2B,0.13,0.139,0.1437,0.1475,0.164,0.1700 -8-32,32,3B,0.13,0.1389,0.1437,0.1465,0.164,0.1689 8-36,36,2B,0.134,0.142,0.146,0.1496,0.164,0.1697 -8-36,36,3B,0.134,0.1416,0.146,0.1487,0.164,0.1687 10-24,24,2B,0.145,0.156,0.1629,0.1672,0.19,0.197 -10-24,24,3B,0.145,0.1555,0.1629,0.1661,0.19,0.1957 10-32,32,2B,0.156,0.164,0.1697,0.1736,0.19,0.1963 -10-32,32,3B,0.156,0.1641,0.1697,0.1726,0.19,0.1952 1/4-20,20,2B,0.196,0.207,0.2175,0.2248,0.25,0.261 -1/4-20,20,3B,0.196,0.207,0.2175,0.22,0.25,0.2554 1/4-28,28,2B,0.211,0.22,0.2268,0.2311,0.25,0.2573 -1/4-28,28,3B,0.211,0.219,0.2268,0.23,0.25,0.2561 5/16-18,18,2B,0.252,0.265,0.2764,0.2817,0.3125,0.3217 -5/16-18,18,3B,0.252,0.263,0.2764,0.2803,0.3125,0.3201 5/16-24,24,2B,0.267,0.277,0.2854,0.2902,0.3125,0.3209 -5/16-24,24,3B,0.267,0.2754,0.2854,0.289,0.3125,0.3196 3/8-16,16,2B,0.307,0.321,0.3344,0.3401,0.375,0.3852 -3/8-16,16,3B,0.307,0.3182,0.3344,0.3387,0.375,0.3836 3/8-24,24,2B,0.33,0.34,0.3479,0.3528,0.375,0.3841 -3/8-24,24,3B,0.33,0.3372,0.3479,0.3516,0.375,0.3828 7/16-14,14,2B,0.36,0.376,0.3911,0.3972,0.4375,0.4488 -7/16-14,14,3B,0.36,0.3717,0.3911,0.3957,0.4375,0.4471 7/16-20,20,2B,0.383,0.395,0.405,0.4104,0.4375,0.4478 -7/16-20,20,3B,0.383,0.3916,0.405,0.4091,0.4375,0.4463 1/2-13,13,2B,0.417,0.434,0.45,0.4565,0.5,0.5123 -1/2-13,13,3B,0.417,0.4284,0.45,0.4548,0.5,0.5104 1/2-20,20,2B,0.446,0.457,0.4675,0.4731,0.5,0.5110 -1/2-20,20,3B,0.446,0.4537,0.4675,0.4717,0.5,0.5095 5/8-11,11,2B,0.527,0.546,0.566,0.5732,0.625,0.6393 -5/8-11,11,3B,0.527,0.5391,0.566,0.5714,0.625,0.6373 5/8-18,18,2B,0.565,0.578,0.5889,0.5949,0.625,0.6377 -5/8-18,18,3B,0.565,0.573,0.5889,0.5934,0.625,0.6361 3/4-10,10,2B,0.642,0.663,0.685,0.6927,0.75,0.7660 -3/4-10,10,3B,0.642,0.6545,0.685,0.6907,0.75,0.7638 3/4-16,16,2B,0.682,0.696,0.7094,0.7159,0.75,0.7644 -3/4-16,16,3B,0.682,0.6908,0.7094,0.7143,0.75,0.7627 7/8-9,9,2B,0.755,0.778,0.8028,0.811,0.875,0.8928 -7/8-9,9,3B,0.755,0.7681,0.8028,0.8089,0.875,0.8905 7/8-14,14,2B,0.798,0.814,0.8286,0.8356,0.875,0.8912 -7/8-14,14,3B,0.798,0.8068,0.8286,0.8339,0.875,0.8894 1-8,8,2B,0.865,0.89,0.9188,0.9276,1,1.0197 -1-8,8,3B,0.865,0.8797,0.9188,0.9254,1,1.0173 1-12,12,2B,0.91,0.928,0.9459,0.9535,1,1.0181 -1-12,12,3B,0.91,0.9198,0.9459,0.9516,1,1.0161 11/8-7,7,2B,0.97,0.998,1.0322,1.0416,1.125,1.1466 11/8-12,12,2B,1.035,1.053,1.0709,1.0787,1.125,1.1445 11/4-7,7,2B,1.095,1.123,1.1572,1.1668,1.25,1.273 diff --git a/src/Mod/Path/Data/Threads/imperial-internal-3B.csv b/src/Mod/Path/Data/Threads/imperial-internal-3B.csv new file mode 100644 index 0000000000..708c47443c --- /dev/null +++ b/src/Mod/Path/Data/Threads/imperial-internal-3B.csv @@ -0,0 +1,36 @@ +name,tpi,class,dMinorMin,dMinorMax,dPitchMin,dPitchMax,dMajorMin,dMajorMax +0-80,80,3B,0.0465,0.0514,0.0519,0.0536,0.06,0.0626 +1-64,64,3B,0.0561,0.0623,0.0629,0.0648,0.073,0.076 +1-72,72,3B,0.058,0.0635,0.064,0.0659,0.073,0.0759 +2-56,56,3B,0.0667,0.0737,0.0744,0.0765,0.086,0.0893 +2-64,64,3B,0.0691,0.0753,0.0759,0.0779,0.086,0.0891 +3-48,48,3B,0.0764,0.0845,0.0855,0.0877,0.099,0.1026 +3-56,56,3B,0.0797,0.0865,0.0874,0.0895,0.099,0.1024 +4-40,40,3B,0.0849,0.0939,0.0958,0.0982,0.112,0.116 +4-48,48,3B,0.0894,0.0968,0.0985,0.1008,0.112,0.1158 +5-40,40,3B,0.0979,0.1062,0.1088,0.1113,0.125,0.1292 +5-44,44,3B,0.1004,0.1079,0.1102,0.1126,0.125,0.129 +6-32,32,3B,0.104,0.114,0.1177,0.1204,0.138,0.1426 +6-40,40,3B,0.111,0.1186,0.1218,0.1243,0.138,0.1422 +8-32,32,3B,0.13,0.1389,0.1437,0.1465,0.164,0.1689 +8-36,36,3B,0.134,0.1416,0.146,0.1487,0.164,0.1687 +10-24,24,3B,0.145,0.1555,0.1629,0.1661,0.19,0.1957 +10-32,32,3B,0.156,0.1641,0.1697,0.1726,0.19,0.1952 +1/4-20,20,3B,0.196,0.207,0.2175,0.22,0.25,0.2554 +1/4-28,28,3B,0.211,0.219,0.2268,0.23,0.25,0.2561 +5/16-18,18,3B,0.252,0.263,0.2764,0.2803,0.3125,0.3201 +5/16-24,24,3B,0.267,0.2754,0.2854,0.289,0.3125,0.3196 +3/8-16,16,3B,0.307,0.3182,0.3344,0.3387,0.375,0.3836 +3/8-24,24,3B,0.33,0.3372,0.3479,0.3516,0.375,0.3828 +7/16-14,14,3B,0.36,0.3717,0.3911,0.3957,0.4375,0.4471 +7/16-20,20,3B,0.383,0.3916,0.405,0.4091,0.4375,0.4463 +1/2-13,13,3B,0.417,0.4284,0.45,0.4548,0.5,0.5104 +1/2-20,20,3B,0.446,0.4537,0.4675,0.4717,0.5,0.5095 +5/8-11,11,3B,0.527,0.5391,0.566,0.5714,0.625,0.6373 +5/8-18,18,3B,0.565,0.573,0.5889,0.5934,0.625,0.6361 +3/4-10,10,3B,0.642,0.6545,0.685,0.6907,0.75,0.7638 +3/4-16,16,3B,0.682,0.6908,0.7094,0.7143,0.75,0.7627 +7/8-9,9,3B,0.755,0.7681,0.8028,0.8089,0.875,0.8905 +7/8-14,14,3B,0.798,0.8068,0.8286,0.8339,0.875,0.8894 +1-8,8,3B,0.865,0.8797,0.9188,0.9254,1,1.0173 +1-12,12,3B,0.91,0.9198,0.9459,0.9516,1,1.0161 diff --git a/src/Mod/Path/Data/Threads/metric-external-4G6G.csv b/src/Mod/Path/Data/Threads/metric-external-4G6G.csv new file mode 100644 index 0000000000..55905b11c4 --- /dev/null +++ b/src/Mod/Path/Data/Threads/metric-external-4G6G.csv @@ -0,0 +1,175 @@ +name,pitch,tol,dMajorMax,dMajorMin,dPitchMax,dPitchMin,dMinorMax,dMinorMin +M1.6 x 0.35,0.35,4G6G,1.581,1.496,1.354,1.314,1.202,1.098 +M1.6 x 0.3,0.3,4G6G,1.582,1.507,1.387,1.359,1.257,1.174 +M1.6 x 0.2,0.2,4G6G,1.583,1.527,1.453,1.421,1.366,1.298 +M1.7 x 0.35,0.35,4G6G,1.681,1.596,1.454,1.414,1.302,1.198 +M1.8 x 0.35,0.35,4G6G,1.781,1.696,1.554,1.514,1.402,1.298 +M1.8 x 0.2,0.2,4G6G,1.783,1.727,1.653,1.621,1.566,1.498 +M2 x 0.4,0.4,4G6G,1.981,1.886,1.721,1.679,1.548,1.433 +M2 x 0.25,0.25,4G6G,1.982,1.915,1.82,1.784,1.711,1.63 +M2.2 x 0.45,0.45,4G6G,2.18,2.08,1.888,1.843,1.693,1.566 +M2.2 x 0.25,0.25,4G6G,2.182,2.115,2.02,1.984,1.911,1.83 +M2.3 x 0.45,0.45,4G6G,2.28,2.18,1.988,1.943,1.793,1.666 +M2.3 x 0.4,0.4,4G6G,2.281,2.186,2.021,1.979,1.848,1.733 +M2.5 x 0.45,0.45,4G6G,2.48,2.38,2.188,2.143,1.993,1.866 +M2.5 x 0.35,0.35,4G6G,2.481,2.396,2.254,2.214,2.102,1.998 +M2.6 x 0.45,0.45,4G6G,2.58,2.48,2.288,2.243,2.093,1.966 +M3 x 0.5,0.5,4G6G,2.98,2.874,2.655,2.607,2.439,2.299 +M3 x 0.35,0.35,4G6G,2.981,2.896,2.754,2.712,2.602,2.496 +M3.5 x 0.6,0.6,4G6G,3.479,3.354,3.089,3.036,2.829,2.667 +M3.5 x 0.35,0.35,4G6G,3.481,3.396,3.254,3.212,3.102,2.996 +M4 x 0.7,0.7,4G6G,3.978,3.838,3.523,3.467,3.22,3.036 +M4 x 0.5,0.5,4G6G,3.98,3.874,3.655,3.607,3.439,3.299 +M4.5 x 0.75,0.75,4G6G,4.478,4.338,3.991,3.935,3.666,3.473 +M4.5 x 0.5,0.5,4G6G,4.48,4.374,4.155,4.107,3.939,3.799 +M5 x 0.8,0.8,4G6G,4.976,4.826,4.456,4.396,4.11,3.904 +M5 x 0.5,0.5,4G6G,4.98,4.874,4.655,4.607,4.439,4.299 +M5.5 x 0.5,0.5,4G6G,5.48,5.374,5.155,5.099,4.939,4.791 +M6 x 1,1,4G6G,5.974,5.794,5.324,5.253,4.891,4.637 +M6 x 0.8,0.8,4G6G,5.976,5.826,5.456,5.406,5.11,4.914 +M6 x 0.75,0.75,4G6G,5.978,5.838,5.491,5.428,5.166,4.966 +M6 x 0.7,0.7,4G6G,5.978,5.838,5.523,5.463,5.22,5.032 +M6 x 0.5,0.5,4G6G,5.98,5.874,5.655,5.602,5.439,5.294 +M7 x 1,1,4G6G,6.974,6.794,6.324,6.253,5.891,5.637 +M7 x 0.75,0.75,4G6G,6.978,6.838,6.491,6.428,6.166,5.966 +M7 x 0.5,0.5,4G6G,6.98,6.874,6.655,6.602,6.439,6.294 +M8 x 1.25,1.25,4G6G,7.972,7.76,7.16,7.085,6.619,6.315 +M8 x 1,1,4G6G,7.974,7.794,7.324,7.253,6.891,6.637 +M8 x 0.8,0.8,4G6G,7.976,7.826,7.456,7.389,7.11,6.897 +M8 x 0.75,0.75,4G6G,7.978,7.838,7.491,7.428,7.166,6.966 +M8 x 0.5,0.5,4G6G,7.98,7.874,7.655,7.602,7.439,7.294 +M9 x 1.25,1.25,4G6G,8.972,8.76,8.16,8.085,7.619,7.315 +M9 x 1,1,4G6G,8.974,8.794,8.324,8.253,7.891,7.637 +M9 x 0.75,0.75,4G6G,8.978,8.838,8.491,8.428,8.166,7.966 +M9 x 0.5,0.5,4G6G,8.98,8.874,8.655,8.602,8.439,8.294 +M10 x 1.5,1.5,4G6G,9.968,9.732,8.994,8.909,8.344,7.985 +M10 x 1.25,1.25,4G6G,9.972,9.76,9.16,9.085,8.619,8.315 +M10 x 1.12,1.12,4G6G,9.973,9.783,9.246,9.171,8.761,8.481 +M10 x 1,1,4G6G,9.974,9.794,9.324,9.253,8.891,8.637 +M10 x 0.75,0.75,4G6G,9.978,9.838,9.491,9.428,9.166,8.966 +M10 x 0.5,0.5,4G6G,9.98,9.874,9.655,9.602,9.439,9.294 +M11 x 1.5,1.5,4G6G,10.968,10.732,9.994,9.911,9.344,8.987 +M11 x 1,1,4G6G,10.974,10.794,10.324,10.253,9.891,9.637 +M11 x 0.75,0.75,4G6G,10.978,10.838,10.491,10.428,10.166,9.966 +M11 x 0.5,0.5,4G6G,10.98,10.874,10.655,10.602,10.439,10.294 +M12 x 1.75,1.75,4G6G,11.966,11.701,10.829,10.734,10.072,9.656 +M12 x 1.25,1.25,4G6G,11.972,11.76,11.16,11.075,10.619,10.305 +M12 x 1,1,4G6G,11.974,11.794,11.324,11.249,10.891,10.633 +M12 x 0.75,0.75,4G6G,11.978,11.838,11.491,11.424,11.166,10.962 +M12 x 0.5,0.5,4G6G,11.98,11.874,11.655,11.598,11.439,11.29 +M14 x 2,2,4G6G,13.962,13.682,12.663,12.563,11.797,11.331 +M14 x 1.5,1.5,4G6G,13.968,13.732,12.994,12.904,12.344,11.98 +M14 x 1.25,1.25,4G6G,13.972,13.76,13.16,13.075,12.619,12.305 +M14 x 1,1,4G6G,13.974,13.794,13.324,13.25,12.891,12.634 +M14 x 0.75,0.75,4G6G,13.978,13.838,13.491,13.424,13.166,12.962 +M14 x 0.5,0.5,4G6G,13.98,13.874,13.655,13.598,13.439,13.29 +M15 x 1.5,1.5,4G6G,14.968,14.732,13.994,13.904,13.344,12.98 +M15 x 1,1,4G6G,14.974,14.794,14.324,14.249,13.891,13.633 +M16 x 2,2,4G6G,15.962,15.682,14.663,14.563,13.797,13.331 +M16 x 1.6,1.6,4G6G,15.968,15.756,14.929,14.863,14.236,13.877 +M16 x 1.5,1.5,4G6G,15.968,15.732,14.994,14.904,14.344,13.98 +M16 x 1.25,1.25,4G6G,15.972,15.76,15.16,15.075,14.619,14.305 +M16 x 1,1,4G6G,15.974,15.794,15.324,15.249,14.891,14.633 +M16 x 0.75,0.75,4G6G,15.978,15.838,15.491,15.424,15.166,14.962 +M16 x 0.5,0.5,4G6G,15.98,15.874,15.655,15.599,15.439,15.291 +M17 x 1.5,1.5,4G6G,16.968,16.732,15.994,15.904,15.344,14.98 +M17 x 1,1,4G6G,16.974,16.794,16.324,16.249,15.891,15.633 +M18 x 2.5,2.5,4G6G,17.958,17.623,16.334,16.228,15.252,14.688 +M18 x 2,2,4G6G,17.962,17.682,16.663,16.563,15.797,15.331 +M18 x 1.5,1.5,4G6G,17.968,17.732,16.994,16.904,16.344,15.98 +M18 x 1.25,1.25,4G6G,17.972,17.76,17.16,17.075,16.619,16.305 +M18 x 1,1,4G6G,17.974,17.794,17.324,17.249,16.891,16.633 +M18 x 0.75,0.75,4G6G,17.978,17.838,17.491,17.424,17.166,16.962 +M18 x 0.5,0.5,4G6G,17.98,17.874,17.655,17.599,17.439,17.291 +M20 x 2.5,2.5,4G6G,19.958,19.623,18.334,18.228,17.252,16.688 +M20 x 2,2,4G6G,19.962,19.682,18.663,18.562,17.797,17.33 +M20 x 1.5,1.5,4G6G,19.968,19.732,18.994,18.904,18.344,17.98 +M20 x 1,1,4G6G,19.974,19.794,19.324,19.249,18.891,18.633 +M20 x 0.75,0.75,4G6G,19.978,19.838,19.491,19.424,19.166,18.962 +M20 x 0.5,0.5,4G6G,19.98,19.874,19.655,19.599,19.439,19.291 +M22 x 3,3,4G6G,21.952,21.577,20.003,19.885,18.704,18.037 +M22 x 2.5,2.5,4G6G,21.958,21.623,20.334,20.234,19.252,18.694 +M22 x 2,2,4G6G,21.962,21.682,20.663,20.563,19.797,19.331 +M22 x 1.5,1.5,4G6G,21.968,21.732,20.994,20.904,20.344,19.98 +M22 x 1,1,4G6G,21.974,21.794,21.324,21.249,20.891,20.633 +M22 x 0.75,0.75,4G6G,21.978,21.838,21.491,21.424,21.166,20.962 +M22 x 0.5,0.5,4G6G,21.98,21.874,21.655,21.598,21.439,21.29 +M24 x 3,3,4G6G,23.952,23.557,22.003,21.878,20.704,20.03 +M24 x 2.5,2.5,4G6G,23.958,23.623,22.334,22.214,21.252,20.674 +M24 x 2,2,4G6G,23.962,23.682,22.663,22.557,21.797,21.325 +M24 x 1.5,1.5,4G6G,23.968,23.732,22.994,22.899,22.344,21.975 +M24 x 1,1,4G6G,23.974,23.794,23.324,23.244,22.891,22.628 +M24 x 0.75,0.75,4G6G,23.978,23.838,23.491,23.42,23.166,22.958 +M25 x 2,2,4G6G,24.962,24.682,23.663,23.557,22.797,22.325 +M25 x 1.5,1.5,4G6G,24.968,24.732,23.994,23.899,23.344,22.975 +M25 x 1,1,4G6G,24.974,24.794,24.324,24.244,23.891,23.628 +M26 x 1.5,1.5,4G6G,25.968,25.732,24.994,24.899,24.344,23.975 +M27 x 3,3,4G6G,26.952,26.577,25.003,24.878,23.704,23.03 +M27 x 2,2,4G6G,29.962,26.682,25.663,25.557,24.797,24.325 +M27 x 1.5,1.5,4G6G,26.968,26.732,25.994,25.899,25.344,24.975 +M27 x 1,1,4G6G,26.974,26.794,26.324,26.244,25.891,25.628 +M27 x 0.75,0.75,4G6G,26.978,26.838,26.491,26.42,26.166,25.958 +M28 x 2,2,4G6G,27.962,27.682,26.663,26.557,25.797,25.325 +M28 x 1.5,1.5,4G6G,27.968,27.732,26.994,26.899,26.344,25.975 +M28 x 1,1,4G6G,27.974,27.794,27.324,27.244,26.891,26.628 +M30 x 3.5,3.5,4G6G,29.947,29.522,27.674,27.542,26.158,25.386 +M30 x 3,3,4G6G,29.952,29.577,28.003,27.878,26.704,26.03 +M30 x 2.5,2.5,4G6G,29.958,29.623,28.334,28.214,27.252,26.674 +M30 x 2,2,4G6G,29.962,29.682,28.663,28.557,27.797,27.325 +M30 x 1.5,1.5,4G6G,29.968,29.732,28.994,28.899,28.344,27.975 +M30 x 1,1,4G6G,29.974,29.794,29.324,29.244,28.891,28.628 +M30 x 0.75,0.75,4G6G,29.978,29.838,29.491,29.42,29.166,28.958 +M32 x 2,2,4G6G,31.962,31.682,30.663,30.557,29.797,29.325 +M32 x 1.5,1.5,4G6G,31.968,31.732,30.994,30.899,30.344,29.975 +M33 x 3.5,3.5,4G6G,32.968,32.543,30.695,30.563,29.179,28.407 +M33 x 3,3,4G6G,32.952,32.577,31.003,30.878,29.704,29.03 +M33 x 2,2,4G6G,32.962,32.682,31.663,31.557,30.797,30.325 +M33 x 1.5,1.5,4G6G,32.968,32.732,31.994,31.899,31.344,30.975 +M33 x 1,1,4G6G,32.974,32.794,32.324,32.244,31.891,31.628 +M33 x 0.75,0.75,4G6G,32.978,32.838,32.491,32.42,32.166,31.958 +M35 x 1.5,1.5,4G6G,34.968,34.732,33.994,33.899,33.344,32.975 +M36 x 4,4,4G6G,35.94,35.465,33.342,33.202,31.61,30.738 +M36 x 3,3,4G6G,35.952,35.577,34.003,33.878,32.704,32.03 +M36 x 2,2,4G6G,35.962,35.682,34.663,34.557,33.797,33.325 +M36 x 1.5,1.5,4G6G,35.968,35.732,34.994,34.899,34.344,33.975 +M36 x 1,1,4G6G,35.974,35.794,35.324,35.244,34.891,34.628 +M38 x 1.5,1.5,4G6G,37.968,37.732,36.994,36.899,36.344,35.975 +M39 x 4,4,4G6G,38.94,38.465,36.342,36.202,34.61,33.738 +M39 x 3,3,4G6G,38.952,38.577,37.003,36.878,35.704,35.03 +M39 x 2,2,4G6G,38.962,38.682,37.663,37.557,36.797,36.325 +M39 x 1.5,1.5,4G6G,38.968,38.732,37.994,37.899,37.344,36.975 +M39 x 1,1,4G6G,38.974,38.794,38.324,38.244,37.891,37.628 +M40 x 3,3,4G6G,39.952,39.577,38.003,37.878,36.704,36.03 +M40 x 2.5,2.5,4G6G,39.958,39.623,38.334,38.215,37.252,36.674 +M40 x 2,2,4G6G,39.962,39.682,38.663,38.557,37.797,37.325 +M40 x 1.5,1.5,4G6G,39.968,39.732,38.994,38.899,38.344,37.975 +M42 x 4.5,4.5,4G6G,41.937,41.437,39.014,38.864,37.066,36.092 +M42 x 4,4,4G6G,41.94,41.465,39.342,39.202,37.61,36.738 +M42 x 3,3,4G6G,41.952,41.577,40.003,39.878,38.704,38.03 +M42 x 2,2,4G6G,41.962,41.682,40.663,40.557,39.797,39.325 +M42 x 1.5,1.5,4G6G,41.968,41.732,40.994,40.899,40.344,39.975 +M42 x 1,1,4G6G,41.974,41.794,41.324,41.244,40.891,40.628 +M45 x 4.5,4.5,4G6G,44.937,44.437,42.014,41.864,40.066,39.092 +M45 x 4,4,4G6G,44.94,44.465,42.342,42.202,40.61,39.738 +M45 x 3,3,4G6G,44.952,44.577,43.003,42.878,41.704,41.03 +M45 x 2,2,4G6G,44.962,44.682,43.663,43.557,42.797,42.325 +M45 x 1.5,1.5,4G6G,44.968,44.732,43.994,43.899,43.344,42.975 +M45 x 1,1,4G6G,44.974,44.794,44.324,44.244,43.891,43.628 +M48 x 5,5,4G6G,47.929,47.399,44.681,44.521,42.516,41.441 +M48 x 4,4,4G6G,47.94,47.465,45.342,45.192,43.61,42.728 +M48 x 3,3,4G6G,47.952,47.577,46.003,45.871,44.704,44.023 +M48 x 2,2,4G6G,47.962,47.682,46.663,46.551,45.797,45.319 +M48 x 1.5,1.5,4G6G,47.968,47.732,46.994,46.894,46.344,45.97 +M50 x 4,4,4G6G,49.94,49.465,47.342,47.192,45.61,44.728 +M50 x 3,3,4G6G,49.952,49.577,48.003,47.871,46.704,46.023 +M50 x 2,2,4G6G,49.962,49.682,48.663,48.551,47.797,47.319 +M50 x 1.5,1.5,4G6G,49.968,49.732,48.994,48.894,48.344,47.97 +M52 x 5,5,4G6G,51.929,51.399,48.681,48.531,46.516,45.451 +M52 x 4,4,4G6G,51.94,51.465,49.342,49.192,47.61,46.728 +M52 x 3,3,4G6G,51.952,51.577,50.003,49.871,48.704,48.023 +M52 x 2,2,4G6G,51.962,51.682,50.663,50.551,49.797,49.319 +M52 x 1.5,1.5,4G6G,51.968,51.732,50.994,50.894,50.344,49.97 +M55 x 4,4,4G6G,54.94,54.465,52.342,52.192,50.61,49.728 +M55 x 3,3,4G6G,54.952,54.577,53.003,52.871,51.704,51.023 +M55 x 2,2,4G6G,54.962,54.682,53.663,53.551,52.797,52.319 +M55 x 1.5,1.5,4G6G,54.968,54.732,53.994,53.894,53.344,52.97 diff --git a/src/Mod/Path/Data/Threads/metric-external-6G.csv b/src/Mod/Path/Data/Threads/metric-external-6G.csv new file mode 100644 index 0000000000..81cbe125e2 --- /dev/null +++ b/src/Mod/Path/Data/Threads/metric-external-6G.csv @@ -0,0 +1,176 @@ +name,pitch,tol,dMajorMax,dMajorMin,dPitchMax,dPitchMin,dMinorMax,dMinorMin +M1.6 x 0.35,0.35,6G,1.581,1.496,1.354,1.291,1.202,1.075 +M1.6 x 0.3,0.3,6G,1.582,1.507,1.387,1.342,1.257,1.157 +M1.6 x 0.2,0.2,6G,1.583,1.527,1.453,1.403,1.366,1.28 +M1.7 x 0.35,0.35,6G,1.681,1.596,1.454,1.391,1.302,1.175 +M1.8 x 0.35,0.35,6G,1.781,1.696,1.554,1.491,1.402,1.275 +M1.8 x 0.2,0.2,6G,1.783,1.727,1.653,1.603,1.566,1.48 +M2 x 0.4,0.4,6G,1.981,1.886,1.721,1.654,1.548,1.408 +M2 x 0.25,0.25,6G,1.982,1.915,1.82,1.764,1.711,1.61 +M2.2 x 0.45,0.45,6G,2.18,2.08,1.888,1.817,1.693,1.54 +M2.2 x 0.25,0.25,6G,2.182,2.115,2.02,1.964,1.911,1.81 +M2.3 x 0.45,0.45,6G,2.28,2.18,1.988,1.917,1.793,1.64 +M2.3 x 0.4,0.4,6G,2.281,2.186,2.021,1.954,1.848,1.708 +M2.5 x 0.45,0.45,6G,2.48,2.38,2.188,2.117,1.993,1.84 +M2.5 x 0.35,0.35,6G,2.481,2.396,2.254,2.191,2.102,1.975 +M2.6 x 0.45,0.45,6G,2.58,2.48,2.288,2.217,2.093,1.94 +M3 x 0.5,0.5,6G,2.98,2.874,2.655,2.58,2.439,2.272 +M3 x 0.35,0.35,6G,2.981,2.896,2.754,2.687,2.602,2.471 +M3.5 x 0.6,0.6,6G,3.479,3.354,3.089,3.004,2.829,2.635 +M3.5 x 0.35,0.35,6G,3.481,3.396,3.254,3.187,3.102,2.971 +M4 x 0.7,0.7,6G,3.978,3.838,3.523,3.433,3.22,3.002 +M4 x 0.5,0.5,6G,3.98,3.874,3.655,3.58,3.439,3.272 +M4.5 x 0.75,0.75,6G,4.478,4.338,3.991,3.901,3.666,3.439 +M4.5 x 0.5,0.5,6G,4.48,4.374,4.155,4.08,3.939,3.772 +M5 x 0.8,0.8,6G,4.976,4.826,4.456,4.361,4.11,3.869 +M5 x 0.5,0.5,6G,4.98,4.874,4.655,4.58,4.439,4.272 +M5.5 x 0.5,0.5,6G,5.48,5.374,5.155,5.065,4.939,4.757 +M6 x 1,1,6G,5.974,5.794,5.324,5.212,4.891,4.596 +M6 x 0.8,0.8,6G,5.976,5.826,5.456,5.376,5.11,4.884 +M6 x 0.75,0.75,6G,5.978,5.838,5.491,5.391,5.166,4.929 +M6 x 0.7,0.7,6G,5.978,5.838,5.523,5.428,5.22,4.997 +M6 x 0.5,0.5,6G,5.98,5.874,5.655,5.57,5.439,5.262 +M7 x 1,1,6G,6.974,6.794,6.324,6.212,5.891,5.596 +M7 x 0.75,0.75,6G,6.978,6.838,6.491,6.391,6.166,5.929 +M7 x 0.5,0.5,6G,6.98,6.874,6.655,6.57,6.439,6.262 +M8 x 1.25,1.25,6G,7.972,7.76,7.16,7.042,6.619,6.272 +M8 x 1,1,6G,7.974,7.794,7.324,7.212,6.891,6.596 +M8 x 0.8,0.8,6G,7.976,7.826,7.456,7.35,7.11,6.858 +M8 x 0.75,0.75,6G,7.978,7.838,7.491,7.391,7.166,6.929 +M8 x 0.5,0.5,6G,7.98,7.874,7.655,7.57,7.439,7.262 +M9 x 1.25,1.25,6G,8.972,8.76,8.16,8.042,7.619,7.272 +M9 x 1,1,6G,8.974,8.794,8.324,8.212,7.891,7.596 +M9 x 0.75,0.75,6G,8.978,8.838,8.491,8.391,8.166,7.929 +M9 x 0.5,0.5,6G,8.98,8.874,8.655,8.57,8.439,8.262 +M10 x 1.5,1.5,6G,9.968,9.732,8.994,8.862,8.344,7.938 +M10 x 1.25,1.25,6G,9.972,9.76,9.16,9.042,8.619,8.272 +M10 x 1.12,1.12,6G,9.973,9.783,9.246,9.128,8.761,8.438 +M10 x 1,1,6G,9.974,9.794,9.324,9.212,8.891,8.596 +M10 x 0.75,0.75,6G,9.978,9.838,9.491,9.391,9.166,8.929 +M10 x 0.5,0.5,6G,9.98,9.874,9.655,9.57,9.439,9.262 +M11 x 1.5,1.5,6G,10.968,10.732,9.994,9.862,9.344,8.938 +M11 x 1,1,6G,10.974,10.794,10.324,10.212,9.891,9.596 +M11 x 0.75,0.75,6G,10.978,10.838,10.491,10.391,10.166,9.929 +M11 x 0.5,0.5,6G,10.98,10.874,10.655,10.57,10.439,10.262 +M12 x 1.75,1.75,6G,11.966,11.701,10.829,10.679,10.072,9.601 +M12 x 1.5,1.5,6G,11.968,11.732,10.994,10.854,10.344,9.93 +M12 x 1.25,1.25,6G,11.972,11.76,11.16,11.028,10.619,10.258 +M12 x 1,1,6G,11.974,11.794,11.324,11.206,10.891,10.59 +M12 x 0.75,0.75,6G,11.978,11.838,11.491,11.385,11.166,10.923 +M12 x 0.5,0.5,6G,11.98,11.874,11.655,11.565,11.439,11.257 +M14 x 2,2,6G,13.962,13.682,12.663,12.503,11.797,11.271 +M14 x 1.5,1.5,6G,13.968,13.732,12.994,12.854,12.344,11.93 +M14 x 1.25,1.25,6G,13.972,13.76,13.16,13.028,12.619,12.258 +M14 x 1,1,6G,13.974,13.794,13.324,13.206,12.891,12.59 +M14 x 0.75,0.75,6G,13.978,13.838,13.491,13.385,13.166,12.923 +M14 x 0.5,0.5,6G,13.98,13.874,13.655,13.565,13.439,13.257 +M15 x 1.5,1.5,6G,14.968,14.732,13.994,13.854,13.344,12.93 +M15 x 1,1,6G,14.974,14.794,14.324,14.206,13.891,13.59 +M16 x 2,2,6G,15.962,15.682,14.663,14.503,13.797,13.271 +M16 x 1.6,1.6,6G,15.968,15.756,14.929,14.824,14.236,13.838 +M16 x 1.5,1.5,6G,15.968,15.732,14.994,14.854,14.344,13.93 +M16 x 1.25,1.25,6G,15.972,15.76,15.16,15.028,14.619,14.258 +M16 x 1,1,6G,15.974,15.794,15.324,15.206,14.891,14.59 +M16 x 0.75,0.75,6G,15.978,15.838,15.491,15.385,15.166,14.923 +M16 x 0.5,0.5,6G,15.98,15.874,15.655,15.565,15.439,15.257 +M17 x 1.5,1.5,6G,16.968,16.732,15.994,15.854,15.344,14.93 +M17 x 1,1,6G,16.974,16.794,16.324,16.206,15.891,15.59 +M18 x 2.5,2.5,6G,17.958,17.623,16.334,16.164,15.252,14.624 +M18 x 2,2,6G,17.962,17.682,16.663,16.503,15.797,15.271 +M18 x 1.5,1.5,6G,17.968,17.732,16.994,16.854,16.344,15.93 +M18 x 1.25,1.25,6G,17.972,17.76,17.16,17.028,16.619,16.258 +M18 x 1,1,6G,17.974,17.794,17.324,17.206,16.891,16.59 +M18 x 0.75,0.75,6G,17.978,17.838,17.491,17.385,17.166,16.923 +M18 x 0.5,0.5,6G,17.98,17.874,17.655,17.565,17.439,17.257 +M20 x 2.5,2.5,6G,19.958,19.623,18.334,18.164,17.252,16.624 +M20 x 2,2,6G,19.962,19.682,18.663,18.503,17.797,17.271 +M20 x 1.5,1.5,6G,19.968,19.732,18.994,18.854,18.344,17.93 +M20 x 1,1,6G,19.974,19.794,19.324,19.206,18.891,18.59 +M20 x 0.75,0.75,6G,19.978,19.838,19.491,19.385,19.166,18.923 +M20 x 0.5,0.5,6G,19.98,19.874,19.655,19.565,19.439,19.257 +M22 x 3,3,6G,21.952,21.577,20.003,19.818,18.704,17.97 +M22 x 2.5,2.5,6G,21.958,21.623,20.334,20.164,19.252,18.624 +M22 x 2,2,6G,21.962,21.682,20.663,20.503,19.797,19.271 +M22 x 1.5,1.5,6G,21.968,21.732,20.994,20.854,20.344,19.93 +M22 x 1,1,6G,21.974,21.794,21.324,21.206,20.891,20.59 +M22 x 0.75,0.75,6G,21.978,21.838,21.491,21.385,21.166,20.923 +M22 x 0.5,0.5,6G,21.98,21.874,21.655,21.565,21.439,21.257 +M24 x 3,3,6G,23.952,23.577,22.003,21.803,20.704,19.955 +M24 x 2.5,2.5,6G,23.958,23.623,22.334,22.144,21.252,20.604 +M24 x 2,2,6G,23.962,23.682,22.663,22.493,21.797,21.261 +M24 x 1.5,1.5,6G,23.968,23.732,22.994,22.844,22.344,21.92 +M24 x 1,1,6G,23.974,23.794,23.324,23.199,22.891,22.583 +M24 x 0.75,0.75,6G,23.978,23.838,23.491,23.379,23.166,22.917 +M25 x 2,2,6G,24.962,24.682,23.663,23.493,22.797,22.261 +M25 x 1.5,1.5,6G,24.968,24.732,23.994,23.844,23.344,22.92 +M25 x 1,1,6G,24.974,24.794,24.324,24.199,23.891,23.583 +M26 x 1.5,1.5,6G,25.968,25.732,24.994,24.844,24.344,23.92 +M27 x 3,3,6G,26.952,26.577,25.003,24.803,23.704,22.955 +M27 x 2,2,6G,26.962,26.682,25.663,25.493,24.797,24.261 +M27 x 1.5,1.5,6G,26.968,26.732,25.994,25.844,25.344,24.92 +M27 x 1,1,6G,26.974,26.794,26.324,26.199,25.891,25.583 +M27 x 0.75,0.75,6G,26.978,26.838,26.491,26.379,26.166,25.917 +M28 x 2,2,6G,27.962,27.682,26.663,26.493,25.797,25.261 +M28 x 1.5,1.5,6G,27.968,27.732,26.994,26.844,26.344,25.92 +M28 x 1,1,6G,27.974,27.794,27.324,27.199,26.891,26.583 +M30 x 3.5,3.5,6G,29.947,29.522,27.674,27.462,26.158,25.306 +M30 x 3,3,6G,29.952,29.577,28.003,27.803,26.704,25.955 +M30 x 2.5,2.5,6G,29.958,29.623,28.334,28.144,27.252,26.604 +M30 x 2,2,6G,29.962,29.682,28.663,28.493,27.797,27.261 +M30 x 1.5,1.5,6G,29.968,29.732,28.994,28.844,28.344,27.92 +M30 x 1,1,6G,29.974,29.794,29.324,29.199,28.891,28.583 +M30 x 0.75,0.75,6G,29.978,29.838,29.491,29.379,29.166,28.917 +M32 x 2,2,6G,31.962,31.682,30.663,30.493,29.797,29.261 +M32 x 1.5,1.5,6G,31.968,31.732,30.994,30.844,30.344,29.92 +M33 x 3.5,3.5,6G,32.968,32.543,30.695,30.483,29.179,28.327 +M33 x 3,3,6G,32.952,32.577,31.003,30.803,29.704,28.955 +M33 x 2,2,6G,32.962,32.682,31.663,31.493,30.797,30.261 +M33 x 1.5,1.5,6G,32.968,32.732,31.994,31.844,31.344,30.92 +M33 x 1,1,6G,32.974,32.794,32.324,32.199,31.891,31.583 +M33 x 0.75,0.75,6G,32.978,32.838,32.491,32.379,32.166,31.917 +M35 x 1.5,1.5,6G,34.968,34.732,33.994,33.844,33.344,33.92 +M36 x 4,4,6G,35.94,35.465,33.342,33.118,31.61,30.654 +M36 x 3,3,6G,35.952,35.577,34.003,33.803,32.704,31.955 +M36 x 2,2,6G,35.962,35.682,34.663,34.493,33.797,33.261 +M36 x 1.5,1.5,6G,35.968,35.732,34.994,34.844,34.344,33.92 +M36 x 1,1,6G,35.974,35.794,35.324,35.199,34.891,34.583 +M38 x 1.5,1.5,6G,37.968,37.732,36.994,36.844,36.344,35.92 +M39 x 4,4,6G,38.94,38.465,36.342,36.118,34.61,33.654 +M39 x 3,3,6G,38.952,38.577,37.003,36.803,35.704,34.955 +M39 x 2,2,6G,38.962,38.682,37.663,37.493,36.797,36.261 +M39 x 1.5,1.5,6G,38.968,38.732,37.994,37.844,37.344,36.92 +M39 x 1,1,6G,38.974,38.794,38.324,38.199,37.891,37.583 +M40 x 3,3,6G,39.952,39.577,38.003,37.803,36.704,35.955 +M40 x 2.5,2.5,6G,39.958,39.623,38.334,38.144,37.252,36.604 +M40 x 2,2,6G,39.962,39.682,38.663,38.493,37.797,37.261 +M40 x 1.5,1.5,6G,39.968,39.732,38.994,38.844,38.344,37.92 +M42 x 4.5,4.5,6G,41.937,41.437,39.014,38.778,37.066,36.006 +M42 x 4,4,6G,41.94,41.465,39.342,39.118,37.61,36.654 +M42 x 3,3,6G,41.952,41.577,40.003,39.803,38.704,37.955 +M42 x 2,2,6G,41.962,41.682,40.663,40.493,39.797,39.261 +M42 x 1.5,1.5,6G,41.968,41.732,40.994,40.844,40.344,39.92 +M42 x 1,1,6G,41.974,41.794,41.324,41.199,40.891,40.583 +M45 x 4.5,4.5,6G,44.937,44.437,42.014,41.778,40.066,39.006 +M45 x 4,4,6G,44.94,44.465,42.342,42.118,40.61,39.654 +M45 x 3,3,6G,44.952,44.577,43.003,42.803,41.704,40.955 +M45 x 2,2,6G,44.962,44.682,43.663,43.493,42.797,42.261 +M45 x 1.5,1.5,6G,44.968,44.732,43.994,43.844,43.344,42.92 +M45 x 1,1,6G,44.974,44.794,44.324,44.199,43.891,43.583 +M48 x 5,5,6G,47.929,47.399,44.681,44.431,42.516,41.351 +M48 x 4,4,6G,47.94,47.465,45.342,45.106,43.61,42.642 +M48 x 3,3,6G,47.952,47.577,46.003,45.791,44.704,43.943 +M48 x 2,2,6G,47.962,47.682,46.663,46.483,45.797,45.251 +M48 x 1.5,1.5,6G,47.968,47.732,46.994,46.834,46.344,45.91 +M50 x 4,4,6G,49.94,49.465,47.342,47.106,45.61,44.642 +M50 x 3,3,6G,49.952,49.577,48.003,47.791,46.704,45.943 +M50 x 2,2,6G,49.962,49.682,48.663,48.483,47.797,47.251 +M50 x 1.5,1.5,6G,49.968,49.732,48.994,48.834,48.344,47.91 +M52 x 5,5,6G,51.929,51.399,48.681,48.445,46.516,45.365 +M52 x 4,4,6G,51.94,51.465,49.342,49.106,47.61,46.642 +M52 x 3,3,6G,51.952,51.577,50.003,49.791,48.704,47.943 +M52 x 2,2,6G,51.962,51.682,50.663,50.483,49.797,49.251 +M52 x 1.5,1.5,6G,51.968,51.732,50.994,50.834,50.344,49.91 +M55 x 4,4,6G,54.94,54.465,52.342,52.106,50.61,49.642 +M55 x 3,3,6G,54.952,54.577,53.003,52.791,51.704,50.943 +M55 x 2,2,6G,54.962,54.682,53.663,53.483,52.797,52.251 +M55 x 1.5,1.5,6G,54.968,54.732,53.994,53.834,53.344,52.91 diff --git a/src/Mod/Path/Data/Threads/metric-internal.csv b/src/Mod/Path/Data/Threads/metric-internal-6H.csv similarity index 100% rename from src/Mod/Path/Data/Threads/metric-internal.csv rename to src/Mod/Path/Data/Threads/metric-internal-6H.csv diff --git a/src/Mod/Path/Data/Threads/sources.txt b/src/Mod/Path/Data/Threads/sources.txt index 20fb5e92fd..d67e754e4e 100644 --- a/src/Mod/Path/Data/Threads/sources.txt +++ b/src/Mod/Path/Data/Threads/sources.txt @@ -1,4 +1,8 @@ https://www.amesweb.info/Screws/Internal-Metric-Thread-Dimensions-Chart.aspx https://www.engineersedge.com/thread_strength/internal_screw_threads_chart.htm - dMajorMax = dMajorMin * 1.01 * (dMinorMax - dMinorMin) + dMajorMax = dMajorMin + 1.01 * (dMinorMax - dMinorMin) formula empirically derived from metric tolerances + +https://www.engineersedge.com/hardware/metric-external-thread-sizes1.htm +https://www.engineersedge.com/hardware/metric-external-thread-sizes2.htm + dMinorMin = dPitchMin - (dMajorMax - dPitchMax) * 0.948 diff --git a/src/Mod/Path/Generators/threadmilling_generator.py b/src/Mod/Path/Generators/threadmilling_generator.py new file mode 100644 index 0000000000..3694acaac0 --- /dev/null +++ b/src/Mod/Path/Generators/threadmilling_generator.py @@ -0,0 +1,208 @@ +# -*- coding: utf-8 -*- +# *************************************************************************** +# * Copyright (c) 2022 sliptonic * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program 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 Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +from __future__ import print_function + +import FreeCAD +import Path +import PathScripts.PathGeom as PathGeom +import PathScripts.PathLog as PathLog +import math +from PySide.QtCore import QT_TRANSLATE_NOOP + +__title__ = "Path Thread Milling generator" +__author__ = "sliptonic (Brad Collette)" +__url__ = "http://www.freecadweb.org" +__doc__ = "Path thread milling operation." + +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) + +translate = FreeCAD.Qt.translate + + +def _comment(path, msg): + """Nice for debugging to insert markers into generated g-code""" + if False: + path.append(Path.Command("(------- {} -------)".format(msg))) + + +class _Thread(object): + """Helper class for dealing with different thread types""" + + def __init__(self, cmd, zStart, zFinal, pitch, internal): + self.cmd = cmd + if zStart < zFinal: + self.pitch = pitch + else: + self.pitch = -pitch + self.hPitch = self.pitch / 2 + self.zStart = zStart + self.zFinal = zFinal + self.internal = internal + + def overshoots(self, z): + """overshoots(z) ... returns true if adding another half helix goes beyond the thread bounds""" + if self.pitch < 0: + return z + self.hPitch < self.zFinal + return z + self.hPitch > self.zFinal + + def adjustX(self, x, dx): + """adjustX(x, dx) ... move x by dx, the direction depends on the thread settings""" + if self.isG3() == (self.pitch > 0): + return x + dx + return x - dx + + def adjustY(self, y, dy): + """adjustY(y, dy) ... move y by dy, the direction depends on the thread settings""" + if self.isG3(): + return y - dy + return y - dy + + def isG3(self): + """isG3() ... returns True if this is a G3 command""" + return self.cmd in ["G3", "G03", "g3", "g03"] + + def isUp(self): + """isUp() ... returns True if the thread goes from the bottom up""" + return self.pitch > 0 + + def g4Opposite(self): + return "G2" if self.isG3() else "G3" + + def g4LeadInOut(self): + if self.internal: + return self.cmd + return self.g4Opposite() + + def g4Start2Elevator(self): + return self.g4Opposite() + + +def generate(center, cmd, zStart, zFinal, pitch, radius, leadInOut, elevator, start): + """generate(center, cmd, zStart, zFinal, pitch, radius, leadInOut, elevator, start) ... returns the g-code to mill the given internal thread""" + thread = _Thread(cmd, zStart, zFinal, pitch, radius > elevator) + + yMin = center.y - radius + yMax = center.y + radius + + path = [] + # at this point the tool is at a safe heiht (depending on the previous thread), so we can move + # into position first, and then drop to the start height. If there is any material in the way this + # op hasn't been setup properly. + if leadInOut: + _comment(path, "lead-in") + if start is None: + path.append(Path.Command("G0", {"X": center.x, "Y": center.y + elevator})) + path.append(Path.Command("G0", {"Z": thread.zStart})) + else: + path.append( + Path.Command( + thread.g4Start2Elevator(), + { + "X": center.x, + "Y": center.y + elevator, + "Z": thread.zStart, + "I": (center.x - start.x) / 2, + "J": (center.y + elevator - start.y) / 2, + "K": (thread.zStart - start.z) / 2, + }, + ) + ) + path.append( + Path.Command( + thread.g4LeadInOut(), + {"Y": yMax, "J": (yMax - (center.y + elevator)) / 2}, + ) + ) + _comment(path, "lead-in") + else: + if start is None: + path.append(Path.Command("G0", {"X": center.x, "Y": center.y + elevator})) + path.append(Path.Command("G0", {"Z": thread.zStart})) + else: + path.append( + Path.Command( + "G0", {"X": center.x, "Y": center.y + elevator, "Z": thread.zStart} + ) + ) + path.append(Path.Command("G1", {"Y": yMax})) + + z = thread.zStart + r = -radius + i = 0 + while not PathGeom.isRoughly(z, thread.zFinal): + if thread.overshoots(z): + break + if 0 == (i & 0x01): + y = yMin + else: + y = yMax + path.append(Path.Command(thread.cmd, {"Y": y, "Z": z + thread.hPitch, "J": r})) + r = -r + i = i + 1 + z = z + thread.hPitch + + if PathGeom.isRoughly(z, thread.zFinal): + x = center.x + y = yMin if (i & 0x01) else yMax + else: + n = math.fabs(thread.zFinal - thread.zStart) / thread.hPitch + k = n - int(n) + dy = math.cos(k * math.pi) + dx = math.sin(k * math.pi) + y = thread.adjustY(center.y, r * dy) + x = thread.adjustX(center.x, r * dx) + _comment(path, "finish-thread") + path.append( + Path.Command(thread.cmd, {"X": x, "Y": y, "Z": thread.zFinal, "J": r}) + ) + _comment(path, "finish-thread") + + a = math.atan2(y - center.y, x - center.x) + dx = math.cos(a) * (radius - elevator) + dy = math.sin(a) * (radius - elevator) + PathLog.debug("") + PathLog.debug("a={}: dx={:.2f}, dy={:.2f}".format(a / math.pi * 180, dx, dy)) + + elevatorX = x - dx + elevatorY = y - dy + PathLog.debug( + "({:.2f}, {:.2f}) -> ({:.2f}, {:.2f})".format(x, y, elevatorX, elevatorY) + ) + + if leadInOut: + _comment(path, "lead-out") + path.append( + Path.Command( + thread.g4LeadInOut(), + {"X": elevatorX, "Y": elevatorY, "I": -dx / 2, "J": -dy / 2}, + ) + ) + _comment(path, "lead-out") + else: + path.append(Path.Command("G1", {"X": elevatorX, "Y": elevatorY})) + + return (path, FreeCAD.Vector(elevatorX, elevatorY, thread.zFinal)) diff --git a/src/Mod/Path/PathScripts/PathThreadMilling.py b/src/Mod/Path/PathScripts/PathThreadMilling.py index 3dc5eb02c3..7ce1ead63e 100644 --- a/src/Mod/Path/PathScripts/PathThreadMilling.py +++ b/src/Mod/Path/PathScripts/PathThreadMilling.py @@ -28,6 +28,7 @@ import PathScripts.PathCircularHoleBase as PathCircularHoleBase import PathScripts.PathGeom as PathGeom import PathScripts.PathLog as PathLog import PathScripts.PathOp as PathOp +import Generators.threadmilling_generator as threadmilling import math from PySide.QtCore import QT_TRANSLATE_NOOP @@ -36,6 +37,9 @@ __author__ = "sliptonic (Brad Collette)" __url__ = "http://www.freecadweb.org" __doc__ = "Path thread milling operation." +# math.sqrt(3)/2 ... 60deg triangle height +SQRT_3_DIVIDED_BY_2 = 0.8660254037844386 + if False: PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) PathLog.trackModule(PathLog.thisModule()) @@ -45,8 +49,8 @@ else: translate = FreeCAD.Qt.translate -def radiiInternal(majorDia, minorDia, toolDia, toolCrest=None): - """internlThreadRadius(majorDia, minorDia, toolDia, toolCrest) ... returns the maximum radius for thread.""" +def threadRadii(internal, majorDia, minorDia, toolDia, toolCrest): + """threadRadii(majorDia, minorDia, toolDia, toolCrest) ... returns the minimum and maximum radius for thread.""" PathLog.track(majorDia, minorDia, toolDia, toolCrest) if toolCrest is None: toolCrest = 0.0 @@ -57,118 +61,61 @@ def radiiInternal(majorDia, minorDia, toolDia, toolCrest=None): # Since we already have the outer diameter it's simpler to just add 1/8 * H # to get the outer tip of the thread. H = ((majorDia - minorDia) / 2.0) * 1.6 # (D - d)/2 = 5/8 * H - outerTip = majorDia / 2.0 + H / 8.0 + if internal: + # mill inside out + outerTip = majorDia / 2.0 + H / 8.0 + # Compensate for the crest of the tool + toolTip = outerTip - toolCrest * SQRT_3_DIVIDED_BY_2 + return ((minorDia - toolDia) / 2.0, toolTip - toolDia / 2.0) + # mill outside in + innerTip = minorDia / 2.0 - H / 4.0 # Compensate for the crest of the tool - toolTip = ( - outerTip - toolCrest * 0.8660254037844386 - ) # math.sqrt(3)/2 ... 60deg triangle height - return ((minorDia - toolDia) / 2.0, toolTip - toolDia / 2.0) + toolTip = innerTip - toolCrest * SQRT_3_DIVIDED_BY_2 + return ((majorDia + toolDia) / 2.0, toolTip + toolDia / 2.0) -def threadPasses(count, radii, majorDia, minorDia, toolDia, toolCrest=None): - PathLog.track(count, radii, majorDia, minorDia, toolDia, toolCrest) - minor, major = radii(majorDia, minorDia, toolDia, toolCrest) - dr = float(major - minor) / count - return [major - dr * (count - (i + 1)) for i in range(count)] +def threadPasses(count, radii, internal, majorDia, minorDia, toolDia, toolCrest): + PathLog.track(count, radii, internal, majorDia, minorDia, toolDia, toolCrest) + # the logic goes as follows, total area to be removed: + # A = H * W ... where H is the depth and W is half the width of a thread + # H = k * sin(30) = k * 1/2 -> k = 2 * H + # W = k * cos(30) = k * sqrt(3)/2 + # -> W = (2 * H) * sqrt(3) / 2 = H * sqrt(3) + # A = sqrt(3) * H^2 + # Each pass has to remove the same area + # An = A / count = sqrt(3) * H^2 / count + # Because each successive pass doesn't have to remove the aera of the previous + # passes the result for the height: + # Ai = (i + 1) * An = (i + 1) * sqrt(3) * Hi^2 = sqrt(3) * H^2 / count + # Hi = sqrt(H^2 * (i + 1) / count) + # Hi = H * sqrt((i + 1) / count) + minor, major = radii(internal, majorDia, minorDia, toolDia, toolCrest) + H = float(major - minor) + Hi = [H * math.sqrt((i + 1) / count) for i in range(count)] + PathLog.debug("threadPasses({}, {}) -> H={} : {}".format(minor, major, H, Hi)) + + if internal: + return [minor + h for h in Hi] + return [major - h for h in Hi] -class _InternalThread(object): - """Helper class for dealing with different thread types""" +def elevatorRadius(obj, center, internal, tool): + """elevatorLocation(obj, center, internal, tool) ... return suitable location for the tool elevator""" - def __init__(self, cmd, zStart, zFinal, pitch): - self.cmd = cmd - if zStart < zFinal: - self.pitch = pitch - else: - self.pitch = -pitch - self.hPitch = self.pitch / 2 - self.zStart = zStart - self.zFinal = zFinal - - def overshoots(self, z): - """overshoots(z) ... returns true if adding another half helix goes beyond the thread bounds""" - if self.pitch < 0: - return z + self.hPitch < self.zFinal - return z + self.hPitch > self.zFinal - - def adjustX(self, x, dx): - """adjustX(x, dx) ... move x by dx, the direction depends on the thread settings""" - if self.isG3() == (self.pitch > 0): - return x + dx - return x - dx - - def adjustY(self, y, dy): - """adjustY(y, dy) ... move y by dy, the direction depends on the thread settings""" - if self.isG3(): - return y - dy - return y - dy - - def isG3(self): - """isG3() ... returns True if this is a G3 command""" - return self.cmd in ["G3", "G03", "g3", "g03"] - - def isUp(self): - """isUp() ... returns True if the thread goes from the bottom up""" - return self.pitch > 0 - - -def internalThreadCommands(loc, cmd, zStart, zFinal, pitch, radius, leadInOut): - """internalThreadCommands(loc, cmd, zStart, zFinal, pitch, radius) ... returns the g-code to mill the given internal thread""" - thread = _InternalThread(cmd, zStart, zFinal, pitch) - - yMin = loc.y - radius - yMax = loc.y + radius - - path = [] - # at this point the tool is at a safe height (depending on the previous thread), so we can move - # into position first, and then drop to the start height. If there is any material in the way this - # op hasn't been setup properly. - path.append(Path.Command("G0", {"X": loc.x, "Y": loc.y})) - path.append(Path.Command("G0", {"Z": thread.zStart})) - if leadInOut: - path.append(Path.Command(thread.cmd, {"Y": yMax, "J": (yMax - loc.y) / 2})) + if internal: + dy = float(obj.MinorDiameter - tool.Diameter) / 2 - 1 + if dy < 0: + if obj.MinorDiameter < tool.Diameter: + PathLog.error( + "The selected tool is too big (d={}) for milling a thread with minor diameter D={}".format( + tool.Diameter, obj.MinorDiameter + ) + ) + dy = 0 else: - path.append(Path.Command("G1", {"Y": yMax})) + dy = float(obj.MajorDiameter + tool.Diameter) / 2 + 1 - z = thread.zStart - r = -radius - i = 0 - while True: - z = thread.zStart + i * thread.hPitch - if thread.overshoots(z): - break - if 0 == (i & 0x01): - y = yMin - else: - y = yMax - path.append(Path.Command(thread.cmd, {"Y": y, "Z": z + thread.hPitch, "J": r})) - r = -r - i = i + 1 - - z = thread.zStart + i * thread.hPitch - if PathGeom.isRoughly(z, thread.zFinal): - x = loc.x - else: - n = math.fabs(thread.zFinal - thread.zStart) / thread.hPitch - k = n - int(n) - dy = math.cos(k * math.pi) - dx = math.sin(k * math.pi) - y = thread.adjustY(loc.y, r * dy) - x = thread.adjustX(loc.x, r * dx) - path.append( - Path.Command(thread.cmd, {"X": x, "Y": y, "Z": thread.zFinal, "J": r}) - ) - - if leadInOut: - path.append( - Path.Command( - thread.cmd, - {"X": loc.x, "Y": loc.y, "I": (loc.x - x) / 2, "J": (loc.y - y) / 2}, - ) - ) - else: - path.append(Path.Command("G1", {"X": loc.x, "Y": loc.y})) - return path + return dy class ObjectThreadMilling(PathCircularHoleBase.ObjectOp): @@ -176,18 +123,55 @@ class ObjectThreadMilling(PathCircularHoleBase.ObjectOp): LeftHand = "LeftHand" RightHand = "RightHand" - ThreadTypeCustom = "Custom" - ThreadTypeMetricInternal = "MetricInternal" - ThreadTypeImperialInternal = "ImperialInternal" + ThreadTypeCustomExternal = "CustomExternal" + ThreadTypeCustomInternal = "CustomInternal" + ThreadTypeImperialExternal2A = "ImperialExternal2A" + ThreadTypeImperialExternal3A = "ImperialExternal3A" + ThreadTypeImperialInternal2B = "ImperialInternal2B" + ThreadTypeImperialInternal3B = "ImperialInternal3B" + ThreadTypeMetricExternal4G6G = "MetricExternal4G6G" + ThreadTypeMetricExternal6G = "MetricExternal6G" + ThreadTypeMetricInternal6H = "MetricInternal6H" DirectionClimb = "Climb" DirectionConventional = "Conventional" ThreadOrientations = [LeftHand, RightHand] - ThreadTypes = [ - ThreadTypeCustom, - ThreadTypeMetricInternal, - ThreadTypeImperialInternal, + + ThreadTypeData = { + ThreadTypeImperialExternal2A: "imperial-external-2A.csv", + ThreadTypeImperialExternal3A: "imperial-external-3A.csv", + ThreadTypeImperialInternal2B: "imperial-internal-2B.csv", + ThreadTypeImperialInternal3B: "imperial-internal-3B.csv", + ThreadTypeMetricExternal4G6G: "metric-external-4G6G.csv", + ThreadTypeMetricExternal6G: "metric-external-6G.csv", + ThreadTypeMetricInternal6H: "metric-internal-6H.csv", + } + + ThreadTypesExternal = [ + ThreadTypeCustomExternal, + ThreadTypeImperialExternal2A, + ThreadTypeImperialExternal3A, + ThreadTypeMetricExternal4G6G, + ThreadTypeMetricExternal6G, ] + ThreadTypesInternal = [ + ThreadTypeCustomInternal, + ThreadTypeImperialInternal2B, + ThreadTypeImperialInternal3B, + ThreadTypeMetricInternal6H, + ] + ThreadTypesImperial = [ + ThreadTypeImperialExternal2A, + ThreadTypeImperialExternal3A, + ThreadTypeImperialInternal2B, + ThreadTypeImperialInternal3B, + ] + ThreadTypesMetric = [ + ThreadTypeMetricExternal4G6G, + ThreadTypeMetricExternal6G, + ThreadTypeMetricInternal6H, + ] + ThreadTypes = ThreadTypesInternal + ThreadTypesExternal Directions = [DirectionClimb, DirectionConventional] @classmethod @@ -200,25 +184,68 @@ class ObjectThreadMilling(PathCircularHoleBase.ObjectOp): 'raw' is list of (translated_text, data_string) tuples 'translated' is list of translated string literals """ + PathLog.track() # Enumeration lists for App::PropertyEnumeration properties enums = { "ThreadType": [ - (translate("Path_ThreadMilling", "Custom"), "Custom"), - (translate("Path_ThreadMilling", "Metric Internal"), "MetricInternal"), ( - translate("Path_ThreadMilling", "Imperial Internal"), - "ImperialInternal", + translate("Path_ThreadMilling", "Custom External"), + ObjectThreadMilling.ThreadTypeCustomExternal, ), - ], # this is the direction that the profile runs + ( + translate("Path_ThreadMilling", "Custom Internal"), + ObjectThreadMilling.ThreadTypeCustomInternal, + ), + ( + translate("Path_ThreadMilling", "Imperial External (2A)"), + ObjectThreadMilling.ThreadTypeImperialExternal2A, + ), + ( + translate("Path_ThreadMilling", "Imperial External (3A)"), + ObjectThreadMilling.ThreadTypeImperialExternal3A, + ), + ( + translate("Path_ThreadMilling", "Imperial Internal (2B)"), + ObjectThreadMilling.ThreadTypeImperialInternal2B, + ), + ( + translate("Path_ThreadMilling", "Imperial Internal (3B)"), + ObjectThreadMilling.ThreadTypeImperialInternal3B, + ), + ( + translate("Path_ThreadMilling", "Metric External (4G6G)"), + ObjectThreadMilling.ThreadTypeMetricExternal4G6G, + ), + ( + translate("Path_ThreadMilling", "Metric External (6G)"), + ObjectThreadMilling.ThreadTypeMetricExternal6G, + ), + ( + translate("Path_ThreadMilling", "Metric Internal (6H)"), + ObjectThreadMilling.ThreadTypeMetricInternal6H, + ), + ], "ThreadOrientation": [ - (translate("Path_ThreadMilling", "LeftHand"), "LeftHand"), - (translate("Path_ThreadMilling", "RightHand"), "RightHand"), - ], # side of profile that cutter is on in relation to direction of profile + ( + translate("Path_ThreadMilling", "LeftHand"), + ObjectThreadMilling.LeftHand, + ), + ( + translate("Path_ThreadMilling", "RightHand"), + ObjectThreadMilling.RightHand, + ), + ], "Direction": [ - (translate("Path_ThreadMilling", "Climb"), "Climb"), - (translate("Path_ThreadMilling", "Conventional"), "Conventional"), - ], # side of profile that cutter is on in relation to direction of profile + ( + translate("Path_ThreadMilling", "Climb"), + ObjectThreadMilling.DirectionClimb, + ), + ( + translate("Path_ThreadMilling", "Conventional"), + ObjectThreadMilling.DirectionConventional, + ), + ], } if dataType == "raw": @@ -236,9 +263,11 @@ class ObjectThreadMilling(PathCircularHoleBase.ObjectOp): return data def circularHoleFeatures(self, obj): + PathLog.track() return PathOp.FeatureBaseGeometry def initCircularHoleOperation(self, obj): + PathLog.track() obj.addProperty( "App::PropertyEnumeration", "ThreadOrientation", @@ -333,48 +362,11 @@ class ObjectThreadMilling(PathCircularHoleBase.ObjectOp): for n in self.propertyEnumerations(): setattr(obj, n[0], n[1]) - def threadStartDepth(self, obj): - if obj.ThreadOrientation == self.RightHand: - if obj.Direction == self.DirectionClimb: - PathLog.track(obj.Label, obj.FinalDepth) - return obj.FinalDepth - PathLog.track(obj.Label, obj.StartDepth) - return obj.StartDepth - if obj.Direction == self.DirectionClimb: - PathLog.track(obj.Label, obj.StartDepth) - return obj.StartDepth - PathLog.track(obj.Label, obj.FinalDepth) - return obj.FinalDepth + def _isThreadInternal(self, obj): + return obj.ThreadType in self.ThreadTypesInternal - def threadFinalDepth(self, obj): - PathLog.track(obj.Label) - if obj.ThreadOrientation == self.RightHand: - if obj.Direction == self.DirectionClimb: - PathLog.track(obj.Label, obj.StartDepth) - return obj.StartDepth - PathLog.track(obj.Label, obj.FinalDepth) - return obj.FinalDepth - if obj.Direction == self.DirectionClimb: - PathLog.track(obj.Label, obj.FinalDepth) - return obj.FinalDepth - PathLog.track(obj.Label, obj.StartDepth) - return obj.StartDepth - - def threadDirectionCmd(self, obj): - PathLog.track(obj.Label) - if obj.ThreadOrientation == self.RightHand: - if obj.Direction == self.DirectionClimb: - PathLog.track(obj.Label, "G2") - return "G2" - PathLog.track(obj.Label, "G3") - return "G3" - if obj.Direction == self.DirectionClimb: - PathLog.track(obj.Label, "G3") - return "G3" - PathLog.track(obj.Label, "G2") - return "G2" - - def threadSetup(self, obj): + def _threadSetupInternal(self, obj): + PathLog.track() # the thing to remember is that Climb, for an internal thread must always be G3 if obj.Direction == self.DirectionClimb: if obj.ThreadOrientation == self.RightHand: @@ -384,6 +376,18 @@ class ObjectThreadMilling(PathCircularHoleBase.ObjectOp): return ("G2", obj.StartDepth.Value, obj.FinalDepth.Value) return ("G2", obj.FinalDepth.Value, obj.StartDepth.Value) + def threadSetup(self, obj): + PathLog.track() + cmd, zbegin, zend = self._threadSetupInternal(obj) + + if obj.ThreadType in self.ThreadTypesInternal: + return (cmd, zbegin, zend) + + # need to reverse direction for external threads + if cmd == "G2": + return ("G3", zbegin, zend) + return ("G2", zbegin, zend) + def threadPassRadii(self, obj): PathLog.track(obj.Label) rMajor = (obj.MajorDiameter.Value - self.tool.Diameter) / 2.0 @@ -398,22 +402,45 @@ class ObjectThreadMilling(PathCircularHoleBase.ObjectOp): def executeThreadMill(self, obj, loc, gcode, zStart, zFinal, pitch): PathLog.track(obj.Label, loc, gcode, zStart, zFinal, pitch) + elevator = elevatorRadius(obj, loc, self._isThreadInternal(obj), self.tool) - self.commandlist.append( - Path.Command("G0", {"Z": obj.ClearanceHeight.Value, "F": self.vertRapid}) + move2clearance = Path.Command( + "G0", {"Z": obj.ClearanceHeight.Value, "F": self.vertRapid} ) + self.commandlist.append(move2clearance) + start = None for radius in threadPasses( obj.Passes, - radiiInternal, + threadRadii, + self._isThreadInternal(obj), obj.MajorDiameter.Value, obj.MinorDiameter.Value, float(self.tool.Diameter), float(self.tool.Crest), ): - commands = internalThreadCommands( - loc, gcode, zStart, zFinal, pitch, radius, obj.LeadInOut + if ( + not start is None + and not self._isThreadInternal(obj) + and not obj.LeadInOut + ): + # external thread without lead in/out have to go up and over + # in other words we need a move to clearance and not take any + # shortcuts when moving to the elevator position + self.commandlist.append(move2clearance) + start = None + commands, start = threadmilling.generate( + loc, + gcode, + zStart, + zFinal, + pitch, + radius, + obj.LeadInOut, + elevator, + start, ) + for cmd in commands: p = cmd.Parameters if cmd.Name in ["G0"]: @@ -454,18 +481,21 @@ class ObjectThreadMilling(PathCircularHoleBase.ObjectOp): PathLog.error("No suitable Tool found for thread milling operation") def opSetDefaultValues(self, obj, job): + PathLog.track() obj.ThreadOrientation = self.RightHand - obj.ThreadType = self.ThreadTypeMetricInternal + obj.ThreadType = self.ThreadTypeMetricInternal6H obj.ThreadFit = 50 obj.Pitch = 1 obj.TPI = 0 obj.Passes = 1 obj.Direction = self.DirectionClimb - obj.LeadInOut = True + obj.LeadInOut = False def isToolSupported(self, obj, tool): """Thread milling only supports thread milling cutters.""" - return hasattr(tool, "Diameter") and hasattr(tool, "Crest") + support = hasattr(tool, "Diameter") and hasattr(tool, "Crest") + PathLog.track(tool.Label, support) + return support def SetupProperties(): diff --git a/src/Mod/Path/PathScripts/PathThreadMillingGui.py b/src/Mod/Path/PathScripts/PathThreadMillingGui.py index 7b9c0e3b82..7b98ebe34e 100644 --- a/src/Mod/Path/PathScripts/PathThreadMillingGui.py +++ b/src/Mod/Path/PathScripts/PathThreadMillingGui.py @@ -49,17 +49,23 @@ else: translate = FreeCAD.Qt.translate -def fillThreads(combo, dataFile): - combo.blockSignals(True) - combo.clear() +def fillThreads(form, dataFile, defaultSelect): + form.threadName.blockSignals(True) + select = form.threadName.currentText() + PathLog.debug("select = '{}'".format(select)) + form.threadName.clear() with open( - "{}Mod/Path/Data/Threads/{}.csv".format(FreeCAD.getHomePath(), dataFile) + "{}Mod/Path/Data/Threads/{}".format(FreeCAD.getHomePath(), dataFile) ) as fp: reader = csv.DictReader(fp) for row in reader: - combo.addItem(row["name"], row) - combo.setEnabled(True) - combo.blockSignals(False) + form.threadName.addItem(row["name"], row) + if select: + form.threadName.setCurrentText(select) + elif defaultSelect: + form.threadName.setCurrentText(defaultSelect) + form.threadName.setEnabled(True) + form.threadName.blockSignals(False) class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage): @@ -74,10 +80,6 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage): ) self.pitch = PathGui.QuantitySpinBox(self.form.threadPitch, obj, "Pitch") - # setupCombo(self.form.threadOrientation, obj.Proxy.ThreadOrientations) - # setupCombo(self.form.threadType, obj.Proxy.ThreadTypes) - # setupCombo(self.form.opDirection, obj.Proxy.Directions) - def getForm(self): """getForm() ... return UI""" form = FreeCADGui.PySideUic.loadUi(":/panels/PageOpThreadMillingEdit.ui") @@ -134,25 +136,41 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage): self.pitch.updateSpinBox() self.setupToolController(obj, self.form.toolController) + self._updateFromThreadType() - def _isThreadMetric(self): - return ( - self.form.threadType.currentData() - == PathThreadMilling.ObjectThreadMilling.ThreadTypeMetricInternal - ) + def _isThreadCustom(self): + return self.form.threadType.currentData() in [ + PathThreadMilling.ObjectThreadMilling.ThreadTypeCustomInternal, + PathThreadMilling.ObjectThreadMilling.ThreadTypeCustomExternal, + ] def _isThreadImperial(self): return ( self.form.threadType.currentData() - == PathThreadMilling.ObjectThreadMilling.ThreadTypeImperialInternal + in PathThreadMilling.ObjectThreadMilling.ThreadTypesImperial + ) + + def _isThreadMetric(self): + return ( + self.form.threadType.currentData() + in PathThreadMilling.ObjectThreadMilling.ThreadTypesMetric + ) + + def _isThreadInternal(self): + return ( + self.form.threadType.currentData() + in PathThreadMilling.ObjectThreadMilling.ThreadTypesInternal + ) + + def _isThreadExternal(self): + return ( + self.form.threadType.currentData() + in PathThreadMilling.ObjectThreadMilling.ThreadTypesExternal ) def _updateFromThreadType(self): - if ( - self.form.threadType.currentData() - == PathThreadMilling.ObjectThreadMilling.ThreadTypeCustom - ): + if self._isThreadCustom(): self.form.threadName.setEnabled(False) self.form.threadFit.setEnabled(False) self.form.threadFitLabel.setEnabled(False) @@ -160,49 +178,53 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage): self.form.threadPitchLabel.setEnabled(True) self.form.threadTPI.setEnabled(True) self.form.threadTPILabel.setEnabled(True) - - if self._isThreadMetric(): + else: self.form.threadFit.setEnabled(True) self.form.threadFitLabel.setEnabled(True) - self.form.threadPitch.setEnabled(True) - self.form.threadPitchLabel.setEnabled(True) - self.form.threadTPI.setEnabled(False) - self.form.threadTPILabel.setEnabled(False) - self.form.threadTPI.setValue(0) - fillThreads(self.form.threadName, "metric-internal") - - if self._isThreadImperial(): - self.form.threadFit.setEnabled(True) - self.form.threadFitLabel.setEnabled(True) - self.form.threadPitch.setEnabled(False) - self.form.threadPitchLabel.setEnabled(False) - self.form.threadTPI.setEnabled(True) - self.form.threadTPILabel.setEnabled(True) - self.pitch.updateSpinBox(0) - fillThreads(self.form.threadName, "imperial-internal") + if self._isThreadMetric(): + self.form.threadPitch.setEnabled(True) + self.form.threadPitchLabel.setEnabled(True) + self.form.threadTPI.setEnabled(False) + self.form.threadTPILabel.setEnabled(False) + self.form.threadTPI.setValue(0) + else: + self.form.threadPitch.setEnabled(False) + self.form.threadPitchLabel.setEnabled(False) + self.form.threadTPI.setEnabled(True) + self.form.threadTPILabel.setEnabled(True) + self.pitch.updateSpinBox(0) + fillThreads( + self.form, + PathThreadMilling.ObjectThreadMilling.ThreadTypeData[ + self.form.threadType.currentData() + ], + self.obj.ThreadName, + ) + self._updateFromThreadName() def _updateFromThreadName(self): - thread = self.form.threadName.currentData() - fit = float(self.form.threadFit.value()) / 100 - mamin = float(thread["dMajorMin"]) - mamax = float(thread["dMajorMax"]) - major = mamin + (mamax - mamin) * fit - mimin = float(thread["dMinorMin"]) - mimax = float(thread["dMinorMax"]) - minor = mimin + (mimax - mimin) * fit + if not self._isThreadCustom(): + thread = self.form.threadName.currentData() + fit = float(self.form.threadFit.value()) / 100 + maxmin = float(thread["dMajorMin"]) + maxmax = float(thread["dMajorMax"]) + major = maxmin + (maxmax - maxmin) * fit + minmin = float(thread["dMinorMin"]) + minmax = float(thread["dMinorMax"]) + minor = minmin + (minmax - minmin) * fit - if self._isThreadMetric(): - pitch = float(thread["pitch"]) - self.pitch.updateSpinBox(pitch) + if self._isThreadMetric(): + pitch = float(thread["pitch"]) + self.pitch.updateSpinBox(pitch) - if self._isThreadImperial(): - tpi = int(thread["tpi"]) - self.form.threadTPI.setValue(tpi) - minor = minor * 25.4 - major = major * 25.4 + if self._isThreadImperial(): + tpi = int(thread["tpi"]) + self.form.threadTPI.setValue(tpi) + minor = minor * 25.4 + major = major * 25.4 - self.majorDia.updateSpinBox(major) - self.minorDia.updateSpinBox(minor) + self.majorDia.updateSpinBox(major) + self.minorDia.updateSpinBox(minor) self.setDirty() diff --git a/src/Mod/Path/PathTests/TestPathThreadMilling.py b/src/Mod/Path/PathTests/TestPathThreadMilling.py index 051c594f57..fcfb49f1c1 100644 --- a/src/Mod/Path/PathTests/TestPathThreadMilling.py +++ b/src/Mod/Path/PathTests/TestPathThreadMilling.py @@ -20,6 +20,7 @@ # * * # *************************************************************************** +import FreeCAD import PathScripts.PathGeom as PathGeom import PathScripts.PathThreadMilling as PathThreadMilling import math @@ -27,7 +28,7 @@ import math from PathTests.PathTestUtils import PathTestBase -def radii(major, minor, toolDia, toolCrest): +def radii(internal, major, minor, toolDia, toolCrest): """test radii function for simple testing""" return (minor, major) @@ -46,20 +47,48 @@ class TestPathThreadMilling(PathTestBase): def test00(self): """Verify internal radii.""" - self.assertRadii(PathThreadMilling.radiiInternal(20, 18, 2, 0), (8, 9.2)) - self.assertRadii(PathThreadMilling.radiiInternal(20, 19, 2, 0), (8.5, 9.1)) + self.assertRadii(PathThreadMilling.threadRadii(True, 20, 18, 2, 0), (8, 9.2)) + self.assertRadii(PathThreadMilling.threadRadii(True, 20, 19, 2, 0), (8.5, 9.1)) def test01(self): """Verify internal radii with tool crest.""" - self.assertRadii(PathThreadMilling.radiiInternal(20, 18, 2, 0.1), (8, 9.113397)) + self.assertRadii( + PathThreadMilling.threadRadii(True, 20, 18, 2, 0.1), (8, 9.113397) + ) def test10(self): - """Verify thread passes.""" - self.assertList(PathThreadMilling.threadPasses(1, radii, 10, 9, 0, 0), [10]) + """Verify internal thread passes.""" self.assertList( - PathThreadMilling.threadPasses(2, radii, 10, 9, 0, 0), [9.5, 10] + PathThreadMilling.threadPasses(1, radii, True, 10, 9, 0, 0), [10] ) self.assertList( - PathThreadMilling.threadPasses(5, radii, 10, 9, 0, 0), - [9.2, 9.4, 9.6, 9.8, 10], + PathThreadMilling.threadPasses(2, radii, True, 10, 9, 0, 0), [9.707107, 10] + ) + self.assertList( + PathThreadMilling.threadPasses(5, radii, True, 10, 9, 0, 0), + [9.447214, 9.632456, 9.774597, 9.894427, 10], + ) + + def test20(self): + """Verify external radii.""" + self.assertRadii(PathThreadMilling.threadRadii(False, 20, 18, 2, 0), (11, 9.6)) + self.assertRadii(PathThreadMilling.threadRadii(False, 20, 19, 2, 0), (11, 10.3)) + + def test21(self): + """Verify external radii with tool crest.""" + self.assertRadii( + PathThreadMilling.threadRadii(False, 20, 18, 2, 0.1), (11, 9.513397) + ) + + def test30(self): + """Verify external thread passes.""" + self.assertList( + PathThreadMilling.threadPasses(1, radii, False, 10, 9, 0, 0), [9] + ) + self.assertList( + PathThreadMilling.threadPasses(2, radii, False, 10, 9, 0, 0), [9.292893, 9] + ) + self.assertList( + PathThreadMilling.threadPasses(5, radii, False, 10, 9, 0, 0), + [9.552786, 9.367544, 9.225403, 9.105573, 9], ) diff --git a/src/Mod/Path/PathTests/TestPathThreadMillingGenerator.py b/src/Mod/Path/PathTests/TestPathThreadMillingGenerator.py new file mode 100644 index 0000000000..c73e5ea592 --- /dev/null +++ b/src/Mod/Path/PathTests/TestPathThreadMillingGenerator.py @@ -0,0 +1,246 @@ +# -*- coding: utf-8 -*- +# *************************************************************************** +# * Copyright (c) 2019 sliptonic * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program 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 Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import FreeCAD +import PathScripts.PathGeom as PathGeom +import Generators.threadmilling_generator as threadmilling +import math + +from PathTests.PathTestUtils import PathTestBase + + +def radii(internal, major, minor, toolDia, toolCrest): + """test radii function for simple testing""" + return (minor, major) + + +class TestPathThreadMillingGenerator(PathTestBase): + """Test thread milling generator.""" + + def test00(self): + """Verify thread commands for a single thread""" + + center = FreeCAD.Vector() + cmd = "G2" + zStart = 0 + zFinal = 1 + pitch = 1 + radius = 3 + leadInOut = False + elevator = 2 + + path, start = threadmilling.generate( + center, cmd, zStart, zFinal, pitch, radius, leadInOut, elevator, None + ) + + gcode = [ + "G0 X0.000000 Y2.000000", + "G0 Z0.000000", + "G1 Y3.000000", + "G2 J-3.000000 Y-3.000000 Z0.500000", + "G2 J3.000000 Y3.000000 Z1.000000", + "G1 X0.000000 Y2.000000", + ] + self.assertEqual([p.toGCode() for p in path], gcode) + self.assertCoincide(start, FreeCAD.Vector(0, 2, zFinal)) + + def test01(self): + """Verify thread commands for a thwo threads""" + + center = FreeCAD.Vector() + cmd = "G2" + zStart = 0 + zFinal = 2 + pitch = 1 + radius = 3 + leadInOut = False + elevator = 2 + + path, start = threadmilling.generate( + center, cmd, zStart, zFinal, pitch, radius, leadInOut, elevator, None + ) + + gcode = [ + "G0 X0.000000 Y2.000000", + "G0 Z0.000000", + "G1 Y3.000000", + "G2 J-3.000000 Y-3.000000 Z0.500000", + "G2 J3.000000 Y3.000000 Z1.000000", + "G2 J-3.000000 Y-3.000000 Z1.500000", + "G2 J3.000000 Y3.000000 Z2.000000", + "G1 X0.000000 Y2.000000", + ] + self.assertEqual([p.toGCode() for p in path], gcode) + self.assertCoincide(start, FreeCAD.Vector(0, 2, zFinal)) + + def test02(self): + """Verify thread commands for a one and a half threads""" + + center = FreeCAD.Vector() + cmd = "G2" + zStart = 0 + zFinal = 1.5 + pitch = 1 + radius = 3 + leadInOut = False + elevator = 2 + + path, start = threadmilling.generate( + center, cmd, zStart, zFinal, pitch, radius, leadInOut, elevator, None + ) + + gcode = [ + "G0 X0.000000 Y2.000000", + "G0 Z0.000000", + "G1 Y3.000000", + "G2 J-3.000000 Y-3.000000 Z0.500000", + "G2 J3.000000 Y3.000000 Z1.000000", + "G2 J-3.000000 Y-3.000000 Z1.500000", + "G1 X0.000000 Y-2.000000", + ] + self.assertEqual([p.toGCode() for p in path], gcode) + self.assertCoincide(start, FreeCAD.Vector(0, -2, zFinal)) + + def test03(self): + """Verify thread commands for a one and 3 quarter threads""" + + center = FreeCAD.Vector() + cmd = "G2" + zStart = 0 + zFinal = 1.75 + pitch = 1 + radius = 3 + leadInOut = False + elevator = 2 + + path, start = threadmilling.generate( + center, cmd, zStart, zFinal, pitch, radius, leadInOut, elevator, None + ) + + gcode = [ + "G0 X0.000000 Y2.000000", + "G0 Z0.000000", + "G1 Y3.000000", + "G2 J-3.000000 Y-3.000000 Z0.500000", + "G2 J3.000000 Y3.000000 Z1.000000", + "G2 J-3.000000 Y-3.000000 Z1.500000", + #'(------- finish-thread -------)', + "G2 J3.000000 X-3.000000 Y0.000000 Z1.750000", + #'(------- finish-thread -------)', + "G1 X-2.000000 Y0.000000", + ] + self.assertEqual([p.toGCode() for p in path], gcode) + self.assertCoincide(start, FreeCAD.Vector(-2, 0, zFinal)) + + def test04(self): + """Verify thread commands for a one and 3 quarter threads - CCW""" + + center = FreeCAD.Vector() + cmd = "G3" + zStart = 0 + zFinal = 1.75 + pitch = 1 + radius = 3 + leadInOut = False + elevator = 2 + + path, start = threadmilling.generate( + center, cmd, zStart, zFinal, pitch, radius, leadInOut, elevator, None + ) + + gcode = [ + "G0 X0.000000 Y2.000000", + "G0 Z0.000000", + "G1 Y3.000000", + "G3 J-3.000000 Y-3.000000 Z0.500000", + "G3 J3.000000 Y3.000000 Z1.000000", + "G3 J-3.000000 Y-3.000000 Z1.500000", + #'(------- finish-thread -------)', + "G3 J3.000000 X3.000000 Y0.000000 Z1.750000", + #'(------- finish-thread -------)', + "G1 X2.000000 Y0.000000", + ] + self.assertEqual([p.toGCode() for p in path], gcode) + self.assertCoincide(start, FreeCAD.Vector(2, 0, zFinal)) + + def test10(self): + """Verify lead in/out commands for a single thread""" + + center = FreeCAD.Vector() + cmd = "G2" + zStart = 0 + zFinal = 1 + pitch = 1 + radius = 3 + leadInOut = True + elevator = 2 + + path, start = threadmilling.generate( + center, cmd, zStart, zFinal, pitch, radius, leadInOut, elevator, None + ) + + gcode = [ + "G0 X0.000000 Y2.000000", + "G0 Z0.000000", + #'(------- lead-in -------)', + "G2 J0.500000 Y3.000000", + #'(------- lead-in -------)', + "G2 J-3.000000 Y-3.000000 Z0.500000", + "G2 J3.000000 Y3.000000 Z1.000000", + #'(------- lead-out -------)', + "G2 I0.000000 J-0.500000 X0.000000 Y2.000000", + #'(------- lead-out -------)', + ] + self.assertEqual([p.toGCode() for p in path], gcode) + self.assertCoincide(start, FreeCAD.Vector(0, 2, zFinal)) + + def test11(self): + """Verify lead in/out commands for one and a half threads""" + + center = FreeCAD.Vector() + cmd = "G2" + zStart = 0 + zFinal = 1.5 + pitch = 1 + radius = 3 + leadInOut = True + elevator = 2 + + path, start = threadmilling.generate( + center, cmd, zStart, zFinal, pitch, radius, leadInOut, elevator, None + ) + + gcode = [ + "G0 X0.000000 Y2.000000", + "G0 Z0.000000", + #'(------- lead-in -------)', + "G2 J0.500000 Y3.000000", + #'(------- lead-in -------)', + "G2 J-3.000000 Y-3.000000 Z0.500000", + "G2 J3.000000 Y3.000000 Z1.000000", + "G2 J-3.000000 Y-3.000000 Z1.500000", + #'(------- lead-out -------)', + "G2 I0.000000 J0.500000 X0.000000 Y-2.000000", + #'(------- lead-out -------)', + ] + self.assertEqual([p.toGCode() for p in path], gcode) + self.assertCoincide(start, FreeCAD.Vector(0, -2, zFinal)) diff --git a/src/Mod/Path/TestPathApp.py b/src/Mod/Path/TestPathApp.py index 9465b2eeb6..28a58e0fb9 100644 --- a/src/Mod/Path/TestPathApp.py +++ b/src/Mod/Path/TestPathApp.py @@ -46,6 +46,7 @@ from PathTests.TestPathRotationGenerator import TestPathRotationGenerator from PathTests.TestPathSetupSheet import TestPathSetupSheet from PathTests.TestPathStock import TestPathStock from PathTests.TestPathThreadMilling import TestPathThreadMilling +from PathTests.TestPathThreadMillingGenerator import TestPathThreadMillingGenerator from PathTests.TestPathTool import TestPathTool from PathTests.TestPathToolBit import TestPathToolBit from PathTests.TestPathToolChangeGenerator import TestPathToolChangeGenerator @@ -77,6 +78,7 @@ False if TestPathRotationGenerator.__name__ else True False if TestPathSetupSheet.__name__ else True False if TestPathStock.__name__ else True False if TestPathThreadMilling.__name__ else True +False if TestPathThreadMillingGenerator.__name__ else True False if TestPathTool.__name__ else True False if TestPathToolBit.__name__ else True False if TestPathToolChangeGenerator.__name__ else True