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) { // This approach will use the symmetric shape of the fasteners' heads. If there is no thread, // we willl consider the area of the positive culinders for bolts and negative cylinder for // nuts. // This is an important point: // 1. Find the small objects using all of the solids // 2. Group them using small objects // 3. Detect the fasteners using multiple references. (for each similar object, detect one of them) var width = 55; var check = 0; LoadingBar.start(width, 0); var smallParts = FastenerDetector.SmallObjectsDetector(DisassemblyDirectionsWithFastener.PartsWithOneGeom); //new List<TessellatedSolid>(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); var checkedSolids = new HashSet <TessellatedSolid>(); 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 (solidPrimitive[solid].Count == 0) { return; } if (HexBoltNutAllen(solid, solidPrimitive[solid], equalPrimitivesForEveryUniqueSolid[solid], multipleRefs[solid])) { //continue; lock (checkedSolids) { checkedSolids.Add(solid); } return; } if (PhillipsHeadBolt(solid, solidPrimitive[solid], equalPrimitivesForEveryUniqueSolid[solid], multipleRefs[solid])) { //continue; lock (checkedSolids) { checkedSolids.Add(solid); } return; } if (SlotHeadBolt(solid, solidPrimitive[solid], equalPrimitivesForEveryUniqueSolid[solid], multipleRefs[solid])) { //continue; lock (checkedSolids) { checkedSolids.Add(solid); } return; } if (PhillipsSlotComboHeadBolt(solid, solidPrimitive[solid], equalPrimitivesForEveryUniqueSolid[solid], multipleRefs[solid])) { //continue; lock (checkedSolids) { checkedSolids.Add(solid); } return; } lock (checkedSolids) { checkedSolids.Add(solid); } } );// // when all of the fasteners are recognized, it's time to check the third level filter: // something is not acceptable: nut without fastener. If there is a nut without fastener, // I will try to look for that. // Is there anyway to detect more? ConnectFastenersNutsAndWashers(groupedPotentialFasteners); LoadingBar.refresh(width, 1); }