private static bool SlotHeadBolt(TessellatedSolid solid, List <PrimitiveSurface> solidPrim, Dictionary <TemporaryFlat, List <TemporaryFlat> > equalPrimitives, List <TessellatedSolid> repeated) { repeated.Add(solid); var twoFlat = FastenerDetector.EqualPrimitivesFinder(equalPrimitives, 2); if (!twoFlat.Any()) { return(false); } foreach (var candidateHex in twoFlat) { var candidateHexVal = equalPrimitives[candidateHex]; var cos = (candidateHexVal[0]).Normal.dotProduct((candidateHexVal[1]).Normal); if (!(Math.Abs(-1 - cos) < 0.0001)) { continue; } // I will add couple of conditions here: // 1. If the number of solid vertices in front of each flat is equal to another // 2. If the summation of the vertices in 1 is greater than the total # of verts // 3. and I also need to add some constraints for the for eample the area of the cylinder var leftVerts = VertsInfrontOfFlat(solid, candidateHexVal[0]); var rightVerts = VertsInfrontOfFlat(solid, candidateHexVal[1]); if (Math.Abs(leftVerts - rightVerts) > 2 || leftVerts + rightVerts <= solid.Vertices.Length) { continue; } if (!solidPrim.Where(p => p is Cylinder).Cast <Cylinder>().Any(c => c.IsPositive)) { continue; } var lengthAndRadius = FastenerEngagedLengthAndRadiusNoThread(solid, solidPrim); foreach (var repeatedSolid in repeated) { var fastener = new Fastener { Solid = repeatedSolid, FastenerType = FastenerTypeEnum.Bolt, Tool = Tool.FlatBlade, RemovalDirection = //RemovalDirectionFinderForSlot(candidateHexVal.Cast<Flat>().ToList(), // solidPrim.Where(p => p is Flat).Cast<Flat>().ToList()), FastenerDetector.RemovalDirectionFinderUsingObb(repeatedSolid, BoundingGeometry.OrientedBoundingBoxDic[repeatedSolid]), OverallLength = GeometryFunctions.SortedLengthOfObbEdges(BoundingGeometry.OrientedBoundingBoxDic[solid])[2], EngagedLength = lengthAndRadius[0], Diameter = lengthAndRadius[1] * 2.0, Certainty = 1.0 }; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(fastener); } return(true); } return(false); }
private static void PreSelectedFastenerToFastenerClass( Dictionary <TessellatedSolid, List <PrimitiveSurface> > solidPrimitive, Dictionary <TessellatedSolid, List <TessellatedSolid> > multipleRefs) { foreach (var preFastener in FastenerDetector.PreSelectedFasteners) { var lengthAndRadius = FastenerEngagedLengthAndRadiusNoThread(preFastener, solidPrimitive[preFastener]); // if this part is repeated, add also those repeated parts to the fastener list var repeated = new HashSet <TessellatedSolid>(); var isAKeyInMultipleRefs = multipleRefs.Keys.Where(r => r == preFastener).ToList(); if (isAKeyInMultipleRefs.Any()) { repeated = new HashSet <TessellatedSolid>(multipleRefs[isAKeyInMultipleRefs[0]]) { preFastener } } ; else { // it is a part in a value list foreach (var key in multipleRefs.Keys) { if (!multipleRefs[key].Contains(preFastener)) { continue; } repeated = new HashSet <TessellatedSolid>(multipleRefs[key]) { key }; } } foreach (var repeatedSolid in repeated) { var fastener = new Fastener { Solid = repeatedSolid, FastenerType = FastenerTypeEnum.Bolt, RemovalDirection = FastenerDetector.RemovalDirectionFinderUsingObb(preFastener, BoundingGeometry.OrientedBoundingBoxDic[preFastener]), OverallLength = GeometryFunctions.SortedLengthOfObbEdges( BoundingGeometry.OrientedBoundingBoxDic[preFastener])[2], EngagedLength = lengthAndRadius[0], Diameter = lengthAndRadius[1] * 2.0, Certainty = 1.0 }; FastenerDetector.Fasteners.Add(fastener); } } }
private static void AddThreadedOrNonthreadedFastener(TessellatedSolid solid, List <TessellatedSolid> repeated, List <PrimitiveSurface> prim, Tool tool, double toolSize) { var newFastener = FastenerPolynomialTrend.PolynomialTrendDetector(solid); if (newFastener != null) { newFastener.Tool = tool; newFastener.ToolSize = toolSize; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AutoThreadedFastenerDetection.AddRepeatedSolidstoFasteners(newFastener, repeated); //continue; return; } var lengthAndRadius = AutoNonthreadedFastenerDetection.FastenerEngagedLengthAndRadiusNoThread(solid, prim); var fastener = new Fastener { Solid = solid, FastenerType = FastenerTypeEnum.Bolt, Tool = tool, 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(fastener); AutoThreadedFastenerDetection.AddRepeatedSolidstoFasteners(fastener, repeated); }
internal static void AddRepeatedSolidstoFasteners(Fastener lastAddedFastener, List <TessellatedSolid> repeatedSolid) { foreach (var solid in repeatedSolid) { if (solid == lastAddedFastener.Solid) { continue; } lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(new Fastener { Solid = solid, NumberOfThreads = lastAddedFastener.NumberOfThreads, FastenerType = lastAddedFastener.FastenerType, RemovalDirection = lastAddedFastener.RemovalDirection, OverallLength = lastAddedFastener.OverallLength, EngagedLength = lastAddedFastener.EngagedLength, Diameter = lastAddedFastener.Diameter, Certainty = lastAddedFastener.Certainty, Tool = lastAddedFastener.Tool, ToolSize = lastAddedFastener.ToolSize }); } }
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 } } }
private static bool PhillipsSlotComboHeadBolt(TessellatedSolid solid, List <PrimitiveSurface> solidPrim, Dictionary <TemporaryFlat, List <TemporaryFlat> > equalPrimitives, List <TessellatedSolid> repeated) { repeated.Add(solid); var fourFlat = FastenerDetector.EqualPrimitivesFinder(equalPrimitives, 4); if (fourFlat.Count < 2) { return(false); } var eachSlot = 0; var flats = new List <TemporaryFlat>(); foreach (var candidateHex in fourFlat) { var candidateHexVal = equalPrimitives[candidateHex]; var cos = new List <double>(); var firstPrimNormal = (candidateHexVal[0]).Normal; for (var i = 1; i < candidateHexVal.Count; i++) { cos.Add(firstPrimNormal.dotProduct((candidateHexVal[i]).Normal)); } // if it is a slot and phillips combo the cos list must have two -1 and one 1 // and this needs to appear 2 times. if (cos.Count(c => Math.Abs(-1 - c) < 0.0001) != 2 || cos.Count(c => Math.Abs(1 - c) < 0.0001) != 1) { continue; } if (!solidPrim.Where(p => p is Cylinder).Cast <Cylinder>().Any(c => c.IsPositive)) { continue; } flats.AddRange(candidateHexVal); eachSlot++; } if (eachSlot != 2) { return(false); } var lengthAndRadius = FastenerEngagedLengthAndRadiusNoThread(solid, solidPrim); foreach (var repeatedSolid in repeated) { var fastener = new Fastener { Solid = repeatedSolid, FastenerType = FastenerTypeEnum.Bolt, Tool = Tool.PhillipsBlade, RemovalDirection = //RemovalDirectionFinderForAllenHexPhillips(flats.Cast<Flat>().ToList(), // BoundingGeometry.OrientedBoundingBoxDic[solid]), FastenerDetector.RemovalDirectionFinderUsingObb(repeatedSolid, BoundingGeometry.OrientedBoundingBoxDic[repeatedSolid]), OverallLength = GeometryFunctions.SortedLengthOfObbEdges(BoundingGeometry.OrientedBoundingBoxDic[solid])[2], EngagedLength = lengthAndRadius[0], Diameter = lengthAndRadius[1] * 2.0, Certainty = 1.0 }; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(fastener); } return(true); }
private static bool PhillipsHeadBolt(TessellatedSolid solid, List <PrimitiveSurface> solidPrim, Dictionary <TemporaryFlat, List <TemporaryFlat> > equalPrimitives, List <TessellatedSolid> repeated) { repeated.Add(solid); var eightFlat = FastenerDetector.EqualPrimitivesFinder(equalPrimitives, 8); if (!eightFlat.Any()) { // before I return false, I will take the ones with 4 faces that have a close area and merge them. /*var fourEqual1 = FastenerDetector.EqualPrimitivesFinder(equalPrimitives, 4); * var closeArea1 = new List<TemporaryFlat[]>(); * for (var i = 0; i < fourEqual1.Count - 1; i++) * { * for (var j = i + 1; j < fourEqual1.Count; j++) * { * if (Math.Abs(fourEqual1[i].Area - fourEqual1[j].Area) < 0.1 * fourEqual1[i].Area) * { * closeArea1.Add(new[] { fourEqual1[i], fourEqual1[j] }); * break; * } * } * } * foreach (var cA in closeArea1) * { * equalPrimitives[cA[0]].AddRange(equalPrimitives[cA[1]]); * } * return PhillipsHeadBolt(solid, solidPrim, equalPrimitives, repeated);*/ return(false); } foreach (var candidateHex in eightFlat) { var candidateHexVal = equalPrimitives[candidateHex]; var cos = new List <double>(); var firstPrimNormal = (candidateHexVal[0]).Normal; for (var i = 1; i < candidateHexVal.Count; i++) { cos.Add(firstPrimNormal.dotProduct((candidateHexVal[i]).Normal)); } // if it is philips head, the cos list must have four 0, two -1 and one 1 if (cos.Count(c => Math.Abs(0.0 - c) < 0.025) != 4 || cos.Count(c => Math.Abs(-1 - c) < 0.025) != 2 || cos.Count(c => Math.Abs(1 - c) < 0.001) != 1) { continue; } var lengthAndRadius = FastenerEngagedLengthAndRadiusNoThread(solid, solidPrim); foreach (var repeatedSolid in repeated) { var fastener = new Fastener { Solid = repeatedSolid, FastenerType = FastenerTypeEnum.Bolt, Tool = Tool.PhillipsBlade, RemovalDirection = //RemovalDirectionFinderForAllenHexPhillips(candidateHexVal.Cast<Flat>().ToList(), // BoundingGeometry.OrientedBoundingBoxDic[solid]), FastenerDetector.RemovalDirectionFinderUsingObb(repeatedSolid, BoundingGeometry.OrientedBoundingBoxDic[repeatedSolid]), OverallLength = GeometryFunctions.SortedLengthOfObbEdges(BoundingGeometry.OrientedBoundingBoxDic[solid])[2], EngagedLength = lengthAndRadius[0], Diameter = lengthAndRadius[1] * 2.0, Certainty = 1.0 }; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(fastener); } return(true); } // before I return false, I will take the ones with 4 faces that have a close area and merge them. /*var fourEqual = FastenerDetector.EqualPrimitivesFinder(equalPrimitives, 4); * var closeArea = new List<TemporaryFlat[]>(); * for (var i = 0; i < fourEqual.Count - 1; i++) * { * for (var j = i+1; j < fourEqual.Count; j++) * { * if (Math.Abs(fourEqual[i].Area - fourEqual[j].Area) < 0.01*fourEqual[i].Area) * { * closeArea.Add(new []{ fourEqual[i] , fourEqual[j] }); * break; * } * } * } * foreach (var cA in closeArea) * { * equalPrimitives[cA[0]].AddRange(equalPrimitives[cA[1]]); * } * return PhillipsHeadBolt(solid, solidPrim, equalPrimitives, repeated);*/ return(false); }
private static bool HexBoltNutAllen(TessellatedSolid solid, List <PrimitiveSurface> solidPrim, Dictionary <TemporaryFlat, List <TemporaryFlat> > equalPrimitives, List <TessellatedSolid> repeated) { repeated.Add(solid); var sixFlat = FastenerDetector.EqualPrimitivesFinder(equalPrimitives, 6); if (!sixFlat.Any()) { return(false); } foreach (var candidateHex in sixFlat) { var candidateHexVal = equalPrimitives[candidateHex]; var cos = new List <double>(); var firstPrimNormal = (candidateHexVal[0]).Normal; for (var i = 1; i < candidateHexVal.Count; i++) { cos.Add(firstPrimNormal.dotProduct((candidateHexVal[i]).Normal)); } // if it is a hex or allen bolt, the cos list must have two 1/2, two -1/2 and one -1 if (cos.Count(c => Math.Abs(0.5 - c) < 0.0001) != 2 || cos.Count(c => Math.Abs(-0.5 - c) < 0.0001) != 2 || cos.Count(c => Math.Abs(-1 - c) < 0.0001) != 1) { continue; } var lengthAndRadius = FastenerEngagedLengthAndRadiusNoThread(solid, solidPrim); if (IsItAllen(candidateHexVal)) { // this is a socket bolt (allen) foreach (var repeatedSolid in repeated) { var fastener = new Fastener { Solid = repeatedSolid, FastenerType = FastenerTypeEnum.Bolt, Tool = Tool.Allen, ToolSize = ToolSizeFinder(candidateHexVal), RemovalDirection = //RemovalDirectionFinderForAllenHexPhillips(candidateHexVal.Cast<Flat>().ToList(), // BoundingGeometry.OrientedBoundingBoxDic[solid]), FastenerDetector.RemovalDirectionFinderUsingObb(repeatedSolid, BoundingGeometry.OrientedBoundingBoxDic[repeatedSolid]), OverallLength = GeometryFunctions.SortedLengthOfObbEdges(BoundingGeometry.OrientedBoundingBoxDic[solid])[2], EngagedLength = lengthAndRadius[0], Diameter = lengthAndRadius[1] * 2.0, Certainty = 1.0 }; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(fastener); } return(true); } // else: it is a hex bolt or nut if (IsItNut(solidPrim.Where(p => p is Cylinder).Cast <Cylinder>().ToList(), solid)) { foreach (var repeatedSolid in repeated) { lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(new Nut { NutType = NutType.Hex, Solid = repeatedSolid, ToolSize = ToolSizeFinder(candidateHexVal), OverallLength = lengthAndRadius[0], Diameter = lengthAndRadius[1] * 2.0, Certainty = 1.0 }); } return(true); } foreach (var repeatedSolid in repeated) { lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(new Fastener { Solid = repeatedSolid, FastenerType = FastenerTypeEnum.Bolt, Tool = Tool.HexWrench, ToolSize = ToolSizeFinder(candidateHexVal), RemovalDirection = //RemovalDirectionFinderForAllenHexPhillips(candidateHexVal.Cast<Flat>().ToList(), // BoundingGeometry.OrientedBoundingBoxDic[solid]), FastenerDetector.RemovalDirectionFinderUsingObb(repeatedSolid, BoundingGeometry.OrientedBoundingBoxDic[repeatedSolid]), OverallLength = GeometryFunctions.SortedLengthOfObbEdges(BoundingGeometry.OrientedBoundingBoxDic[solid]) [2], EngagedLength = lengthAndRadius[0], Diameter = lengthAndRadius[1] * 2.0, Certainty = 1.0 }); } return(true); } return(false); }
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); }
private static void AddFastenerToArc(designGraph assemblyGraph, List <string> lockedByTheFastener, Fastener fastener) { fastener.PartsLockedByFastener = new List <int>(); if (lockedByTheFastener.Count == 1) { var comp = (Component)assemblyGraph[lockedByTheFastener[0]]; fastener.PartsLockedByFastener.Add(assemblyGraph.nodes.IndexOf(comp)); if (comp.Pins == null) { comp.Pins = new List <Fastener>(); } if (comp.Pins.All(f => f.Solid != fastener.Solid)) { comp.Pins.Add(fastener); } } foreach ( Connection connection in assemblyGraph.arcs.Where( a => lockedByTheFastener.Contains(a.From.name) && lockedByTheFastener.Contains(a.To.name)) .ToList()) { if (lockedByTheFastener.Count > 2) { foreach (var solid in lockedByTheFastener) { var nodeInd = assemblyGraph.nodes.IndexOf(assemblyGraph.nodes.Where(n => n.name == solid).ToList()[0]); if (fastener.PartsLockedByFastener.Contains(nodeInd)) { continue; } fastener.PartsLockedByFastener.Add(nodeInd); } } connection.Fasteners.Add(fastener); } }
internal static void AddFastenersInformation(designGraph assemblyGraph, Dictionary <string, List <TessellatedSolid> > solidsNoFastener, Dictionary <TessellatedSolid, List <PrimitiveSurface> > solidPrimitive) { var counter = 0; foreach (var fastener in FastenerDetector.Fasteners) { counter++; var lockedByTheFastener = PartsLockedByTheFastenerFinder(fastener.Solid, solidsNoFastener, solidPrimitive); AddFastenerToArc(assemblyGraph, lockedByTheFastener, fastener); } // So, by this point, if there is a fastener between two or more parts, a new local variable // is added to their arc which shows the direction of freedom of the fastener. // So if I want to seperate two parts or two subassemblies, now I know that there is a // fastener holding them to each other. And I also know the removal direction of the fastener // There is still a possibility here: if any of the potential fasteners are holding 2 or more parts // The point is that they can be either a washer, nut or fastener. But if it is a fastener, I need // to find the parts that it's holding and add it to their arc counter = 0; foreach (var possible in FastenerDetector.PotentialFastener.Keys) { counter++; var locked = PartsLockedByTheFastenerFinder(possible, solidsNoFastener, solidPrimitive); if (locked.Count < 2) { if (locked.Count == 1) { var comp = (Component)assemblyGraph[locked[0]]; var pin = new Fastener() { RemovalDirection = FastenerDetector.RemovalDirectionFinderUsingObb(possible, BoundingGeometry.OrientedBoundingBoxDic[possible]), Solid = possible, Diameter = BoundingGeometry.BoundingCylinderDic[possible].Radius, OverallLength = BoundingGeometry.BoundingCylinderDic[possible].Length }; if (comp.Pins == null) { comp.Pins = new List <Fastener>(); } comp.Pins.Add(pin); } } PolygonalFace topPlane = null; var fastener = new Fastener() { RemovalDirection = FastenerDetector.RemovalDirectionFinderUsingObbWithTopPlane(possible, BoundingGeometry.OrientedBoundingBoxDic[possible], out topPlane), Solid = possible, Diameter = BoundingGeometry.BoundingCylinderDic[possible].Radius, OverallLength = BoundingGeometry.BoundingCylinderDic[possible].Length }; AddFastenerToArc(assemblyGraph, locked, fastener); /*(if (fastener.PartsLockedByFastener.Count > 2) * // if there are more than 2 parts locked by the fastener, sort them based on their distance to the top plane of the fastener * { * * }*/ } }
internal static List <int> RunGraphGeneration(designGraph assemblyGraph, Dictionary <string, List <TessellatedSolid> > solidsNoFastener) { Solids = Program.Solids; solidsNoFastener = Program.SolidsNoFastener; //$ Added because it seems that primitive surfaces are populated in step one // Extracting primitives from the list of solids foreach (KeyValuePair <string, List <TessellatedSolid> > p in Solids) { foreach (TessellatedSolid t in p.Value) { SolidPrimitive[t] = t.Primitives; } } // //PrintOutSomeInitialStats(); var globalDirPool = new List <int>(); // Detect gear mates //------------------------------------------------------------------------------------------ var gears = GearDetector.Run(PartsWithOneGeom, SolidPrimitive); var sw = new Stopwatch(); sw.Start(); // Add the solids as nodes to the graph. Exclude the fasteners //------------------------------------------------------------------------------------------ //DisassemblyDirections.Solids = new List<TessellatedSolid>(solidsNoFastener); AddingNodesToGraph(assemblyGraph, solidsNoFastener); //, gears, screwsAndBolts); // Implementing region octree for every solid //------------------------------------------------------------------------------------------ PartitioningSolid.Partitions = new Dictionary <TessellatedSolid, Partition[]>(); PartitioningSolid.PartitionsAABB = new Dictionary <TessellatedSolid, PartitionAABB[]>(); PartitioningSolid.CreatePartitions(solidsNoFastener); // Part to part interaction to obtain removal directions between every connected pair //------------------------------------------------------------------------------------------ Console.WriteLine(" \n\nAdjacent Blocking Determination ..."); var width = 55; LoadingBar.start(width, 0); BlockingDetermination.OverlappingSurfaces = new List <OverlappedSurfaces>(); var solidNofastenerList = solidsNoFastener.ToList(); long totalTriTobeChecked = 0; var overlapCheck = new HashSet <KeyValuePair <string, List <TessellatedSolid> >[]>(); for (var i = 0; i < solidsNoFastener.Count - 1; i++) { var subAssem1 = solidNofastenerList[i]; for (var j = i + 1; j < solidsNoFastener.Count; j++) { var subAssem2 = solidNofastenerList[j]; overlapCheck.Add(new[] { subAssem1, subAssem2 }); var tri2Sub1 = subAssem1.Value.Sum(s => s.Faces.Length); var tri2Sub2 = subAssem2.Value.Sum(s => s.Faces.Length); totalTriTobeChecked += tri2Sub1 * tri2Sub2; } } var total = overlapCheck.Count; var refresh = (int)Math.Ceiling(((float)total) / ((float)(width * 4))); var check = 0; long counter = 0; //$ Need to convert back to parallel after debug //foreach (var each in overlapCheck) Parallel.ForEach(overlapCheck, each => { if (check % refresh == 0) { LoadingBar.refresh(width, ((float)check) / ((float)total)); } check++; var localDirInd = new List <int>(); for (var t = 0; t < DisassemblyDirections.Directions.Count; t++) { localDirInd.Add(t); } var connected = false; var certainty = 0.0; foreach (var solid1 in each[0].Value) { foreach (var solid2 in each[1].Value) { counter += solid1.Faces.Length * solid2.Faces.Length; double localCertainty; var blocked = BlockingDetermination.DefineBlocking(solid1, solid2, globalDirPool, localDirInd, out localCertainty); if (connected == false) { connected = blocked; } if (localCertainty > certainty) { certainty = localCertainty; } } } if (connected) { // I wrote the code in a way that "solid1" is always "Reference" and "solid2" is always "Moving". // Update the romoval direction if it is a gear mate: localDirInd = GearDetector.UpdateRemovalDirectionsIfGearMate(each[0].Value, each[1].Value, gears, localDirInd); List <int> finDirs, infDirs; NonadjacentBlockingDetermination.FiniteDirectionsBetweenConnectedPartsWithPartitioning( each[0].Value, each[1].Value, localDirInd, out finDirs, out infDirs); lock (assemblyGraph) { var from = assemblyGraph[each[1].Key]; // Moving var to = assemblyGraph[each[0].Key]; // Reference assemblyGraph.addArc((node)from, (node)to, "", typeof(Connection)); var a = (Connection)assemblyGraph.arcs.Last(); a.Certainty = certainty; AddInformationToArc(a, finDirs, infDirs); } } }); LoadingBar.refresh(width, 1); Fastener.AddFastenersInformation(assemblyGraph, solidsNoFastener, SolidPrimitive); // create oppositeDirections for global direction pool. FindingOppositeDirectionsForGlobalPool(globalDirPool); // Simplify the solids, before doing anything //------------------------------------------------------------------------------------------ foreach (var solid in solidsNoFastener) { Program.SolidsNoFastenerSimplified.Add(solid.Key, Program.SimplifiedSolids[solid.Key]); } SimplifySolids(Program.SimplifiedSolids, 0.7); // Implementing region octree for every solid //------------------------------------------------------------------------------------------ PartitioningSolid.Partitions = new Dictionary <TessellatedSolid, Partition[]>(); PartitioningSolid.PartitionsAABB = new Dictionary <TessellatedSolid, PartitionAABB[]>(); PartitioningSolid.CreatePartitions(Program.SimplifiedSolids); CheckToHaveConnectedGraph(assemblyGraph); return(globalDirPool); }