/* Function to sort an array using insertion sort*/ void insertionSort(EdgeTableTuple ett) { int i, j; EdgeBucket temp = new EdgeBucket(); for (i = 1; i < ett.countEdgeBucket; i++) { temp.ymax = ett.buckets[i].ymax; temp.xofymin = ett.buckets[i].xofymin; temp.slopeinverse = ett.buckets[i].slopeinverse; j = i - 1; while (j >= 0) { bool v = (temp.xofymin < ett.buckets[j].xofymin); if (!v) { break; } ett.buckets[j + 1].ymax = ett.buckets[j].ymax; ett.buckets[j + 1].xofymin = ett.buckets[j].xofymin; ett.buckets[j + 1].slopeinverse = ett.buckets[j].slopeinverse; j = j - 1; } ett.buckets[j + 1].ymax = temp.ymax; ett.buckets[j + 1].xofymin = temp.xofymin; ett.buckets[j + 1].slopeinverse = temp.slopeinverse; } }
// menambah data edge public void AddEdge(int x1, int y1, int x2, int y2) { EdgeBucket edgeBucket = new EdgeBucket(); // menentukan titik maksimum dan minimum if (y1 > y2) { edgeBucket.yMax = y1; edgeBucket.xMax = x1; edgeBucket.yMin = y2; edgeBucket.xMin = x2; } else { edgeBucket.yMax = y2; edgeBucket.xMax = x2; edgeBucket.yMin = y1; edgeBucket.xMin = x1; } edgeBucket.sum = x1; float dx = (float)x2 - (float)x1; float dy = (float)y2 - (float)y1; float m = (float)dy / (float)dx; // menentukan arah garis berdasarkan nilai gradiennya if (m < 0) { edgeBucket.sign = -1; } else { edgeBucket.sign = 1; } edgeBucket.dX = Mathf.Abs(dx); edgeBucket.dY = Mathf.Abs(dy); // hanya garis yang memiliki jarak y yang dimasukkan, // garis horizontal tidak perlu dimasukkan if (Mathf.Abs(edgeBucket.dY) > 0) { this.EdgeTable.Add(edgeBucket); } }
public void EdgeTableFill(Color?color, bool del = false) { EdgeTable activeEdgeTable = new EdgeTable(); List <Point> vertices = new List <Point>(); for (int i = 0; i < Vertices.Count - 1; i++) { vertices.Add(Vertices[i]); } List <int> indexList = Enumerable.Range(0, vertices.Count).OrderBy(x => vertices[x].Y).ToList(); int tmpIndex = 0; int beg = indexList[0]; int yMin = (int)vertices.Min(x => x.Y), yMax = (int)vertices.Max(x => x.Y); while (yMin < yMax) { if (vertices[beg].Y == yMin) { if (vertices[(beg + 1) % vertices.Count].Y > vertices[beg].Y) { activeEdgeTable.Buckets.Add(new EdgeBucket(vertices[beg], vertices[(beg + 1 + vertices.Count) % vertices.Count])); } if (vertices[(beg - 1 + vertices.Count) % vertices.Count].Y > vertices[beg].Y) { activeEdgeTable.Buckets.Add(new EdgeBucket(vertices[beg], vertices[(beg - 1 + vertices.Count) % vertices.Count])); } beg = indexList[++tmpIndex]; } activeEdgeTable.Buckets = activeEdgeTable.Buckets.OrderBy(x => x.XOfYMin).ToList(); for (int i = 0; i < activeEdgeTable.Buckets.Count - 1; i++) { EdgeBucket start = activeEdgeTable.Buckets[i], end = activeEdgeTable.Buckets[i + 1]; MainWindow.DrawLine((int)start.XOfYMin, yMin, (int)end.XOfYMin, yMin, 1, color == null ? ColorPoly : (Color)color, del); } yMin++; activeEdgeTable.RemoveElems(yMin); activeEdgeTable.Increment(); } IsFilled = true; FillColor = (Color)color; }
public void ProcessEdgeTable() { if (EdgeTable.Count <= 0) { return; } // menyusun edge table berdasarkan nilai yMin EdgeTable.Sort((a, b) => a.yMin.CompareTo(b.yMin)); int y = EdgeTable[0].yMin; // mendapatkan posisi minimum dan maksimum semua edge // untuk menentukan batas scan int minX = int.MaxValue; int maxX = int.MinValue; int minY = int.MaxValue; int maxY = int.MinValue; for (int itET = 0; itET < EdgeTable.Count; itET++) { EdgeBucket bucket = EdgeTable[itET]; if (bucket.xMin <= minX) { minX = bucket.xMin; } if (bucket.xMax <= minX) { minX = bucket.xMax; } if (bucket.xMax >= maxX) { maxX = bucket.xMax; } if (bucket.xMin >= maxX) { maxX = bucket.xMin; } // mencari batas y if (bucket.yMin <= minY) { minY = bucket.yMin; } if (bucket.yMax <= minY) { minY = bucket.yMax; } if (bucket.yMax >= maxY) { maxY = bucket.yMax; } if (bucket.yMin >= maxY) { maxY = bucket.yMin; } } // proses scan while (EdgeTable.Count > 0) { // masukkan edge ke active list jika posisi yMin == y for (int itET = 0; itET < EdgeTable.Count; itET++) { EdgeBucket currentBucket = EdgeTable[itET]; if (currentBucket.yMin == y && currentBucket.dY != 0) { ActiveList.Add(currentBucket); } } // sort edges di Active List berdasarkan nilai x ActiveList.Sort((a, b) => a.xMin.CompareTo(b.xMin)); // update active list x for (int itAL = 0; itAL < ActiveList.Count; itAL++) { EdgeBucket currentBucket = ActiveList[itAL]; // ubah nilai x berdasarkan gradiennya if (currentBucket.dX != 0) { float calcX = (float)(y - currentBucket.yMin) / (currentBucket.dY / currentBucket.dX); currentBucket.sum = (int)(currentBucket.xMin + currentBucket.sign * calcX); } } // isi scanline di antara pasangan edges dalam Active List List <Vector2Int> edgePair = new List <Vector2Int>(); for (int x = minX; x <= maxX; x++) { for (int i = 0; i < ActiveList.Count; i++) { EdgeBucket activeBucket = ActiveList[i]; if (activeBucket.sum == x) { // masukkan posisi titik perpotongan scanline edgePair.Add(new Vector2Int(x, y)); } if (edgePair.Count >= 2) { var pair1 = edgePair[0]; var pair2 = edgePair[1]; for (int itPair = pair1.x; itPair <= pair2.x; itPair++) { Color previousColor = targetTex.GetPixel(itPair, y); // warnai kolom di antara dua garis potong Color color = gradient.Evaluate(Mathf.InverseLerp(minY, maxY, y)); color = color + previousColor * (1f - color.a); targetTex.SetPixel(itPair, y, color); } edgePair.Clear(); } } } // lakukan proses ke baris selanjutnya y++; // hilangkan dari list jika sudah menyentuh titik ujung paling atas for (int itAL = ActiveList.Count - 1; itAL >= 0; itAL--) { EdgeBucket activeEdge = ActiveList[itAL]; if (y == activeEdge.yMax) { EdgeTable.Remove(activeEdge); ActiveList.Remove(activeEdge); } } } }
public int[][] ConvexFill(int[][] points) { // edge table EdgeTable et = new EdgeTable(); int topx1 = -1, topx2 = -1, topy = -1; for (int pIndex = 0, len = points.GetLength(0); pIndex < len; pIndex++) { int[] p1 = points[pIndex]; int[] p2 = points[pIndex + 1 >= len ? 0 : pIndex + 1]; if (p1[1] != p2[1]) { int yMin = 0; EdgeNode node = new EdgeNode(); if (p1[1] > p2[1]) { yMin = p2[1]; node.yMax = p1[1]; node.xMin = p2[0]; } else { yMin = p1[1]; node.yMax = p2[1]; node.xMin = p1[0]; } node.m = (float)(p1[0] - p2[0]) / (p1[1] - p2[1]); et.AddNode(yMin, node); } else { // 记录top horizontal edge // 这种简单判断topEdge的方式只对Convex有效 if (p1[1] > topy) { topy = p1[1]; if (p1[0] > p2[0]) { topx1 = p2[0]; topx2 = p1[0]; } else { topx1 = p1[0]; topx2 = p2[0]; } } if (pIndex == len - 1 && topy < points[1][1]) { topy = -1; } } } // active edge table EdgeBucket aet = new EdgeBucket(); if (et.Count == 0) { return(null); } else { // loop Queue <int[]> result = new Queue <int[]>(); while (et.Count > 0 || aet.Count > 0) { if (aet.Count == 0) { aet.yMin = et[0].yMin; et[0].ForEach((EdgeNode each) => aet.AddNode(each)); et.RemoveAt(0); } else { if (et.Count > 0 && aet.yMin == et[0].yMin) { et[0].ForEach((EdgeNode each) => aet.AddNode(each)); et.RemoveAt(0); } } for (int aIndex = aet.Count - 1; aIndex >= 0; aIndex--) { if (aet[aIndex].yMax <= aet.yMin) { aet.RemoveAt(aIndex); } } for (int aIndex = 0; aIndex < aet.Count; aIndex++) { if (aIndex % 2 == 0 && aIndex < aet.Count - 1) { float left = aet[aIndex].xMin; float right = aet[aIndex + 1].xMin; if (topy == -1 || aet.yMin != topy || left >= topx2 || right <= topx1) { // 以上判断是为了排除top horizontal edge int ileft = MathS.Floor(left); int iright = MathS.Floor(right); for (int ixMin = ileft; ixMin <= iright; ixMin += 1) { if (ixMin >= left && ixMin < right) { // 以上判断是为了排除像素点刚好在rightEdge的情况 result.Enqueue(new int[] { ixMin, aet.yMin }); } } } aet[aIndex].xMin += aet[aIndex].m; aet[aIndex + 1].xMin += aet[aIndex + 1].m; if (aet[aIndex].xMin > aet[aIndex + 1].xMin) { EdgeNode temp = aet[aIndex]; aet[aIndex] = aet[aIndex + 1]; aet[aIndex + 1] = temp; } } } aet.yMin += 1; } return(result.ToArray()); } }