Jypeli 10
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
28using Scalar = System.Double;
29#else
30using Scalar = System.Single;
31#endif
32using System;
33using System.Collections.Generic;
34
35using 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);
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 }
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}
System.Single Scalar
Definition: BitmapHelper.cs:30
System.Single Scalar
Definition: Clamped.cs:29
ArrayBitmap(bool[,] bitmap)
Definition: BitmapHelper.cs:49
bool TryGetSkip(Point2D point, out int nextY)
BitMapSkipper(IBitmap bitmap, List< Point2D > points)
Definition: BitmapHelper.cs:82
void FormatScan(IBitmap bitmap, int x)
void FillScans(List< Point2D > points)
void FromVectors(List< Point2D > points)
Definition: BitmapHelper.cs:90
static Point2D GetFirst(IBitmap bitmap)
static List< Point2D > CreateFromBitmap(IBitmap bitmap, Point2D first)
static Vector2D[] CreateFromBitmap(IBitmap bitmap)
static Vector2D[][] CreateManyFromBitmap(IBitmap bitmap)
static IEnumerable< Point2D > GetFirsts(IBitmap bitmap, List< BitMapSkipper > skippers)
static Point2D GetNextVertex(IBitmap bitmap, Point2D current, Point2D last)
static Vector2D[] Reduce(List< Point2D > list)
static bool IsInLine(ref Point2D p1, ref Point2D p2, ref Point2D p3)
static readonly Point2D[] bitmapPoints
This is the Vector Class.
Definition: Point2D.cs:50
static Point2D Add(Point2D left, Point2D right)
Adds 2 Vectors2Ds.
Definition: Point2D.cs:77
override bool Equals(object obj)
Compares this Vector to another object. This should be done because the equality operators (==,...
Definition: Point2D.cs:397
int Y
This is the Y value. (Usually represents a vertical position or direction.)
Definition: Point2D.cs:206
int X
This is the X value. (Usually represents a horizontal position or direction.)
Definition: Point2D.cs:197
This is the Vector Class.
Definition: Vector2D.cs:50