2013-03-18 13:52:27 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
using CodeImp.DoomBuilder.Map;
|
|
|
|
|
using CodeImp.DoomBuilder.VisualModes;
|
|
|
|
|
using CodeImp.DoomBuilder.Windows;
|
|
|
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
|
|
|
|
|
|
|
|
namespace CodeImp.DoomBuilder.BuilderEffects
|
|
|
|
|
{
|
2014-10-22 13:07:17 +00:00
|
|
|
|
public partial class JitterVerticesForm : DelayedForm
|
2013-03-18 13:52:27 +00:00
|
|
|
|
{
|
2014-05-03 14:44:59 +00:00
|
|
|
|
private readonly string editingModeName;
|
|
|
|
|
private readonly List<Vertex> selection;
|
|
|
|
|
private readonly List<VisualSector> visualSectors;
|
2014-10-29 13:11:35 +00:00
|
|
|
|
private readonly List<VisualVertexPair> visualVerts;
|
2014-05-03 14:44:59 +00:00
|
|
|
|
private readonly VertexData[] vertexData;
|
|
|
|
|
private readonly int MaxSafeDistance;
|
2013-03-18 13:52:27 +00:00
|
|
|
|
|
|
|
|
|
private struct VertexData
|
|
|
|
|
{
|
|
|
|
|
public Vector2D Position;
|
|
|
|
|
public int SafeDistance;
|
|
|
|
|
public float JitterAngle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public JitterVerticesForm(string editingModeName) {
|
|
|
|
|
this.editingModeName = editingModeName;
|
2014-02-21 14:42:12 +00:00
|
|
|
|
this.HelpRequested += JitterVerticesForm_HelpRequested;
|
2013-03-18 13:52:27 +00:00
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-29 13:11:35 +00:00
|
|
|
|
visualVerts = new List<VisualVertexPair>();
|
|
|
|
|
foreach(Vertex vert in selection)
|
|
|
|
|
{
|
|
|
|
|
if(vm.VisualVertices.ContainsKey(vert)) visualVerts.Add(vm.VisualVertices[vert]);
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-18 13:52:27 +00:00
|
|
|
|
//update window header
|
2014-05-03 14:44:59 +00:00
|
|
|
|
this.Text = "Randomize " + linesCount + (linesCount > 1 ? " linedefs" : " linedef");
|
2014-10-29 13:11:35 +00:00
|
|
|
|
|
2013-03-18 13:52:27 +00:00
|
|
|
|
} 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
|
2014-05-03 14:44:59 +00:00
|
|
|
|
this.Text = "Randomize " + linesCount + (linesCount > 1 ? " linedefs" : " linedef");
|
2013-03-18 13:52:27 +00:00
|
|
|
|
} else {
|
|
|
|
|
ICollection<Vertex> list = General.Map.Map.GetSelectedVertices(true);
|
|
|
|
|
|
|
|
|
|
foreach(Vertex v in list)
|
|
|
|
|
selection.Add(v);
|
|
|
|
|
|
|
|
|
|
//update window header
|
2014-05-03 14:44:59 +00:00
|
|
|
|
this.Text = "Randomize " + selection.Count + (selection.Count > 1 ? " vertices" : " vertex");
|
2013-03-18 13:52:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(selection.Count == 0) {
|
|
|
|
|
General.Interface.DisplayStatus(StatusType.Warning, "Unable to get vertices from selection!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-29 13:11:35 +00:00
|
|
|
|
//create undo
|
|
|
|
|
General.Map.UndoRedo.ClearAllRedos();
|
|
|
|
|
General.Map.UndoRedo.CreateUndo("Randomize " + selection.Count + (selection.Count > 1 ? " vertices" : " vertex"));
|
|
|
|
|
|
2013-03-18 13:52:27 +00:00
|
|
|
|
Dictionary<Vertex, VertexData> data = new Dictionary<Vertex, VertexData>();
|
|
|
|
|
|
|
|
|
|
foreach(Vertex v in selection) {
|
2014-05-03 14:44:59 +00:00
|
|
|
|
VertexData vd = new VertexData {Position = v.Position};
|
2013-03-18 13:52:27 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-03 14:44:59 +00:00
|
|
|
|
positionJitterAmmount.Maximum = MaxSafeDistance;
|
2013-03-18 13:52:27 +00:00
|
|
|
|
|
2014-05-03 14:44:59 +00:00
|
|
|
|
updateAngles();
|
2013-03-18 13:52:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//utility
|
|
|
|
|
private void applyTranslationJitter(int ammount) {
|
|
|
|
|
int curAmmount;
|
|
|
|
|
|
2014-05-03 14:44:59 +00:00
|
|
|
|
for(int i = 0; i < selection.Count; i++) {
|
|
|
|
|
curAmmount = ammount > vertexData[i].SafeDistance ? vertexData[i].SafeDistance : ammount;
|
|
|
|
|
selection[i].Move(new Vector2D(vertexData[i].Position.x + (int)(Math.Sin(vertexData[i].JitterAngle) * curAmmount), vertexData[i].Position.y + (int)(Math.Cos(vertexData[i].JitterAngle) * curAmmount)));
|
2013-03-18 13:52:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//update view
|
|
|
|
|
if(editingModeName == "BaseVisualMode") {
|
|
|
|
|
General.Map.Map.Update();
|
|
|
|
|
General.Map.IsChanged = true;
|
|
|
|
|
|
2014-10-29 13:11:35 +00:00
|
|
|
|
foreach(VisualSector vs in visualSectors) vs.UpdateSectorGeometry(true);
|
|
|
|
|
foreach(VisualSector vs in visualSectors) vs.UpdateSectorData();
|
|
|
|
|
foreach(VisualVertexPair pair in visualVerts)
|
|
|
|
|
{
|
|
|
|
|
pair.Changed = true;
|
|
|
|
|
pair.Update();
|
|
|
|
|
}
|
2013-03-18 13:52:27 +00:00
|
|
|
|
} else {
|
|
|
|
|
General.Interface.RedrawDisplay();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void updateAngles() {
|
|
|
|
|
for(int i = 0; i < vertexData.Length; i++) {
|
|
|
|
|
VertexData vd = vertexData[i];
|
2014-05-03 14:44:59 +00:00
|
|
|
|
vd.JitterAngle = (float)(General.Random(0, 359) * Math.PI / 180f);
|
2013-03-18 13:52:27 +00:00
|
|
|
|
vertexData[i] = vd;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//EVENTS
|
|
|
|
|
private void bApply_Click(object sender, EventArgs e) {
|
|
|
|
|
// Update cached values
|
|
|
|
|
General.Map.Map.Update();
|
|
|
|
|
General.Map.IsChanged = true;
|
|
|
|
|
|
2014-10-20 12:16:51 +00:00
|
|
|
|
// Clear selection
|
|
|
|
|
General.Actions.InvokeAction("builder_clearselection");
|
2013-03-18 13:52:27 +00:00
|
|
|
|
|
|
|
|
|
this.DialogResult = DialogResult.OK;
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void bCancel_Click(object sender, EventArgs e) {
|
|
|
|
|
this.DialogResult = DialogResult.Cancel;
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void JitterVerticesForm_FormClosing(object sender, FormClosingEventArgs e) {
|
|
|
|
|
if(this.DialogResult == DialogResult.Cancel)
|
|
|
|
|
General.Map.UndoRedo.WithdrawUndo(); //undo changes
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void positionJitterAmmount_OnValueChanging(object sender, EventArgs e) {
|
|
|
|
|
applyTranslationJitter(positionJitterAmmount.Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void bUpdateTranslation_Click(object sender, EventArgs e) {
|
|
|
|
|
updateAngles();
|
|
|
|
|
applyTranslationJitter(positionJitterAmmount.Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void JitterVerticesForm_HelpRequested(object sender, HelpEventArgs hlpevent) {
|
2013-08-19 12:12:31 +00:00
|
|
|
|
General.ShowHelp("gzdb/features/all_modes/jitter.html");
|
2013-03-18 13:52:27 +00:00
|
|
|
|
hlpevent.Handled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|