コード例 #1
0
        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);
        }
コード例 #2
0
        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);
        }
コード例 #3
0
        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;
            }
        }
コード例 #4
0
        public static AxisAlignedBoundingBox Bounds(this List <Vector3> list)
        {
            var bounds = AxisAlignedBoundingBox.Empty();

            foreach (var position in list)
            {
                bounds.ExpandToInclude(position);
            }

            return(bounds);
        }
コード例 #5
0
        public static AxisAlignedBoundingBox GetAxisAlignedBoundingBox(this IEnumerable <IObject3D> items)
        {
            var aabb = AxisAlignedBoundingBox.Empty();

            foreach (var item in items)
            {
                aabb += item.GetAxisAlignedBoundingBox();
            }

            return(aabb);
        }
コード例 #6
0
        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);
        }
コード例 #7
0
        public AxisAlignedBoundingBox GetAxisAlignedBoundingBox()
        {
            AxisAlignedBoundingBox aabb = AxisAlignedBoundingBox.Empty();

            foreach (FaceEdge faceEdge in FaceEdges())
            {
                aabb = AxisAlignedBoundingBox.Union(aabb, faceEdge.FirstVertex.Position);
            }

            return(aabb);
        }
コード例 #8
0
        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);
        }
コード例 #9
0
        /// <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);
        }
コード例 #10
0
        /// <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);
        }
コード例 #11
0
        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);
        }
コード例 #12
0
        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);
            }
        }
コード例 #13
0
        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);
        }