diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp b/src/Mod/PartDesign/App/AppPartDesign.cpp index 0fb65d14d9..e9ef3b7f64 100644 --- a/src/Mod/PartDesign/App/AppPartDesign.cpp +++ b/src/Mod/PartDesign/App/AppPartDesign.cpp @@ -47,7 +47,7 @@ #include "FeaturePolarPattern.h" #include "FeatureScaled.h" #include "FeatureMultiTransform.h" -//#include "FeatureHole.h" +#include "FeatureHole.h" #include "DatumPlane.h" #include "DatumLine.h" #include "DatumPoint.h" @@ -96,7 +96,7 @@ PyMOD_INIT_FUNC(_PartDesign) PartDesign::PolarPattern ::init(); PartDesign::Scaled ::init(); PartDesign::MultiTransform ::init(); - //PartDesign::Hole ::init(); + PartDesign::Hole ::init(); PartDesign::Body ::init(); PartDesign::Pad ::init(); PartDesign::Pocket ::init(); diff --git a/src/Mod/PartDesign/App/FeatureHole.cpp b/src/Mod/PartDesign/App/FeatureHole.cpp index d761a76e19..e7b1ab1094 100644 --- a/src/Mod/PartDesign/App/FeatureHole.cpp +++ b/src/Mod/PartDesign/App/FeatureHole.cpp @@ -25,138 +25,1245 @@ #ifndef _PreComp_ # include # include +# include # include # include # include # include # include +# include # include # include +# include +# include +# include +# include # include -# include +# include +# include # include # include # include # include +# include # include +# include +# include #endif #include +#include +#include +#include +#include +#include #include "FeatureHole.h" - using namespace PartDesign; -const char* Hole::TypeEnums[] = {"Dimension","UpToLast","UpToFirst",NULL}; -const char* Hole::HoleTypeEnums[]= {"Simple","Counterbore","Countersunk",NULL}; -const char* Hole::ThreadEnums[] = {"None","Metric","MetricFine",NULL}; +const char* Hole::DepthTypeEnums[] = { "Dimension", "ThroughAll", /*, "UpToFirst", */ NULL }; +const char* Hole::ThreadTypeEnums[] = { "None", "ISOMetricProfile", "ISOMetricFineProfile", "UNC", "UNF", "UNEF", NULL}; +const char* Hole::ThreadFitEnums[] = { "Standard", "Close", NULL}; +const char* Hole::DrillPointEnums[] = { "Flat", "Angled", NULL}; + +/* "None" profile */ + +const char* Hole::HoleCutType_None_Enums[] = { "None", "Counterbore", "Countersink", NULL }; +const char* Hole::ThreadSize_None_Enums[] = { "None", NULL }; +const char* Hole::ThreadClass_None_Enums[] = { "None", NULL }; + +/* Sources: + http://www.engineeringtoolbox.com/metric-threads-d_777.html + http://www.metalmart.com/tools/miscellaneous-guides/standard-drill-size/ + +*/ + +const Hole::ThreadDescription Hole::threadDescription[][171] = +{ + /* None */ + { + { "---", 6.0, 0.0 }, + }, + + /* ISO metric coarse */ + { + { "M1.60", 1.60, 0.35 }, + { "M2.00", 2.00, 0.40 }, + { "M2.50", 2.50, 0.45 }, + { "M3", 3.00, 0.50 }, + { "M3.50", 3.50, 0.60 }, + { "M4", 4.00, 0.70 }, + { "M5", 5.00, 0.80 }, + { "M6", 6.00, 1.00 }, + { "M8", 8.00, 1.25 }, + { "M10", 10.00, 1.50 }, + { "M12", 12.00, 1.75 }, + { "M14", 14.00, 2.00 }, + { "M16", 16.00, 2.00 }, + { "M20", 20.00, 2.50 }, + { "M22", 22.00, 2.50 }, + { "M24", 24.00, 3.00 }, + { "M27", 27.00, 3.00 }, + { "M30", 30.00, 3.50 }, + { "M36", 36.00, 4.00 }, + { "M42", 42.00, 4.50 }, + { "M48", 48.00, 5.00 }, + { "M56", 56.00, 5.50 }, + { "M64", 64.00, 6.00 }, + { "M68", 68.00, 6.00 }, + }, + /* ISO metric fine */ + { + { "M1.0x0.2", 1.0, 0.20 }, + { "M1.1x0.2", 1.1, 0.20 }, + { "M1.2x0.2", 1.2, 0.20 }, + { "M1.4z0.2", 1.4, 0.20 }, + { "M1.6x0.2", 1.6, 0.20 }, + { "M1.8x0.2", 1.8, 0.20 }, + { "M2x0.25", 2.0, 0.25 }, + { "M2.2x0.25", 2.2, 0.25 }, + { "M2.5x0.35", 2.5, 0.35 }, + { "M3x0.35", 3.0, 0.35 }, + { "M3.5x0.35", 3.5, 0.35 }, + { "M4x0.5", 4.0, 0.50 }, + { "M4.5x0.5", 4.5, 0.50 }, + { "M5x0.5", 5.0, 0.50 }, + { "M5.5x0.5", 5.5, 0.50 }, + { "M6x0.75", 6.0, 0.75 }, + { "M7x0.75", 7.0, 0.75 }, + { "M8x0.75", 8.0, 0.75 }, + { "M8x1.0", 8.0, 1.00 }, + { "M9x0.75", 9.0, 0.75 }, + { "M9x1", 9.0, 1.00 }, + { "M10x0.75", 10.0, 0.75 }, + { "M10x1", 10.0, 1.00 }, + { "M10x1.25", 10.0, 1.25 }, + { "M11x0.75", 11.0, 0.75 }, + { "M11x1", 11.0, 1.00 }, + { "M12x1", 12.0, 1.00 }, + { "M12x1.25", 12.0, 1.25 }, + { "M12x1.5", 12.0, 1.50 }, + { "M14x1.0", 14.0, 1.00 }, + { "M14x1.25", 14.0, 1.25 }, + { "M14x1.5", 14.0, 1.50 }, + { "M15x1", 15.0, 1.00 }, + { "M15x1.5", 15.0, 1.50 }, + { "M16x1", 16.0, 1.00 }, + { "M16x1.5", 16.0, 1.50 }, + { "M17x1.0", 17.0, 1.00 }, + { "M17x1.5", 17.0, 1.50 }, + { "M18x1.0", 18.0, 1.00 }, + { "M18x1.5", 18.0, 1.50 }, + { "M18x2.0", 18.0, 2.00 }, + { "M20x1.0", 20.0, 1.00 }, + { "M20x1.5", 20.0, 1.50 }, + { "M20x2.0", 20.0, 2.00 }, + { "M22x1.0", 22.0, 1.00 }, + { "M22x1.5", 22.0, 1.50 }, + { "M22x2.0", 22.0, 2.00 }, + { "M24x1.0", 24.0, 1.00 }, + { "M24x1.5", 24.0, 1.50 }, + { "M24x2.0", 24.0, 2.00 }, + { "M25x1.0", 25.0, 1.00 }, + { "M25x1.5", 25.0, 1.50 }, + { "M25x2.0", 25.0, 2.00 }, + { "M27x1.0", 27.0, 1.00 }, + { "M27x1.5", 27.0, 1.50 }, + { "M27x2.0", 27.0, 2.00 }, + { "M28x1.0", 28.0, 1.00 }, + { "M28x1.5", 28.0, 1.50 }, + { "M28x2.0", 28.0, 2.00 }, + { "M30x1.0", 30.0, 1.00 }, + { "M30x1.5", 30.0, 1.50 }, + { "M30x2.0", 30.0, 2.00 }, + { "M30x3.0", 30.0, 3.00 }, + { "M32x1.5", 32.0, 1.50 }, + { "M32x2.0", 32.0, 2.00 }, + { "M33x1.5", 33.0, 1.50 }, + { "M33x2.0", 33.0, 2.00 }, + { "M33x3.0", 33.0, 3.00 }, + { "M35x1.5", 35.0, 1.50 }, + { "M35x2.0", 35.0, 2.00 }, + { "M36x1.5", 36.0, 1.50 }, + { "M36x2.0", 36.0, 2.00 }, + { "M36x3.0", 36.0, 3.00 }, + { "M39x1.5", 39.0, 1.50 }, + { "M39x2.0", 39.0, 2.00 }, + { "M39x3.0", 39.0, 3.00 }, + { "M40x1.5", 40.0, 1.50 }, + { "M40x2.0", 40.0, 2.00 }, + { "M40x3.0", 40.0, 3.00 }, + { "M42x1.5", 42.0, 1.50 }, + { "M42x2.0", 42.0, 2.00 }, + { "M42x3.0", 42.0, 3.00 }, + { "M42x4.0", 42.0, 4.00 }, + { "M45x1.5", 45.0, 1.50 }, + { "M45x2.0", 45.0, 2.00 }, + { "M45x3.0", 45.0, 3.00 }, + { "M45x4.0", 45.0, 4.00 }, + { "M48x1.5", 48.0, 1.50 }, + { "M48x2.0", 48.0, 2.00 }, + { "M48x3.0", 48.0, 3.00 }, + { "M48x4.0", 48.0, 4.00 }, + { "M50x1.5", 50.0, 1.50 }, + { "M50x2.0", 50.0, 2.00 }, + { "M50x3.0", 50.0, 3.00 }, + { "M52x1.5", 52.0, 1.50 }, + { "M52x2.0", 52.0, 2.00 }, + { "M52x3.0", 52.0, 3.00 }, + { "M52x4.0", 52.0, 4.00 }, + { "M55x1.5", 55.0, 1.50 }, + { "M55x2.0", 55.0, 2.00 }, + { "M55x3.0", 55.0, 3.00 }, + { "M55x4.0", 55.0, 4.00 }, + { "M56x1.5", 56.0, 1.50 }, + { "M56x2.0", 56.0, 2.00 }, + { "M56x3.0", 56.0, 3.00 }, + { "M56x4.0", 56.0, 4.00 }, + { "M58x1.5", 58.0, 1.50 }, + { "M58x2.0", 58.0, 2.00 }, + { "M58x3.0", 58.0, 3.00 }, + { "M58x4.0", 58.0, 4.00 }, + { "M60x1.5", 60.0, 1.50 }, + { "M60x2.0", 60.0, 2.00 }, + { "M60x3.0", 60.0, 3.00 }, + { "M60x4.0", 60.0, 4.00 }, + { "M62x1.5", 62.0, 1.50 }, + { "M62x2.0", 62.0, 2.00 }, + { "M62x3.0", 62.0, 3.00 }, + { "M62x4.0", 62.0, 4.00 }, + { "M64x1.5", 64.0, 1.50 }, + { "M64x2.0", 64.0, 2.00 }, + { "M64x3.0", 64.0, 3.00 }, + { "M64x4.0", 64.0, 4.00 }, + { "M65x1.5", 65.0, 1.50 }, + { "M65x2.0", 65.0, 2.00 }, + { "M65x3.0", 65.0, 3.00 }, + { "M65x4.0", 65.0, 4.00 }, + { "M68x1.5", 68.0, 1.50 }, + { "M68x2.0", 68.0, 2.00 }, + { "M68x3.0", 68.0, 3.00 }, + { "M68x4.0", 68.0, 4.00 }, + { "M70x1.5", 70.0, 1.50 }, + { "M70x2.0", 70.0, 2.00 }, + { "M70x3.0", 70.0, 3.00 }, + { "M70x4.0", 70.0, 4.00 }, + { "M70x6.0", 70.0, 6.00 }, + { "M72x1.5", 72.0, 1.50 }, + { "M72x2.0", 72.0, 2.00 }, + { "M72x3.0", 72.0, 3.00 }, + { "M72x4.0", 72.0, 4.00 }, + { "M72x6.0", 72.0, 6.00 }, + { "M75x1.5", 75.0, 1.50 }, + { "M75x2.0", 75.0, 2.00 }, + { "M75x3.0", 75.0, 3.00 }, + { "M75x4.0", 75.0, 4.00 }, + { "M75x6.0", 75.0, 6.00 }, + { "M76x1.5", 76.0, 1.50 }, + { "M76x2.0", 76.0, 2.00 }, + { "M76x3.0", 76.0, 3.00 }, + { "M76x4.0", 76.0, 4.00 }, + { "M76x6.0", 76.0, 6.00 }, + { "M80x1.5", 80.0, 1.50 }, + { "M80x2.0", 80.0, 2.00 }, + { "M80x3.0", 80.0, 3.00 }, + { "M80x4.0", 80.0, 4.00 }, + { "M80x6.0", 80.0, 6.00 }, + { "M85x2.0", 85.0, 2.00 }, + { "M85x3.0", 85.0, 3.00 }, + { "M85x4.0", 85.0, 4.00 }, + { "M85x6.0", 85.0, 6.00 }, + { "M90x2.0", 90.0, 2.00 }, + { "M90x3.0", 90.0, 3.00 }, + { "M90x4.0", 90.0, 4.00 }, + { "M90x6.0", 90.0, 6.00 }, + { "M95x2.0", 95.0, 2.00 }, + { "M95x3.0", 95.0, 3.00 }, + { "M95x4.0", 95.0, 4.00 }, + { "M95x6.0", 95.0, 6.00 }, + { "M100x2.0", 100.0, 2.00 }, + { "M100x3.0", 100.0, 3.00 }, + { "M100x4.0", 100.0, 4.00 }, + { "M100x6.0", 100.0, 6.00 } + }, + /* UNC */ + { + { "#1", 1.8542, 0.3969 }, + { "#2", 2.1844, 0.4536 }, + { "#3", 2.5146, 0.5292 }, + { "#4", 2.8448, 0.6350 }, + { "#5", 3.1750, 0.6350 }, + { "#6", 3.5052, 0.7938 }, + { "#8", 4.1656, 0.7938 }, + { "#10", 4.8260, 1.0583 }, + { "#12", 5.4864, 1.0583 }, + { "1/4", 6.3500, 1.2700 }, + { "5/16", 7.9375, 1.4111 }, + { "3/8", 9.5250, 1.5875 }, + { "7/16", 11.1125, 1.8143 }, + { "1/2", 12.7000, 1.9538 }, + { "9/16", 14.2875, 2.1167 }, + { "5/8", 15.8750, 2.3091 }, + { "3/4", 19.0500, 2.5400 }, + { "7/8", 22.2250, 2.8222 }, + { "1", 25.4000, 3.1750 }, + }, + /* UNF */ + { + { "#0", 1.5240, 0.3175 }, + { "#1", 1.8542, 0.3528 }, + { "#2", 2.1844, 0.3969 }, + { "#3", 2.5146, 0.4536 }, + { "#4", 2.8448, 0.5292 }, + { "#5", 3.1750, 0.5773 }, + { "#6", 3.5052, 0.6350 }, + { "#8", 4.1656, 0.7056 }, + { "#10", 4.8260, 0.7938 }, + { "#12", 5.4864, 0.9071 }, + { "1/4", 6.3500, 0.9071 }, + { "5/16", 7.9375, 1.0583 }, + { "3/8", 9.5250, 1.0583 }, + { "7/16", 11.1125, 1.2700 }, + { "1/2", 12.7000, 1.2700 }, + { "9/16", 14.2875, 1.4111 }, + { "5/8", 15.8750, 1.4111 }, + { "3/4", 19.0500, 1.5875 }, + { "7/8", 22.2250, 1.8143 }, + { "1", 25.4000, 2.1167 }, + } , + /* UNEF */ + { + { "#12", 5.4864, 0.7938 }, + { "1/4", 6.3500, 0.7938 }, + { "5/16", 7.9375, 0.7938 }, + { "3/8", 9.5250, 0.7938 }, + { "7/16", 11.1125, 0.9071 }, + { "1/2", 12.7000, 0.9071 }, + { "9/16", 14.2875, 1.0583 }, + { "5/8", 15.8750, 1.0583 }, + { "3/4", 19.0500, 1.2700 }, + { "7/8", 22.2250, 1.2700 }, + { "1", 25.4000, 1.2700 }, + } + +}; + +/* ISO coarse metric enums */ +const char* Hole::HoleCutType_ISOmetric_Enums[] = { "None", "Counterbore", "Countersink", "Cheesehead", "Countersink socket screw", "Cap screw", NULL}; +const char* Hole::ThreadSize_ISOmetric_Enums[] = { "M1.60", "M2", "M2.50", "M3", + "M3.50", "M4", "M5", "M6", + "M8", "M10", "M12", "M14", + "M16", "M20", "M22", "M24", + "M27", "M30", "M36", "M42", + "M48", "M56", "M64", "M68", NULL }; +const char* Hole::ThreadClass_ISOmetric_Enums[] = { "4G", "4H", "5G", "5H", "6G", "6H", "7G", "7H","8G", "8H", NULL }; + +const char* Hole::HoleCutType_ISOmetricfine_Enums[] = { "None", "Counterbore", "Countersink", "Cheesehead", "Countersink socket screw", "Cap screw", NULL}; +const char* Hole::ThreadSize_ISOmetricfine_Enums[] = { + "M1.0x0.2", "M1.1x0.2", "M1.2x0.2", "M1.4z0.2", + "M1.6x0.2", "M1.8x0.2", "M2x0.25", "M2.2x0.25", + "M2.5x0.35", "M3x0.35", "M3.5x0.35", + "M4x0.5", "M4.5x0.5", "M5x0.5", "M5.5x0.5", + "M6x0.75", "M7x0.75", "M8x0.75", "M8x1.0", + "M9x0.75", "M9x 1", "M10x0.75", "M10x1", + "M10x1.25", "M11x0.75", "M11x1", "M12x1", + "M12x1.25", "M12x1.5", "M14x1.0", "M14x1.25", + "M14x1.5", "M15x1", "M15x1.5", "M16x1", + "M16x1.5", "M17x1.0", "M17x1.5", "M18x1.0", + "M18x1.5", "M18x2.0", "M20x1.0", "M20x1.5", + "M20x2.0", "M22x1.0", "M22x1.5", "M22x2.0", + "M24x1.0", "M24x1.5", "M24x2.0", "M25x1.0", + "M25x1.5", "M25x2.0", "M27x1.0", "M27x1.5", + "M27x2.0", "M28x1.0", "M28x1.5", "M28x2.0", + "M30x1.0", "M30x1.5", "M30x2.0", "M30x3.0", + "M32x1.5", "M32x2.0", "M33x1.5", "M33x2.0", + "M33x3.0", "M35x1.5", "M35x2.0", "M36x1.5", + "M36x2.0", "M36x3.0", "M39x1.5", "M39x2.0", + "M39x3.0", "M40x1.5", "M40x2.0", "M40x3.0", + "M42x1.5", "M42x2.0", "M42x3.0", "M42x4.0", + "M45x1.5", "M45x2.0", "M45x3.0", "M45x4.0", + "M48x1.5", "M48x2.0", "M48x3.0", "M48x4.0", + "M50x1.5", "M50x2.0", "M50x3.0", "M52x1.5", + "M52x2.0", "M52x3.0", "M52x4.0", "M55x1.5", + "M55x2.0", "M55x3.0", "M55x4.0", "M56x1.5", + "M56x2.0", "M56x3.0", "M56x4.0", "M58x1.5", + "M58x2.0", "M58x3.0", "M58x4.0", "M60x1.5", + "M60x2.0", "M60x3.0", "M60x4.0", "M62x1.5", + "M62x2.0", "M62x3.0", "M62x4.0", "M64x1.5", + "M64x2.0", "M64x3.0", "M64x4.0", "M65x1.5", + "M65x2.0", "M65x3.0", "M65x4.0", "M68x1.5", + "M68x2.0", "M68x3.0", "M68x4.0", "M70x1.5", + "M70x2.0", "M70x3.0", "M70x4.0", "M70x6.0", + "M72x1.5", "M72x2.0", "M72x3.0", "M72x4.0", + "M72x6.0", "M75x1.5", "M75x2.0", "M75x3.0", + "M75x4.0", "M75x6.0", "M76x1.5", "M76x2.0", + "M76x3.0", "M76x4.0", "M76x6.0", "M80x1.5", + "M80x2.0", "M80x3.0", "M80x4.0", "M80x6.0", + "M85x2.0", "M85x3.0", "M85x4.0", "M85x6.0", + "M90x2.0", "M90x3.0", "M90x4.0", "M90x6.0", + "M95x2.0", "M95x3.0", "M95x4.0", "M95x6.0", + "M100x2.0", "M100x3.0", "M100x4.0", "M100x6.0", NULL }; +const char* Hole::ThreadClass_ISOmetricfine_Enums[] = { "4G", "4H", "5G", "5H", "6G", "6H", "7G", "7H","8G", "8H", NULL }; + +/* Details from https://en.wikipedia.org/wiki/Unified_Thread_Standard */ + +/* UTS coarse */ +const char* Hole::HoleCutType_UNC_Enums[] = { "None", "Counterbore", "Countersink", NULL}; +const char* Hole::ThreadSize_UNC_Enums[] = { "#1", "#2", "#3", "#4", "#5", "#6", + "#8", "#10", "#12", + "1/4", "5/16", "3/8", "7/16", "1/2", + "9/16", "5/8", "3/4", "7/8", "1", NULL }; +const char* Hole::ThreadClass_UNC_Enums[] = { "1B", "2B", "3B", NULL }; + +/* UTS fine */ +const char* Hole::HoleCutType_UNF_Enums[] = { "None", "Counterbore", "Countersink", NULL}; +const char* Hole::ThreadSize_UNF_Enums[] = { "#1", "#2", "#3", "#4", "#5", "#6", + "#8", "#10", "#12", + "1/4", "5/16", "3/8", "7/16", "1/2", + "9/16", "5/8", "3/4", "7/8", "1", NULL }; +const char* Hole::ThreadClass_UNF_Enums[] = { "1B", "2B", "3B", NULL }; + +/* UTS extrafine */ +const char* Hole::HoleCutType_UNEF_Enums[] = { "None", "Counterbore", "Countersink", NULL}; +const char* Hole::ThreadSize_UNEF_Enums[] = { "#12", "1/4", "5/16", "3/8", "7/16", "1/2", + "9/16", "5/8", "3/4", "7/8", "1", NULL }; +const char* Hole::ThreadClass_UNEF_Enums[] = { "1B", "2B", "3B", NULL }; + +const char* Hole::ThreadDirectionEnums[] = { "Right", "Left", NULL}; PROPERTY_SOURCE(PartDesign::Hole, PartDesign::ProfileBased) Hole::Hole() { addSubType = FeatureAddSub::Subtractive; + + ADD_PROPERTY_TYPE(Threaded, ((long)0), "Hole", App::Prop_None, "Threaded"); + + ADD_PROPERTY_TYPE(ModelActualThread, ((long)0), "Hole", App::Prop_None, "Model actual thread"); + ADD_PROPERTY_TYPE(ThreadPitch, ((long)0), "Hole", App::Prop_None, "Thread pitch"); + ADD_PROPERTY_TYPE(ThreadAngle, ((long)0), "Hole", App::Prop_None, "Thread angle"); + ADD_PROPERTY_TYPE(ThreadCutOffInner, ((long)0), "Hole", App::Prop_None, "Thread CutOff Inner"); + ADD_PROPERTY_TYPE(ThreadCutOffOuter, ((long)0), "Hole", App::Prop_None, "Thread CutOff Outer"); + + ADD_PROPERTY_TYPE(ThreadType, ((long)0), "Hole", App::Prop_None, "Thread type"); + ThreadType.setEnums(ThreadTypeEnums); - ADD_PROPERTY(Type,((long)0)); - Type.setEnums(TypeEnums); - ADD_PROPERTY(HoleType,((long)0)); - Type.setEnums(HoleTypeEnums); - ADD_PROPERTY(ThreadType,((long)0)); - Type.setEnums(ThreadEnums); - ADD_PROPERTY(Length,(100.0)); - ADD_PROPERTY(ThreadSize,(6.0)); + ADD_PROPERTY_TYPE(ThreadSize, ((long)0), "Hole", App::Prop_None, "Thread size"); + ThreadSize.setEnums(ThreadSize_None_Enums); + + ADD_PROPERTY_TYPE(ThreadClass, ((long)0), "Hole", App::Prop_None, "Thread class"); + ThreadClass.setEnums(ThreadClass_None_Enums); + + ADD_PROPERTY_TYPE(ThreadFit, ((long)0), "Hole", App::Prop_None, "Thread fit"); + ThreadFit.setEnums(ThreadFitEnums); + + ADD_PROPERTY_TYPE(Diameter, (6.0), "Hole", App::Prop_None, "Diameter"); + + ADD_PROPERTY_TYPE(ThreadDirection, ((long)0), "Hole", App::Prop_None, "Thread direction"); + ThreadDirection.setEnums(ThreadDirectionEnums); + + ADD_PROPERTY_TYPE(HoleCutType, ((long)0), "Hole", App::Prop_None, "Head cut type"); + HoleCutType.setEnums(HoleCutType_None_Enums); + + ADD_PROPERTY_TYPE(HoleCutDiameter, (0.0), "Hole", App::Prop_None, "Head cut diameter"); + + ADD_PROPERTY_TYPE(HoleCutDepth, (0.0), "Hole", App::Prop_None, "Head cut deth"); + + ADD_PROPERTY_TYPE(HoleCutCountersinkAngle, (90.0), "Hole", App::Prop_None, "Head cut countersink angle"); + + ADD_PROPERTY_TYPE(DepthType, ((long)0), "Hole", App::Prop_None, "Type"); + DepthType.setEnums(DepthTypeEnums); + + ADD_PROPERTY_TYPE(Depth, (25.0), "Hole", App::Prop_None, "Length"); + + ADD_PROPERTY_TYPE(DrillPoint, ((long)1), "Hole", App::Prop_None, "Drill point type"); + DrillPoint.setEnums(DrillPointEnums); + + ADD_PROPERTY_TYPE(DrillPointAngle, (118.0), "Hole", App::Prop_None, "Drill point angle"); + + ADD_PROPERTY_TYPE(Tapered, ((bool)false),"Hole", App::Prop_None, "Tapered"); + + ADD_PROPERTY_TYPE(TaperedAngle, (90.0), "Hole", App::Prop_None, "Tapered angle"); } -//short Hole::mustExecute() const -//{ -// if (Sketch.isTouched() || -// Length.isTouched()) -// return 1; -// return Subtractive::mustExecute(); -//} +void Hole::updateHoleCutParams() +{ + std::string threadType = ThreadType.getValueAsString(); + + if (threadType == "ISOMetricProfile" || threadType == "ISOMetricFineProfile") { + std::string holeCutType = HoleCutType.getValueAsString(); + double diameter = PartDesign::Hole::threadDescription[ThreadType.getValue()][ThreadSize.getValue()].diameter; + double f = 1.0; + double depth = 0; + + if (holeCutType == "Counterbore") { + f = 2.0; + depth = 0.6; + } + else if (holeCutType == "Countersink") { + f = 2.0; + depth = 0; + } + else if (holeCutType == "Cheesehead") { + f = 1.6; + depth = 0.6; + } + else if (holeCutType == "Countersink socket screw") { + f = 2.0; + depth = 0; + } + else if (holeCutType == "Cap screw") { + f = 1.5; + depth = 1.25; + } + HoleCutDiameter.setValue(diameter * f); + HoleCutDepth.setValue(diameter * depth); + } +} + +void Hole::updateDiameterParam() +{ + // Diameter parameter depends on Threaded, ThreadType, ThreadSize, and ThreadFit + + int threadType = ThreadType.getValue(); + int threadSize = ThreadSize.getValue(); + double diameter = threadDescription[threadType][threadSize].diameter; + double pitch = threadDescription[threadType][threadSize].pitch; + + if (threadType == 0) + return; + + if (Threaded.getValue()) { + if (std::string(ThreadType.getValueAsString()) != "None") { + double h = pitch * sqrt(3) / 2; + + // Basic profile for ISO and UTS threads + ThreadPitch.setValue(pitch); + ThreadAngle.setValue(60); + ThreadCutOffInner.setValue(h/8); + ThreadCutOffOuter.setValue(h/4); + } + + if (ModelActualThread.getValue()) { + pitch = ThreadPitch.getValue(); + } + + /* Use thread tap diameter, normall D - pitch */ + diameter = diameter - pitch; + } + else { + switch ( ThreadFit.getValue() ) { + case 0: /* standard */ + diameter = ( 5 * ( (int)( ( diameter * 110 ) / 5 ) ) ) / 100.0; + break; + case 1: /* close */ + diameter = ( 5 * ( (int)( ( diameter * 105 ) / 5 ) ) ) / 100.0; + break; + default: + assert( 0 ); + } + } + Diameter.setValue(diameter); +} + +void Hole::onChanged(const App::Property *prop) +{ + if (prop == &ThreadType) { + std::string type(ThreadType.getValueAsString()); + std::string holeCutType(HoleCutType.getValueAsString()); + + if (type == "None" ) { + ThreadSize.setEnums(ThreadSize_None_Enums); + ThreadClass.setEnums(ThreadClass_None_Enums); + HoleCutType.setEnums(HoleCutType_None_Enums); + Threaded.setReadOnly(true); + ThreadSize.setReadOnly(true); + ThreadFit.setReadOnly(true); + ThreadClass.setReadOnly(true); + Diameter.setReadOnly(false); + + if (holeCutType == "None") { + HoleCutDiameter.setReadOnly(true); + HoleCutDepth.setReadOnly(true); + HoleCutCountersinkAngle.setReadOnly(true); + } + else if (holeCutType == "Counterbore") { + HoleCutDiameter.setReadOnly(false); + HoleCutDepth.setReadOnly(false); + HoleCutCountersinkAngle.setReadOnly(true); + + } + else if (holeCutType == "Countersink") { + HoleCutDiameter.setReadOnly(false); + HoleCutDepth.setReadOnly(true); + HoleCutCountersinkAngle.setReadOnly(false); + } + Threaded.setValue(0); + } + else if ( type == "ISOMetricProfile" ) { + ThreadSize.setEnums(ThreadSize_ISOmetric_Enums); + ThreadClass.setEnums(ThreadClass_ISOmetric_Enums); + HoleCutType.setEnums(HoleCutType_ISOmetric_Enums); + Threaded.setReadOnly(false); + ThreadSize.setReadOnly(false); + ThreadFit.setReadOnly(false); + ThreadClass.setReadOnly(false); + Diameter.setReadOnly(true); + HoleCutDiameter.setReadOnly(true); + HoleCutDepth.setReadOnly(true); + HoleCutCountersinkAngle.setReadOnly(true); + } + else if ( type == "ISOMetricFineProfile" ) { + ThreadSize.setEnums(ThreadSize_ISOmetricfine_Enums); + ThreadClass.setEnums(ThreadClass_ISOmetricfine_Enums); + HoleCutType.setEnums(HoleCutType_ISOmetricfine_Enums); + Threaded.setReadOnly(false); + ThreadSize.setReadOnly(false); + ThreadFit.setReadOnly(false); + ThreadClass.setReadOnly(false); + Diameter.setReadOnly(true); + HoleCutDiameter.setReadOnly(true); + HoleCutDepth.setReadOnly(true); + HoleCutCountersinkAngle.setReadOnly(true); + } + else if ( type == "UNC" ) { + ThreadSize.setEnums(ThreadSize_UNC_Enums); + ThreadClass.setEnums(ThreadClass_UNC_Enums); + HoleCutType.setEnums(HoleCutType_UNC_Enums); + Threaded.setReadOnly(false); + ThreadSize.setReadOnly(false); + ThreadFit.setReadOnly(false); + ThreadClass.setReadOnly(false); + Diameter.setReadOnly(true); + + if (holeCutType == "None") { + HoleCutDiameter.setReadOnly(true); + HoleCutDepth.setReadOnly(true); + HoleCutCountersinkAngle.setReadOnly(true); + } + else if (holeCutType == "Counterbore") { + HoleCutDiameter.setReadOnly(false); + HoleCutDepth.setReadOnly(false); + HoleCutCountersinkAngle.setReadOnly(true); + + } + else if (holeCutType == "Countersink") { + HoleCutDiameter.setReadOnly(false); + HoleCutDepth.setReadOnly(true); + HoleCutCountersinkAngle.setReadOnly(false); + } + } + else if ( type == "UNF" ) { + ThreadSize.setEnums(ThreadSize_UNF_Enums); + ThreadClass.setEnums(ThreadClass_UNF_Enums); + HoleCutType.setEnums(HoleCutType_UNF_Enums); + Threaded.setReadOnly(false); + ThreadSize.setReadOnly(false); + ThreadFit.setReadOnly(false); + ThreadClass.setReadOnly(false); + Diameter.setReadOnly(true); + + if (holeCutType == "None") { + HoleCutDiameter.setReadOnly(true); + HoleCutDepth.setReadOnly(true); + HoleCutCountersinkAngle.setReadOnly(true); + } + else if (holeCutType == "Counterbore") { + HoleCutDiameter.setReadOnly(false); + HoleCutDepth.setReadOnly(false); + HoleCutCountersinkAngle.setReadOnly(true); + + } + else if (holeCutType == "Countersink") { + HoleCutDiameter.setReadOnly(false); + HoleCutDepth.setReadOnly(true); + HoleCutCountersinkAngle.setReadOnly(false); + } + } + else if ( type == "UNEF" ) { + ThreadSize.setEnums(ThreadSize_UNEF_Enums); + ThreadClass.setEnums(ThreadClass_UNEF_Enums); + HoleCutType.setEnums(HoleCutType_UNEF_Enums); + Threaded.setReadOnly(false); + ThreadSize.setReadOnly(false); + ThreadFit.setReadOnly(false); + ThreadClass.setReadOnly(false); + Diameter.setReadOnly(true); + + if (holeCutType == "None") { + HoleCutDiameter.setReadOnly(true); + HoleCutDepth.setReadOnly(true); + HoleCutCountersinkAngle.setReadOnly(true); + } + else if (holeCutType == "Counterbore") { + HoleCutDiameter.setReadOnly(false); + HoleCutDepth.setReadOnly(false); + HoleCutCountersinkAngle.setReadOnly(true); + + } + else if (holeCutType == "Countersink") { + HoleCutDiameter.setReadOnly(false); + HoleCutDepth.setReadOnly(true); + HoleCutCountersinkAngle.setReadOnly(false); + } + } + + if (type == "ISOMetricProfile" || type == "ISOMetricFineProfile") + HoleCutCountersinkAngle.setValue(90.0); + else if (type == "UNC" || type == "UNF" || type == "UNEF") + HoleCutCountersinkAngle.setValue(82.0); + + // Signal changes to these + ProfileBased::onChanged(&ThreadSize); + ProfileBased::onChanged(&ThreadClass); + ProfileBased::onChanged(&HoleCutType); + ProfileBased::onChanged(&Threaded); + + bool v = (type != "None") || !Threaded.getValue() || !ModelActualThread.getValue(); + ThreadPitch.setReadOnly(v); + ThreadAngle.setReadOnly(v); + ThreadCutOffInner.setReadOnly(v); + ThreadCutOffOuter.setReadOnly(v); + + // Diameter parameter depends on this + if (type != "None" ) + updateDiameterParam(); + } + else if (prop == &Threaded) { + std::string type(ThreadType.getValueAsString()); + + if (Threaded.getValue()) { + ThreadDirection.setReadOnly(false); + ThreadFit.setReadOnly(true); + ModelActualThread.setReadOnly(true); // For now set this one to read only + } + else { + ThreadDirection.setReadOnly(true); + if (type == "None") + ThreadFit.setReadOnly(true); + else + ThreadFit.setReadOnly(false); + ModelActualThread.setReadOnly(true); + } + + // Diameter parameter depends on this + updateDiameterParam(); + } + else if (prop == &ModelActualThread) { + bool v =(!ModelActualThread.getValue()) || + (Threaded.isReadOnly()) || + (std::string(ThreadType.getValueAsString()) != "None"); + + ThreadPitch.setReadOnly(v); + ThreadAngle.setReadOnly(v); + ThreadCutOffInner.setReadOnly(v); + ThreadCutOffOuter.setReadOnly(v); + } + else if (prop == &DrillPoint) { + if (DrillPoint.getValue() == 1) + DrillPointAngle.setReadOnly(false); + else + DrillPointAngle.setReadOnly(true); + } + else if (prop == &Tapered) { + if (Tapered.getValue()) + TaperedAngle.setReadOnly(false); + else + TaperedAngle.setReadOnly(true); + } + else if (prop == &ThreadSize) { + updateDiameterParam(); + updateHoleCutParams(); + } + else if (prop == &ThreadFit) { + updateDiameterParam(); + } + else if (prop == &HoleCutType) { + std::string threadType = ThreadType.getValueAsString(); + std::string holeCutType = HoleCutType.getValueAsString(); + bool holeCutEnable = ( threadType != "ISOMetricProfile" && + threadType !="ISOMetricFineProfile" && + (holeCutType != "None")); + + HoleCutDiameter.setReadOnly(!holeCutEnable); + + if (holeCutType == "Countersink" || holeCutType == "Countersink socket screw") + HoleCutDepth.setReadOnly(true); + else + HoleCutDepth.setReadOnly(!holeCutEnable); + + if (holeCutType != "Countersink" && holeCutType != "Countersink socket screw") + HoleCutCountersinkAngle.setReadOnly(true); + else + HoleCutCountersinkAngle.setReadOnly(!holeCutEnable); + + updateHoleCutParams(); + } + else if (prop == &DepthType) { + Depth.setReadOnly((std::string(DepthType.getValueAsString()) != "Dimension")); + } + ProfileBased::onChanged(prop); +} + +/** + * Compute 2D intersection between the lines (pa1, pa2) and (pb1, pb2). + * The lines are assumed to be crossing, and it is an error + * to specify parallel lines. + * + * Only the x and y coordinates are used to compute the 2D intersection. + * + */ + +static void computeIntersection(gp_Pnt pa1, gp_Pnt pa2, gp_Pnt pb1, gp_Pnt pb2, double & x, double & y) +{ + double vx1 = pa1.X() - pa2.X(); + double vy1 = pa1.Y() - pa2.Y(); + double vx2 = pb1.X() - pb2.X(); + double vy2 = pb1.Y() - pb2.Y(); + double x1 = pa1.X(); + double y1 = pa1.Y(); + double x2 = pb1.X(); + double y2 = pb1.Y(); + + /* Solve the system + x1 + t1 * vx1 = x2 + t2 * vx2 + y1 + t1 * vy1 = y2 + t2 * vy2 + + => + + [ vx1 -vx2 ] [ t1 ] = [ x2 - x1 ] + [ vy1 -vy2 ] [ t2 ] = [ y2 - y1 ] + + => + + [ t1 ] = f * [ -vy2 vx2 ] [ x2 - x1 ] + [ t2 ] = [ -vy1 vx1 ] [ y2 - y1 ] + + */ + + assert( ( ( vx1 * - vy2 ) - ( -vx2 * vy1 ) ) != 0 ); + + double f = 1 / ( ( vx1 * - vy2 ) - ( -vx2 * vy1 ) ); + + double t1 = -vy2 * f * ( x2 - x1 ) + vx2 * f * ( y2 - y1 ); + +#ifdef _DEBUG + double t2 = -vy1 * f * ( x2 - x1 ) + vx1 * f * ( y2 - y1 ); + + assert( ( x1 + t1 * vx1 ) - ( x2 + t2 * vx2 ) < 1e-6 ); + assert( ( y1 + t1 * vy1 ) - ( y2 + t2 * vy2 ) < 1e-6 ); +#endif + + x = x1 + t1 * vx1; + y = y1 + t1 * vy1; +} + +short Hole::mustExecute() const +{ + if ( ThreadType.isTouched() || + Threaded.isTouched() || + ModelActualThread.isTouched() || + ThreadPitch.isTouched() || + ThreadAngle.isTouched() || + ThreadCutOffInner.isTouched() || + ThreadCutOffOuter.isTouched() || + ThreadSize.isTouched() || + ThreadClass.isTouched() || + ThreadFit.isTouched() || + Diameter.isTouched() || + ThreadDirection.isTouched() || + HoleCutType.isTouched() || + HoleCutDiameter.isTouched() || + HoleCutDepth.isTouched() || + HoleCutCountersinkAngle.isTouched() || + DepthType.isTouched() || + Depth.isTouched() || + DrillPoint.isTouched() || + DrillPointAngle.isTouched() || + Tapered.isTouched() || + TaperedAngle.isTouched() ) + return 1; + return ProfileBased::mustExecute(); +} + +void Hole::Restore(Base::XMLReader &reader) +{ + ProfileBased::Restore(reader); + + updateProps(); +} + +void Hole::updateProps() +{ + onChanged(&Threaded); + onChanged(&ModelActualThread); + onChanged(&ThreadPitch); + onChanged(&ThreadAngle); + onChanged(&ThreadCutOffInner); + onChanged(&ThreadCutOffOuter); + onChanged(&ThreadType); + onChanged(&ThreadSize); + onChanged(&ThreadClass); + onChanged(&ThreadFit); + onChanged(&Diameter); + onChanged(&ThreadDirection); + onChanged(&HoleCutType); + onChanged(&HoleCutDiameter); + onChanged(&HoleCutDepth); + onChanged(&HoleCutCountersinkAngle); + onChanged(&DepthType); + onChanged(&Depth); + onChanged(&DrillPoint); + onChanged(&DrillPointAngle); + onChanged(&Tapered); + onChanged(&TaperedAngle); +} + +static gp_Pnt toPnt(gp_Vec dir) +{ + return gp_Pnt(dir.X(), dir.Y(), dir.Z()); +} App::DocumentObjectExecReturn *Hole::execute(void) { - //App::DocumentObject* link = Sketch.getValue(); - //if (!link) - // return new App::DocumentObjectExecReturn("No sketch linked"); - //if (!link->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) - // return new App::DocumentObjectExecReturn("Linked object is not a Sketch or Part2DObject"); - //TopoDS_Shape shape = static_cast(link)->Shape.getShape().getShape(); - //if (shape.IsNull()) - // return new App::DocumentObjectExecReturn("Linked shape object is empty"); + Part::Feature* profile = 0; + TopoDS_Shape profileshape; + try { + profile = getVerifiedObject(); + profileshape = getVerifiedFace(); + } catch (const Base::Exception& e) { + return new App::DocumentObjectExecReturn(e.what()); + } - //// this is a workaround for an obscure OCC bug which leads to empty tessellations - //// for some faces. Making an explicit copy of the linked shape seems to fix it. - //// The error almost happens when re-computing the shape but sometimes also for the - //// first time - //BRepBuilderAPI_Copy copy(shape); - //shape = copy.Shape(); - //if (shape.IsNull()) - // return new App::DocumentObjectExecReturn("Linked shape object is empty"); + // Find the base shape + TopoDS_Shape base; + try { + base = getBaseShape(); + } catch (const Base::Exception&) { + return new App::DocumentObjectExecReturn("No sketch support and no base shape: Please tell me where to remove the material of the hole!"); + } - //TopExp_Explorer ex; - //std::vector wires; - //for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) { - // wires.push_back(TopoDS::Wire(ex.Current())); - //} - //if (/*shape.ShapeType() != TopAbs_WIRE*/wires.empty()) // there can be several wires - // return new App::DocumentObjectExecReturn("Linked shape object is not a wire"); + try { + std::string method(DepthType.getValueAsString()); + double length = 0.0; - //// get the Sketch plane - //Base::Placement SketchPos = static_cast(link)->Placement.getValue(); - //Base::Rotation SketchOrientation = SketchPos.getRotation(); - //Base::Vector3d SketchVector(0,0,1); - //SketchOrientation.multVec(SketchVector,SketchVector); + this->positionByPrevious(); + TopLoc_Location invObjLoc = this->getLocation().Inverted(); - //// get the support of the Sketch if any - //App::DocumentObject* SupportLink = static_cast(link)->Support.getValue(); - //Part::Feature *SupportObject = 0; - //if (SupportLink && SupportLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - // SupportObject = static_cast(SupportLink); + base.Move(invObjLoc); - //if (!SupportObject) - // return new App::DocumentObjectExecReturn("No support in Sketch!"); + if (profileshape.IsNull()) + return new App::DocumentObjectExecReturn("Pocket: Creating a face from sketch failed"); + profileshape.Move(invObjLoc); - //TopoDS_Shape aFace = makeFace(wires); - //if (aFace.IsNull()) - // return new App::DocumentObjectExecReturn("Creating a face from sketch failed"); + /* Build the prototype hole */ - //// lengthen the vector - //SketchVector *= Length.getValue(); + // Get vector normal to profile + Base::Vector3d SketchVector = getProfileNormal(); - //// turn around for pockets - //SketchVector *= -1; + // Define this as zDir + gp_Vec zDir(SketchVector.x, SketchVector.y, SketchVector.z); + zDir.Transform(invObjLoc.Transformation()); - //// extrude the face to a solid - //gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z); - //BRepPrimAPI_MakePrism PrismMaker(aFace,vec,0,1); - //if (PrismMaker.IsDone()) { - // // if the sketch has a support fuse them to get one result object (PAD!) - // if (SupportObject) { - // // Set the subtractive shape property for later usage in e.g. pattern - // this->SubShape.setValue(getSolid(PrismMaker.Shape())); - // const TopoDS_Shape& support = SupportObject->Shape.getValue(); - // if (support.IsNull()) - // return new App::DocumentObjectExecReturn("Support shape is invalid"); - // TopExp_Explorer xp (support, TopAbs_SOLID); - // if (!xp.More()) - // return new App::DocumentObjectExecReturn("Support shape is not a solid"); - // // Let's call algorithm computing a fuse operation: - // BRepAlgoAPI_Cut mkCut(support, PrismMaker.Shape()); - // // Let's check if the fusion has been successful - // if (!mkCut.IsDone()) - // return new App::DocumentObjectExecReturn("Cut with support failed"); - // this->Shape.setValue(getSolid(mkCut.Shape())); - // } - // else{ - // return new App::DocumentObjectExecReturn("Cannot create a tool out of sketch with no support"); - // } - //} - //else - // return new App::DocumentObjectExecReturn("Could not extrude the sketch!"); + // Define xDir + gp_Vec xDir; - return App::DocumentObject::StdReturn; + /* Compute xDir normal to zDir */ + if (std::abs(zDir.Z() - zDir.X()) > Precision::Confusion()) + xDir = gp_Vec(zDir.Z(), 0, -zDir.X()); + else if (std::abs(zDir.Z() - zDir.Y()) > Precision::Confusion()) + xDir = gp_Vec(zDir.Y(), -zDir.X(), 0); + else + xDir = gp_Vec(0, -zDir.Z(), zDir.Y()); + + if ( method == "Dimension" ) + length = Depth.getValue(); + else if ( method == "UpToFirst" ) { + /* FIXME */ + } + else if ( method == "ThroughAll" ) { + // Use a large (10m), but finite length + length = 1e4; + } + else + return new App::DocumentObjectExecReturn("Hole: Unsupported length specification."); + + if (length <= 0) + return new App::DocumentObjectExecReturn("Hole: Invalid hole depth"); + + BRepBuilderAPI_MakeWire mkWire; + std::string holeCutType = HoleCutType.getValueAsString(); + bool isCountersink = (holeCutType == "Countersink" || holeCutType == "Countersink socket screw"); + bool isCounterbore = (holeCutType == "Counterbore" || holeCutType == "Cheesehead" || holeCutType == "Cap screw"); + double hasTaperedAngle = Tapered.getValue() ? Base::toRadians( TaperedAngle.getValue() ) : Base::toRadians(90.0); + double radiusBottom = Diameter.getValue() / 2.0 - length * cos( hasTaperedAngle ); + double radius = Diameter.getValue() / 2.0; + double holeCutRadius = HoleCutDiameter.getValue() / 2.0; + gp_Pnt firstPoint(0, 0, 0); + gp_Pnt lastPoint(0, 0, 0); + double length1 = 0; + + if ( hasTaperedAngle <= 0 || hasTaperedAngle > Base::toRadians( 180.0 ) ) + return new App::DocumentObjectExecReturn("Hole: Invalid taper angle."); + + if ( isCountersink ) { + double x, z; + double countersinkAngle = Base::toRadians( HoleCutCountersinkAngle.getValue() / 2.0 ); + + if ( countersinkAngle <= 0 || countersinkAngle > Base::toRadians( 180.0 ) ) + return new App::DocumentObjectExecReturn("Hole: Invalid countersink angle."); + + if (holeCutRadius < radius) + return new App::DocumentObjectExecReturn("Hole: Hole cut diameter too small."); + + // Top point + gp_Pnt newPoint = toPnt(holeCutRadius * xDir); + mkWire.Add( BRepBuilderAPI_MakeEdge(lastPoint, newPoint) ); + lastPoint = newPoint; + + computeIntersection(gp_Pnt( holeCutRadius, 0, 0 ), + gp_Pnt( holeCutRadius - sin( countersinkAngle ), -cos( countersinkAngle ), 0 ), + gp_Pnt( radius, 0, 0 ), + gp_Pnt( radiusBottom, -length, 0), x, z ); + if (-length > z) + return new App::DocumentObjectExecReturn("Hole: Invalid countersink."); + + length1 = z; + + newPoint = toPnt(x * xDir + z * zDir); + mkWire.Add( BRepBuilderAPI_MakeEdge( lastPoint, newPoint ) ); + lastPoint = newPoint; + } + else if ( isCounterbore ) { + double holeCutDepth = HoleCutDepth.getValue(); + double x, z; + + if (holeCutDepth <= 0) + return new App::DocumentObjectExecReturn("Hole: Hole cut depth must be greater than zero."); + + if (holeCutDepth > length) + return new App::DocumentObjectExecReturn("Hole: Hole cut depth must be less than hole depth."); + + if (holeCutRadius < radius) + return new App::DocumentObjectExecReturn("Hole: Hole cut diameter too small."); + + // Top point + gp_Pnt newPoint = toPnt(holeCutRadius * xDir); + mkWire.Add(BRepBuilderAPI_MakeEdge(lastPoint, newPoint)); + lastPoint = newPoint; + + // Bottom of counterbore + newPoint = toPnt(holeCutRadius * xDir -holeCutDepth * zDir); + mkWire.Add(BRepBuilderAPI_MakeEdge(lastPoint, newPoint)); + lastPoint = newPoint; + + // Compute intersection of tapered edge and line at bottom of counterbore hole + computeIntersection(gp_Pnt( 0, -holeCutDepth, 0 ), + gp_Pnt( holeCutRadius, -holeCutDepth, 0 ), + gp_Pnt( radius, 0, 0 ), + gp_Pnt( radiusBottom, length, 0 ), x, z ); + + length1 = z; + newPoint = toPnt(x * xDir + z * zDir); + mkWire.Add(BRepBuilderAPI_MakeEdge(lastPoint, newPoint)); + lastPoint = newPoint; + } + else { + gp_Pnt newPoint = toPnt(radius * xDir); + mkWire.Add(BRepBuilderAPI_MakeEdge(lastPoint, newPoint)); + lastPoint = newPoint; + length1 = 0; + } + + std::string drillPoint = DrillPoint.getValueAsString(); + if (drillPoint == "Flat") { + gp_Pnt newPoint = toPnt(radiusBottom * xDir + -length * zDir); + mkWire.Add(BRepBuilderAPI_MakeEdge(lastPoint, newPoint)); + lastPoint = newPoint; + + newPoint = toPnt(-length * zDir); + mkWire.Add( BRepBuilderAPI_MakeEdge( lastPoint, newPoint ) ); + lastPoint = newPoint; + } + else if (drillPoint == "Angled") { + double drillPointAngle = Base::toRadians( ( 180.0 - DrillPointAngle.getValue() ) / 2.0 ); + double x, z; + gp_Pnt newPoint; + + if ( drillPointAngle <= 0 || drillPointAngle > Base::toRadians( 180.0 ) ) + return new App::DocumentObjectExecReturn("Hole: Invalid drill point angle."); + + computeIntersection(gp_Pnt( 0, -length, 0 ), + gp_Pnt( cos( drillPointAngle ), -length + sin( drillPointAngle ), 0), + gp_Pnt(radius, 0, 0), + gp_Pnt(radiusBottom, -length, 0), x, z); + + if (z > 0 || z >= length1) + return new App::DocumentObjectExecReturn("Hole: Invalid drill point."); + + newPoint = toPnt(x * xDir + z * zDir); + mkWire.Add(BRepBuilderAPI_MakeEdge(lastPoint, newPoint)); + lastPoint = newPoint; + + newPoint = toPnt(-length * zDir); + mkWire.Add(BRepBuilderAPI_MakeEdge(lastPoint, newPoint)); + lastPoint = newPoint; + } + mkWire.Add( BRepBuilderAPI_MakeEdge(lastPoint, firstPoint) ); + + + TopoDS_Wire wire = mkWire.Wire(); + + TopoDS_Face face = BRepBuilderAPI_MakeFace(wire); + + double angle = Base::toRadians(360.0); + BRepPrimAPI_MakeRevol RevolMaker(face, gp_Ax1(firstPoint, zDir), angle); + + TopoDS_Shape protoHole; + if (RevolMaker.IsDone()) { + protoHole = RevolMaker.Shape(); + + if (protoHole.IsNull()) + return new App::DocumentObjectExecReturn("Hole: Resulting shape is empty"); + } + else + return new App::DocumentObjectExecReturn("Hole: Could not revolve sketch!"); + +#if 0 + // Make thread + + // This code is work in progress; making threas in OCC is not very easy, so + // this work is postponed until later + if (ModelActualThread.getValue()) { + BRepBuilderAPI_MakeWire mkThreadWire; + double z = 0; + double d_min = Diameter.getValue() + ThreadCutOffInner.getValue(); + double d_maj = Diameter.getValue() - ThreadCutOffInner.getValue(); + int i = 0; + + firstPoint = toPnt(xDir * d_min); + + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), firstPoint)); + while (z < length) { + double z1 = i * ThreadPitch.getValue() + ThreadPitch.getValue() * 0.1; + double z2 = i * ThreadPitch.getValue() + ThreadPitch.getValue() * 0.45; + double z3 = i * ThreadPitch.getValue() + ThreadPitch.getValue() * 0.55; + double z4 = i * ThreadPitch.getValue() + ThreadPitch.getValue() * 0.9; + + gp_Pnt p2 = toPnt(xDir * d_min - zDir * z1); + gp_Pnt p3 = toPnt(xDir * d_maj - zDir * z2); + gp_Pnt p4 = toPnt(xDir * d_maj - zDir * z3); + gp_Pnt p5 = toPnt(xDir * d_min - zDir * z4); + + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(firstPoint, p2)); + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p2, p3)); + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p3, p4)); + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(p4, p5)); + firstPoint = p5; + + ++i; + z += ThreadPitch.getValue(); + } + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(firstPoint, toPnt(-z * zDir))); + mkThreadWire.Add(BRepBuilderAPI_MakeEdge(toPnt(-z * zDir), gp_Pnt(0, 0, 0))); + + TopoDS_Wire threadWire = mkThreadWire.Wire(); + + TopoDS_Face threadFace = BRepBuilderAPI_MakeFace(threadWire); + + //TopoDS_Wire helix = TopoShape::makeHelix(ThreadPitch.getValue(), ThreadPitch.getValue(), Diameter.getValue()); + + double angle = Base::toRadians(360.0); + BRepPrimAPI_MakeRevol RevolMaker2(threadFace, gp_Ax1(gp_Pnt(0,0,0), zDir), angle); + + //TopoDS_Shape protoHole; + if (RevolMaker2.IsDone()) { + protoHole = RevolMaker2.Shape(); + + if (protoHole.IsNull()) + return new App::DocumentObjectExecReturn("Hole: Resulting shape is empty"); + } + else + return new App::DocumentObjectExecReturn("Hole: Could not revolve sketch!"); + } +#endif + + BRep_Builder builder; + TopoDS_Compound holes; + builder.MakeCompound(holes); + + TopTools_IndexedMapOfShape edgeMap; + TopExp::MapShapes(profileshape, TopAbs_EDGE, edgeMap); + for ( int i=1 ; i<=edgeMap.Extent() ; i++ ) { + Standard_Real c_start; + Standard_Real c_end; + TopoDS_Edge edge = TopoDS::Edge(edgeMap(i)); + Handle(Geom_Curve) c = BRep_Tool::Curve(edge, c_start, c_end); + + // Circle? + if (c->DynamicType() != STANDARD_TYPE(Geom_Circle)) + continue; + + Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(c); + + const gp_Pnt& loc = circle->Axis().Location(); + + gp_Trsf sketchTransformation; + gp_Trsf localSketchTransformation; + Base::Placement SketchPos = profile->Placement.getValue(); + Base::Matrix4D mat = SketchPos.toMatrix(); + sketchTransformation.SetValues( + mat[0][0], mat[0][1], mat[0][2], mat[0][3], + mat[1][0], mat[1][1], mat[1][2], mat[1][3], + mat[2][0], mat[2][1], mat[2][2], mat[2][3] +#if OCC_VERSION_HEX < 0x060800 + , 0.00001, 0.00001 +#endif + ); //precision was removed in OCCT CR0025194 + localSketchTransformation.SetTranslation( gp_Pnt( 0, 0, 0 ), + gp_Pnt(loc.X(), loc.Y(), loc.Z()) ); + + TopoDS_Shape copy = protoHole; + BRepBuilderAPI_Transform transformer(copy, localSketchTransformation ); + + copy = transformer.Shape(); + BRepAlgoAPI_Cut mkCut( base, copy ); + if (!mkCut.IsDone()) + return new App::DocumentObjectExecReturn("Hole: Cut out of base feature failed"); + + TopoDS_Shape result = mkCut.Shape(); + + // We have to get the solids (fuse sometimes creates compounds) + base = getSolid(result); + if (base.IsNull()) + return new App::DocumentObjectExecReturn("Hole: Resulting shape is not a solid"); + + builder.Add(holes, transformer.Shape() ); + } + + holes.Move( this->getLocation().Inverted() ); + + // set the subtractive shape property for later usage in e.g. pattern + this->AddSubShape.setValue( holes ); + + remapSupportShape(base); + this->Shape.setValue(base); + + return App::DocumentObject::StdReturn; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + if (std::string(e->GetMessageString()) == "TopoDS::Face" && + (std::string(DepthType.getValueAsString()) == "UpToFirst" || std::string(DepthType.getValueAsString()) == "UpToFace")) + return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" + "Intersecting sketch entities or multiple faces in a sketch are not allowed " + "for making a pocket up to a face."); + else + return new App::DocumentObjectExecReturn(e->GetMessageString()); + } + catch (Base::Exception& e) { + return new App::DocumentObjectExecReturn(e.what()); + } } diff --git a/src/Mod/PartDesign/App/FeatureHole.h b/src/Mod/PartDesign/App/FeatureHole.h index ee4b415ff2..f7049da1d1 100644 --- a/src/Mod/PartDesign/App/FeatureHole.h +++ b/src/Mod/PartDesign/App/FeatureHole.h @@ -27,6 +27,12 @@ #include #include "FeatureSketchBased.h" +class Property; + +namespace Base { +class XMLReader; +} + namespace PartDesign { @@ -37,27 +43,94 @@ class PartDesignExport Hole : public ProfileBased public: Hole(); - App::PropertyEnumeration Type; - App::PropertyEnumeration HoleType; + App::PropertyBool Threaded; + App::PropertyBool ModelActualThread; + App::PropertyLength ThreadPitch; + App::PropertyAngle ThreadAngle; + App::PropertyLength ThreadCutOffInner; + App::PropertyLength ThreadCutOffOuter; App::PropertyEnumeration ThreadType; - App::PropertyLength Length; - App::PropertyFloat ThreadSize; + App::PropertyEnumeration ThreadSize; + App::PropertyEnumeration ThreadClass; + App::PropertyEnumeration ThreadFit; + App::PropertyLength Diameter; + App::PropertyEnumeration ThreadDirection; + App::PropertyEnumeration HoleCutType; + App::PropertyLength HoleCutDiameter; + App::PropertyLength HoleCutDepth; + App::PropertyAngle HoleCutCountersinkAngle; + App::PropertyEnumeration DepthType; + App::PropertyLength Depth; + App::PropertyEnumeration DrillPoint; + App::PropertyAngle DrillPointAngle; + App::PropertyBool Tapered; + App::PropertyAngle TaperedAngle; /** @name methods override feature */ //@{ /// recalculate the feature App::DocumentObjectExecReturn *execute(void); - //short mustExecute() const; + /// returns the type name of the view provider const char* getViewProviderName(void) const { return "PartDesignGui::ViewProviderHole"; } //@} -private: - static const char* TypeEnums[]; - static const char* HoleTypeEnums[]; - static const char* ThreadEnums[]; + short mustExecute() const; + typedef struct { + const char * designation; + double diameter; + double pitch; + } ThreadDescription; + + static const ThreadDescription threadDescription[][171]; + + virtual void Restore(Base::XMLReader & reader); + + virtual void updateProps(); + +protected: + void onChanged(const App::Property* prop); +private: + static const char* DepthTypeEnums[]; + static const char* ThreadTypeEnums[]; + static const char* ThreadFitEnums[]; + static const char* DrillPointEnums[]; + static const char* ThreadDirectionEnums[]; + + /* "None" thread profile */ + static const char* HoleCutType_None_Enums[]; + static const char* ThreadSize_None_Enums[]; + static const char* ThreadClass_None_Enums[]; + + /* ISO metric coarse profile */ + static const char* HoleCutType_ISOmetric_Enums[]; + static const char* ThreadSize_ISOmetric_Enums[]; + static const char* ThreadClass_ISOmetric_Enums[]; + + /* ISO metric fine profile */ + static const char* HoleCutType_ISOmetricfine_Enums[]; + static const char* ThreadSize_ISOmetricfine_Enums[]; + static const char* ThreadClass_ISOmetricfine_Enums[]; + + /* UNC profile */ + static const char* HoleCutType_UNC_Enums[]; + static const char* ThreadSize_UNC_Enums[]; + static const char* ThreadClass_UNC_Enums[]; + + /* UNF profile */ + static const char* HoleCutType_UNF_Enums[]; + static const char* ThreadSize_UNF_Enums[]; + static const char* ThreadClass_UNF_Enums[]; + + /* UNEF profile */ + static const char* HoleCutType_UNEF_Enums[]; + static const char* ThreadSize_UNEF_Enums[]; + static const char* ThreadClass_UNEF_Enums[]; + + void updateHoleCutParams(); + void updateDiameterParam(); }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp index 41dd078a7f..76f3d178b3 100644 --- a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp +++ b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp @@ -36,6 +36,7 @@ #include "Workbench.h" #include "ViewProviderPocket.h" +#include "ViewProviderHole.h" #include "ViewProviderBody.h" #include "ViewProviderSketchBased.h" #include "ViewProviderPad.h" @@ -127,6 +128,7 @@ PyMOD_INIT_FUNC(PartDesignGui) PartDesignGui::ViewProviderBody ::init(); PartDesignGui::ViewProviderSketchBased ::init(); PartDesignGui::ViewProviderPocket ::init(); + PartDesignGui::ViewProviderHole ::init(); PartDesignGui::ViewProviderPad ::init(); PartDesignGui::ViewProviderRevolution ::init(); PartDesignGui::ViewProviderDressUp ::init(); diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index 03b37fa317..8fcb7e8e3c 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -40,7 +40,7 @@ set(PartDesignGui_MOC_HDRS TaskDraftParameters.h TaskThicknessParameters.h TaskDressUpParameters.h - #TaskHoleParameters.h + TaskHoleParameters.h TaskRevolutionParameters.h TaskTransformedMessages.h TaskTransformedParameters.h @@ -74,7 +74,7 @@ set(PartDesignGui_UIC_SRCS TaskDraftParameters.ui TaskThicknessParameters.ui TaskBooleanParameters.ui - #TaskHoleParameters.ui + TaskHoleParameters.ui TaskRevolutionParameters.ui TaskTransformedMessages.ui TaskMirroredParameters.ui @@ -106,8 +106,8 @@ SET(PartDesignGuiViewProvider_SRCS ViewProviderSketchBased.h ViewProviderPad.cpp ViewProviderPad.h - #ViewProviderHole.cpp - #ViewProviderHole.h + ViewProviderHole.cpp + ViewProviderHole.h ViewProviderPocket.cpp ViewProviderPocket.h ViewProviderChamfer.cpp @@ -214,9 +214,9 @@ SET(PartDesignGuiTaskDlgs_SRCS TaskMultiTransformParameters.ui TaskMultiTransformParameters.cpp TaskMultiTransformParameters.h - #TaskHoleParameters.ui - #TaskHoleParameters.cpp - #TaskHoleParameters.h + TaskHoleParameters.ui + TaskHoleParameters.cpp + TaskHoleParameters.h TaskDatumParameters.cpp TaskDatumParameters.h TaskShapeBinder.ui diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 0f11b5ea79..0bb1d2ae70 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -1038,6 +1038,52 @@ bool CmdPartDesignPocket::isActive(void) return hasActiveDocument(); } +//=========================================================================== +// PartDesign_Hole +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignHole); + +CmdPartDesignHole::CmdPartDesignHole() + : Command("PartDesign_Hole") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Hole"); + sToolTipText = QT_TR_NOOP("Create a hole with the selected sketch"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Hole"; +} + +void CmdPartDesignHole::activated(int iMsg) +{ + Q_UNUSED(iMsg); + App::Document *doc = getDocument(); + if (!PartDesignGui::assureModernWorkflow(doc)) + return; + + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(true); + + if (!pcActiveBody) + return; + + Gui::Command* cmd = this; + auto worker = [this, cmd](Part::Feature* sketch, std::string FeatName) { + + if (FeatName.empty()) return; + + finishProfileBased(cmd, sketch, FeatName); + cmd->adjustCameraPosition(); + }; + + prepareProfileBased(this, "Hole", worker); +} + +bool CmdPartDesignHole::isActive(void) +{ + return hasActiveDocument(); +} + //=========================================================================== // PartDesign_Revolution //=========================================================================== @@ -2138,6 +2184,7 @@ void CreatePartDesignCommands(void) rcCmdMgr.addCommand(new CmdPartDesignPad()); rcCmdMgr.addCommand(new CmdPartDesignPocket()); + rcCmdMgr.addCommand(new CmdPartDesignHole()); rcCmdMgr.addCommand(new CmdPartDesignRevolution()); rcCmdMgr.addCommand(new CmdPartDesignGroove()); rcCmdMgr.addCommand(new CmdPartDesignAdditivePipe); diff --git a/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp b/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp index 7b00e4d2bf..e4a05b0bca 100644 --- a/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp @@ -34,18 +34,20 @@ #include #include #include -#include #include #include - +#include +#include using namespace PartDesignGui; using namespace Gui; /* TRANSLATOR PartDesignGui::TaskHoleParameters */ -TaskHoleParameters::TaskHoleParameters(QWidget *parent) - : TaskBox(Gui::BitmapFactory().pixmap("document-new"),tr("TaskHoleParameters"),true, parent) +TaskHoleParameters::TaskHoleParameters(ViewProviderHole *HoleView, QWidget *parent) + : TaskSketchBasedParameters(HoleView, parent, "PartDesign_Hole",tr("Hole parameters")) + , observer(new Observer(this, static_cast(vp->getObject()))) + , isApplying(false) { // we need a separate container widget to add all controls to proxy = new QWidget(this); @@ -53,15 +55,267 @@ TaskHoleParameters::TaskHoleParameters(QWidget *parent) ui->setupUi(proxy); QMetaObject::connectSlotsByName(this); - this->groupLayout()->addWidget(proxy); + /* Remove actual threading parameters for now */ + ui->ModelActualThread->setVisible(false); + ui->ThreadPitch->setVisible(false); + ui->ThreadCutOffInner->setVisible(false); + ui->ThreadCutOffOuter->setVisible(false); + ui->ThreadAngle->setVisible(false); + ui->label_Pitch->setVisible(false); + ui->label_CutoffInner->setVisible(false); + ui->label_CutoffOuter->setVisible(false); + ui->label_Angle->setVisible(false); - Gui::Selection().Attach(this); + ui->ThreadType->addItem(tr("None")); + ui->ThreadType->addItem(tr("ISO metric coarse profile")); + ui->ThreadType->addItem(tr("ISO metric fine profile")); + ui->ThreadType->addItem(tr("UTS coarse profile")); + ui->ThreadType->addItem(tr("UTS fine profile")); + ui->ThreadType->addItem(tr("UTS extra fine profile")); + + connect(ui->Threaded, SIGNAL(clicked(bool)), this, SLOT(threadedChanged())); + connect(ui->ThreadType, SIGNAL(currentIndexChanged(int)), this, SLOT(threadTypeChanged(int))); + connect(ui->ModelActualThread, SIGNAL(clicked(bool)), this, SLOT(modelActualThreadChanged())); + connect(ui->ThreadPitch, SIGNAL(valueChanged(double)), this, SLOT(threadPitchChanged(double))); + connect(ui->ThreadAngle, SIGNAL(valueChanged(double)), this, SLOT(threadAngleChanged(double))); + connect(ui->ThreadCutOffInner, SIGNAL(valueChanged(double)), this, SLOT(threadCutOffInnerChanged(double))); + connect(ui->ThreadCutOffOuter, SIGNAL(valueChanged(double)), this, SLOT(threadCutOffOuterChanged(double))); + connect(ui->ThreadSize, SIGNAL(currentIndexChanged(int)), this, SLOT(threadSizeChanged(int))); + connect(ui->ThreadClass, SIGNAL(currentIndexChanged(int)), this, SLOT(threadClassChanged(int))); + connect(ui->ThreadFit, SIGNAL(currentIndexChanged(int)), this, SLOT(threadFitChanged(int))); + connect(ui->Diameter, SIGNAL(valueChanged(double)), this, SLOT(threadDiameterChanged(double))); + connect(ui->directionRightHand, SIGNAL(clicked(bool)), this, SLOT(threadDirectionChanged())); + connect(ui->directionLeftHand, SIGNAL(clicked(bool)), this, SLOT(threadDirectionChanged())); + connect(ui->HoleCutType, SIGNAL(currentIndexChanged(int)), this, SLOT(holeCutChanged(int))); + connect(ui->HoleCutDiameter, SIGNAL(valueChanged(double)), this, SLOT(holeCutDiameterChanged(double))); + connect(ui->HoleCutDepth, SIGNAL(valueChanged(double)), this, SLOT(holeCutDepthChanged(double))); + connect(ui->HoleCutCountersinkAngle, SIGNAL(valueChanged(double)), this, SLOT(holeCutCountersinkAngleChanged(double))); + connect(ui->DepthType, SIGNAL(currentIndexChanged(int)), this, SLOT(depthChanged(int))); + connect(ui->Depth, SIGNAL(valueChanged(double)), this, SLOT(depthValueChanged(double))); + connect(ui->drillPointFlat, SIGNAL(clicked(bool)), this, SLOT(drillPointChanged())); + connect(ui->drillPointAngled, SIGNAL(clicked(bool)), this, SLOT(drillPointChanged())); + connect(ui->DrillPointAngle, SIGNAL(valueChanged(double)), this, SLOT(drillPointAngledValueChanged(double))); + connect(ui->Tapered, SIGNAL(clicked(bool)), this, SLOT(taperedChanged())); + connect(ui->TaperedAngle, SIGNAL(valueChanged(double)), this, SLOT(taperedAngleChanged(double))); + + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->updateProps(); + + ui->ThreadPitch->bind(pcHole->ThreadPitch); + ui->ThreadAngle->bind(pcHole->ThreadAngle); + ui->ThreadCutOffInner->bind(pcHole->ThreadCutOffInner); + ui->ThreadCutOffOuter->bind(pcHole->ThreadCutOffOuter); + ui->Diameter->bind(pcHole->Diameter); + ui->HoleCutDiameter->bind(pcHole->HoleCutDiameter); + ui->HoleCutDepth->bind(pcHole->HoleCutDepth); + ui->HoleCutCountersinkAngle->bind(pcHole->HoleCutCountersinkAngle); + ui->Depth->bind(pcHole->Depth); + ui->DrillPointAngle->bind(pcHole->DrillPointAngle); + ui->TaperedAngle->bind(pcHole->TaperedAngle); + + connectPropChanged = App::GetApplication().signalChangePropertyEditor.connect(boost::bind(&TaskHoleParameters::changedObject, this, _1)); + + this->groupLayout()->addWidget(proxy); } TaskHoleParameters::~TaskHoleParameters() { delete ui; - Gui::Selection().Detach(this); +} + +void TaskHoleParameters::threadedChanged() +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->Threaded.setValue(ui->Threaded->isChecked()); + recomputeFeature(); +} + +void TaskHoleParameters::modelActualThreadChanged() +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->ModelActualThread.setValue(ui->ModelActualThread->isChecked()); + recomputeFeature(); +} + +void TaskHoleParameters::threadPitchChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->ThreadPitch.setValue(value); + recomputeFeature(); +} + +void TaskHoleParameters::threadAngleChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->ThreadAngle.setValue(value); + recomputeFeature(); +} + +void TaskHoleParameters::threadCutOffInnerChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->ThreadCutOffInner.setValue(value); + recomputeFeature(); +} + +void TaskHoleParameters::threadCutOffOuterChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->ThreadCutOffOuter.setValue(value); + recomputeFeature(); +} + +void TaskHoleParameters::holeCutChanged(int index) +{ + if (index < 0) + return; + + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->HoleCutType.setValue(index); + recomputeFeature(); +} + +void TaskHoleParameters::holeCutDiameterChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->HoleCutDiameter.setValue(value); + recomputeFeature(); +} + +void TaskHoleParameters::holeCutDepthChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->HoleCutDepth.setValue(value); + recomputeFeature(); +} + +void TaskHoleParameters::holeCutCountersinkAngleChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->HoleCutCountersinkAngle.setValue((double)value); + recomputeFeature(); +} + +void TaskHoleParameters::depthChanged(int index) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->DepthType.setValue(index); + recomputeFeature(); +} + +void TaskHoleParameters::depthValueChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->Depth.setValue(value); + recomputeFeature(); +} + +void TaskHoleParameters::drillPointChanged() +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + if (sender() == ui->drillPointFlat) + pcHole->DrillPoint.setValue((long)0); + else if (sender() == ui->drillPointAngled) + pcHole->DrillPoint.setValue((long)1); + else + assert( 0 ); + recomputeFeature(); +} + +void TaskHoleParameters::drillPointAngledValueChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->DrillPointAngle.setValue((double)value); + recomputeFeature(); +} + +void TaskHoleParameters::taperedChanged() +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->Tapered.setValue(ui->Tapered->isChecked()); + recomputeFeature(); +} + +void TaskHoleParameters::taperedAngleChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->TaperedAngle.setValue(value); + recomputeFeature(); +} + +void TaskHoleParameters::threadTypeChanged(int index) +{ + if (index < 0) + return; + + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + pcHole->ThreadType.setValue(index); +} + +void TaskHoleParameters::threadSizeChanged(int index) +{ + if (index < 0) + return; + + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->ThreadSize.setValue(index); + recomputeFeature(); +} + +void TaskHoleParameters::threadClassChanged(int index) +{ + if (index < 0) + return; + + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->ThreadClass.setValue(index); + recomputeFeature(); +} + +void TaskHoleParameters::threadDiameterChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->Diameter.setValue(value); + recomputeFeature(); +} + +void TaskHoleParameters::threadFitChanged(int index) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->ThreadFit.setValue(index); + recomputeFeature(); +} + +void TaskHoleParameters::threadDirectionChanged() +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + if (sender() == ui->directionRightHand) + pcHole->ThreadDirection.setValue((long)0); + else + pcHole->ThreadDirection.setValue((long)1); + recomputeFeature(); } void TaskHoleParameters::changeEvent(QEvent *e) @@ -72,17 +326,412 @@ void TaskHoleParameters::changeEvent(QEvent *e) } } -/// @cond DOXERR -void TaskHoleParameters::OnChange(Gui::SelectionSingleton::SubjectType &rCaller, - Gui::SelectionSingleton::MessageType Reason) +void TaskHoleParameters::changedObject(const App::Property &Prop) { - if (Reason.Type == SelectionChanges::AddSelection || - Reason.Type == SelectionChanges::RmvSelection || - Reason.Type == SelectionChanges::SetSelection || - Reason.Type == SelectionChanges::ClrSelection) { + // happens when aborting the command + if (vp == nullptr) + return; + + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + bool ro = Prop.isReadOnly(); + + Base::Console().Log("Parameter %s was updated\n", Prop.getName()); + + if (&Prop == &pcHole->Threaded) { + ui->Threaded->setEnabled(true); + if (ui->Threaded->isChecked() ^ pcHole->Threaded.getValue()) { + ui->Threaded->blockSignals(true); + ui->Threaded->setChecked(pcHole->Threaded.getValue()); + ui->Threaded->blockSignals(false); + } + ui->Threaded->setDisabled(ro); + } + else if (&Prop == &pcHole->ModelActualThread) { + if (ui->ModelActualThread->isChecked() ^ pcHole->ModelActualThread.getValue()) { + ui->ModelActualThread->blockSignals(true); + ui->ModelActualThread->setChecked(pcHole->ModelActualThread.getValue()); + ui->ModelActualThread->blockSignals(false); + } + ui->ModelActualThread->setDisabled(ro); + } + else if (&Prop == &pcHole->ThreadPitch) { + if (ui->ThreadPitch->value().getValue() != pcHole->ThreadPitch.getValue()) { + ui->ThreadPitch->blockSignals(true); + ui->ThreadPitch->setValue(pcHole->ThreadPitch.getValue()); + ui->ThreadPitch->blockSignals(false); + } + ui->ThreadPitch->setDisabled(ro); + } + else if (&Prop == &pcHole->ThreadAngle) { + if (ui->ThreadAngle->value().getValue() != pcHole->ThreadAngle.getValue()) { + ui->ThreadAngle->blockSignals(true); + ui->ThreadAngle->setValue(pcHole->ThreadAngle.getValue()); + ui->ThreadAngle->blockSignals(false); + } + ui->ThreadAngle->setDisabled(ro); + } + else if (&Prop == &pcHole->ThreadCutOffInner) { + if (ui->ThreadCutOffInner->value().getValue() != pcHole->ThreadCutOffInner.getValue()) { + ui->ThreadCutOffInner->blockSignals(true); + ui->ThreadCutOffInner->setValue(pcHole->ThreadCutOffInner.getValue()); + ui->ThreadCutOffInner->blockSignals(false); + } + ui->ThreadCutOffInner->setDisabled(ro); + } + else if (&Prop == &pcHole->ThreadCutOffOuter) { + if (ui->ThreadCutOffOuter->value().getValue() != pcHole->ThreadCutOffOuter.getValue()) { + ui->ThreadCutOffOuter->blockSignals(true); + ui->ThreadCutOffOuter->setValue(pcHole->ThreadCutOffOuter.getValue()); + ui->ThreadCutOffOuter->blockSignals(false); + } + ui->ThreadCutOffOuter->setDisabled(ro); + } + else if (&Prop == &pcHole->ThreadType) { + ui->ThreadType->setEnabled(true); + + ui->ThreadSize->blockSignals(true); + ui->ThreadSize->clear(); + const char ** cursor = pcHole->ThreadSize.getEnums(); + while (*cursor) { + ui->ThreadSize->addItem(tr(*cursor)); + ++cursor; + } + ui->ThreadSize->setCurrentIndex(pcHole->ThreadSize.getValue()); + ui->ThreadSize->blockSignals(false); + + // Thread type also updates HoleCutType and ThreadClass + ui->HoleCutType->blockSignals(true); + ui->HoleCutType->clear(); + cursor = pcHole->HoleCutType.getEnums(); + while (*cursor) { + ui->HoleCutType->addItem(tr(*cursor)); + ++cursor; + } + ui->HoleCutType->setCurrentIndex(pcHole->HoleCutType.getValue()); + ui->HoleCutType->blockSignals(false); + + ui->ThreadClass->blockSignals(true); + ui->ThreadClass->clear(); + cursor = pcHole->ThreadClass.getEnums(); + while (*cursor) { + ui->ThreadClass->addItem(tr(*cursor)); + ++cursor; + } + ui->ThreadClass->setCurrentIndex(pcHole->ThreadClass.getValue()); + ui->ThreadClass->blockSignals(false); + + if (ui->ThreadType->currentIndex() != pcHole->ThreadType.getValue()) { + ui->ThreadType->blockSignals(true); + ui->ThreadType->setCurrentIndex(pcHole->ThreadType.getValue()); + ui->ThreadType->blockSignals(false); + } + ui->ThreadType->setDisabled(ro); + } + else if (&Prop == &pcHole->ThreadSize) { + ui->ThreadSize->setEnabled(true); + if (ui->ThreadSize->currentIndex() != pcHole->ThreadSize.getValue()) { + ui->ThreadSize->blockSignals(true); + ui->ThreadSize->setCurrentIndex(pcHole->ThreadSize.getValue()); + ui->ThreadSize->blockSignals(false); + } + ui->ThreadSize->setDisabled(ro); + } + else if (&Prop == &pcHole->ThreadClass) { + ui->ThreadClass->setEnabled(true); + if (ui->ThreadClass->currentIndex() != pcHole->ThreadClass.getValue()) { + ui->ThreadClass->blockSignals(true); + ui->ThreadClass->setCurrentIndex(pcHole->ThreadClass.getValue()); + ui->ThreadClass->blockSignals(false); + } + ui->ThreadClass->setDisabled(ro); + } + else if (&Prop == &pcHole->ThreadFit) { + ui->ThreadFit->setEnabled(true); + if (ui->ThreadFit->currentIndex() != pcHole->ThreadFit.getValue()) { + ui->ThreadFit->blockSignals(true); + ui->ThreadFit->setCurrentIndex(pcHole->ThreadFit.getValue()); + ui->ThreadFit->blockSignals(false); + } + ui->ThreadFit->setDisabled(ro); + } + else if (&Prop == &pcHole->Diameter) { + ui->Diameter->setEnabled(true); + if (ui->Diameter->value().getValue() != pcHole->Diameter.getValue()) { + ui->Diameter->blockSignals(true); + ui->Diameter->setValue(pcHole->Diameter.getValue()); + ui->Diameter->blockSignals(false); + } + ui->Diameter->setDisabled(ro); + } + else if (&Prop == &pcHole->ThreadDirection) { + ui->directionRightHand->setEnabled(true); + ui->directionLeftHand->setEnabled(true); + std::string direction(pcHole->ThreadDirection.getValueAsString()); + if (direction == "Right" && !ui->directionRightHand->isChecked()) { + ui->directionRightHand->blockSignals(true); + ui->directionRightHand->setChecked(true); + ui->directionRightHand->blockSignals(false); + } + if (direction == "Left" && !ui->directionLeftHand->isChecked()) { + ui->directionLeftHand->blockSignals(true); + ui->directionLeftHand->setChecked(true); + ui->directionLeftHand->blockSignals(false); + } + ui->directionRightHand->setDisabled(ro); + ui->directionLeftHand->setDisabled(ro); + } + else if (&Prop == &pcHole->HoleCutType) { + ui->HoleCutType->setEnabled(true); + if (ui->HoleCutType->currentIndex() != pcHole->HoleCutType.getValue()) { + ui->HoleCutType->blockSignals(true); + ui->HoleCutType->setCurrentIndex(pcHole->HoleCutType.getValue()); + ui->HoleCutType->blockSignals(false); + } + ui->HoleCutType->setDisabled(ro); + } + else if (&Prop == &pcHole->HoleCutDiameter) { + ui->HoleCutDiameter->setEnabled(true); + if (ui->HoleCutDiameter->value().getValue() != pcHole->HoleCutDiameter.getValue()) { + ui->HoleCutDiameter->blockSignals(true); + ui->HoleCutDiameter->setValue(pcHole->HoleCutDiameter.getValue()); + ui->HoleCutDiameter->blockSignals(false); + } + ui->HoleCutDiameter->setDisabled(ro); + } + else if (&Prop == &pcHole->HoleCutDepth) { + ui->HoleCutDepth->setEnabled(true); + if (ui->HoleCutDepth->value().getValue() != pcHole->HoleCutDepth.getValue()) { + ui->HoleCutDepth->blockSignals(true); + ui->HoleCutDepth->setValue(pcHole->HoleCutDepth.getValue()); + ui->HoleCutDepth->blockSignals(false); + } + ui->HoleCutDepth->setDisabled(ro); + } + else if (&Prop == &pcHole->HoleCutCountersinkAngle) { + ui->HoleCutCountersinkAngle->setEnabled(true); + if (ui->HoleCutCountersinkAngle->value().getValue() != pcHole->HoleCutCountersinkAngle.getValue()) { + ui->HoleCutCountersinkAngle->blockSignals(true); + ui->HoleCutCountersinkAngle->setValue(pcHole->HoleCutCountersinkAngle.getValue()); + ui->HoleCutCountersinkAngle->blockSignals(false); + } + ui->HoleCutCountersinkAngle->setDisabled(ro); + } + else if (&Prop == &pcHole->DepthType) { + ui->DepthType->setEnabled(true); + if (ui->DepthType->currentIndex() != pcHole->DepthType.getValue()) { + ui->DepthType->blockSignals(true); + ui->DepthType->setCurrentIndex(pcHole->DepthType.getValue()); + ui->DepthType->blockSignals(false); + } + ui->DepthType->setDisabled(ro); + } + else if (&Prop == &pcHole->Depth) { + ui->Depth->setEnabled(true); + if (ui->Depth->value().getValue() != pcHole->Depth.getValue()) { + ui->Depth->blockSignals(true); + ui->Depth->setValue(pcHole->Depth.getValue()); + ui->Depth->blockSignals(false); + } + ui->Depth->setDisabled(ro); + } + else if (&Prop == &pcHole->DrillPoint) { + ui->drillPointFlat->setEnabled(true); + ui->drillPointAngled->setEnabled(true); + std::string drillPoint(pcHole->DrillPoint.getValueAsString()); + if (drillPoint == "Flat" && !ui->drillPointFlat->isChecked()) { + ui->drillPointFlat->blockSignals(true); + ui->drillPointFlat->setChecked(true); + ui->drillPointFlat->blockSignals(false); + } + if (drillPoint == "Angled" && !ui->drillPointAngled->isChecked()) { + ui->drillPointAngled->blockSignals(true); + ui->drillPointAngled->setChecked(true); + ui->drillPointAngled->blockSignals(false); + } + ui->drillPointFlat->setDisabled(ro); + ui->drillPointAngled->setDisabled(ro); + } + else if (&Prop == &pcHole->DrillPointAngle) { + ui->DrillPointAngle->setEnabled(true); + if (ui->DrillPointAngle->value().getValue() != pcHole->DrillPointAngle.getValue()) { + ui->DrillPointAngle->blockSignals(true); + ui->DrillPointAngle->setValue(pcHole->DrillPointAngle.getValue()); + ui->DrillPointAngle->blockSignals(false); + } + ui->DrillPointAngle->setDisabled(ro); + } + else if (&Prop == &pcHole->Tapered) { + ui->Tapered->setEnabled(true); + if (ui->Tapered->isChecked() ^ pcHole->Tapered.getValue()) { + ui->Tapered->blockSignals(true); + ui->Tapered->setChecked(pcHole->Tapered.getValue()); + ui->Tapered->blockSignals(false); + } + ui->Tapered->setDisabled(ro); + } + else if (&Prop == &pcHole->TaperedAngle) { + ui->TaperedAngle->setEnabled(true); + if (ui->TaperedAngle->value().getValue() != pcHole->TaperedAngle.getValue()) { + ui->TaperedAngle->blockSignals(true); + ui->TaperedAngle->setValue(pcHole->TaperedAngle.getValue()); + ui->TaperedAngle->blockSignals(false); + } + ui->TaperedAngle->setDisabled(ro); } } -/// @endcond + +void TaskHoleParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + Q_UNUSED(msg) +} + +bool TaskHoleParameters::getThreaded() const +{ + return ui->Threaded->isChecked(); +} + +long TaskHoleParameters::getThreadType() const +{ + return ui->ThreadType->currentIndex(); +} + +long TaskHoleParameters::getThreadSize() const +{ + if ( ui->ThreadSize->currentIndex() == -1 ) + return 0; + else + return ui->ThreadSize->currentIndex(); +} + +long TaskHoleParameters::getThreadClass() const +{ + if ( ui->ThreadSize->currentIndex() == -1 ) + return 0; + else + return ui->ThreadClass->currentIndex(); +} + +long TaskHoleParameters::getThreadFit() const +{ + if (ui->Threaded->isChecked()) + return ui->ThreadFit->currentIndex(); + else + return 0; +} + +Base::Quantity TaskHoleParameters::getDiameter() const +{ + return ui->Diameter->value(); +} + +bool TaskHoleParameters::getThreadDirection() const +{ + return ui->directionRightHand->isChecked(); +} + +long TaskHoleParameters::getHoleCutType() const +{ + if (ui->HoleCutType->currentIndex() == -1) + return 0; + else + return ui->HoleCutType->currentIndex(); +} + +Base::Quantity TaskHoleParameters::getHoleCutDiameter() const +{ + return ui->HoleCutDiameter->value(); +} + +Base::Quantity TaskHoleParameters::getHoleCutDepth() const +{ + return ui->HoleCutDepth->value(); +} + +Base::Quantity TaskHoleParameters::getHoleCutCountersinkAngle() const +{ + return ui->HoleCutCountersinkAngle->value(); +} + +long TaskHoleParameters::getDepthType() const +{ + return ui->DepthType->currentIndex(); +} + +Base::Quantity TaskHoleParameters::getDepth() const +{ + return ui->Depth->value(); +} + +long TaskHoleParameters::getDrillPoint() const +{ + if ( ui->drillPointFlat->isChecked() ) + return 0; + if ( ui->drillPointAngled->isChecked() ) + return 1; + assert( 0 ); + return -1; // to avoid a compiler warning +} + +Base::Quantity TaskHoleParameters::getDrillPointAngle() const +{ + return ui->DrillPointAngle->value(); +} + +bool TaskHoleParameters::getTapered() const +{ + return ui->Tapered->isChecked(); +} + +Base::Quantity TaskHoleParameters::getTaperedAngle() const +{ + return ui->TaperedAngle->value(); +} + +void TaskHoleParameters::apply() +{ + std::string name = vp->getObject()->getNameInDocument(); + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + const char * cname = name.c_str(); + + isApplying = true; + + ui->ThreadPitch->apply(); + ui->ThreadAngle->apply(); + ui->ThreadCutOffInner->apply(); + ui->ThreadCutOffOuter->apply(); + ui->Diameter->apply(); + ui->HoleCutDiameter->apply(); + ui->HoleCutDepth->apply(); + ui->HoleCutCountersinkAngle->apply(); + ui->Depth->apply(); + ui->DrillPointAngle->apply(); + ui->TaperedAngle->apply(); + + if (!pcHole->Threaded.isReadOnly()) + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Threaded = %u", cname, getThreaded() ? 1 : 0); + if (!pcHole->ModelActualThread.isReadOnly()) + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ModelActualThread = %u", cname, getThreaded() ? 1 : 0); + if (!pcHole->ThreadType.isReadOnly()) + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ThreadType = %u", cname, getThreadType()); + if (!pcHole->ThreadSize.isReadOnly()) + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ThreadSize = %u", cname, getThreadSize()); + if (!pcHole->ThreadClass.isReadOnly()) + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ThreadClass = %u", cname, getThreadClass()); + if (!pcHole->ThreadFit.isReadOnly()) + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ThreadFit = %u", cname, getThreadFit()); + if (!pcHole->ThreadDirection.isReadOnly()) + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ThreadDirection = %u", cname, getThreadDirection()); + if (!pcHole->HoleCutType.isReadOnly()) + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.HoleCutType = %u", cname, getHoleCutType()); + if (!pcHole->DepthType.isReadOnly()) + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.DepthType = %u", cname, getDepthType()); + if (!pcHole->DrillPoint.isReadOnly()) + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.DrillPoint = %u", cname, getDrillPoint()); + if (!pcHole->Tapered.isReadOnly()) + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Tapered = %u", cname, getTapered()); + + isApplying = false; +} //************************************************************************** //************************************************************************** @@ -90,10 +739,10 @@ void TaskHoleParameters::OnChange(Gui::SelectionSingleton::SubjectType &rCaller, //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ TaskDlgHoleParameters::TaskDlgHoleParameters(ViewProviderHole *HoleView) - : TaskDialog(),HoleView(HoleView) + : TaskDlgSketchBasedParameters(HoleView) { assert(HoleView); - parameter = new TaskHoleParameters(); + parameter = new TaskHoleParameters(static_cast(vp)); Content.push_back(parameter); } @@ -103,40 +752,19 @@ TaskDlgHoleParameters::~TaskDlgHoleParameters() } -//==== calls from the TaskView =============================================================== - - -void TaskDlgHoleParameters::open() -{ - -} - -void TaskDlgHoleParameters::clicked(int) -{ - -} - -bool TaskDlgHoleParameters::accept() -{ - return true; -} - -bool TaskDlgHoleParameters::reject() -{ - Gui::Command::openCommand("Hole changed"); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - Gui::Command::commitCommand(); - - return true; -} - -void TaskDlgHoleParameters::helpRequested() -{ - -} - - - - #include "moc_TaskHoleParameters.cpp" + +TaskHoleParameters::Observer::Observer(TaskHoleParameters *_owner, PartDesign::Hole * _hole) + : DocumentObserver(_hole->getDocument()) + , owner(_owner) + , hole(_hole) +{ +} + +void TaskHoleParameters::Observer::slotChangedObject(const App::DocumentObject &Obj, const App::Property &Prop) +{ + if (&Obj == hole) { + Base::Console().Log("Parameter %s was updated with a new value\n", Prop.getName()); + owner->changedObject(Prop); + } +} diff --git a/src/Mod/PartDesign/Gui/TaskHoleParameters.h b/src/Mod/PartDesign/Gui/TaskHoleParameters.h index 29d59844cd..62f78046bc 100644 --- a/src/Mod/PartDesign/Gui/TaskHoleParameters.h +++ b/src/Mod/PartDesign/Gui/TaskHoleParameters.h @@ -27,7 +27,10 @@ #include #include #include +#include +#include +#include "TaskSketchBasedParameters.h" #include "ViewProviderHole.h" class Ui_TaskHoleParameters; @@ -40,35 +43,95 @@ namespace Gui { class ViewProvider; } +namespace PartDesign { +class Hole; +} + namespace PartDesignGui { -class TaskHoleParameters : public Gui::TaskView::TaskBox, public Gui::SelectionSingleton::ObserverType +class TaskHoleParameters : public TaskSketchBasedParameters { Q_OBJECT public: - TaskHoleParameters(QWidget *parent = 0); + TaskHoleParameters(ViewProviderHole *HoleView, QWidget *parent = 0); ~TaskHoleParameters(); - /// Observer message from the Selection - void OnChange(Gui::SelectionSingleton::SubjectType &rCaller, - Gui::SelectionSingleton::MessageType Reason); + + void apply() override; + + bool getThreaded() const; + long getThreadType() const; + long getThreadSize() const; + long getThreadClass() const; + long getThreadFit() const; + Base::Quantity getDiameter() const; + bool getThreadDirection() const; + long getHoleCutType() const; + Base::Quantity getHoleCutDiameter() const; + Base::Quantity getHoleCutDepth() const; + Base::Quantity getHoleCutCountersinkAngle() const; + long getDepthType() const; + Base::Quantity getDepth() const; + long getDrillPoint() const; + Base::Quantity getDrillPointAngle() const; + bool getTapered() const; + Base::Quantity getTaperedAngle() const; private Q_SLOTS: + void threadedChanged(); + void threadTypeChanged(int index); + void threadSizeChanged(int index); + void threadClassChanged(int index); + void threadFitChanged(int index); + void modelActualThreadChanged(); + void threadPitchChanged(double value); + void threadCutOffOuterChanged(double value); + void threadCutOffInnerChanged(double value); + void threadAngleChanged(double value); + void threadDiameterChanged(double value); + void threadDirectionChanged(); + void holeCutChanged(int index); + void holeCutDiameterChanged(double value); + void holeCutDepthChanged(double value); + void holeCutCountersinkAngleChanged(double value); + void depthChanged(int index); + void depthValueChanged(double value); + void drillPointChanged(); + void drillPointAngledValueChanged(double value); + void taperedChanged(); + void taperedAngleChanged(double value); +private: + class Observer : public App::DocumentObserver { + public: + Observer(TaskHoleParameters * _owner, PartDesign::Hole * _hole); + private: + virtual void slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop); + TaskHoleParameters * owner; + PartDesign::Hole * hole; + }; protected: void changeEvent(QEvent *e); + void changedObject(const App::Property& Prop); + +private: + void onSelectionChanged(const Gui::SelectionChanges &msg); private: -private: + typedef boost::BOOST_SIGNALS_NAMESPACE::scoped_connection Connection; + Connection connectPropChanged; + + std::unique_ptr observer; QWidget* proxy; Ui_TaskHoleParameters* ui; + bool isApplying; }; /// simulation dialog for the TaskView -class TaskDlgHoleParameters : public Gui::TaskView::TaskDialog +class TaskDlgHoleParameters : public TaskDlgSketchBasedParameters { Q_OBJECT @@ -76,30 +139,9 @@ public: TaskDlgHoleParameters(ViewProviderHole *HoleView); ~TaskDlgHoleParameters(); - ViewProviderHole* getHoleView() const - { return HoleView; } - -public: - /// is called the TaskView when the dialog is opened - virtual void open(); - /// is called by the framework if an button is clicked which has no accept or reject role - virtual void clicked(int); - /// is called by the framework if the dialog is accepted (Ok) - virtual bool accept(); - /// is called by the framework if the dialog is rejected (Cancel) - virtual bool reject(); - /// is called by the framework if the user presses the help button - virtual void helpRequested(); - virtual bool isAllowedAlterDocument(void) const - { return false; } - - /// returns for Close and Help button - virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const - { return QDialogButtonBox::Close|QDialogButtonBox::Help; } + ViewProviderHole* getHoleView() const { return static_cast(vp); } protected: - ViewProviderHole *HoleView; - TaskHoleParameters *parameter; }; diff --git a/src/Mod/PartDesign/Gui/TaskHoleParameters.ui b/src/Mod/PartDesign/Gui/TaskHoleParameters.ui index e623d5744c..013b868ea9 100644 --- a/src/Mod/PartDesign/Gui/TaskHoleParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskHoleParameters.ui @@ -1,77 +1,453 @@ - PartDesignGui::TaskHoleParameters - + TaskHoleParameters + 0 0 - 137 - 116 + 356 + 660 - Form + Task Hole Parameters - - - - - - - Type: - - - - - - - - Dimension - - - - - Up to last - - - - - Up to first - - - - - + + + - - + + + + + 0 + 0 + + + + Type + + + + + + + Diameter + + + + + + + Depth + + + + + + + false + + + Cutoff inner + + + + + + + + 0 + 0 + + + + Class + + + + + + + Tapered + + + + + + + + + + + 0 + 0 + + + + Direction + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + Fit + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Flat + + + + + + + + + + 0 + 0 + + + + Angled + + + + + + + + + + + + + + + false + + + Pitch + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Right hand + + + + + + + Left hand + + + + + + + + + + false + + + Model actual thread + + + + + + + Threaded + + + + + + + false + + + Angle + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + Profile + + + + + + + + + + Countersink angle + + + + + + + Type + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + 0 + 0 + + + + Diameter + + + + + + + + + + + 0 + 0 + + + + Depth + + + + + + + + + + + 0 + 0 + + - - - Size: - - + + Dimension + - - - mm - - - 0.000000000000000 - - + + Through all + - + + + + + + + 0 + 0 + + + + Size + + + + + + + + Standard fit + + + + + Close fit + + + + + + + + false + + + Cutoff outer + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + + + 0 + 0 + + + + <b>Drill point</b> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + <b>Misc</b> + + + + + + + <b>Hole cut</b> + + + + + + + <b>Threading and size</b> + + + + + - Gui::QuantitySpinBox + Gui::PrefQuantitySpinBox QWidget -
Gui/QuantitySpinBox.h
+
Gui/PrefWidgets.h
diff --git a/src/Mod/PartDesign/Gui/ViewProviderHole.cpp b/src/Mod/PartDesign/Gui/ViewProviderHole.cpp index f0c0d07bc9..b9bb49bccf 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderHole.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderHole.cpp @@ -26,8 +26,16 @@ #ifndef _PreComp_ #endif +#include +#include +#include #include "ViewProviderHole.h" -#include +#include "TaskHoleParameters.h" +#include +#include +#include +#include +#include using namespace PartDesignGui; @@ -45,9 +53,72 @@ ViewProviderHole::~ViewProviderHole() std::vector ViewProviderHole::claimChildren(void)const { std::vector temp; - temp.push_back(static_cast(getObject())->Profile.getValue()); + temp.push_back(static_cast(getObject())->Profile.getValue()); return temp; } +void ViewProviderHole::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + QAction* act; + act = menu->addAction(QObject::tr("Edit hole"), receiver, member); + act->setData(QVariant((int)ViewProvider::Default)); + PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); +} +bool ViewProviderHole::setEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default ) { + // When double-clicking on the item for this hole the + // object unsets and sets its edit mode without closing + // the task panel + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + TaskDlgHoleParameters *holeDlg = qobject_cast(dlg); + if (holeDlg && holeDlg->getHoleView() != this) + holeDlg = 0; // another hole left open its task panel + if (dlg && !holeDlg) { + QMessageBox msgBox; + msgBox.setText(QObject::tr("A dialog is already open in the task panel")); + msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + int ret = msgBox.exec(); + if (ret == QMessageBox::Yes) + Gui::Control().closeDialog(); + else + return false; + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); + + // start the edit dialog + if (holeDlg) + Gui::Control().showDialog(holeDlg); + else + Gui::Control().showDialog(new TaskDlgHoleParameters(this)); + + return true; + } + else { + return PartGui::ViewProviderPart::setEdit(ModNum); + } +} + +bool ViewProviderHole::onDelete(const std::vector &s) +{ + // get the Sketch + PartDesign::Hole* pcHole = static_cast(getObject()); + Sketcher::SketchObject *pcSketch = 0; + if (pcHole->Profile.getValue()) + pcSketch = static_cast(pcHole->Profile.getValue()); + + // if abort command deleted the object the sketch is visible again + if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) + Gui::Application::Instance->getViewProvider(pcSketch)->show(); + + return ViewProvider::onDelete(s); +} diff --git a/src/Mod/PartDesign/Gui/ViewProviderHole.h b/src/Mod/PartDesign/Gui/ViewProviderHole.h index 6eaca17b75..9a56cc6e19 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderHole.h +++ b/src/Mod/PartDesign/Gui/ViewProviderHole.h @@ -41,6 +41,10 @@ public: /// grouping handling std::vector claimChildren(void)const; + void setupContextMenu(QMenu *menu, QObject *receiver, const char *member); + bool onDelete(const std::vector &s); +protected: + bool setEdit(int ModNum); }; diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index bd7b07118e..9a87c917ea 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -366,6 +366,7 @@ void Workbench::activated() "PartDesign_NewSketch", "PartDesign_Pad", "PartDesign_Pocket", + "PartDesign_Hole", "PartDesign_Revolution", "PartDesign_Groove", "PartDesign_AdditivePipe", @@ -456,6 +457,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "PartDesign_CompPrimitiveAdditive" << "Separator" << "PartDesign_Pocket" + << "PartDesign_Hole" << "PartDesign_Groove" << "PartDesign_SubtractiveLoft" << "PartDesign_SubtractivePipe" @@ -522,6 +524,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "PartDesign_CompPrimitiveAdditive" << "Separator" << "PartDesign_Pocket" + << "PartDesign_Hole" << "PartDesign_Groove" << "PartDesign_SubtractiveLoft" << "PartDesign_SubtractivePipe"