625 lines
19 KiB
C#
625 lines
19 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
using System.Runtime.InteropServices;
|
|
using Dalamud.Bindings.ImGui;
|
|
using Dalamud.Interface.Textures.TextureWraps;
|
|
|
|
namespace LLib.ImGui;
|
|
|
|
public sealed class MapPolygonEditor
|
|
{
|
|
private readonly MapTextureService _mapService;
|
|
|
|
private float _zoom = 0.5f;
|
|
|
|
private Vector2 _offset = Vector2.Zero;
|
|
|
|
private bool _isPanning;
|
|
|
|
private Vector2 _lastMousePos;
|
|
|
|
private Vector2 _panStartPos;
|
|
|
|
private bool _isDrawing;
|
|
|
|
private readonly List<Vector2> _drawingVertices = new List<Vector2>();
|
|
|
|
private bool _isDraggingVertex;
|
|
|
|
private bool _suppressClickThisFrame;
|
|
|
|
private int _dragPolyIndex = -1;
|
|
|
|
private int _dragVertexIndex = -1;
|
|
|
|
private int _hoveredVertexIndex = -1;
|
|
|
|
private int _hoveredEdgeIndex = -1;
|
|
|
|
private const float VertexHandleRadius = 5f;
|
|
|
|
private const float VertexHitRadius = 12f;
|
|
|
|
private const float EdgeMidpointRadius = 4f;
|
|
|
|
private const float EdgeMidpointHitRadius = 10f;
|
|
|
|
private const float VertexSnapRadius = 10f;
|
|
|
|
private const float ClickThreshold = 4f;
|
|
|
|
private const float ClosePolygonPixelDist = 12f;
|
|
|
|
private const int MinVerticesForPolygon = 3;
|
|
|
|
public bool IsDrawing => _isDrawing;
|
|
|
|
public int SelectedIndex { get; set; } = -1;
|
|
|
|
public MapPolygonEditor(MapTextureService mapService)
|
|
{
|
|
_mapService = mapService;
|
|
}
|
|
|
|
public void StartDrawing()
|
|
{
|
|
_isDrawing = true;
|
|
_drawingVertices.Clear();
|
|
}
|
|
|
|
public void CancelDrawing()
|
|
{
|
|
_isDrawing = false;
|
|
_drawingVertices.Clear();
|
|
}
|
|
|
|
public void ResetView()
|
|
{
|
|
_zoom = 0.5f;
|
|
_offset = Vector2.Zero;
|
|
}
|
|
|
|
public void Draw(IEditablePolygonSet polygons, Vector3? playerPosition, Vector2? size = null)
|
|
{
|
|
Vector2 contentRegionAvail = Dalamud.Bindings.ImGui.ImGui.GetContentRegionAvail();
|
|
Vector2 size2 = size ?? new Vector2(contentRegionAvail.X, MathF.Max(contentRegionAvail.Y, 400f));
|
|
if (!Dalamud.Bindings.ImGui.ImGui.BeginChild("##MapPolygonEditor", size2, border: true))
|
|
{
|
|
Dalamud.Bindings.ImGui.ImGui.EndChild();
|
|
return;
|
|
}
|
|
Vector2 cursorScreenPos = Dalamud.Bindings.ImGui.ImGui.GetCursorScreenPos();
|
|
Vector2 contentRegionAvail2 = Dalamud.Bindings.ImGui.ImGui.GetContentRegionAvail();
|
|
Dalamud.Bindings.ImGui.ImGui.InvisibleButton("##MapCapture", contentRegionAvail2);
|
|
bool flag = Dalamud.Bindings.ImGui.ImGui.IsItemHovered();
|
|
IDalamudTextureWrap textureWrap = _mapService.GetTextureWrap();
|
|
if (textureWrap == null)
|
|
{
|
|
Dalamud.Bindings.ImGui.ImGui.SetCursorScreenPos(cursorScreenPos + new Vector2(8f, 8f));
|
|
if (_mapService.IsSearching)
|
|
{
|
|
Dalamud.Bindings.ImGui.ImGui.TextDisabled("Loading map texture...");
|
|
}
|
|
else
|
|
{
|
|
Dalamud.Bindings.ImGui.ImGui.TextDisabled("No map texture available.");
|
|
}
|
|
Dalamud.Bindings.ImGui.ImGui.EndChild();
|
|
return;
|
|
}
|
|
float value = 2048f * _zoom;
|
|
Vector2 vector = new Vector2(value);
|
|
Vector2 imagePos = cursorScreenPos + _offset + contentRegionAvail2 * 0.5f - vector * 0.5f;
|
|
int nearVertexIndex = -1;
|
|
if (!_isDrawing && SelectedIndex >= 0 && SelectedIndex < polygons.PolygonCount)
|
|
{
|
|
IList<Vector2> vertices = polygons.GetVertices(SelectedIndex);
|
|
nearVertexIndex = FindNearestVertexHandle(vertices, imagePos, vector);
|
|
}
|
|
HandleVertexDrag(polygons, imagePos, vector, flag, nearVertexIndex);
|
|
if (!_isDraggingVertex)
|
|
{
|
|
HandlePanZoom(cursorScreenPos, contentRegionAvail2, flag);
|
|
}
|
|
imagePos = cursorScreenPos + _offset + contentRegionAvail2 * 0.5f - vector * 0.5f;
|
|
ImDrawListPtr windowDrawList = Dalamud.Bindings.ImGui.ImGui.GetWindowDrawList();
|
|
windowDrawList.AddImage(textureWrap.Handle, imagePos, imagePos + vector);
|
|
DrawPolygons(windowDrawList, polygons, imagePos, vector);
|
|
if (playerPosition.HasValue)
|
|
{
|
|
Vector3 valueOrDefault = playerPosition.GetValueOrDefault();
|
|
Vector2 center = _mapService.WorldToScreen(valueOrDefault.X, valueOrDefault.Z, imagePos, vector);
|
|
windowDrawList.AddCircleFilled(center, 4f, 4278255360u);
|
|
windowDrawList.AddCircle(center, 6f, 4278190080u);
|
|
}
|
|
if (_isDrawing)
|
|
{
|
|
DrawPolygonInProgress(windowDrawList, imagePos, vector);
|
|
}
|
|
HandleMouseInput(polygons, imagePos, vector, flag);
|
|
HandleDrawingInput(polygons, imagePos, vector, flag);
|
|
Dalamud.Bindings.ImGui.ImGui.EndChild();
|
|
}
|
|
|
|
private void DrawPolygons(ImDrawListPtr drawList, IEditablePolygonSet polygons, Vector2 imagePos, Vector2 imageSizeVec)
|
|
{
|
|
for (int i = 0; i < polygons.PolygonCount; i++)
|
|
{
|
|
IList<Vector2> vertices = polygons.GetVertices(i);
|
|
if (vertices.Count >= 3)
|
|
{
|
|
uint num = polygons.GetColor(i);
|
|
bool num2 = i == SelectedIndex;
|
|
if (num2)
|
|
{
|
|
num = (num & 0xFFFFFF) | 0x90000000u;
|
|
}
|
|
DrawFilledPolygon(drawList, vertices, imagePos, imageSizeVec, num);
|
|
float thickness = (num2 ? 3f : 1f);
|
|
uint color = (num2 ? uint.MaxValue : (num | 0xFF000000u));
|
|
DrawPolygonBorder(drawList, vertices, imagePos, imageSizeVec, color, thickness);
|
|
if (num2)
|
|
{
|
|
DrawVertexHandles(drawList, vertices, imagePos, imageSizeVec);
|
|
}
|
|
string label = polygons.GetLabel(i);
|
|
if (!string.IsNullOrEmpty(label))
|
|
{
|
|
Vector2 vector = ComputeCentroid(vertices);
|
|
Vector2 pos = _mapService.WorldToScreen(vector.X, vector.Y, imagePos, imageSizeVec);
|
|
drawList.AddText(pos, uint.MaxValue, label);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawFilledPolygon(ImDrawListPtr drawList, IList<Vector2> verts, Vector2 imagePos, Vector2 imageSizeVec, uint color)
|
|
{
|
|
Vector2[] array = new Vector2[verts.Count];
|
|
for (int i = 0; i < verts.Count; i++)
|
|
{
|
|
array[i] = _mapService.WorldToScreen(verts[i].X, verts[i].Y, imagePos, imageSizeVec);
|
|
}
|
|
List<int> list = new List<int>(verts.Count);
|
|
for (int j = 0; j < verts.Count; j++)
|
|
{
|
|
list.Add(j);
|
|
}
|
|
float polySignedArea = SignedArea(array, list);
|
|
while (list.Count > 2)
|
|
{
|
|
bool flag = false;
|
|
for (int k = 0; k < list.Count; k++)
|
|
{
|
|
int index = (k - 1 + list.Count) % list.Count;
|
|
int index2 = (k + 1) % list.Count;
|
|
int num = list[index];
|
|
int num2 = list[k];
|
|
int num3 = list[index2];
|
|
if (IsEar(array, list, num, num2, num3, polySignedArea))
|
|
{
|
|
drawList.AddTriangleFilled(array[num], array[num2], array[num3], color);
|
|
list.RemoveAt(k);
|
|
flag = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!flag)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static float SignedArea(Vector2[] verts, List<int> indices)
|
|
{
|
|
float num = 0f;
|
|
for (int i = 0; i < indices.Count; i++)
|
|
{
|
|
Vector2 vector = verts[indices[i]];
|
|
Vector2 vector2 = verts[indices[(i + 1) % indices.Count]];
|
|
num += (vector2.X - vector.X) * (vector2.Y + vector.Y);
|
|
}
|
|
return num;
|
|
}
|
|
|
|
private static bool IsEar(Vector2[] verts, List<int> indices, int prev, int curr, int next, float polySignedArea)
|
|
{
|
|
Vector2 vector = verts[prev];
|
|
Vector2 vector2 = verts[curr];
|
|
Vector2 vector3 = verts[next];
|
|
float num = Cross2D(vector2 - vector, vector3 - vector);
|
|
if (polySignedArea > 0f && num >= 0f)
|
|
{
|
|
return false;
|
|
}
|
|
if (polySignedArea <= 0f && num <= 0f)
|
|
{
|
|
return false;
|
|
}
|
|
foreach (int index in indices)
|
|
{
|
|
if (index != prev && index != curr && index != next && PointInTriangle(verts[index], vector, vector2, vector3))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private static bool PointInTriangle(Vector2 p, Vector2 a, Vector2 b, Vector2 c)
|
|
{
|
|
float num = Cross2D(p - a, b - a);
|
|
float num2 = Cross2D(p - b, c - b);
|
|
float num3 = Cross2D(p - c, a - c);
|
|
bool flag = num < 0f || num2 < 0f || num3 < 0f;
|
|
bool flag2 = num > 0f || num2 > 0f || num3 > 0f;
|
|
return !(flag && flag2);
|
|
}
|
|
|
|
private static float Cross2D(Vector2 a, Vector2 b)
|
|
{
|
|
return a.X * b.Y - a.Y * b.X;
|
|
}
|
|
|
|
private void DrawPolygonBorder(ImDrawListPtr drawList, IList<Vector2> verts, Vector2 imagePos, Vector2 imageSizeVec, uint color, float thickness)
|
|
{
|
|
for (int i = 0; i < verts.Count; i++)
|
|
{
|
|
int index = (i + 1) % verts.Count;
|
|
Vector2 p = _mapService.WorldToScreen(verts[i].X, verts[i].Y, imagePos, imageSizeVec);
|
|
Vector2 p2 = _mapService.WorldToScreen(verts[index].X, verts[index].Y, imagePos, imageSizeVec);
|
|
drawList.AddLine(p, p2, color, thickness);
|
|
}
|
|
}
|
|
|
|
private void DrawVertexHandles(ImDrawListPtr drawList, IList<Vector2> verts, Vector2 imagePos, Vector2 imageSizeVec)
|
|
{
|
|
_hoveredVertexIndex = FindNearestVertexHandle(verts, imagePos, imageSizeVec);
|
|
_hoveredEdgeIndex = -1;
|
|
if (_hoveredVertexIndex < 0 && !_isDraggingVertex)
|
|
{
|
|
_hoveredEdgeIndex = FindNearestEdgeMidpoint(verts, imagePos, imageSizeVec);
|
|
}
|
|
for (int i = 0; i < verts.Count; i++)
|
|
{
|
|
int index = (i + 1) % verts.Count;
|
|
Vector2 vector = (verts[i] + verts[index]) / 2f;
|
|
Vector2 center = _mapService.WorldToScreen(vector.X, vector.Y, imagePos, imageSizeVec);
|
|
bool num = i == _hoveredEdgeIndex;
|
|
uint col = (num ? 4278255615u : 2164260863u);
|
|
float radius = (num ? 6f : 4f);
|
|
drawList.AddCircleFilled(center, radius, col);
|
|
Vector2 vector2 = verts[i];
|
|
Vector2 center2 = _mapService.WorldToScreen(vector2.X, vector2.Y, imagePos, imageSizeVec);
|
|
bool num2 = i == _hoveredVertexIndex;
|
|
uint col2 = (num2 ? 4278255615u : uint.MaxValue);
|
|
float radius2 = (num2 ? 7f : 5f);
|
|
drawList.AddCircleFilled(center2, radius2, col2);
|
|
drawList.AddCircle(center2, radius2, 4278190080u);
|
|
}
|
|
}
|
|
|
|
private void DrawPolygonInProgress(ImDrawListPtr drawList, Vector2 imagePos, Vector2 imageSizeVec)
|
|
{
|
|
Vector2 mousePos = Dalamud.Bindings.ImGui.ImGui.GetMousePos();
|
|
if (_drawingVertices.Count == 0)
|
|
{
|
|
drawList.AddCircle(mousePos, 4f, uint.MaxValue);
|
|
return;
|
|
}
|
|
for (int i = 0; i < _drawingVertices.Count - 1; i++)
|
|
{
|
|
Vector2 p = _mapService.WorldToScreen(_drawingVertices[i].X, _drawingVertices[i].Y, imagePos, imageSizeVec);
|
|
Vector2 p2 = _mapService.WorldToScreen(_drawingVertices[i + 1].X, _drawingVertices[i + 1].Y, imagePos, imageSizeVec);
|
|
drawList.AddLine(p, p2, uint.MaxValue, 2f);
|
|
}
|
|
for (int j = 0; j < _drawingVertices.Count; j++)
|
|
{
|
|
Vector2 center = _mapService.WorldToScreen(_drawingVertices[j].X, _drawingVertices[j].Y, imagePos, imageSizeVec);
|
|
uint col = ((j == 0) ? 4278255360u : uint.MaxValue);
|
|
drawList.AddCircleFilled(center, 4f, col);
|
|
}
|
|
MapTextureService mapService = _mapService;
|
|
List<Vector2> drawingVertices = _drawingVertices;
|
|
float x = drawingVertices[drawingVertices.Count - 1].X;
|
|
List<Vector2> drawingVertices2 = _drawingVertices;
|
|
Vector2 p3 = mapService.WorldToScreen(x, drawingVertices2[drawingVertices2.Count - 1].Y, imagePos, imageSizeVec);
|
|
drawList.AddLine(p3, mousePos, 2164260863u, 1.5f);
|
|
if (_drawingVertices.Count >= 3)
|
|
{
|
|
Vector2 vector = _mapService.WorldToScreen(_drawingVertices[0].X, _drawingVertices[0].Y, imagePos, imageSizeVec);
|
|
if (Vector2.Distance(mousePos, vector) < 12f)
|
|
{
|
|
drawList.AddCircle(vector, 12f, 4278255360u, 0, 2f);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandlePanZoom(Vector2 canvasPos, Vector2 canvasSize, bool isHovered)
|
|
{
|
|
ImGuiIOPtr iO = Dalamud.Bindings.ImGui.ImGui.GetIO();
|
|
if (isHovered && MathF.Abs(iO.MouseWheel) > 0.01f)
|
|
{
|
|
float zoom = _zoom;
|
|
_zoom = MathF.Max(0.1f, MathF.Min(3f, _zoom + iO.MouseWheel * 0.05f));
|
|
Vector2 vector = Dalamud.Bindings.ImGui.ImGui.GetMousePos() - canvasPos - canvasSize * 0.5f - _offset;
|
|
_offset -= vector * (_zoom / zoom - 1f);
|
|
}
|
|
bool flag = Dalamud.Bindings.ImGui.ImGui.IsMouseDown(ImGuiMouseButton.Left) || Dalamud.Bindings.ImGui.ImGui.IsMouseDown(ImGuiMouseButton.Right) || Dalamud.Bindings.ImGui.ImGui.IsMouseDown(ImGuiMouseButton.Middle);
|
|
if (isHovered && flag)
|
|
{
|
|
if (!_isPanning)
|
|
{
|
|
_isPanning = true;
|
|
_lastMousePos = Dalamud.Bindings.ImGui.ImGui.GetMousePos();
|
|
_panStartPos = _lastMousePos;
|
|
}
|
|
else
|
|
{
|
|
Vector2 mousePos = Dalamud.Bindings.ImGui.ImGui.GetMousePos();
|
|
Vector2 vector2 = mousePos - _lastMousePos;
|
|
_offset += vector2;
|
|
_lastMousePos = mousePos;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_isPanning = false;
|
|
}
|
|
}
|
|
|
|
private void HandleVertexDrag(IEditablePolygonSet polygons, Vector2 imagePos, Vector2 imageSizeVec, bool mapHovered, int nearVertexIndex)
|
|
{
|
|
if (!_isDraggingVertex && !_isDrawing && mapHovered && nearVertexIndex >= 0 && Dalamud.Bindings.ImGui.ImGui.IsMouseClicked(ImGuiMouseButton.Left))
|
|
{
|
|
_isDraggingVertex = true;
|
|
_dragPolyIndex = SelectedIndex;
|
|
_dragVertexIndex = nearVertexIndex;
|
|
}
|
|
if (_isDraggingVertex && Dalamud.Bindings.ImGui.ImGui.IsMouseDown(ImGuiMouseButton.Left) && _dragPolyIndex >= 0 && _dragPolyIndex < polygons.PolygonCount)
|
|
{
|
|
IList<Vector2> vertices = polygons.GetVertices(_dragPolyIndex);
|
|
if (_dragVertexIndex >= 0 && _dragVertexIndex < vertices.Count)
|
|
{
|
|
Vector2 mousePos = Dalamud.Bindings.ImGui.ImGui.GetMousePos();
|
|
Vector2 vector = _mapService.ScreenToWorld(mousePos, imagePos, imageSizeVec);
|
|
Vector2? vector2 = FindSnapTarget(polygons, _dragPolyIndex, _dragVertexIndex, mousePos, imagePos, imageSizeVec);
|
|
vertices[_dragVertexIndex] = vector2 ?? vector;
|
|
}
|
|
}
|
|
if (_isDraggingVertex && Dalamud.Bindings.ImGui.ImGui.IsMouseReleased(ImGuiMouseButton.Left))
|
|
{
|
|
_isDraggingVertex = false;
|
|
_dragPolyIndex = -1;
|
|
_dragVertexIndex = -1;
|
|
_suppressClickThisFrame = true;
|
|
}
|
|
if (!_isDraggingVertex && !_isDrawing && mapHovered && nearVertexIndex >= 0 && Dalamud.Bindings.ImGui.ImGui.IsMouseClicked(ImGuiMouseButton.Right) && SelectedIndex >= 0 && SelectedIndex < polygons.PolygonCount)
|
|
{
|
|
IList<Vector2> vertices2 = polygons.GetVertices(SelectedIndex);
|
|
if (vertices2.Count > 3)
|
|
{
|
|
vertices2.RemoveAt(nearVertexIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandleMouseInput(IEditablePolygonSet polygons, Vector2 imagePos, Vector2 imageSizeVec, bool mapHovered)
|
|
{
|
|
if (!Dalamud.Bindings.ImGui.ImGui.IsMouseReleased(ImGuiMouseButton.Left))
|
|
{
|
|
return;
|
|
}
|
|
if (_suppressClickThisFrame)
|
|
{
|
|
_suppressClickThisFrame = false;
|
|
}
|
|
else
|
|
{
|
|
if (_isDrawing || _isDraggingVertex || Vector2.Distance(Dalamud.Bindings.ImGui.ImGui.GetMousePos(), _panStartPos) > 4f || !mapHovered)
|
|
{
|
|
return;
|
|
}
|
|
Vector2 mousePos = Dalamud.Bindings.ImGui.ImGui.GetMousePos();
|
|
Vector2 point = _mapService.ScreenToWorld(mousePos, imagePos, imageSizeVec);
|
|
if (_hoveredEdgeIndex >= 0 && SelectedIndex >= 0 && SelectedIndex < polygons.PolygonCount)
|
|
{
|
|
IList<Vector2> vertices = polygons.GetVertices(SelectedIndex);
|
|
int hoveredEdgeIndex = _hoveredEdgeIndex;
|
|
if (hoveredEdgeIndex < vertices.Count)
|
|
{
|
|
int index = (hoveredEdgeIndex + 1) % vertices.Count;
|
|
Vector2 item = (vertices[hoveredEdgeIndex] + vertices[index]) / 2f;
|
|
vertices.Insert(index, item);
|
|
return;
|
|
}
|
|
}
|
|
int num = -1;
|
|
for (int i = 0; i < polygons.PolygonCount; i++)
|
|
{
|
|
IList<Vector2> vertices2 = polygons.GetVertices(i);
|
|
if (PointInPolygon(point, vertices2))
|
|
{
|
|
num = i;
|
|
}
|
|
}
|
|
if (num >= 0)
|
|
{
|
|
SelectedIndex = num;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandleDrawingInput(IEditablePolygonSet polygons, Vector2 imagePos, Vector2 imageSizeVec, bool mapHovered)
|
|
{
|
|
if (!_isDrawing)
|
|
{
|
|
return;
|
|
}
|
|
if (Dalamud.Bindings.ImGui.ImGui.IsKeyPressed(ImGuiKey.Escape))
|
|
{
|
|
_isDrawing = false;
|
|
_drawingVertices.Clear();
|
|
}
|
|
else if (Dalamud.Bindings.ImGui.ImGui.IsKeyPressed(ImGuiKey.Enter) && _drawingVertices.Count >= 3)
|
|
{
|
|
FinishDrawing(polygons);
|
|
}
|
|
else
|
|
{
|
|
if (!mapHovered)
|
|
{
|
|
return;
|
|
}
|
|
if (Dalamud.Bindings.ImGui.ImGui.IsMouseDoubleClicked(ImGuiMouseButton.Left) && _drawingVertices.Count >= 3)
|
|
{
|
|
FinishDrawing(polygons);
|
|
}
|
|
else
|
|
{
|
|
if (!Dalamud.Bindings.ImGui.ImGui.IsMouseClicked(ImGuiMouseButton.Left))
|
|
{
|
|
return;
|
|
}
|
|
Vector2 mousePos = Dalamud.Bindings.ImGui.ImGui.GetMousePos();
|
|
Vector2 item = _mapService.ScreenToWorld(mousePos, imagePos, imageSizeVec);
|
|
if (_drawingVertices.Count >= 3)
|
|
{
|
|
Vector2 value = _mapService.WorldToScreen(_drawingVertices[0].X, _drawingVertices[0].Y, imagePos, imageSizeVec);
|
|
if (Vector2.Distance(mousePos, value) < 12f)
|
|
{
|
|
FinishDrawing(polygons);
|
|
return;
|
|
}
|
|
}
|
|
_drawingVertices.Add(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void FinishDrawing(IEditablePolygonSet polygons)
|
|
{
|
|
_isDrawing = false;
|
|
if (_drawingVertices.Count < 3)
|
|
{
|
|
_drawingVertices.Clear();
|
|
return;
|
|
}
|
|
List<Vector2> drawingVertices = _drawingVertices;
|
|
int count = drawingVertices.Count;
|
|
List<Vector2> list = new List<Vector2>(count);
|
|
CollectionsMarshal.SetCount(list, count);
|
|
Span<Vector2> span = CollectionsMarshal.AsSpan(list);
|
|
int num = 0;
|
|
Span<Vector2> span2 = CollectionsMarshal.AsSpan(drawingVertices);
|
|
span2.CopyTo(span.Slice(num, span2.Length));
|
|
num += span2.Length;
|
|
polygons.AddPolygon(list);
|
|
SelectedIndex = polygons.PolygonCount - 1;
|
|
_drawingVertices.Clear();
|
|
}
|
|
|
|
private int FindNearestVertexHandle(IList<Vector2> verts, Vector2 imagePos, Vector2 imageSizeVec)
|
|
{
|
|
Vector2 mousePos = Dalamud.Bindings.ImGui.ImGui.GetMousePos();
|
|
float num = 12f;
|
|
int result = -1;
|
|
for (int i = 0; i < verts.Count; i++)
|
|
{
|
|
Vector2 value = _mapService.WorldToScreen(verts[i].X, verts[i].Y, imagePos, imageSizeVec);
|
|
float num2 = Vector2.Distance(mousePos, value);
|
|
if (num2 < num)
|
|
{
|
|
num = num2;
|
|
result = i;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private int FindNearestEdgeMidpoint(IList<Vector2> verts, Vector2 imagePos, Vector2 imageSizeVec)
|
|
{
|
|
if (verts.Count < 2)
|
|
{
|
|
return -1;
|
|
}
|
|
Vector2 mousePos = Dalamud.Bindings.ImGui.ImGui.GetMousePos();
|
|
float num = 10f;
|
|
int result = -1;
|
|
for (int i = 0; i < verts.Count; i++)
|
|
{
|
|
int index = (i + 1) % verts.Count;
|
|
Vector2 vector = (verts[i] + verts[index]) / 2f;
|
|
Vector2 value = _mapService.WorldToScreen(vector.X, vector.Y, imagePos, imageSizeVec);
|
|
float num2 = Vector2.Distance(mousePos, value);
|
|
if (num2 < num)
|
|
{
|
|
num = num2;
|
|
result = i;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private Vector2? FindSnapTarget(IEditablePolygonSet polygons, int currentPolyIndex, int currentVertexIndex, Vector2 mouseScreenPos, Vector2 imagePos, Vector2 imageSizeVec)
|
|
{
|
|
float num = 10f;
|
|
Vector2? result = null;
|
|
for (int i = 0; i < polygons.PolygonCount; i++)
|
|
{
|
|
IList<Vector2> vertices = polygons.GetVertices(i);
|
|
for (int j = 0; j < vertices.Count; j++)
|
|
{
|
|
if (i != currentPolyIndex || j != currentVertexIndex)
|
|
{
|
|
Vector2 value = _mapService.WorldToScreen(vertices[j].X, vertices[j].Y, imagePos, imageSizeVec);
|
|
float num2 = Vector2.Distance(mouseScreenPos, value);
|
|
if (num2 < num)
|
|
{
|
|
num = num2;
|
|
result = vertices[j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static bool PointInPolygon(Vector2 point, IList<Vector2> verts)
|
|
{
|
|
if (verts.Count < 3)
|
|
{
|
|
return false;
|
|
}
|
|
bool flag = false;
|
|
int num = 0;
|
|
int index = verts.Count - 1;
|
|
while (num < verts.Count)
|
|
{
|
|
float x = verts[num].X;
|
|
float y = verts[num].Y;
|
|
float x2 = verts[index].X;
|
|
float y2 = verts[index].Y;
|
|
if (y > point.Y != y2 > point.Y && point.X < (x2 - x) * (point.Y - y) / (y2 - y) + x)
|
|
{
|
|
flag = !flag;
|
|
}
|
|
index = num++;
|
|
}
|
|
return flag;
|
|
}
|
|
|
|
private static Vector2 ComputeCentroid(IList<Vector2> verts)
|
|
{
|
|
float num = 0f;
|
|
float num2 = 0f;
|
|
for (int i = 0; i < verts.Count; i++)
|
|
{
|
|
num += verts[i].X;
|
|
num2 += verts[i].Y;
|
|
}
|
|
return new Vector2(num / (float)verts.Count, num2 / (float)verts.Count);
|
|
}
|
|
}
|