public LuaVector2D NearestOnLine(LuaVector2D pos) { if (linedef.IsDisposed) { throw new ScriptRuntimeException("Linedef has been disposed, can't NearestOnLine."); } return(new LuaVector2D(linedef.NearestOnLine(pos.vec))); }
public JitterSectorsForm(string editingModeName) { this.editingModeName = editingModeName; InitializeComponent(); //get selection List <Vertex> verts = new List <Vertex>(); List <Sector> sectors = new List <Sector>(); if (editingModeName == "BaseVisualMode") { VisualMode vm = (VisualMode)General.Editing.Mode; List <VisualGeometry> visualGeometry = vm.GetSelectedSurfaces(); visualSectors = new List <VisualSector>(); //get selected visual and regular sectors foreach (VisualGeometry vg in visualGeometry) { if (vg.GeometryType != VisualGeometryType.CEILING && vg.GeometryType != VisualGeometryType.FLOOR) { continue; } if (vg.Sector != null && vg.Sector.Sector != null) { foreach (Sidedef sd in vg.Sector.Sector.Sidedefs) { if (!verts.Contains(sd.Line.Start)) { verts.Add(sd.Line.Start); } if (!verts.Contains(sd.Line.End)) { verts.Add(sd.Line.End); } } sectors.Add(vg.Sector.Sector); visualSectors.Add(vg.Sector); } } //also get visual sectors around selected ones (because they also may be affected) List <Vertex> affectedVerts = new List <Vertex>(); foreach (Sector s in sectors) { foreach (Sidedef sd in s.Sidedefs) { if (!affectedVerts.Contains(sd.Line.Start)) { affectedVerts.Add(sd.Line.Start); } if (!affectedVerts.Contains(sd.Line.End)) { affectedVerts.Add(sd.Line.End); } } } List <Sector> affectedSectors = new List <Sector>(); foreach (Vertex v in affectedVerts) { foreach (Linedef l in v.Linedefs) { if (l.Front != null && !sectors.Contains(l.Front.Sector) && !affectedSectors.Contains(l.Front.Sector) && vm.VisualSectorExists(l.Front.Sector)) { visualSectors.Add(vm.GetVisualSector(l.Front.Sector)); affectedSectors.Add(l.Front.Sector); } if (l.Back != null && !sectors.Contains(l.Back.Sector) && !affectedSectors.Contains(l.Back.Sector) && vm.VisualSectorExists(l.Back.Sector)) { visualSectors.Add(vm.GetVisualSector(l.Back.Sector)); affectedSectors.Add(l.Back.Sector); } } } visualVerts = new List <VisualVertexPair>(); foreach (Vertex vert in affectedVerts) { if (vm.VisualVertices.ContainsKey(vert)) { visualVerts.Add(vm.VisualVertices[vert]); } } } else if (editingModeName == "SectorsMode") { ICollection <Sector> list = General.Map.Map.GetSelectedSectors(true); foreach (Sector s in list) { foreach (Sidedef sd in s.Sidedefs) { if (!verts.Contains(sd.Line.Start)) { verts.Add(sd.Line.Start); } if (!verts.Contains(sd.Line.End)) { verts.Add(sd.Line.End); } } sectors.Add(s); } } if (verts.Count == 0 || sectors.Count == 0) { General.Interface.DisplayStatus(StatusType.Warning, "Unable to get sectors from selection!"); return; } //create undo General.Map.UndoRedo.ClearAllRedos(); General.Map.UndoRedo.CreateUndo("Randomize " + sectors.Count + (sectors.Count > 1 ? " sectors" : " sector")); //update window header this.Text = "Randomize " + sectors.Count + (sectors.Count > 1 ? " sectors" : " sector"); //store intial properties //process verts... Dictionary <Vertex, TranslationOffsetVertexData> data = new Dictionary <Vertex, TranslationOffsetVertexData>(); foreach (Vertex v in verts) { TranslationOffsetVertexData vd = new TranslationOffsetVertexData(); vd.Vertex = v; vd.InitialPosition = v.Position; data.Add(v, vd); } foreach (Vertex v in verts) { if (v.Linedefs == null) { continue; } //get nearest linedef Linedef closestLine = null; double distance = double.MaxValue; // Go for all linedefs in selection foreach (Linedef l in General.Map.Map.Linedefs) { if (v.Linedefs.Contains(l)) { continue; } // Calculate distance and check if closer than previous find double d = l.SafeDistanceToSq(v.Position, true); if (d < distance) { // This one is closer closestLine = l; distance = d; } } if (closestLine == null) { continue; } double closestLineDistance = Vector2D.Distance(v.Position, closestLine.NearestOnLine(v.Position)); //check SafeDistance of closest line if (data.ContainsKey(closestLine.Start) && data[closestLine.Start].SafeDistance > closestLineDistance) { TranslationOffsetVertexData vd = data[closestLine.Start]; vd.SafeDistance = (int)Math.Floor(closestLineDistance); data[closestLine.Start] = vd; } if (data.ContainsKey(closestLine.End) && data[closestLine.End].SafeDistance > closestLineDistance) { TranslationOffsetVertexData vd = data[closestLine.End]; vd.SafeDistance = (int)Math.Floor(closestLineDistance); data[closestLine.End] = vd; } //save SafeDistance int dist = (int)Math.Floor(closestLineDistance); if (data[v].SafeDistance == 0 || data[v].SafeDistance > dist) { TranslationOffsetVertexData vd = data[v]; vd.SafeDistance = dist; data[v] = vd; } } //store properties vertexData = new TranslationOffsetVertexData[data.Values.Count]; data.Values.CopyTo(vertexData, 0); for (int i = 0; i < data.Count; i++) { if (vertexData[i].SafeDistance > 0) { vertexData[i].SafeDistance /= 2; } if (MaxSafeDistance < vertexData[i].SafeDistance) { MaxSafeDistance = vertexData[i].SafeDistance; } } //process sectors and linedes sectorData = new List <SectorData>(); sidedefData = new List <SidedefData>(); foreach (Sector s in sectors) { SectorData sd = new SectorData(); sd.Sector = s; sd.InitialCeilingHeight = s.CeilHeight; sd.InitialFloorHeight = s.FloorHeight; sd.Triangular = General.Map.UDMF && s.Sidedefs.Count == 3; if (sd.Triangular) { Vertex[] sectorverts = GetSectorVerts(s); sd.Verts = new HeightOffsetVertexData[sectorverts.Length]; for (int i = 0; i < sectorverts.Length; i++) { HeightOffsetVertexData vd = new HeightOffsetVertexData(); vd.Vertex = sectorverts[i]; vd.ZFloor = sectorverts[i].ZFloor; vd.ZCeiling = sectorverts[i].ZCeiling; vd.InitialFloorHeight = double.IsNaN(vd.ZFloor) ? GetHighestFloor(sectorverts[i]) : sectorverts[i].ZFloor; vd.InitialCeilingHeight = double.IsNaN(vd.ZCeiling) ? GetLowestCeiling(sectorverts[i]) : sectorverts[i].ZCeiling; sd.Verts[i] = vd; } } sd.SafeDistance = (s.CeilHeight - s.FloorHeight) / 2; if (sd.SafeDistance > MaxSafeHeightDistance) { MaxSafeHeightDistance = sd.SafeDistance; } sectorData.Add(sd); foreach (Sidedef side in s.Sidedefs) { //store initial sidedef properties SidedefData sdd = new SidedefData(); sdd.Side = side; sdd.LowTexture = side.LowTexture; sdd.HighTexture = side.HighTexture; sdd.PegBottom = side.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag); sdd.PegTop = side.Line.IsFlagSet(General.Map.Config.UpperUnpeggedFlag); if (side.Other != null && !sectors.Contains(side.Other.Sector)) { sdd.UpdateTextureOnOtherSide = true; sdd.OtherHighTexture = side.Other.HighTexture; sdd.OtherLowTexture = side.Other.LowTexture; } sidedefData.Add(sdd); } } positionJitterAmmount.Maximum = MaxSafeDistance; floorHeightAmmount.Maximum = MaxSafeHeightDistance; ceilingHeightAmmount.Maximum = MaxSafeHeightDistance; //set editing settings cbKeepExistingTextures.Checked = keepExistingSideTextures; ceiloffsetmode.SelectedIndex = storedceiloffsetmode; flooroffsetmode.SelectedIndex = storedflooroffsetmode; //vertex heights can not be set in non-UDMF maps if (General.Map.UDMF) { cbUseFloorVertexHeights.Checked = useFloorVertexHeights; cbUseCeilingVertexHeights.Checked = useCeilingVertexHeights; } else { useFloorVertexHeights = false; cbUseFloorVertexHeights.Checked = false; cbUseFloorVertexHeights.Enabled = false; useCeilingVertexHeights = false; cbUseCeilingVertexHeights.Checked = false; cbUseCeilingVertexHeights.Enabled = false; } //texture pickers textureLower.Initialize(); textureUpper.Initialize(); //We can't use floor/ceiling textures when MixTexturesFlats is disabled if (General.Map.Config.MixTexturesFlats) { textureLower.TextureName = General.Settings.DefaultFloorTexture; textureUpper.TextureName = General.Settings.DefaultCeilingTexture; } else { textureLower.TextureName = General.Settings.DefaultTexture; textureUpper.TextureName = General.Settings.DefaultTexture; cbUpperTexStyle.Items[1] = "Use default texture"; cbLowerTexStyle.Items[1] = "Use default texture"; } cbUpperTexStyle.SelectedIndex = 0; cbLowerTexStyle.SelectedIndex = 0; UpdateTextureSelectors(); //update interface //create random values UpdateAngles(); UpdateFloorHeights(); UpdateCeilingHeights(); }
// 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); }
public JitterVerticesForm(string editingModeName) { this.editingModeName = editingModeName; this.HelpRequested += JitterVerticesForm_HelpRequested; InitializeComponent(); //get selection selection = new List <Vertex>(); if (editingModeName == "BaseVisualMode") { VisualMode vm = (VisualMode)General.Editing.Mode; List <VisualGeometry> visualSelection = vm.GetSelectedSurfaces(); visualSectors = new List <VisualSector>(); int linesCount = 0; foreach (VisualGeometry vg in visualSelection) { if (vg.Sidedef != null && vm.VisualSectorExists(vg.Sidedef.Sector)) { if (!selection.Contains(vg.Sidedef.Line.Start)) { selection.Add(vg.Sidedef.Line.Start); } if (!selection.Contains(vg.Sidedef.Line.End)) { selection.Add(vg.Sidedef.Line.End); } linesCount++; visualSectors.Add(vm.GetVisualSector(vg.Sidedef.Sector)); if (vg.Sidedef.Other != null && vg.Sidedef.Other.Sector != null && vm.VisualSectorExists(vg.Sidedef.Other.Sector)) { visualSectors.Add(vm.GetVisualSector(vg.Sidedef.Other.Sector)); } } } visualVerts = new List <VisualVertexPair>(); foreach (Vertex vert in selection) { if (vm.VisualVertices.ContainsKey(vert)) { visualVerts.Add(vm.VisualVertices[vert]); } } //update window header this.Text = "Randomize " + linesCount + (linesCount > 1 ? " linedefs" : " linedef"); } else if (editingModeName == "LinedefsMode") { ICollection <Linedef> list = General.Map.Map.GetSelectedLinedefs(true); int linesCount = 0; foreach (Linedef l in list) { if (!selection.Contains(l.Start)) { selection.Add(l.Start); } if (!selection.Contains(l.End)) { selection.Add(l.End); } linesCount++; } //update window header this.Text = "Randomize " + linesCount + (linesCount > 1 ? " linedefs" : " linedef"); } else { ICollection <Vertex> list = General.Map.Map.GetSelectedVertices(true); foreach (Vertex v in list) { selection.Add(v); } //update window header this.Text = "Randomize " + selection.Count + (selection.Count > 1 ? " vertices" : " vertex"); } if (selection.Count == 0) { General.Interface.DisplayStatus(StatusType.Warning, "Unable to get vertices from selection!"); return; } //create undo General.Map.UndoRedo.ClearAllRedos(); General.Map.UndoRedo.CreateUndo("Randomize " + selection.Count + (selection.Count > 1 ? " vertices" : " vertex")); Dictionary <Vertex, VertexData> data = new Dictionary <Vertex, VertexData>(); foreach (Vertex v in selection) { VertexData vd = new VertexData { Position = v.Position }; data.Add(v, vd); } foreach (Vertex v in selection) { if (v.Linedefs == null) { continue; } //get nearest linedef Linedef closestLine = null; float distance = float.MaxValue; // Go for all linedefs in selection foreach (Linedef l in General.Map.Map.Linedefs) { if (v.Linedefs.Contains(l)) { continue; } // Calculate distance and check if closer than previous find float d = l.SafeDistanceToSq(v.Position, true); if (d < distance) { // This one is closer closestLine = l; distance = d; } } if (closestLine == null) { continue; } float closestLineDistance = Vector2D.Distance(v.Position, closestLine.NearestOnLine(v.Position)); //check SafeDistance of closest line if (data.ContainsKey(closestLine.Start) && data[closestLine.Start].SafeDistance > closestLineDistance) { VertexData vd = data[closestLine.Start]; vd.SafeDistance = (int)Math.Floor(closestLineDistance); data[closestLine.Start] = vd; } if (data.ContainsKey(closestLine.End) && data[closestLine.End].SafeDistance > closestLineDistance) { VertexData vd = data[closestLine.End]; vd.SafeDistance = (int)Math.Floor(closestLineDistance); data[closestLine.End] = vd; } //save SafeDistance int dist = (int)Math.Floor(closestLineDistance); if (data[v].SafeDistance == 0 || data[v].SafeDistance > dist) { VertexData vd = data[v]; vd.SafeDistance = dist; data[v] = vd; } } //store properties vertexData = new VertexData[data.Values.Count]; data.Values.CopyTo(vertexData, 0); for (int i = 0; i < vertexData.Length; i++) { if (vertexData[i].SafeDistance > 0) { vertexData[i].SafeDistance /= 2; } if (MaxSafeDistance < vertexData[i].SafeDistance) { MaxSafeDistance = vertexData[i].SafeDistance; } } positionJitterAmmount.Maximum = MaxSafeDistance; UpdateAngles(); }
// 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) ))); } }