Ejemplo n.º 1
0
        private void RenderLine(Vector3 start, Vector3 end, Plane plane, Color color, ICamera camera, Graphics graphics)
        {
            var line = new Line(start, end);
            var cls  = line.ClassifyAgainstPlane(plane);

            if (cls == PlaneClassification.Back)
            {
                return;
            }
            if (cls == PlaneClassification.Spanning)
            {
                var isect = plane.GetIntersectionPoint(line, true);
                var first = plane.OnPlane(line.Start) > 0 ? line.Start : line.End;
                if (!isect.HasValue)
                {
                    return;
                }
                line = new Line(first, isect.Value);
            }

            var st = camera.WorldToScreen(line.Start);
            var en = camera.WorldToScreen(line.End);

            using (var p = new Pen(color, 2))
            {
                graphics.DrawLine(p, st.X, st.Y, en.X, en.Y);
            }
        }
Ejemplo n.º 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);
        }
Ejemplo n.º 3
0
 public override void Dispose()
 {
     _plane = null;
     _objects = null;
     _parents = null;
     base.Dispose();
 }
Ejemplo n.º 4
0
        public void PlaneConstructionTest()
        {
            var p1 = new Coordinate(-100, -100, 100);
            var p2 = new Coordinate(100, -100, 100);
            var p3 = new Coordinate(100, 100, 100);
            var p4 = new Coordinate(0, 0, 0);
            var refPlane = new Plane(new Coordinate(0, 0, 1), 100);
            var plane = new Plane(p3, p2, p1);

            var o1 = refPlane.OnPlane(p1);
            var o2 = plane.OnPlane(p1);
            var o3 = refPlane.OnPlane(p4);
            var o4 = plane.OnPlane(p4);

            Assert.IsTrue(o1 == 0);
            Assert.IsTrue(o2 == 0);
            Assert.IsFalse(o3 == 0);
            Assert.IsFalse(o4 == 0);

            Assert.AreEqual(refPlane.A, plane.A);
            Assert.AreEqual(refPlane.B, plane.B);
            Assert.AreEqual(refPlane.C, plane.C);
            Assert.AreEqual(refPlane.D, plane.D);

            var plane2 = new Plane(new Coordinate(-192, 704, 192),
                                   new Coordinate(-192, 320, 192),
                                   new Coordinate(-192, 320, -192));
        }
Ejemplo n.º 5
0
        private void RenderLine(Vector3 start, Vector3 end, Plane plane, Color color, ICamera camera, I2DRenderer im)
        {
            var line = new Line(start, end);
            var cls  = line.ClassifyAgainstPlane(plane);

            if (cls == PlaneClassification.Back)
            {
                return;
            }
            if (cls == PlaneClassification.Spanning)
            {
                var isect = plane.GetIntersectionPoint(line, true);
                var first = plane.OnPlane(line.Start) > 0 ? line.Start : line.End;
                if (!isect.HasValue)
                {
                    return;
                }
                line = new Line(first, isect.Value);
            }

            var st = camera.WorldToScreen(line.Start);
            var en = camera.WorldToScreen(line.End);

            im.AddLine(st.ToVector2(), en.ToVector2(), color, 2);
        }
Ejemplo n.º 6
0
        public static void AlignWithTexture(this Texture tex, Plane currentPlane, Plane alignToPlane, Texture alignToTexture)
        {
            // Get reference values for the axes
            var refU = alignToTexture.UAxis;
            var refV = alignToTexture.VAxis;
            // Reference points in the texture plane to use for shifting later on
            var refX = alignToTexture.UAxis * alignToTexture.XShift * alignToTexture.XScale;
            var refY = alignToTexture.VAxis * alignToTexture.YShift * alignToTexture.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 = alignToPlane.Normal.Cross(currentPlane.Normal);

            // If the planes are parallel, the texture doesn't need any rotation - just different shift values.
            if (Math.Abs(intersectionEdge.Length()) > 0.01f)
            {
                // Create a plane using the intersection edge as the normal
                var intersectionPlane = new Plane(intersectionEdge, 0);

                var intersect = Plane.Intersect(alignToPlane, currentPlane, intersectionPlane);
                if (intersect != null)
                {
                    // Since the intersection plane is perpendicular to both face planes, we can find the angle
                    // between the two planes (the align 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 apNormal = intersectionPlane.Project(alignToPlane.Normal).Normalise();
                    var cpNormal = intersectionPlane.Project(currentPlane.Normal).Normalise();

                    // Get the angle between the projected normals
                    var dot   = Math.Round(apNormal.Dot(cpNormal), 4);
                    var angle = (float)Math.Acos(dot);  // A.B = cos(angle)

                    // Rotate the texture axis by the angle around the intersection edge
                    var transform = Matrix4x4.CreateFromAxisAngle(intersectionEdge.Normalise(), angle);
                    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.Value) - intersect.Value;
                    refY = transform.Transform(refY + intersect.Value) - intersect.Value;
                }
            }

            // Convert the reference points back to get the final values
            tex.Rotation = 0;
            tex.UAxis    = refU;
            tex.VAxis    = refV;
            tex.XShift   = refU.Dot(refX) / alignToTexture.XScale;
            tex.YShift   = refV.Dot(refY) / alignToTexture.YScale;
            tex.XScale   = alignToTexture.XScale;
            tex.YScale   = alignToTexture.YScale;
        }
Ejemplo n.º 7
0
Archivo: Clip.cs Proyecto: silky/sledge
 public Clip(IEnumerable<Solid> objects, Plane plane, bool keepFront, bool keepBack)
 {
     _objects = objects.Where(x => x.IsValid()).ToList();
     _plane = plane;
     _keepFront = keepFront;
     _keepBack = keepBack;
     _firstRun = true;
 }
Ejemplo n.º 8
0
Archivo: Line.cs Proyecto: silky/sledge
        /// <summary>
        /// Determines if this line is behind, in front, or spanning a plane.
        /// </summary>
        /// <param name="p">The plane to test against</param>
        /// <returns>A PlaneClassification value.</returns>
        public PlaneClassification ClassifyAgainstPlane(Plane p)
        {
            var start = p.OnPlane(Start);
            var end = p.OnPlane(End);

            if (start == 0 && end == 0) return PlaneClassification.OnPlane;
            if (start <= 0 && end <= 0) return PlaneClassification.Back;
            if (start >= 0 && end >= 0) return PlaneClassification.Front;
            return PlaneClassification.Spanning;
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Same as Plane.GetClosestAxisToNormal(), but prioritises the axes Z, X, Y.
        /// </summary>
        /// <param name="plane">Input plane</param>
        /// <returns>Vector3.UnitX, Vector3.UnitY, or Vector3.UnitZ depending on the plane's normal</returns>
        private static Vector3 QuakeEdClosestAxisToNormal(Plane plane)
        {
            var norm = plane.Normal.Absolute();

            if (norm.Z >= norm.X && norm.Z >= norm.Y)
            {
                return(Vector3.UnitZ);
            }
            if (norm.X >= norm.Y)
            {
                return(Vector3.UnitX);
            }
            return(Vector3.UnitY);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Determines if this polygon is behind, in front, or spanning a plane.
        /// </summary>
        /// <param name="p">The plane to test against</param>
        /// <returns>A PlaneClassification value.</returns>
        public PlaneClassification ClassifyAgainstPlane(Plane p)
        {
            int front = 0, back = 0, onplane = 0, count = Vertices.Count;

            foreach (var test in Vertices.Select(p.OnPlane))
            {
                // Vertices on the plane are both in front and behind the plane in this context
                if (test <= 0) back++;
                if (test >= 0) front++;
                if (test == 0) onplane++;
            }

            if (onplane == count) return PlaneClassification.OnPlane;
            if (front == count) return PlaneClassification.Front;
            if (back == count) return PlaneClassification.Back;
            return PlaneClassification.Spanning;
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Creates a polygon from a plane and a radius.
        /// Expands the plane to the radius size to create a large polygon with 4 vertices.
        /// </summary>
        /// <param name="plane">The polygon plane</param>
        /// <param name="radius">The polygon radius</param>
        public Polygon(Plane plane, decimal radius = 1000000m)
        {
            Plane = plane;

            // Get aligned up and right axes to the plane
            var direction = Plane.GetClosestAxisToNormal();
            var tempV = direction == Coordinate.UnitZ ? -Coordinate.UnitY : -Coordinate.UnitZ;
            var up = tempV.Cross(Plane.Normal).Normalise();
            var right = Plane.Normal.Cross(up).Normalise();

            Vertices = new List<Coordinate>
                           {
                               plane.PointOnPlane + right + up, // Top right
                               plane.PointOnPlane - right + up, // Top left
                               plane.PointOnPlane - right - up, // Bottom left
                               plane.PointOnPlane + right - up, // Bottom right
                           };
            Expand(radius);
        }
Ejemplo n.º 12
0
        private void AddLine(CircleType type, Vector3 start, Vector3 end, Plane test, CachedLines cache)
        {
            var line = new Line(start, end);
            var cls  = line.ClassifyAgainstPlane(test);

            if (cls == PlaneClassification.Back)
            {
                return;
            }
            if (cls == PlaneClassification.Spanning)
            {
                var isect = test.GetIntersectionPoint(line, true);
                var first = test.OnPlane(line.Start) > 0 ? line.Start : line.End;
                if (isect.HasValue)
                {
                    line = new Line(first, isect.Value);
                }
            }
            cache.Cache[type].Add(new Line(cache.Viewport.Camera.WorldToScreen(line.Start), cache.Viewport.Camera.WorldToScreen(line.End)));
        }
Ejemplo n.º 13
0
        private void PerformClip(MapDocument document)
        {
            var objects = document.Selection.OfType <Solid>().ToList();

            if (!objects.Any())
            {
                return;
            }

            var plane = new Plane(_clipPlanePoint1.Value, _clipPlanePoint2.Value, _clipPlanePoint3.Value);
            var clip  = new Transaction();
            var found = false;

            foreach (var solid in objects)
            {
                solid.Split(document.Map.NumberGenerator, plane, out var backSolid, out var frontSolid);
                found = true;

                // Remove the clipped solid
                clip.Add(new Detatch(solid.Hierarchy.Parent.ID, solid));

                if (_side != ClipSide.Back && frontSolid != null)
                {
                    // Add front solid
                    clip.Add(new Attach(solid.Hierarchy.Parent.ID, frontSolid));
                }

                if (_side != ClipSide.Front && backSolid != null)
                {
                    // Add back solid
                    clip.Add(new Attach(solid.Hierarchy.Parent.ID, backSolid));
                }
            }
            if (found)
            {
                MapDocumentOperation.Perform(document, clip);
            }
        }
Ejemplo n.º 14
0
        public void PlaneLineIntersectionTest()
        {
            var plane = new Plane(new Coordinate(0, 0, 1), 100);

            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 pass1 = plane.GetIntersectionPoint(passLine);
            var pass2 = plane.GetIntersectionPoint(reversePassLine, true);
            var pass3 = plane.GetIntersectionPoint(failSegment, false, true);

            var fail1 = plane.GetIntersectionPoint(reversePassLine);
            var fail2 = plane.GetIntersectionPoint(failSegment);
            var fail3 = plane.GetIntersectionPoint(failLine);

            Assert.IsNotNull(pass1);
            Assert.IsNotNull(pass2);
            Assert.IsNotNull(pass3);
            Assert.IsNull(fail1);
            Assert.IsNull(fail2);
            Assert.IsNull(fail3);
        }
Ejemplo n.º 15
0
 /// <summary>
 /// Creates a polygon from a list of points
 /// </summary>
 /// <param name="vertices">The vertices of the polygon</param>
 public Polygon(IEnumerable<Coordinate> vertices)
 {
     Vertices = vertices.ToList();
     Plane = new Plane(Vertices[0], Vertices[1], Vertices[2]);
     Simplify();
 }
Ejemplo n.º 16
0
 /// <summary>
 /// Splits this polygon by a clipping plane, discarding the front side.
 /// The original polygon is modified to be the back side of the split.
 /// </summary>
 /// <param name="clip">The clipping plane</param>
 public void Split(Plane clip)
 {
     Polygon front, back;
     if (Split(clip, out back, out front))
     {
         Unclone(back);
     }
 }
Ejemplo n.º 17
0
        /// <summary>
        /// Splits this solid into two solids by intersecting against a plane.
        /// </summary>
        /// <param name="plane">The splitting plane</param>
        /// <param name="back">The back side of the solid</param>
        /// <param name="front">The front side of the solid</param>
        /// <param name="generator">The IDGenerator to use</param>
        /// <returns>True if the plane splits the solid, false if the plane doesn't intersect</returns>
        public bool Split(Plane plane, out Solid back, out Solid front, IDGenerator generator)
        {
            back = front = null;
            // Check that this solid actually spans the plane
            var classify = Faces.Select(x => x.ClassifyAgainstPlane(plane)).Distinct().ToList();
            if (classify.All(x => x != PlaneClassification.Spanning))
            {
                if (classify.Any(x => x == PlaneClassification.Back)) back = this;
                else if (classify.Any(x => x == PlaneClassification.Front)) front = this;
                return false;
            }

            var backPlanes = new List<Plane> { plane };
            var frontPlanes = new List<Plane> { new Plane(-plane.Normal, -plane.DistanceFromOrigin) };

            foreach (var face in Faces)
            {
                var classification = face.ClassifyAgainstPlane(plane);
                if (classification != PlaneClassification.Back) frontPlanes.Add(face.Plane);
                if (classification != PlaneClassification.Front) backPlanes.Add(face.Plane);
            }

            back = CreateFromIntersectingPlanes(backPlanes, generator);
            front = CreateFromIntersectingPlanes(frontPlanes, generator);
            CopyBase(back, generator);
            CopyBase(front, generator);

            front.Faces.Union(back.Faces).ToList().ForEach(x =>
                                    {
                                        x.Texture = Faces[0].Texture.Clone();
                                        x.AlignTextureToFace();
                                        x.Colour = Colour;
                                    });
            // Restore textures (match the planes up on each face)
            foreach (var orig in Faces)
            {
                foreach (var face in back.Faces)
                {
                    var classification = face.ClassifyAgainstPlane(orig.Plane);
                    if (classification != PlaneClassification.OnPlane) continue;
                    face.Texture = orig.Texture.Clone();
                    break;
                }
                foreach (var face in front.Faces)
                {
                    var classification = face.ClassifyAgainstPlane(orig.Plane);
                    if (classification != PlaneClassification.OnPlane) continue;
                    face.Texture = orig.Texture.Clone();
                    break;
                }
            }
            front.Faces.Union(back.Faces).ToList().ForEach(x => x.CalculateTextureCoordinates(true));

            return true;
        }
Ejemplo n.º 18
0
 public override void MouseDown(ViewportBase viewport, ViewportEvent e)
 {
     //
     switch (_state)
     {
         case SketchState.None:
             // nothin
             break;
         case SketchState.Ready:
             if (e.Button != MouseButtons.Left) break;
             _drawing = new Box(_intersection, _intersection);
             _state = SketchState.DrawingBase;
             break;
         case SketchState.DrawingBase:
             if (e.Button == MouseButtons.Right)
             {
                 // Cancel
                 _state = SketchState.None;
                 _drawing = null;
             }
             else if (e.Button == MouseButtons.Left)
             {
                 _drawing = new Box(_drawing.Start, _intersection);
                 _volumePlane = new Plane(new Coordinate(_drawing.End.X, _drawing.Start.Y, _drawing.Start.Z), _drawing.End, _drawing.End + _currentFace.Plane.Normal);
                 _state = SketchState.DrawingVolume;
             }
             break;
         case SketchState.DrawingVolume:
             if (e.Button == MouseButtons.Right)
             {
                 _state = SketchState.DrawingBase;
                 _volumePlane = null;
             }
             else if (e.Button == MouseButtons.Left)
             {
                 CreateBrush(new Box(new[] {_drawing.Start, _drawing.End}));
                 _drawing = null;
                 _volumePlane = null;
                 _state = SketchState.None;
             }
             break;
         default:
             throw new ArgumentOutOfRangeException();
     }
 }
Ejemplo n.º 19
0
Archivo: Face.cs Proyecto: silky/sledge
        public virtual void Transform(IUnitTransformation transform, TransformFlags flags)
        {
            foreach (var t in Vertices)
            {
                t.Location = transform.Transform(t.Location);
            }
            Plane = new Plane(Vertices[0].Location, Vertices[1].Location, Vertices[2].Location);
            Colour = Colour;
            if (flags.HasFlag(TransformFlags.TextureScalingLock) && Texture.Texture != null)
            {
                // Make a best-effort guess of retaining scaling. All bets are off during skew operations.
                // Transform the current texture axes
                var origin = transform.Transform(Coordinate.Zero);
                var ua = transform.Transform(Texture.UAxis) - origin;
                var va = transform.Transform(Texture.VAxis) - origin;
                // Multiply the scales by the magnitudes (they were normals before the transform operation)
                Texture.XScale *= ua.VectorMagnitude();
                Texture.YScale *= va.VectorMagnitude();
            }
            {
                // Transform the texture axes and move them back to the origin
                var origin = transform.Transform(Coordinate.Zero);
                var ua = transform.Transform(Texture.UAxis) - origin;
                var va = transform.Transform(Texture.VAxis) - origin;

                // Only do the transform if the axes end up being not perpendicular
                // Otherwise just make a best-effort guess, same as the scaling lock
                if (Math.Abs(ua.Dot(va)) < 0.0001m && DMath.Abs(Plane.Normal.Dot(ua.Cross(va).Normalise())) > 0.0001m)
                {
                    Texture.UAxis = ua;
                    Texture.VAxis = va;
                }
                else
                {
                    AlignTextureToFace();
                }

                if (flags.HasFlag(TransformFlags.TextureLock) && Texture.Texture != null)
                {
                    // Check some original reference points to see how the transform mutates them
                    var scaled = (transform.Transform(Coordinate.One) - transform.Transform(Coordinate.Zero)).VectorMagnitude();
                    var original = (Coordinate.One - Coordinate.Zero).VectorMagnitude();

                    // Ignore texture lock when the transformation contains a scale
                    if (DMath.Abs(scaled - original) <= 0.01m)
                    {
                        // Calculate the new shift values based on the UV values of the vertices
                        var vtx = Vertices[0];
                        Texture.XShift = Texture.Texture.Width * vtx.TextureU - (vtx.Location.Dot(Texture.UAxis)) / Texture.XScale;
                        Texture.YShift = Texture.Texture.Height * vtx.TextureV - (vtx.Location.Dot(Texture.VAxis)) / Texture.YScale;
                    }
                }
            }
            CalculateTextureCoordinates(true);
            UpdateBoundingBox();
        }
Ejemplo n.º 20
0
Archivo: Face.cs Proyecto: silky/sledge
        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);
        }
Ejemplo n.º 21
0
 public void TestClip()
 {
     var all = _document.Map.WorldSpawn.FindAll().OfType<Solid>().ToList();
     var plane = new Plane(Coordinate.UnitZ, Coordinate.Zero);
     TestAction(new Clip(all, plane));
 }
Ejemplo n.º 22
0
 public bool EquivalentTo(Plane other, decimal delta = 0.0001m)
 {
     return Normal.EquivalentTo(other.Normal, delta)
            && Math.Abs(DistanceFromOrigin - other.DistanceFromOrigin) < delta;
 }
Ejemplo n.º 23
0
 public bool Equals(Plane other)
 {
     if (ReferenceEquals(null, other)) return false;
     if (ReferenceEquals(this, other)) return true;
     return Equals(other.Normal, Normal) && other.DistanceFromOrigin == DistanceFromOrigin;
 }
Ejemplo n.º 24
0
        private void UpdateCache(IViewport viewport, PerspectiveCamera camera)
        {
            var ccl  = camera.EyeLocation;
            var ccla = camera.Position + camera.Direction;

            var cache = _cachedLines.FirstOrDefault(x => x.Viewport == viewport);

            if (cache == null)
            {
                cache = new CachedLines(viewport);
                _cachedLines.Add(cache);
            }
            if (ccl == cache.CameraLocation && ccla == cache.CameraLookAt && cache.PivotPoint == _pivotPoint && cache.Width == viewport.Width && cache.Height == viewport.Height)
            {
                return;
            }

            var origin   = _pivotPoint;
            var distance = (ccl - origin).Length();

            if (distance <= 1)
            {
                return;
            }

            cache.CameraLocation = ccl;
            cache.CameraLookAt   = ccla;
            cache.PivotPoint     = _pivotPoint;
            cache.Width          = viewport.Width;
            cache.Height         = viewport.Height;

            var normal = (ccl - origin).Normalise();
            var right  = normal.Cross(Vector3.UnitZ).Normalise();
            var up     = normal.Cross(right).Normalise();

            var plane = new Plane(normal, origin.Dot(normal));

            const float sides = 32;
            var         diff  = (2 * Math.PI) / sides;

            var radius = 0.15f * distance;

            cache.Cache[CircleType.Outer].Clear();
            cache.Cache[CircleType.X].Clear();
            cache.Cache[CircleType.Y].Clear();
            cache.Cache[CircleType.Z].Clear();

            for (var i = 0; i < sides; i++)
            {
                var cos1 = (float)Math.Cos(diff * i);
                var sin1 = (float)Math.Sin(diff * i);
                var cos2 = (float)Math.Cos(diff * (i + 1));
                var sin2 = (float)Math.Sin(diff * (i + 1));

                // outer circle
                AddLine(CircleType.Outer,
                        origin + right * cos1 * radius * 1.2f + up * sin1 * radius * 1.2f,
                        origin + right * cos2 * radius * 1.2f + up * sin2 * radius * 1.2f,
                        plane, cache);

                cos1 *= radius;
                sin1 *= radius;
                cos2 *= radius;
                sin2 *= radius;

                // X/Y plane = Z axis
                AddLine(CircleType.Z,
                        origin + Vector3.UnitX * cos1 + Vector3.UnitY * sin1,
                        origin + Vector3.UnitX * cos2 + Vector3.UnitY * sin2,
                        plane, cache);

                // Y/Z plane = X axis
                AddLine(CircleType.X,
                        origin + Vector3.UnitY * cos1 + Vector3.UnitZ * sin1,
                        origin + Vector3.UnitY * cos2 + Vector3.UnitZ * sin2,
                        plane, cache);

                // X/Z plane = Y axis
                AddLine(CircleType.Y,
                        origin + Vector3.UnitZ * cos1 + Vector3.UnitX * sin1,
                        origin + Vector3.UnitZ * cos2 + Vector3.UnitX * sin2,
                        plane, cache);
            }
        }
Ejemplo n.º 25
0
        private void RenderCircleTypeNone(PerspectiveCamera camera, Graphics graphics)
        {
            var center = _pivotPoint;
            var origin = new Vector3(center.X, center.Y, center.Z);

            var distance = (camera.EyeLocation - origin).Length();

            if (distance <= 1)
            {
                return;
            }

            // Ensure points that can't be projected properly don't get rendered
            var screenOrigin = camera.WorldToScreen(origin);
            var sop          = new PointF(screenOrigin.X, screenOrigin.Y);
            var rec          = new RectangleF(-200, -200, camera.Width + 400, camera.Height + 400);

            if (!rec.Contains(sop))
            {
                return;
            }

            var radius = 0.15f * distance;

            var normal = Vector3.Normalize(Vector3.Subtract(camera.EyeLocation, origin));
            var right  = Vector3.Normalize(Vector3.Cross(normal, Vector3.UnitZ));
            var up     = Vector3.Normalize(Vector3.Cross(normal, right));

            graphics.SmoothingMode = SmoothingMode.HighQuality;

            const int   sides = 32;
            const float diff  = (float)(2 * Math.PI) / sides;

            for (var i = 0; i < sides; i++)
            {
                var cos1 = (float)Math.Cos(diff * i);
                var sin1 = (float)Math.Sin(diff * i);
                var cos2 = (float)Math.Cos(diff * (i + 1));
                var sin2 = (float)Math.Sin(diff * (i + 1));

                var line = new Line(
                    origin + right * cos1 * radius + up * sin1 * radius,
                    origin + right * cos2 * radius + up * sin2 * radius
                    );

                var st = camera.WorldToScreen(line.Start);
                var en = camera.WorldToScreen(line.End);

                graphics.DrawLine(Pens.DarkGray, st.X, st.Y, en.X, en.Y);

                line = new Line(
                    origin + right * cos1 * radius * 1.2f + up * sin1 * radius * 1.2f,
                    origin + right * cos2 * radius * 1.2f + up * sin2 * radius * 1.2f
                    );

                st = camera.WorldToScreen(line.Start);
                en = camera.WorldToScreen(line.End);

                graphics.DrawLine(_mouseOver == CircleType.Outer ? Pens.White : Pens.LightGray, st.X, st.Y, en.X, en.Y);
            }

            var plane = new Plane(normal, Vector3.Dot(origin, normal));

            for (var i = 0; i < sides; i++)
            {
                var cos1 = (float)Math.Cos(diff * i) * radius;
                var sin1 = (float)Math.Sin(diff * i) * radius;
                var cos2 = (float)Math.Cos(diff * (i + 1)) * radius;
                var sin2 = (float)Math.Sin(diff * (i + 1)) * radius;

                RenderLine(
                    (origin + Vector3.UnitX * cos1 + Vector3.UnitY * sin1),
                    (origin + Vector3.UnitX * cos2 + Vector3.UnitY * sin2),
                    plane,
                    _mouseOver == CircleType.Z ? Color.Blue : Color.DarkBlue,
                    camera, graphics);

                RenderLine(
                    (origin + Vector3.UnitY * cos1 + Vector3.UnitZ * sin1),
                    (origin + Vector3.UnitY * cos2 + Vector3.UnitZ * sin2),
                    plane,
                    _mouseOver == CircleType.X ? Color.Red : Color.DarkRed,
                    camera, graphics);

                RenderLine(
                    (origin + Vector3.UnitZ * cos1 + Vector3.UnitX * sin1),
                    (origin + Vector3.UnitZ * cos2 + Vector3.UnitX * sin2),
                    plane,
                    _mouseOver == CircleType.Y ? Color.Lime : Color.LimeGreen,
                    camera, graphics);
            }

            graphics.SmoothingMode = SmoothingMode.Default;
        }
Ejemplo n.º 26
0
        internal static Task ConvertBox(BufferBuilder builder, IMapObject obj, Box box)
        {
            // It's always a box, these numbers are known
            const uint numVertices = 4 * 6;

            // Pack the indices like this [ solid1 ... solidn ] [ wireframe1 ... wireframe n ]
            const uint numSolidIndices     = 36;
            const uint numWireframeIndices = numVertices * 2;

            var points  = new VertexStandard[numVertices];
            var indices = new uint[numSolidIndices + numWireframeIndices];

            var c      = obj.IsSelected ? Color.Red : obj.Data.GetOne <ObjectColor>()?.Color ?? Color.Magenta;
            var colour = new Vector4(c.R, c.G, c.B, c.A) / 255f;

            var flags = obj.IsSelected ? VertexFlags.SelectiveTransformed : VertexFlags.None;

            var vi = 0u;
            var si = 0u;
            var wi = numSolidIndices;

            foreach (var face in box.GetBoxFaces())
            {
                var offs = vi;

                var normal = new Plane(face[0], face[1], face[2]).Normal;
                foreach (var v in face)
                {
                    points[vi++] = new VertexStandard
                    {
                        Position = v,
                        Colour   = colour,
                        Normal   = normal,
                        Texture  = Vector2.Zero,
                        Tint     = Vector4.One,
                        Flags    = flags | VertexFlags.FlatColour
                    };
                }

                // Triangles - [0 1 2]  ... [0 n-1 n]
                for (uint i = 2; i < 4; i++)
                {
                    indices[si++] = offs;
                    indices[si++] = offs + i - 1;
                    indices[si++] = offs + i;
                }

                // Lines - [0 1] ... [n-1 n] [n 0]
                for (uint i = 0; i < 4; i++)
                {
                    indices[wi++] = offs + i;
                    indices[wi++] = offs + (i == 4 - 1 ? 0 : i + 1);
                }
            }

            var origin = obj.Data.GetOne <Origin>()?.Location ?? box.Center;

            var groups = new List <BufferGroup>();

            if (!obj.Data.OfType <IContentsReplaced>().Any(x => x.ContentsReplaced))
            {
                groups.Add(new BufferGroup(PipelineType.TexturedOpaque, CameraType.Perspective, 0, numSolidIndices));
            }

            groups.Add(new BufferGroup(PipelineType.Wireframe, obj.IsSelected ? CameraType.Both : CameraType.Orthographic, numSolidIndices, numWireframeIndices));

            builder.Append(points, indices, groups);

            // Also push the untransformed wireframe when selected
            if (obj.IsSelected)
            {
                for (var i = 0; i < points.Length; i++)
                {
                    points[i].Flags = VertexFlags.None;
                }
                var untransformedIndices = indices.Skip((int)numSolidIndices);
                builder.Append(points, untransformedIndices, new[]
                {
                    new BufferGroup(PipelineType.Wireframe, CameraType.Both, 0, numWireframeIndices)
                });
            }

            return(Task.FromResult(0));
        }
Ejemplo n.º 27
0
        protected override void Render(MapDocument document, BufferBuilder builder, ResourceCollector resourceCollector)
        {
            base.Render(document, builder, resourceCollector);

            if (_state != ClipState.None && _clipPlanePoint1 != null && _clipPlanePoint2 != null && _clipPlanePoint3 != null)
            {
                // Draw the lines
                var p1 = _clipPlanePoint1.Value;
                var p2 = _clipPlanePoint2.Value;
                var p3 = _clipPlanePoint3.Value;

                builder.Append(
                    new []
                {
                    new VertexStandard {
                        Position = p1, Colour = Vector4.One, Tint = Vector4.One
                    },
                    new VertexStandard {
                        Position = p2, Colour = Vector4.One, Tint = Vector4.One
                    },
                    new VertexStandard {
                        Position = p3, Colour = Vector4.One, Tint = Vector4.One
                    },
                },
                    new uint [] { 0, 1, 1, 2, 2, 0 },
                    new []
                {
                    new BufferGroup(PipelineType.Wireframe, CameraType.Both, 0, 6)
                }
                    );

                if (!p1.EquivalentTo(p2) &&
                    !p2.EquivalentTo(p3) &&
                    !p1.EquivalentTo(p3) &&
                    !document.Selection.IsEmpty)
                {
                    var plane = new Plane(p1, p2, p3);
                    var pp    = plane.ToPrecisionPlane();

                    // Draw the clipped solids
                    var faces = new List <Polygon>();
                    foreach (var solid in document.Selection.OfType <Solid>().ToList())
                    {
                        var s = solid.ToPolyhedron().ToPrecisionPolyhedron();
                        s.Split(pp, out var back, out var front);

                        if (_side != ClipSide.Front && back != null)
                        {
                            faces.AddRange(back.Polygons.Select(x => x.ToStandardPolygon()));
                        }
                        if (_side != ClipSide.Back && front != null)
                        {
                            faces.AddRange(front.Polygons.Select(x => x.ToStandardPolygon()));
                        }
                    }

                    var verts   = new List <VertexStandard>();
                    var indices = new List <int>();

                    foreach (var polygon in faces)
                    {
                        var c = verts.Count;
                        verts.AddRange(polygon.Vertices.Select(x => new VertexStandard {
                            Position = x, Colour = Vector4.One, Tint = Vector4.One
                        }));
                        for (var i = 0; i < polygon.Vertices.Count; i++)
                        {
                            indices.Add(c + i);
                            indices.Add(c + (i + 1) % polygon.Vertices.Count);
                        }
                    }

                    builder.Append(
                        verts, indices.Select(x => (uint)x),
                        new[] { new BufferGroup(PipelineType.Wireframe, CameraType.Both, 0, (uint)indices.Count) }
                        );

                    // Draw the clipping plane

                    var poly  = new DataStructures.Geometric.Precision.Polygon(pp);
                    var bbox  = document.Selection.GetSelectionBoundingBox();
                    var point = bbox.Center;
                    foreach (var boxPlane in bbox.GetBoxPlanes())
                    {
                        var proj = boxPlane.Project(point);
                        var dist = (point - proj).Length() * 0.1f;
                        var pln  = new Plane(boxPlane.Normal, proj + boxPlane.Normal * Math.Max(dist, 100)).ToPrecisionPlane();
                        if (poly.Split(pln, out var b, out _))
                        {
                            poly = b;
                        }
                    }

                    verts.Clear();
                    indices.Clear();

                    var clipPoly = poly.ToStandardPolygon();
                    var colour   = Color.FromArgb(64, Color.Turquoise).ToVector4();

                    // Add the face in both directions so it renders on both sides
                    var polies = new[] { clipPoly.Vertices.ToList(), clipPoly.Vertices.Reverse().ToList() };
                    foreach (var p in polies)
                    {
                        var offs = verts.Count;
                        verts.AddRange(p.Select(x => new VertexStandard
                        {
                            Position = x,
                            Colour   = Vector4.One,
                            Tint     = colour,
                            Flags    = VertexFlags.FlatColour
                        }));

                        for (var i = 2; i < clipPoly.Vertices.Count; i++)
                        {
                            indices.Add(offs);
                            indices.Add(offs + i - 1);
                            indices.Add(offs + i);
                        }
                    }

                    builder.Append(
                        verts, indices.Select(x => (uint)x),
                        new[] { new BufferGroup(PipelineType.TexturedAlpha, CameraType.Perspective, p1, 0, (uint)indices.Count) }
                        );
                }
            }
        }
Ejemplo n.º 28
0
Archivo: Face.cs Proyecto: silky/sledge
 public virtual void Flip()
 {
     Vertices.Reverse();
     Plane = new Plane(Vertices[0].Location, Vertices[1].Location, Vertices[2].Location);
     UpdateBoundingBox();
 }
Ejemplo n.º 29
0
 public virtual void Transform(IUnitTransformation transform, TransformFlags flags)
 {
     foreach (var t in Vertices)
     {
         t.Location = transform.Transform(t.Location);
     }
     Plane = new Plane(Vertices[0].Location, Vertices[1].Location, Vertices[2].Location);
     Colour = Colour;
     if (flags.HasFlag(TransformFlags.TextureScalingLock) && Texture.Texture != null)
     {
         // Make a best-effort guess of retaining scaling. All bets are off during skew operations.
         // Transform the current texture axes
         var origin = transform.Transform(Coordinate.Zero);
         var ua = transform.Transform(Texture.UAxis) - origin;
         var va = transform.Transform(Texture.VAxis) - origin;
         // Multiply the scales by the magnitudes (they were normals before the transform operation)
         Texture.XScale *= ua.VectorMagnitude();
         Texture.YScale *= va.VectorMagnitude();
     }
     if (flags.HasFlag(TransformFlags.TextureLock) && Texture.Texture != null)
     {
         // Transform the texture axes and move them back to the origin
         var origin = transform.Transform(Coordinate.Zero);
         var ua = transform.Transform(Texture.UAxis) - origin;
         var va = transform.Transform(Texture.VAxis) - origin;
         // Only do the transform if the axes end up being not perpendicular
         // Otherwise just make a best-effort guess, same as the scaling lock
         if (Math.Abs(ua.Dot(va)) < 0.0001m)
         {
             Texture.UAxis = ua;
             Texture.VAxis = va;
         }
         // Calculate the new shift values based on the UV values of the vertices
         var vtx = Vertices[0];
         Texture.XShift = Texture.Texture.Width * vtx.TextureU - (vtx.Location.Dot(Texture.UAxis)) / Texture.XScale;
         Texture.YShift = Texture.Texture.Height * vtx.TextureV - (vtx.Location.Dot(Texture.VAxis)) / Texture.YScale;
     }
     else
     {
         // During rotate/skew operations we'll mess up the texture axes, just reset them.
         AlignTextureToFace();
     }
     CalculateTextureCoordinates();
     UpdateBoundingBox();
 }
Ejemplo n.º 30
0
Archivo: Face.cs Proyecto: silky/sledge
        protected static Coordinate GetIntersectionPoint(IList<Coordinate> coordinates, Line line, bool ignoreDirection = false)
        {
            var plane = new Plane(coordinates[0], coordinates[1], coordinates[2]);
            var intersect = plane.GetIntersectionPoint(line, ignoreDirection);
            if (intersect == null) return null;

            // http://paulbourke.net/geometry/insidepoly/

            // The angle sum will be 2 * PI if the point is inside the face
            double sum = 0;
            for (var i = 0; i < coordinates.Count; i++)
            {
                var i1 = i;
                var i2 = (i + 1) % coordinates.Count;

                // Translate the vertices so that the intersect point is on the origin
                var v1 = coordinates[i1] - intersect;
                var v2 = coordinates[i2] - intersect;

                var m1 = v1.VectorMagnitude();
                var m2 = v2.VectorMagnitude();
                var nom = m1 * m2;
                if (nom < 0.001m)
                {
                    // intersection is at a vertex
                    return intersect;
                }
                sum += Math.Acos((double)(v1.Dot(v2) / nom));
            }

            var delta = Math.Abs(sum - Math.PI * 2);
            return (delta < 0.001d) ? intersect : null;
        }
Ejemplo n.º 31
0
        private static IEnumerable <Face> CalculateDecalGeometry(Entity entity, TextureItem decal, MapDocument document, ICollection <long> solidIds)
        {
            if (decal == null || entity.Hierarchy.Parent == null)
            {
                yield break;                                                   // Texture not found
            }
            var boxRadius = Vector3.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(entity.Origin - boxRadius, entity.Origin + boxRadius);

            // Get the faces that intersect with the decal's radius
            var lines = box.GetBoxLines().ToList();
            var faces = GetBoxIntersections(document, box)
                        .OfType <Solid>()
                        .SelectMany(x => x.Faces.Select(f => new { Solid = x, Face = f }))
                        .Where(x =>
            {
                var p = new Polygon(x.Face.Vertices);
                return(lines.Any(l => p.GetIntersectionPoint(l, true) != null));
            });

            foreach (var sf in faces)
            {
                var solid = sf.Solid;
                var face  = sf.Face;
                solidIds.Add(solid.ID);

                // Project the decal onto the face
                var center  = face.Plane.Project(entity.Origin);
                var texture = face.Texture.Clone();
                texture.Name   = decal.Name;
                texture.XShift = -decal.Width / 2f;
                texture.YShift = -decal.Height / 2f;
                var decalFace = new Face(0)
                {
                    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[]
                {
                    face.Plane.Project(center + xShift - yShift), // Bottom Right
                    face.Plane.Project(center + xShift + yShift), // Top Right
                    face.Plane.Project(center - xShift + yShift), // Top Left
                    face.Plane.Project(center - xShift - yShift)  // 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], verts[1], verts[2]);
                if (!face.Plane.Normal.EquivalentTo(vertPlane.Normal))
                {
                    Array.Reverse(verts);
                }

                decalFace.Vertices.AddRange(verts);

                // 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.Dot(decalFace.Texture.UAxis)) / decalFace.Texture.XScale;
                decalFace.Texture.YShift = -(vtx.Dot(decalFace.Texture.VAxis)) / decalFace.Texture.YScale;

                // Next, the decal geometry needs to be clipped to the face so it doesn't spill into the void
                var poly = new Polygon(decalFace.Vertices).ToPrecisionPolygon();

                foreach (var f in solid.Faces.Except(new[] { decalFace }))
                {
                    poly.Split(f.Plane.ToPrecisionPlane(), out var back, out _);
                    poly = back ?? poly;
                }

                var newFace = poly.ToStandardPolygon();

                decalFace.Vertices.Clear();
                decalFace.Vertices.AddRange(newFace.Vertices);

                // 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.2f;
                decalFace.Transform(Matrix4x4.CreateTranslation(normalAdd));

                yield return(decalFace);
            }
        }
Ejemplo n.º 32
0
 public override void ToolSelected(bool preventHistory)
 {
     _state = SketchState.None;
     _currentFace = _cloneFace = null;
     _intersection = null;
     _drawing = null;
     _volumePlane = null;
 }
Ejemplo n.º 33
0
 public void Flip()
 {
     Vertices.Reverse();
     Plane = new Plane(-Plane.Normal, Plane.PointOnPlane);
 }
Ejemplo n.º 34
0
 /// <summary>
 /// Expands this plane's points outwards from the origin by a radius value.
 /// </summary>
 /// <param name="radius">The distance the points will be from the origin after expanding</param>
 public void Expand(decimal radius)
 {
     // 1. Center the polygon at the world origin
     // 2. Normalise all the vertices
     // 3. Multiply them by the radius
     // 4. Move the polygon back to the original origin
     var origin = GetOrigin();
     Vertices = Vertices.Select(x => (x - origin).Normalise() * radius + origin).ToList();
     Plane = new Plane(Vertices[0], Vertices[1], Vertices[2]);
 }
Ejemplo n.º 35
0
 /// <summary>
 /// Splits this polygon by a clipping plane, returning the back and front planes.
 /// The original polygon is not modified.
 /// </summary>
 /// <param name="clip">The clipping plane</param>
 /// <param name="back">The back polygon</param>
 /// <param name="front">The front polygon</param>
 /// <returns>True if the split was successful</returns>
 public bool Split(Plane clip, out Polygon back, out Polygon front)
 {
     Polygon cFront, cBack;
     return Split(clip, out back, out front, out cBack, out cFront);
 }
Ejemplo n.º 36
0
        /// <summary>
        /// Splits this polygon by a clipping plane, returning the back and front planes.
        /// The original polygon is not modified.
        /// </summary>
        /// <param name="clip">The clipping plane</param>
        /// <param name="back">The back polygon</param>
        /// <param name="front">The front polygon</param>
        /// <returns>True if the split was successful</returns>
        public bool Split(Plane clip, out Polygon back, out Polygon front)
        {
            // If the polygon doesn't span the plane, return false.
            var classify = ClassifyAgainstPlane(clip);
            if (classify != PlaneClassification.Spanning)
            {
                back = front = null;
                if (classify == PlaneClassification.Back) back = this;
                else if (classify == PlaneClassification.Front) front = this;
                return false;
            }

            // Get the new front and back vertices
            var backVerts = new List<Coordinate>();
            var frontVerts = new List<Coordinate>();
            var prev = 0;

            for (var i = 0; i <= Vertices.Count; i++)
            {
                var end = Vertices[i % Vertices.Count];
                var cls = clip.OnPlane(end);

                // Check plane crossing
                if (i > 0 && cls != 0 && prev != 0 && prev != cls)
                {
                    // This line end point has crossed the plane
                    // Add the line intersect to the
                    var start = Vertices[i - 1];
                    var line = new Line(start, end);
                    var isect = clip.GetIntersectionPoint(line, true);
                    if (isect == null) throw new Exception("Expected intersection, got null.");
                    frontVerts.Add(isect);
                    backVerts.Add(isect);
                }

                // Add original points
                if (i < Vertices.Count)
                {
                    // OnPlane points get put in both polygons, doesn't generate split
                    if (cls >= 0) frontVerts.Add(end);
                    if (cls <= 0) backVerts.Add(end);
                }

                prev = cls;
            }

            back = new Polygon(backVerts);
            front = new Polygon(frontVerts);

            return true;
        }
Ejemplo n.º 37
0
 public Plane PropertyPlane(string name)
 {
     var prop = this[name];
     var defaultValue = new Plane(Coordinate.UnitZ, 0);
     if (prop == null || prop.Count(c => c == ' ') != 8) return defaultValue;
     var split = prop.Replace("(", "").Replace(")", "").Split(' ');
     decimal x1, x2, x3, y1, y2, y3, z1, z2, z3;
     if (decimal.TryParse(split[0], NumberStyles.Float, CultureInfo.InvariantCulture, out x1)
         && decimal.TryParse(split[1], NumberStyles.Float, CultureInfo.InvariantCulture, out y1)
         && decimal.TryParse(split[2], NumberStyles.Float, CultureInfo.InvariantCulture, out z1)
         && decimal.TryParse(split[3], NumberStyles.Float, CultureInfo.InvariantCulture, out x2)
         && decimal.TryParse(split[4], NumberStyles.Float, CultureInfo.InvariantCulture, out y2)
         && decimal.TryParse(split[5], NumberStyles.Float, CultureInfo.InvariantCulture, out z2)
         && decimal.TryParse(split[6], NumberStyles.Float, CultureInfo.InvariantCulture, out x3)
         && decimal.TryParse(split[7], NumberStyles.Float, CultureInfo.InvariantCulture, out y3)
         && decimal.TryParse(split[8], NumberStyles.Float, CultureInfo.InvariantCulture, out z3))
     {
         return new Plane(
             new Coordinate(x1, y1, z1).Round(),
             new Coordinate(x2, y2, z2).Round(),
             new Coordinate(x3, y3, z3).Round());
     }
     return defaultValue;
 }
Ejemplo n.º 38
0
 /// <summary>
 /// Transforms all the points in the polygon.
 /// </summary>
 /// <param name="transform">The transformation to perform</param>
 public void Transform(IUnitTransformation transform)
 {
     Vertices = Vertices.Select(transform.Transform).ToList();
     Plane = new Plane(Vertices[0], Vertices[1], Vertices[2]);
 }
Ejemplo n.º 39
0
 public override void MouseDown(ViewportBase viewport, ViewportEvent e)
 {
     //
     switch (_state)
     {
         case SketchState.None:
             // nothin
             break;
         case SketchState.Ready:
             if (e.Button != MouseButtons.Left) break;
             _base = new Polygon(_currentFace.Plane, 1);
             _base.Transform(new UnitTranslate(_intersection - _base.Vertices[0]));
             _state = SketchState.DrawingBase;
             break;
         case SketchState.DrawingBase:
             if (e.Button == MouseButtons.Right)
             {
                 // Cancel
                 _state = SketchState.None;
                 _base = null;
             }
             else if (e.Button == MouseButtons.Left)
             {
                 ExpandBase(_intersection);
                 _volumePlane = new Plane(_base.Vertices[1], _base.Vertices[2], _base.Vertices[2] + _base.Plane.Normal);
                 _state = SketchState.DrawingVolume;
             }
             break;
         case SketchState.DrawingVolume:
             if (e.Button == MouseButtons.Right)
             {
                 _state = SketchState.DrawingBase;
                 _volumePlane = null;
             }
             else if (e.Button == MouseButtons.Left)
             {
                 var diff = _intersection - _base.Vertices[2];
                 var sign = _base.Plane.OnPlane(_intersection) < 0 ? -1 : 1;
                 _depth = diff.VectorMagnitude() * sign;
                 CreateBrush(_base, _depth);
                 _base = null;
                 _volumePlane = null;
                 _state = SketchState.None;
             }
             break;
         default:
             throw new ArgumentOutOfRangeException();
     }
 }
Ejemplo n.º 40
0
        private void Split(object sender)
        {
            var face = GetSplitFace();
            if (face == null) return;

            var solid = face.Parent;

            var sel = MainTool.Points.Where(x => x.IsSelected).ToList();
            var p1 = sel[0];
            var p2 = sel[1];

            if (p1.IsMidPoint) AddAdjacentPoint(face, p1);
            if (p2.IsMidPoint) AddAdjacentPoint(face, p2);

            var polygon = new Polygon(face.Vertices.Select(x => x.Location));
            var clip = new Plane(p1.Coordinate, p2.Coordinate, p1.Coordinate + face.Plane.Normal * 10);
            Polygon back, front;
            polygon.Split(clip, out back, out front);
            if (back == null || front == null) return;

            solid.Faces.Remove(face);
            face.Parent = null;

            CreateFace(back, solid, face);
            CreateFace(front, solid, face);

            solid.UpdateBoundingBox();

            MainTool.SetDirty(true, true);
        }
Ejemplo n.º 41
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);
            }
        }