internal static Gear PolynomialTrendDetector(TessellatedSolid solid)
        {
            // Since gears have different shapes, we need to generate bounding circles in multiple locations
            // around the gear (bounding cylinde). If any of them are showing a gear, return true.
            // This makes the code really slow.
            // To also find negative (internal) gears:
            //   1. if the closest with negative dot product triangles to bounding cylinder points, it is a positive gear
            //   2. if the closest with positive dot product triangles to bounding cylinder points, it is a negative gear
            var section          = 5.0;
            var bC               = BoundingCylinder.Run(solid);
            var kPointsOnSurface = KpointObMidSurfaceOfCylinderGenerator(bC, 1000);

            for (var i = 0.0; i <= 1; i += 1 / section)
            {
                var distancePointToSolidPositive = PointToSolidDistanceCalculator(solid, kPointsOnSurface, bC, i);
                // in the distance point to solid array, first one  is for outer triangle (general case)
                // the second one is for inner triangle (written for negative gears)
                List <int> originalInds;
                distancePointToSolidPositive[0] =
                    FastenerPolynomialTrend.MergingEqualDistances(distancePointToSolidPositive[0], out originalInds, 0.001);
                //FastenerPolynomialTrend.PlotInMatlab(distancePointToSolidPositive[0]);
                if (IsGear(distancePointToSolidPositive[0]))
                {
                    return new Gear
                           {
                               Solid               = solid,
                               PointOnAxis         = bC.PointOnTheCenterLine,
                               Axis                = bC.CenterLineVector,
                               LargeCylinderRadius = bC.Radius,
                               SmallCylinderRadius = bC.Radius - TeethDepthFinder(distancePointToSolidPositive[0])
                           }
                }
                ;
                // check and see if it is an inner gear
                List <int> originalInds2;
                distancePointToSolidPositive[1] =
                    FastenerPolynomialTrend.MergingEqualDistances(distancePointToSolidPositive[1], out originalInds2, 0.001);
                if (IsGear(distancePointToSolidPositive[1]))
                {
                    return new Gear
                           {
                               Solid               = solid,
                               Type                = GearType.Internal,
                               PointOnAxis         = bC.PointOnTheCenterLine,
                               Axis                = bC.CenterLineVector,
                               LargeCylinderRadius = bC.Radius,
                               SmallCylinderRadius = bC.Radius - TeethDepthFinder(distancePointToSolidPositive[0])
                           }
                }
                ;
            }
            return(null);
        }
Beispiel #2
0
        internal static Nut PolynomialTrendDetector(TessellatedSolid solid)
        {
            // first create the bounding cylinder.
            // then from the centerline of the cylinder, shoot rays.
            var       bCy = BoundingGeometry.BoundingCylinderDic[solid];
            const int k   = 500;

            // I can do the same thing I did for FastenerPolynomial to speed up the code.
            // To create the sections, they need to be created based on the OBB, then use it in
            // bounding cylinder.
            var partitions = new NutBoundingCylinderPartition(solid, 50);

            var secondPoint             = bCy.PointOnTheCenterLine.add(bCy.CenterLineVector.multiply(bCy.Length));
            var kPointsBetweenMidPoints = FastenerPolynomialTrend.KpointBtwPointsGenerator(bCy.PointOnTheCenterLine, secondPoint, k);

            double longestDist;
            var    distancePointToSolid = FastenerPolynomialTrend.PointToSolidDistanceCalculatorWithPartitioning(solid,
                                                                                                                 partitions.Partitions, kPointsBetweenMidPoints, bCy.PerpVector, out longestDist);

            // one more step: Merge points with equal distances.
            List <int> originalInds;

            distancePointToSolid = FastenerPolynomialTrend.MergingEqualDistances(distancePointToSolid, out originalInds, 0.001);
            int numberOfThreads;

            int[] threadStartEndPoints;
            if (FastenerPolynomialTrend.ContainsThread(distancePointToSolid, out numberOfThreads, out threadStartEndPoints))
            {
                return(new Nut
                {
                    Solid = solid,
                    NumberOfThreads = numberOfThreads,
                    OverallLength = bCy.Length,
                    Diameter = bCy.Radius * 2,
                    Certainty = 1.0
                });
            }
            // Plot:
            //if (hasThread)
            //FastenerPolynomialTrend.PlotInMatlab(distancePointToSolid);
            return(null);
        }
        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);
        }
Beispiel #4
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
             });
         }
     }
 }
Beispiel #5
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 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);
        }