2 using System.Collections.Generic;
3 using Microsoft.Xna.Framework;
4 using Microsoft.Xna.Framework.Graphics;
13 public static class ShapeExtensions
15 private static Texture2D _whitePixelTexture;
17 private static Texture2D GetTexture(SpriteBatch spriteBatch)
19 if (_whitePixelTexture ==
null)
21 CrossThread.RequestExecutionOnMainThread(() =>
23 _whitePixelTexture =
new Texture2D(spriteBatch.GraphicsDevice, 1, 1,
false, SurfaceFormat.Color);
24 _whitePixelTexture.SetData(
new[] { Color.White });
28 return _whitePixelTexture;
34 public static void DrawPolygon(
this SpriteBatch spriteBatch, Vector2 position, Polygon polygon, Color color,
37 DrawPolygon(spriteBatch, position, polygon.Vertices, color, thickness);
43 public static void DrawPolygon(
this SpriteBatch spriteBatch, Vector2 offset, IReadOnlyList<Vector2> points, Color color,
46 if (points.Count == 0)
49 if (points.Count == 1)
51 DrawPoint(spriteBatch, points[0], color, (
int)thickness);
55 var texture = GetTexture(spriteBatch);
57 for (var i = 0; i < points.Count - 1; i++)
58 DrawPolygonEdge(spriteBatch, points[i] + offset, points[i + 1] + offset, color, thickness);
60 DrawPolygonEdge(spriteBatch, points[points.Count - 1] + offset, points[0] + offset, color,
67 public static void DrawPolygonInner(
this SpriteBatch spriteBatch, Vector2 offset, IReadOnlyList<Vector2> points, Color color,
float thickness = 1f)
69 if (points.Count == 0) {
return; }
71 if (points.Count == 1)
73 DrawPoint(spriteBatch, points[0], color, (
int)thickness);
77 for (var i = 0; i < points.Count - 1; i++)
79 Vector2 point1 = points[i] + offset,
80 point2 = points[i + 1] + offset;
82 DrawPolygonEdgeInner(spriteBatch, point1, point2, color, thickness);
85 DrawPolygonEdgeInner(spriteBatch, points[^1] + offset, points[0] + offset, color, thickness);
88 private static void DrawPolygonEdgeInner(SpriteBatch spriteBatch, Vector2 point1, Vector2 point2, Color color,
float thickness)
90 var length = Vector2.Distance(point1, point2) + thickness;
91 var angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
92 var scale =
new Vector2(length, thickness);
93 Vector2 middle =
new Vector2((point1.X + point2.X) / 2f, (point1.Y + point2.Y) / 2f);
94 Texture2D tex = GUI.WhiteTexture;
95 spriteBatch.Draw(tex, middle,
null, color, angle,
new Vector2(tex.Width / 2f, tex.Height / 2f), scale, SpriteEffects.None, 0);
98 private static void DrawPolygonEdge(SpriteBatch spriteBatch, Vector2 point1, Vector2 point2, Color color,
float thickness)
100 var length = Vector2.Distance(point1, point2);
101 var angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
102 var scale =
new Vector2(length, thickness);
103 spriteBatch.Draw(GetTexture(spriteBatch), point1,
null, color, angle, Vector2.Zero, scale, SpriteEffects.None, 0);
109 public static void DrawLine(
this SpriteBatch spriteBatch,
float x1,
float y1,
float x2,
float y2, Color color,
110 float thickness = 1f)
112 DrawLine(spriteBatch,
new Vector2(x1, y1),
new Vector2(x2, y2), color, thickness);
115 public static void DrawLineWithTexture(
this SpriteBatch spriteBatch, Texture2D tex, Vector2 point1, Vector2 point2,
116 Color color,
float thickness = 1f)
119 var distance = Vector2.Distance(point1, point2);
122 var angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
124 DrawLine(spriteBatch, tex, point1, distance, angle, color, thickness);
130 public static void DrawLine(
this SpriteBatch spriteBatch, Vector2 point1, Vector2 point2, Color color,
131 float thickness = 1f)
134 var distance = Vector2.Distance(point1, point2);
137 var angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
139 DrawLine(spriteBatch, GetTexture(spriteBatch), point1, distance, angle, color, thickness);
145 public static void DrawLine(
this SpriteBatch spriteBatch, Texture2D tex, Vector2 point,
float length,
float angle, Color color,
146 float thickness = 1f)
148 var origin =
new Vector2(0f, tex.Height / 2f);
149 var scale =
new Vector2(length / tex.Width, thickness / tex.Height);
150 spriteBatch.Draw(tex, point,
null, color, angle, origin, scale, SpriteEffects.None, 0);
156 public static void DrawPoint(
this SpriteBatch spriteBatch,
float x,
float y, Color color,
float size = 1f)
158 DrawPoint(spriteBatch,
new Vector2(x, y), color, size);
164 public static void DrawPoint(
this SpriteBatch spriteBatch, Vector2 position, Color color,
float size = 1f)
166 var offset =
new Vector2(0.5f) -
new Vector2(size * 0.5f);
167 spriteBatch.Draw(GetTexture(spriteBatch), position + offset,
null, color, 0.0f, Vector2.Zero,
new Vector2(size), SpriteEffects.None, 0);
170 public static void DrawCircle(
this SpriteBatch spriteBatch, Vector2 center,
float radius,
int sides, Color color,
171 float thickness = 1f)
173 DrawPolygon(spriteBatch, center, CreateCircle(radius, sides), color, thickness);
176 public static void DrawCircle(
this SpriteBatch spriteBatch,
float x,
float y,
float radius,
int sides,
177 Color color,
float thickness = 1f)
179 DrawPolygon(spriteBatch,
new Vector2(x, y), CreateCircle(radius, sides), color, thickness);
182 public static void DrawSector(
this SpriteBatch spriteBatch, Vector2 center,
float radius,
float radians,
int sides, Color color,
float offset = 0,
float thickness = 1)
184 DrawPolygon(spriteBatch, center, CreateSector(radius, sides, radians, offset), color, thickness);
187 private static Vector2[] CreateSector(
double radius,
int sides,
float radians,
float offset = 0)
190 var points =
new Vector2[radians < MathHelper.TwoPi ? sides + 1 : sides];
191 var step = radians / sides;
193 double theta = offset;
194 for (var i = 0; i < sides; i++)
196 points[i] =
new Vector2((
float)Math.Cos(theta), (
float)Math.Sin(theta)) * (float)radius;
203 private static Vector2[] CreateCircle(
double radius,
int sides)
205 return CreateSector(radius, sides, MathHelper.TwoPi);
216 _localVertices = vertices.ToArray();
217 _transformedVertices = _localVertices;
218 _offset = Vector2.Zero;
220 _scale = Vector2.One;
224 private readonly Vector2[] _localVertices;
225 private Vector2[] _transformedVertices;
226 private Vector2 _offset;
227 private float _rotation;
228 private Vector2 _scale;
229 private bool _isDirty;
237 _transformedVertices = GetTransformedVertices();
241 return _transformedVertices;
247 get {
return Vertices.Min(v => v.X); }
252 get {
return Vertices.Max(v => v.X); }
257 get {
return Vertices.Min(v => v.Y); }
262 get {
return Vertices.Max(v => v.Y); }
283 private Vector2[] GetTransformedVertices()
285 var newVertices =
new Vector2[_localVertices.Length];
286 var isScaled = _scale != Vector2.One;
288 for (var i = 0; i < _localVertices.Length; i++)
290 var p = _localVertices[i];
298 var cos = (float)Math.Cos(_rotation);
299 var sin = (float)Math.Sin(_rotation);
300 p =
new Vector2(cos * p.X - sin * p.Y, sin * p.X + cos * p.Y);
303 newVertices[i] = p + _offset;
311 var polygon =
new Polygon(_localVertices);
312 polygon.Offset(offset);
313 polygon.Rotate(rotation);
314 polygon.Scale(scale - Vector2.One);
315 return new Polygon(polygon.Vertices);
328 for (var i = 0; i < vertices.Length; i++)
330 var x1 = vertices[i].X;
331 var y1 = vertices[i].Y;
332 var x2 = vertices[(i + 1) % vertices.Length].X;
333 var y2 = vertices[(i + 1) % vertices.Length].Y;
335 if ((((y1 <= y) && (y < y2)) || ((y2 <= y) && (y < y1))) && (x < (x2 - x1) / (y2 - y1) * (y - y1) + x1))
339 return (intersects & 1) == 1;
354 if (ReferenceEquals(
null, obj))
return false;
367 return Vertices.Aggregate(27, (current, v) => current + 13 * current + v.GetHashCode());
Original source: https://github.com/craftworkgames/MonoGame.Extended/blob/develop/Source/MonoGame....
bool Equals(Polygon other)
void Scale(Vector2 amount)
void Offset(Vector2 amount)
static bool operator!=(Polygon a, Polygon b)
Polygon(IEnumerable< Vector2 > vertices)
static bool operator==(Polygon a, Polygon b)
void Rotate(float amount)
override int GetHashCode()
override bool Equals(object obj)
bool Contains(Vector2 point)
bool Contains(float x, float y)
Polygon TransformedCopy(Vector2 offset, float rotation, Vector2 scale)