internal static Dictionary <TessellatedSolid, List <PrimitiveSurface> > PrimitiveMaker(List <TessellatedSolid> parts) { Console.WriteLine(); Console.WriteLine("Classifying Primitives for " + parts.Count + " unique parts ...."); var partPrimitive = new Dictionary <TessellatedSolid, List <PrimitiveSurface> >(); int width = 55; int refresh = (int)Math.Ceiling(((float)parts.Count) / ((float)(width))); int check = 0; LoadingBar.start(width, 0); Parallel.ForEach(parts, solid => //foreach (var solid in parts) { if (check % refresh == 0) { LoadingBar.refresh(width, ((float)check) / ((float)parts.Count)); } check++; var solidPrim = solid.ClassifyPrimitiveSurfaces(true); lock (partPrimitive) partPrimitive.Add(solid, solidPrim); } );// LoadingBar.refresh(width, 1); return(partPrimitive); }
internal static void Run( Dictionary <TessellatedSolid, List <PrimitiveSurface> > solidPrimitive, Dictionary <TessellatedSolid, List <TessellatedSolid> > multipleRefs) { // This is mostly similar to the auto fastener detection with no thread, but instead of learning // from the area of the cylinder and for example flat, we will learn from the number of faces. // why? because if we have thread, we will have too many triangles. And this can be useful. // I can also detect helix and use this to detect the threaded fasteners // Important: if the fasteners are threaded using solidworks Fastener toolbox, it will not // have helix. The threads will be small cones with the same axis and equal area. var width = 55; var check = 0; LoadingBar.start(width, 0); var smallParts = FastenerDetector.SmallObjectsDetector(DisassemblyDirectionsWithFastener.PartsWithOneGeom); PreSelectedFastenerToFastenerClass(solidPrimitive, multipleRefs); foreach ( var preSelected in FastenerDetector.PreSelectedFasteners.Where(preSelected => !smallParts.Contains(preSelected))) { smallParts.Add(preSelected); } FastenerDetector.PotentialFastener = new Dictionary <TessellatedSolid, double>(); foreach (var p in smallParts) { FastenerDetector.PotentialFastener.Add(p, 0.1); } var groupedPotentialFasteners = FastenerDetector.GroupingSmallParts(smallParts); var uniqueParts = new HashSet <TessellatedSolid>(); foreach (var s in multipleRefs.Keys.Where(FastenerDetector.PotentialFastener.Keys.Contains)) { uniqueParts.Add(s); } foreach ( var preFastener in FastenerDetector.Fasteners.Where(preFastener => uniqueParts.Contains(preFastener.Solid))) { uniqueParts.Remove(preFastener.Solid); } var equalPrimitivesForEveryUniqueSolid = FastenerDetector.EqualFlatPrimitiveAreaFinder(uniqueParts, solidPrimitive); List <int> learnerVotes; var learnerWeights = FastenerPerceptronLearner.ReadingLearnerWeightsAndVotesFromCsv(out learnerVotes); FastenerGaussianNaiveBayes.GNB(); List <string> nameList = new List <string>(); foreach (var part in uniqueParts) { nameList.Add(part.Name); } float nameRating; float ratingAverage = 0; float ratingMax = -1; float ratingMin = 100000000000; int preCutoff = 0; int postCutoff = 0; PartNameAnalysis.findCommonPreSuffixes(nameList, ref preCutoff, ref postCutoff); foreach (var part in uniqueParts) { nameRating = PartNameAnalysis.SolidHasFastenerKeyword(part, preCutoff, postCutoff); ratingAverage += nameRating; ratingMax = Math.Max(ratingMax, nameRating); ratingMin = Math.Min(ratingMin, nameRating); } float proportion = 1 - (ratingMax - ratingMin) / 3; var refresh = (int)Math.Ceiling((float)uniqueParts.Count / (float)(width * 4)); Parallel.ForEach(uniqueParts, solid => //foreach (var solid in uniqueParts) { if (check % refresh == 0) { LoadingBar.refresh(width, ((float)check) / ((float)uniqueParts.Count)); } check++; var initialCertainty = FastenerGaussianNaiveBayes.GaussianNaiveBayesClassifier(solidPrimitive[solid], solid); nameRating = (PartNameAnalysis.SolidHasFastenerKeyword(solid, preCutoff, postCutoff) - ratingMin) / (0.001f + ratingMax - ratingMin); FastenerDetector.PotentialFastener[solid] = (0.1 + initialCertainty) * proportion + (1 - nameRating) * (1 - proportion); foreach (var up in multipleRefs[solid]) { FastenerDetector.PotentialFastener[up] = (0.1 + initialCertainty) * proportion + (1 - nameRating) * (1 - proportion); } // if a fastener is detected using polynomial trend approach, it is definitely a fastener but not a nut. // if it is detected using any other approach, but not polynomial trend, it is a possible nut. double toolSize; var commonHead = CommonHeadCheck(solid, solidPrimitive[solid], equalPrimitivesForEveryUniqueSolid[solid], out toolSize); if (commonHead != 0) { var newFastener = FastenerPolynomialTrend.PolynomialTrendDetector(solid); if (newFastener != null) { newFastener.ToolSize = toolSize; if (commonHead == 1) { newFastener.Tool = Tool.HexWrench; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } if (commonHead == 2) { newFastener.Tool = Tool.Allen; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } if (commonHead == 3) { newFastener.Tool = Tool.PhillipsBlade; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } if (commonHead == 4) { newFastener.Tool = Tool.FlatBlade; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } if (commonHead == 5) { newFastener.Tool = Tool.PhillipsBlade; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } } else // can be a nut { if (commonHead == 1) { FastenerDetector.Nuts.Add(new Nut { Solid = solid, NutType = NutType.Hex, Tool = Tool.HexWrench, ToolSize = toolSize, OverallLength = BoundingGeometry.BoundingCylinderDic[solid].Length, Certainty = initialCertainty // 0.9 }); foreach (var repeatedSolid in multipleRefs[solid]) { lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(new Nut { Solid = repeatedSolid, NutType = NutType.Hex, Tool = Tool.HexWrench, ToolSize = toolSize, OverallLength = BoundingGeometry.BoundingCylinderDic[solid].Length, Certainty = initialCertainty // 0.9 }); } //continue; return; } } } if (FastenerPerceptronLearner.FastenerPerceptronClassifier(solidPrimitive[solid], solid, learnerWeights, learnerVotes)) { var newFastener = FastenerPolynomialTrend.PolynomialTrendDetector(solid); if (newFastener != null) { lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } // can be a nut // use bounding cylinder to detect nuts. // Since the nuts are small, the OBB function doesnt work accurately for them. // So, I cannot really trust this. var newNut = NutPolynomialTrend.PolynomialTrendDetector(solid); if (newNut != null) // It is a nut with certainty == 1 { lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(newNut); AddRepeatedSolidstoNuts(newNut, multipleRefs[solid]); //continue; return; } // still can be a nut since the upper approach is not really accurate // this 50 percent certainty can go up if the nut is mated with a // detected fastener foreach (var repeatedSolid in multipleRefs[solid]) { lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(new Nut { Solid = repeatedSolid, Diameter = BoundingGeometry.BoundingCylinderDic[solid].Radius * 2.0, // this is approximate OverallLength = BoundingGeometry.BoundingCylinderDic[solid].Length, Certainty = initialCertainty // 0.5 }); } //continue; return; } // if it is not captured by any of the upper methods, give it another chance: if (ThreadDetector(solid, solidPrimitive[solid])) { var newFastener = FastenerPolynomialTrend.PolynomialTrendDetector(solid); if (newFastener != null) { newFastener.FastenerType = FastenerTypeEnum.Bolt; lock (FastenerDetector.Fasteners) FastenerDetector.Fasteners.Add(newFastener); AddRepeatedSolidstoFasteners(newFastener, multipleRefs[solid]); //continue; return; } //if not, it is a nut: foreach (var repeatedSolid in multipleRefs[solid]) { lock (FastenerDetector.Nuts) FastenerDetector.Nuts.Add(new Nut { Solid = repeatedSolid, Diameter = BoundingGeometry.BoundingCylinderDic[solid].Radius * 2.0, // this is approximate OverallLength = BoundingGeometry.BoundingCylinderDic[solid].Length * 2.0, Certainty = initialCertainty // 0.5 }); } } } ); // // now use groupped small objects: AutoNonthreadedFastenerDetection.ConnectFastenersNutsAndWashers(groupedPotentialFasteners); LoadingBar.refresh(width, 1); }
internal static void Run( Dictionary <TessellatedSolid, List <PrimitiveSurface> > solidPrimitive, Dictionary <TessellatedSolid, List <TessellatedSolid> > multipleRefs) { // This approach will use the symmetric shape of the fasteners' heads. If there is no thread, // we willl consider the area of the positive culinders for bolts and negative cylinder for // nuts. // This is an important point: // 1. Find the small objects using all of the solids // 2. Group them using small objects // 3. Detect the fasteners using multiple references. (for each similar object, detect one of them) var width = 55; var check = 0; LoadingBar.start(width, 0); var smallParts = FastenerDetector.SmallObjectsDetector(DisassemblyDirectionsWithFastener.PartsWithOneGeom); //new List<TessellatedSolid>(DisassemblyDirectionsWithFastener.PartsWithOneGeom); PreSelectedFastenerToFastenerClass(solidPrimitive, multipleRefs); foreach ( var preSelected in FastenerDetector.PreSelectedFasteners.Where(preSelected => !smallParts.Contains(preSelected))) { smallParts.Add(preSelected); } FastenerDetector.PotentialFastener = new Dictionary <TessellatedSolid, double>(); foreach (var p in smallParts) { FastenerDetector.PotentialFastener.Add(p, 0.1); } var groupedPotentialFasteners = FastenerDetector.GroupingSmallParts(smallParts); var uniqueParts = new HashSet <TessellatedSolid>(); foreach (var s in multipleRefs.Keys.Where(FastenerDetector.PotentialFastener.Keys.Contains)) { uniqueParts.Add(s); } foreach ( var preFastener in FastenerDetector.Fasteners.Where(preFastener => uniqueParts.Contains(preFastener.Solid))) { uniqueParts.Remove(preFastener.Solid); } var equalPrimitivesForEveryUniqueSolid = FastenerDetector.EqualFlatPrimitiveAreaFinder(uniqueParts, solidPrimitive); var checkedSolids = new HashSet <TessellatedSolid>(); FastenerGaussianNaiveBayes.GNB(); List <string> nameList = new List <string>(); foreach (var part in uniqueParts) { nameList.Add(part.Name); } float nameRating; float ratingAverage = 0; float ratingMax = -1; float ratingMin = 100000000000; int preCutoff = 0; int postCutoff = 0; PartNameAnalysis.findCommonPreSuffixes(nameList, ref preCutoff, ref postCutoff); foreach (var part in uniqueParts) { nameRating = PartNameAnalysis.SolidHasFastenerKeyword(part, preCutoff, postCutoff); ratingAverage += nameRating; ratingMax = Math.Max(ratingMax, nameRating); ratingMin = Math.Min(ratingMin, nameRating); } float proportion = 1 - (ratingMax - ratingMin) / 3; var refresh = (int)Math.Ceiling((float)uniqueParts.Count / (float)(width * 4)); Parallel.ForEach(uniqueParts, solid => //foreach (var solid in uniqueParts) { if (check % refresh == 0) { LoadingBar.refresh(width, ((float)check) / ((float)uniqueParts.Count)); } check++; var initialCertainty = FastenerGaussianNaiveBayes.GaussianNaiveBayesClassifier(solidPrimitive[solid], solid); nameRating = (PartNameAnalysis.SolidHasFastenerKeyword(solid, preCutoff, postCutoff) - ratingMin) / (0.001f + ratingMax - ratingMin); FastenerDetector.PotentialFastener[solid] = (0.1 + initialCertainty) * proportion + (1 - nameRating) * (1 - proportion); foreach (var up in multipleRefs[solid]) { FastenerDetector.PotentialFastener[up] = (0.1 + initialCertainty) * proportion + (1 - nameRating) * (1 - proportion); } if (solidPrimitive[solid].Count == 0) { return; } if (HexBoltNutAllen(solid, solidPrimitive[solid], equalPrimitivesForEveryUniqueSolid[solid], multipleRefs[solid])) { //continue; lock (checkedSolids) { checkedSolids.Add(solid); } return; } if (PhillipsHeadBolt(solid, solidPrimitive[solid], equalPrimitivesForEveryUniqueSolid[solid], multipleRefs[solid])) { //continue; lock (checkedSolids) { checkedSolids.Add(solid); } return; } if (SlotHeadBolt(solid, solidPrimitive[solid], equalPrimitivesForEveryUniqueSolid[solid], multipleRefs[solid])) { //continue; lock (checkedSolids) { checkedSolids.Add(solid); } return; } if (PhillipsSlotComboHeadBolt(solid, solidPrimitive[solid], equalPrimitivesForEveryUniqueSolid[solid], multipleRefs[solid])) { //continue; lock (checkedSolids) { checkedSolids.Add(solid); } return; } lock (checkedSolids) { checkedSolids.Add(solid); } } );// // when all of the fasteners are recognized, it's time to check the third level filter: // something is not acceptable: nut without fastener. If there is a nut without fastener, // I will try to look for that. // Is there anyway to detect more? ConnectFastenersNutsAndWashers(groupedPotentialFasteners); LoadingBar.refresh(width, 1); }
// This class is added as an alternative for current Nonadjacent blocking determination approach. // The overal approach is the same as before (ray shooting), but number of both rays and blocking // triangles are droped to speedup the function. // Rays: Instead of checking blockings for every direction, for every two parts, their possible // blocking directions are found based upon the planes that can seperate the two CVHs linearlly. // (If the CVHs are not linearly seperable we cannot apply this.) // Triangles: Number of triangles (of the blocking solid) is the most affecting factor in blocking // determination. Code gets really really slow when it goes to check intersection of the ray // and all the triangles of the solid. We are avoiding this problem here by partitionaning // our search space into k number of sections obtained originally from OBB of the solid. internal static void Run(designGraph graph, Dictionary <string, List <TessellatedSolid> > subAssems, List <int> gDir) { Console.WriteLine("\n\nNonadjacent Blocking Determination is running ...."); long totalCases = 0; var subAssemsToList = subAssems.ToList(); for (var i = 0; i < subAssems.Count - 1; i++) { var subAssem1 = subAssemsToList[i]; for (var j = i + 1; j < subAssems.Count; j++) { var subAssem2 = subAssemsToList[j]; var tri2Sub1 = subAssem1.Value.Sum(s => s.Faces.Length); var tri2Sub2 = subAssem2.Value.Sum(s => s.Faces.Length); totalCases += tri2Sub1 * tri2Sub2; } } ObbFacesHashSet = new Dictionary <TessellatedSolid, HashSet <PolygonalFace> >(); CombinedCVHForMultipleGeometries = new Dictionary <string, TVGLConvexHull>(); long counter = 0; foreach (var subAssem in subAssems) { List <BoundingBox> pairList = new List <BoundingBox>(); foreach (var s in subAssem.Value) { //CvhHashSet.Add(s, new HashSet<PolygonalFace>(s.ConvexHull.Faces)); //$ What was used previously /* * ObbFacesHashSet.Add(s, * new HashSet<PolygonalFace>( * PartitioningSolid.TwelveFaceGenerator( * BoundingGeometry.OrientedBoundingBoxDic.First(b=> b.Key.Name == s.Name).Value.CornerVertices.Select( * cv => new Vertex(cv.Position)).ToArray()))); */ KeyValuePair <TessellatedSolid, BoundingBox> pair = BoundingGeometry.OrientedBoundingBoxDic.FirstOrDefault(b => b.Key.Name == s.Name); if (!pair.Equals(default(KeyValuePair <TessellatedSolid, BoundingBox>))) { ObbFacesHashSet.Add(s, new HashSet <PolygonalFace>(PartitioningSolid.TwelveFaceGenerator(pair.Value.CornerVertices.Select(cv => new Vertex(cv.Position)).ToArray()))); } } } CreateCombinedCVHs(subAssems); var solidsL = subAssems.ToList(); int width = 55; int total = (solidsL.Count + 1) * (solidsL.Count / 2); int refresh = (int)Math.Ceiling(((float)total) / ((float)(width))); int check = 0; LoadingBar.start(width, 0); for (var i = 0; i < solidsL.Count; i++) { var solidMoving = solidsL[i].Value; for (var j = i + 1; j < solidsL.Count; j++) { if (check % refresh == 0) { LoadingBar.refresh(width, ((float)check) / ((float)total)); } check++; var blocked = false; // check the convex hull of these two solids to find the planes tha can linearly seperate them // solid1 is moving and solid2 is blocking var solidBlocking = solidsL[j].Value; counter += solidMoving.Sum(s => s.Faces.Length) * solidBlocking.Sum(s => s.Faces.Length); if ( graph.arcs.Any( a => a is Connection && ((a.From.name == solidsL[i].Key && a.To.name == solidsL[j].Key) || (a.From.name == solidsL[j].Key && a.To.name == solidsL[i].Key)))) { continue; } // Add a secondary arc to the var from = GetNode(graph, solidsL[i].Key); var to = GetNode(graph, solidsL[j].Key); graph.addArc(from, to, from.name + to.name, typeof(SecondaryConnection)); var lastAddedSecArc = (SecondaryConnection)graph.arcs.Last(); var filteredDirections = FilterGlobalDirections(solidMoving, solidBlocking, gDir); var oppositeFiltrdDirs = filteredDirections.Select(d => DisassemblyDirections.DirectionsAndOppositsForGlobalpool[d]).ToList(); // remember this: if solid2 is not blocking solid1, we need to check if solid1 is blocking 2 in the opposite direction. // if filteredDirections.Count == gDir.Count then the CVHs overlap // Only directions need to be checked which the moving part can move along them: var scndFilteredDirectionsMoving = FinalSetOfDirectionsFinder(graph, solidMoving, filteredDirections); var scndFilteredDirectionsBlocking = new List <int>(); scndFilteredDirectionsBlocking = FinalSetOfDirectionsFinder(graph, solidBlocking, filteredDirections.Count == gDir.Count ? filteredDirections : oppositeFiltrdDirs); foreach ( var d in scndFilteredDirectionsMoving.Where( d => !scndFilteredDirectionsBlocking.Contains( DisassemblyDirections.DirectionsAndOppositsForGlobalpool[d]))) { scndFilteredDirectionsBlocking.Add(DisassemblyDirections.DirectionsAndOppositsForGlobalpool[d]); } foreach ( var d in scndFilteredDirectionsBlocking.Where( d => !scndFilteredDirectionsMoving.Contains( DisassemblyDirections.DirectionsAndOppositsForGlobalpool[d]))) { scndFilteredDirectionsMoving.Add(DisassemblyDirections.DirectionsAndOppositsForGlobalpool[d]); } if (filteredDirections.Count == gDir.Count) { //continue; Parallel.ForEach(scndFilteredDirectionsMoving, filtDir => //foreach (var filtDir in filteredDirections) { var direction = DisassemblyDirections.Directions[filtDir]; blocked = BlockingDeterminationWithCvhOverlapping(direction, solidMoving, solidBlocking); if (blocked) { lock (lastAddedSecArc.Directions) lastAddedSecArc.Directions.Add(filtDir); if ( scndFilteredDirectionsBlocking.Contains( DisassemblyDirections.DirectionsAndOppositsForGlobalpool[filtDir])) { scndFilteredDirectionsBlocking.Remove( DisassemblyDirections.DirectionsAndOppositsForGlobalpool[filtDir]); } } }); Parallel.ForEach(scndFilteredDirectionsBlocking, filtDir => //foreach (var filtDir in filteredDirections) { var direction = DisassemblyDirections.Directions[filtDir]; blocked = BlockingDeterminationWithCvhOverlapping(direction, solidBlocking, solidMoving); if (blocked) { lock (lastAddedSecArc.Directions) lastAddedSecArc.Directions.Add(DisassemblyDirections.DirectionsAndOppositsForGlobalpool[filtDir]); } }); if (lastAddedSecArc.Directions.Count == 0) { graph.removeArc(lastAddedSecArc); } } else { //continue; // If CVHs dont overlap: //$ Made this non-parallel for debugging purposes - switch back later Parallel.ForEach(scndFilteredDirectionsMoving, filtDir => //foreach (var filtDir in filteredDirections) { var direction = DisassemblyDirections.Directions[filtDir]; blocked = BlockingDeterminationNoCvhOverlapping(direction, solidMoving, solidBlocking); if (blocked) { lock (lastAddedSecArc.Directions) lastAddedSecArc.Directions.Add(filtDir); if ( scndFilteredDirectionsBlocking.Contains( DisassemblyDirections.DirectionsAndOppositsForGlobalpool[filtDir])) { scndFilteredDirectionsBlocking.Remove( DisassemblyDirections.DirectionsAndOppositsForGlobalpool[filtDir]); } } }); Parallel.ForEach(scndFilteredDirectionsBlocking, filtDir => //foreach (var filtDir in filteredDirections) { var direction = DisassemblyDirections.Directions[filtDir]; blocked = BlockingDeterminationNoCvhOverlapping(direction, solidBlocking, solidMoving); if (blocked) { lock (lastAddedSecArc.Directions) lastAddedSecArc.Directions.Add(DisassemblyDirections.DirectionsAndOppositsForGlobalpool[filtDir]); } }); if (lastAddedSecArc.Directions.Count == 0) { graph.removeArc(lastAddedSecArc); } } } } LoadingBar.refresh(width, 1); CreateSameDirectionDictionary(gDir); }
internal static void CreatePartitions(Dictionary <string, List <TessellatedSolid> > solids) { Console.WriteLine("\nUpdating Bounding Geometries ...."); int width = 55; int refresh = (int)Math.Ceiling(((float)solids.Count) / ((float)(width * 4))); int check = 0; LoadingBar.start(width, 0); var solidGeometries = solids.SelectMany(s => s.Value).ToList(); var solidGeometries2 = Program.Solids.SelectMany(s => s.Value).ToList(); var totalVerts = solidGeometries.Sum(s => s.Vertices.Count()); foreach (var solid in solidGeometries) //Parallel.ForEach(solidGeometries, solid => { if (check % refresh == 0) { LoadingBar.refresh(width, ((float)check) / ((float)solidGeometries.Count)); } check++; //solid.SimplifyByPercentage(0.5); /*Partition[] prtn; * * for () * { * * }*/ BoundingBox bad = new BoundingBox(); BoundingBox val = bad; Partition[] prtn = new Partition[0]; foreach (KeyValuePair <TessellatedSolid, BoundingBox> b in BoundingGeometry.OrientedBoundingBoxDic) { if (b.Key.Name == solid.Name) { val = b.Value; } } if (!val.Equals(bad)) { prtn = Run(new HashSet <Vertex>(solid.Vertices), new HashSet <PolygonalFace>(solid.Faces), val.CornerVertices.Select(cv => new Vertex(cv.Position)).ToArray()); } else { //$ Removing this check for now //string err = "A bounding box was not found"; //throw new SystemException(err); } /* * prtn = Run(new HashSet<Vertex>(solid.Vertices), new HashSet<PolygonalFace>(solid.Faces), * BoundingGeometry.OrientedBoundingBoxDic.First(b=>b.Key.Name == solid.Name).Value.CornerVertices.Select( * cv => new Vertex(cv.Position)).ToArray());*/ //lock (Partitions) //{ Partitions.Add(solid, prtn); //} }//); // partition of AABB: Parallel.ForEach(solidGeometries2, solid => { var cornerVer = new[] { new Vertex(new [] { solid.XMin, solid.YMin, solid.ZMin }), new Vertex(new [] { solid.XMin, solid.YMin, solid.ZMax }), new Vertex(new [] { solid.XMin, solid.YMax, solid.ZMin }), new Vertex(new [] { solid.XMin, solid.YMax, solid.ZMax }), new Vertex(new [] { solid.XMax, solid.YMin, solid.ZMin }), new Vertex(new [] { solid.XMax, solid.YMin, solid.ZMax }), new Vertex(new [] { solid.XMax, solid.YMax, solid.ZMin }), new Vertex(new [] { solid.XMax, solid.YMax, solid.ZMax }), }; var prtn = RunForAABB(new HashSet <Vertex>(solid.Vertices), new HashSet <PolygonalFace>(solid.Faces), cornerVer); lock (PartitionsAABB) { PartitionsAABB.Add(solid, prtn); } });// 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 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); }