Beispiel #1
0
        protected virtual Vector3 GetResizeOrigin(MapViewport viewport, OrthographicCamera camera, Vector3 position)
        {
            var st = camera.Flatten(BoxState.Start);
            var ed = camera.Flatten(BoxState.End);

            return((st + ed) / 2);
        }
Beispiel #2
0
        private ClipState GetStateAtPoint(int x, int y, OrthographicCamera camera)
        {
            if (_clipPlanePoint1 == null || _clipPlanePoint2 == null || _clipPlanePoint3 == null)
            {
                return(ClipState.None);
            }

            var p  = camera.Flatten(camera.ScreenToWorld(new Vector3(x, y, 0)));
            var p1 = camera.Flatten(_clipPlanePoint1.Value);
            var p2 = camera.Flatten(_clipPlanePoint2.Value);
            var p3 = camera.Flatten(_clipPlanePoint3.Value);

            var d = 5 / camera.Zoom;

            if (p.X >= p1.X - d && p.X <= p1.X + d && p.Y >= p1.Y - d && p.Y <= p1.Y + d)
            {
                return(ClipState.MovingPoint1);
            }
            if (p.X >= p2.X - d && p.X <= p2.X + d && p.Y >= p2.Y - d && p.Y <= p2.Y + d)
            {
                return(ClipState.MovingPoint2);
            }
            if (p.X >= p3.X - d && p.X <= p3.X + d && p.Y >= p3.Y - d && p.Y <= p3.Y + d)
            {
                return(ClipState.MovingPoint3);
            }

            return(ClipState.None);
        }
        private RectangleF GetValidatedBounds(OrthographicCamera camera, int padding)
        {
            var vmin = camera.Flatten(camera.ScreenToWorld(new Vector3(-padding, camera.Height + padding, 0)));
            var vmax = camera.Flatten(camera.ScreenToWorld(new Vector3(camera.Width + padding, -padding, 0)));

            return(new RectangleF(vmin.X, vmin.Y, vmax.X - vmin.X, vmax.Y - vmin.Y));
        }
Beispiel #4
0
        protected override Vector3 GetResizeOrigin(MapViewport viewport, OrthographicCamera camera, Vector3 position)
        {
            var st     = camera.Flatten(BoxState.Start);
            var ed     = camera.Flatten(BoxState.End);
            var points = new[] { st, ed, new Vector3(st.X, ed.Y, 0), new Vector3(ed.X, st.Y, 0) };

            return(points.OrderBy(x => (position - x).LengthSquared()).First());
        }
Beispiel #5
0
 public override bool CanDrag(MapViewport viewport, OrthographicCamera camera, ViewportEvent e, Vector3 position)
 {
     if (Handle == ResizeHandle.Center)
     {
         const int padding = 2;
         var       box     = new Box(camera.Flatten(BoxState.Start), camera.Flatten(BoxState.End));
         var       c       = position;
         return(c.X >= box.Start.X - padding && c.Y >= box.Start.Y - padding && c.Z >= box.Start.Z - padding &&
                c.X <= box.End.X + padding && c.Y <= box.End.Y + padding && c.Z <= box.End.Z + padding);
     }
     return(base.CanDrag(viewport, camera, e, position));
 }
        protected override void DragMove(MapViewport viewport, OrthographicCamera camera, ViewportEvent e)
        {
            if (e.Button != MouseButtons.Left)
            {
                return;
            }
            if (CurrentDraggable == null || !_lastDragPoint.HasValue)
            {
                return;
            }
            var point = camera.Flatten(camera.ScreenToWorld(e.X, e.Y));
            var last  = _lastDragPoint.Value;

            OnDraggableDragMoving(viewport, camera, e, last, point, CurrentDraggable);
            if (!e.Handled)
            {
                CurrentDraggable.Drag(viewport, camera, e, last, point);
            }
            if (!e.Handled)
            {
                OnDraggableDragMoved(viewport, camera, e, last, point, CurrentDraggable);
            }
            _lastDragPoint     = point;
            _lastDragMoveEvent = e;
            Invalidate();
        }
Beispiel #7
0
        protected override void MouseMove(MapDocument document, MapViewport viewport, OrthographicCamera camera, ViewportEvent e)
        {
            if (e.Dragging || e.Button == MouseButtons.Left)
            {
                return;
            }
            var point = camera.ScreenToWorld(e.X, e.Y);

            point = camera.Flatten(point);
            IDraggable drag = null;

            foreach (var state in States)
            {
                var drags = state.GetDraggables().ToList();
                drags.Add(state);
                foreach (var draggable in drags)
                {
                    if (draggable.CanDrag(document, viewport, camera, e, point))
                    {
                        drag = draggable;
                        break;
                    }
                }
                if (drag != null)
                {
                    break;
                }
            }
            if (drag != CurrentDraggable)
            {
                CurrentDraggable?.Unhighlight(document, viewport);
                CurrentDraggable = drag;
                CurrentDraggable?.Highlight(document, viewport);
            }
        }
Beispiel #8
0
        public Matrix4x4?GetTransformationMatrix(MapViewport viewport, OrthographicCamera camera, BoxState state, MapDocument doc)
        {
            var origin = camera.ZeroUnusedCoordinate((state.OrigStart + state.OrigEnd) / 2);

            if (_origin != null)
            {
                origin = _origin.Position;
            }

            if (!_rotateStart.HasValue || !_rotateEnd.HasValue)
            {
                return(null);
            }

            var forigin = camera.Flatten(origin);

            var origv = Vector3.Normalize(_rotateStart.Value - forigin);
            var newv  = Vector3.Normalize(_rotateEnd.Value - forigin);

            var angle = Math.Acos(Math.Max(-1, Math.Min(1, origv.Dot(newv))));

            if ((origv.Cross(newv).Z < 0))
            {
                angle = 2 * Math.PI - angle;
            }

            // TODO post-beta: configurable rotation snapping
            var roundingDegrees = 15f;

            if (KeyboardState.Alt)
            {
                roundingDegrees = 1;
            }

            var deg = angle * (180 / Math.PI);
            var rnd = Math.Round(deg / roundingDegrees) * roundingDegrees;

            angle = rnd * (Math.PI / 180);

            Matrix4x4 rotm;

            if (camera.ViewType == OrthographicCamera.OrthographicType.Top)
            {
                rotm = Matrix4x4.CreateRotationZ((float)angle);
            }
            else if (camera.ViewType == OrthographicCamera.OrthographicType.Front)
            {
                rotm = Matrix4x4.CreateRotationX((float)angle);
            }
            else
            {
                rotm = Matrix4x4.CreateRotationY((float)-angle);  // The Y axis rotation goes in the reverse direction for whatever reason
            }
            var mov = Matrix4x4.CreateTranslation(-origin.X, -origin.Y, -origin.Z);
            var rot = Matrix4x4.Multiply(mov, rotm);
            var inv = Matrix4x4.Invert(mov, out var i) ? i : Matrix4x4.Identity;

            return(Matrix4x4.Multiply(rot, inv));
        }
 protected override void MouseUp(MapDocument document, MapViewport viewport, OrthographicCamera camera, ViewportEvent e)
 {
     if (CurrentDraggable == null) return;
     var point = camera.ScreenToWorld(e.X, e.Y);
     point = camera.Flatten(point);
     OnDraggableMouseUp(document, viewport, camera, e, point, CurrentDraggable);
     if (!e.Handled) CurrentDraggable.MouseUp(document, viewport, camera, e, point);
 }
 protected override void MouseClick(MapDocument document, MapViewport viewport, OrthographicCamera camera, ViewportEvent e)
 {
     if (e.Dragging || e.Button != MouseButtons.Left) return;
     if (CurrentDraggable == null) return;
     var point = camera.ScreenToWorld(e.X, e.Y);
     point = camera.Flatten(point);
     OnDraggableClicked(document, viewport, camera, e, point, CurrentDraggable);
     if (!e.Handled) CurrentDraggable.Click(document, viewport, camera, e, point);
 }
 protected override void DragStart(MapDocument document, MapViewport viewport, OrthographicCamera camera, ViewportEvent e)
 {
     if (e.Button != MouseButtons.Left) return;
     if (CurrentDraggable == null) return;
     var point = camera.Flatten(camera.ScreenToWorld(e.X, e.Y));
     OnDraggableDragStarted(document, viewport, camera, e, point, CurrentDraggable);
     if (!e.Handled) CurrentDraggable.StartDrag(document, viewport, camera, e, point);
     _lastDragPoint = point;
 }
Beispiel #12
0
        protected virtual void DrawBoxText(IViewport viewport, OrthographicCamera camera, Graphics graphics, Vector3 start, Vector3 end)
        {
            // Don't draw the text at all if the rectangle is entirely outside the viewport
            if (start.X > camera.Width || end.X < 0)
            {
                return;
            }
            if (start.Y < 0 || end.Y > camera.Height)
            {
                return;
            }

            // Find the width and height for the given projection
            var st = camera.Flatten(State.Start);
            var en = camera.Flatten(State.End);

            var widthText  = (Math.Abs(Math.Round(en.X - st.X, 1))).ToString("0.##");
            var heightText = (Math.Abs(Math.Round(en.Y - st.Y, 1))).ToString("0.##");

            using (var f = new Font(FontFamily.GenericSansSerif, SystemFonts.DefaultFont.Size * 2))
                using (var b = new SolidBrush(GetRenderBoxColour()))
                {
                    // Determine the size of the value strings
                    var mWidth  = graphics.MeasureString(widthText, f);
                    var mHeight = graphics.MeasureString(heightText, f);

                    const int padding = 6;

                    // Ensure the text is clamped inside the viewport
                    var vWidth = new Vector3((end.X + start.X - mWidth.Width) / 2, end.Y - mWidth.Height - padding, 0);
                    vWidth = Vector3.Clamp(vWidth, Vector3.Zero,
                                           new Vector3(camera.Width - mWidth.Width - padding, camera.Height - mHeight.Height - padding, 0));

                    var vHeight = new Vector3(end.X + padding, (end.Y + start.Y - mHeight.Height) / 2, 0);
                    vHeight = Vector3.Clamp(vHeight, new Vector3(0, mWidth.Height + padding, 0),
                                            new Vector3(camera.Width - mWidth.Width - padding, camera.Height - mHeight.Height - padding, 0));

                    // Draw the strings
                    graphics.DrawString(widthText, f, b, vWidth.X, vWidth.Y);
                    graphics.DrawString(heightText, f, b, vHeight.X, vHeight.Y);
                }
        }
Beispiel #13
0
        public void Render(IViewport viewport, ICollection <IMapObject> objects, OrthographicCamera camera, Vector3 worldMin, Vector3 worldMax, Graphics graphics)
        {
            if (camera.Zoom < 1)
            {
                return;
            }

            var font     = SystemFonts.DefaultFont;
            var nameFont = new Font(font, FontStyle.Bold);

            // Escape hatch in case there's too many entities on screen
            var ents = objects.OfType <Entity>().Where(x => x.EntityData != null).Where(x => !x.Data.OfType <IObjectVisibility>().Any(v => v.IsHidden)).ToList();

            if (ents.Count <= 0 || ents.Count > 100)
            {
                return;
            }

            graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
            var renderNames = camera.Zoom > 2 && ents.Count < 50;

            foreach (var ed in ents)
            {
                var c = ed.Color?.Color ?? Color.White;

                var loc = camera.WorldToScreen(ed.BoundingBox.Center);

                var box = ed.BoundingBox;
                var dim = camera.Flatten(box.Dimensions / 2);
                loc.Y -= camera.UnitsToPixels(dim.Y);

                var str        = ed.EntityData.Name;
                var targetname = ed.EntityData.Get <string>("targetname")?.Trim() ?? "";

                var size = graphics.MeasureString(str, font);

                var pos  = new PointF(loc.X - size.Width / 2, loc.Y - size.Height - 2);
                var rect = new RectangleF(pos, size);

                using (var b = new SolidBrush(c))
                {
                    graphics.DrawString(str, font, b, rect.X, rect.Y);

                    if (renderNames && targetname.Length > 0)
                    {
                        var nmms = graphics.MeasureString(targetname, nameFont);
                        graphics.DrawString(targetname, nameFont, b, loc.X - nmms.Width / 2, loc.Y + 2);
                    }
                }
            }

            nameFont.Dispose();
        }
        private List <VertexPoint> GetPoints(OrthographicCamera camera, Vector3 position, bool allowMixed, bool topmostOnly, bool oneSolidOnly)
        {
            var p = camera.Flatten(position);
            var d = 5 / camera.Zoom; // Tolerance value = 5 pixels

            // Order by the unused Vector3 in the view (which is the up axis) descending to get the "closest" point
            var points = (from pp in GetVisiblePoints()
                          let c = camera.Flatten(pp.Position)
                                  where p.X >= c.X - d && p.X <= c.X + d && p.Y >= c.Y - d && p.Y <= c.Y + d
                                  let unused = camera.GetUnusedCoordinate(pp.Position)
                                               orderby unused.X + unused.Y + unused.Z descending
                                               select pp).ToList();

            if (!allowMixed && points.Any(x => !x.IsMidpoint))
            {
                points.RemoveAll(x => x.IsMidpoint);
            }
            if (points.Count <= 0)
            {
                return(points);
            }

            var first = points[0];

            if (topmostOnly)
            {
                points = new List <VertexPoint> {
                    first
                }
            }
            ;
            if (oneSolidOnly)
            {
                points.RemoveAll(x => x.Solid != first.Solid);
            }

            return(points);
        }
Beispiel #15
0
        protected virtual void DrawBoxText(IViewport viewport, OrthographicCamera camera, I2DRenderer im, Vector3 start, Vector3 end)
        {
            // Don't draw the text at all if the rectangle is entirely outside the viewport
            if (start.X > camera.Width || end.X < 0)
            {
                return;
            }
            if (start.Y < 0 || end.Y > camera.Height)
            {
                return;
            }

            // Find the width and height for the given projection
            var st = camera.Flatten(State.Start);
            var en = camera.Flatten(State.End);

            var widthText  = (Math.Abs(Math.Round(en.X - st.X, 1))).ToString("0.##");
            var heightText = (Math.Abs(Math.Round(en.Y - st.Y, 1))).ToString("0.##");

            // Determine the size of the value strings
            var mWidth  = im.CalcTextSize(FontType.Large, widthText);
            var mHeight = im.CalcTextSize(FontType.Large, heightText);

            const int padding = 6;

            // Ensure the text is clamped inside the viewport
            var vWidth = new Vector3((end.X + start.X - mWidth.X) / 2, end.Y - mWidth.Y - padding, 0);

            vWidth = Vector3.Clamp(vWidth, Vector3.Zero, new Vector3(camera.Width - mWidth.X - padding, camera.Height - mHeight.Y - padding, 0));

            var vHeight = new Vector3(end.X + padding, (end.Y + start.Y - mHeight.Y) / 2, 0);

            vHeight = Vector3.Clamp(vHeight, new Vector3(0, mWidth.Y + padding, 0), new Vector3(camera.Width - mWidth.X - padding, camera.Height - mHeight.Y - padding, 0));

            // Draw the strings
            im.AddText(vWidth.ToVector2(), GetRenderBoxColour(), FontType.Large, widthText);
            im.AddText(vHeight.ToVector2(), GetRenderBoxColour(), FontType.Large, heightText);
        }
Beispiel #16
0
        private State GetStateAtPoint(int x, int y, OrthographicCamera camera, out Camera activeCamera)
        {
            var d = 5 / camera.Zoom;

            foreach (var cam in GetCameraList())
            {
                var p    = camera.Flatten(camera.ScreenToWorld(new Vector3(x, y, 0)));
                var pos  = camera.Flatten(cam.EyePosition);
                var look = camera.Flatten(cam.LookPosition);
                activeCamera = cam;
                if (p.X >= pos.X - d && p.X <= pos.X + d && p.Y >= pos.Y - d && p.Y <= pos.Y + d)
                {
                    return(State.MovingPosition);
                }
                if (p.X >= look.X - d && p.X <= look.X + d && p.Y >= look.Y - d && p.Y <= look.Y + d)
                {
                    return(State.MovingLook);
                }
            }

            activeCamera = null;
            return(State.None);
        }
Beispiel #17
0
        protected override void MouseDown(MapViewport viewport, OrthographicCamera camera, ViewportEvent e)
        {
            if (CurrentDraggable == null)
            {
                return;
            }
            var point = camera.ScreenToWorld(e.X, e.Y);

            point = camera.Flatten(point);
            OnDraggableMouseDown(viewport, camera, e, point, CurrentDraggable);
            if (!e.Handled)
            {
                CurrentDraggable.MouseDown(viewport, camera, e, point);
            }
            Invalidate();
        }
        public void Render(IViewport viewport, ICollection <IMapObject> objects, OrthographicCamera camera, Vector3 worldMin, Vector3 worldMax, I2DRenderer im)
        {
            if (camera.Zoom < 1)
            {
                return;
            }

            // Escape hatch in case there's too many entities on screen
            var ents = objects.OfType <Entity>().Where(x => x.EntityData != null).Where(x => !x.Data.OfType <IObjectVisibility>().Any(v => v.IsHidden)).ToList();

            if (ents.Count <= 0 || ents.Count > 1000)
            {
                return;
            }

            var renderNames = camera.Zoom > 2 && ents.Count < 50;

            foreach (var ed in ents)
            {
                var c = ed.Color?.Color ?? Color.White;

                var loc = camera.WorldToScreen(ed.BoundingBox.Center);

                var box = ed.BoundingBox;
                var dim = camera.Flatten(box.Dimensions / 2);
                loc.Y -= camera.UnitsToPixels(dim.Y);

                var str        = ed.EntityData.Name;
                var targetname = ed.EntityData.Get <string>("targetname")?.Trim() ?? "";

                var size = im.CalcTextSize(FontType.Normal, str);

                var pos = new Vector2(loc.X - size.X / 2, loc.Y - size.Y - 2);

                im.AddText(pos, c, FontType.Normal, str);

                if (renderNames && targetname.Length > 0)
                {
                    var nmms = im.CalcTextSize(FontType.Bold, targetname);
                    im.AddText(new Vector2(loc.X - nmms.X / 2, loc.Y + 2), c, FontType.Bold, targetname);
                }
            }
        }
Beispiel #19
0
        protected override void DragEnd(MapDocument document, MapViewport viewport, OrthographicCamera camera, ViewportEvent e)
        {
            if (e.Button != MouseButtons.Left)
            {
                return;
            }
            if (CurrentDraggable == null)
            {
                return;
            }
            var point = camera.ScreenToWorld(e.X, e.Y);

            point = camera.Flatten(point);
            OnDraggableDragEnded(document, viewport, camera, e, point, CurrentDraggable);
            if (!e.Handled)
            {
                CurrentDraggable.EndDrag(document, viewport, camera, e, point);
            }
            _lastDragPoint = null;
        }
        public Matrix4x4?GetTransformationMatrix(MapViewport viewport, OrthographicCamera camera, BoxState state, MapDocument doc)
        {
            var shearUpDown   = Handle == ResizeHandle.Left || Handle == ResizeHandle.Right;
            var shearTopRight = Handle == ResizeHandle.Top || Handle == ResizeHandle.Right;

            if (!_skewStart.HasValue || !_skewEnd.HasValue)
            {
                return(null);
            }

            var nsmd      = _skewEnd.Value - _skewStart.Value;
            var mouseDiff = State.Tool.SnapIfNeeded(nsmd);

            if (KeyboardState.Shift && !KeyboardState.Alt)
            {
                // todo post-beta: this is hard-coded to only work on the square grid
                var gridData = doc.Map.Data.GetOne <GridData>();
                if (gridData?.Grid is SquareGrid sg && gridData?.SnapToGrid == true)
                {
                    mouseDiff = nsmd.Snap(sg.Step / 2);
                }
            }

            var relative    = camera.Flatten(state.OrigEnd - state.OrigStart);
            var shearOrigin = (shearTopRight) ? state.OrigStart : state.OrigEnd;

            var shearAmount = new Vector3(mouseDiff.X / relative.Y, mouseDiff.Y / relative.X, 0);

            if (!shearTopRight)
            {
                shearAmount *= -1;
            }

            var shearMatrix = Matrix4x4.Identity;
            var sax         = shearAmount.X;
            var say         = shearAmount.Y;

            switch (camera.ViewType)
            {
            case OrthographicCamera.OrthographicType.Top:
                if (shearUpDown)
                {
                    shearMatrix.M12 = say;
                }
                else
                {
                    shearMatrix.M21 = sax;
                }
                break;

            case OrthographicCamera.OrthographicType.Front:
                if (shearUpDown)
                {
                    shearMatrix.M23 = say;
                }
                else
                {
                    shearMatrix.M32 = sax;
                }
                break;

            case OrthographicCamera.OrthographicType.Side:
                if (shearUpDown)
                {
                    shearMatrix.M13 = say;
                }
                else
                {
                    shearMatrix.M31 = sax;
                }
                break;
            }

            var stran = Matrix4x4.CreateTranslation(-shearOrigin.X, -shearOrigin.Y, -shearOrigin.Z);
            var shear = Matrix4x4.Multiply(stran, shearMatrix);
            var inv   = Matrix4x4.Invert(stran, out var i) ? i : Matrix4x4.Identity;

            return(Matrix4x4.Multiply(shear, inv));
        }
Beispiel #21
0
        public Vector3 SnapToSelection(Vector3 c, OrthographicCamera camera)
        {
            var doc      = GetDocument();
            var gridData = doc?.Map.Data.GetOne <GridData>();
            var snap     = !KeyboardState.Alt && gridData?.SnapToGrid == true;

            if (doc == null || !snap)
            {
                return(c.Snap(1));
            }

            var snapped = gridData.Grid?.Snap(c) ?? c.Snap(1);

            if (doc.Selection.IsEmpty)
            {
                return(snapped);
            }

            // Try and snap the the selection box center
            var selBox    = doc.Selection.GetSelectionBoundingBox();
            var selCenter = camera.Flatten(selBox.Center);

            if (Math.Abs(selCenter.X - c.X) < selBox.Width / 10 && Math.Abs(selCenter.Y - c.Y) < selBox.Height / 10)
            {
                return(selCenter);
            }

            var objects = doc.Selection.ToList();

            // Try and snap to an object center
            foreach (var mo in objects)
            {
                if (mo is Group || mo is Root)
                {
                    continue;
                }
                var center = camera.Flatten(mo.BoundingBox.Center);
                if (Math.Abs(center.X - c.X) >= mo.BoundingBox.Width / 10f)
                {
                    continue;
                }
                if (Math.Abs(center.Y - c.Y) >= mo.BoundingBox.Height / 10f)
                {
                    continue;
                }
                return(center);
            }

            // Get all the edges of the selected objects
            var lines = objects
                        .SelectMany(x => x.GetPolygons())
                        .SelectMany(x => x.GetLines())
                        .Select(x => new Line(camera.Flatten(x.Start), camera.Flatten(x.End)))
                        .ToList();

            // Try and snap to an edge
            var closest = snapped;

            foreach (var line in lines)
            {
                // if the line and the grid are in the same spot, return the snapped point
                if (line.ClosestPoint(snapped).EquivalentTo(snapped))
                {
                    return(snapped);
                }

                // Test for corners and midpoints within a 10% tolerance
                var pointTolerance = (line.End - line.Start).Length() / 10;
                if ((line.Start - c).Length() < pointTolerance)
                {
                    return(line.Start);
                }
                if ((line.End - c).Length() < pointTolerance)
                {
                    return(line.End);
                }

                var center = (line.Start + line.End) / 2;
                if ((center - c).Length() < pointTolerance)
                {
                    return(center);
                }

                // If the line is closer to the grid point, return the line
                var lineSnap = line.ClosestPoint(c);
                if ((closest - c).Length() > (lineSnap - c).Length())
                {
                    closest = lineSnap;
                }
            }
            return(closest);
        }