Пример #1
0
        /// <summary>
        /// Expands a polygon by the specified distance.
        /// </summary>
        /// <param name="poly"></param>
        /// <param name="distance"></param>
        /// <param name="constructor"></param>
        /// <returns></returns>
        public static IPoly Expand(this IPoly poly, float distance, Func <IEnumerable <Vector3>, IPoly> constructor = null)
        {
            if (constructor == null)
            {
                constructor = poly.Clone;
            }
            Vector3[] points    = new Vector3[poly.Resolution];
            Vector3[] normals   = new Vector3[poly.Resolution];
            Vector3[] direction = new Vector3[poly.Resolution];
            for (int i = 0; i < poly.Resolution; i++)
            {
                points[i]    = poly.GetPoint(i);
                normals[i]   = poly.GetSurfaceNormal(i).normalized;
                direction[i] = poly.GetPoint((i + 1) % poly.Resolution) - poly.GetPoint(i);
            }

            Vector3[] outputPoints = new Vector3[poly.Resolution];
            for (int i = 0; i < poly.Resolution; i++)
            {
                Vector3 p0     = points[i] + normals[i] * distance;
                int     iMinus = (i - 1 + poly.Resolution) % poly.Resolution;
                Vector3 l0     = points[iMinus] + normals[iMinus] * distance;
                outputPoints[i] = Math3d.LinePlaneIntersection(l0, direction[iMinus], p0, normals[i]);
            }

            return(constructor(outputPoints));
        }
Пример #2
0
        /// <summary>
        /// Find the optimal split for a polygon
        /// </summary>
        /// <param name="poly"></param>
        /// <returns></returns>
        private (Vector3 point, Vector3 normal, List <BSPPoly <T> > left, List <BSPPoly <T> > right) FindOptimalSplit(BSPPoly <T>[] poly)
        {
            //init
            Vector3             point = Vector3.zero, normal = Vector3.zero;
            List <BSPPoly <T> > left = null, right = null;

            //optimal diff
            int diff = int.MaxValue;

            //get the working polygon
            IPoly working = poly[0].working;

            for (int i = 0; i < working.Resolution; i++)
            {
                //get the current point and normal
                Vector3 localPoint  = working.GetPoint(i),
                        localNormal = working.GetSurfaceNormal(i);

                //get output
                (List <BSPPoly <T> > localInside, List <BSPPoly <T> > localOutput) = GetSplit(poly, localPoint, localNormal);

                //calc the diff, and compare
                int localDiff = Math.Abs(localInside.Count - localOutput.Count);
                if (localDiff < diff)
                {
                    left   = localInside;
                    right  = localOutput;
                    point  = localPoint;
                    normal = localNormal;
                    diff   = localDiff;
                }
            }

            return(point, normal, left, right);
        }
Пример #3
0
        /// <summary>
        /// Get the next bsp node for the polygons
        /// </summary>
        /// <param name="polygons"></param>
        /// <param name="optimize"></param>
        /// <returns></returns>
        private BSPNode <T> GetNode(BSPPoly <T>[] polygons, bool optimize)
        {
            if (polygons.Length == 0)
            {
                return(null);
            }
            if (polygons.Length == 1)
            {
                return(new BSPNode <T>(polygons[0], null, null, Vector3.zero, Vector3.zero));
            }

            if (optimize)
            {
                polygons = FindOptimalPoly(polygons);

                Vector3             point, normal;
                List <BSPPoly <T> > left, right;

                (point, normal, left, right) = FindOptimalSplit(polygons);

                return(new BSPNode <T>(polygons[0], GetNode(left.ToArray(), optimize), GetNode(right.ToArray(), optimize), point, normal));
            }

            else
            {
                IPoly   working = polygons[0].working;
                Vector3 point   = working.GetPoint(0),
                        normal  = working.GetSurfaceNormal(0);

                (List <BSPPoly <T> > left, List <BSPPoly <T> > right) = GetSplit(polygons, point, normal);

                return(new BSPNode <T>(polygons[0], GetNode(left.ToArray(), optimize), GetNode(right.ToArray(), optimize), point, normal));
            }
        }
Пример #4
0
        /// <summary>
        /// Calculates the collision status of two polygons.
        /// Returns colliding is the polygons are intersecting, not colliding if they are not, AEnclosedInB is A is inside B, and BEnclosedInA for ...
        /// This method also returns the offending index
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="offendingIndex"></param>
        /// <param name="threshold"></param>
        /// <returns></returns>
        public static CollisionType CalcCollision2D(IPoly a, IPoly b, out int offendingIndex, float threshold = 0.001f)
        {
            offendingIndex = -1;

            //check for a
            bool enclosed = true;

            for (int i = 0; i < a.Resolution; i++)
            {
                Vector3 point = a.GetPoint(i);
                Vector3 surfaceNormal = a.GetSurfaceNormal(i);
                bool    inside, outside;
                CheckPoly(b, point, surfaceNormal, out inside, out outside, threshold);
                if (outside)
                {
                    enclosed = false;
                }
                if (!inside)
                {
                    return(CollisionType.NotColliding);
                }
                if (inside && outside)
                {
                    offendingIndex = i;
                }
            }
            if (enclosed)
            {
                return(CollisionType.BEnclosedInA);
            }

            //check for b
            enclosed = true;
            for (int i = 0; i < b.Resolution; i++)
            {
                Vector3 point = b.GetPoint(i);
                Vector3 surfaceNormal = b.GetSurfaceNormal(i);
                bool    inside, outside;
                CheckPoly(a, point, surfaceNormal, out inside, out outside, threshold);
                if (outside)
                {
                    enclosed = false;
                }
                if (!inside)
                {
                    return(CollisionType.NotColliding);
                }
            }
            if (enclosed)
            {
                return(CollisionType.AEnclosedInB);
            }

            return(CollisionType.Colliding);
        }
Пример #5
0
        /// <summary>
        /// Preforms the set subtract operation with multiple pos and a single neg.
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="neg"></param>
        /// <param name="constructor"></param>
        /// <returns></returns>
        public static List <IPoly> SetSubtract(IEnumerable <IPoly> pos, IPoly neg, Func <IPoly, IEnumerable <Vector3>, IPoly> constructor)
        {
            //set subtract algorithm
            //this version works for only 1 negative poly, and is the basis for multiple polys
            //append all positive polys to a working stack
            //pop polys from the working stack and compare them to the neg poly
            //if they intersect, split them, and push them on the working stack
            //if they are enclosed, remove them from the working list
            //if they aren't instersecting append them to the output stack
            //continue until working stack is empty

            //Initialization
            List <IPoly>  outputList   = new List <IPoly>();
            Stack <IPoly> workingStack = new Stack <IPoly>(pos);

            //working stack loop
            while (workingStack.Count > 0)
            {
                //initialization
                IPoly current = workingStack.Pop();
                int   offendingIndex;

                //detect collision status
                var status = CSGPhysics.CalcCollision2D(neg, current, out offendingIndex);
                //enclosed, just throw away polygon
                if (status == CSGPhysics.CollisionType.BEnclosedInA)
                {
                    continue;
                }
                //if colliding, divide the polygon and push them on the working stack
                else if (status != CSGPhysics.CollisionType.NotColliding)
                {
                    IPoly inside, outside;
                    Divide(current, out inside, out outside, neg.GetPoint(offendingIndex), neg.GetSurfaceNormal(offendingIndex), constructor);
                    workingStack.Push(inside);
                    workingStack.Push(outside);
                }
                //if not colliding, append to output list
                else
                {
                    outputList.Add(current);
                }
            }
            return(outputList);
        }