public static Dictionary <TessellatedSolid, double> PotentialFastener = new Dictionary <TessellatedSolid, double>(); // value is its certainty internal static HashSet <TessellatedSolid> Run( Dictionary <TessellatedSolid, List <PrimitiveSurface> > solidPrimitive, Dictionary <TessellatedSolid, List <TessellatedSolid> > multipleRefs, int threaded, bool regenerateTrainingData = false) { var s = Stopwatch.StartNew(); s.Start(); Console.WriteLine(); Console.WriteLine("\nDetecting Fasteners ....\n"); Fasteners.Clear(); Nuts.Clear(); Washers.Clear(); PotentialFastener.Clear(); if (threaded != 0) // either all of them or some of them are threaded { FastenerPerceptronLearner.RunPerecptronLearner(regenerateTrainingData); FastenerGaussianNaiveBayes.RunGaussianNaiveBayes(); // after training data is generated (or exists), now I should check and see // if the csv containing weights and votes exists or not. // Even if the trainingData csv doesnt exist but the csv of w and votes exist, // we can run the classifier. // In TrainingDataGenerator, if user says dont regenerate the training data, // now check and see if the WeightsAndVotes.csv exists or not. } var fastener = new HashSet <TessellatedSolid>(); if (multipleRefs.Count == 1) { return(fastener); } if (threaded == 0) // non of them are threaded { AutoNonthreadedFastenerDetection.Run(solidPrimitive, multipleRefs); } else { if (threaded == 1) // all of them are threaded { AutoThreadedFastenerDetection.Run(solidPrimitive, multipleRefs); } else // some are threaded, some not { AutoSemiThreadedFastenerDetection.Run(solidPrimitive, multipleRefs); } } RemoveDetectedFastenersFromPotentialFasteners(); return(fastener); }
internal static void Run( Dictionary <TessellatedSolid, List <PrimitiveSurface> > solidPrimitive, Dictionary <TessellatedSolid, List <TessellatedSolid> > multipleRefs) { // This is mostly similar to the auto fastener detection with no thread, but instead of learning // from the area of the cylinder and for example flat, we will learn from the number of faces. // why? because if we have thread, we will have too many triangles. And this can be useful. // I can also detect helix and use this to detect the threaded fasteners // Important: if the fasteners are threaded using solidworks Fastener toolbox, it will not // have helix. The threads will be small cones with the same axis and equal area. var width = 55; var check = 0; LoadingBar.start(width, 0); var smallParts = FastenerDetector.SmallObjectsDetector(DisassemblyDirectionsWithFastener.PartsWithOneGeom); PreSelectedFastenerToFastenerClass(solidPrimitive, multipleRefs); foreach ( var preSelected in FastenerDetector.PreSelectedFasteners.Where(preSelected => !smallParts.Contains(preSelected))) { smallParts.Add(preSelected); } FastenerDetector.PotentialFastener = new Dictionary <TessellatedSolid, double>(); foreach (var p in smallParts) { FastenerDetector.PotentialFastener.Add(p, 0.1); } var groupedPotentialFasteners = FastenerDetector.GroupingSmallParts(smallParts); var uniqueParts = new HashSet <TessellatedSolid>(); foreach (var s in multipleRefs.Keys.Where(FastenerDetector.PotentialFastener.Keys.Contains)) { uniqueParts.Add(s); } foreach ( var preFastener in FastenerDetector.Fasteners.Where(preFastener => uniqueParts.Contains(preFastener.Solid))) { uniqueParts.Remove(preFastener.Solid); } var equalPrimitivesForEveryUniqueSolid = FastenerDetector.EqualFlatPrimitiveAreaFinder(uniqueParts, solidPrimitive); List <int> learnerVotes; var learnerWeights = FastenerPerceptronLearner.ReadingLearnerWeightsAndVotesFromCsv(out learnerVotes); FastenerGaussianNaiveBayes.GNB(); List <string> nameList = new List <string>(); foreach (var part in uniqueParts) { nameList.Add(part.Name); } float nameRating; float ratingAverage = 0; float ratingMax = -1; float ratingMin = 100000000000; int preCutoff = 0; int postCutoff = 0; PartNameAnalysis.findCommonPreSuffixes(nameList, ref preCutoff, ref postCutoff); foreach (var part in uniqueParts) { nameRating = PartNameAnalysis.SolidHasFastenerKeyword(part, preCutoff, postCutoff); ratingAverage += nameRating; ratingMax = Math.Max(ratingMax, nameRating); ratingMin = Math.Min(ratingMin, nameRating); } float proportion = 1 - (ratingMax - ratingMin) / 3; var refresh = (int)Math.Ceiling((float)uniqueParts.Count / (float)(width * 4)); Parallel.ForEach(uniqueParts, solid => //foreach (var solid in uniqueParts) { if (check % refresh == 0) { LoadingBar.refresh(width, ((float)check) / ((float)uniqueParts.Count)); } check++; var initialCertainty = FastenerGaussianNaiveBayes.GaussianNaiveBayesClassifier(solidPrimitive[solid], solid); nameRating = (PartNameAnalysis.SolidHasFastenerKeyword(solid, preCutoff, postCutoff) - ratingMin) / (0.001f + ratingMax - ratingMin); FastenerDetector.PotentialFastener[solid] = (0.1 + initialCertainty) * proportion + (1 - nameRating) * (1 - proportion); foreach (var up in multipleRefs[solid]) { FastenerDetector.PotentialFastener[up] = (0.1 + initialCertainty) * proportion + (1 - nameRating) * (1 - proportion); } // if a fastener is detected using polynomial trend approach, it is definitely a fastener but not a nut. // if it is detected using any other approach, but not polynomial trend, it is a possible nut. double toolSize; var commonHead = CommonHeadCheck(solid, solidPrimitive[solid], equalPrimitivesForEveryUniqueSolid[solid], out toolSize); if (commonHead != 0) { var newFastener = FastenerPolynomialTrend.PolynomialTrendDetector(solid); if (newFastener != null) { newFastener.ToolSize = toolSize; if (commonHead == 1) { newFastener.Tool = Tool.HexWrench; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } if (commonHead == 2) { newFastener.Tool = Tool.Allen; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } if (commonHead == 3) { newFastener.Tool = Tool.PhillipsBlade; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } if (commonHead == 4) { newFastener.Tool = Tool.FlatBlade; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } if (commonHead == 5) { newFastener.Tool = Tool.PhillipsBlade; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } } else // can be a nut { if (commonHead == 1) { FastenerDetector.Nuts.Add(new Nut { Solid = solid, NutType = NutType.Hex, Tool = Tool.HexWrench, ToolSize = toolSize, OverallLength = BoundingGeometry.BoundingCylinderDic[solid].Length, Certainty = initialCertainty // 0.9 }); foreach (var repeatedSolid in multipleRefs[solid]) { lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(new Nut { Solid = repeatedSolid, NutType = NutType.Hex, Tool = Tool.HexWrench, ToolSize = toolSize, OverallLength = BoundingGeometry.BoundingCylinderDic[solid].Length, Certainty = initialCertainty // 0.9 }); } //continue; return; } } } if (FastenerPerceptronLearner.FastenerPerceptronClassifier(solidPrimitive[solid], solid, learnerWeights, learnerVotes)) { var newFastener = FastenerPolynomialTrend.PolynomialTrendDetector(solid); if (newFastener != null) { lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } // can be a nut // use bounding cylinder to detect nuts. // Since the nuts are small, the OBB function doesnt work accurately for them. // So, I cannot really trust this. var newNut = NutPolynomialTrend.PolynomialTrendDetector(solid); if (newNut != null) // It is a nut with certainty == 1 { lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(newNut); AddRepeatedSolidstoNuts(newNut, multipleRefs[solid]); //continue; return; } // still can be a nut since the upper approach is not really accurate // this 50 percent certainty can go up if the nut is mated with a // detected fastener foreach (var repeatedSolid in multipleRefs[solid]) { lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(new Nut { Solid = repeatedSolid, Diameter = BoundingGeometry.BoundingCylinderDic[solid].Radius * 2.0, // this is approximate OverallLength = BoundingGeometry.BoundingCylinderDic[solid].Length, Certainty = initialCertainty // 0.5 }); } //continue; return; } // if it is not captured by any of the upper methods, give it another chance: if (ThreadDetector(solid, solidPrimitive[solid])) { var newFastener = FastenerPolynomialTrend.PolynomialTrendDetector(solid); if (newFastener != null) { newFastener.FastenerType = FastenerTypeEnum.Bolt; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } //if not, it is a nut: foreach (var repeatedSolid in multipleRefs[solid]) { lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(new Nut { Solid = repeatedSolid, Diameter = BoundingGeometry.BoundingCylinderDic[solid].Radius * 2.0, // this is approximate OverallLength = BoundingGeometry.BoundingCylinderDic[solid].Length * 2.0, Certainty = initialCertainty // 0.5 }); } } } ); // // now use groupped small objects: AutoNonthreadedFastenerDetection.ConnectFastenersNutsAndWashers(groupedPotentialFasteners); LoadingBar.refresh(width, 1); }
internal static void Run( Dictionary <TessellatedSolid, List <PrimitiveSurface> > solidPrimitive, Dictionary <TessellatedSolid, List <TessellatedSolid> > multipleRefs) { var width = 55; var check = 0; LoadingBar.start(width, 0); var smallParts = FastenerDetector.SmallObjectsDetector(DisassemblyDirectionsWithFastener.PartsWithOneGeom); PreSelectedFastenerToFastenerClass(solidPrimitive, multipleRefs); foreach ( var preSelected in FastenerDetector.PreSelectedFasteners.Where(preSelected => !smallParts.Contains(preSelected))) { smallParts.Add(preSelected); } FastenerDetector.PotentialFastener = new Dictionary <TessellatedSolid, double>(); foreach (var p in smallParts) { FastenerDetector.PotentialFastener.Add(p, 0.1); } var groupedPotentialFasteners = FastenerDetector.GroupingSmallParts(smallParts); var uniqueParts = new HashSet <TessellatedSolid>(); foreach (var s in multipleRefs.Keys.Where(FastenerDetector.PotentialFastener.Keys.Contains)) { uniqueParts.Add(s); } foreach ( var preFastener in FastenerDetector.Fasteners.Where(preFastener => uniqueParts.Contains(preFastener.Solid))) { uniqueParts.Remove(preFastener.Solid); } var equalPrimitivesForEveryUniqueSolid = FastenerDetector.EqualFlatPrimitiveAreaFinder(uniqueParts, solidPrimitive); List <int> learnerVotes; var learnerWeights = FastenerPerceptronLearner.ReadingLearnerWeightsAndVotesFromCsv(out learnerVotes); List <string> nameList = new List <string>(); foreach (var part in uniqueParts) { nameList.Add(part.Name); } int preCutoff = 0; int postCutoff = 0; PartNameAnalysis.findCommonPreSuffixes(nameList, ref preCutoff, ref postCutoff); var refresh = (int)Math.Ceiling((float)uniqueParts.Count / (float)(width * 4)); Parallel.ForEach(uniqueParts, solid => //foreach (var solid in uniqueParts) { if (check % refresh == 0) { LoadingBar.refresh(width, ((float)check) / ((float)uniqueParts.Count)); } check++; double toolSize; var commonHead = AutoThreadedFastenerDetection.CommonHeadCheck(solid, solidPrimitive[solid], equalPrimitivesForEveryUniqueSolid[solid], out toolSize); if (commonHead == 1) { // can be a threaded hex fastener, threaded hex nut, nonthreaded hex fastener, nonthreaded hex nut var newFastener = FastenerPolynomialTrend.PolynomialTrendDetector(solid); if (newFastener != null) { // threaded hex fastener newFastener.Tool = Tool.HexWrench; newFastener.ToolSize = toolSize; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AutoThreadedFastenerDetection.AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } var lengthAndRadius = AutoNonthreadedFastenerDetection.FastenerEngagedLengthAndRadiusNoThread(solid, solidPrimitive[solid]); if (AutoNonthreadedFastenerDetection.IsItNut( solidPrimitive[solid].Where(p => p is Cylinder).Cast <Cylinder>().ToList(), solid)) { var nut = new Nut { NutType = NutType.Hex, Solid = solid, ToolSize = toolSize, OverallLength = lengthAndRadius[0], Diameter = lengthAndRadius[1] * 2.0 }; lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(nut); AutoThreadedFastenerDetection.AddRepeatedSolidstoNuts(nut, multipleRefs[solid]); } // nonthreaded hex fastener var fas = new Fastener { Solid = solid, FastenerType = FastenerTypeEnum.Bolt, Tool = Tool.HexWrench, ToolSize = toolSize, RemovalDirection = FastenerDetector.RemovalDirectionFinderUsingObb(solid, BoundingGeometry.OrientedBoundingBoxDic[solid]), OverallLength = GeometryFunctions.SortedLengthOfObbEdges(BoundingGeometry.OrientedBoundingBoxDic[solid]) [2], EngagedLength = lengthAndRadius[0], Diameter = lengthAndRadius[1] * 2.0, Certainty = 1.0 }; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(fas); AutoThreadedFastenerDetection.AddRepeatedSolidstoFasteners(fas, multipleRefs[solid]); return; } if (commonHead == 2) { // can be a threaded allen, nonthreaded allen AddThreadedOrNonthreadedFastener(solid, multipleRefs[solid], solidPrimitive[solid], Tool.Allen, toolSize); return; } if (commonHead == 3 || commonHead == 5) { // can be a threaded philips fastener, nonthreaded philips fastener AddThreadedOrNonthreadedFastener(solid, multipleRefs[solid], solidPrimitive[solid], Tool.PhillipsBlade, toolSize); return; } if (commonHead == 4) { // can be a threaded flat fastener, nonthreaded flat fastener AddThreadedOrNonthreadedFastener(solid, multipleRefs[solid], solidPrimitive[solid], Tool.FlatBlade, toolSize); return; } // if it's not a common head and not threaded, I cannot detect it. // so the rest will be similar to threaded fastener detector if (FastenerPerceptronLearner.FastenerPerceptronClassifier(solidPrimitive[solid], solid, learnerWeights, learnerVotes)) { var newFastener = FastenerPolynomialTrend.PolynomialTrendDetector(solid); if (newFastener != null) { lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AutoThreadedFastenerDetection.AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } // can be a nut // use bounding cylinder to detect nuts. // Since the nuts are small, the OBB function doesnt work accurately for them. // So, I cannot really trust this. var newNut = NutPolynomialTrend.PolynomialTrendDetector(solid); if (newNut != null) // It is a nut with certainty == 1 { lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(newNut); AutoThreadedFastenerDetection.AddRepeatedSolidstoNuts(newNut, multipleRefs[solid]); //continue; return; } // still can be a nut since the upper approach is not really accurate // this 50 percent certainty can go up if the nut is mated with a // detected fastener foreach (var repeatedSolid in multipleRefs[solid]) { lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(new Nut { Solid = repeatedSolid, Diameter = BoundingGeometry.BoundingCylinderDic[solid].Radius * 2.0, // this is approximate OverallLength = BoundingGeometry.BoundingCylinderDic[solid].Length, Certainty = 0.5 }); } //continue; return; } // if it is not captured by any of the upper methods, give it another chance: if (AutoThreadedFastenerDetection.ThreadDetector(solid, solidPrimitive[solid])) { var newFastener = FastenerPolynomialTrend.PolynomialTrendDetector(solid); if (newFastener != null) { newFastener.FastenerType = FastenerTypeEnum.Bolt; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AutoThreadedFastenerDetection.AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } //if not, it is a nut: foreach (var repeatedSolid in multipleRefs[solid]) { lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(new Nut { Solid = repeatedSolid, Diameter = BoundingGeometry.BoundingCylinderDic[solid].Radius * 2.0, // this is approximate OverallLength = BoundingGeometry.BoundingCylinderDic[solid].Length * 2.0, Certainty = 0.5 }); } } } ); // now use groupped small objects: AutoNonthreadedFastenerDetection.ConnectFastenersNutsAndWashers(groupedPotentialFasteners); LoadingBar.refresh(width, 1); }