diff --git a/src/Mod/PartDesign/App/FeatureHole.cpp b/src/Mod/PartDesign/App/FeatureHole.cpp index cd46abc519..d4329b4a31 100644 --- a/src/Mod/PartDesign/App/FeatureHole.cpp +++ b/src/Mod/PartDesign/App/FeatureHole.cpp @@ -37,6 +37,8 @@ # include # include # include +# include +# include # include # include # include @@ -65,7 +67,7 @@ namespace PartDesign { const char* Hole::DepthTypeEnums[] = { "Dimension", "ThroughAll", /*, "UpToFirst", */ nullptr }; const char* Hole::ThreadDepthTypeEnums[] = { "Hole Depth", "Dimension", "Tapped (DIN76)", nullptr }; -const char* Hole::ThreadTypeEnums[] = { "None", "ISOMetricProfile", "ISOMetricFineProfile", "UNC", "UNF", "UNEF", nullptr}; +const char* Hole::ThreadTypeEnums[] = { "None", "ISOMetricProfile", "ISOMetricFineProfile", "UNC", "UNF", "UNEF", "NPT", "BSP", "BSW", "BSF", nullptr}; const char* Hole::ClearanceMetricEnums[] = { "Standard", "Close", "Wide", nullptr}; const char* Hole::ClearanceUTSEnums[] = { "Normal", "Close", "Loose", nullptr }; const char* Hole::DrillPointEnums[] = { "Flat", "Angled", nullptr}; @@ -86,55 +88,55 @@ const Hole::ThreadDescription Hole::threadDescription[][171] = { /* None */ { - { "---", 6.0, 0.0, 0.0 }, + { "---", 6.0, 0.0, 0.0 }, }, /* ISO metric regular */ - /* ISO metric threaded core hole diameters according to ISO 2306 */ - // {name, thread diameter, thread pitch, core hole diameter} + /* ISO metric threaded Tap-Drill diameters according to ISO 2306 */ + // {name, thread diameter, thread pitch, Tap-Drill diameter} { - { "M1", 1.0, 0.25, 0.75 }, - { "M1.1", 1.1, 0.25, 0.85 }, - { "M1.2", 1.2, 0.25, 0.95 }, - { "M1.4", 1.4, 0.30, 1.10 }, - { "M1.6", 1.6, 0.35, 1.25 }, - { "M1.8", 1.8, 0.35, 1.45 }, - { "M2", 2.0, 0.40, 1.60 }, - { "M2.2", 2.2, 0.45, 1.75 }, - { "M2.5", 2.5, 0.45, 2.05 }, - { "M3", 3.0, 0.50, 2.50 }, - { "M3.5", 3.5, 0.60, 2.90 }, - { "M4", 4.0, 0.70, 3.30 }, - { "M4.5", 4.5, 0.75, 3.70 }, - { "M5", 5.0, 0.80, 4.20 }, - { "M6", 6.0, 1.00, 5.00 }, - { "M7", 7.0, 1.00, 6.00 }, - { "M8", 8.0, 1.25, 6.80 }, - { "M9", 9.0, 1.25, 7.80 }, - { "M10", 10.0, 1.50, 8.50 }, - { "M11", 11.0, 1.50, 9.50 }, - { "M12", 12.0, 1.75, 10.20 }, - { "M14", 14.0, 2.00, 12.00 }, - { "M16", 16.0, 2.00, 14.00 }, - { "M18", 18.0, 2.50, 15.50 }, - { "M20", 20.0, 2.50, 17.50 }, - { "M22", 22.0, 2.50, 19.50 }, - { "M24", 24.0, 3.00, 21.00 }, - { "M27", 27.0, 3.00, 24.00 }, - { "M30", 30.0, 3.50, 26.50 }, - { "M33", 33.0, 3.50, 29.50 }, - { "M36", 36.0, 4.00, 32.00 }, - { "M39", 39.0, 4.00, 35.00 }, - { "M42", 42.0, 4.50, 37.50 }, - { "M45", 45.0, 4.50, 40.50 }, - { "M48", 48.0, 5.00, 43.00 }, - { "M52", 52.0, 5.00, 47.00 }, - { "M56", 56.0, 5.50, 50.50 }, - { "M60", 60.0, 5.50, 54.50 }, - { "M64", 64.0, 6.00, 58.00 }, - { "M68", 68.0, 6.00, 62.00 }, + { "M1", 1.0, 0.25, 0.75 }, + { "M1.1", 1.1, 0.25, 0.85 }, + { "M1.2", 1.2, 0.25, 0.95 }, + { "M1.4", 1.4, 0.30, 1.10 }, + { "M1.6", 1.6, 0.35, 1.25 }, + { "M1.8", 1.8, 0.35, 1.45 }, + { "M2", 2.0, 0.40, 1.60 }, + { "M2.2", 2.2, 0.45, 1.75 }, + { "M2.5", 2.5, 0.45, 2.05 }, + { "M3", 3.0, 0.50, 2.50 }, + { "M3.5", 3.5, 0.60, 2.90 }, + { "M4", 4.0, 0.70, 3.30 }, + { "M4.5", 4.5, 0.75, 3.70 }, + { "M5", 5.0, 0.80, 4.20 }, + { "M6", 6.0, 1.00, 5.00 }, + { "M7", 7.0, 1.00, 6.00 }, + { "M8", 8.0, 1.25, 6.80 }, + { "M9", 9.0, 1.25, 7.80 }, + { "M10", 10.0, 1.50, 8.50 }, + { "M11", 11.0, 1.50, 9.50 }, + { "M12", 12.0, 1.75, 10.20 }, + { "M14", 14.0, 2.00, 12.00 }, + { "M16", 16.0, 2.00, 14.00 }, + { "M18", 18.0, 2.50, 15.50 }, + { "M20", 20.0, 2.50, 17.50 }, + { "M22", 22.0, 2.50, 19.50 }, + { "M24", 24.0, 3.00, 21.00 }, + { "M27", 27.0, 3.00, 24.00 }, + { "M30", 30.0, 3.50, 26.50 }, + { "M33", 33.0, 3.50, 29.50 }, + { "M36", 36.0, 4.00, 32.00 }, + { "M39", 39.0, 4.00, 35.00 }, + { "M42", 42.0, 4.50, 37.50 }, + { "M45", 45.0, 4.50, 40.50 }, + { "M48", 48.0, 5.00, 43.00 }, + { "M52", 52.0, 5.00, 47.00 }, + { "M56", 56.0, 5.50, 50.50 }, + { "M60", 60.0, 5.50, 54.50 }, + { "M64", 64.0, 6.00, 58.00 }, + { "M68", 68.0, 6.00, 62.00 }, }, - /* ISO metric fine (core hole entry is calculated exactly by diameter - pitch) */ + /* ISO metric fine (drill = diameter - pitch) */ { { "M1x0.2", 1.0, 0.20, 0.80 }, { "M1.1x0.2", 1.1, 0.20, 0.90 }, @@ -397,52 +399,187 @@ const Hole::ThreadDescription Hole::threadDescription[][171] = { "1 9/16", 39.688, 1.411, 38.55 }, { "1 5/8", 41.275, 1.411, 40.10 }, { "1 11/16", 42.862, 1.411, 41.60 }, + }, + /* NPT National pipe threads */ + // Asme B1.20.1 + { + { "1/16", 7.938, 0.941, 0.0 }, + { "1/8", 10.287, 0.941, 0.0 }, + { "1/4", 13.716, 1.411, 0.0 }, + { "3/8", 17.145, 1.411, 0.0 }, + { "1/2", 21.336, 1.814, 0.0 }, + { "3/4", 26.670, 1.814, 0.0 }, + { "1", 33.401, 2.209, 0.0 }, + { "1 1/4", 42.164, 2.209, 0.0 }, + { "1 1/2", 48.260, 2.209, 0.0 }, + { "2", 60.325, 2.209, 0.0 }, + { "2 1/2", 73.025, 3.175, 0.0 }, + { "3", 88.900, 3.175, 0.0 }, + { "3 1/2", 101.600, 3.175, 0.0 }, + { "4", 114.300, 3.175, 0.0 }, + { "5", 141.300, 3.175, 0.0 }, + { "6", 168.275, 3.175, 0.0 }, + { "8", 219.075, 3.175, 0.0 }, + { "10", 273.050, 3.175, 0.0 }, + { "12", 323.850, 3.175, 0.0 }, + }, + /* BSP */ + // Parallel - ISO 228-1 + // Tapered - ISO 7-1 + { + { "1/16", 7.723, 0.907, 6.6 }, + { "1/8", 9.728, 0.907, 8.8 }, + { "1/4", 13.157, 1.337, 11.8 }, + { "3/8", 16.662, 1.337, 15.25 }, + { "1/2", 20.955, 1.814, 19.00 }, + { "5/8", 22.911, 1.814, 21.00 }, + { "3/4", 26.441, 1.814, 24.50 }, + { "7/8", 30.201, 1.814, 28.25 }, + { "1", 33.249, 2.309, 30.75 }, + { "1 1/8", 37.897, 2.309, 0.0 }, + { "1 1/4", 41.910, 2.309, 39.50 }, + { "1 1/2", 47.803, 2.309, 45.50 }, + { "1 3/4", 53.743, 2.309, 51.00 }, + { "2", 59.614, 2.309, 57.00 }, + { "2 1/4", 65.710, 2.309, 0.0 }, + { "2 1/2", 75.184, 2.309, 0.0 }, + { "2 3/4", 81.534, 2.309, 0.0 }, + { "3", 87.884, 2.309, 0.0 }, + { "3 1/2", 100.330, 2.309, 0.0 }, + { "4", 113.030, 2.309, 0.0 }, + { "4 1/2", 125.730, 2.309, 0.0 }, + { "5", 138.430, 2.309, 0.0 }, + { "5 1/2", 151.130, 2.309, 0.0 }, + { "6", 163.830, 2.309, 0.0 }, + }, + /* BSW */ + // BS 84 Basic sizes + { + { "1/8", 3.175, 0.635, 2.55 }, + { "3/16", 4.762, 1.058, 3.70 }, + { "1/4", 6.350, 1.270, 5.10 }, + { "5/16", 7.938, 1.411, 6.50 }, + { "3/8", 9.525, 1.588, 7.90 }, + { "7/16", 11.113, 1.814, 9.30 }, + { "1/2", 12.700, 2.117, 10.50 }, + { "9/16", 14.290, 2.117, 12.10 }, + { "5/8", 15.876, 2.309, 13.50 }, + { "11/16", 17.463, 2.309, 15.00 }, + { "3/4", 19.051, 2.540, 16.25 }, + { "7/8", 22.226, 2.822, 19.25 }, + { "1", 25.400, 3.175, 22.00 }, + { "1 1/8", 28.576, 3.629, 24.75 }, + { "1 1/4", 31.751, 3.629, 28.00 }, + { "1 1/2", 38.100, 4.233, 33.50 }, + { "1 3/4", 44.452, 5.080, 39.00 }, + { "2", 50.802, 5.644, 44.50 }, + { "2 1/4", 57.152, 6.350, 0.0 }, + { "2 1/2", 63.502, 6.350, 0.0 }, + { "2 3/4", 69.853, 7.257, 0.0 }, + { "3", 76.203, 7.257, 0.0 }, + { "3 1/4", 82.553, 7.815, 0.0 }, + { "3 1/2", 88.903, 7.815, 0.0 }, + { "3 3/4", 95.254, 8.467, 0.0 }, + { "4", 101.604, 8.467, 0.0 }, + { "4 1/2", 114.304, 8.835, 0.0 }, + { "5", 127.005, 9.236, 0.0 }, + { "5 1/2", 139.705, 9.676, 0.0 }, + { "6", 152.406, 10.16, 0.0 }, + }, + /* BSF */ + // BS 84 Basic sizes + // BS 1157 for drill sizes + { + { "3/16", 4.763, 0.794, 4.00 }, + { "7/32", 5.558, 0.907, 4.60 }, + { "1/4", 6.350, 0.977, 5.30 }, + { "9/32", 7.142, 0.977, 6.10 }, + { "5/16", 7.938, 1.154, 6.80 }, + { "3/8", 9.525, 1.270, 8.30 }, + { "7/16", 11.113, 1.411, 9.70 }, + { "1/2", 12.700, 1.588, 11.10 }, + { "9/16", 14.288, 1.588, 12.70 }, + { "5/8", 15.875, 1.814, 14.00 }, + { "11/16", 17.463, 1.814, 15.50 }, + { "3/4", 19.050, 2.116, 16.75 }, + { "7/8", 22.225, 2.309, 19.75 }, + { "1", 25.400, 2.540, 22.75 }, + { "1 1/8", 28.575, 2.822, 25.50 }, + { "1 1/4", 31.750, 2.822, 28.50 }, + { "1 3/8", 34.925, 3.175, 31.50 }, + { "1 1/2", 38.100, 3.175, 34.50 }, + { "1 5/8", 41.275, 3.175, 0.0 }, + { "1 3/4", 44.450, 3.629, 0.0 }, + { "2", 50.800, 3.629, 0.0 }, + { "2 1/4", 57.150, 4.233, 0.0 }, + { "2 1/2", 63.500, 4.233, 0.0 }, + { "2 3/4", 69.850, 4.233, 0.0 }, + { "3", 76.200, 5.080, 0.0 }, + { "3 1/4", 82.550, 5.080, 0.0 }, + { "3 1/2", 88.900, 5.644, 0.0 }, + { "3 3/4", 95.250, 5.644, 0.0 }, + { "4", 101.600, 5.644, 0.0 }, + { "4 1/4", 107.950, 6.350, 0.0 }, } - }; -const double Hole::metricHoleDiameters[36][4] = +const double Hole::metricHoleDiameters[51][4] = { /* ISO metric clearance hole diameters according to ISO 273 */ // {screw diameter, close, standard, coarse} - { 1.0, 1.1, 1.2, 1.3}, - { 1.2, 1.3, 1.4, 1.5}, - { 1.4, 1.5, 1.6, 1.8}, - { 1.6, 1.7, 1.8, 2.0}, - { 1.8, 2.0, 2.1, 2.2}, - { 2.0, 2.2, 2.4, 2.6}, - { 2.5, 2.7, 2.9, 3.1}, - { 3.0, 3.2, 3.4, 3.6}, - { 3.5, 3.7, 3.9, 4.2}, - { 4.0, 4.3, 4.5, 4.8}, - { 4.5, 4.8, 5.0, 5.3}, - { 5.0, 5.3, 5.5, 5.8}, - { 6.0, 6.4, 6.6, 7.0}, - { 7.0, 7.4, 7.6, 8.0}, - { 8.0, 8.4, 9.0, 10.0}, + { 1.0, 1.1, 1.2, 1.3}, + { 1.2, 1.3, 1.4, 1.5}, + { 1.4, 1.5, 1.6, 1.8}, + { 1.6, 1.7, 1.8, 2.0}, + { 1.8, 2.0, 2.1, 2.2}, + { 2.0, 2.2, 2.4, 2.6}, + { 2.5, 2.7, 2.9, 3.1}, + { 3.0, 3.2, 3.4, 3.6}, + { 3.5, 3.7, 3.9, 4.2}, + { 4.0, 4.3, 4.5, 4.8}, + { 4.5, 4.8, 5.0, 5.3}, + { 5.0, 5.3, 5.5, 5.8}, + { 6.0, 6.4, 6.6, 7.0}, + { 7.0, 7.4, 7.6, 8.0}, + { 8.0, 8.4, 9.0, 10.0}, // 9.0 undefined - { 10.0, 10.5, 11.0, 12.0}, + { 10.0, 10.5, 11.0, 12.0}, // 11.0 undefined - { 12.0, 13.0, 13.5, 14.5}, - { 14.0, 15.0, 15.5, 16.5}, - { 16.0, 17.0, 17.5, 18.5}, - { 18.0, 19.0, 20.0, 21.0}, - { 20.0, 21.0, 22.0, 24.0}, - { 22.0, 23.0, 24.0, 26.0}, - { 24.0, 25.0, 26.0, 28.0}, - { 27.0, 28.0, 30.0, 32.0}, - { 30.0, 31.0, 33.0, 35.0}, - { 33.0, 34.0, 36.0, 38.0}, - { 36.0, 37.0, 39.0, 42.0}, - { 39.0, 40.0, 42.0, 45.0}, - { 42.0, 43.0, 45.0, 48.0}, - { 45.0, 46.0, 48.0, 52.0}, - { 48.0, 50.0, 52.0, 56.0}, - { 52.0, 54.0, 56.0, 62.0}, - { 56.0, 58.0, 62.0, 66.0}, - { 60.0, 62.0, 66.0, 70.0}, - { 64.0, 66.0, 70.0, 74.0}, - { 68.0, 70.0, 77.0, 78.0} + { 12.0, 13.0, 13.5, 14.5}, + { 14.0, 15.0, 15.5, 16.5}, + { 16.0, 17.0, 17.5, 18.5}, + { 18.0, 19.0, 20.0, 21.0}, + { 20.0, 21.0, 22.0, 24.0}, + { 22.0, 23.0, 24.0, 26.0}, + { 24.0, 25.0, 26.0, 28.0}, + { 27.0, 28.0, 30.0, 32.0}, + { 30.0, 31.0, 33.0, 35.0}, + { 33.0, 34.0, 36.0, 38.0}, + { 36.0, 37.0, 39.0, 42.0}, + { 39.0, 40.0, 42.0, 45.0}, + { 42.0, 43.0, 45.0, 48.0}, + { 45.0, 46.0, 48.0, 52.0}, + { 48.0, 50.0, 52.0, 56.0}, + { 52.0, 54.0, 56.0, 62.0}, + { 56.0, 58.0, 62.0, 66.0}, + { 60.0, 62.0, 66.0, 70.0}, + { 64.0, 66.0, 70.0, 74.0}, + { 68.0, 70.0, 74.0, 78.0}, + { 72.0, 74.0, 78.0, 82.0}, + { 76.0, 78.0, 82.0, 86.0}, + { 80.0, 82.0, 86.0, 91.0}, + { 85.0, 87.0, 91.0, 96.0}, + { 90.0, 93.0, 96.0, 101.0}, + { 95.0, 98.0, 101.0, 107.0}, + { 100.0, 104.0, 107.0, 112.0}, + { 105.0, 109.0, 112.0, 117.0}, + { 110.0, 114.0, 117.0, 122.0}, + { 115.0, 119.0, 122.0, 127.0}, + { 120.0, 124.0, 127.0, 132.0}, + { 125.0, 129.0, 132.0, 137.0}, + { 130.0, 134.0, 137.0, 144.0}, + { 140.0, 144.0, 147.0, 155.0}, + { 150.0, 155.0, 158.0, 165.0} }; const Hole::UTSClearanceDefinition Hole::UTSHoleDiameters[22] = @@ -637,6 +774,42 @@ const char* Hole::ThreadSize_UNEF_Enums[] = { "#12", "1/4", "5/16", "3/8", "7/1 "1 5/8", "1 11/16", nullptr }; const char* Hole::ThreadClass_UNEF_Enums[] = { "1B", "2B", "3B", nullptr }; +/* NPT */ +const char* Hole::HoleCutType_NPT_Enums[] = { "None", "Counterbore", "Countersink", "Counterdrill", nullptr}; +const char* Hole::ThreadSize_NPT_Enums[] = { "1/16", "1/8", "1/4", "3/8", "1/2", "3/4", + "1", "1 1/4", "1 1/2", + "2", "2 1/2", + "3", "3 1/2", + "4", "5", "6", "8", "10", "12", nullptr }; + +/* BSP */ +const char* Hole::HoleCutType_BSP_Enums[] = { "None", "Counterbore", "Countersink", "Counterdrill", nullptr}; +const char* Hole::ThreadSize_BSP_Enums[] = { "1/16", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", + "1", "1 1/8", "1 1/4", "1 3/8", "1 1/2", "1 3/4", + "2", "2 1/4", "2 1/2", "2 3/4", + "3", "3 1/2", "4", "4 1/2", + "5", "5 1/2", "6", nullptr }; + +/* BSW */ +const char* Hole::HoleCutType_BSW_Enums[] = { "None", "Counterbore", "Countersink", "Counterdrill", nullptr}; +const char* Hole::ThreadSize_BSW_Enums[] = { "1/8", "3/16", "1/4", "5/16", "3/8", "7/16", + "1/2", "9/16", "5/8", "11/16", "3/4", "7/8", + "1", "1 1/8", "1 1/4", "1 1/2", "1 3/4", + "2", "2 1/4", "2 1/2", "2 3/4", + "3", "3 1/4", "3 1/2", "3 3/4", + "4", "4 1/2", "5", "5 1/2", "6", nullptr }; +const char* Hole::ThreadClass_BSW_Enums[] = { "Medium", "Normal", nullptr }; + +/* BSF */ +const char* Hole::HoleCutType_BSF_Enums[] = { "None", "Counterbore", "Countersink", "Counterdrill", nullptr}; +const char* Hole::ThreadSize_BSF_Enums[] = { "3/16", "7/32", "1/4", "9/32", "5/16", "3/8", "7/16", + "1/2", "9/16", "5/8", "11/16", "3/4", "7/8", + "1", "1 1/8", "1 1/4", "1 3/8", "1 1/2", "1 5/8", "1 3/4", + "2", "2 1/4", "2 1/2", "2 3/4", + "3", "3 1/4", "3 1/2", "3 3/4", + "4", "4 1/4", nullptr }; +const char* Hole::ThreadClass_BSF_Enums[] = { "Medium", "Normal", nullptr }; + const char* Hole::ThreadDirectionEnums[] = { "Right", "Left", nullptr}; PROPERTY_SOURCE(PartDesign::Hole, PartDesign::ProfileBased) @@ -911,8 +1084,7 @@ void Hole::updateHoleCutParams() } } - else { // we have an UTS profile or none - + else { // we don't update for these settings but we need to set a value for new holes // furthermore we must assure the hole cut diameter is not <= the hole diameter // if we have a cut but the values are zero, we assume it is a new hole @@ -930,17 +1102,10 @@ void Hole::updateHoleCutParams() else if (holeCutTypeStr == "Countersink" || holeCutTypeStr == "Counterdrill") { if (HoleCutDiameter.getValue() == 0.0 || HoleCutDiameter.getValue() <= diameterVal) { HoleCutDiameter.setValue(diameterVal * 1.7); - // 82 degrees for UTS, 90 otherwise - if (threadTypeStr != "None") - HoleCutCountersinkAngle.setValue(82.0); - else - HoleCutCountersinkAngle.setValue(90.0); + HoleCutCountersinkAngle.setValue(getCountersinkAngle()); } if (HoleCutCountersinkAngle.getValue() == 0.0) { - if (threadTypeStr != "None") - HoleCutCountersinkAngle.setValue(82.0); - else - HoleCutCountersinkAngle.setValue(90.0); + HoleCutCountersinkAngle.setValue(getCountersinkAngle()); } if (HoleCutDepth.getValue() == 0.0 && holeCutTypeStr == "Counterdrill") { HoleCutDepth.setValue(1.0); @@ -952,6 +1117,23 @@ void Hole::updateHoleCutParams() } } +double Hole::getCountersinkAngle() const +{ + std::string threadTypeStr = ThreadType.getValueAsString(); + if ( + threadTypeStr == "BSW" + || threadTypeStr == "BSF" + ) + return 100.0; + if ( + threadTypeStr == "UNC" + || threadTypeStr == "UNF" + || threadTypeStr == "UNEF" + ) + return 82.0; + return 90.0; +} + double Hole::getThreadClassClearance() const { double pitch = getThreadPitch(); @@ -1093,11 +1275,22 @@ std::optional Hole::determineDiameter() const // use normed diameters if possible std::string threadTypeStr = ThreadType.getValueAsString(); - if (threadTypeStr == "ISOMetricProfile" || threadTypeStr == "UNC" - || threadTypeStr == "UNF" || threadTypeStr == "UNEF") { - diameter = threadDescription[threadType][threadSize].CoreHole + clearance; + if (threadDescription[threadType][threadSize].TapDrill > 0) { + diameter = threadDescription[threadType][threadSize].TapDrill + clearance; + } // if nothing is available, we must calculate + else if ( + threadTypeStr == "BSP" + || threadTypeStr == "BSW" + || threadTypeStr == "BSF" + ) { + double thread = 2 * (0.640327 * pitch); + // truncation is allowed by ISO-228 and BS 84 + diameter = diameter - thread * 0.75 + clearance; + } + else if (threadTypeStr == "NPT") { + double thread = 2 * (0.8 * pitch); + diameter = diameter - thread * 0.75 + clearance; } - // if nothing available, we must calculate else { // this fits exactly the definition for ISO metric fine diameter = diameter - pitch + clearance; @@ -1241,6 +1434,12 @@ void Hole::updateDiameterParam() Diameter.setValue(opt.value()); } +double Hole::getThreadProfileAngle() +{ + // Both ISO 7-1 and ASME B1.20.1 define the same angle + return 90 - 1.79; +} + void Hole::onChanged(const App::Property* prop) { if (prop == &ThreadType) { @@ -1358,6 +1557,62 @@ void Hole::onChanged(const App::Property* prop) ThreadDepthType.setReadOnly(!Threaded.getValue()); ThreadDepth.setReadOnly(!Threaded.getValue()); } + else if (type == "BSP") { + ThreadSize.setEnums(ThreadSize_BSP_Enums); + ThreadClass.setEnums(ThreadClass_None_Enums); + HoleCutType.setEnums(HoleCutType_BSP_Enums); + Threaded.setReadOnly(false); + ThreadSize.setReadOnly(false); + ThreadFit.setReadOnly(Threaded.getValue()); + Diameter.setReadOnly(true); + ModelThread.setReadOnly(!Threaded.getValue()); + UseCustomThreadClearance.setReadOnly(!Threaded.getValue() || !ModelThread.getValue()); + CustomThreadClearance.setReadOnly(!Threaded.getValue() || !ModelThread.getValue() || !UseCustomThreadClearance.getValue()); + ThreadDepthType.setReadOnly(!Threaded.getValue()); + ThreadDepth.setReadOnly(!Threaded.getValue()); + } + else if (type == "NPT") { + ThreadSize.setEnums(ThreadSize_NPT_Enums); + ThreadClass.setEnums(ThreadClass_None_Enums); + HoleCutType.setEnums(HoleCutType_NPT_Enums); + Threaded.setReadOnly(false); + ThreadSize.setReadOnly(false); + ThreadFit.setReadOnly(Threaded.getValue()); + Diameter.setReadOnly(true); + ModelThread.setReadOnly(!Threaded.getValue()); + UseCustomThreadClearance.setReadOnly(!Threaded.getValue() || !ModelThread.getValue()); + CustomThreadClearance.setReadOnly(!Threaded.getValue() || !ModelThread.getValue() || !UseCustomThreadClearance.getValue()); + ThreadDepthType.setReadOnly(!Threaded.getValue()); + ThreadDepth.setReadOnly(!Threaded.getValue()); + } + else if (type == "BSW") { + ThreadSize.setEnums(ThreadSize_BSW_Enums); + ThreadClass.setEnums(ThreadClass_BSW_Enums); + HoleCutType.setEnums(HoleCutType_BSW_Enums); + Threaded.setReadOnly(false); + ThreadSize.setReadOnly(false); + ThreadFit.setReadOnly(Threaded.getValue()); + Diameter.setReadOnly(true); + ModelThread.setReadOnly(!Threaded.getValue()); + UseCustomThreadClearance.setReadOnly(!Threaded.getValue() || !ModelThread.getValue()); + CustomThreadClearance.setReadOnly(!Threaded.getValue() || !ModelThread.getValue() || !UseCustomThreadClearance.getValue()); + ThreadDepthType.setReadOnly(!Threaded.getValue()); + ThreadDepth.setReadOnly(!Threaded.getValue()); + } + else if (type == "BSF") { + ThreadSize.setEnums(ThreadSize_BSF_Enums); + ThreadClass.setEnums(ThreadClass_BSF_Enums); + HoleCutType.setEnums(HoleCutType_BSF_Enums); + Threaded.setReadOnly(false); + ThreadSize.setReadOnly(false); + ThreadFit.setReadOnly(Threaded.getValue()); + Diameter.setReadOnly(true); + ModelThread.setReadOnly(!Threaded.getValue()); + UseCustomThreadClearance.setReadOnly(!Threaded.getValue() || !ModelThread.getValue()); + CustomThreadClearance.setReadOnly(!Threaded.getValue() || !ModelThread.getValue() || !UseCustomThreadClearance.getValue()); + ThreadDepthType.setReadOnly(!Threaded.getValue()); + ThreadDepth.setReadOnly(!Threaded.getValue()); + } if (holeCutTypeStr == "None") { HoleCutCustomValues.setReadOnly(true); @@ -1417,6 +1672,8 @@ void Hole::onChanged(const App::Property* prop) CustomThreadClearance.setReadOnly(!UseCustomThreadClearance.getValue()); ThreadDepthType.setReadOnly(false); ThreadDepth.setReadOnly(std::string(ThreadDepthType.getValueAsString()) != "Dimension"); + if (Tapered.getValue() && TaperedAngle.getValue() == 90) + TaperedAngle.setValue(getThreadProfileAngle()); } else { ThreadClass.setReadOnly(true); @@ -1451,11 +1708,15 @@ void Hole::onChanged(const App::Property* prop) } } else if (prop == &Tapered) { - if (Tapered.getValue()) + if (Tapered.getValue()) { TaperedAngle.setReadOnly(false); - else + if (Threaded.getValue() && TaperedAngle.getValue() == 90) + TaperedAngle.setValue(getThreadProfileAngle()); + } + else { + TaperedAngle.setValue(90); TaperedAngle.setReadOnly(true); - + } } else if (prop == &ThreadSize) { updateDiameterParam(); @@ -2085,34 +2346,90 @@ TopoDS_Shape Hole::makeThread(const gp_Vec& xDir, const gp_Vec& zDir, double len // Nomenclature and formulae according to Figure 1 of ISO 68-1 // this is the same for all metric and UTS threads as stated here: // https://en.wikipedia.org/wiki/File:ISO_and_UTS_Thread_Dimensions.svg - // Note that in the ISO standard, Dmaj is called D, which has been followed here. - double Diam = threadDescription[threadType][threadSize].diameter; // major diameter + // Rmaj is half of the major diameter + double Rmaj = threadDescription[threadType][threadSize].diameter / 2; double Pitch = getThreadPitch(); - double H = sqrt(3) / 2 * Pitch; // height of fundamental triangle double clearance; // clearance to be added on the diameter if (UseCustomThreadClearance.getValue()) - clearance = CustomThreadClearance.getValue(); + clearance = CustomThreadClearance.getValue() / 2; else - clearance = getThreadClassClearance(); - - // construct the cross section going counter-clockwise - // for graphical explanation of geometrical construction of p1-p6 see: - // https://forum.freecad.org/viewtopic.php?f=19&t=54284#p466570 - gp_Pnt p1 = toPnt((Diam / 2 - 5 * H / 8 + clearance / 2) * xDir + Pitch / 8 * zDir); - gp_Pnt p2 = toPnt((Diam / 2 + clearance / 2) * xDir + 7 * Pitch / 16 * zDir); - gp_Pnt p3 = toPnt((Diam / 2 + clearance / 2) * xDir + 9 * Pitch / 16 * zDir); - gp_Pnt p4 = toPnt((Diam / 2 - 5 * H / 8 + clearance / 2) * xDir + 7 * Pitch / 8 * zDir); - gp_Pnt p5 = toPnt(0.9 * (Diam / 2 - 5 * H / 8) * xDir + 7 * Pitch / 8 * zDir); - gp_Pnt p6 = toPnt(0.9 * (Diam / 2 - 5 * H / 8) * xDir + Pitch / 8 * zDir); + clearance = getThreadClassClearance() / 2; + double RmajC = Rmaj + clearance; + double marginZ = 0.001; BRepBuilderAPI_MakeWire mkThreadWire; - mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p1, p2).Edge()); - mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p2, p3).Edge()); - mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p3, p4).Edge()); - mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p4, p5).Edge()); - mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p5, p6).Edge()); - mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p6, p1).Edge()); + double H; + std::string threadTypeStr = ThreadType.getValueAsString(); + if (threadTypeStr == "BSP" || threadTypeStr == "BSW" || threadTypeStr == "BSF") { + H = 0.960491 * Pitch; // Height of Sharp V + double radius = 0.137329 * Pitch; // radius of the crest + // construct the cross section going counter-clockwise + // -------------- + // P | p4 + // 5/8P | p3 + // | crest + // 3/8P | p2 + // 0 | p1 + // -------------- + // | base-sharpV Rmaj H + + // the little adjustment of p1 and p4 is here to prevent coincidencies + double marginX = std::tan(62.5 * M_PI / 180.0) * marginZ; + + gp_Pnt p1 = toPnt( + (RmajC - 5 * H / 6 + marginX) * xDir + + marginZ * zDir + ); + gp_Pnt p4 = toPnt( + (RmajC - 5 * H / 6 + marginX) * xDir + + (Pitch - marginZ) * zDir + ); + + // Calculate positions for p2 and p3 + double p23x = RmajC - radius * 0.58284013094; + + gp_Pnt p2 = toPnt(p23x * xDir + 3 * Pitch / 8 * zDir); + gp_Pnt p3 = toPnt(p23x * xDir + 5 * Pitch / 8 * zDir); + gp_Pnt crest = toPnt((RmajC) * xDir + Pitch / 2 * zDir); + + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p1, p2).Edge()); + Handle(Geom_TrimmedCurve) arc1 = GC_MakeArcOfCircle(p2, crest, p3).Value(); + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(arc1).Edge()); + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p3, p4).Edge()); + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p4, p1).Edge()); + } else { + H = sqrt(3) / 2 * Pitch; // height of fundamental triangle + double h = 7 * H / 8; // distance from Rmaj to the base + // construct the cross section going counter-clockwise + // pitch + // -------------- + // P | p4 + // 9/16P | p3 + // 7/16P | p2 + // 0 | p1 + // -------------- + // | base-sharpV Rmaj + + // the little adjustment of p1 and p4 is here to prevent coincidencies + double marginX = std::tan(60.0 * M_PI / 180.0) * marginZ; + gp_Pnt p1 = toPnt( + (RmajC - h + marginX) * xDir + + marginZ * zDir + ); + gp_Pnt p2 = toPnt((RmajC) * xDir + 7 * Pitch / 16 * zDir); + gp_Pnt p3 = toPnt((RmajC) * xDir + 9 * Pitch / 16 * zDir); + gp_Pnt p4 = toPnt( + (RmajC - h + marginX) * xDir + + (Pitch - marginZ) * zDir + ); + + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p1, p2).Edge()); + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p2, p3).Edge()); + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p3, p4).Edge()); + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p4, p1).Edge()); + } + mkThreadWire.Build(); TopoDS_Wire threadWire = mkThreadWire.Wire(); @@ -2147,7 +2464,9 @@ TopoDS_Shape Hole::makeThread(const gp_Vec& xDir, const gp_Vec& zDir, double len helixLength = holeDepth + Pitch / 8; } } - TopoDS_Shape helix = TopoShape().makeLongHelix(Pitch, helixLength, Diam / 2, 0.0, leftHanded); + double helixAngle = + Tapered.getValue() ? TaperedAngle.getValue() - 90 : 0.0; + TopoDS_Shape helix = TopoShape().makeLongHelix(Pitch, helixLength, Rmaj, helixAngle, leftHanded); gp_Pnt origo(0.0, 0.0, 0.0); gp_Dir dir_axis1(0.0, 0.0, 1.0); // pointing along the helix axis, as created. diff --git a/src/Mod/PartDesign/App/FeatureHole.h b/src/Mod/PartDesign/App/FeatureHole.h index 662dde2b6c..b239f44e1b 100644 --- a/src/Mod/PartDesign/App/FeatureHole.h +++ b/src/Mod/PartDesign/App/FeatureHole.h @@ -90,11 +90,11 @@ public: const char * designation; double diameter; double pitch; - double CoreHole; + double TapDrill; }; static const ThreadDescription threadDescription[][171]; - static const double metricHoleDiameters[36][4]; + static const double metricHoleDiameters[51][4]; using UTSClearanceDefinition = struct { std::string designation; @@ -152,6 +152,24 @@ private: static const char* ThreadSize_UNEF_Enums[]; static const char* ThreadClass_UNEF_Enums[]; + /* NPT profile */ + static const char* HoleCutType_NPT_Enums[]; + static const char* ThreadSize_NPT_Enums[]; + + /* BSP profile */ + static const char* HoleCutType_BSP_Enums[]; + static const char* ThreadSize_BSP_Enums[]; + + /* BSW profile */ + static const char* HoleCutType_BSW_Enums[]; + static const char* ThreadSize_BSW_Enums[]; + static const char* ThreadClass_BSW_Enums[]; + + /* BSF profile */ + static const char* HoleCutType_BSF_Enums[]; + static const char* ThreadSize_BSF_Enums[]; + static const char* ThreadClass_BSF_Enums[]; + static const double ThreadRunout[ThreadRunout_size][2]; /* Counter-xxx */ @@ -218,9 +236,11 @@ private: void updateThreadDepthParam(); void readCutDefinitions(); + double getCountersinkAngle() const; double getThreadClassClearance() const; double getThreadRunout(int mode = 1) const; double getThreadPitch() const; + double getThreadProfileAngle(); void rotateToNormal(const gp_Dir& helixAxis, const gp_Dir& normalAxis, TopoDS_Shape& helixShape) const; gp_Vec computePerpendicular(const gp_Vec&) const; TopoDS_Shape makeThread(const gp_Vec&, const gp_Vec&, double); diff --git a/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp b/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp index 0173d7cdc3..5bca81cd1b 100644 --- a/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp @@ -66,6 +66,10 @@ TaskHoleParameters::TaskHoleParameters(ViewProviderHole* HoleView, QWidget* pare ui->ThreadType->addItem(tr("UTS coarse profile"), QByteArray("UTS")); ui->ThreadType->addItem(tr("UTS fine profile"), QByteArray("UTS")); ui->ThreadType->addItem(tr("UTS extra fine profile"), QByteArray("UTS")); + ui->ThreadType->addItem(tr("ANSI pipe profile"), QByteArray("NPT")); + ui->ThreadType->addItem(tr("BSP pipe profile"), QByteArray("BSP")); + ui->ThreadType->addItem(tr("BSW whitworth profile"), QByteArray("BSW")); + ui->ThreadType->addItem(tr("BSF whitworth fine profile"), QByteArray("BSF")); // read values from the hole properties auto pcHole = getObject(); diff --git a/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py b/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py index 0e92ad22ff..cdb8d6b1c1 100644 --- a/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py +++ b/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py @@ -482,31 +482,25 @@ class TestSketcherSolver(unittest.TestCase): def testRemovedExternalGeometryReference(self): body = self.Doc.addObject("PartDesign::Body", "Body") - sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") + sketch = body.newObject("Sketcher::SketchObject", "Sketch") CreateRectangleSketch(sketch, (0, 0), (30, 30)) - pad = self.Doc.addObject("PartDesign::Pad", "Pad") + pad = body.newObject("PartDesign::Pad", "Pad") pad.Profile = sketch - sketch1 = self.Doc.addObject("Sketcher::SketchObject", "Sketch1") + sketch1 = body.newObject("Sketcher::SketchObject", "Sketch1") CreateCircleSketch(sketch1, (15, 15), 0.25) - body.addObject(sketch) - body.addObject(pad) - body.addObject(sketch1) self.Doc.recompute() + self.assertEqual(len(pad.Shape.Edges), 12) + hole = self.Doc.addObject("PartDesign::Hole", "Hole") hole.Refine = True + hole.Reversed = True body.addObject(hole) hole.Profile = sketch1 - hole.Diameter = 0.250000 - hole.Depth = 10.000000 hole.DrillPointAngle = 118.000000 - hole.TaperedAngle = 90.000000 hole.Diameter = 6.000000 - hole.Depth = 8.000000 - hole.DrillPointAngle = 118.000000 hole.TaperedAngle = 90.000000 hole.Tapered = 0 hole.Depth = 8.000000 - hole.DrillPointAngle = 118.000000 hole.Threaded = 1 hole.ModelThread = 0 hole.ThreadDepthType = 0 @@ -518,24 +512,24 @@ class TestSketcherSolver(unittest.TestCase): hole.DepthType = 0 hole.DrillPoint = 1 hole.DrillForDepth = 0 - hole.Tapered = 0 self.Doc.recompute() - self.assertEqual(len(hole.Shape.Edges), 12) - hole.Threaded = True - hole.ModelThread = True - # body.addObject(hole) # Commented out as this is a duplicate - # (already performed after hole = self.Doc.addObject("PartDesign::Hole", "Hole")) - # - sketch2 = self.Doc.addObject("Sketcher::SketchObject", "Sketch2") + # 15 edges if it's passthrough-flat 17 if DrillPoint = 1 + self.assertEqual(len(hole.Shape.Edges), 17) + + hole.ModelThread = 1 + sketch2 = body.newObject("Sketcher::SketchObject", "Sketch2") CreateRectangleSketch(sketch2, (0, 0), (3, 3)) - body.addObject(sketch2) self.Doc.recompute() - sketch2.addExternal("Hole", "Edge29") # Edge29 will disappear when we stop modeling threads - self.assertEqual(len(hole.Shape.Edges), 32) - hole.ModelThread = False - hole.Refine = True + self.assertGreater(len(hole.Shape.Edges), 17) + # 77 edges for basic profile + self.assertEqual(len(hole.Shape.Edges), 77) + + # Edges in the thread should disappear when we stop modeling thread + sketch2.addExternal("Hole", "Edge29") + hole.ModelThread = 0 + hole.Refine = 1 self.Doc.recompute() - self.assertEqual(len(hole.Shape.Edges), 12) + self.assertEqual(len(hole.Shape.Edges), 17) self.assertEqual(len(sketch2.ExternalGeometry), 0) def testSaveLoadWithExternalGeometryReference(self):