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); }
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)); }