private static void RunOptions(Options opts) { // TODO: Make sure the best versions of these generic collections are being used in the right places. // Use arrays when size is known and is not expected to change // Otherwise, use a list // Consider places where we can avoid a conversion of .ToArray/.ToList and rely on the IEnumerable interface try { Mesh3 model = new Mesh3(ReadFacetsFromFile(opts.StlInputPath, opts.IsStlAscii)); Console.WriteLine("Read " + model.Facets.Length + " facets from file"); Polygon3[] unsupportedFacets = model.Facets.Where(facet => DoesFacetNeedSupported(facet, opts.CriticalAngle)).ToArray(); Console.WriteLine("Identified " + unsupportedFacets.Length + " unsupported facets"); Point3Tree <List <Polygon3> > edgeFacetIndex = new Point3Tree <List <Polygon3> >(GetEdgeFacetKeys(unsupportedFacets)); Console.WriteLine("Created an index with " + edgeFacetIndex.Keys.Length + " edges"); CreateEdgeFacetAssociation(unsupportedFacets, edgeFacetIndex); Console.WriteLine("Association created between facets and edges"); List <Mesh3> unsupportedRegions = BuildUnsupportedRegions(unsupportedFacets, edgeFacetIndex); Console.WriteLine("Built " + unsupportedRegions.Count + " unsupported regions"); List <Mesh3> largeRegions = unsupportedRegions.Where(region => IsLargeRegion(region, edgeFacetIndex, opts.DimensionLength, opts.ToleranceAngle)).ToList(); Console.WriteLine("Removed " + (unsupportedRegions.Count - largeRegions.Count) + " small unsupported regions"); List <Polygon3> scaffoldingFacets = new List <Polygon3>(); if (opts.DoXScaffolding || opts.DoYScaffolding) { List <Vector3> supportNormals = new List <Vector3>(); Quaternion rotation = new Quaternion(0, 0, (float)AngleConverter.DegToRad(opts.ScaffoldingAngle)); if (opts.DoXScaffolding) { supportNormals.Add(Vector3.Transform(YZNormal, rotation)); } if (opts.DoYScaffolding) { supportNormals.Add(Vector3.Transform(XZNormal, rotation)); } Console.WriteLine("Made support normals"); foreach (Vector3 supportNormal in supportNormals) { scaffoldingFacets.AddRange(GenerateLineScaffolding(model, largeRegions, supportNormal, (float)opts.SupportSpacing, (float)opts.PlateSpacing)); } } if (opts.DoContourScaffolding) { scaffoldingFacets.AddRange(GenerateContourScaffolding(largeRegions, (float)opts.PlateSpacing, edgeFacetIndex)); } StlBinaryWriter writer = new StlBinaryWriter(); writer.Write(opts.StlOutputPath, scaffoldingFacets.ToArray()); } catch (Exception ex) { Console.Error.WriteLine(ex); Environment.Exit(1); } }
private static List <Mesh3> BuildUnsupportedRegions(Polygon3[] unsupportedFacets, Point3Tree <List <Polygon3> > edgeFacetIndex) { Point3Tree <bool> facetVisitedIndex = new Point3Tree <bool>(unsupportedFacets.Select(facet => facet.Centroid).ToArray()); List <Mesh3> unsupportedRegions = new List <Mesh3>(); foreach (Polygon3 unsupportedFacet in unsupportedFacets) { if (!facetVisitedIndex[unsupportedFacet.Centroid]) { unsupportedRegions.Add(new Mesh3(GrowUnsupportedRegion(unsupportedFacet, edgeFacetIndex, facetVisitedIndex))); } } return(unsupportedRegions); }
private static List <Point3> GetBoundingVertices(Mesh3 region, Point3Tree <List <Polygon3> > edgeFacetIndex) { List <Point3> boundingVertices = new List <Point3>(); foreach (Polygon3 facet in region.Facets) { foreach (Point3 edgeMidPoint in facet.EdgeMidPoints) { if (edgeFacetIndex[edgeMidPoint].Count == 1) { boundingVertices.Add(edgeMidPoint); } } } return(boundingVertices); }
private static List <Polygon3> GetAdjacentFacets(Polygon3 facet, Point3Tree <List <Polygon3> > edgeFacetIndex) { List <Polygon3> adjacentFacets = new List <Polygon3>(3); foreach (Point3 edgeMidPoint in facet.EdgeMidPoints) { foreach (Polygon3 adjacentFacet in edgeFacetIndex[edgeMidPoint]) { if (adjacentFacet != facet) { adjacentFacets.Add(adjacentFacet); } } } return(adjacentFacets); }
private static Polygon3[] GrowUnsupportedRegion(Polygon3 unsupportedFacet, Point3Tree <List <Polygon3> > edgeFacetIndex, Point3Tree <bool> facetVisitedIndex) { Queue <Polygon3> adjacentQueue = new Queue <Polygon3>(); adjacentQueue.Enqueue(unsupportedFacet); facetVisitedIndex[unsupportedFacet.Centroid] = true; List <Polygon3> unsupportedRegion = new List <Polygon3>(); while (adjacentQueue.Count != 0) { Polygon3 adjacentFacet = adjacentQueue.Dequeue(); unsupportedRegion.Add(adjacentFacet); EnqueueAdjacentFacets(adjacentFacet, adjacentQueue, edgeFacetIndex, facetVisitedIndex); } return(unsupportedRegion.ToArray()); }
private static bool IsLargeRegion(Mesh3 region, Point3Tree <List <Polygon3> > edgeFacetIndex, double dimensionLength, double toleranceAngle) { bool isLargeRegion = false; List <Vector3> largeDiagonals = GetLargeDiagonals(GetBoundingVertices(region, edgeFacetIndex), dimensionLength); for (int i = 0; i != largeDiagonals.Count && !isLargeRegion; i++) { Vector3 diagonal1 = largeDiagonals[i]; for (int j = i; j != largeDiagonals.Count && !isLargeRegion; j++) { Vector3 diagonal2 = largeDiagonals[j]; double angleBetween = AngleConverter.RadToDeg(Vector3.CalculateAngle(diagonal1, diagonal2)); if (angleBetween >= 90 - toleranceAngle && angleBetween <= 90 + toleranceAngle) { isLargeRegion = true; } } } return(isLargeRegion); }
private static void CreateEdgeFacetAssociation(Polygon3[] facets, Point3Tree <List <Polygon3> > edgeFacetIndex) { foreach (Polygon3 facet in facets) { foreach (Point3 edgeMidPoint in facet.EdgeMidPoints) { List <Polygon3> edgeFacetList = edgeFacetIndex[edgeMidPoint]; if (edgeFacetList == null) { edgeFacetList = new List <Polygon3>(2); edgeFacetIndex[edgeMidPoint] = edgeFacetList; } edgeFacetList.Add(facet); } } if (edgeFacetIndex.Values.Where(list => list != null && list.Count > 2).ToArray().Length > 0) { throw new Exception("Found bad STL file with more than two facets sharing an edge"); } }
private static List <Polygon3> GenerateContourScaffolding(List <Mesh3> regions, float plateSpacing, Point3Tree <List <Polygon3> > edgeFacetIndex) { List <Polygon3> scaffolding = new List <Polygon3>(); foreach (Mesh3 region in regions) { foreach (Polygon3 facet in region.Facets) { for (int i = 0; i != facet.EdgeMidPoints.Length; i++) { if (edgeFacetIndex[facet.EdgeMidPoints[i]].Count == 1) { LineSegment3 boundingEdge = facet.Edges[i]; scaffolding.AddRange(CreateTesselatedLineSupport(new List <Point3> { boundingEdge.StartPoint, boundingEdge.EndPoint }, plateSpacing, region)); } } } } return(scaffolding); }
private static void EnqueueAdjacentFacets(Polygon3 adjacentFacet, Queue <Polygon3> adjacentQueue, Point3Tree <List <Polygon3> > edgeFacetIndex, Point3Tree <bool> facetVisitedIndex) { foreach (Polygon3 facet in GetAdjacentFacets(adjacentFacet, edgeFacetIndex)) { if (!facetVisitedIndex[facet.Centroid]) { adjacentQueue.Enqueue(facet); facetVisitedIndex[facet.Centroid] = true; } } }