Exemple #1
0
        public static Solid CreateFromIntersectingPlanes(IEnumerable<Plane> planes, IDGenerator generator)
        {
            var solid = new Solid(generator.GetNextObjectID());
            var list = planes.ToList();
            for (var i = 0; i < list.Count; i++)
            {
                // Split the polygon by all the other planes
                var poly = new Polygon(list[i]);
                for (var j = 0; j < list.Count; j++)
                {
                    if (i != j) poly.Split(list[j]);
                }

                // The final polygon is the face
                var face = new Face(generator.GetNextFaceID()) { Plane = poly.Plane , Parent = solid };
                face.Vertices.AddRange(poly.Vertices.Select(x => new Vertex(x, face)));
                face.UpdateBoundingBox();
                face.AlignTextureToWorld();
                solid.Faces.Add(face);
            }

            // Ensure all the faces point outwards
            var origin = solid.GetOrigin();
            foreach (var face in solid.Faces)
            {
                if (face.Plane.OnPlane(origin) >= 0) face.Flip();
            }

            solid.UpdateBoundingBox();
            return solid;
        }
Exemple #2
0
        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);
        }
Exemple #3
0
 public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
 {
     var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() };
     // The higher Z plane will be triangle, with the lower X value getting the two corners
     var c1 = new Coordinate(box.Start.X, box.Start.Y, box.End.Z).Round(roundDecimals);
     var c2 = new Coordinate(box.End.X, box.Start.Y, box.End.Z).Round(roundDecimals);
     var c3 = new Coordinate(box.Center.X, box.End.Y, box.End.Z).Round(roundDecimals);
     var c4 = new Coordinate(box.Center.X, box.Center.Y, box.Start.Z).Round(roundDecimals);
     var faces = new[]
                     {
                         new[] { c3, c2, c1 },
                         new[] { c3, c1, c4 },
                         new[] { c2, c3, c4 },
                         new[] { c1, c2, c4 }
                     };
     foreach (var arr in faces)
     {
         var face = new Face(generator.GetNextFaceID())
                        {
                            Parent = solid,
                            Plane = new Plane(arr[0], arr[1], arr[2]),
                            Colour = solid.Colour,
                            Texture = { Texture = texture }
                        };
         face.Vertices.AddRange(arr.Select(x => new Vertex(x, face)));
         face.UpdateBoundingBox();
         face.AlignTextureToFace();
         solid.Faces.Add(face);
     }
     solid.UpdateBoundingBox();
     yield return solid;
 }
Exemple #4
0
 public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture)
 {
     var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() };
     // The lower Z plane will be base, the x planes will be triangles
     var c1 = new Coordinate(box.Start.X, box.Start.Y, box.Start.Z);
     var c2 = new Coordinate(box.End.X, box.Start.Y, box.Start.Z);
     var c3 = new Coordinate(box.End.X, box.End.Y, box.Start.Z);
     var c4 = new Coordinate(box.Start.X, box.End.Y, box.Start.Z);
     var c5 = new Coordinate(box.Center.X, box.Start.Y, box.End.Z);
     var c6 = new Coordinate(box.Center.X, box.End.Y, box.End.Z);
     var faces = new[]
                     {
                         new[] { c1, c2, c3, c4 },
                         new[] { c2, c1, c5 },
                         new[] { c5, c6, c3, c2 },
                         new[] { c4, c3, c6 },
                         new[] { c6, c5, c1, c4 }
                     };
     foreach (var arr in faces)
     {
         var face = new Face(generator.GetNextFaceID())
                        {
                            Parent = solid,
                            Plane = new Plane(arr[0], arr[1], arr[2]),
                            Colour = solid.Colour,
                            Texture = { Texture = texture }
                        };
         face.Vertices.AddRange(arr.Select(x => new Vertex(x, face)));
         face.UpdateBoundingBox();
         face.AlignTextureToFace();
         solid.Faces.Add(face);
     }
     solid.UpdateBoundingBox();
     yield return solid;
 }
Exemple #5
0
        public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture)
        {
            var numsides = (int) _numSides.GetValue();
            if (numsides < 3) yield break;

            // This is all very similar to the cylinder brush.
            var width = box.Width;
            var length = box.Length;
            var major = width / 2;
            var minor = length / 2;
            var angle = 2 * DMath.PI / numsides;

            var points = new Coordinate[numsides];
            for (var i = 0; i < numsides; i++)
            {
                var a = i * angle;
                var xval = box.Center.X + major * DMath.Cos(a);
                var yval = box.Center.Y + minor * DMath.Sin(a);
                var zval = box.Start.Z;
                points[i] = new Coordinate(xval, yval, zval).Round(0);
            }

            var faces = new List<Coordinate[]>();

            var point = new Coordinate(box.Center.X, box.Center.Y, box.End.Z);
            for (var i = 0; i < numsides; i++)
            {
                var next = (i + 1) % numsides;
                faces.Add(new[] {points[i], point, points[next]});
            }
            faces.Add(points.ToArray());

            var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() };
            foreach (var arr in faces)
            {
                var face = new Face(generator.GetNextFaceID())
                {
                    Parent = solid,
                    Plane = new Plane(arr[0], arr[1], arr[2]),
                    Colour = solid.Colour,
                    Texture = { Texture = texture }
                };
                face.Vertices.AddRange(arr.Select(x => new Vertex(x, face)));
                face.UpdateBoundingBox();
                face.AlignTextureToFace();
                solid.Faces.Add(face);
            }
            solid.UpdateBoundingBox();
            yield return solid;
        }
Exemple #6
0
 public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
 {
     var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() };
     foreach (var arr in box.GetBoxFaces())
     {
         var face = new Face(generator.GetNextFaceID())
         {
             Parent = solid,
             Plane = new Plane(arr[0], arr[1], arr[2]),
             Colour = solid.Colour,
             Texture = { Texture = texture }
         };
         face.Vertices.AddRange(arr.Select(x => new Vertex(x.Round(roundDecimals), face)));
         face.UpdateBoundingBox();
         face.AlignTextureToFace();
         solid.Faces.Add(face);
     }
     solid.UpdateBoundingBox();
     yield return solid;
 }
 public void BenchmarkSolidConstruction()
 {
     var idg = new IDGenerator();
     var box = new Box(Coordinate.One * -100, Coordinate.One * 100);
     var planes = new CylinderBrush().Create(idg, box, null, 2).OfType<Solid>().SelectMany(x => x.Faces).Select(x => x.Plane).ToList();
     var stopwatch = new Stopwatch();
     stopwatch.Start();
     for (var b = 0; b < 1000; b++)
     {
         Solid.CreateFromIntersectingPlanes(planes, idg);
     }
     stopwatch.Stop();
     Debug.WriteLine(stopwatch.Elapsed);
     stopwatch.Restart();
     for (var b = 0; b < 1000; b++)
     {
         var polys = new List<Polygon>();
         for (var i = 0; i < planes.Count; i++)
         {
             var poly = new Polygon(planes[i]);
             for (var j = 0; j < planes.Count; j++)
             {
                 if (i != j) poly.Split(planes[j]);
             }
             polys.Add(poly);
         }
         var solid = new Solid(idg.GetNextObjectID());
         foreach (var polygon in polys)
         {
             var face = new Face(idg.GetNextFaceID()) {Plane = polygon.Plane};
             face.Vertices.AddRange(polygon.Vertices.Select(x => new Vertex(x, face)));
             face.UpdateBoundingBox();
             face.AlignTextureToWorld();
             solid.Faces.Add(face);
         }
         solid.UpdateBoundingBox();
     }
     stopwatch.Stop();
     Debug.WriteLine(stopwatch.Elapsed);
 }
Exemple #8
0
 private Face CreateFace(DataStructures.MapObjects.Map map, List<Coordinate> points, ObjFace objFace)
 {
     var verts = objFace.Vertices.Select(x => points[x]).ToList();
     var f = new Face(map.IDGenerator.GetNextFaceID());
     f.Plane = new Plane(verts[2], verts[1], verts[0]);
     f.Vertices.AddRange(verts.Select(x => new Vertex(x, f)).Reverse());
     f.UpdateBoundingBox();
     return f;
 }
Exemple #9
0
        private void UpdateCurrentFace(Viewport3D viewport, ViewportEvent e)
        {
            var ray = viewport.CastRayFromScreen(e.X, e.Y);

            // The face doesn't change when drawing, just update the intersection
            if (_state == SketchState.DrawingBase || _state == SketchState.DrawingVolume)
            {
                _intersection = (_state == SketchState.DrawingBase ? _currentFace.Plane : _volumePlane).GetIntersectionPoint(ray, true, true);
                return;
            }

            var isect = Document.Map.WorldSpawn.GetAllNodesIntersectingWith(ray)
                .OfType<Solid>()
                .SelectMany(x => x.Faces)
                .Select(x => new { Item = x, Intersection = x.GetIntersectionPoint(ray) })
                .Where(x => x.Intersection != null)
                .OrderBy(x => (x.Intersection - ray.Start).VectorMagnitude())
                .FirstOrDefault();

            if (isect != null)
            {
                if (_currentFace != isect.Item)
                {
                    _cloneFace = isect.Item.Clone();
                    _cloneFace.Transform(new UnitTranslate(isect.Item.Plane.Normal * 0.1m), TransformFlags.None);
                }

                _currentFace = isect.Item;
                _intersection = isect.Intersection;
                _state = SketchState.Ready;
            }
            else
            {
                _cloneFace = null;
                _currentFace = null;
                _intersection = null;
                _state = SketchState.None;
            }
        }
Exemple #10
0
 public override void Render(ViewportBase viewport)
 {
     // Render
     if (_drawing != null)
     {
         var faces = _drawing.GetBoxFaces().Select(x =>
         {
             var f = new Face(0) { Plane = new Plane(x[0], x[1], x[2])};
             f.Vertices.AddRange(x.Select(v => new Vertex(v + f.Plane.Normal * 0.1m, f)));
             return f;
         });
         MapObjectRenderer.DrawFilled(faces, Color.FromArgb(64, Color.DodgerBlue), false, false);
     }
     else if (_cloneFace != null)
     {
         MapObjectRenderer.DrawFilled(new[] { _cloneFace }, Color.FromArgb(64, Color.Orange), false, false);
     }
 }
Exemple #11
0
 public virtual void Unclone(Face f)
 {
     Paste(f);
     ID = f.ID;
 }
Exemple #12
0
 public virtual Face Copy(IDGenerator generator)
 {
     var f = new Face(generator.GetNextFaceID())
                 {
                     Plane = Plane.Clone(),
                     Colour = Colour,
                     IsSelected = IsSelected,
                     IsHidden = IsHidden,
                     Opacity = Opacity,
                     Texture = Texture.Clone(),
                     Parent = Parent,
                     BoundingBox = BoundingBox.Clone()
                 };
     foreach (var v in Vertices.Select(x => x.Clone()))
     {
         v.Parent = f;
         f.Vertices.Add(v);
     }
     return f;
 }
Exemple #13
0
        public IEnumerable<Face> GetBoxFaces()
        {
            var faces = new List<Face>();
            if (Children.Any()) return faces;

            var box = BoundingBox.GetBoxFaces();
            var dummySolid = new Solid(-1)
                                 {
                                     IsCodeHidden = IsCodeHidden,
                                     IsRenderHidden2D = IsRenderHidden2D,
                                     IsSelected = IsSelected,
                                     IsRenderHidden3D = IsRenderHidden3D,
                                     IsVisgroupHidden = IsVisgroupHidden
                                 };
            foreach (var ca in box)
            {
                var face = new Face(0)
                               {
                                   Plane = new Plane(ca[0], ca[1], ca[2]),
                                   Colour = Colour,
                                   IsSelected = IsSelected,
                                   Parent = dummySolid
                               };
                face.Vertices.AddRange(ca.Select(x => new Vertex(x, face)));
                face.UpdateBoundingBox();
                faces.Add(face);
            }
            return faces;
        }
Exemple #14
0
        private IEnumerable<Face> GetSides()
        {
            if (_state == SketchState.None || _state == SketchState.Ready || _base == null) yield break;

            var b = new Face(0) {Plane = _base.Plane};
            b.Vertices.AddRange(_base.Vertices.Select(x => new Vertex(x, b)));
            b.UpdateBoundingBox();
            yield return b;

            if (_state != SketchState.DrawingVolume) yield break;

            var t = new Face(0) { Plane = new Plane(_base.Plane.Normal, _base.Plane.PointOnPlane + _base.Plane.Normal * _depth) };
            t.Vertices.AddRange(_base.Vertices.Select(x => new Vertex(x + _base.Plane.Normal * _depth, t)));
            t.UpdateBoundingBox();
            yield return t;
        }
Exemple #15
0
 public void Deselect(Face face)
 {
     SelectedFaces.RemoveAll(x => x == face);
     face.IsSelected = false;
 }
Exemple #16
0
 public void Select(Face face)
 {
     face.IsSelected = true;
     SelectedFaces.Add(face);
     _changed = true;
 }
Exemple #17
0
        private IEnumerable<Solid> CreateSolids(DataStructures.MapObjects.Map map, List<Coordinate> points, IEnumerable<ObjFace> objFaces)
        {
            var faces = objFaces.Select(x => CreateFace(map, points, x)).ToList();

            // See if the solid is valid
            var solid = new Solid(map.IDGenerator.GetNextObjectID());
            solid.Colour = Colour.GetRandomBrushColour();
            solid.Faces.AddRange(faces);
            faces.ForEach(x => x.Parent = solid);
            if (solid.IsValid())
            {
                // Do an additional check to ensure that all edges are shared
                var edges = solid.Faces.SelectMany(x => x.GetEdges()).ToList();
                if (edges.All(x => edges.Count(y => x.EquivalentTo(y)) == 2))
                {
                    // Valid! let's get out of here!
                    yield return solid;
                    yield break;
                }
            }

            // Not a valid solid, decompose into tetrahedrons/etc
            foreach (var face in faces)
            {
                var polygon = new Polygon(face.Vertices.Select(x => x.Location));
                if (!polygon.IsValid() || !polygon.IsConvex())
                {
                    // tetrahedrons
                    foreach (var triangle in face.GetTriangles())
                    {
                        var tf = new Face(map.IDGenerator.GetNextFaceID());
                        tf.Plane = new Plane(triangle[0].Location, triangle[1].Location, triangle[2].Location);
                        tf.Vertices.AddRange(triangle.Select(x => new Vertex(x.Location, tf)));
                        tf.UpdateBoundingBox();
                        yield return SolidifyFace(map, tf);
                    }
                }
                else
                {
                    // cone/pyramid/whatever
                    yield return SolidifyFace(map, face);
                }
            }
        }
Exemple #18
0
        private Solid SolidifyFace(DataStructures.MapObjects.Map map, Face face)
        {
            var solid = new Solid(map.IDGenerator.GetNextObjectID());
            solid.Colour = Colour.GetRandomBrushColour();
            solid.Faces.Add(face);
            face.Parent = solid;
            var center = face.Vertices.Aggregate(Coordinate.Zero, (sum, v) => sum + v.Location) / face.Vertices.Count;
            var offset = center - face.Plane.Normal * 5;
            for (var i = 0; i < face.Vertices.Count; i++)
            {
                var v1 = face.Vertices[i];
                var v2 = face.Vertices[(i + 1) % face.Vertices.Count];
                var f = new Face(map.IDGenerator.GetNextFaceID());
                f.Parent = solid;
                f.Plane = new Plane(v1.Location, offset, v2.Location);
                f.Parent = solid;
                f.Vertices.Add(new Vertex(offset, f));
                f.Vertices.Add(new Vertex(v2.Location, f));
                f.Vertices.Add(new Vertex(v1.Location, f));
                f.UpdateBoundingBox();

                solid.Faces.Add(f);
            }
            return solid;
        }
Exemple #19
0
 private static Solid CreateFakeDecalSolid(Face face)
 {
     var s = new Solid(0)
                 {
                     Colour = face.Colour,
                     IsVisgroupHidden = face.IsHidden,
                     IsSelected = face.IsSelected
                 };
     s.Faces.Add(face);
     var p = face.BoundingBox.Center - face.Plane.Normal * 10; // create a new point underneath the face
     var p1 = face.Vertices[0].Location;
     var p2 = face.Vertices[1].Location;
     var p3 = face.Vertices[2].Location;
     var p4 = face.Vertices[3].Location;
     var faces = new[]
                     {
                         new[] { p2, p1, p},
                         new[] { p3, p2, p},
                         new[] { p4, p3, p},
                         new[] { p1, p4, p}
                     };
     foreach (var ff in faces)
     {
         var f = new Face(-1)
                     {
                         Colour = face.Colour,
                         IsSelected = face.IsSelected,
                         IsHidden = face.IsHidden,
                         Plane = new Plane(ff[0], ff[1], ff[2])
                     };
         f.Vertices.AddRange(ff.Select(x => new Vertex(x, f)));
         f.UpdateBoundingBox();
         s.Faces.Add(f);
     }
     s.UpdateBoundingBox();
     return s;
 }
Exemple #20
0
        public void AlignTextureWithFace(Face face)
        {
            // Get reference values for the axes
            var refU = face.Texture.UAxis;
            var refV = face.Texture.VAxis;
            // Reference points in the texture plane to use for shifting later on
            var refX = face.Texture.UAxis * face.Texture.XShift * face.Texture.XScale;
            var refY = face.Texture.VAxis * face.Texture.YShift * face.Texture.YScale;

            // Two non-parallel planes intersect at an edge. We want the textures on this face
            // to line up with the textures on the provided face. To do this, we rotate the texture
            // normal on the provided face around the intersection edge to get the new texture axes.
            // Then we rotate the texture reference point around this edge as well to get the new shift values.
            // The scale values on both faces will always end up being the same value.

            // Find the intersection edge vector
            var intersectionEdge = face.Plane.Normal.Cross(Plane.Normal);
            // Create a plane using the intersection edge as the normal
            var intersectionPlane = new Plane(intersectionEdge, 0);

            // If the planes are parallel, the texture doesn't need any rotation - just different shift values.
            var intersect = Plane.Intersect(face.Plane, Plane, intersectionPlane);
            if (intersect != null)
            {
                var texNormal = face.Texture.GetNormal();

                // Since the intersection plane is perpendicular to both face planes, we can find the angle
                // between the two planes (the original texture plane and the plane of this face) by projecting
                // the normals of the planes onto the perpendicular plane and taking the cross product.

                // Project the two normals onto the perpendicular plane
                var ptNormal = intersectionPlane.Project(texNormal).Normalise();
                var ppNormal = intersectionPlane.Project(Plane.Normal).Normalise();

                // Get the angle between the projected normals
                var dot = Math.Round(ptNormal.Dot(ppNormal), 4);
                var angle = DMath.Acos(dot); // A.B = cos(angle)

                // Rotate the texture axis by the angle around the intersection edge
                var transform = new UnitRotate(angle, new Line(Coordinate.Zero, intersectionEdge));
                refU = transform.Transform(refU);
                refV = transform.Transform(refV);

                // Rotate the texture reference points as well, but around the intersection line, not the origin
                refX = transform.Transform(refX + intersect) - intersect;
                refY = transform.Transform(refY + intersect) - intersect;
            }

            // Convert the reference points back to get the final values
            Texture.Rotation = 0;
            Texture.UAxis = refU;
            Texture.VAxis = refV;
            Texture.XShift = refU.Dot(refX) / face.Texture.XScale;
            Texture.YShift = refV.Dot(refY) / face.Texture.YScale;
            Texture.XScale = face.Texture.XScale;
            Texture.YScale = face.Texture.YScale;

            CalculateTextureCoordinates(true);
        }
Exemple #21
0
        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);
            }
        }
Exemple #22
0
 public virtual void Paste(Face f)
 {
     Plane = f.Plane.Clone();
     Colour = f.Colour;
     IsSelected = f.IsSelected;
     IsHidden = f.IsHidden;
     Opacity = f.Opacity;
     Texture = f.Texture.Clone();
     Parent = f.Parent;
     BoundingBox = f.BoundingBox.Clone();
     Vertices.Clear();
     foreach (var v in f.Vertices.Select(x => x.Clone()))
     {
         v.Parent = this;
         Vertices.Add(v);
     }
 }
Exemple #23
0
 private static Face ReadFace(BinaryReader br, IDGenerator generator)
 {
     var face = new Face(generator.GetNextFaceID());
     var textureName = br.ReadFixedLengthString(Encoding.UTF8, 256);
     br.ReadBytes(4); // Unused
     face.Texture.Name = textureName;
     face.Texture.UAxis = br.ReadCoordinate();
     face.Texture.XShift = br.ReadSingleAsDecimal();
     face.Texture.VAxis = br.ReadCoordinate();
     face.Texture.YShift = br.ReadSingleAsDecimal();
     face.Texture.Rotation = br.ReadSingleAsDecimal();
     face.Texture.XScale = br.ReadSingleAsDecimal();
     face.Texture.YScale = br.ReadSingleAsDecimal();
     br.ReadBytes(16); // Unused
     var numVerts = br.ReadInt32();
     for (var i = 0; i < numVerts; i++)
     {
         face.Vertices.Add(new Vertex(br.ReadCoordinate(), face));
     }
     face.Plane = br.ReadPlane();
     face.UpdateBoundingBox();
     return face;
 }
Exemple #24
0
 private static bool RenderTransparent(ITexture texture, Face face)
 {
     //if (face.Parent != null && face.Parent.IsTransparent) return true;
     if (texture == null || texture.Name == null) return false;
     return texture.Name.ToLower() == "aaatrigger";
 }
Exemple #25
0
 private static void WriteFace(BinaryWriter bw, Face face)
 {
     bw.WriteFixedLengthString(Encoding.UTF8, 256, face.Texture.Name);
     bw.Write(new byte[4]);
     bw.WriteCoordinate(face.Texture.UAxis);
     bw.WriteDecimalAsSingle(face.Texture.XShift);
     bw.WriteCoordinate(face.Texture.VAxis);
     bw.WriteDecimalAsSingle(face.Texture.YShift);
     bw.WriteDecimalAsSingle(face.Texture.Rotation);
     bw.WriteDecimalAsSingle(face.Texture.XScale);
     bw.WriteDecimalAsSingle(face.Texture.YScale);
     bw.Write(new byte[16]);
     bw.Write(face.Vertices.Count);
     foreach (var vertex in face.Vertices)
     {
         bw.WriteCoordinate(vertex.Location);
     }
     bw.WritePlane(face.Vertices.Select(v => v.Location).ToArray());
 }
Exemple #26
0
 public override void ToolSelected(bool preventHistory)
 {
     _state = SketchState.None;
     _currentFace = _cloneFace = null;
     _intersection = null;
     _drawing = null;
     _volumePlane = null;
 }
Exemple #27
0
 private Solid MakeSolid(IDGenerator generator, IEnumerable<Coordinate[]> faces, ITexture texture, Color col)
 {
     var solid = new Solid(generator.GetNextObjectID()) { Colour = col };
     foreach (var arr in faces)
     {
         var face = new Face(generator.GetNextFaceID())
         {
             Parent = solid,
             Plane = new Plane(arr[0], arr[1], arr[2]),
             Colour = solid.Colour,
             Texture = { Texture = texture }
         };
         face.Vertices.AddRange(arr.Select(x => new Vertex(x, face)));
         face.UpdateBoundingBox();
         face.AlignTextureToWorld();
         solid.Faces.Add(face);
     }
     solid.UpdateBoundingBox();
     return solid;
 }
Exemple #28
0
 public Vertex(Coordinate location, Face parent)
 {
     Location = location;
     Parent = parent;
     TextureV = TextureU = 0;
 }
Exemple #29
0
 public Vertex(Coordinate location, Face parent)
 {
     Location = location;
     Parent   = parent;
     TextureV = TextureU = 0;
 }
Exemple #30
0
        public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
        {
            var numsides = (int) _numSides.GetValue();
            if (numsides < 3) yield break;

            // Cylinders can be elliptical so use both major and minor rather than just the radius
            // NOTE: when a low number (< 10ish) of faces are selected this will cause the cylinder to not touch all the edges of the box.
            var width = box.Width;
            var length = box.Length;
            var height = box.Height;
            var major = width / 2;
            var minor = length / 2;
            var angle = 2 * DMath.PI / numsides;

            // Calculate the X and Y points for the ellipse
            var points = new Coordinate[numsides];
            for (var i = 0; i < numsides; i++)
            {
                var a = i * angle;
                var xval = box.Center.X + major * DMath.Cos(a);
                var yval = box.Center.Y + minor * DMath.Sin(a);
                var zval = box.Start.Z;
                points[i] = new Coordinate(xval, yval, zval).Round(roundDecimals);
            }

            var faces = new List<Coordinate[]>();

            // Add the vertical faces
            var z = new Coordinate(0, 0, height).Round(roundDecimals);
            for (var i = 0; i < numsides; i++)
            {
                var next = (i + 1) % numsides;
                faces.Add(new[] {points[i], points[i] + z, points[next] + z, points[next]});
            }
            // Add the elliptical top and bottom faces
            faces.Add(points.ToArray());
            faces.Add(points.Select(x => x + z).Reverse().ToArray());

            // Nothing new here, move along
            var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() };
            foreach (var arr in faces)
            {
                var face = new Face(generator.GetNextFaceID())
                {
                    Parent = solid,
                    Plane = new Plane(arr[0], arr[1], arr[2]),
                    Colour = solid.Colour,
                    Texture = { Texture = texture }
                };
                face.Vertices.AddRange(arr.Select(x => new Vertex(x, face)));
                face.UpdateBoundingBox();
                face.AlignTextureToFace();
                solid.Faces.Add(face);
            }
            solid.UpdateBoundingBox();
            yield return solid;
        }
Exemple #31
0
        public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
        {
            var width = box.Width;
            var length = Math.Max(1, Math.Abs((int) box.Length));
            var height = box.Height;
            var flatten = (float) _flattenFactor.Value;
            var text = _text.GetValue();

            var family = _fontChooser.GetFontFamily();
            var style = Enum.GetValues(typeof (FontStyle)).OfType<FontStyle>().FirstOrDefault(fs => family.IsStyleAvailable(fs));
            if (!family.IsStyleAvailable(style)) family = FontFamily.GenericSansSerif;

            var set = new PolygonSet();

            var sizes = new List<RectangleF>();
            using (var bmp = new Bitmap(1,1))
            {
                using (var g = System.Drawing.Graphics.FromImage(bmp))
                {
                    using (var font = new Font(family, length, style, GraphicsUnit.Pixel))
                    {
                        for (var i = 0; i < text.Length; i += 32)
                        {
                            using (var sf = new StringFormat(StringFormat.GenericTypographic))
                            {
                                var rem = Math.Min(text.Length, i + 32) - i;
                                var range = Enumerable.Range(0, rem).Select(x => new CharacterRange(x, 1)).ToArray();
                                sf.SetMeasurableCharacterRanges(range);
                                var reg = g.MeasureCharacterRanges(text.Substring(i, rem), font, new RectangleF(0, 0, float.MaxValue, float.MaxValue), sf);
                                sizes.AddRange(reg.Select(x => x.GetBounds(g)));
                            }
                        }
                    }
                }
            }

            var xOffset = box.Start.DX;
            var yOffset = box.End.DY;

            for (var ci = 0; ci < text.Length; ci++)
            {
                var c = text[ci];
                var size = sizes[ci];

                var gp = new GraphicsPath();
                gp.AddString(c.ToString(CultureInfo.InvariantCulture), family, (int)style, length, new PointF(0, 0), StringFormat.GenericTypographic);
                gp.Flatten(new System.Drawing.Drawing2D.Matrix(), flatten);

                var polygons = new List<Polygon>();
                var poly = new List<PolygonPoint>();

                for (var i = 0; i < gp.PointCount; i++)
                {
                    var type = gp.PathTypes[i];
                    var point = gp.PathPoints[i];

                    poly.Add(new PolygonPoint(point.X + xOffset, -point.Y + yOffset));

                    if ((type & 0x80) == 0x80)
                    {
                        polygons.Add(new Polygon(poly));
                        poly.Clear();
                    }
                }

                var tri = new List<Polygon>();
                Polygon polygon = null;
                foreach (var p in polygons)
                {
                    if (polygon == null)
                    {
                        polygon = p;
                        tri.Add(p);
                    }
                    else if (p.CalculateWindingOrder() != polygon.CalculateWindingOrder())
                    {
                        polygon.AddHole(p);
                    }
                    else
                    {
                        polygon = null;
                        tri.Add(p);
                    }
                }

                foreach (var pp in tri)
                {
                    try
                    {
                        P2T.Triangulate(pp);
                        set.Add(pp);
                    }
                    catch
                    {
                        // Ignore
                    }
                }

                xOffset += size.Width;
            }

            var zOffset = box.Start.Z;

            foreach (var polygon in set.Polygons)
            {
                foreach (var t in polygon.Triangles)
                {
                    var points = t.Points.Select(x => new Coordinate((decimal) x.X, (decimal) x.Y, zOffset).Round(roundDecimals)).ToList();

                    var faces = new List<Coordinate[]>();

                    // Add the vertical faces
                    var z = new Coordinate(0, 0, height).Round(roundDecimals);
                    for (var j = 0; j < points.Count; j++)
                    {
                        var next = (j + 1) % points.Count;
                        faces.Add(new[] {points[j], points[j] + z, points[next] + z, points[next]});
                    }
                    // Add the top and bottom faces
                    faces.Add(points.ToArray());
                    faces.Add(points.Select(x => x + z).Reverse().ToArray());

                    // Nothing new here, move along
                    var solid = new Solid(generator.GetNextObjectID()) {Colour = Colour.GetRandomBrushColour()};
                    foreach (var arr in faces)
                    {
                        var face = new Face(generator.GetNextFaceID())
                        {
                            Parent = solid,
                            Plane = new Plane(arr[0], arr[1], arr[2]),
                            Colour = solid.Colour,
                            Texture = {Texture = texture}
                        };
                        face.Vertices.AddRange(arr.Select(x => new Vertex(x, face)));
                        face.UpdateBoundingBox();
                        face.AlignTextureToFace();
                        solid.Faces.Add(face);
                    }
                    solid.UpdateBoundingBox();
                    yield return solid;
                }
            }
        }