Jypeli  9
The simple game programming library
BitmapHelper.cs
Siirry tämän tiedoston dokumentaatioon.
1 #region MIT License
2 /*
3  * Copyright (c) 2005-2008 Jonathan Mark Porter. http://physics2d.googlepages.com/
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
17  * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  */
22 #endregion
23 
24 
25 
26 
27 #if UseDouble
28 using Scalar = System.Double;
29 #else
30 using Scalar = System.Single;
31 #endif
32 using System;
33 using System.Collections.Generic;
34 
35 using AdvanceMath;
36 
37 
39 {
40  public interface IBitmap
41  {
42  int Width { get;}
43  int Height { get;}
44  bool this[int x, int y] { get;}
45  }
46  public sealed class ArrayBitmap : IBitmap
47  {
48  bool[,] bitmap;
49  public ArrayBitmap(bool[,] bitmap)
50  {
51  if (bitmap == null) { throw new ArgumentNullException("bitmap"); }
52  this.bitmap = bitmap;
53  }
54  public int Width
55  {
56  get { return bitmap.GetLength(0); }
57  }
58  public int Height
59  {
60  get { return bitmap.GetLength(1); }
61  }
62  public bool this[int x, int y]
63  {
64  get
65  {
66  return
67  x >= 0 && x < Width &&
68  y >= 0 && y < Height &&
69  bitmap[x, y];
70  }
71  }
72  }
73  static class BitmapHelper
74  {
76  {
77  int xMin;
78  int xMax;
79  List<int>[] scans;
80 
81 
82  public BitMapSkipper(IBitmap bitmap, List<Point2D> points)
83  {
84  FromVectors(points);
85  CreateScans();
86  FillScans(points);
87  FormatScans(bitmap);
88  }
89 
90  void FromVectors(List<Point2D> points)
91  {
92  if (points == null) { throw new ArgumentNullException("vectors"); }
93  if (points.Count == 0) { throw new ArgumentOutOfRangeException("points"); }
94  xMin = points[0].X;
95  xMax = xMin;
96  for (int index = 1; index < points.Count; ++index)
97  {
98  Point2D current = points[index];
99  if (current.X > xMax)
100  {
101  xMax = current.X;
102  }
103  else if (current.X < xMin)
104  {
105  xMin = current.X;
106  }
107  }
108  }
109  void CreateScans()
110  {
111  scans = new List<int>[(xMax - xMin) + 1];
112  for (int index = 0; index < scans.Length; ++index)
113  {
114  scans[index] = new List<int>();
115  }
116  }
117  void FillScans(List<Point2D> points)
118  {
119  for (int index = 0; index < points.Count; ++index)
120  {
121  Point2D point = points[index];
122  int scanIndex = point.X - xMin;
123  scans[scanIndex].Add(point.Y);
124  }
125  }
126 
127  void FormatScans(IBitmap bitmap)
128  {
129  for (int index = 0; index < scans.Length; ++index)
130  {
131  scans[index].Sort();
132  FormatScan(bitmap, index);
133  }
134  }
135  void FormatScan(IBitmap bitmap, int x)
136  {
137  List<int> scan = scans[x];
138  List<int> newScan = new List<int>();
139  bool inPoly = false;
140  for (int index = 0; index < scan.Count; ++index)
141  {
142  int y = scan[index];
143  if (!inPoly)
144  {
145  newScan.Add(y);
146  }
147  bool value = bitmap[x + xMin, y + 1];
148  if (value)
149  {
150  inPoly = true;
151  }
152  else
153  {
154  newScan.Add(y);
155  inPoly = false;
156  }
157  }
158  //if (newScan.Count % 2 != 0) { throw new Exception(); }
159  scans[x] = newScan;
160  }
161  public bool TryGetSkip(Point2D point, out int nextY)
162  {
163  int scanIndex = point.X - xMin;
164  if (scanIndex < 0 || scanIndex >= scans.Length)
165  {
166  nextY = 0;
167  return false;
168  }
169  List<int> scan = scans[scanIndex];
170  for (int index = 1; index < scan.Count; index += 2)
171  {
172  if (point.Y >= scan[index - 1] &&
173  point.Y <= scan[index])
174  {
175  nextY = scan[index];
176  return true;
177  }
178  }
179  nextY = 0;
180  return false;
181  }
182  }
183  static readonly Point2D[] bitmapPoints = new Point2D[]{
184  new Point2D (1,1),
185  new Point2D (0,1),
186  new Point2D (-1,1),
187  new Point2D (-1,0),
188  new Point2D (-1,-1),
189  new Point2D (0,-1),
190  new Point2D (1,-1),
191  new Point2D (1,0),
192  };
193 
194  public static Vector2D[] CreateFromBitmap(IBitmap bitmap)
195  {
196  return Reduce(CreateFromBitmap(bitmap, GetFirst(bitmap)));
197  }
198  public static Vector2D[][] CreateManyFromBitmap(IBitmap bitmap)
199  {
200  List<BitMapSkipper> skippers = new List<BitMapSkipper>();
201  List<Vector2D[]> result = new List<Vector2D[]>();
202  foreach(Point2D first in GetFirsts(bitmap,skippers))
203  {
204  List<Point2D> points = CreateFromBitmap(bitmap, first);
205  BitMapSkipper skipper = new BitMapSkipper(bitmap, points);
206  skippers.Add(skipper);
207  result.Add(Reduce(points));
208  }
209  return result.ToArray();
210  }
211  private static List<Point2D> CreateFromBitmap(IBitmap bitmap, Point2D first)
212  {
213  Point2D current = first;
214  Point2D last = first - new Point2D(0, 1);
215  List<Point2D> result = new List<Point2D>();
216  do
217  {
218  result.Add(current);
219  current = GetNextVertex(bitmap, current, last);
220  last = result[result.Count - 1];
221  } while (current != first);
222  if (result.Count < 3) { throw new ArgumentException("The image has an area with less then 3 pixels (possibly an artifact).", "bitmap"); }
223  return result;
224  }
225  private static Point2D GetFirst(IBitmap bitmap)
226  {
227  for (int x = bitmap.Width - 1; x > -1; --x)
228  {
229  for (int y = 0; y < bitmap.Height; ++y)
230  {
231  if (bitmap[x, y])
232  {
233  return new Point2D(x, y);
234  }
235  }
236  }
237  throw new ArgumentException("TODO", "bitmap");
238  }
239  private static IEnumerable<Point2D> GetFirsts(IBitmap bitmap, List<BitMapSkipper> skippers)
240  {
241  for (int x = bitmap.Width - 1; x > -1; --x)
242  {
243  for (int y = 0; y < bitmap.Height; ++y)
244  {
245  if (bitmap[x, y])
246  {
247  bool contains = false;
248  Point2D result = new Point2D(x, y);
249  for (int index = 0; index < skippers.Count; ++index)
250  {
251  int nextY;
252  if (skippers[index].TryGetSkip(result, out nextY))
253  {
254  contains = true;
255  y = nextY;
256  break;
257  }
258  }
259  if (!contains)
260  {
261  yield return result;
262  }
263  }
264  }
265  }
266  }
267  private static Point2D GetNextVertex(IBitmap bitmap, Point2D current, Point2D last)
268  {
269  int offset = 0;
270  Point2D point;
271  for (int index = 0; index < bitmapPoints.Length; ++index)
272  {
273  Point2D.Add(ref current, ref bitmapPoints[index], out point);
274  if (Point2D.Equals(ref point, ref last))
275  {
276  offset = index + 1;
277  break;
278  }
279  }
280  for (int index = 0; index < bitmapPoints.Length; ++index)
281  {
282  Point2D.Add(
283  ref current,
284  ref bitmapPoints[(index + offset) % bitmapPoints.Length],
285  out point);
286  if (point.X >= 0 && point.X < bitmap.Width &&
287  point.Y >= 0 && point.Y < bitmap.Height &&
288  bitmap[point.X, point.Y])
289  {
290  return point;
291  }
292  }
293  throw new ArgumentException("The image has an area with less then 3 pixels (possibly an artifact).", "bitmap");
294  }
295  private static Vector2D[] Reduce(List<Point2D> list)
296  {
297  List<Vector2D> result = new List<Vector2D>(list.Count);
298  Point2D p1 = list[list.Count - 2];
299  Point2D p2 = list[list.Count - 1];
300  Point2D p3;
301  for (int index = 0; index < list.Count; ++index, p2 = p3)
302  {
303  if (index == list.Count - 1)
304  {
305  if (result.Count == 0) { throw new ArgumentException("Bad Polygon"); }
306  p3.X = (int)result[0].X;
307  p3.Y = (int)result[0].Y;
308  }
309  else { p3 = list[index]; }
310  if (!IsInLine(ref p1, ref p2, ref p3))
311  {
312  result.Add(new Vector2D(p2.X, p2.Y));
313  p1 = p2;
314  }
315  }
316  return result.ToArray();
317  }
318  private static bool IsInLine(ref Point2D p1, ref Point2D p2, ref Point2D p3)
319  {
320  int slope1 = (p1.Y - p2.Y);
321  int slope2 = (p2.Y - p3.Y);
322  return 0 == slope1 && 0 == slope2 ||
323  ((p1.X - p2.X) / (Scalar)slope1) == ((p2.X - p3.X) / (Scalar)slope2);
324  }
325  }
326 }
AdvanceMath.Point2D.Equals
override bool Equals(object obj)
Compares this Vector to another object. This should be done because the equality operators (==,...
Definition: Point2D.cs:397
Jypeli.Physics2d.BitmapHelper.BitMapSkipper.BitMapSkipper
BitMapSkipper(IBitmap bitmap, List< Point2D > points)
Definition: BitmapHelper.cs:82
AdvanceMath.Point2D
This is the Vector Class.
Definition: Point2D.cs:50
Jypeli.Physics2d.BitmapHelper.CreateFromBitmap
static Vector2D[] CreateFromBitmap(IBitmap bitmap)
Definition: BitmapHelper.cs:194
Jypeli.Physics2d.IBitmap.Width
int Width
Definition: BitmapHelper.cs:42
Jypeli.Physics2d.BitmapHelper.Reduce
static Vector2D[] Reduce(List< Point2D > list)
Definition: BitmapHelper.cs:295
Scalar
System.Single Scalar
Definition: BitmapHelper.cs:30
Jypeli.Physics2d.BitmapHelper.bitmapPoints
static readonly Point2D[] bitmapPoints
Definition: BitmapHelper.cs:183
Jypeli.Physics2d.BitmapHelper
Definition: BitmapHelper.cs:74
Jypeli.Physics2d.BitmapHelper.CreateManyFromBitmap
static Vector2D[][] CreateManyFromBitmap(IBitmap bitmap)
Definition: BitmapHelper.cs:198
Jypeli.Physics2d.BitmapHelper.BitMapSkipper.xMax
int xMax
Definition: BitmapHelper.cs:78
Jypeli.Physics2d.BitmapHelper.BitMapSkipper.TryGetSkip
bool TryGetSkip(Point2D point, out int nextY)
Definition: BitmapHelper.cs:161
AdvanceMath.Point2D.Y
int Y
This is the Y value. (Usually represents a vertical position or direction.)
Definition: Point2D.cs:206
Jypeli.Physics2d.BitmapHelper.BitMapSkipper.CreateScans
void CreateScans()
Definition: BitmapHelper.cs:109
Jypeli.Physics2d.BitmapHelper.GetFirst
static Point2D GetFirst(IBitmap bitmap)
Definition: BitmapHelper.cs:225
Jypeli.Physics2d.BitmapHelper.BitMapSkipper.scans
List< int >[] scans
Definition: BitmapHelper.cs:79
Jypeli.Physics2d.ArrayBitmap.Height
int Height
Definition: BitmapHelper.cs:59
Jypeli.Physics2d.BitmapHelper.GetNextVertex
static Point2D GetNextVertex(IBitmap bitmap, Point2D current, Point2D last)
Definition: BitmapHelper.cs:267
AdvanceMath.Point2D.X
int X
This is the X value. (Usually represents a horizontal position or direction.)
Definition: Point2D.cs:197
Jypeli.Physics2d.BitmapHelper.BitMapSkipper
Definition: BitmapHelper.cs:76
Jypeli.Physics2d.BitmapHelper.GetFirsts
static IEnumerable< Point2D > GetFirsts(IBitmap bitmap, List< BitMapSkipper > skippers)
Definition: BitmapHelper.cs:239
Jypeli.Physics2d.BitmapHelper.CreateFromBitmap
static List< Point2D > CreateFromBitmap(IBitmap bitmap, Point2D first)
Definition: BitmapHelper.cs:211
AdvanceMath.Point2D.Add
static Point2D Add(Point2D left, Point2D right)
Adds 2 Vectors2Ds.
Definition: Point2D.cs:77
Jypeli.Physics2d.ArrayBitmap.bitmap
bool[,] bitmap
Definition: BitmapHelper.cs:48
Jypeli.Physics2d
Definition: BitmapHelper.cs:39
Jypeli.Physics2d.BitmapHelper.IsInLine
static bool IsInLine(ref Point2D p1, ref Point2D p2, ref Point2D p3)
Definition: BitmapHelper.cs:318
Jypeli.Physics2d.IBitmap.Height
int Height
Definition: BitmapHelper.cs:43
Jypeli.Physics2d.BitmapHelper.BitMapSkipper.FromVectors
void FromVectors(List< Point2D > points)
Definition: BitmapHelper.cs:90
Scalar
System.Single Scalar
Definition: Clamped.cs:29
Jypeli.Physics2d.BitmapHelper.BitMapSkipper.FormatScan
void FormatScan(IBitmap bitmap, int x)
Definition: BitmapHelper.cs:135
System
Definition: CFFauxAttributes.cs:29
Jypeli.Physics2d.BitmapHelper.BitMapSkipper.xMin
int xMin
Definition: BitmapHelper.cs:77
Jypeli.Physics2d.IBitmap
Definition: BitmapHelper.cs:41
Jypeli.Physics2d.ArrayBitmap.Width
int Width
Definition: BitmapHelper.cs:55
AdvanceMath.Vector2D
This is the Vector Class.
Definition: Vector2D.cs:50
Jypeli.Physics2d.BitmapHelper.BitMapSkipper.FormatScans
void FormatScans(IBitmap bitmap)
Definition: BitmapHelper.cs:127
Jypeli.Physics2d.ArrayBitmap
Definition: BitmapHelper.cs:47
Jypeli.Physics2d.ArrayBitmap.ArrayBitmap
ArrayBitmap(bool[,] bitmap)
Definition: BitmapHelper.cs:49
AdvanceMath
Definition: Clamped.cs:36
Jypeli.Physics2d.BitmapHelper.BitMapSkipper.FillScans
void FillScans(List< Point2D > points)
Definition: BitmapHelper.cs:117