public static double CheckStabilityForReference(SubAssembly newSubAsm, FootprintFace f) { var refCOM = newSubAsm.Install.Reference.CenterOfMass; CenterOfMassProjectionOnFootprintFace(f, refCOM); f.MinDisNeaEdg = double.PositiveInfinity; var x02 = f.COMP.Position[0]; var y02 = f.COMP.Position[1]; var z02 = f.COMP.Position[2]; f.Height = Math.Sqrt(Math.Pow(x02 - refCOM.Position[0], 2) + Math.Pow(y02 - refCOM.Position[1], 2) + Math.Pow(z02 - refCOM.Position[2], 2)); foreach (var edge in f.OuterEdges) { var edgeVector = edge.From.Position.subtract(edge.To.Position).normalize(); var distanceOfEdgeToComProj = GeometryFunctions.DistanceBetweenLineAndVertex(edgeVector, edge.From.Position, f.COMP.Position); if (distanceOfEdgeToComProj < f.MinDisNeaEdg) { f.MinDisNeaEdg = distanceOfEdgeToComProj; f.IsComInsideFace = IsTheProjectionInsideOfTheFace(f, edge); } } var spf = Math.Pow(((2 / Math.PI) * (Math.Atan(f.Height / f.MinDisNeaEdg))), 2); f.RefS = spf; return(f.RefS); }
private static double DetermineDistanceToSeparateHull(SubAssembly newSubAsm, Double[] insertionDirection) { var refMaxValue = GeometryFunctions.FindMaxPlaneHeightInDirection(newSubAsm.Install.Reference.CVXHull.Vertices, insertionDirection); var refMinValue = GeometryFunctions.FindMinPlaneHeightInDirection(newSubAsm.Install.Reference.CVXHull.Vertices, insertionDirection); var movingMaxValue = GeometryFunctions.FindMaxPlaneHeightInDirection(newSubAsm.Install.Moving.CVXHull.Vertices, insertionDirection); var movingMinValue = GeometryFunctions.FindMinPlaneHeightInDirection(newSubAsm.Install.Moving.CVXHull.Vertices, insertionDirection); var distanceToFree = Math.Abs(refMaxValue - movingMinValue); if (distanceToFree < 0) { distanceToFree = 0; throw new Exception("How is distance to free less than zero?"); } return(distanceToFree + (movingMaxValue - movingMinValue) + (refMaxValue - refMinValue)); }
private static bool IsTheLocalDirectionFinite(List <TessellatedSolid> blockingSubAssem, List <Ray> rays) { var fin = false; Parallel.ForEach(rays, (ray, state) => //foreach (var ray in rays) { foreach (var blockingSolid in blockingSubAssem) { var memoFace = new HashSet <PolygonalFace>(); var affectedPartitions = NonadjacentBlockingWithPartitioning.AffectedPartitionsWithRayCvhOverlaps( PartitioningSolid.Partitions[blockingSolid], ray); foreach (var prtn in affectedPartitions) { foreach (var t in prtn.SolidTriangles.Where(t => !memoFace.Contains(t))) { memoFace.Add(t); if (GeometryFunctions.RayIntersectsWithFaceFinInf(ray, t)) { //return true; fin = true; state.Stop(); } } } } }); //return false; return(fin); }
internal static List <double> PointToSolidDistanceCalculator(TessellatedSolid solid, 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; foreach (var face in solid.Faces) { 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()); }
private static bool DontConcexHullsOverlapNonAdjacent(List <Ray> rays, TessellatedSolid solidBlocking) { var overlap = false; foreach (var ray in rays) { if (solidBlocking.ConvexHull.Faces.Any(f => GeometryFunctions.RayIntersectsWithFace(ray, f))) //now find the faces that intersect with the ray and find the distance between them { foreach ( var blockingPolygonalFace in solidBlocking.Faces.Where(f => GeometryFunctions.RayIntersectsWithFace(ray, f)).ToList()) { var d = GeometryFunctions.DistanceBetweenVertexAndPlane(ray.Position, blockingPolygonalFace); //if (d < distanceToTheClosestFace) distanceToTheClosestFace = d; if (d < 0) { continue; } overlap = true; break; } if (overlap) { break; } } } return(overlap); }
private static bool ConvexHullOverlappNonAdjacent(List <Ray> rays, TessellatedSolid solid, TessellatedSolid solidBlocking, double[] direction) { var boo = false; foreach (var ray in rays) { foreach ( var blockingPolygonalFace in solidBlocking.Faces.Where(f => GeometryFunctions.RayIntersectsWithFace(ray, f)).ToList()) { var d = GeometryFunctions.DistanceBetweenVertexAndPlane(ray.Position, blockingPolygonalFace); //if (d < distanceToTheClosestFace) distanceToTheClosestFace = d; if (d < 0) { continue; } boo = true; break; } if (boo) { var blocked = _2DProjectionCheck(solid, solidBlocking, direction); if (!blocked) { boo = false; } break; } } return(boo); }
internal static void FiniteDirectionsBetweenConnectedParts(TessellatedSolid solid1, TessellatedSolid solid2, List <int> localDirInd, out List <int> finDirs, out List <int> infDirs) { // solid1 is Reference and solid2 is Moving finDirs = new List <int>(); infDirs = new List <int>(); foreach (var dir in localDirInd) { var direction = DisassemblyDirections.Directions[dir]; var rays = new List <Ray>(); foreach (var vertex in solid2.ConvexHull.Vertices) { rays.Add(new Ray(new Vertex(new[] { vertex.Position[0], vertex.Position[1], vertex.Position[2] }), new[] { direction[0], direction[1], direction[2] })); } var direction2 = DisassemblyDirections.Directions[dir].multiply(-1.0); var rays2 = new List <Ray>(); foreach (var vertex in solid1.ConvexHull.Vertices) { rays2.Add(new Ray(new Vertex(new[] { vertex.Position[0], vertex.Position[1], vertex.Position[2] }), new[] { direction2[0], direction2[1], direction2[2] })); } if (rays.Any(ray => solid1.Faces.Any(f => GeometryFunctions.RayIntersectsWithFace(ray, f) && GeometryFunctions.DistanceBetweenVertexAndPlane(ray.Position, f) > 0))) { finDirs.Add(dir); } else if (rays2.Any(ray => solid2.Faces.Any(f => GeometryFunctions.RayIntersectsWithFace(ray, f) && GeometryFunctions.DistanceBetweenVertexAndPlane(ray.Position, f) > 0))) { finDirs.Add(dir); } else { infDirs.Add(dir); } } }
private static int RemovalDirectionFinderForAllenHexPhillips(List <Flat> flatPrims, BoundingBox solid) { // This function works for hex bolt, alle, philips and phillips and slot combo // For slot, it will be different var normalGuess = NormalGuessFinder(flatPrims); var equInDirections = DisassemblyDirections.Directions.Where(d => Math.Abs(d.dotProduct(normalGuess) - 1) < 0.01).ToList()[0]; // find the furthest vertex (b) to a vertex (a) from allen faces. if // Normal.dotproduct(a-b) must be positive. If it was negative, return // multiply(-1) var a = flatPrims[0].Vertices[0]; var farthestVer = flatPrims[0].Vertices[0]; var dist = 0.0; foreach (var ver in solid.CornerVertices) { var locDist = GeometryFunctions.DistanceBetweenTwoVertices(a.Position, ver.Position); if (locDist <= dist) { continue; } farthestVer = new Vertex(ver.Position); dist = locDist; } var reference = a.Position.subtract(farthestVer.Position); if (normalGuess.dotProduct(reference) > 0) { return(DisassemblyDirections.Directions.IndexOf(equInDirections)); } return(DisassemblyDirections.Directions.IndexOf(equInDirections.multiply(-1.0))); }
internal static double[] FastenerEngagedLengthAndRadiusNoThread(TessellatedSolid solid, List <PrimitiveSurface> solidPrim) { // the length and the radius of the longest cylinder //if (!solidPrim.Any(p => p is Cylinder)) // throw new Exception("the fastener does not have any cylinder"); //[0] = length, [1] = radius if (!solidPrim.Any(p => p is Cylinder)) { return new[] { BoundingGeometry.BoundingCylinderDic[solid].Length, BoundingGeometry.BoundingCylinderDic[solid].Radius } } ; Cylinder longestCyl = null; var length = double.NegativeInfinity; foreach (Cylinder cylinder in solidPrim.Where(p => p is Cylinder)) { var medLength = GeometryFunctions.SortedEdgeLengthOfTriangle(cylinder.Faces[0])[1]; if (medLength <= length) { continue; } length = medLength; longestCyl = cylinder; } return(new[] { length, longestCyl.Radius }); }
private static bool RayIntersectsCVHOverlap(Partition[] partitions, Ray ray) { var memoFace = new HashSet <PolygonalFace>(); var affectedPartitions = AffectedPartitionsWithRayCvhOverlapsNABD(partitions, ray); foreach (var prtn in affectedPartitions) { if (prtn.InnerPartition != null) { RayIntersectsCVHOverlap(prtn.InnerPartition, ray); } foreach (var tri in prtn.SolidTriangles.Where(t => !memoFace.Contains(t))) { memoFace.Add(tri); if (!GeometryFunctions.RayIntersectsWithFaceNABD(ray, tri)) { continue; } return(true); } } return(false); //if (!NonadjacentBlockingDetermination._2DProjectionCheck(solidMoving, solidBlocking, direction)) // boo = false; }
internal static Gear GearDetectorEstimate(TessellatedSolid solid, List <PrimitiveSurface> solidPrimitives) { var flats = solidPrimitives.Where( p => p is Flat && p.Faces.Count > BoltAndGearConstants.TriabglesInTheGearSideFaces).ToList(); foreach (var flatPrim in flats) { var outerGearEdges = GearEdge.FromTVGLEdgeClassToGearEdgeClass(flatPrim.OuterEdges); var patches = SortedConnectedPatches(outerGearEdges); foreach (var patch in patches) { var cluster = new List <GearEdge> [2]; var newPatch = new List <GearEdge>(); if (ClusteringDenseAndSparseEdges.ContainsDense(patch)) { cluster = ClusteringDenseAndSparseEdges.ClusteringDenseSparse(patch); } if (cluster[0] != null && cluster[1].Count > BoltAndGearConstants.AcceptableNumberOfDenseEdges) { newPatch = ClusteringDenseAndSparseEdges.ReplacingDenseEdges(patch, cluster); } var crossP = new List <double[]>(); if (newPatch.Count == 0) { newPatch = patch; } for (var i = 0; i < newPatch.Count - 1; i++) { var cross = new[] { 0.0, 0, 0 }; var vec1 = newPatch[i].Vector.normalize(); var vec2 = newPatch[i + 1].Vector.normalize(); if (SmoothAngle(vec1, vec2)) { continue; } cross = vec1.crossProduct(vec2); crossP.Add(cross); } if (crossP.Count < 10) { continue; } var crossSign = GeometryFunctions.ConvertCrossProductToSign(crossP); if (!IsGear(crossSign)) { continue; } //Console.WriteLine("Is " + solid.Name + " a gear? 'y' or 'n'"); //var read = Convert.ToString(Console.ReadLine()); //if (read == "n") // continue; return(new Gear { Solid = solid, Axis = flatPrim.Faces[0].Normal }); } } return(null); }
private static List <Partition> AffectedPartitionsWithRayNABD(Partition[] partition, Ray ray) { return (partition.Where( prtn => prtn.SolidTriangles.Count > 0 && prtn.Faces.Any(f => GeometryFunctions.RayIntersectsWithFaceNABD(ray, f))).ToList()); }
private static bool SlotHeadBolt(TessellatedSolid solid, List <PrimitiveSurface> solidPrim, Dictionary <TemporaryFlat, List <TemporaryFlat> > equalPrimitives, List <TessellatedSolid> repeated) { repeated.Add(solid); var twoFlat = FastenerDetector.EqualPrimitivesFinder(equalPrimitives, 2); if (!twoFlat.Any()) { return(false); } foreach (var candidateHex in twoFlat) { var candidateHexVal = equalPrimitives[candidateHex]; var cos = (candidateHexVal[0]).Normal.dotProduct((candidateHexVal[1]).Normal); if (!(Math.Abs(-1 - cos) < 0.0001)) { continue; } // I will add couple of conditions here: // 1. If the number of solid vertices in front of each flat is equal to another // 2. If the summation of the vertices in 1 is greater than the total # of verts // 3. and I also need to add some constraints for the for eample the area of the cylinder var leftVerts = VertsInfrontOfFlat(solid, candidateHexVal[0]); var rightVerts = VertsInfrontOfFlat(solid, candidateHexVal[1]); if (Math.Abs(leftVerts - rightVerts) > 2 || leftVerts + rightVerts <= solid.Vertices.Length) { continue; } if (!solidPrim.Where(p => p is Cylinder).Cast <Cylinder>().Any(c => c.IsPositive)) { continue; } var lengthAndRadius = FastenerEngagedLengthAndRadiusNoThread(solid, solidPrim); foreach (var repeatedSolid in repeated) { var fastener = new Fastener { Solid = repeatedSolid, FastenerType = FastenerTypeEnum.Bolt, Tool = Tool.FlatBlade, RemovalDirection = //RemovalDirectionFinderForSlot(candidateHexVal.Cast<Flat>().ToList(), // solidPrim.Where(p => p is Flat).Cast<Flat>().ToList()), FastenerDetector.RemovalDirectionFinderUsingObb(repeatedSolid, BoundingGeometry.OrientedBoundingBoxDic[repeatedSolid]), 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); } return(true); } return(false); }
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); }
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 }); }
internal static List <Partition> AffectedPartitionsWithRayCvhOverlaps(Partition[] partitions, Ray ray) { var affected = partitions.Where( prtn => prtn.SolidTriangles.Count > 0 && prtn.Faces.Any(f => GeometryFunctions.RayIntersectsWithFace(ray, f))).ToList(); var currentPartition = partitions.Where(p => PartitioningSolid.IsVertexInsidePartition(p, new TVGL.Vertex(ray.Position))); affected.AddRange(currentPartition); return(affected); }
private static void PreSelectedFastenerToFastenerClass( Dictionary <TessellatedSolid, List <PrimitiveSurface> > solidPrimitive, Dictionary <TessellatedSolid, List <TessellatedSolid> > multipleRefs) { foreach (var preFastener in FastenerDetector.PreSelectedFasteners) { var lengthAndRadius = FastenerEngagedLengthAndRadiusNoThread(preFastener, solidPrimitive[preFastener]); // 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 }; } } foreach (var repeatedSolid in repeated) { var fastener = new Fastener { Solid = repeatedSolid, FastenerType = FastenerTypeEnum.Bolt, RemovalDirection = FastenerDetector.RemovalDirectionFinderUsingObb(preFastener, BoundingGeometry.OrientedBoundingBoxDic[preFastener]), OverallLength = GeometryFunctions.SortedLengthOfObbEdges( BoundingGeometry.OrientedBoundingBoxDic[preFastener])[2], EngagedLength = lengthAndRadius[0], Diameter = lengthAndRadius[1] * 2.0, Certainty = 1.0 }; FastenerDetector.Fasteners.Add(fastener); } } }
private static double RadiusOfBoundingCylinder(TessellatedSolid solid, double[] faceCenters, double[] vector) { var maxDistance = double.NegativeInfinity; foreach (var vertex in solid.Vertices) { var dis = GeometryFunctions.DistanceBetweenLineAndVertex(vector, faceCenters, vertex.Position); if (dis > maxDistance) { maxDistance = dis; } } return(maxDistance); }
private List <FastenerAndNutPartition> CreatePartitions(PolygonalFace faceFromLongestSide, int numberOfPartitions) { var sortedEdges = GeometryFunctions.SortedEdgesOfTriangle(faceFromLongestSide); var cornerVer = sortedEdges[0].First(sortedEdges[1].Contains); var otherVerShertestEdge = sortedEdges[0].First(a => a != cornerVer); var partitionGeneratorDirection = sortedEdges[1].First(a => a != cornerVer).Position.subtract(cornerVer.Position); var stepVector = partitionGeneratorDirection.divide((double)numberOfPartitions); var partis = new List <FastenerAndNutPartition>(); for (var i = 0; i < NumberOfPartitions; i++) { var prt = new FastenerAndNutPartition { Edge1 = new[] { new Vertex(cornerVer.Position.add(stepVector.multiply(i))), new Vertex(otherVerShertestEdge.Position.add(stepVector.multiply(i))) }, Edge2 = new[] { new Vertex(cornerVer.Position.add(stepVector.multiply(i + 1))), new Vertex(otherVerShertestEdge.Position.add(stepVector.multiply(i + 1))) } }; if (i == 0) { prt.Edge1 = new[] { new Vertex(cornerVer.Position.add(stepVector.multiply(-0.1))), new Vertex(otherVerShertestEdge.Position.add(stepVector.multiply(-0.1))) }; } if (i == NumberOfPartitions - 1) { prt.Edge2 = new[] { new Vertex(cornerVer.Position.add(stepVector.multiply(i + 1.1))), new Vertex(otherVerShertestEdge.Position.add(stepVector.multiply(i + 1.1))) }; } partis.Add(prt); } return(partis); }
private static double DetermineTheMagnifier() { // Regardless of the actual size of the assembly, I will fit it in a box with // a diagonal length of 500,000 var allVertices = Solids.SelectMany(p => p.Value).SelectMany(g => g.Vertices); var maxX = (double)allVertices.Max(v => v.X); var maxY = (double)allVertices.Max(v => v.Y); var maxZ = (double)allVertices.Max(v => v.Z); var minX = (double)allVertices.Min(v => v.X); var minY = (double)allVertices.Min(v => v.Y); var minZ = (double)allVertices.Min(v => v.Z); var diagonalLength = GeometryFunctions.DistanceBetweenTwoVertices(new[] { maxX, maxY, maxZ }, new[] { minX, minY, minZ }); return(500000 / diagonalLength); }
internal static int RemovalDirectionFinderUsingObbWithTopPlane(TessellatedSolid solid, BoundingBox obb, out PolygonalFace topPlane) { // this is hard. it can be a simple threaded rod,or it can be a standard // bolt that could not be detected by other approaches. // If it is a rod, the removal direction is not really important, // but if not, it's important I still have no idea about how to detect it. // Idea: find any of the 4 longest sides of the OBB. // find the closest vertex to this side. (if it's a rod, // the closest vertex can be everywhere, but in a regular bolt, // it's on the top (it's most definitely a vertex from the head)) PolygonalFace facePrepToRD1; PolygonalFace facePrepToRD2; var longestPlane = GeometryFunctions.LongestPlaneOfObbDetector(obb, out facePrepToRD1, out facePrepToRD2); Vertex closestVerToPlane = null; var minDist = double.PositiveInfinity; foreach (var ver in solid.ConvexHull.Vertices) { var dis = Math.Abs(GeometryFunctions.DistanceBetweenVertexAndPlane(ver.Position, longestPlane[0])); if (dis >= minDist) { continue; } closestVerToPlane = ver; minDist = dis; } // The closest vertex to plane is closer to which facePrepToRD? double[] normalGuess = null; if (Math.Abs(GeometryFunctions.DistanceBetweenVertexAndPlane(closestVerToPlane.Position, facePrepToRD1)) < Math.Abs(GeometryFunctions.DistanceBetweenVertexAndPlane(closestVerToPlane.Position, facePrepToRD2))) { normalGuess = facePrepToRD1.Normal; topPlane = facePrepToRD1; } else { normalGuess = facePrepToRD2.Normal; topPlane = facePrepToRD2; } var equInDirections = DisassemblyDirections.Directions.First(d => Math.Abs(d.dotProduct(normalGuess) - 1) < 0.05); return(DisassemblyDirections.Directions.IndexOf(equInDirections)); }
private static double[] FaceCenterFinder(PolygonalFace side) { var longestEdge = new Vertex[2]; var maxLength = double.NegativeInfinity; for (var i = 0; i < side.Vertices.Count - 1; i++) { for (var j = i + 1; j < side.Vertices.Count; j++) { var dis = GeometryFunctions.DistanceBetweenTwoVertices(side.Vertices[i].Position, side.Vertices[j].Position); if (dis > maxLength) { maxLength = dis; longestEdge = new[] { side.Vertices[i], side.Vertices[j] }; } } } return((longestEdge[0].Position.add(longestEdge[1].Position)).divide(2.0)); }
private static double[] ShortestEdgeMidPointOfTriangle(PolygonalFace triangle) { var shortestEdge = new Vertex[2]; var shortestDist = double.PositiveInfinity; for (var i = 0; i < triangle.Vertices.Count - 1; i++) { for (var j = i + 1; j < triangle.Vertices.Count; j++) { var dis = GeometryFunctions.DistanceBetweenTwoVertices(triangle.Vertices[i].Position, triangle.Vertices[j].Position); if (dis >= shortestDist) { continue; } shortestDist = dis; shortestEdge = new[] { triangle.Vertices[i], triangle.Vertices[j] }; } } return((shortestEdge[0].Position.add(shortestEdge[1].Position)).divide(2.0)); }
private static double DiameterOfFastenerFinderUsingPolynomial(List <double> distancePointToSolid, int[] threadStartEndPoints, PolygonalFace longestSide, TessellatedSolid solid, double longestDist) { var newList = new List <double>(); for (var i = threadStartEndPoints[0]; i < threadStartEndPoints[1]; i++) { newList.Add(distancePointToSolid[i]); } var obbEdgesLength = GeometryFunctions.SortedLengthOfObbEdges(BoundingGeometry.OrientedBoundingBoxDic[solid]); // one of the first two small lengths are the number that I am looking for. var shortestEdgeOfTriangle = GeometryFunctions.SortedEdgeLengthOfTriangle(longestSide)[0]; var obbDepth = Math.Abs(obbEdgesLength[0] - shortestEdgeOfTriangle) < 0.01 ? obbEdgesLength[1] : obbEdgesLength[0]; return(obbDepth - 2 * (newList.Min() * longestDist)); }
private static Vertex[] CornerEdgeFinder(PolygonalFace polygonalFace) { // We want to find the second long edge: var dist0 = GeometryFunctions.DistanceBetweenTwoVertices(polygonalFace.Vertices[0].Position, polygonalFace.Vertices[1].Position); var dist1 = GeometryFunctions.DistanceBetweenTwoVertices(polygonalFace.Vertices[0].Position, polygonalFace.Vertices[2].Position); var dist2 = GeometryFunctions.DistanceBetweenTwoVertices(polygonalFace.Vertices[1].Position, polygonalFace.Vertices[2].Position); if ((dist0 > dist1 && dist0 < dist2) || (dist0 > dist2 && dist0 < dist1)) { return new[] { polygonalFace.Vertices[0], polygonalFace.Vertices[1] } } ; if ((dist1 > dist0 && dist1 < dist2) || (dist1 > dist2 && dist1 < dist0)) { return new[] { polygonalFace.Vertices[0], polygonalFace.Vertices[2] } } ; return(new[] { polygonalFace.Vertices[1], polygonalFace.Vertices[2] }); }
private static Dictionary <PolygonalFace, double> ThreeSidesOfTheObb(TessellatedSolid solid) { // This is based on my own OBB function: // it returns a dictionary with size of three (3 sides). // Key: triangle, value: length of the potential cylinder var cornerVer = BoundingGeometry.OrientedBoundingBoxDic[solid].CornerVertices; var face1 = new PolygonalFace(new[] { new Vertex(cornerVer[0].Position), new Vertex(cornerVer[1].Position), new Vertex(cornerVer[3].Position) }, ((cornerVer[3].Position.subtract(cornerVer[0].Position)).crossProduct( cornerVer[1].Position.subtract(cornerVer[0].Position))).normalize()); var length1 = GeometryFunctions.DistanceBetweenTwoVertices(cornerVer[0].Position, cornerVer[4].Position); var face2 = new PolygonalFace(new[] { new Vertex(cornerVer[1].Position), new Vertex(cornerVer[0].Position), new Vertex(cornerVer[4].Position) }, ((cornerVer[1].Position.subtract(cornerVer[0].Position)).crossProduct( cornerVer[4].Position.subtract(cornerVer[0].Position))).normalize()); var length2 = GeometryFunctions.DistanceBetweenTwoVertices(cornerVer[0].Position, cornerVer[3].Position); var face3 = new PolygonalFace(new[] { new Vertex(cornerVer[0].Position), new Vertex(cornerVer[3].Position), new Vertex(cornerVer[7].Position) }, ((cornerVer[0].Position.subtract(cornerVer[3].Position)).crossProduct( cornerVer[7].Position.subtract(cornerVer[3].Position))).normalize()); var length3 = GeometryFunctions.DistanceBetweenTwoVertices(cornerVer[0].Position, cornerVer[1].Position); return(new Dictionary <PolygonalFace, double> { { face1, length1 }, { face2, length2 }, { face3, length3 } }); }
internal static void SolidTrianglesOfPartitions(List <FastenerAndNutPartition> partitions, TessellatedSolid solid, PolygonalFace faceFromLongestSide) { foreach (var vertex in solid.Vertices) { var ray = new Ray(new Vertex(vertex.Position), faceFromLongestSide.Normal); var intersectionPoint = GeometryFunctions.RayIntersectionPointWithFace(ray, faceFromLongestSide); var chosenPrtn = PartitionOfThePoint(partitions, intersectionPoint); chosenPrtn.VerticesOfSolidInPartition.Add(vertex); } foreach (var face in solid.Faces) { var inds = new List <int>(); foreach (var fV in face.Vertices) { var prt = partitions.First(p => p.VerticesOfSolidInPartition.Contains(fV)); inds.Add(partitions.IndexOf(prt)); } for (var i = inds.Min(); i <= inds.Max(); i++) { partitions[i].FacesOfSolidInPartition.Add(face); } } }
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); }
internal static FastenerAndNutPartition PartitionOfThePoint(List <FastenerAndNutPartition> partitions, double[] point) { FastenerAndNutPartition chosenPrtn = null; var sumDisToEdgs = double.PositiveInfinity; foreach (var prtn in partitions) { var dis1 = GeometryFunctions.DistanceBetweenLineAndVertex( prtn.Edge1[0].Position.subtract(prtn.Edge1[1].Position), prtn.Edge1[0].Position, point); var dis2 = GeometryFunctions.DistanceBetweenLineAndVertex( prtn.Edge2[0].Position.subtract(prtn.Edge2[1].Position), prtn.Edge2[0].Position, point); var sum = dis1 + dis2; if (sum < sumDisToEdgs) { sumDisToEdgs = sum; chosenPrtn = prtn; } } return(chosenPrtn); }