private bool MappedConnectionsContainsKey(CSGVertex key)
 {
     foreach (CSGVertex csgVertex in mappedConnections.Keys)
     {
         if (csgVertex == key)
         {
             return(true);
         }
     }
     return(false);
 }
 public IEnumerable <CSGConnection> GetConnections(CSGVertex v, bool outboundOnly = false)
 {
     if (!MappedConnectionsContainsKey(v))
     {
         mappedConnections.Add(v, new List <CSGConnection>());
     }
     if (outboundOnly)
     {
         return(mappedConnections.GetNoBoxing(v).Where(conn => conn.A == v));
     }
     else
     {
         return(mappedConnections.GetNoBoxing(v));
     }
 }
        public void AddConnection(CSGVertex a, CSGVertex b)
        {
            if (!MappedConnectionsContainsKey(a))
            {
                mappedConnections.Add(a, new List <CSGConnection>());
            }
            if (!MappedConnectionsContainsKey(b))
            {
                mappedConnections.Add(b, new List <CSGConnection>());
            }

            mappedConnections.GetNoBoxing(a).Add(new CSGConnection(a, b));
            mappedConnections.GetNoBoxing(b).Add(new CSGConnection(b, a));
            allConnections.Add(new CSGConnection(a, b));
            allConnections.Add(new CSGConnection(b, a));
        }
        public CSGPlane Transform(Transform transform, Vector3 shapeOrigin)
        {
            CSGVertex[] transformedVerts = new CSGVertex[vertices.Length];
            for (int i = 0; i < vertices.Length; ++i)
            {
                CSGVertex originalVert             = vertices[i];
                Vector3   scaledPosition           = (originalVert.Position - shapeOrigin).Scale(transform.Scale) + shapeOrigin;
                Vector3   scaledPosFromOrigin      = scaledPosition - shapeOrigin;
                Vector3   scaledAndRotatedPosition = shapeOrigin + scaledPosFromOrigin * transform.Rotation;
                transformedVerts[i] = new CSGVertex(
                    scaledAndRotatedPosition + transform.Translation,
                    originalVert.Normal * transform.Rotation,
                    originalVert.TexUV
                    );
            }

            Plane newPlane = new Plane(transform.Rotation * Plane.Normal, vertices[0].Position);

            return(new CSGPlane(newPlane, transformedVerts));
        }
        public static void GeneratePlane(IList <Vector3> coplanarPoints, Transform transform, Vector2 texScale, bool doubleSided, out IList <CSGVertex> vertices, out IList <uint> indices)
        {
            if (coplanarPoints.Count < 2)
            {
                throw new ArgumentException("Must supply at least 3 points.", "coplanarPoints");
            }
            CSGPlane[] planes = new CSGPlane[2];

            Vector3 barycentre = Vector3.ZERO;

            coplanarPoints.ForEach(point => barycentre += point);
            barycentre /= coplanarPoints.Count;
            CSGVertex[] csgVertices;
            Plane       plane            = Plane.FromPoints(coplanarPoints[0], coplanarPoints[1], coplanarPoints[2]);
            Vector3     uvX              = (coplanarPoints[0] - barycentre).ToUnit();
            Vector3     uvY              = uvX.Cross(plane.Normal);
            Vector2     invTexDimensions = new Vector2(1f / texScale.X, 1f / texScale.Y);

            #region Plane A
            csgVertices = new CSGVertex[coplanarPoints.Count];
            plane       = -plane;
            for (int i = 0; i < coplanarPoints.Count; ++i)
            {
                Vector3 centreOffset = coplanarPoints[i] - barycentre;

                csgVertices[csgVertices.Length - (i + 1)] = new CSGVertex(
                    coplanarPoints[i],
                    plane.Normal,
                    new Vector2(centreOffset.Dot(uvX), centreOffset.Dot(uvY)).Scale(invTexDimensions)
                    );
            }

            planes[0] = new CSGPlane(plane, csgVertices, barycentre);
            #endregion

            #region Plane B
            if (doubleSided)
            {
                csgVertices = new CSGVertex[coplanarPoints.Count];
                for (int i = 0; i < coplanarPoints.Count; ++i)
                {
                    Vector3 centreOffset = coplanarPoints[i] - barycentre;

                    csgVertices[i] = new CSGVertex(
                        coplanarPoints[i],
                        plane.Normal,
                        new Vector2(centreOffset.Dot(uvX), centreOffset.Dot(uvY)).Scale(invTexDimensions)
                        );
                }

                planes[1] = new CSGPlane(plane, csgVertices, barycentre);
            }
            #endregion

            for (int i = 0; i < (doubleSided ? 2 : 1); ++i)
            {
                planes[i] = planes[i].Transform(transform, planes[i].Center);
            }

            CreateVBAndIB(planes.Take(doubleSided ? 2 : 1).ToList(), out vertices, out indices, false);
        }
Exemple #6
0
        private static IList <uint> TriangulatePlane(CSGPlane plane, bool insideOut)
        {
            CSGVertexConnectionGraph connectionGraph = new CSGVertexConnectionGraph();

            // Add the initial connections
            Ray[] initialConnectionRays = new Ray[plane.NumVertices];
            for (uint i = 0U; i < plane.NumVertices; ++i)
            {
                connectionGraph.AddConnection(plane[i], plane[(i + 1) % plane.NumVertices]);
                initialConnectionRays[i] = Ray.FromStartAndEndPoint(plane[i].Position, plane[(i + 1) % plane.NumVertices].Position);
            }

            // Add the algorithmic connections
            for (uint a = 0U; a < plane.NumVertices; ++a)
            {
                for (uint b = 0U; b < plane.NumVertices; ++b)
                {
                    if (a == b)
                    {
                        continue;
                    }
                    CSGVertex vertA = plane[a];
                    CSGVertex vertB = plane[b];

                    // Skip existing connections
                    if (connectionGraph.CheckForConnection(vertA, vertB))
                    {
                        continue;
                    }

                    // Is a triangle formable by drawing a connection between A and B?
                    if (!connectionGraph
                        .GetConnections(vertA)
                        .Select(conn => conn.B)
                        .Intersect(connectionGraph.GetConnections(vertB).Select(conn => conn.B))
                        .Any())
                    {
                        continue;
                    }

                    // Does the connection go outside the polygon? If so, it's no good.
                    CSGConnection potentialConnection = new CSGConnection(vertA, vertB);
                    Vector3       connectionCentre    = potentialConnection.Ray.StartPoint + (potentialConnection.Ray.EndPoint.Value - potentialConnection.Ray.StartPoint) / 2f;
                    if (connectionCentre != plane.Center)
                    {
                        Ray connectionToCentreRay = new Ray(connectionCentre, plane.Center - connectionCentre);
                        if ((initialConnectionRays.Count(ray => {
                            Vector3?potentialIntersection = ray.IntersectionWith(connectionToCentreRay);
                            // We check that we're not intersecting the start point because that means this ray is going through a vertex;
                            // so by rejecting intersections through the start point we're not accidentally bumping the number of edge crossings
                            // by 2
                            return(potentialIntersection.HasValue && potentialIntersection != ray.StartPoint);
                        }) & 1) == 0)
                        {
                            continue;
                        }
                    }

                    // Does the connection intersect any other connection? If it does, we would have to create more vertices, so ignore it.
                    if (connectionGraph.GetAllConnections().Any(conn => {
                        Vector3?intersectionPoint = conn.Ray.IntersectionWith(potentialConnection.Ray);
                        if (intersectionPoint.HasValue)
                        {
                            float minDist = Math.Min(
                                Vector3.DistanceSquared(intersectionPoint.Value, potentialConnection.A.Position),
                                Vector3.DistanceSquared(intersectionPoint.Value, potentialConnection.B.Position)
                                );
                            if (minDist > MathUtils.FlopsErrorMargin)
                            {
                                return(true);
                            }
                            return(conn == potentialConnection);
                        }

                        return(false);
                    }))
                    {
                        continue;
                    }

                    // Add this connection.
                    connectionGraph.AddConnection(potentialConnection);
                }
            }

            // Compose the triangles by looking for three-cycles
            List <CSGTriangle> formulatedTriangles = new List <CSGTriangle>();

            for (uint v = 0U; v < plane.NumVertices; ++v)
            {
                CSGVertex sourceVertex = plane[v];
                IEnumerable <CSGConnection> primaryConnections = connectionGraph.GetConnections(sourceVertex, true);

                foreach (CSGConnection primary in primaryConnections)
                {
                    IEnumerable <CSGConnection> secondaryConnections = connectionGraph.GetConnections(primary.B, true)
                                                                       .Where(sConn => sConn.B != sourceVertex && primaryConnections.Any(pConn => pConn.B == sConn.B));

                    // Now we have a set of triangles (source -> pConn.B -> sConn.B), let's find the ones we haven't already
                    // added and add those!
                    foreach (CSGConnection secondary in secondaryConnections)
                    {
                        CSGTriangle potentialTriangle = new CSGTriangle(v, plane.IndexOf(secondary.A), plane.IndexOf(secondary.B));
                        if (!formulatedTriangles.Contains(potentialTriangle))
                        {
                            formulatedTriangles.Add(potentialTriangle);
                        }
                    }
                }
            }

            List <uint> result = new List <uint>();

            foreach (CSGTriangle triangle in formulatedTriangles)
            {
                Vector3 aPos           = plane[triangle.A].Position;
                Vector3 bPos           = plane[triangle.B].Position;
                Vector3 triCentre      = (aPos + bPos + plane[triangle.C].Position) / 3f;
                bool    triIsClockwise = plane.Plane.Normal.Dot(Vector3.Cross(aPos - triCentre, bPos - triCentre)) > 0f;
                if (insideOut)
                {
                    triIsClockwise = !triIsClockwise;
                }

                result.Add(triangle.A);

                if (triIsClockwise)
                {
                    result.Add(triangle.B);
                    result.Add(triangle.C);
                }
                else
                {
                    result.Add(triangle.C);
                    result.Add(triangle.B);
                }
            }

            return(result);
        }
 public uint IndexOf(CSGVertex vertex)
 {
     return((uint)vertices.IndexOf(vertex));
 }
 public CSGConnection(CSGVertex a, CSGVertex b)
 {
     A   = a;
     B   = b;
     Ray = Ray.FromStartAndEndPoint(A.Position, B.Position);
 }
 public bool CheckForConnection(CSGVertex a, CSGVertex b)
 {
     return(MappedConnectionsContainsKey(a) && mappedConnections.GetNoBoxing(a).Any(conn => conn.B == b));
 }