public Task Create(IProgress <ProgressStatus> progress, CancellationToken cancelationToken) { ProgressStatus status = new ProgressStatus(); status.Status = "Enter"; progress.Report(status); // Get visible meshes for each of them var supportCandidates = scene.Children.SelectMany(i => i.VisibleMeshes()); AxisAlignedBoundingBox allBounds = AxisAlignedBoundingBox.Empty(); foreach (var candidate in supportCandidates) { allBounds += candidate.GetAxisAlignedBoundingBox(candidate.Matrix.Inverted * candidate.WorldMatrix()); } // create the gird of possible support var gridBounds = new RectangleDouble(Math.Floor((double)(allBounds.MinXYZ.X / PillarSize)), Math.Floor((double)(allBounds.MinXYZ.Y / PillarSize)), Math.Ceiling(allBounds.MaxXYZ.X / PillarSize), Math.Ceiling(allBounds.MaxXYZ.Y / PillarSize)); var partBounds = new RectangleDouble(gridBounds.Left * PillarSize, gridBounds.Bottom * PillarSize, gridBounds.Right * PillarSize, gridBounds.Top * PillarSize); int gridWidth = (int)gridBounds.Width; int gridHeight = (int)gridBounds.Height; var supportGrid = new List <List <List <(bool isBottom, double z)> > >(); for (int x = 0; x < gridWidth; x++) { supportGrid.Add(new List <List <(bool, double)> >()); for (int y = 0; y < gridHeight; y++) { supportGrid[x].Add(new List <(bool, double)>()); } } // get all the support plane intersections status.Status = "Trace"; progress.Report(status); var detectedPlanes = DetectRequiredSupportByTracing(gridBounds, supportCandidates); status.Status = "Columns"; progress.Report(status); AddSupportColumns(gridBounds, detectedPlanes); // this is the theory for regions rather than pillars // separate the faces into face patch groups (these are the new support tops) // project all the vertices of each patch group down until they hit an up face in the scene (or 0) // make a new patch group at the z of the hit (these will be the bottoms) // find the outline of the patch groups (these will be the walls of the top and bottom patches // make a new mesh object with the top, bottom and walls, add it to the scene and mark it as support return(Task.CompletedTask); }
public static AxisAlignedBoundingBox GetAxisAlignedBoundingBox(this Face face, Mesh mesh) { var bounds = AxisAlignedBoundingBox.Empty(); bounds.ExpandToInclude(mesh.Vertices[face.v0]); bounds.ExpandToInclude(mesh.Vertices[face.v1]); bounds.ExpandToInclude(mesh.Vertices[face.v2]); return(bounds); }
public static void Translate(this IEnumerable <IObject3D> items, Vector3 translation) { var matrix = Matrix4X4.CreateTranslation(translation); var aabb = AxisAlignedBoundingBox.Empty(); foreach (var item in items) { item.Matrix *= matrix; } }
public static AxisAlignedBoundingBox Bounds(this List <Vector3> list) { var bounds = AxisAlignedBoundingBox.Empty(); foreach (var position in list) { bounds.ExpandToInclude(position); } return(bounds); }
public static AxisAlignedBoundingBox GetAxisAlignedBoundingBox(this IEnumerable <IObject3D> items) { var aabb = AxisAlignedBoundingBox.Empty(); foreach (var item in items) { aabb += item.GetAxisAlignedBoundingBox(); } return(aabb); }
public AxisAlignedBoundingBox GetAxisAlignedBoundingBox(Matrix4X4 matrix) { AxisAlignedBoundingBox aabb = AxisAlignedBoundingBox.Empty(); foreach (FaceEdge faceEdge in FaceEdges()) { aabb = AxisAlignedBoundingBox.Union(aabb, Vector3.Transform(faceEdge.FirstVertex.Position, matrix)); } return(aabb); }
public AxisAlignedBoundingBox GetAxisAlignedBoundingBox() { AxisAlignedBoundingBox aabb = AxisAlignedBoundingBox.Empty(); foreach (FaceEdge faceEdge in FaceEdges()) { aabb = AxisAlignedBoundingBox.Union(aabb, faceEdge.FirstVertex.Position); } return(aabb); }
public static AxisAlignedBoundingBox GetUnionedAxisAlignedBoundingBox(this IEnumerable <IObject3D> items) { // first find the bounds of what is already here. AxisAlignedBoundingBox totalBounds = AxisAlignedBoundingBox.Empty(); foreach (var object3D in items) { totalBounds = AxisAlignedBoundingBox.Union(totalBounds, object3D.GetAxisAlignedBoundingBox(Matrix4X4.Identity)); } return(totalBounds); }
/// <summary> /// MeshWrapperObject3D overrides GetAabb so that it can only check the geometry that it has created /// </summary> /// <param name="matrix"></param> /// <returns></returns> public override AxisAlignedBoundingBox GetAxisAlignedBoundingBox(Matrix4X4 matrix) { AxisAlignedBoundingBox totalBounds = AxisAlignedBoundingBox.Empty(); foreach (var child in this.Descendants().Where(i => i.OwnerID == this.ID && i.Visible)) { // Add the bounds of each child object var childBounds = child.Mesh.GetAxisAlignedBoundingBox(child.WorldMatrix(this) * matrix); //var childBounds = child.GetAxisAlignedBoundingBox(child.WorldMatrix(item) * matrix); // Check if the child actually has any bounds if (childBounds.XSize > 0) { totalBounds += childBounds; } } return(totalBounds); }
/// <summary> /// MeshWrapperObject3D overrides GetAabb so that it can only check the geometry that it has created /// </summary> /// <param name="matrix"></param> /// <returns></returns> public override AxisAlignedBoundingBox GetAxisAlignedBoundingBox(Matrix4X4 matrix) { AxisAlignedBoundingBox totalBounds = AxisAlignedBoundingBox.Empty(); // This needs to be Descendants because we need to move past the first visible mesh to our owned objects foreach (var child in this.Descendants().Where(i => i.OwnerID == this.ID && i.Visible)) { var childMesh = child.Mesh; if (childMesh != null) { // Add the bounds of each child object var childBounds = childMesh.GetAxisAlignedBoundingBox(child.WorldMatrix(this) * matrix); // Check if the child actually has any bounds if (childBounds.XSize > 0) { totalBounds += childBounds; } } } return(totalBounds); }
public static AxisAlignedBoundingBox GetWorldspaceAabbOfRenderPathOutline(this WorldView world, Matrix4X4 worldMatrix, IVertexSource path, double lineWidth = 1) { AxisAlignedBoundingBox box = AxisAlignedBoundingBox.Empty(); Vector3 prevPosition = default(Vector3); foreach (var vertex in path.Vertices()) { if (vertex.command == ShapePath.FlagsAndCommand.MoveTo) { prevPosition = new Vector3(vertex.position).Transform(worldMatrix); } else if (vertex.command == ShapePath.FlagsAndCommand.LineTo) { var position = new Vector3(vertex.position).Transform(worldMatrix); box.ExpandToInclude(prevPosition); box.ExpandToInclude(position); prevPosition = position; } } return(box); }
public static IPrimitive CreateNewHierachy(List <IPrimitive> traceableItems, int maxRecursion = int.MaxValue, int recursionDepth = 0, SortingAccelerator accelerator = null) { if (accelerator == null) { accelerator = new SortingAccelerator(); } int numItems = traceableItems.Count; if (numItems == 0) { return(null); } if (numItems == 1) { return(traceableItems[0]); } int bestAxis = -1; int bestIndexToSplitOn = -1; var axisSorter = new CompareCentersOnAxis(0); if (recursionDepth < maxRecursion) { if (numItems > 50) { bestAxis = accelerator.NextAxis; bestIndexToSplitOn = numItems / 2; } else { double totalIntersectCost = 0; int skipInterval = 1; for (int i = 0; i < numItems; i += skipInterval) { IPrimitive item = traceableItems[i]; totalIntersectCost += item.GetIntersectCost(); } // get the bounding box of all the items we are going to consider. AxisAlignedBoundingBox OverallBox = traceableItems[0].GetAxisAlignedBoundingBox(); for (int i = skipInterval; i < numItems; i += skipInterval) { OverallBox += traceableItems[i].GetAxisAlignedBoundingBox(); } double areaOfTotalBounds = OverallBox.GetSurfaceArea(); double bestCost = totalIntersectCost; var totalDeviationOnAxis = default(Vector3); double[] surfaceArreaOfItem = new double[numItems - 1]; double[] rightBoundsAtItem = new double[numItems - 1]; for (int axis = 0; axis < 3; axis++) { double intersectCostOnLeft = 0; axisSorter.WhichAxis = axis; traceableItems.Sort(axisSorter); // Get all left bounds AxisAlignedBoundingBox currentLeftBounds = traceableItems[0].GetAxisAlignedBoundingBox(); surfaceArreaOfItem[0] = currentLeftBounds.GetSurfaceArea(); for (int itemIndex = 1; itemIndex < numItems - 1; itemIndex += skipInterval) { currentLeftBounds += traceableItems[itemIndex].GetAxisAlignedBoundingBox(); surfaceArreaOfItem[itemIndex] = currentLeftBounds.GetSurfaceArea(); totalDeviationOnAxis[axis] += Math.Abs(traceableItems[itemIndex].GetCenter()[axis] - traceableItems[itemIndex - 1].GetCenter()[axis]); } // Get all right bounds if (numItems > 1) { AxisAlignedBoundingBox currentRightBounds = traceableItems[numItems - 1].GetAxisAlignedBoundingBox(); rightBoundsAtItem[numItems - 2] = currentRightBounds.GetSurfaceArea(); for (int itemIndex = numItems - 1; itemIndex > 1; itemIndex -= skipInterval) { currentRightBounds += traceableItems[itemIndex - 1].GetAxisAlignedBoundingBox(); rightBoundsAtItem[itemIndex - 2] = currentRightBounds.GetSurfaceArea(); } } // Sweep from left for (int itemIndex = 0; itemIndex < numItems - 1; itemIndex += skipInterval) { double thisCost = 0; { // Evaluate Surface Cost Equation double costOfTwoAABB = 2 * AxisAlignedBoundingBox.GetIntersectCost(); // the cost of the two children AABB tests // do the left cost intersectCostOnLeft += traceableItems[itemIndex].GetIntersectCost(); double leftCost = (surfaceArreaOfItem[itemIndex] / areaOfTotalBounds) * intersectCostOnLeft; // do the right cost double intersectCostOnRight = totalIntersectCost - intersectCostOnLeft; double rightCost = (rightBoundsAtItem[itemIndex] / areaOfTotalBounds) * intersectCostOnRight; thisCost = costOfTwoAABB + leftCost + rightCost; } if (thisCost < bestCost + .000000001) // if it is less within some tiny error { if (thisCost > bestCost - .000000001) { // they are the same within the error if (axis > 0 && bestAxis != axis) // we have changed axis since last best and we need to decide if this is better than the last axis best { if (totalDeviationOnAxis[axis] > totalDeviationOnAxis[axis - 1]) { // this new axis is better and we'll switch to it. Otherwise don't switch. bestCost = thisCost; bestIndexToSplitOn = itemIndex; bestAxis = axis; } } } else // this is just better { bestCost = thisCost; bestIndexToSplitOn = itemIndex; bestAxis = axis; } } } } } } if (bestAxis == -1) { // No better partition found return(new UnboundCollection(traceableItems)); } else { var leftItems = new List <IPrimitive>(bestIndexToSplitOn + 1); var rightItems = new List <IPrimitive>(numItems - bestIndexToSplitOn + 1); if (numItems > 100) { // there are lots of items, lets find a sampled bounds and then choose a center var totalBounds = AxisAlignedBoundingBox.Empty(); for (int i = 0; i < 50; i++) { totalBounds.ExpandToInclude(traceableItems[i * numItems / 50].GetCenter()); } bestAxis = totalBounds.XSize > totalBounds.YSize ? 0 : 1; bestAxis = totalBounds.Size[bestAxis] > totalBounds.ZSize ? bestAxis : 2; var axisCenter = totalBounds.Center[bestAxis]; for (int i = 0; i < numItems; i++) { if (traceableItems[i].GetAxisCenter(bestAxis) <= axisCenter) { leftItems.Add(traceableItems[i]); } else { rightItems.Add(traceableItems[i]); } } } else // sort them and find the center { axisSorter.WhichAxis = bestAxis; traceableItems.Sort(axisSorter); for (int i = 0; i <= bestIndexToSplitOn; i++) { leftItems.Add(traceableItems[i]); } for (int i = bestIndexToSplitOn + 1; i < numItems; i++) { rightItems.Add(traceableItems[i]); } } IPrimitive leftGroup = CreateNewHierachy(leftItems, maxRecursion, recursionDepth + 1, accelerator); IPrimitive rightGroup = CreateNewHierachy(rightItems, maxRecursion, recursionDepth + 1, accelerator); var newBVHNode = new BoundingVolumeHierarchy(leftGroup, rightGroup, bestAxis); return(newBVHNode); } }
private static Mesh CreateHullMesh(Mesh mesh) { var bounds = AxisAlignedBoundingBox.Empty(); // Get the convex hull for the mesh var cHVertexList = new List <CHVertex>(); foreach (var position in mesh.Vertices.Distinct().ToArray()) { cHVertexList.Add(new CHVertex(position)); bounds.ExpandToInclude(position); } var tollerance = .01; if (cHVertexList.Count == 0 || bounds.XSize <= tollerance || bounds.YSize <= tollerance || bounds.ZSize <= tollerance || double.IsNaN(cHVertexList.First().Position[0])) { return(mesh); } var convexHull = ConvexHull.Create <CHVertex, CHFace>(cHVertexList, tollerance); if (convexHull?.Result != null) { // create the mesh from the hull data Mesh hullMesh = new Mesh(); foreach (var face in convexHull.Result.Faces) { int vertexCount = hullMesh.Vertices.Count; foreach (var vertex in face.Vertices) { hullMesh.Vertices.Add(new Vector3(vertex.Position[0], vertex.Position[1], vertex.Position[2])); } hullMesh.Faces.Add(vertexCount, vertexCount + 1, vertexCount + 2, hullMesh.Vertices); } try { // make sure there is not currently a convex hull on this object if (mesh.PropertyBag.ContainsKey(ConvexHullMesh)) { mesh.PropertyBag.Remove(ConvexHullMesh); } // add the new hull mesh.PropertyBag.Add(ConvexHullMesh, hullMesh); // make sure we remove this hull if the mesh changes mesh.Changed += MeshChanged_RemoveConvexHull; // remove the marker that says we are building the hull if (mesh.PropertyBag.ContainsKey(CreatingConvexHullMesh)) { mesh.PropertyBag.Remove(CreatingConvexHullMesh); } return(hullMesh); } catch { mesh.PropertyBag.Remove(CreatingConvexHullMesh); } } return(null); }