2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
#region ================== Copyright (c) 2007 Pascal vd Heiden
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
|
|
|
|
* This program is released under GNU General Public License
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Namespaces
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
2016-03-04 13:41:55 +00:00
|
|
|
using System.Drawing;
|
2009-04-19 18:07:22 +00:00
|
|
|
using System.Windows.Forms;
|
2016-03-04 13:41:55 +00:00
|
|
|
using CodeImp.DoomBuilder.Actions;
|
|
|
|
using CodeImp.DoomBuilder.Editing;
|
|
|
|
using CodeImp.DoomBuilder.Geometry;
|
2009-04-19 18:07:22 +00:00
|
|
|
using CodeImp.DoomBuilder.Map;
|
|
|
|
using CodeImp.DoomBuilder.Rendering;
|
2016-03-04 13:41:55 +00:00
|
|
|
using CodeImp.DoomBuilder.Windows;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
namespace CodeImp.DoomBuilder.BuilderModes
|
|
|
|
{
|
2015-07-09 22:32:12 +00:00
|
|
|
[EditMode(DisplayName = "Draw Lines Mode",
|
2009-04-19 18:07:22 +00:00
|
|
|
SwitchAction = "drawlinesmode",
|
2014-02-28 14:32:20 +00:00
|
|
|
ButtonImage = "DrawGeometryMode.png", //mxd
|
2014-02-26 14:11:06 +00:00
|
|
|
ButtonOrder = int.MinValue + 1, //mxd
|
|
|
|
ButtonGroup = "000_drawing", //mxd
|
2011-12-03 14:49:53 +00:00
|
|
|
AllowCopyPaste = false,
|
2009-04-19 18:07:22 +00:00
|
|
|
Volatile = true,
|
|
|
|
UseByDefault = true,
|
|
|
|
Optional = false)]
|
|
|
|
|
|
|
|
public class DrawGeometryMode : BaseClassicMode
|
|
|
|
{
|
|
|
|
#region ================== Constants
|
|
|
|
|
2012-06-04 23:42:13 +00:00
|
|
|
protected const float LINE_THICKNESS = 0.8f;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Variables
|
|
|
|
|
|
|
|
// Drawing points
|
2013-09-11 09:47:53 +00:00
|
|
|
protected List<DrawnVertex> points;
|
|
|
|
protected List<LineLengthLabel> labels;
|
2016-04-21 21:00:58 +00:00
|
|
|
private LineLengthLabel[] guidelabels; //mxd
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Options
|
2012-06-04 23:42:13 +00:00
|
|
|
protected bool snaptogrid; // SHIFT to toggle
|
2014-02-28 14:32:20 +00:00
|
|
|
protected bool snaptonearest; // CTRL to enable
|
2015-07-09 22:32:12 +00:00
|
|
|
protected bool snaptocardinaldirection; //mxd. ALT-SHIFT to enable
|
2016-04-21 21:00:58 +00:00
|
|
|
protected bool usefourcardinaldirections;
|
2016-02-17 22:23:18 +00:00
|
|
|
protected bool continuousdrawing; //mxd. Restart after finishing drawing?
|
2016-03-14 10:25:27 +00:00
|
|
|
protected bool autoclosedrawing; //mxd. Finish drawing when new points and existing geometry form a closed shape
|
|
|
|
protected bool drawingautoclosed; //mxd
|
2016-09-26 12:53:50 +00:00
|
|
|
protected bool showguidelines; //mxd
|
2016-04-21 21:00:58 +00:00
|
|
|
|
|
|
|
//mxd. Map area bounds
|
|
|
|
private Line2D top, bottom, left, right;
|
Fixed, Draw Lines/Rectangle/Circle/Curve modes: line length labels displayed incorrect length.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: line length labels are now displayed the same way as in Draw modes.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: "lock movement to cardinal directions" mode (Alt-Shift-Drag) now locks movement in 4 directions instead of 8 and doesn't snap map elements to nearest grid intersections when they are not aligned to it.
Added, Visual mode, GZDoom, DECORATE: FORCEXYBILLBOARD flag is now supported.
Added, Visual mode, GLOOME, DECORATE: FLOORSPRITE, CEILSPRITE, WALLSPRITE, ROLLSPRITE and STICKTOPLANE flags are now supported (implementation is somewhat broken ATM and probably doesn't work the same way as in GLOOME, because Windows build with most these features is nowhere to be found...).
Fixed, Visual mode: in some cases Thing brightness was calculated incorrectly.
Updated ZDoom_DECORATE.cfg.
2015-08-25 22:05:14 +00:00
|
|
|
|
|
|
|
//mxd. Labels display style
|
|
|
|
protected bool labelshowangle = true;
|
|
|
|
protected bool labeluseoffset = true;
|
2016-02-17 22:23:18 +00:00
|
|
|
|
|
|
|
//mxd. Interface
|
|
|
|
private DrawLineOptionsPanel panel;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Properties
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Constructor / Disposer
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
public DrawGeometryMode()
|
|
|
|
{
|
|
|
|
// Initialize
|
|
|
|
points = new List<DrawnVertex>();
|
|
|
|
labels = new List<LineLengthLabel>();
|
|
|
|
|
|
|
|
// No selection in this mode
|
|
|
|
General.Map.Map.ClearAllSelected();
|
|
|
|
General.Map.Map.ClearAllMarks(false);
|
2016-02-17 22:23:18 +00:00
|
|
|
|
|
|
|
//mxd
|
|
|
|
SetupInterface();
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// We have no destructor
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disposer
|
|
|
|
public override void Dispose()
|
|
|
|
{
|
|
|
|
// Not already disposed?
|
|
|
|
if(!isdisposed)
|
|
|
|
{
|
|
|
|
// Clean up
|
2016-04-21 21:00:58 +00:00
|
|
|
if(labels != null) foreach(LineLengthLabel l in labels) l.Dispose();
|
|
|
|
if(guidelabels != null) foreach(LineLengthLabel l in guidelabels) l.Dispose();
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Done
|
|
|
|
base.Dispose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Methods
|
|
|
|
|
2014-02-28 14:32:20 +00:00
|
|
|
// This checks if the view offset/zoom changed and updates the check (never used. mxd)
|
2014-01-16 09:32:05 +00:00
|
|
|
/*protected bool CheckViewChanged()
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
|
|
|
// View changed?
|
2013-09-05 13:03:17 +00:00
|
|
|
bool viewchanged = (renderer.OffsetX != lastoffsetx || renderer.OffsetY != lastoffsety || renderer.Scale != lastscale);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Keep view information
|
|
|
|
lastoffsetx = renderer.OffsetX;
|
|
|
|
lastoffsety = renderer.OffsetY;
|
|
|
|
lastscale = renderer.Scale;
|
|
|
|
|
|
|
|
// Return result
|
|
|
|
return viewchanged;
|
2014-01-16 09:32:05 +00:00
|
|
|
}*/
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// This updates the dragging
|
2012-06-04 23:42:13 +00:00
|
|
|
protected virtual void Update()
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2013-09-11 09:47:53 +00:00
|
|
|
PixelColor stitchcolor = General.Colors.Highlight;
|
2009-04-19 18:07:22 +00:00
|
|
|
PixelColor losecolor = General.Colors.Selection;
|
|
|
|
|
2015-07-09 22:32:12 +00:00
|
|
|
snaptocardinaldirection = General.Interface.ShiftState && General.Interface.AltState; //mxd
|
|
|
|
snaptogrid = (snaptocardinaldirection || General.Interface.ShiftState ^ General.Interface.SnapToGrid);
|
2009-04-19 18:07:22 +00:00
|
|
|
snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
|
|
|
|
|
|
|
|
DrawnVertex curp = GetCurrentPosition();
|
2013-09-05 13:03:17 +00:00
|
|
|
float vsize = (renderer.VertexSize + 1.0f) / renderer.Scale;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
2015-08-24 21:49:15 +00:00
|
|
|
// Update label positions (mxd)
|
|
|
|
if(labels.Count > 0)
|
|
|
|
{
|
|
|
|
// Update labels for already drawn lines
|
Fixed, Draw Lines/Rectangle/Circle/Curve modes: line length labels displayed incorrect length.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: line length labels are now displayed the same way as in Draw modes.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: "lock movement to cardinal directions" mode (Alt-Shift-Drag) now locks movement in 4 directions instead of 8 and doesn't snap map elements to nearest grid intersections when they are not aligned to it.
Added, Visual mode, GZDoom, DECORATE: FORCEXYBILLBOARD flag is now supported.
Added, Visual mode, GLOOME, DECORATE: FLOORSPRITE, CEILSPRITE, WALLSPRITE, ROLLSPRITE and STICKTOPLANE flags are now supported (implementation is somewhat broken ATM and probably doesn't work the same way as in GLOOME, because Windows build with most these features is nowhere to be found...).
Fixed, Visual mode: in some cases Thing brightness was calculated incorrectly.
Updated ZDoom_DECORATE.cfg.
2015-08-25 22:05:14 +00:00
|
|
|
for(int i = 0; i < labels.Count - 1; i++)
|
2016-04-21 21:00:58 +00:00
|
|
|
{
|
|
|
|
labels[i].ShowAngle = showguidelines;
|
Fixed, Draw Lines/Rectangle/Circle/Curve modes: line length labels displayed incorrect length.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: line length labels are now displayed the same way as in Draw modes.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: "lock movement to cardinal directions" mode (Alt-Shift-Drag) now locks movement in 4 directions instead of 8 and doesn't snap map elements to nearest grid intersections when they are not aligned to it.
Added, Visual mode, GZDoom, DECORATE: FORCEXYBILLBOARD flag is now supported.
Added, Visual mode, GLOOME, DECORATE: FLOORSPRITE, CEILSPRITE, WALLSPRITE, ROLLSPRITE and STICKTOPLANE flags are now supported (implementation is somewhat broken ATM and probably doesn't work the same way as in GLOOME, because Windows build with most these features is nowhere to be found...).
Fixed, Visual mode: in some cases Thing brightness was calculated incorrectly.
Updated ZDoom_DECORATE.cfg.
2015-08-25 22:05:14 +00:00
|
|
|
labels[i].Move(points[i].pos, points[i + 1].pos);
|
2016-04-21 21:00:58 +00:00
|
|
|
}
|
2015-08-24 21:49:15 +00:00
|
|
|
|
|
|
|
// Update label for active line
|
2016-04-21 21:00:58 +00:00
|
|
|
labels[labels.Count - 1].ShowAngle = showguidelines;
|
Fixed, Draw Lines/Rectangle/Circle/Curve modes: line length labels displayed incorrect length.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: line length labels are now displayed the same way as in Draw modes.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: "lock movement to cardinal directions" mode (Alt-Shift-Drag) now locks movement in 4 directions instead of 8 and doesn't snap map elements to nearest grid intersections when they are not aligned to it.
Added, Visual mode, GZDoom, DECORATE: FORCEXYBILLBOARD flag is now supported.
Added, Visual mode, GLOOME, DECORATE: FLOORSPRITE, CEILSPRITE, WALLSPRITE, ROLLSPRITE and STICKTOPLANE flags are now supported (implementation is somewhat broken ATM and probably doesn't work the same way as in GLOOME, because Windows build with most these features is nowhere to be found...).
Fixed, Visual mode: in some cases Thing brightness was calculated incorrectly.
Updated ZDoom_DECORATE.cfg.
2015-08-25 22:05:14 +00:00
|
|
|
labels[labels.Count - 1].Move(points[points.Count - 1].pos, curp.pos);
|
2015-08-24 21:49:15 +00:00
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Render drawing lines
|
|
|
|
if(renderer.StartOverlay(true))
|
|
|
|
{
|
|
|
|
// Go for all points to draw lines
|
Fixed, Draw Lines/Rectangle/Circle/Curve modes: line length labels displayed incorrect length.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: line length labels are now displayed the same way as in Draw modes.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: "lock movement to cardinal directions" mode (Alt-Shift-Drag) now locks movement in 4 directions instead of 8 and doesn't snap map elements to nearest grid intersections when they are not aligned to it.
Added, Visual mode, GZDoom, DECORATE: FORCEXYBILLBOARD flag is now supported.
Added, Visual mode, GLOOME, DECORATE: FLOORSPRITE, CEILSPRITE, WALLSPRITE, ROLLSPRITE and STICKTOPLANE flags are now supported (implementation is somewhat broken ATM and probably doesn't work the same way as in GLOOME, because Windows build with most these features is nowhere to be found...).
Fixed, Visual mode: in some cases Thing brightness was calculated incorrectly.
Updated ZDoom_DECORATE.cfg.
2015-08-25 22:05:14 +00:00
|
|
|
PixelColor color;
|
2009-04-19 18:07:22 +00:00
|
|
|
if(points.Count > 0)
|
|
|
|
{
|
2016-04-21 21:00:58 +00:00
|
|
|
//mxd
|
|
|
|
bool renderguidelabels = false;
|
|
|
|
if(showguidelines)
|
|
|
|
{
|
|
|
|
Vector2D prevp = points[points.Count - 1].pos;
|
2016-09-26 12:53:50 +00:00
|
|
|
renderguidelabels = (curp.pos.x != prevp.x && curp.pos.y != prevp.y);
|
2020-06-15 19:57:59 +00:00
|
|
|
RenderGuidelines(prevp, curp.pos, General.Colors.Guideline.WithAlpha(80), -General.Map.Grid.GridRotate);
|
2016-04-21 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// Render lines
|
2014-11-12 11:22:14 +00:00
|
|
|
DrawnVertex lastp = points[0];
|
2009-04-19 18:07:22 +00:00
|
|
|
for(int i = 1; i < points.Count; i++)
|
|
|
|
{
|
|
|
|
// Determine line color
|
|
|
|
if(lastp.stitchline && points[i].stitchline) color = stitchcolor;
|
|
|
|
else color = losecolor;
|
|
|
|
|
|
|
|
// Render line
|
|
|
|
renderer.RenderLine(lastp.pos, points[i].pos, LINE_THICKNESS, color, true);
|
2012-09-02 23:37:17 +00:00
|
|
|
RenderLinedefDirectionIndicator(lastp.pos, points[i].pos, color); //mxd
|
2009-04-19 18:07:22 +00:00
|
|
|
lastp = points[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine line color
|
2014-02-28 14:32:20 +00:00
|
|
|
color = (lastp.stitchline && snaptonearest ? stitchcolor : losecolor);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Render line to cursor
|
|
|
|
renderer.RenderLine(lastp.pos, curp.pos, LINE_THICKNESS, color, true);
|
2012-09-02 23:37:17 +00:00
|
|
|
RenderLinedefDirectionIndicator(lastp.pos, curp.pos, color); //mxd
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Render vertices
|
|
|
|
for(int i = 0; i < points.Count; i++)
|
|
|
|
{
|
|
|
|
// Determine vertex color
|
2013-09-05 13:03:17 +00:00
|
|
|
color = points[i].stitch ? stitchcolor : losecolor;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Render vertex
|
2020-05-21 12:20:02 +00:00
|
|
|
renderer.RenderRectangleFilled(new RectangleF((float)(points[i].pos.x - vsize), (float)(points[i].pos.y - vsize), vsize * 2.0f, vsize * 2.0f), color, true);
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
2016-04-21 21:00:58 +00:00
|
|
|
|
|
|
|
//mxd. Render guide labels?
|
2016-04-25 14:48:39 +00:00
|
|
|
if(renderguidelabels) renderer.RenderText(guidelabels);
|
|
|
|
|
|
|
|
// Render labels
|
|
|
|
renderer.RenderText(labels.ToArray());
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Determine point color
|
2013-09-05 13:03:17 +00:00
|
|
|
color = snaptonearest ? stitchcolor : losecolor;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Render vertex at cursor
|
2020-05-21 12:20:02 +00:00
|
|
|
renderer.RenderRectangleFilled(new RectangleF((float)(curp.pos.x - vsize), (float)(curp.pos.y - vsize), vsize * 2.0f, vsize * 2.0f), color, true);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Done
|
|
|
|
renderer.Finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Done
|
|
|
|
renderer.Present();
|
|
|
|
}
|
2012-09-02 23:37:17 +00:00
|
|
|
|
2016-09-26 12:53:50 +00:00
|
|
|
protected void RenderGuidelines(Vector2D start, Vector2D end, PixelColor c)
|
|
|
|
{
|
2020-06-14 20:37:37 +00:00
|
|
|
RenderGuidelines(start, end, c, 0.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//mxd
|
|
|
|
protected void RenderGuidelines(Vector2D start, Vector2D end, PixelColor c, double angle)
|
|
|
|
{
|
|
|
|
start = start.GetRotated(angle);
|
|
|
|
end = end.GetRotated(angle);
|
|
|
|
|
2016-09-26 12:53:50 +00:00
|
|
|
if(end.x != start.x && end.y != start.y)
|
|
|
|
{
|
|
|
|
Vector2D tr = new Vector2D(Math.Max(end.x, start.x), Math.Max(end.y, start.y));
|
|
|
|
Vector2D bl = new Vector2D(Math.Min(end.x, start.x), Math.Min(end.y, start.y));
|
|
|
|
|
|
|
|
// Create guidelines
|
|
|
|
Line3D[] lines = new Line3D[5];
|
2020-06-14 20:37:37 +00:00
|
|
|
lines[0] = new Line3D(new Vector2D(tr.x, General.Map.Config.TopBoundary).GetRotated(-angle), new Vector2D(tr.x, General.Map.Config.BottomBoundary).GetRotated(-angle), c, false);
|
|
|
|
lines[1] = new Line3D(new Vector2D(bl.x, General.Map.Config.TopBoundary).GetRotated(-angle), new Vector2D(bl.x, General.Map.Config.BottomBoundary).GetRotated(-angle), c, false);
|
|
|
|
lines[2] = new Line3D(new Vector2D(General.Map.Config.LeftBoundary, tr.y).GetRotated(-angle), new Vector2D(General.Map.Config.RightBoundary, tr.y).GetRotated(-angle), c, false);
|
|
|
|
lines[3] = new Line3D(new Vector2D(General.Map.Config.LeftBoundary, bl.y).GetRotated(-angle), new Vector2D(General.Map.Config.RightBoundary, bl.y).GetRotated(-angle), c, false);
|
2016-09-26 12:53:50 +00:00
|
|
|
|
|
|
|
// Create current line extent. Make sure v1 is to the left of v2
|
|
|
|
Line2D current = (end.x < start.x ? new Line2D(end, start) : new Line2D(start, end));
|
|
|
|
|
|
|
|
Vector2D extentstart, extentend;
|
|
|
|
if(current.v1.y < current.v2.y) // Start is lower
|
|
|
|
{
|
|
|
|
// Start point can hit left or bottom boundaries
|
|
|
|
extentstart = Line2D.GetIntersectionPoint(left, current, false);
|
|
|
|
if(extentstart.y < General.Map.Config.BottomBoundary)
|
|
|
|
extentstart = Line2D.GetIntersectionPoint(bottom, current, false);
|
|
|
|
|
|
|
|
// End point can hit right or top boundaries
|
|
|
|
extentend = Line2D.GetIntersectionPoint(right, current, false);
|
|
|
|
if(extentend.y > General.Map.Config.TopBoundary)
|
|
|
|
extentend = Line2D.GetIntersectionPoint(top, current, false);
|
|
|
|
}
|
|
|
|
else // Start is higher
|
|
|
|
{
|
|
|
|
// Start point can hit left or top boundaries
|
|
|
|
extentstart = Line2D.GetIntersectionPoint(left, current, false);
|
|
|
|
if(extentstart.y > General.Map.Config.TopBoundary)
|
|
|
|
extentstart = Line2D.GetIntersectionPoint(top, current, false);
|
|
|
|
|
|
|
|
// End point can hit right or bottom boundaries
|
|
|
|
extentend = Line2D.GetIntersectionPoint(right, current, false);
|
|
|
|
if(extentend.y < General.Map.Config.BottomBoundary)
|
|
|
|
extentend = Line2D.GetIntersectionPoint(bottom, current, false);
|
|
|
|
}
|
|
|
|
|
2020-06-15 19:57:59 +00:00
|
|
|
lines[4] = new Line3D(extentstart.GetRotated(-angle), extentend.GetRotated(-angle), c, false);
|
2016-09-26 12:53:50 +00:00
|
|
|
|
|
|
|
// Render them
|
|
|
|
renderer.RenderArrows(lines);
|
|
|
|
|
|
|
|
// Update horiz/vert length labels
|
|
|
|
if(guidelabels != null)
|
|
|
|
{
|
2020-06-15 19:57:59 +00:00
|
|
|
guidelabels[0].Move(tr.GetRotated(-angle), new Vector2D(tr.x, bl.y).GetRotated(-angle));
|
|
|
|
guidelabels[1].Move(new Vector2D(bl.x, tr.y).GetRotated(-angle), tr.GetRotated(-angle));
|
|
|
|
guidelabels[2].Move(new Vector2D(tr.x, bl.y).GetRotated(-angle), bl.GetRotated(-angle));
|
|
|
|
guidelabels[3].Move(bl.GetRotated(-angle), new Vector2D(bl.x, tr.y).GetRotated(-angle));
|
2016-09-26 12:53:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Render horizontal line + 2 vertical guidelines
|
|
|
|
else if(end.x != start.x)
|
|
|
|
{
|
2020-06-15 19:37:47 +00:00
|
|
|
Line3D l = new Line3D(new Vector2D(General.Map.Config.LeftBoundary, end.y).GetRotated(-angle), new Vector2D(General.Map.Config.RightBoundary, end.y).GetRotated(-angle), c, false);
|
|
|
|
Line3D gs = new Line3D(new Vector2D(start.x, General.Map.Config.TopBoundary).GetRotated(-angle), new Vector2D(start.x, General.Map.Config.BottomBoundary).GetRotated(-angle), c, false);
|
|
|
|
Line3D ge = new Line3D(new Vector2D(end.x, General.Map.Config.TopBoundary).GetRotated(-angle), new Vector2D(end.x, General.Map.Config.BottomBoundary).GetRotated(-angle), c, false);
|
2016-09-26 12:53:50 +00:00
|
|
|
renderer.RenderArrows(new List<Line3D> { l, gs, ge });
|
|
|
|
}
|
|
|
|
// Render vertical line + 2 horizontal guidelines
|
|
|
|
else if(end.y != start.y)
|
|
|
|
{
|
2020-06-15 19:37:47 +00:00
|
|
|
Line3D l = new Line3D(new Vector2D(end.x, General.Map.Config.TopBoundary).GetRotated(-angle), new Vector2D(end.x, General.Map.Config.BottomBoundary).GetRotated(-angle), c, false);
|
|
|
|
Line3D gs = new Line3D(new Vector2D(General.Map.Config.LeftBoundary, start.y).GetRotated(-angle), new Vector2D(General.Map.Config.RightBoundary, start.y).GetRotated(-angle), c, false);
|
|
|
|
Line3D ge = new Line3D(new Vector2D(General.Map.Config.LeftBoundary, end.y).GetRotated(-angle), new Vector2D(General.Map.Config.RightBoundary, end.y).GetRotated(-angle), c, false);
|
2016-09-26 12:53:50 +00:00
|
|
|
renderer.RenderArrows(new List<Line3D> {l, gs, ge});
|
|
|
|
}
|
|
|
|
// Start and end match. Render a cross
|
|
|
|
else
|
|
|
|
{
|
2020-06-15 19:37:47 +00:00
|
|
|
Line3D gs = new Line3D(new Vector2D(General.Map.Config.LeftBoundary, start.y).GetRotated(-angle), new Vector2D(General.Map.Config.RightBoundary, start.y).GetRotated(-angle), c, false);
|
|
|
|
Line3D ge = new Line3D(new Vector2D(start.x, General.Map.Config.TopBoundary).GetRotated(-angle), new Vector2D(start.x, General.Map.Config.BottomBoundary).GetRotated(-angle), c, false);
|
2016-09-26 12:53:50 +00:00
|
|
|
renderer.RenderArrows(new List<Line3D> { gs, ge });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-02 23:37:17 +00:00
|
|
|
//mxd
|
2014-11-12 11:22:14 +00:00
|
|
|
private void RenderLinedefDirectionIndicator(Vector2D start, Vector2D end, PixelColor color)
|
|
|
|
{
|
2012-09-02 23:37:17 +00:00
|
|
|
Vector2D delta = end - start;
|
|
|
|
Vector2D middlePoint = new Vector2D(start.x + delta.x / 2, start.y + delta.y / 2);
|
|
|
|
Vector2D scaledPerpendicular = delta.GetPerpendicular().GetNormal().GetScaled(18f / renderer.Scale);
|
|
|
|
renderer.RenderLine(middlePoint, new Vector2D(middlePoint.x - scaledPerpendicular.x, middlePoint.y - scaledPerpendicular.y), LINE_THICKNESS, color, true);
|
|
|
|
}
|
2022-02-04 23:44:04 +00:00
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// This returns the aligned and snapped draw position
|
2016-04-21 21:00:58 +00:00
|
|
|
public static DrawnVertex GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, bool snaptocardinal, bool usefourcardinaldirections, IRenderer2D renderer, List<DrawnVertex> points)
|
2022-02-04 23:44:04 +00:00
|
|
|
{
|
|
|
|
return GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, snaptocardinal, usefourcardinaldirections, renderer, points, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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, BlockMap<BlockEntry> blockmap)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
|
|
|
DrawnVertex p = new DrawnVertex();
|
2013-07-30 09:25:27 +00:00
|
|
|
p.stitch = true; //mxd. Setting these to false seems to be a good way to create invalid geometry...
|
|
|
|
p.stitchline = true; //mxd
|
2016-07-17 21:38:29 +00:00
|
|
|
snaptocardinal = (snaptocardinal && points.Count > 0); //mxd. Don't snap to cardinal when there are no points
|
2015-07-09 22:32:12 +00:00
|
|
|
|
|
|
|
//mxd. If snap to cardinal directions is enabled and we have points, modify mouse position
|
2016-04-21 21:00:58 +00:00
|
|
|
Vector2D vm, gridoffset;
|
2016-07-17 21:38:29 +00:00
|
|
|
if(snaptocardinal)
|
2015-07-09 22:32:12 +00:00
|
|
|
{
|
|
|
|
Vector2D offset = mousemappos - points[points.Count - 1].pos;
|
2020-05-21 12:20:02 +00:00
|
|
|
|
|
|
|
double angle;
|
2015-07-09 22:32:12 +00:00
|
|
|
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;
|
2016-04-21 21:00:58 +00:00
|
|
|
|
|
|
|
//mxd. We need to be snapped relative to initial position
|
|
|
|
Vector2D prev = points[points.Count - 1].pos;
|
|
|
|
gridoffset = prev - General.Map.Grid.SnappedToGrid(prev);
|
2015-07-09 22:32:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vm = mousemappos;
|
2016-04-21 21:00:58 +00:00
|
|
|
gridoffset = new Vector2D();
|
2015-07-09 22:32:12 +00:00
|
|
|
}
|
|
|
|
|
2009-05-20 15:03:08 +00:00
|
|
|
float vrange = BuilderPlug.Me.StitchRange / renderer.Scale;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Snap to nearest?
|
|
|
|
if(snaptonearest)
|
|
|
|
{
|
|
|
|
// Go for all drawn points
|
|
|
|
foreach(DrawnVertex v in points)
|
|
|
|
{
|
2016-04-21 21:00:58 +00:00
|
|
|
if(Vector2D.DistanceSq(vm, v.pos) < (vrange * vrange))
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
|
|
|
p.pos = v.pos;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-04 23:44:04 +00:00
|
|
|
List<Vertex> vertices = new List<Vertex>();
|
|
|
|
Vertex nv = null;
|
|
|
|
|
|
|
|
// If we got a blockmap get the veritces that are in range only
|
|
|
|
if (blockmap != null)
|
|
|
|
{
|
|
|
|
HashSet<BlockEntry> blocks = blockmap.GetSquareRange(vm.x - vrange, vm.y - vrange, vrange * 2, vrange * 2);
|
|
|
|
foreach (BlockEntry be in blocks)
|
|
|
|
vertices.AddRange(be.Vertices);
|
|
|
|
|
|
|
|
nv = MapSet.NearestVertexSquareRange(vertices, vm, vrange);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
nv = General.Map.Map.NearestVertexSquareRange(vm, vrange);
|
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// Try the nearest vertex
|
|
|
|
if(nv != null)
|
|
|
|
{
|
2016-04-21 21:00:58 +00:00
|
|
|
//mxd. Line angle must stay the same
|
2016-07-17 21:38:29 +00:00
|
|
|
if(snaptocardinal)
|
2016-04-21 21:00:58 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
2016-04-21 21:00:58 +00:00
|
|
|
// Try the nearest linedef. mxd. We'll need much bigger stitch distance when snapping to cardinal directions
|
2022-02-04 23:44:04 +00:00
|
|
|
Linedef nl = blockmap != null ? MapSet.NearestLinedefRange(blockmap, vm, BuilderPlug.Me.StitchRange / renderer.Scale) : General.Map.Map.NearestLinedefRange(vm, BuilderPlug.Me.StitchRange / renderer.Scale);
|
2009-04-19 18:07:22 +00:00
|
|
|
if(nl != null)
|
|
|
|
{
|
2016-04-21 21:00:58 +00:00
|
|
|
//mxd. Line angle must stay the same
|
|
|
|
if(snaptocardinal)
|
|
|
|
{
|
2016-07-17 21:38:29 +00:00
|
|
|
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);
|
2020-05-21 12:20:02 +00:00
|
|
|
if(!double.IsNaN(intersection.x))
|
2016-04-21 21:00:58 +00:00
|
|
|
{
|
2016-07-17 21:38:29 +00:00
|
|
|
// Intersection is on nearestline?
|
2020-05-21 12:20:02 +00:00
|
|
|
double u = Line2D.GetNearestOnLine(nearestline.v1, nearestline.v2, intersection);
|
2016-07-17 21:38:29 +00:00
|
|
|
|
|
|
|
if(u < 0f || u > 1f) { }
|
|
|
|
else
|
2016-04-21 21:00:58 +00:00
|
|
|
{
|
2020-05-21 12:20:02 +00:00
|
|
|
p.pos = new Vector2D(Math.Round(intersection.x, General.Map.FormatInterface.VertexDecimals),
|
|
|
|
Math.Round(intersection.y, General.Map.FormatInterface.VertexDecimals));
|
2016-07-17 21:38:29 +00:00
|
|
|
return p;
|
2016-04-21 21:00:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
// Snap to grid?
|
2016-04-21 21:00:58 +00:00
|
|
|
else if(snaptogrid)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
|
|
|
// Get grid intersection coordinates
|
2019-01-14 18:07:08 +00:00
|
|
|
List<Vector2D> coords = nl.GetGridIntersections(General.Map.Grid.GridRotate,
|
|
|
|
General.Map.Grid.GridOriginX, General.Map.Grid.GridOriginY);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Find nearest grid intersection
|
2010-10-03 13:10:52 +00:00
|
|
|
bool found = false;
|
2020-05-21 12:20:02 +00:00
|
|
|
double found_distance = double.MaxValue;
|
2009-04-19 18:07:22 +00:00
|
|
|
Vector2D found_coord = new Vector2D();
|
|
|
|
foreach(Vector2D v in coords)
|
|
|
|
{
|
2016-04-21 21:00:58 +00:00
|
|
|
Vector2D delta = vm - v;
|
2009-04-19 18:07:22 +00:00
|
|
|
if(delta.GetLengthSq() < found_distance)
|
|
|
|
{
|
|
|
|
found_distance = delta.GetLengthSq();
|
|
|
|
found_coord = v;
|
2010-10-03 13:10:52 +00:00
|
|
|
found = true;
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-03 13:10:52 +00:00
|
|
|
if(found)
|
|
|
|
{
|
|
|
|
// Align to the closest grid intersection
|
|
|
|
p.pos = found_coord;
|
|
|
|
return p;
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Aligned to line
|
2016-04-21 21:00:58 +00:00
|
|
|
p.pos = nl.NearestOnLine(vm);
|
2009-04-19 18:07:22 +00:00
|
|
|
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)
|
|
|
|
{
|
2016-04-21 21:00:58 +00:00
|
|
|
if(Vector2D.DistanceSq(vm, points[0].pos) < (vrange * vrange))
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
|
|
|
p.pos = points[0].pos;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-13 18:32:21 +00:00
|
|
|
// 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
|
2015-12-28 15:01:53 +00:00
|
|
|
if(points.Count > 0 &&
|
2010-08-13 18:32:21 +00:00
|
|
|
(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;
|
2020-05-22 20:30:32 +00:00
|
|
|
double u = 0.0;
|
2010-08-13 18:32:21 +00:00
|
|
|
List<Line2D> blines = new List<Line2D>();
|
|
|
|
|
2015-07-09 22:32:12 +00:00
|
|
|
// lines for left, top, right and bottom boundaries
|
2010-08-13 18:32:21 +00:00
|
|
|
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
|
2015-12-28 15:01:53 +00:00
|
|
|
for(int i = 0; i < blines.Count; i++)
|
2010-08-13 18:32:21 +00:00
|
|
|
{
|
2015-12-28 15:01:53 +00:00
|
|
|
if(!foundintersection)
|
2010-08-13 18:32:21 +00:00
|
|
|
{
|
|
|
|
// only check for intersection if the last set point is not on the
|
|
|
|
// line we are checking against
|
2020-05-22 20:30:32 +00:00
|
|
|
if(blines[i].GetSideOfLine(points[points.Count - 1].pos) != 0.0)
|
2010-08-13 18:32:21 +00:00
|
|
|
{
|
|
|
|
foundintersection = blines[i].GetIntersection(dline, out u);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if there was no intersection set the position to the last set point
|
2015-12-28 15:01:53 +00:00
|
|
|
if(!foundintersection)
|
2010-08-13 18:32:21 +00:00
|
|
|
vm = points[points.Count - 1].pos;
|
|
|
|
else
|
|
|
|
vm = dline.GetCoordinatesAt(u);
|
|
|
|
}
|
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// Snap to grid?
|
|
|
|
if(snaptogrid)
|
|
|
|
{
|
|
|
|
// Aligned to grid
|
2016-04-21 21:00:58 +00:00
|
|
|
p.pos = General.Map.Grid.SnappedToGrid(vm - gridoffset) + gridoffset;
|
2010-08-13 18:32:21 +00:00
|
|
|
|
|
|
|
// special handling
|
2015-12-28 15:01:53 +00:00
|
|
|
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;
|
2016-04-21 21:00:58 +00:00
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Normal position
|
2020-05-22 20:30:32 +00:00
|
|
|
p.pos.x = Math.Round(vm.x); //mxd
|
|
|
|
p.pos.y = Math.Round(vm.y); //mxd
|
2016-04-21 21:00:58 +00:00
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This gets the aligned and snapped draw position
|
2012-06-04 23:42:13 +00:00
|
|
|
protected DrawnVertex GetCurrentPosition()
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2016-04-21 21:00:58 +00:00
|
|
|
return GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, snaptocardinaldirection, usefourcardinaldirections, renderer, points);
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This draws a point at a specific location
|
2013-09-11 09:47:53 +00:00
|
|
|
public bool DrawPointAt(DrawnVertex p)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2010-08-13 18:32:21 +00:00
|
|
|
return DrawPointAt(p.pos, p.stitch, p.stitchline);
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This draws a point at a specific location
|
2013-09-11 09:47:53 +00:00
|
|
|
public virtual bool DrawPointAt(Vector2D pos, bool stitch, bool stitchline)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2015-12-28 15:01:53 +00:00
|
|
|
if(pos.x < General.Map.Config.LeftBoundary || pos.x > General.Map.Config.RightBoundary ||
|
2010-08-13 18:32:21 +00:00
|
|
|
pos.y > General.Map.Config.TopBoundary || pos.y < General.Map.Config.BottomBoundary)
|
|
|
|
return false;
|
|
|
|
|
2016-10-24 19:19:11 +00:00
|
|
|
//mxd. Avoid zero-length lines...
|
|
|
|
if(points.Count > 0)
|
|
|
|
{
|
|
|
|
Vector2D delta = points[points.Count - 1].pos - pos;
|
|
|
|
if((Math.Abs(delta.x) <= 0.001f) && (Math.Abs(delta.y) <= 0.001f))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
DrawnVertex newpoint = new DrawnVertex();
|
|
|
|
newpoint.pos = pos;
|
|
|
|
newpoint.stitch = stitch;
|
|
|
|
newpoint.stitchline = stitchline;
|
|
|
|
points.Add(newpoint);
|
Fixed, Draw Lines/Rectangle/Circle/Curve modes: line length labels displayed incorrect length.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: line length labels are now displayed the same way as in Draw modes.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: "lock movement to cardinal directions" mode (Alt-Shift-Drag) now locks movement in 4 directions instead of 8 and doesn't snap map elements to nearest grid intersections when they are not aligned to it.
Added, Visual mode, GZDoom, DECORATE: FORCEXYBILLBOARD flag is now supported.
Added, Visual mode, GLOOME, DECORATE: FLOORSPRITE, CEILSPRITE, WALLSPRITE, ROLLSPRITE and STICKTOPLANE flags are now supported (implementation is somewhat broken ATM and probably doesn't work the same way as in GLOOME, because Windows build with most these features is nowhere to be found...).
Fixed, Visual mode: in some cases Thing brightness was calculated incorrectly.
Updated ZDoom_DECORATE.cfg.
2015-08-25 22:05:14 +00:00
|
|
|
labels.Add(new LineLengthLabel(labelshowangle, labeluseoffset));
|
2009-04-19 18:07:22 +00:00
|
|
|
Update();
|
|
|
|
|
2016-03-14 10:25:27 +00:00
|
|
|
if(points.Count > 1)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2016-03-14 10:25:27 +00:00
|
|
|
// Check if point stitches with the first
|
|
|
|
if(points[points.Count - 1].stitch)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2016-03-14 10:25:27 +00:00
|
|
|
Vector2D p1 = points[0].pos;
|
|
|
|
Vector2D p2 = points[points.Count - 1].pos;
|
|
|
|
Vector2D delta = p1 - p2;
|
|
|
|
if((Math.Abs(delta.x) <= 0.001f) && (Math.Abs(delta.y) <= 0.001f))
|
2014-12-03 23:15:26 +00:00
|
|
|
{
|
2016-03-14 10:25:27 +00:00
|
|
|
//mxd. Seems... logical?
|
|
|
|
if(points.Count == 2)
|
|
|
|
{
|
|
|
|
OnCancel();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finish drawing
|
|
|
|
FinishDraw();
|
2013-09-11 09:47:53 +00:00
|
|
|
return true;
|
|
|
|
}
|
2016-03-14 10:25:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//mxd. Points and existing geometry form a closed shape?
|
2016-03-23 14:52:33 +00:00
|
|
|
if(autoclosedrawing)
|
2016-03-14 10:25:27 +00:00
|
|
|
{
|
|
|
|
// Determive center point
|
2020-05-21 12:20:02 +00:00
|
|
|
double minx = float.MaxValue;
|
|
|
|
double maxx = float.MinValue;
|
|
|
|
double miny = float.MaxValue;
|
|
|
|
double maxy = float.MinValue;
|
2016-03-14 10:25:27 +00:00
|
|
|
|
|
|
|
foreach(DrawnVertex v in points)
|
|
|
|
{
|
|
|
|
if(v.pos.x < minx) minx = v.pos.x;
|
|
|
|
if(v.pos.x > maxx) maxx = v.pos.x;
|
|
|
|
if(v.pos.y < miny) miny = v.pos.y;
|
|
|
|
if(v.pos.y > maxy) maxy = v.pos.y;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2D shapecenter = new Vector2D(minx + (maxx - minx) / 2, miny + (maxy - miny) / 2);
|
2013-09-11 09:47:53 +00:00
|
|
|
|
2016-03-14 10:25:27 +00:00
|
|
|
// Determine center point between start and end points
|
|
|
|
minx = Math.Min(points[0].pos.x, points[points.Count - 1].pos.x);
|
|
|
|
maxx = Math.Max(points[0].pos.x, points[points.Count - 1].pos.x);
|
|
|
|
miny = Math.Min(points[0].pos.y, points[points.Count - 1].pos.y);
|
|
|
|
maxy = Math.Max(points[0].pos.y, points[points.Count - 1].pos.y);
|
|
|
|
|
|
|
|
Vector2D startendcenter = new Vector2D(minx + (maxx - minx) / 2, miny + (maxy - miny) / 2);
|
|
|
|
|
|
|
|
// Offset the center perpendicular to the start -> end line direction...
|
|
|
|
if(shapecenter == startendcenter)
|
|
|
|
{
|
|
|
|
shapecenter -= new Line2D(points[0].pos, points[points.Count - 1].pos).GetPerpendicular().GetNormal();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do the check
|
|
|
|
if(CanFinishDrawing(points[0].pos, points[points.Count - 1].pos, shapecenter))
|
|
|
|
{
|
|
|
|
drawingautoclosed = true;
|
|
|
|
FinishDraw();
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
}
|
2010-08-13 18:32:21 +00:00
|
|
|
|
|
|
|
return true;
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
2016-03-14 10:25:27 +00:00
|
|
|
|
|
|
|
//mxd
|
|
|
|
private static bool CanFinishDrawing(Vector2D start, Vector2D end, Vector2D center)
|
|
|
|
{
|
|
|
|
Linedef startline = FindPotentialLine(start, center);
|
|
|
|
if(startline == null) return false;
|
|
|
|
|
|
|
|
Linedef endline = FindPotentialLine(end, center);
|
|
|
|
if(endline == null) return false;
|
|
|
|
|
|
|
|
// Can finish drawing if a path between startline and endline exists
|
|
|
|
return Tools.FindClosestPath(startline, startline.SideOfLine(center) < 0.0f, endline, endline.SideOfLine(center) < 0.0f, true) != null;
|
|
|
|
}
|
|
|
|
|
|
|
|
//mxd
|
|
|
|
private static Linedef FindPotentialLine(Vector2D target, Vector2D center)
|
|
|
|
{
|
|
|
|
// Target position on top of existing vertex?
|
|
|
|
Vertex v = General.Map.Map.NearestVertex(target);
|
|
|
|
if(v == null) return null;
|
|
|
|
|
|
|
|
Linedef result = null;
|
|
|
|
if(v.Position == target)
|
|
|
|
{
|
2020-05-21 12:20:02 +00:00
|
|
|
double mindistance = double.MaxValue;
|
2016-03-14 10:25:27 +00:00
|
|
|
foreach(Linedef l in v.Linedefs)
|
|
|
|
{
|
|
|
|
if(result == null)
|
|
|
|
{
|
|
|
|
result = l;
|
|
|
|
mindistance = Vector2D.DistanceSq(l.GetCenterPoint(), center);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-21 12:20:02 +00:00
|
|
|
double curdistance = Vector2D.DistanceSq(l.GetCenterPoint(), center);
|
2016-03-14 10:25:27 +00:00
|
|
|
if(curdistance < mindistance)
|
|
|
|
{
|
|
|
|
mindistance = curdistance;
|
|
|
|
result = l;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Result position will split a line?
|
|
|
|
result = General.Map.Map.NearestLinedef(target);
|
2016-04-22 13:28:23 +00:00
|
|
|
if(result.SideOfLine(target) != 0) return null;
|
2016-03-14 10:25:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
2016-02-17 22:23:18 +00:00
|
|
|
#region ================== mxd. Settings panel
|
|
|
|
|
|
|
|
protected virtual void SetupInterface()
|
|
|
|
{
|
|
|
|
//Add options docker
|
|
|
|
panel = new DrawLineOptionsPanel();
|
|
|
|
panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged;
|
2016-03-14 10:25:27 +00:00
|
|
|
panel.OnAutoCloseDrawingChanged += OnAutoCloseDrawingChanged;
|
2016-04-21 21:00:58 +00:00
|
|
|
panel.OnShowGuidelinesChanged += OnShowGuidelinesChanged;
|
2016-03-04 13:41:55 +00:00
|
|
|
|
2016-03-14 10:25:27 +00:00
|
|
|
// Needs to be set after adding the events...
|
2016-03-04 13:41:55 +00:00
|
|
|
panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawlinesmode.continuousdrawing", false);
|
2016-03-14 10:25:27 +00:00
|
|
|
panel.AutoCloseDrawing = General.Settings.ReadPluginSetting("drawlinesmode.autoclosedrawing", false);
|
2016-04-21 21:00:58 +00:00
|
|
|
panel.ShowGuidelines = General.Settings.ReadPluginSetting("drawlinesmode.showguidelines", false);
|
|
|
|
|
|
|
|
// Create guide labels
|
|
|
|
guidelabels = new LineLengthLabel[4];
|
|
|
|
for(int i = 0; i < guidelabels.Length; i++)
|
|
|
|
{
|
|
|
|
guidelabels[i] = new LineLengthLabel { ShowAngle = false, Color = General.Colors.InfoLine };
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create map boudary lines
|
|
|
|
Vector2D btl = new Vector2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary);
|
|
|
|
Vector2D btr = new Vector2D(General.Map.Config.RightBoundary, General.Map.Config.TopBoundary);
|
|
|
|
Vector2D bbl = new Vector2D(General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary);
|
|
|
|
Vector2D bbr = new Vector2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary);
|
|
|
|
top = new Line2D(btl, btr);
|
|
|
|
right = new Line2D(btr, bbr);
|
|
|
|
bottom = new Line2D(bbl, bbr);
|
|
|
|
left = new Line2D(btl, bbl);
|
2016-02-17 22:23:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
protected virtual void AddInterface()
|
|
|
|
{
|
|
|
|
panel.Register();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected virtual void RemoveInterface()
|
|
|
|
{
|
2016-03-04 13:41:55 +00:00
|
|
|
General.Settings.WritePluginSetting("drawlinesmode.continuousdrawing", panel.ContinuousDrawing);
|
2016-03-14 10:25:27 +00:00
|
|
|
General.Settings.WritePluginSetting("drawlinesmode.autoclosedrawing", panel.AutoCloseDrawing);
|
2016-04-21 21:00:58 +00:00
|
|
|
General.Settings.WritePluginSetting("drawlinesmode.showguidelines", panel.ShowGuidelines);
|
2016-02-17 22:23:18 +00:00
|
|
|
panel.Unregister();
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
#region ================== Events
|
|
|
|
|
|
|
|
public override void OnHelp()
|
|
|
|
{
|
|
|
|
General.ShowHelp("e_drawgeometry.html");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Engaging
|
|
|
|
public override void OnEngage()
|
|
|
|
{
|
|
|
|
base.OnEngage();
|
|
|
|
EnableAutoPanning();
|
2016-02-17 22:23:18 +00:00
|
|
|
AddInterface(); //mxd
|
2009-04-19 18:07:22 +00:00
|
|
|
renderer.SetPresentation(Presentation.Standard);
|
|
|
|
|
|
|
|
// Set cursor
|
|
|
|
General.Interface.SetCursor(Cursors.Cross);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disengaging
|
|
|
|
public override void OnDisengage()
|
|
|
|
{
|
2016-02-17 22:23:18 +00:00
|
|
|
RemoveInterface(); //mxd
|
2009-04-19 18:07:22 +00:00
|
|
|
base.OnDisengage();
|
|
|
|
DisableAutoPanning();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cancelled
|
|
|
|
public override void OnCancel()
|
|
|
|
{
|
2016-02-17 22:23:18 +00:00
|
|
|
//mxd. Cannot leave this way when continuous drawing is enabled
|
2016-03-14 10:25:27 +00:00
|
|
|
if(continuousdrawing)
|
|
|
|
{
|
|
|
|
drawingautoclosed = false;
|
|
|
|
return;
|
|
|
|
}
|
2016-02-17 22:23:18 +00:00
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// Cancel base class
|
|
|
|
base.OnCancel();
|
|
|
|
|
|
|
|
// Return to original mode
|
|
|
|
General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Accepted
|
|
|
|
public override void OnAccept()
|
|
|
|
{
|
|
|
|
Cursor.Current = Cursors.AppStarting;
|
|
|
|
General.Settings.FindDefaultDrawSettings();
|
|
|
|
|
|
|
|
// When points have been drawn
|
|
|
|
if(points.Count > 0)
|
|
|
|
{
|
|
|
|
// Make undo for the draw
|
|
|
|
General.Map.UndoRedo.CreateUndo("Line draw");
|
|
|
|
|
|
|
|
// Make an analysis and show info
|
2014-12-03 23:15:26 +00:00
|
|
|
string[] adjectives = new[]
|
2009-04-19 18:07:22 +00:00
|
|
|
{ "beautiful", "lovely", "romantic", "stylish", "cheerful", "comical",
|
|
|
|
"awesome", "accurate", "adorable", "adventurous", "attractive", "cute",
|
|
|
|
"elegant", "glamorous", "gorgeous", "handsome", "magnificent", "unusual",
|
|
|
|
"outstanding", "mysterious", "amusing", "charming", "fantastic", "jolly" };
|
|
|
|
string word = adjectives[points.Count % adjectives.Length];
|
|
|
|
word = (points.Count > adjectives.Length) ? "very " + word : word;
|
2013-04-15 10:54:55 +00:00
|
|
|
string a = ((word[0] == 'a') || (word[0] == 'e') || (word[0] == 'o') || (word[0] == 'u')) ? "an " : "a ";
|
2009-04-19 18:07:22 +00:00
|
|
|
General.Interface.DisplayStatus(StatusType.Action, "Created " + a + word + " drawing.");
|
|
|
|
|
|
|
|
// Make the drawing
|
2016-02-17 22:23:18 +00:00
|
|
|
if(Tools.DrawLines(points, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) //mxd
|
|
|
|
{
|
|
|
|
// Snap to map format accuracy
|
|
|
|
General.Map.Map.SnapAllToAccuracy();
|
|
|
|
|
|
|
|
// Clear selection
|
|
|
|
General.Map.Map.ClearAllSelected();
|
|
|
|
|
|
|
|
// Update cached values
|
|
|
|
General.Map.Map.Update();
|
|
|
|
|
2016-05-18 20:31:40 +00:00
|
|
|
//mxd. Outer sectors may require some splittin...
|
2016-06-15 22:02:51 +00:00
|
|
|
if(General.Settings.SplitJoinedSectors) Tools.SplitOuterSectors(General.Map.Map.GetMarkedLinedefs(true));
|
2016-05-18 20:31:40 +00:00
|
|
|
|
2016-02-17 22:23:18 +00:00
|
|
|
// Edit new sectors?
|
|
|
|
List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
|
|
|
|
if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
|
|
|
|
General.Interface.ShowEditSectors(newsectors);
|
|
|
|
|
|
|
|
// Update the used textures
|
|
|
|
General.Map.Data.UpdateUsedTextures();
|
|
|
|
|
|
|
|
//mxd
|
|
|
|
General.Map.Renderer2D.UpdateExtraFloorFlag();
|
|
|
|
|
|
|
|
// Map is changed
|
|
|
|
General.Map.IsChanged = true;
|
|
|
|
}
|
|
|
|
else
|
2010-08-15 19:43:00 +00:00
|
|
|
{
|
|
|
|
// Drawing failed
|
|
|
|
General.Map.UndoRedo.WithdrawUndo();
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Done
|
|
|
|
Cursor.Current = Cursors.Default;
|
2016-02-17 22:23:18 +00:00
|
|
|
|
|
|
|
if(continuousdrawing)
|
|
|
|
{
|
|
|
|
//mxd. Reset settings
|
|
|
|
points.Clear();
|
|
|
|
labels.Clear();
|
2016-03-14 10:25:27 +00:00
|
|
|
drawingautoclosed = false;
|
2016-02-17 22:23:18 +00:00
|
|
|
|
|
|
|
//mxd. Redraw display
|
|
|
|
General.Interface.RedrawDisplay();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Return to original mode
|
|
|
|
General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This redraws the display
|
|
|
|
public override void OnRedrawDisplay()
|
|
|
|
{
|
|
|
|
renderer.RedrawSurface();
|
|
|
|
|
|
|
|
// Render lines
|
|
|
|
if(renderer.StartPlotter(true))
|
|
|
|
{
|
|
|
|
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
|
|
|
|
renderer.PlotVerticesSet(General.Map.Map.Vertices);
|
|
|
|
renderer.Finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Render things
|
|
|
|
if(renderer.StartThings(true))
|
|
|
|
{
|
2016-04-01 10:49:19 +00:00
|
|
|
renderer.RenderThingSet(General.Map.Map.Things, General.Settings.ActiveThingsAlpha);
|
2009-04-19 18:07:22 +00:00
|
|
|
renderer.Finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Normal update
|
|
|
|
Update();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mouse moving
|
|
|
|
public override void OnMouseMove(MouseEventArgs e)
|
|
|
|
{
|
|
|
|
base.OnMouseMove(e);
|
2015-08-24 21:49:15 +00:00
|
|
|
if(panning) return; //mxd. Skip all this jazz while panning
|
2009-04-19 18:07:22 +00:00
|
|
|
Update();
|
|
|
|
}
|
|
|
|
|
|
|
|
// When a key is released
|
|
|
|
public override void OnKeyUp(KeyEventArgs e)
|
|
|
|
{
|
|
|
|
base.OnKeyUp(e);
|
2020-10-02 17:46:01 +00:00
|
|
|
if((snaptogrid != (snaptocardinaldirection || (General.Interface.ShiftState ^ General.Interface.SnapToGrid))) ||
|
2015-07-09 22:32:12 +00:00
|
|
|
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge)) ||
|
|
|
|
(snaptocardinaldirection != (General.Interface.AltState && General.Interface.ShiftState))) Update();
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// When a key is pressed
|
|
|
|
public override void OnKeyDown(KeyEventArgs e)
|
|
|
|
{
|
|
|
|
base.OnKeyDown(e);
|
2020-10-02 17:46:01 +00:00
|
|
|
if ((snaptogrid != (snaptocardinaldirection || (General.Interface.ShiftState ^ General.Interface.SnapToGrid))) ||
|
2015-07-09 22:32:12 +00:00
|
|
|
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge)) ||
|
|
|
|
(snaptocardinaldirection != (General.Interface.AltState && General.Interface.ShiftState))) Update();
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
2016-02-17 22:23:18 +00:00
|
|
|
|
|
|
|
//mxd
|
|
|
|
protected void OnContinuousDrawingChanged(object value, EventArgs e)
|
|
|
|
{
|
|
|
|
continuousdrawing = (bool)value;
|
|
|
|
}
|
2016-03-14 10:25:27 +00:00
|
|
|
|
|
|
|
//mxd
|
|
|
|
protected void OnAutoCloseDrawingChanged(object value, EventArgs e)
|
|
|
|
{
|
|
|
|
autoclosedrawing = (bool)value;
|
|
|
|
}
|
2016-04-21 21:00:58 +00:00
|
|
|
|
|
|
|
//mxd
|
2016-09-26 12:53:50 +00:00
|
|
|
protected void OnShowGuidelinesChanged(object value, EventArgs e)
|
2016-04-21 21:00:58 +00:00
|
|
|
{
|
|
|
|
showguidelines = (bool)value;
|
|
|
|
General.Interface.RedrawDisplay();
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Actions
|
|
|
|
|
|
|
|
// Drawing a point
|
|
|
|
[BeginAction("drawpoint")]
|
2013-09-11 09:47:53 +00:00
|
|
|
public void DrawPoint()
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
|
|
|
// Mouse inside window?
|
|
|
|
if(General.Interface.MouseInDisplay)
|
|
|
|
{
|
|
|
|
DrawnVertex newpoint = GetCurrentPosition();
|
2010-08-13 18:32:21 +00:00
|
|
|
if(!DrawPointAt(newpoint)) General.Interface.DisplayStatus(StatusType.Warning, "Failed to draw point: outside of map boundaries.");
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 21:23:37 +00:00
|
|
|
// Remove last point
|
2009-04-19 18:07:22 +00:00
|
|
|
[BeginAction("removepoint")]
|
2016-12-16 21:23:37 +00:00
|
|
|
public virtual void RemovePoint() { RemovePointAt(points.Count - 1); }
|
|
|
|
|
|
|
|
//mxd. Remove first point
|
|
|
|
[BeginAction("removefirstpoint")]
|
|
|
|
public virtual void RemoveFirstPoint() { RemovePointAt(0); }
|
|
|
|
|
|
|
|
//mxd
|
|
|
|
private void RemovePointAt(int index)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2016-12-16 21:23:37 +00:00
|
|
|
if(points.Count > 0 && points.Count > index) points.RemoveAt(index);
|
|
|
|
if(labels.Count > 0 && labels.Count > index)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2016-12-16 21:23:37 +00:00
|
|
|
labels[index].Dispose();
|
|
|
|
labels.RemoveAt(index);
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Update();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finish drawing
|
|
|
|
[BeginAction("finishdraw")]
|
|
|
|
public void FinishDraw()
|
|
|
|
{
|
|
|
|
// Accept the changes
|
|
|
|
General.Editing.AcceptMode();
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|