// Idea:
        //   1. Take the OBB
        //   2. Take every side (3 sides)
        //   3. The center of each side with its normal, create the centerline of the cylinder.
        //   4. The distance of the farthest vertex from the center line is the radius.
        //   5. Three different cylinders, with three different volumes. The cylinder with
        //      smallest volume is the bounding cylinder
        public static BoundingCylinder Run(TessellatedSolid solid)
        {
            var threeSides = ThreeSidesOfTheObb(solid);
            var bC         = new BoundingCylinder();
            var minVolume  = double.PositiveInfinity;

            foreach (var side in threeSides)
            {
                // every side will create a seperate bounding cylinder
                var faceCenters = FaceCenterFinder(side.Key);
                // Now I have the center, I have the vector of the centerline and also the length
                // find the radius:
                var radius = RadiusOfBoundingCylinder(solid, faceCenters, side.Key.Normal);
                var volume = Math.PI * Math.Pow(radius, 2.0) * side.Value;
                if (volume >= minVolume)
                {
                    continue;
                }
                minVolume               = volume;
                bC.CenterLineVector     = side.Key.Normal.multiply(-1.0);
                bC.PointOnTheCenterLine = faceCenters;
                bC.PerpVector           = (side.Key.Vertices[0].Position.subtract(faceCenters)).normalize();
                bC.Radius               = radius;
                bC.Length               = side.Value;
                bC.Volume               = volume;
            }
            return(bC);
        }
        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);
        }
        private static List <double[]> KpointObMidSurfaceOfCylinderGenerator(BoundingCylinder bC, int k)
        {
            var points   = new List <double[]>();
            var tt       = new[] { 0.0, Math.PI / 2, Math.PI, Math.PI * 3 / 4.0, 2 * Math.PI };
            var stepSize = (2 * Math.PI) / (k + 1);
            var n        = bC.CenterLineVector;
            var u        = bC.PerpVector;
            var r        = bC.Radius;

            for (var i = 0.0; i < 2 * Math.PI; i += stepSize)
            {
                points.Add((((u.multiply(r * Math.Cos(i))).add((n.crossProduct(u)).multiply(r * Math.Sin(i)))).add(
                                bC.PointOnTheCenterLine)));
            }
            return(points);
        }
Example #4
0
        internal static void CreateBoundingCylinder(Dictionary <string, List <TessellatedSolid> > solids)
        {
            // This function uses my own OBB code not the one in TVGL
            // It has more accurate results
            //var s = new Stopwatch();
            //s.Start();
            //Console.WriteLine();
            //Console.WriteLine("Bounding Cylinders are being Created ...");
            var solidGeometries = solids.SelectMany(s => s.Value).ToList();

            Parallel.ForEach(solidGeometries, solid =>
            {
                var bc = BoundingCylinder.Run(solid);
                lock (BoundingCylinderDic)
                {
                    BoundingCylinderDic.Add(solid, bc);
                }
            }
                             );
            //s.Stop();
            //Console.WriteLine("Bounding Cylinder Creation is done in:" + "     " + s.Elapsed);
        }
        private static List <double>[] PointToSolidDistanceCalculator(TessellatedSolid solid, List <double[]> kPointsOnSurface, BoundingCylinder bC, double section)
        {
            var distListOuter = new List <double>();
            var distListInner = new List <double>();
            var met           = bC.CenterLineVector.multiply(bC.Length * section);

            kPointsOnSurface =
                kPointsOnSurface.Select(p => p.add(met)).ToList();
            foreach (var point in kPointsOnSurface)
            {
                var rayVector   = (bC.PointOnTheCenterLine.add(met)).subtract(point);
                var ray         = new Ray(new Vertex(point), rayVector);
                var minDisOuter = double.PositiveInfinity;
                var minDisInner = double.PositiveInfinity;
                foreach (var face in solid.Faces)
                {
                    double[] hittingPoint;
                    bool     outerTriangle;
                    if (!GeometryFunctions.RayIntersectsWithFace(ray, face, out hittingPoint, out outerTriangle))
                    {
                        continue;
                    }
                    var dis = GeometryFunctions.DistanceBetweenTwoVertices(hittingPoint, point);
                    if (outerTriangle)
                    {
                        if (dis < minDisOuter)
                        {
                            minDisOuter = dis;
                        }
                    }
                    else
                    {
                        if (dis < minDisInner)
                        {
                            minDisInner = dis;
                        }
                    }
                }
                if (!double.IsPositiveInfinity(minDisOuter))
                {
                    distListOuter.Add(minDisOuter);
                }
                if (!double.IsPositiveInfinity(minDisInner))
                {
                    distListInner.Add(minDisOuter);
                }
            }
            // Normalizing:
            var longestDis1 = distListOuter.Max();
            var distanceToOuterTriangles = distListOuter.Select(d => d / longestDis1).ToList();
            var longestDis2 = distListInner.Max();
            var distanceToInnerTriangles = distListInner.Select(d => d / longestDis2).ToList();

            return(new[] { distanceToOuterTriangles, distanceToInnerTriangles });
        }