internal static void AddRepeatedSolidstoNuts(Nut lastAddedNut, List <TessellatedSolid> repeatedSolid) { foreach (var solid in repeatedSolid) { if (solid == lastAddedNut.Solid) { continue; } FastenerDetector.Nuts.Add(new Nut { Solid = solid, NumberOfThreads = lastAddedNut.NumberOfThreads, RemovalDirection = lastAddedNut.RemovalDirection, OverallLength = lastAddedNut.OverallLength, Diameter = lastAddedNut.Diameter, Certainty = lastAddedNut.Certainty, Tool = lastAddedNut.Tool, ToolSize = lastAddedNut.ToolSize, NutType = lastAddedNut.NutType }); } }
internal static void ConnectFastenersNutsAndWashers(List <List <TessellatedSolid> > groupedPotentialFasteners) { // Possible cases: // 1. Fastener // 2. Fastener-Nut // 3. Fastener-Nut-Washer // 4. Fastener-Washer // 5. Nut // 6. Nut-Washer var counter1 = 0; foreach (var fastener in FastenerDetector.Fasteners) { counter1++; // if there is a fastener, find its nuts and washers var groupList = groupedPotentialFasteners.Where(g => g.Contains(fastener.Solid)).ToList(); //------------------------------------- Case 1 ------------------------------------ if (groupList.Count == 0) { continue; } var group = groupList.ToList()[0]; var numFasteners = group.Count(s => FastenerDetector.Fasteners.Any(f => f.Solid == s)); if (numFasteners > 1) { continue; } //group.Add(fastener.Solid); //if (group.Count == 1) continue; //----------------------------------- Cases 2,3,4 --------------------------------- var nutAndWasherRemovalDirection = DisassemblyDirections.DirectionsAndOpposits[fastener.RemovalDirection]; var nuts = FastenerDetector.Nuts.Where(n => group.Contains(n.Solid)).ToList(); var nutList = new List <Nut>(); if (nuts.Any()) { foreach (var nut in nuts) { nut.RemovalDirection = nutAndWasherRemovalDirection; nut.Diameter = fastener.Diameter; nut.Certainty = 1.0; nutList.Add(nut); } } var potentialWasher = group.Where(s => s != fastener.Solid && nuts.All(n => s != n.Solid)).ToList(); // if there is a solid which is very very small comparing the bolt, it is a washer? // the possible washer can still be a nut that has not been detected before // take its obb. if the smallest edge to the longest edge is less than 0.2, it's a washer, // otherwise it can be a nut with low certainty var washers = new List <Washer>(); foreach (var pWasher in potentialWasher) { if (Math.Abs(pWasher.Volume) > Math.Abs(fastener.Solid.Volume)) { continue; } var edgesOfObb = GeometryFunctions.SortedLengthOfObbEdges(BoundingGeometry.OrientedBoundingBoxDic[pWasher]); if ((edgesOfObb[0] / edgesOfObb[2]) < 0.2) // shortest/ longest // this can be fuzzified to define ceratinty { washers.Add(new Washer { Solid = pWasher, Certainty = 0.7, RemovalDirection = nutAndWasherRemovalDirection }); } else { // it can be a nut var uncertainNut = new Nut { Solid = pWasher, Certainty = 0.4, RemovalDirection = nutAndWasherRemovalDirection }; nutList.Add(uncertainNut); FastenerDetector.Nuts.Add(uncertainNut); } } fastener.Nuts = nutList; fastener.Washer = washers; FastenerDetector.Washers.UnionWith(washers); } // if there is a detected nut, but its fastener was not detected: // fastener is unknown var counter2 = 0; foreach (var nut in FastenerDetector.Nuts) { counter2++; if (FastenerDetector.Fasteners.All(f => f.Nuts == null || !f.Nuts.Contains(nut))) { // this a nut that doesnt have any fastener. var groupList = groupedPotentialFasteners.Where(g => g.Contains(nut.Solid)).ToList(); //------------------------------------- Case 5 ------------------------------------ if (groupList.Count == 0) { continue; } var group = groupList.ToList()[0]; group.Add(nut.Solid); //if (group.Count == 1) continue; //---------------------------------- Cases 2,6 -------------------------------- var potentialFastener = group.Where(s => s != nut.Solid).ToList(); Fastener fastener = null; var nutAndWasherRemovalDirection = 0; List <Washer> washers = new List <Washer>(); foreach (var pF in potentialFastener) { if (pF.Volume > nut.Solid.Volume && fastener == null) { // can be a fastener fastener = new Fastener { Solid = pF, RemovalDirection = FastenerDetector.RemovalDirectionFinderUsingObb(pF, BoundingGeometry.OrientedBoundingBoxDic[pF]), OverallLength = GeometryFunctions.SortedLengthOfObbEdges( BoundingGeometry.OrientedBoundingBoxDic[pF])[2], EngagedLength = GeometryFunctions.SortedLengthOfObbEdges( // TBD BoundingGeometry.OrientedBoundingBoxDic[pF])[2], Diameter = nut.Diameter, Certainty = 0.3 }; nutAndWasherRemovalDirection = DisassemblyDirections.Directions.IndexOf( DisassemblyDirections.Directions[fastener.RemovalDirection].multiply(-1.0)); } if (pF.Volume < nut.Solid.Volume) { // can be a washer washers.Add(new Washer { Solid = pF, Certainty = 0.2 }); } } // by this point these things can have happened: // A nut that its unknown fastener is found // or a nut that its washer is found without fastener // a nut, with its fastener and washer FastenerDetector.Washers.UnionWith(washers); if (fastener != null) { FastenerDetector.Fasteners.Add(fastener); nut.RemovalDirection = nutAndWasherRemovalDirection; fastener.Nuts = new List <Nut> { nut }; fastener.Washer = washers; } // but if the fastener is null, if any washer exists, // it is a washer for the nut. Example: there is a // rod with some threads on one of its ends. // I cannot find the rod, but I can possibly find the // nut and the washer. So I will also define washer as // a property for nut. nut.Washer = washers; // removal direction? I can say along a line, and // the see if any of those directions are infinite. // but this doesnt work for threaded nuts and rods } } }
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); }