public void FaceLineIntersectionTest() { var plane = new Plane(new Coordinate(0, 0, 1), 100); var face = new Face(1) {Plane = plane}; var coords = new[] { new Coordinate(-100, -100, 100), new Coordinate(100, -100, 100), new Coordinate(100, 100, 100), new Coordinate(-100, 100, 100) }; face.Vertices.AddRange(coords.Select(x => new Vertex(x, face))); face.CalculateTextureCoordinates(true); var passLine = new Line(new Coordinate(0, 0, 0), new Coordinate(0, 0, 200)); var reversePassLine = passLine.Reverse(); var failSegment = new Line(new Coordinate(0, 0, 0), new Coordinate(0, 0, 50)); var failLine = new Line(new Coordinate(0, 0, 0), new Coordinate(1, 0, 0)); var outsideFaceLine = new Line(new Coordinate(200, 0, 0), new Coordinate(200, 0, 200)); var pass1 = face.GetIntersectionPoint(passLine); var fail1 = face.GetIntersectionPoint(reversePassLine); var fail2 = face.GetIntersectionPoint(failSegment); var fail3 = face.GetIntersectionPoint(failLine); var fail4 = face.GetIntersectionPoint(outsideFaceLine); Assert.IsNotNull(pass1); Assert.IsNull(fail1); Assert.IsNull(fail2); Assert.IsNull(fail3); Assert.IsNull(fail4); }
public void CalculateDecalGeometry() { _decalGeometry = new List<Face>(); if (Decal == null) return; // Texture not found var boxRadius = Coordinate.One * 4; // Decals apply to all faces that intersect within an 8x8x8 bounding box // centered at the origin of the decal var box = new Box(Origin - boxRadius, Origin + boxRadius); var root = GetRoot(Parent); // Get the faces that intersect with the decal's radius var faces = root.GetAllNodesIntersectingWith(box).OfType<Solid>() .SelectMany(x => x.Faces).Where(x => x.IntersectsWithBox(box)); var idg = new IDGenerator(); // Dummy generator foreach (var face in faces) { // Project the decal onto the face var center = face.Plane.Project(Origin); var texture = face.Texture.Clone(); texture.Name = Decal.Name; texture.Texture = Decal; texture.XShift = -Decal.Width / 2m; texture.YShift = -Decal.Height / 2m; var decalFace = new Face(idg.GetNextFaceID()) { Colour = Colour, IsSelected = IsSelected, IsHidden = IsCodeHidden, Plane = face.Plane, Texture = texture }; // Re-project the vertices in case the texture axes are not on the face plane var xShift = face.Texture.UAxis * face.Texture.XScale * Decal.Width / 2; var yShift = face.Texture.VAxis * face.Texture.YScale * Decal.Height / 2; var verts = new[] { new Vertex(face.Plane.Project(center + xShift - yShift), decalFace), // Bottom Right new Vertex(face.Plane.Project(center + xShift + yShift), decalFace), // Top Right new Vertex(face.Plane.Project(center - xShift + yShift), decalFace), // Top Left new Vertex(face.Plane.Project(center - xShift - yShift), decalFace) // Bottom Left }; // Because the texture axes don't have to align to the face, we might have a reversed face here // If so, reverse the points to get a valid face for the plane. // TODO: Is there a better way to do this? var vertPlane = new Plane(verts[0].Location, verts[1].Location, verts[2].Location); if (!face.Plane.Normal.EquivalentTo(vertPlane.Normal)) { Array.Reverse(verts); } decalFace.Vertices.AddRange(verts); decalFace.UpdateBoundingBox(); // Calculate the X and Y shift bases on the first vertex location (assuming U/V of first vertex is zero) - we dont want these to change var vtx = decalFace.Vertices[0]; decalFace.Texture.XShift = -(vtx.Location.Dot(decalFace.Texture.UAxis)) / decalFace.Texture.XScale; decalFace.Texture.YShift = -(vtx.Location.Dot(decalFace.Texture.VAxis)) / decalFace.Texture.YScale; decalFace.CalculateTextureCoordinates(); // Next, the decal geometry needs to be clipped to the face so it doesn't spill into the void // Create a fake solid out of the decal geometry and clip it against all the brush planes var fake = CreateFakeDecalSolid(decalFace); foreach (var f in face.Parent.Faces.Except(new[] { face })) { Solid back, front; fake.Split(f.Plane, out back, out front, idg); fake = back ?? fake; } // Extract out the original face decalFace = fake.Faces.First(x => x.Plane.EquivalentTo(face.Plane, 0.05m)); // Add a tiny bit to the normal axis to ensure the decal is rendered in front of the face var normalAdd = face.Plane.Normal * 0.2m; decalFace.Transform(new UnitTranslate(normalAdd), TransformFlags.TextureLock); _decalGeometry.Add(decalFace); } }
private void CreateFace(Polygon polygon, Solid parent, Face original) { var verts = polygon.Vertices; var f = new Face(Document.Map.IDGenerator.GetNextFaceID()) { Parent = parent, Plane = new Plane(verts[0], verts[1], verts[2]), Colour = parent.Colour, Texture = original.Texture.Clone() }; f.Vertices.AddRange(verts.Select(x => new Vertex(x, f))); f.UpdateBoundingBox(); f.CalculateTextureCoordinates(true); parent.Faces.Add(f); }