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