unsafe static bool CheckNearestPixel(float x, float y, BitmapIterator iter, Predicate <int> isFound) { if (x < 0 || y < 0) { return(false); } if (x >= iter.Bmp.Width || y >= iter.Bmp.Height) { return(false); } int val = ((int *)iter.PixelData)[(int)x + (int)y * iter.Bmp.Width]; if (isFound == null) { if (val != 0) { return(true); } } else { if (isFound(val)) { return(true); } } return(false); }
// ptとdirが表す直線状を、ptから双方向に操作したときに最初に見つかるピクセル // iterは32ビット長を仮定 unsafe static PointF GetNearestPixel(BitmapIterator iter, PointF pt, PointF dir, Rectangle bounds, Predicate <int> isFound = null) { if (iter.PixelSize != 4) { return(new PointF(-1, -1)); } float len = FMath.Distance(dir, PointF.Empty); if (len <= 1e-4) { return(new PointF(-1, -1)); } float dx = dir.X / len; float dy = dir.Y / len; int cnt = 0; while (true) { float x1 = pt.X + dx * cnt; float y1 = pt.Y + dy * cnt; float x2 = pt.X - dx * cnt; float y2 = pt.Y - dy * cnt; bool out1 = !bounds.Contains((int)x1, (int)y1); bool out2 = !bounds.Contains((int)x2, (int)y2); if (out1 && out2) { return(new PointF(-1, -1)); } if (!out1 && CheckNearestPixel(x1, y1, iter, isFound)) { return(new PointF(x1, y1)); } if (!out2 && CheckNearestPixel(x2, y2, iter, isFound)) { return(new PointF(x2, y2)); } cnt++; } }
unsafe Bitmap CreatGradBitmap(int w, int h) { var bmp = new Bitmap(200, 200, PixelFormat.Format32bppArgb); using (var iter = new BitmapIterator(bmp, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb)) { for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { iter.Data[iter.Stride * y + 4 * x + 0] = 255; iter.Data[iter.Stride * y + 4 * x + 1] = (byte)(255f * x / w); iter.Data[iter.Stride * y + 4 * x + 2] = (byte)(255f * y / h); iter.Data[iter.Stride * y + 4 * x + 3] = 255; } } } return(bmp); }
// テクスチャマッピングをする unsafe public Bitmap ToBitmap(Bitmap texture) { int maxx = (int)meshPointList.Select(p => p.X).Max() + 1; int maxy = (int)meshPointList.Select(p => p.Y).Max() + 1; if (maxx <= 0 || maxy <= 0) { return(null); } Bitmap bmp = new Bitmap(maxx, maxy, System.Drawing.Imaging.PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(bmp)) { g.Clear(Color.Transparent); } if (bmp != null) { using (var inIter = new BitmapIterator(texture, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) using (var outIter = new BitmapIterator(bmp, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { for (int i = 0; i < meshList.Count; i++) { var tri = meshList[i]; PointF pt0 = meshPointList[tri.idx0]; PointF pt1 = meshPointList[tri.idx1]; PointF pt2 = meshPointList[tri.idx2]; PointF cd0 = texcoordList[tri.idx0]; PointF cd1 = texcoordList[tri.idx1]; PointF cd2 = texcoordList[tri.idx2]; List <PointF> pts = new List <PointF>() { pt0, pt1, pt2, }; pts = pts.OrderBy(p => p.Y).ToList(); // ラスタライズ float v1_dx = pt1.X - pt0.X; float v1_dy = pt1.Y - pt0.Y; float v2_dx = pt2.X - pt0.X; float v2_dy = pt2.Y - pt0.Y; float v1_len = (float)Math.Sqrt(v1_dx * v1_dx + v1_dy * v1_dy); if (v1_len <= 1e-4) { continue; } float v2_len = (float)Math.Sqrt(v2_dx * v2_dx + v2_dy * v2_dy); if (v2_len <= 1e-4) { continue; } float v1_x = v1_dx / v1_len; float v1_y = v1_dy / v1_len; float v2_x = v2_dx / v2_len; float v2_y = v2_dy / v2_len; float ds = 1 / v1_len; float dt = 1 / v2_len; for (float t = 0; t <= 1; t += dt) { for (float s = 0; t + s <= 1; s += ds) { float x = pt0.X + v1_dx * s + v2_dx * t; float y = pt0.Y + v1_dy * s + v2_dy * t; float cx = cd0.X * (1 - s - t) + cd1.X * s + cd2.X * t; float cy = cd0.Y * (1 - s - t) + cd1.Y * s + cd2.Y * t; int offset_out = (int)x * 4 + (int)y * outIter.Stride; int offset_in = (int)cx * 4 + (int)cy * inIter.Stride; outIter.Data[offset_out + 0] = inIter.Data[offset_in + 0]; outIter.Data[offset_out + 1] = inIter.Data[offset_in + 1]; outIter.Data[offset_out + 2] = inIter.Data[offset_in + 2]; outIter.Data[offset_out + 3] = inIter.Data[offset_in + 3]; } } } } } using (Graphics g = Graphics.FromImage(bmp)) { g.DrawLines(penB, GetPath().ToArray()); foreach (var t in meshList) { PointF pt0 = meshPointList[t.idx0]; PointF pt1 = meshPointList[t.idx1]; PointF pt2 = meshPointList[t.idx2]; g.DrawLines(pen, new PointF[] { pt0, pt1, pt2, pt0 }); } } return(bmp); }
unsafe public bool[] GetPixelsInPath(Bitmap pathBmp, out Rectangle pixelBound) { pixelBound = new Rectangle(); bool[] isBoarder = new bool[pathBmp.Width * pathBmp.Height]; using (var bbmp = new BitmapIterator(pathBmp, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)) { for (int y = 0; y < pathBmp.Height; y++) { for (int x = 0; x < pathBmp.Width; x++) { bool onBoarder = bbmp.Data[bbmp.Stride * y + 4 * x + 1] >= 128; if (onBoarder) { isBoarder[x + y * pathBmp.Width] = true; } } } } // FloodFill HashSet <int> pixels = new HashSet <int>(); HashSet <int> checks = new HashSet <int>(pixels); checks.Add(0); while (checks.Count >= 1) { int idx = checks.First(); pixels.Add(idx); checks.Remove(idx); int x; int y = Math.DivRem(idx, pathBmp.Width, out x); if (x - 1 >= 0) { int i = (x - 1) + y * pathBmp.Width; if (!isBoarder[i] && !pixels.Contains(i)) { checks.Add(i); } } if (x + 1 < pathBmp.Width) { int i = (x + 1) + y * pathBmp.Width; if (!isBoarder[i] && !pixels.Contains(i)) { checks.Add(i); } } if (y - 1 >= 0) { int i = x + (y - 1) * pathBmp.Width; if (!isBoarder[i] && !pixels.Contains(i)) { checks.Add(i); } } if (y + 1 < pathBmp.Height) { int i = x + (y + 1) * pathBmp.Width; if (!isBoarder[i] && !pixels.Contains(i)) { checks.Add(i); } } } int xx = int.MaxValue; int yy = int.MaxValue; int x1 = int.MinValue; int y1 = int.MinValue; List <int> xs = new List <int>(); List <int> ys = new List <int>(); for (int y = 0; y < pathBmp.Height; y++) { for (int x = 0; x < pathBmp.Width; x++) { int i = x + y * pathBmp.Width; if (pixels.Contains(i)) { continue; } xx = Math.Min(xx, x); yy = Math.Min(yy, y); x1 = Math.Max(x1, x); y1 = Math.Max(y1, y); xs.Add(x); ys.Add(y); } } pixelBound = new Rectangle(xx, yy, x1 - xx + 1, y1 - yy + 1); bool[] trimmedPixels = new bool[pixelBound.Width * pixelBound.Height]; for (int i = 0; i < xs.Count; i++) { trimmedPixels[(xs[i] - pixelBound.X) + (ys[i] - pixelBound.Y) * pixelBound.Width] = true; } return(trimmedPixels); }
unsafe public void UpdateBitmap(SegmentRoot root) { if (root != null) { this.root = root; } if (!Closed) { return; } if (root == null || root.bmp == null) { return; } if (bmp != null) { bmp.Dispose(); } var expBound = GetExpandedBound(path); var pathBmp = DrawPath(expBound); Rectangle pixelBound = new Rectangle(); bool[] pixels = GetPixelsInPath(pathBmp, out pixelBound); offset = new Point(expBound.X + pixelBound.X, expBound.Y + pixelBound.Y); bmp = new Bitmap((int)pixelBound.Width, (int)pixelBound.Height, root.bmp.PixelFormat); using (var initer = new BitmapIterator(root.bmp, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)) using (var outiter = new BitmapIterator(bmp, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)) { for (int y = 0; y < pixelBound.Height; y++) { for (int x = 0; x < pixelBound.Width; x++) { if (pixels[pixelBound.Width * y + x]) { int xx = offset.X + x; int yy = offset.Y + y; if (xx < 0 || root.bmp.Width <= xx || yy < 0 || root.bmp.Height <= yy) { continue; } if (x < 0 || bmp.Width <= x || y < 0 || bmp.Height <= y) { continue; } int ii = initer.Stride * yy + 4 * xx; int oi = outiter.Stride * y + 4 * x; outiter.Data[oi + 0] = initer.Data[ii + 0]; outiter.Data[oi + 1] = initer.Data[ii + 1]; outiter.Data[oi + 2] = initer.Data[ii + 2]; outiter.Data[oi + 3] = initer.Data[ii + 3]; } } } } }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <param name="course">0以上.値が大きいほど荒くなる</param> /// <returns></returns> public static List <PointF> Subdivide(List <PointF> path, float course) { if (course <= 0) { return(null); } float x = float.MaxValue, y = float.MaxValue, x1 = float.MinValue, y1 = float.MinValue; foreach (var p in path) { x = Math.Min(p.X, x); y = Math.Min(p.Y, y); x1 = Math.Max(p.X, x1); y1 = Math.Max(p.Y, y1); } int w = (int)(x1 - x), h = (int)(y1 - y); x = x - w; y = y - h; w *= 3; h *= 3; Rectangle bounds = new Rectangle((int)x, (int)y, w, h); Pen pen = new Pen(Brushes.Red, 2); List <PointF> divPath = new List <PointF>(); using (Bitmap line = new Bitmap((int)x + w, (int)y + h)) { using (var g = Graphics.FromImage(line)) { g.Clear(Color.Transparent); g.DrawCurve(pen, path.ToArray()); } using (BitmapIterator iter = new BitmapIterator(line, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { for (int i = 0; i < path.Count - 1; i++) { divPath.Add(path[i]); List <PointF> seg = SubdivideSegment(path[i], path[i + 1], course); if (seg == null) { continue; } float len = FMath.Distance(path[i], path[i + 1]); if (len <= 1e-4) { continue; } float dy = (path[i].X - path[i + 1].X) / len; float dx = (path[i + 1].Y - path[i].Y) / len; PointF dir = new PointF(dx, dy); foreach (var p in seg) { PointF pt = GetNearestPixel(iter, p, dir, bounds, null); if (pt.X >= 0 && pt.Y >= 0) { divPath.Add(pt); } } } } } divPath.Add(path.Last()); return(divPath); }