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);
        }
 internal NutBoundingCylinderPartition(TessellatedSolid solid, int numberOfPartitions)
 {
     this.NumberOfPartitions = numberOfPartitions;
     this.Solid = solid;
     Vertex[] startingVerts;
     double[] partnCreationVect;
     var faceFromObbSide = GeometryFunctions.BoundingCylindertoFaceOnObbRespectiveSide(solid, out startingVerts, out partnCreationVect);
     this.Partitions = CreatePartitions(startingVerts, partnCreationVect, this.NumberOfPartitions);
     FastenerBoundingBoxPartition.SolidTrianglesOfPartitions(this.Partitions, solid, faceFromObbSide);
 }
        internal static List <double> PointToSolidDistanceCalculatorWithPartitioning(TessellatedSolid solid,
                                                                                     List <FastenerAndNutPartition> partitions, List <double[]> kPointsBetweenMidPoints, double[] vector,
                                                                                     out double longestDist)
        {
            var distList = new List <double>();

            foreach (var point in kPointsBetweenMidPoints)
            {
                var ray    = new Ray(new Vertex(point), vector);
                var minDis = double.PositiveInfinity;
                var prtn   = FastenerBoundingBoxPartition.PartitionOfThePoint(partitions, point);
                foreach (var face in prtn.FacesOfSolidInPartition)
                {
                    double[] hittingPoint;
                    bool     outer;
                    if (!GeometryFunctions.RayIntersectsWithFace(ray, face, out hittingPoint, out outer) || !outer)
                    {
                        continue;
                    }
                    var dis = GeometryFunctions.DistanceBetweenTwoVertices(hittingPoint, point);
                    if (dis < minDis)
                    {
                        minDis = dis;
                    }
                }
                if (minDis != double.PositiveInfinity)
                {
                    distList.Add(minDis);
                }
            }
            // Normalizing:
            var longestDis = distList.Max();

            longestDist = longestDis;
            return(distList.Select(d => d / longestDis).ToList());
        }