public LuaVector2D GetCenterPoint() { if (linedef.IsDisposed) { throw new ScriptRuntimeException("Linedef has been disposed, can't GetCenterPoint."); } return(new LuaVector2D(linedef.GetCenterPoint())); }
//mxd public override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); closestline = MapSet.NearestLinedef(selectedlines, mousedownmappos); // Special cases... int distance; if(panel.FixedCurve) { if(panel.Angle > 0) { // Calculate diameter for current angle... double ma = Angle2D.DegToRad(panel.Angle); double d = (closestline.Length / Math.Tan(ma / 2f)) / 2; double D = d / Math.Cos(ma / 2f); distance = (int)Math.Round(D - d) * Math.Sign(panel.Distance); } else { distance = 0; // Special cases... } } else { distance = panel.Distance; } // Store offset between intial mouse position and curve top Vector2D perpendicular = closestline.Line.GetPerpendicular().GetNormal(); if(distance != 0) perpendicular *= distance; // Special cases... Vector2D curvetop = closestline.GetCenterPoint() - perpendicular; mousedownoffset = mousedownmappos - curvetop; }
/// <summary> /// Sets the association to a map element. Only works with an instance of Thing, Sector, or Linedef. /// Also gets the forward and reverse associations /// </summary> /// <param name="element">An instance of Thing, Sector, or Linedef</param> public void Set(SelectableElement element) { this.element = element; things = new List <Thing>(); sectors = new List <Sector>(); linedefs = new List <Linedef>(); eventlines = new Dictionary <string, List <Line3D> >(); if (element is Sector) { Sector s = element as Sector; center = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); type = UniversalType.SectorTag; tags = new HashSet <int>(s.Tags); } else if (element is Linedef) { Linedef ld = element as Linedef; center = ld.GetCenterPoint(); type = UniversalType.LinedefTag; tags = new HashSet <int>(ld.Tags); } else if (element is Thing) { Thing t = element as Thing; center = t.Position; ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); if (ti != null) { directlinktype = ti.ThingLink; } else { directlinktype = 0; } type = UniversalType.ThingTag; tags = new HashSet <int>(new int[] { t.Tag }); } // Remove the tag 0, because nothing sensible will come from it tags.Remove(0); // Get forward and reverse associations GetAssociations(); // Cache width of label text and generate the labels textwidths = new Dictionary <string, Vector2D>(eventlines.Count); textlabels = new Dictionary <string, List <TextLabel> >(eventlines.Count); foreach (KeyValuePair <string, List <Line3D> > kvp in eventlines) { SizeF size = General.Interface.MeasureString(kvp.Key, font); textwidths[kvp.Key] = new Vector2D(size.Width, size.Height); // Create one label for each line. We might not need them all, but better // to have them all at the beginning than to generate them later textlabels[kvp.Key] = new List <TextLabel>(kvp.Value.Count); for (int i = 0; i < kvp.Value.Count; i++) { // We don't need to set the position here, since it'll be done on the fly later TextLabel l = new TextLabel(); l.AlignX = TextAlignmentX.Center; l.AlignY = TextAlignmentY.Middle; l.TransformCoords = true; l.Text = kvp.Key; textlabels[kvp.Key].Add(l); } textwidths[kvp.Key] = new Vector2D(textlabels[kvp.Key][0].TextSize.Width, textlabels[kvp.Key][0].TextSize.Height); } SetEventLineColors(); }
//mxd public override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); // Anything to do? if ((!selectpressed && !editpressed) || closestline == null) { hintlabel.Text = string.Empty; return; } // Do something... Vector2D perpendicular = closestline.Line.GetPerpendicular().GetNormal(); if (panel.Distance != 0) { perpendicular *= panel.Distance; // Special cases... } Vector2D center = closestline.GetCenterPoint(); Line2D radius = new Line2D(center, center - perpendicular); float u = radius.GetNearestOnLine(mousemappos - mousedownoffset); int dist = (panel.Distance == 0 ? 1 : panel.Distance); // Special cases... int offset = (int)Math.Round(dist * u - dist); bool updaterequired = false; // Clamp values? bool clampvalue = !General.Interface.ShiftState; // Change verts amount if (selectpressed && editpressed) { if (prevoffset != 0) { // Set new verts count without triggering the update... panel.SetValues(panel.Vertices + Math.Sign(prevoffset - offset), panel.Distance, panel.Angle, panel.FixedCurve); // Update hint text hintlabel.Text = "Vertices: " + panel.Vertices; updaterequired = true; } } // Change distance else if (selectpressed && !panel.FixedCurve) { if (float.IsNaN(u)) { // Set new distance without triggering the update... panel.SetValues(panel.Vertices, 0, panel.Angle, panel.FixedCurve); // Special cases... } else { int newoffset; if (clampvalue) { newoffset = (panel.Distance + offset) / panel.DistanceIncrement * panel.DistanceIncrement; // Clamp to 8 mu increments } else { newoffset = panel.Distance + offset; } // Set new distance without triggering the update... panel.SetValues(panel.Vertices, newoffset, panel.Angle, panel.FixedCurve); } // Update hint text hintlabel.Text = "Distance: " + panel.Distance; updaterequired = true; } // Change angle else if (editpressed && prevoffset != 0) { int newangle = 0; if (panel.FixedCurve) { // Flip required? if (panel.Angle == 0 && (Math.Sign(offset - prevoffset) != Math.Sign(panel.Distance))) { // Set new distance without triggering the update... panel.SetValues(panel.Vertices, -panel.Distance, panel.Angle, panel.FixedCurve); // Recalculate affected values... perpendicular *= -1; radius.v2 = center - perpendicular; u = radius.GetNearestOnLine(mousemappos - mousedownoffset); } //TODO: there surely is a way to get new angle without iteration... float targetoffset = radius.GetLength() * u; float prevdiff = float.MaxValue; int increment = (clampvalue ? panel.AngleIncrement : 1); for (int i = 1; i < panel.MaximumAngle; i += increment) { // Calculate diameter for current angle... float ma = Angle2D.DegToRad(i); float d = (closestline.Length / (float)Math.Tan(ma / 2f)) / 2; float D = d / (float)Math.Cos(ma / 2f); float h = D - d; float curdiff = Math.Abs(h - targetoffset); // This one matches better... if (curdiff < prevdiff) { newangle = i; } prevdiff = curdiff; } // Clamp to 5 deg increments if (clampvalue) { newangle = (newangle / panel.AngleIncrement) * panel.AngleIncrement; } } else { int diff = (int)Math.Round((offset - prevoffset) * renderer.Scale); if (panel.Angle + diff > 0) { if (clampvalue) { newangle = (panel.Angle / panel.AngleIncrement + Math.Sign(diff)) * panel.AngleIncrement; // Clamp to 5 deg increments } else { newangle = panel.Angle + diff; } } } // Set new angle without triggering the update... panel.SetValues(panel.Vertices, panel.Distance, newangle, panel.FixedCurve); // Update hint text hintlabel.Text = "Angle: " + panel.Angle; updaterequired = true; } // Update UI if (updaterequired) { // Update label position float labeldistance; if (panel.Angle == 0) { labeldistance = 0; // Special cases! } else if (panel.FixedCurve) { float ma = Angle2D.DegToRad(panel.Angle); float d = (closestline.Length / (float)Math.Tan(ma / 2f)) / 2; float D = d / (float)Math.Cos(ma / 2f); labeldistance = D - d; } else { labeldistance = Math.Abs(panel.Distance); } labeldistance += 16 / renderer.Scale; Vector2D labelpos = radius.GetCoordinatesAt(labeldistance / radius.GetLength()); hintlabel.Move(labelpos, labelpos); // Trigger update OnValuesChanged(null, EventArgs.Empty); } // Store current offset prevoffset = offset; }
// This generates the vertices to split the line with, from start to end private List <Vector2D> GenerateCurve(Linedef line) { // Fetch settings from the panel bool fixedcurve = panel.FixedCurve; int vertices = Math.Min(panel.Vertices, (int)Math.Ceiling(line.Length / 4)); int distance = panel.Distance; int angle = (!fixedcurve && distance == 0 ? Math.Max(5, panel.Angle) : panel.Angle); float theta = Angle2D.DegToRad(angle); if (distance < 0) { theta = -theta; //mxd } // Make list List <Vector2D> points = new List <Vector2D>(vertices); float segDelta = 1.0f / (vertices + 1); //mxd Vector2D linecenter = line.GetCenterPoint(); //mxd //mxd. Special cases... if (angle == 0) { for (int v = 1; v <= vertices; v++) { float x = (line.Length * segDelta) * (vertices - v + 1) - line.Length * 0.5f; // Line segment coord // Rotate and transform to fit original line Vector2D vertex = new Vector2D(x, 0).GetRotated(line.Angle + Angle2D.PIHALF) + linecenter; points.Add(vertex); } } else { //Added by Anders Åstrand 2008-05-18 //The formulas used are taken from http://mathworld.wolfram.com/CircularSegment.html //c and theta are known (length of line and angle parameter). d, R and h are //calculated from those two //If the curve is not supposed to be a circular segment it's simply deformed to fit //the value set for distance. //The vertices are generated to be evenly distributed (by angle) along the curve //and lastly they are rotated and moved to fit with the original line //calculate some identities of a circle segment (refer to the graph in the url above) float c = line.Length; float d = (c / (float)Math.Tan(theta / 2)) / 2; float R = d / (float)Math.Cos(theta / 2); float h = R - d; float yDeform = (fixedcurve ? 1 : distance / h); float xDelta = Math.Min(1, yDeform); //mxd for (int v = 1; v <= vertices; v++) { //calculate the angle for this vertex //the curve starts at PI/2 - theta/2 and is segmented into vertices+1 segments //this assumes the line is horisontal and on y = 0, the point is rotated and moved later float a = (Angle2D.PI - theta) / 2 + v * (theta / (vertices + 1)); //calculate the coordinates of the point, and distort the y coordinate //using the deform factor calculated above float xr = (float)Math.Cos(a) * R; //mxd. Circle segment coord float xl = (line.Length * segDelta) * (vertices - v + 1) - line.Length * 0.5f; // mxd. Line segment coord float x = InterpolationTools.Linear(xl, xr, xDelta); //mxd float y = ((float)Math.Sin(a) * R - d) * yDeform; //rotate and transform to fit original line Vector2D vertex = new Vector2D(x, y).GetRotated(line.Angle + Angle2D.PIHALF) + linecenter; points.Add(vertex); } } // Done return(points); }
// This generates the vertices to split the line with, from start to end private List <Vector2D> GenerateCurve(Linedef line) { // Fetch settings from window int vertices = BuilderPlug.Me.CurveLinedefsForm.Vertices; float distance = BuilderPlug.Me.CurveLinedefsForm.Distance; float angle = BuilderPlug.Me.CurveLinedefsForm.Angle; bool fixedcurve = BuilderPlug.Me.CurveLinedefsForm.FixedCurve; bool backwards = BuilderPlug.Me.CurveLinedefsForm.Backwards; // Make list List <Vector2D> points = new List <Vector2D>(vertices); //Added by Anders Åstrand 2008-05-18 //The formulas used are taken from http://mathworld.wolfram.com/CircularSegment.html //c and theta are known (length of line and angle parameter). d, R and h are //calculated from those two //If the curve is not supposed to be a circular segment it's simply deformed to fit //the value set for distance. //The vertices are generated to be evenly distributed (by angle) along the curve //and lastly they are rotated and moved to fit with the original line //calculate some identities of a circle segment (refer to the graph in the url above) double c = line.Length; double theta = angle; double d = (c / Math.Tan(theta / 2)) / 2; double R = d / Math.Cos(theta / 2); double h = R - d; double yDeform = fixedcurve ? 1 : distance / h; if (backwards) { yDeform = -yDeform; } double a, x, y; Vector2D vertex; for (int v = 1; v <= vertices; v++) { //calculate the angle for this vertex //the curve starts at PI/2 - theta/2 and is segmented into vertices+1 segments //this assumes the line is horisontal and on y = 0, the point is rotated and moved later a = (Math.PI - theta) / 2 + v * (theta / (vertices + 1)); //calculate the coordinates of the point, and distort the y coordinate //using the deform factor calculated above x = Math.Cos(a) * R; y = (Math.Sin(a) * R - d) * yDeform; //rotate and transform to fit original line vertex = new Vector2D((float)x, (float)y).GetRotated(line.Angle + Angle2D.PIHALF); vertex = vertex.GetTransformed(line.GetCenterPoint().x, line.GetCenterPoint().y, 1, 1); points.Add(vertex); } // Done return(points); }