public List <LuaVector2D> GetGridIntersections() { if (linedef.IsDisposed) { throw new ScriptRuntimeException("Linedef has been disposed, can't GetGridIntersections."); } List <Vector2D> intersections = linedef.GetGridIntersections(); int count = intersections.Count; List <LuaVector2D> output = new List <LuaVector2D>(count); for (int i = 0; i < count; i++) { output.Add(new LuaVector2D(intersections[i])); } return(output); }
// This moves the selected geometry relatively // Returns true when geometry has actually moved private bool MoveGeometryRelative(Vector2D offset, bool snapgrid, bool snapnearest) { Vector2D oldpos = dragitem.Position; Vector2D anchorpos = dragitemposition + offset; Vector2D tl, br; // don't move if the offset contains invalid data if (!offset.IsFinite()) { return(false); } // Find the outmost vertices tl = br = oldpositions[0]; for (int i = 0; i < oldpositions.Count; i++) { if (oldpositions[i].x < tl.x) { tl.x = (int)oldpositions[i].x; } if (oldpositions[i].x > br.x) { br.x = (int)oldpositions[i].x; } if (oldpositions[i].y > tl.y) { tl.y = (int)oldpositions[i].y; } if (oldpositions[i].y < br.y) { br.y = (int)oldpositions[i].y; } } // Snap to nearest? if (snapnearest) { // Find nearest unselected vertex within range Vertex nv = MapSet.NearestVertexSquareRange(unselectedverts, anchorpos, BuilderPlug.Me.StitchRange / renderer.Scale); if (nv != null) { // Move the dragged item dragitem.Move(nv.Position); // Adjust the offset offset = nv.Position - dragitemposition; // Do not snap to grid! snapgrid = false; } else { // Find the nearest unselected line within range Linedef nl = MapSet.NearestLinedefRange(snaptolines, anchorpos, BuilderPlug.Me.StitchRange / renderer.Scale); if (nl != null) { // Snap to grid? if (snaptogrid) { // Get grid intersection coordinates List <Vector2D> coords = nl.GetGridIntersections(); // Find nearest grid intersection float found_distance = float.MaxValue; Vector2D found_coord = new Vector2D(); foreach (Vector2D v in coords) { Vector2D delta = anchorpos - v; if (delta.GetLengthSq() < found_distance) { found_distance = delta.GetLengthSq(); found_coord = v; } } // Move the dragged item dragitem.Move(found_coord); // Align to line here offset = found_coord - dragitemposition; // Do not snap to grid anymore snapgrid = false; } else { // Move the dragged item dragitem.Move(nl.NearestOnLine(anchorpos)); // Align to line here offset = nl.NearestOnLine(anchorpos) - dragitemposition; } } } } // Snap to grid? if (snapgrid) { // Move the dragged item dragitem.Move(anchorpos); // Snap item to grid dragitem.SnapToGrid(); // Adjust the offset offset += dragitem.Position - anchorpos; } // Make sure the offset is inside the map boundaries if (offset.x + tl.x < General.Map.FormatInterface.LeftBoundary) { offset.x = General.Map.FormatInterface.LeftBoundary - tl.x; } if (offset.x + br.x > General.Map.FormatInterface.RightBoundary) { offset.x = General.Map.FormatInterface.RightBoundary - br.x; } if (offset.y + tl.y > General.Map.FormatInterface.TopBoundary) { offset.y = General.Map.FormatInterface.TopBoundary - tl.y; } if (offset.y + br.y < General.Map.FormatInterface.BottomBoundary) { offset.y = General.Map.FormatInterface.BottomBoundary - br.y; } // Drag item moved? if (!snapgrid || (dragitem.Position != oldpos)) { int i = 0; // Move selected geometry foreach (Vertex v in selectedverts) { // Move vertex from old position relative to the // mouse position change since drag start v.Move(oldpositions[i] + offset); // Next i++; } // Update labels int index = 0; foreach (Linedef l in unstablelines) { labels[index++].Move(l.Start.Position, l.End.Position); } // Moved return(true); } else { // No changes return(false); } }
public static void InsertVertex(Vector2D mousemappos, float rendererscale) { bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid; bool snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge; // Mouse in window? if (General.Interface.MouseInDisplay) { Vector2D insertpos; Linedef l = null; // Create undo General.Map.UndoRedo.CreateUndo("Insert vertex"); // Snap to geometry? l = General.Map.Map.NearestLinedefRange(mousemappos, BuilderPlug.Me.SplitLinedefsRange / rendererscale); if (snaptonearest && (l != null)) { // Snip to grid also? if (snaptogrid) { // Find all points where the grid intersects the line List <Vector2D> points = l.GetGridIntersections(); insertpos = mousemappos; float distance = float.MaxValue; foreach (Vector2D p in points) { float pdist = Vector2D.DistanceSq(p, mousemappos); if (pdist < distance) { insertpos = p; distance = pdist; } } } else { // Just use the nearest point on line insertpos = l.NearestOnLine(mousemappos); } } // Snap to grid? else if (snaptogrid) { // Snap to grid insertpos = General.Map.Grid.SnappedToGrid(mousemappos); } else { // Just insert here, don't snap to anything insertpos = mousemappos; } // Make the vertex Vertex v = General.Map.Map.CreateVertex(insertpos); if (v == null) { General.Map.UndoRedo.WithdrawUndo(); return; } // Snap to map format accuracy v.SnapToAccuracy(); // Split the line with this vertex if (snaptonearest && (l != null)) { General.Interface.DisplayStatus(StatusType.Action, "Split a linedef."); Linedef sld = l.Split(v); if (sld == null) { General.Map.UndoRedo.WithdrawUndo(); return; } BuilderPlug.Me.AdjustSplitCoordinates(l, sld); } else { General.Interface.DisplayStatus(StatusType.Action, "Inserted a vertex."); } // Update General.Map.Map.Update(); // Redraw screen General.Interface.RedrawDisplay(); } }
// Start editing protected override void OnEditBegin() { bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid; bool snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge; // Vertex highlighted? if ((highlighted != null) && !highlighted.IsDisposed) { // Edit pressed in this mode editpressed = true; // Highlighted item not selected? if (!highlighted.Selected && (BuilderPlug.Me.AutoClearSelection || (General.Map.Map.SelectedVerticessCount == 0))) { // Make this the only selection General.Map.Map.ClearSelectedVertices(); highlighted.Selected = true; General.Interface.RedrawDisplay(); } // Update display if (renderer.StartPlotter(false)) { // Redraw highlight to show selection renderer.PlotVertex(highlighted, renderer.DetermineVertexColor(highlighted)); renderer.Finish(); renderer.Present(); } } else { // Find the nearest linedef within highlight range Linedef l = General.Map.Map.NearestLinedefRange(mousemappos, BuilderPlug.Me.SplitLinedefsRange / renderer.Scale); if (l != null) { // Create undo General.Map.UndoRedo.CreateUndo("Split linedef"); Vector2D insertpos; // Snip to grid also? if (snaptogrid) { // Find all points where the grid intersects the line List <Vector2D> points = l.GetGridIntersections(); insertpos = mousemappos; float distance = float.MaxValue; foreach (Vector2D p in points) { float pdist = Vector2D.DistanceSq(p, mousemappos); if (pdist < distance) { insertpos = p; distance = pdist; } } } else { // Just use the nearest point on line insertpos = l.NearestOnLine(mousemappos); } // Make the vertex Vertex v = General.Map.Map.CreateVertex(insertpos); if (v == null) { General.Map.UndoRedo.WithdrawUndo(); return; } // Snap to map format accuracy v.SnapToAccuracy(); // Split the line with this vertex Linedef sld = l.Split(v); if (sld == null) { General.Map.UndoRedo.WithdrawUndo(); return; } BuilderPlug.Me.AdjustSplitCoordinates(l, sld); // Update General.Map.Map.Update(); // Highlight it Highlight(v); // Redraw display General.Interface.RedrawDisplay(); } else { // Start drawing mode DrawGeometryMode drawmode = new DrawGeometryMode(); DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, renderer, new List <DrawnVertex>()); if (drawmode.DrawPointAt(v)) { General.Editing.ChangeMode(drawmode); } else { General.Interface.DisplayStatus(StatusType.Warning, "Failed to draw point: outside of map boundaries."); } } } base.OnEditBegin(); }
// This returns the aligned and snapped draw position public static DrawnVertex GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, IRenderer2D renderer, List <DrawnVertex> points) { DrawnVertex p = new DrawnVertex(); Vector2D vm = mousemappos; float vrange = BuilderPlug.Me.StitchRange / renderer.Scale; // Snap to nearest? if (snaptonearest) { // Go for all drawn points foreach (DrawnVertex v in points) { if (Vector2D.DistanceSq(mousemappos, v.pos) < (vrange * vrange)) { p.pos = v.pos; p.stitch = true; p.stitchline = true; return(p); } } // Try the nearest vertex Vertex nv = General.Map.Map.NearestVertexSquareRange(mousemappos, vrange); if (nv != null) { p.pos = nv.Position; p.stitch = true; p.stitchline = true; return(p); } // Try the nearest linedef Linedef nl = General.Map.Map.NearestLinedefRange(mousemappos, BuilderPlug.Me.StitchRange / renderer.Scale); if (nl != null) { // Snap to grid? if (snaptogrid) { // Get grid intersection coordinates List <Vector2D> coords = nl.GetGridIntersections(); // Find nearest grid intersection bool found = false; float found_distance = float.MaxValue; Vector2D found_coord = new Vector2D(); foreach (Vector2D v in coords) { Vector2D delta = mousemappos - v; if (delta.GetLengthSq() < found_distance) { found_distance = delta.GetLengthSq(); found_coord = v; found = true; } } if (found) { // Align to the closest grid intersection p.pos = found_coord; p.stitch = true; p.stitchline = true; return(p); } } else { // Aligned to line p.pos = nl.NearestOnLine(mousemappos); p.stitch = true; p.stitchline = true; return(p); } } } else { // Always snap to the first drawn vertex so that the user can finish a complete sector without stitching if (points.Count > 0) { if (Vector2D.DistanceSq(mousemappos, points[0].pos) < (vrange * vrange)) { p.pos = points[0].pos; p.stitch = true; p.stitchline = false; return(p); } } } // if the mouse cursor is outside the map bondaries check if the line between the last set point and the // mouse cursor intersect any of the boundary lines. If it does, set the position to this intersection if (points.Count > 0 && (mousemappos.x < General.Map.Config.LeftBoundary || mousemappos.x > General.Map.Config.RightBoundary || mousemappos.y > General.Map.Config.TopBoundary || mousemappos.y < General.Map.Config.BottomBoundary)) { Line2D dline = new Line2D(mousemappos, points[points.Count - 1].pos); bool foundintersection = false; float u = 0.0f; List <Line2D> blines = new List <Line2D>(); // lines for left, top, right and bottom bondaries blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary)); blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.TopBoundary)); blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary)); blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary)); // check for intersections with boundaries for (int i = 0; i < blines.Count; i++) { if (!foundintersection) { // only check for intersection if the last set point is not on the // line we are checking against if (blines[i].GetSideOfLine(points[points.Count - 1].pos) != 0.0f) { foundintersection = blines[i].GetIntersection(dline, out u); } } } // if there was no intersection set the position to the last set point if (!foundintersection) { vm = points[points.Count - 1].pos; } else { vm = dline.GetCoordinatesAt(u); } } // Snap to grid? if (snaptogrid) { // Aligned to grid p.pos = General.Map.Grid.SnappedToGrid(vm); // special handling if (p.pos.x > General.Map.Config.RightBoundary) { p.pos.x = General.Map.Config.RightBoundary; } if (p.pos.y < General.Map.Config.BottomBoundary) { p.pos.y = General.Map.Config.BottomBoundary; } p.stitch = snaptonearest; p.stitchline = snaptonearest; return(p); } else { // Normal position p.pos = vm; p.stitch = snaptonearest; p.stitchline = snaptonearest; return(p); } }
// Mouse moves public override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (panning) { return; //mxd. Skip all this jazz while panning } //mxd if (selectpressed && !editpressed && !selecting) { // Check if moved enough pixels for multiselect Vector2D delta = mousedownpos - mousepos; if ((Math.Abs(delta.x) > MULTISELECT_START_MOVE_PIXELS) || (Math.Abs(delta.y) > MULTISELECT_START_MOVE_PIXELS)) { // Start multiselecting StartMultiSelection(); } } else if (paintselectpressed && !editpressed && !selecting) //mxd. Drag-select { // Find the nearest thing within highlight range Vertex v = General.Map.Map.NearestVertexSquareRange(mousemappos, BuilderPlug.Me.HighlightRange / renderer.Scale); if (v != null) { if (v != highlighted) { //toggle selected state if (General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect) { v.Selected = true; } else if (General.Interface.CtrlState) { v.Selected = false; } else { v.Selected = !v.Selected; } highlighted = v; UpdateSelectionInfo(); //mxd // Update entire display General.Interface.RedrawDisplay(); } } else if (highlighted != null) { highlighted = null; Highlight(null); // Update entire display General.Interface.RedrawDisplay(); } } else if (e.Button == MouseButtons.None) // Not holding any buttons? { //mxd. Render insert vertex preview Linedef l = General.Map.Map.NearestLinedefRange(mousemappos, BuilderPlug.Me.SplitLinedefsRange / renderer.Scale); if (l != null) { // Snip to grid? if (General.Interface.ShiftState ^ General.Interface.SnapToGrid) { // Find all points where the grid intersects the line List <Vector2D> points = l.GetGridIntersections(); if (points.Count == 0) { insertpreview = l.NearestOnLine(mousemappos); } else { insertpreview = mousemappos; float distance = float.MaxValue; foreach (Vector2D p in points) { float pdist = Vector2D.DistanceSq(p, mousemappos); if (pdist < distance) { insertpreview = p; distance = pdist; } } } } else { // Just use the nearest point on line insertpreview = l.NearestOnLine(mousemappos); } //render preview if (renderer.StartOverlay(true)) { float dist = Math.Min(Vector2D.Distance(mousemappos, insertpreview), BuilderPlug.Me.SplitLinedefsRange); byte alpha = (byte)(255 - (dist / BuilderPlug.Me.SplitLinedefsRange) * 128); float vsize = (renderer.VertexSize + 1.0f) / renderer.Scale; renderer.RenderRectangleFilled(new RectangleF(insertpreview.x - vsize, insertpreview.y - vsize, vsize * 2.0f, vsize * 2.0f), General.Colors.InfoLine.WithAlpha(alpha), true); renderer.Finish(); renderer.Present(); } } else if (insertpreview.IsFinite()) { insertpreview.x = float.NaN; //undraw preveiw if (renderer.StartOverlay(true)) { renderer.Finish(); renderer.Present(); } } // Find the nearest vertex within highlight range Vertex v = General.Map.Map.NearestVertexSquareRange(mousemappos, BuilderPlug.Me.HighlightRange / renderer.Scale); // Highlight if not the same if (v != highlighted) { Highlight(v); } } }
// This returns the aligned and snapped draw position public static DrawnVertex GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, bool snaptocardinal, bool usefourcardinaldirections, IRenderer2D renderer, List <DrawnVertex> points) { DrawnVertex p = new DrawnVertex(); p.stitch = true; //mxd. Setting these to false seems to be a good way to create invalid geometry... p.stitchline = true; //mxd snaptocardinal = (snaptocardinal && points.Count > 0); //mxd. Don't snap to cardinal when there are no points //mxd. If snap to cardinal directions is enabled and we have points, modify mouse position Vector2D vm, gridoffset; if (snaptocardinal) { Vector2D offset = mousemappos - points[points.Count - 1].pos; float angle; if (usefourcardinaldirections) { angle = Angle2D.DegToRad((General.ClampAngle((int)Angle2D.RadToDeg(offset.GetAngle()))) / 90 * 90 + 45); } else { angle = Angle2D.DegToRad((General.ClampAngle((int)Angle2D.RadToDeg(offset.GetAngle()) + 22)) / 45 * 45); } offset = new Vector2D(0, -offset.GetLength()).GetRotated(angle); vm = points[points.Count - 1].pos + offset; //mxd. We need to be snapped relative to initial position Vector2D prev = points[points.Count - 1].pos; gridoffset = prev - General.Map.Grid.SnappedToGrid(prev); } else { vm = mousemappos; gridoffset = new Vector2D(); } float vrange = BuilderPlug.Me.StitchRange / renderer.Scale; // Snap to nearest? if (snaptonearest) { // Go for all drawn points foreach (DrawnVertex v in points) { if (Vector2D.DistanceSq(vm, v.pos) < (vrange * vrange)) { p.pos = v.pos; return(p); } } // Try the nearest vertex Vertex nv = General.Map.Map.NearestVertexSquareRange(vm, vrange); if (nv != null) { //mxd. Line angle must stay the same if (snaptocardinal) { Line2D ourline = new Line2D(points[points.Count - 1].pos, vm); if (Math.Round(ourline.GetSideOfLine(nv.Position), 1) == 0) { p.pos = nv.Position; return(p); } } else { p.pos = nv.Position; return(p); } } // Try the nearest linedef. mxd. We'll need much bigger stitch distance when snapping to cardinal directions Linedef nl = General.Map.Map.NearestLinedefRange(vm, BuilderPlug.Me.StitchRange / renderer.Scale); if (nl != null) { //mxd. Line angle must stay the same if (snaptocardinal) { Line2D ourline = new Line2D(points[points.Count - 1].pos, vm); Line2D nearestline = new Line2D(nl.Start.Position, nl.End.Position); Vector2D intersection = Line2D.GetIntersectionPoint(nearestline, ourline, false); if (!float.IsNaN(intersection.x)) { // Intersection is on nearestline? float u = Line2D.GetNearestOnLine(nearestline.v1, nearestline.v2, intersection); if (u < 0f || u > 1f) { } else { p.pos = new Vector2D((float)Math.Round(intersection.x, General.Map.FormatInterface.VertexDecimals), (float)Math.Round(intersection.y, General.Map.FormatInterface.VertexDecimals)); return(p); } } } // Snap to grid? else if (snaptogrid) { // Get grid intersection coordinates List <Vector2D> coords = nl.GetGridIntersections(General.Map.Grid.GridRotate, General.Map.Grid.GridOriginX, General.Map.Grid.GridOriginY); // Find nearest grid intersection bool found = false; float found_distance = float.MaxValue; Vector2D found_coord = new Vector2D(); foreach (Vector2D v in coords) { Vector2D delta = vm - v; if (delta.GetLengthSq() < found_distance) { found_distance = delta.GetLengthSq(); found_coord = v; found = true; } } if (found) { // Align to the closest grid intersection p.pos = found_coord; return(p); } } else { // Aligned to line p.pos = nl.NearestOnLine(vm); return(p); } } } else { // Always snap to the first drawn vertex so that the user can finish a complete sector without stitching if (points.Count > 0) { if (Vector2D.DistanceSq(vm, points[0].pos) < (vrange * vrange)) { p.pos = points[0].pos; return(p); } } } // if the mouse cursor is outside the map bondaries check if the line between the last set point and the // mouse cursor intersect any of the boundary lines. If it does, set the position to this intersection if (points.Count > 0 && (mousemappos.x < General.Map.Config.LeftBoundary || mousemappos.x > General.Map.Config.RightBoundary || mousemappos.y > General.Map.Config.TopBoundary || mousemappos.y < General.Map.Config.BottomBoundary)) { Line2D dline = new Line2D(mousemappos, points[points.Count - 1].pos); bool foundintersection = false; float u = 0.0f; List <Line2D> blines = new List <Line2D>(); // lines for left, top, right and bottom boundaries blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary)); blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.TopBoundary)); blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary)); blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary)); // check for intersections with boundaries for (int i = 0; i < blines.Count; i++) { if (!foundintersection) { // only check for intersection if the last set point is not on the // line we are checking against if (blines[i].GetSideOfLine(points[points.Count - 1].pos) != 0.0f) { foundintersection = blines[i].GetIntersection(dline, out u); } } } // if there was no intersection set the position to the last set point if (!foundintersection) { vm = points[points.Count - 1].pos; } else { vm = dline.GetCoordinatesAt(u); } } // Snap to grid? if (snaptogrid) { // Aligned to grid p.pos = General.Map.Grid.SnappedToGrid(vm - gridoffset) + gridoffset; // special handling if (p.pos.x > General.Map.Config.RightBoundary) { p.pos.x = General.Map.Config.RightBoundary; } if (p.pos.y < General.Map.Config.BottomBoundary) { p.pos.y = General.Map.Config.BottomBoundary; } return(p); } else { // Normal position p.pos.x = (float)Math.Round(vm.x); //mxd p.pos.y = (float)Math.Round(vm.y); //mxd return(p); } }
// This updates the selection private void Update() { // Not in any modifying mode? if (mode == ModifyMode.None) { Vector2D prevdragoffset = alignoffset; alignoffset = new Vector2D(float.MinValue, float.MinValue); showalignoffset = false; // Check what grip the mouse is over // and change cursor accordingly Grip mousegrip = CheckMouseGrip(); switch (mousegrip) { case Grip.Main: int closestcorner = -1; float cornerdist = float.MaxValue; for (int i = 0; i < 4; i++) { Vector2D delta = corners[i] - mousemappos; float d = delta.GetLengthSq(); if (d < cornerdist) { closestcorner = i; cornerdist = d; } } switch (closestcorner) { // TODO: case 0: alignoffset = new Vector2D(0f, 0f); break; case 1: alignoffset = new Vector2D(texture.ScaledWidth, 0f); break; case 2: alignoffset = new Vector2D(texture.ScaledWidth, -texture.ScaledHeight); break; case 3: alignoffset = new Vector2D(0f, -texture.ScaledHeight); break; } showalignoffset = true; General.Interface.SetCursor(Cursors.Hand); break; case Grip.RotateLB: case Grip.RotateRT: alignoffset = new Vector2D(0f, 0f); showalignoffset = true; General.Interface.SetCursor(Cursors.Cross); break; case Grip.SizeH: case Grip.SizeV: alignoffset = new Vector2D(0f, 0f); showalignoffset = true; // Pick the best matching cursor depending on rotation and side float resizeangle = -(rotation + sectorinfo[0].rotation); if (mousegrip == Grip.SizeH) { resizeangle += Angle2D.PIHALF; } resizeangle = Angle2D.Normalized(resizeangle); if (resizeangle > Angle2D.PI) { resizeangle -= Angle2D.PI; } resizeangle = Math.Abs(resizeangle + Angle2D.PI / 8.000001f); int cursorindex = (int)Math.Floor((resizeangle / Angle2D.PI) * 4.0f) % 4; General.Interface.SetCursor(RESIZE_CURSORS[cursorindex]); break; default: General.Interface.SetCursor(Cursors.Default); break; } if (prevdragoffset != alignoffset) { General.Interface.RedrawDisplay(); } } else { Vector2D snappedmappos = mousemappos; bool dosnaptogrid = snaptogrid; // Options snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid; snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge; // Change to crosshair cursor so we can clearly see around the mouse cursor General.Interface.SetCursor(Cursors.Cross); // Check what modifying mode we are in switch (mode) { case ModifyMode.Dragging: offset = -mousemappos - dragoffset; Vector2D transformedpos = TexToWorld(alignoffset); // Snap to nearest vertex? if (snaptonearest) { float vrange = BuilderPlug.Me.StitchRange / renderer.Scale; // Try the nearest vertex Vertex nv = MapSet.NearestVertexSquareRange(General.Map.Map.Vertices, transformedpos, vrange); if (nv != null) { // Change offset to snap to target offset -= nv.Position - transformedpos; dosnaptogrid = false; } else { // Find the nearest line within range Linedef nl = MapSet.NearestLinedefRange(General.Map.Map.Linedefs, transformedpos, vrange); if (nl != null) { // Snap to grid? if (dosnaptogrid) { // Get grid intersection coordinates List <Vector2D> coords = nl.GetGridIntersections(); // Find nearest grid intersection float found_distance = float.MaxValue; Vector2D found_pos = new Vector2D(float.NaN, float.NaN); foreach (Vector2D v in coords) { Vector2D dist = transformedpos - v; if (dist.GetLengthSq() < found_distance) { // Found a better match found_distance = dist.GetLengthSq(); found_pos = v; // Do not snap to grid anymore dosnaptogrid = false; } } // Found something? if (!float.IsNaN(found_pos.x)) { // Change offset to snap to target offset -= found_pos - transformedpos; } } else { // Change offset to snap onto the line offset -= nl.NearestOnLine(transformedpos) - transformedpos; } } } } // Snap to grid? if (dosnaptogrid) { // Change offset to align to grid offset -= General.Map.Grid.SnappedToGrid(transformedpos) - transformedpos; } break; case ModifyMode.Resizing: // Snap to nearest vertex? if (snaptonearest) { float vrange = BuilderPlug.Me.StitchRange / renderer.Scale; // Try the nearest vertex Vertex nv = MapSet.NearestVertexSquareRange(General.Map.Map.Vertices, snappedmappos, vrange); if (nv != null) { snappedmappos = nv.Position; dosnaptogrid = false; } } // Snap to grid? if (dosnaptogrid) { // Aligned to grid snappedmappos = General.Map.Grid.SnappedToGrid(snappedmappos); } float newscale = 1f / resizeaxis.GetNearestOnLine(snappedmappos); if (float.IsInfinity(newscale) || float.IsNaN(newscale)) { newscale = 99999f; } scale = (newscale * resizefilter) + scale * (1.0f - resizefilter); if (float.IsInfinity(scale.x) || float.IsNaN(scale.x)) { scale.x = 99999f; } if (float.IsInfinity(scale.y) || float.IsNaN(scale.y)) { scale.y = 99999f; } // Show the extension line so that the user knows what it is aligning to UpdateRectangleComponents(); Line2D edgeline; if (resizefilter.x > resizefilter.y) { edgeline = new Line2D(corners[1], corners[2]); } else { edgeline = new Line2D(corners[3], corners[2]); } float nearestonedge = edgeline.GetNearestOnLine(snappedmappos); if (nearestonedge > 0.5f) { extensionline = new Line2D(edgeline.v1, snappedmappos); } else { extensionline = new Line2D(edgeline.v2, snappedmappos); } break; case ModifyMode.Rotating: // Snap to nearest vertex? extensionline = new Line2D(); if (snaptonearest) { float vrange = BuilderPlug.Me.StitchRange / renderer.Scale; // Try the nearest vertex Vertex nv = MapSet.NearestVertexSquareRange(General.Map.Map.Vertices, snappedmappos, vrange); if (nv != null) { snappedmappos = nv.Position; dosnaptogrid = false; // Show the extension line so that the user knows what it is aligning to extensionline = new Line2D(corners[0], snappedmappos); } } Vector2D delta = snappedmappos - rotationcenter; float deltaangle = -delta.GetAngle(); // Snap to grid? if (dosnaptogrid) { // We make 8 vectors that the rotation can snap to float founddistance = float.MaxValue; float foundrotation = rotation; for (int i = 0; i < 8; i++) { // Make the vectors float angle = (float)i * Angle2D.PI * 0.25f; Vector2D gridvec = Vector2D.FromAngle(angle); Vector3D rotvec = Vector2D.FromAngle(deltaangle + rotationoffset); // Check distance float dist = 2.0f - Vector2D.DotProduct(gridvec, rotvec); if (dist < founddistance) { foundrotation = angle; founddistance = dist; } } // Keep rotation rotation = foundrotation - sectorinfo[0].rotation; } else { rotation = deltaangle + rotationoffset - sectorinfo[0].rotation; } break; } UpdateSectors(); General.Interface.RedrawDisplay(); } }
//retrieves the current mouse position on the grid, snapped as necessary private Vector2D SnapToNearest(Vector2D vm) { float vrange = 20f / renderer.Scale; bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid; //allow temporary disable of snap by holding shift if (General.Interface.AutoMerge) //only snap to geometry if the option is enabled { // Try the nearest slope vertex SlopeVertex nh = NearestSlopeVertexSquareRange(vm, vrange); if (nh != null) { return(nh.Pos); } // Try the nearest map vertex Vertex nv = General.Map.Map.NearestVertexSquareRange(vm, vrange); if (nv != null) { return(nv.Position); } // Try the nearest linedef Linedef nl = General.Map.Map.NearestLinedefRange(vm, vrange); if (nl != null) { // Snap to grid? if (snaptogrid) { // Get grid intersection coordinates List <Vector2D> coords = nl.GetGridIntersections(); // Find nearest grid intersection bool found = false; float found_distance = float.MaxValue; Vector2D found_coord = new Vector2D(); foreach (Vector2D v in coords) { Vector2D delta = vm - v; if (delta.GetLengthSq() < found_distance) { found_distance = delta.GetLengthSq(); found_coord = v; found = true; } } if (found) { return(found_coord); } } else { return(nl.NearestOnLine(vm)); } } } //Just get the current mouse location instead if (snaptogrid) { return(General.Map.Grid.SnappedToGrid(vm)); } return(vm); }
// from CodeImp's DrawGeometryMode public static Vector2D GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, IRenderer2D renderer) { Vector2D output = new Vector2D(); Vector2D vm = mousemappos; float vrange = BuilderPlug.Me.StitchRange / renderer.Scale; // Snap to nearest? if (snaptonearest) { // Try the nearest vertex Vertex nv = General.Map.Map.NearestVertexSquareRange(mousemappos, vrange); if (nv != null) { output = nv.Position; return(output); } // Try the nearest linedef Linedef nl = General.Map.Map.NearestLinedefRange(mousemappos, BuilderPlug.Me.StitchRange / renderer.Scale); if (nl != null) { // Snap to grid? if (snaptogrid) { // Get grid intersection coordinates List <Vector2D> coords = nl.GetGridIntersections(); // Find nearest grid intersection bool found = false; float found_distance = float.MaxValue; Vector2D found_coord = new Vector2D(); foreach (Vector2D v in coords) { Vector2D delta = mousemappos - v; if (delta.GetLengthSq() < found_distance) { found_distance = delta.GetLengthSq(); found_coord = v; found = true; } } if (found) { // Align to the closest grid intersection output = found_coord; return(output); } } else { // Aligned to line output = nl.NearestOnLine(mousemappos); return(output); } } } // Snap to grid? if (snaptogrid) { // Aligned to grid output = General.Map.Grid.SnappedToGrid(vm); // special handling if (output.x > General.Map.Config.RightBoundary) { output.x = General.Map.Config.RightBoundary; } if (output.y < General.Map.Config.BottomBoundary) { output.y = General.Map.Config.BottomBoundary; } return(output); } else { // Normal position output = vm; return(output); } }
private void InsertVertex() { bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid; bool snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge; // Mouse in window? if (General.Interface.MouseInDisplay) { Vector2D insertpos; // Create undo General.Map.UndoRedo.CreateUndo("Insert vertex"); // Snap to geometry? Linedef l = MapSet.NearestLinedefRange(blockmap, mousemappos, BuilderPlug.Me.SplitLinedefsRange / renderer.Scale); if (snaptonearest && (l != null)) { // Snip to grid also? if (snaptogrid) { // Find all points where the grid intersects the line List <Vector2D> points = l.GetGridIntersections(General.Map.Grid.GridRotate, General.Map.Grid.GridOriginX, General.Map.Grid.GridOriginY); if (points.Count == 0) { //mxd. Just use the nearest point on line insertpos = l.NearestOnLine(mousemappos); } else { insertpos = mousemappos; double distance = double.MaxValue; foreach (Vector2D p in points) { double pdist = Vector2D.DistanceSq(p, mousemappos); if (pdist < distance) { insertpos = p; distance = pdist; } } } } else { // Just use the nearest point on line insertpos = l.NearestOnLine(mousemappos); } } // Snap to grid? else if (snaptogrid) { // Snap to grid insertpos = General.Map.Grid.SnappedToGrid(mousemappos); } else { // Just insert here, don't snap to anything insertpos = mousemappos; } // Make the vertex Vertex v = General.Map.Map.CreateVertex(insertpos); if (v == null) { General.Map.UndoRedo.WithdrawUndo(); return; } // Snap to map format accuracy v.SnapToAccuracy(); // Split the line with this vertex if (snaptonearest) { //mxd. Check if snapped vertex is still on top of a linedef l = MapSet.NearestLinedefRange(blockmap, v.Position, BuilderPlug.Me.SplitLinedefsRange / renderer.Scale); if (l != null) { //mxd if (v.Position == l.Start.Position || v.Position == l.End.Position) { General.Interface.DisplayStatus(StatusType.Info, "There's already a vertex here."); General.Map.UndoRedo.WithdrawUndo(); return; } General.Interface.DisplayStatus(StatusType.Action, "Split a linedef."); Linedef sld = l.Split(v); if (sld == null) { General.Map.UndoRedo.WithdrawUndo(); return; } //BuilderPlug.Me.AdjustSplitCoordinates(l, sld); } } else { General.Interface.DisplayStatus(StatusType.Action, "Inserted a vertex."); } // Create the blockmap CreateBlockmap(); // Update General.Map.Map.Update(); // Redraw screen General.Interface.RedrawDisplay(); } }
// This moves the selected geometry relatively // Returns true when geometry has actually moved private bool MoveGeometryRelative(Vector2D offset, bool snapgrid, bool snapgridincrement, bool snapnearest, bool snapcardinal) { //mxd. If snap to cardinal directions is enabled, modify the offset if (snapcardinal) { double angle = Angle2D.DegToRad((General.ClampAngle((int)Angle2D.RadToDeg(offset.GetAngle()) + 44)) / 90 * 90); offset = new Vector2D(0, -offset.GetLength()).GetRotated(angle); snapgridincrement = true; // We don't want to move the geometry away from the cardinal directions } Vector2D oldpos = dragitem.Position; Vector2D anchorpos = dragitemposition + offset; Vector2D tl, br; // don't move if the offset contains invalid data if (!offset.IsFinite()) { return(false); } // Find the outmost vertices tl = br = oldpositions[0]; for (int i = 0; i < oldpositions.Count; i++) { if (oldpositions[i].x < tl.x) { tl.x = (int)oldpositions[i].x; } if (oldpositions[i].x > br.x) { br.x = (int)oldpositions[i].x; } if (oldpositions[i].y > tl.y) { tl.y = (int)oldpositions[i].y; } if (oldpositions[i].y < br.y) { br.y = (int)oldpositions[i].y; } } // Snap to nearest? if (snapnearest) { // Find nearest unselected vertex within range Vertex nv = MapSet.NearestVertexSquareRange(unselectedverts, anchorpos, BuilderPlug.Me.StitchRange / renderer.Scale); if (nv != null) { // Move the dragged item dragitem.Move(nv.Position); // Adjust the offset offset = nv.Position - dragitemposition; // Do not snap to grid! snapgrid = false; snaptogridincrement = false; //mxd } else { // Find the nearest unselected line within range Linedef nl = MapSet.NearestLinedefRange(snaptolines, anchorpos, BuilderPlug.Me.StitchRange / renderer.Scale); if (nl != null) { // Snap to grid? if (snapgrid || snapgridincrement) { // Get grid intersection coordinates List <Vector2D> coords = nl.GetGridIntersections(snapgridincrement ? dragstartoffset : new Vector2D(), General.Map.Grid.GridRotate, General.Map.Grid.GridOriginX, General.Map.Grid.GridOriginY); // mxd. Do the rest only if we actually have some coordinates if (coords.Count > 0) { // Find nearest grid intersection double found_distance = double.MaxValue; Vector2D found_coord = new Vector2D(); foreach (Vector2D v in coords) { Vector2D delta = anchorpos - v; if (delta.GetLengthSq() < found_distance) { found_distance = delta.GetLengthSq(); found_coord = v; } } // Move the dragged item dragitem.Move(found_coord); // Align to line here offset = found_coord - dragitemposition; // Do not snap to grid anymore snapgrid = false; snapgridincrement = false; //mxd } } else { // Move the dragged item dragitem.Move(nl.NearestOnLine(anchorpos)); // Align to line here offset = nl.NearestOnLine(anchorpos) - dragitemposition; } } } } // Snap to grid or grid increment? if (snapgrid || snapgridincrement) { // Move the dragged item dragitem.Move(anchorpos); // Snap item to grid increment if (snapgridincrement) //mxd { dragitem.Move(General.Map.Grid.SnappedToGrid(dragitem.Position) - dragstartoffset); } else // Or to the grid itself { dragitem.SnapToGrid(); } // Adjust the offset offset += dragitem.Position - anchorpos; } // Make sure the offset is inside the map boundaries if (offset.x + tl.x < General.Map.Config.LeftBoundary) { offset.x = General.Map.Config.LeftBoundary - tl.x; } if (offset.x + br.x > General.Map.Config.RightBoundary) { offset.x = General.Map.Config.RightBoundary - br.x; } if (offset.y + tl.y > General.Map.Config.TopBoundary) { offset.y = General.Map.Config.TopBoundary - tl.y; } if (offset.y + br.y < General.Map.Config.BottomBoundary) { offset.y = General.Map.Config.BottomBoundary - br.y; } // Drag item moved? if ((!snapgrid && !snapgridincrement) || (dragitem.Position != oldpos)) { int i = 0; // Move selected geometry foreach (Vertex v in selectedverts) { // Move vertex from old position relative to the mouse position change since drag start v.Move(oldpositions[i++] + offset); } //mxd. Move selected things i = 0; foreach (Thing t in thingstodrag) { t.Move(oldthingpositions[i++] + offset); } // Update labels int index = 0; foreach (Linedef l in unstablelines) { labels[index++].Move(l.Start.Position, l.End.Position); } // Moved return(true); } // No changes return(false); }
// FIXME provide a version with snaptogrid based on shift key but no snaptonearest public static LuaVector2D GetMouseMapPosition(bool snaptogrid, bool snaptonearest) { Vector2D mousemappos = ScriptContext.context.mousemappos; // Snap to nearest? if (snaptonearest) { float vrange = BuilderPlug.Me.StitchRange / ScriptContext.context.rendererscale; // Try the nearest vertex Vertex nv = General.Map.Map.NearestVertexSquareRange(mousemappos, vrange); if (nv != null) { return(new LuaVector2D(nv.Position)); } // Try the nearest linedef Linedef nl = General.Map.Map.NearestLinedefRange(mousemappos, vrange); if (nl != null) { // Snap to grid? if (snaptogrid) { // Get grid intersection coordinates List <Vector2D> coords = nl.GetGridIntersections(); // Find nearest grid intersection bool found = false; float found_distance = float.MaxValue; Vector2D found_coord = new Vector2D(); foreach (Vector2D v in coords) { Vector2D delta = mousemappos - v; if (delta.GetLengthSq() < found_distance) { found_distance = delta.GetLengthSq(); found_coord = v; found = true; } } if (found) { // Align to the closest grid intersection return(new LuaVector2D(found_coord)); } } else { return(new LuaVector2D(nl.NearestOnLine(mousemappos))); } } } if (snaptogrid) { return(new LuaVector2D(General.Map.Grid.SnappedToGrid(mousemappos))); } else { return(new LuaVector2D(new Vector2D( (float)Math.Round(mousemappos.x, General.Map.FormatInterface.VertexDecimals), (float)Math.Round(mousemappos.y, General.Map.FormatInterface.VertexDecimals) ))); } }