// 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); }
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 }); }