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); }
internal static Fastener PolynomialTrendDetector(TessellatedSolid solid) { // Assumptions: // 1. In fasteners, length is longer than width. var obb = BoundingGeometry.OrientedBoundingBoxDic[solid]; //if (!solid.Name.Contains("STLB ASM")) return true; const int k = 500; PolygonalFace f1; PolygonalFace f2; var longestSide = GeometryFunctions.LongestPlaneOfObbDetector(obb, out f1, out f2); var partitions = new FastenerBoundingBoxPartition(solid, longestSide[0], 50); // 1. Take the middle point of the smallest edge of each triangle. Or the points of the 2nd longest edge of a side triangle // 2. Generate k points between them with equal distances. // 3. Generate rays using generated points. var midPoint1 = ShortestEdgeMidPointOfTriangle(longestSide[0]); var midPoint2 = ShortestEdgeMidPointOfTriangle(longestSide[1]); var kPointsBetweenMidPoints = KpointBtwPointsGenerator(midPoint1, midPoint2, k); double longestDist; var distancePointToSolid = PointToSolidDistanceCalculatorWithPartitioning(solid, partitions.Partitions, kPointsBetweenMidPoints, longestSide[0].Normal.multiply(-1.0), out longestDist); // one more step: Merge points with equal distances. List <int> originalInds; distancePointToSolid = MergingEqualDistances(distancePointToSolid, out originalInds, 0.001); int numberOfThreads; int[] threadStartEndPoints; if (ContainsThread(distancePointToSolid, out numberOfThreads, out threadStartEndPoints)) { //PlotInMatlab(distancePointToSolid); var startEndThreadPoints = Math.Abs(originalInds[threadStartEndPoints[0] + 2] - originalInds[threadStartEndPoints[1] - 2]); return(new Fastener { Solid = solid, NumberOfThreads = numberOfThreads, FastenerType = FastenerTypeEnum.Bolt, RemovalDirection = FastenerDetector.RemovalDirectionFinderUsingObb(solid, BoundingGeometry.OrientedBoundingBoxDic[solid]), OverallLength = GeometryFunctions.SortedLengthOfObbEdges(BoundingGeometry.OrientedBoundingBoxDic[solid])[2], EngagedLength = (startEndThreadPoints + (startEndThreadPoints * 2) / (double)numberOfThreads) * (GeometryFunctions.DistanceBetweenTwoVertices(midPoint1, midPoint2) / ((double)k + 1)), Diameter = DiameterOfFastenerFinderUsingPolynomial(distancePointToSolid, threadStartEndPoints, longestSide[0], solid, longestDist), Certainty = 1.0 }); } // Plot: //if (hasThread) //PlotInMatlab(distancePointToSolid); return(null); }
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); } } }
internal static void RunFastenerDetection(Dictionary <string, List <TessellatedSolid> > solids, int threaded) { PartsWithOneGeom = new List <TessellatedSolid>(); foreach (var subAssem in solids.Values) { if (subAssem.Count == 1) { PartsWithOneGeom.Add(subAssem[0]); } } // From repeated parts take only one of them: //------------------------------------------------------------------------------------------ var multipleRefs = DuplicatePartsDetector(PartsWithOneGeom); // Detect fasteners //------------------------------------------------------------------------------------------ FastenerDetector.Run(SolidPrimitive, multipleRefs, threaded, false); }
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 int CommonHeadCheck(TessellatedSolid solid, List <PrimitiveSurface> solidPrim, Dictionary <TemporaryFlat, List <TemporaryFlat> > equalPrimitives, out double toolSize) { // 0: false (doesnt have any common head shape) // 1: HexBolt or Nut // 2: Allen // 3: Phillips // 4: Slot // 5: Phillips and Slot combo toolSize = 0.0; // check for hex bolt, nut and allen ------------------------------------------------------------- var sixFlat = FastenerDetector.EqualPrimitivesFinder(equalPrimitives, 6); var eightFlat = FastenerDetector.EqualPrimitivesFinder(equalPrimitives, 8); var twoFlat = FastenerDetector.EqualPrimitivesFinder(equalPrimitives, 2); var fourFlat = FastenerDetector.EqualPrimitivesFinder(equalPrimitives, 4); //if (!sixFlat.Any()) return 0; 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; } toolSize = AutoNonthreadedFastenerDetection.ToolSizeFinder(candidateHexVal); if (AutoNonthreadedFastenerDetection.IsItAllen(candidateHexVal)) { return(2); } return(1); } 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)); } var oneFlat = FastenerDetector.EqualPrimitivesFinder(equalPrimitives, 1); // Any flat that is adjacent to all of these eights? // if it is philips head, the cos list must have four 0, two -1 and one 1 foreach (var sh in oneFlat) { if (candidateHexVal.All(f => f.OuterEdges.Any(sh.OuterEdges.Contains))) { return(3); } } /*if (cos.Count(c => Math.Abs(0.0 - c) < 0.0001) != 4 || * cos.Count(c => Math.Abs(-1 - c) < 0.0001) != 2 || * cos.Count(c => Math.Abs(1 - c) < 0.0001) != 1) continue; * return 3;*/ continue; } 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 = AutoNonthreadedFastenerDetection.VertsInfrontOfFlat(solid, candidateHexVal[0]); var rightVerts = AutoNonthreadedFastenerDetection.VertsInfrontOfFlat(solid, candidateHexVal[1]); if (Math.Abs(leftVerts - rightVerts) > 10 || leftVerts + rightVerts <= solid.Vertices.Length) { continue; } return(4); } 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; } flats.AddRange(candidateHexVal); eachSlot++; } if (eachSlot == 2) { return(5); } return(0); }
private static void PreSelectedFastenerToFastenerClass( Dictionary <TessellatedSolid, List <PrimitiveSurface> > solidPrimitive, Dictionary <TessellatedSolid, List <TessellatedSolid> > multipleRefs) { foreach (var preFastener in FastenerDetector.PreSelectedFasteners) { // 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 }; } } var newFastener = FastenerPolynomialTrend.PolynomialTrendDetector(preFastener); if (newFastener != null) { foreach (var repeatedSolid in repeated) { FastenerDetector.Fasteners.Add(new Fastener { Solid = repeatedSolid, NumberOfThreads = newFastener.NumberOfThreads, FastenerType = newFastener.FastenerType, RemovalDirection = newFastener.RemovalDirection, OverallLength = newFastener.OverallLength, EngagedLength = newFastener.EngagedLength, Diameter = newFastener.Diameter, Certainty = 1.0 }); } return; } var overalLength = GeometryFunctions.SortedLengthOfObbEdges(BoundingGeometry.OrientedBoundingBoxDic[preFastener])[2]; foreach (var repeatedSolid in repeated) { FastenerDetector.Fasteners.Add(new Fastener { Solid = repeatedSolid, FastenerType = FastenerTypeEnum.Bolt, RemovalDirection = FastenerDetector.RemovalDirectionFinderUsingObb(preFastener, BoundingGeometry.OrientedBoundingBoxDic[preFastener]), OverallLength = overalLength, EngagedLength = overalLength, Diameter = BoundingGeometry.BoundingCylinderDic[repeatedSolid].Radius, Certainty = 1.0 }); } } }
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 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) { // 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); }
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); }
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 * { * * }*/ } }