private int[] BuildCollapseIndex(List <EdgeRecord> collapseRec) { int vn = mesh.VertexCount; int[] collapseIndex = new int[vn]; for (int i = 0; i < vn; i++) { collapseIndex[i] = -1; } for (int i = collapseRec.Count - 1; i >= 0; i--) { EdgeRecord rec = collapseRec[i]; int s = rec.vIndex; int t = rec.minIndex; if (collapseIndex[t] == -1) { collapseIndex[s] = t; } else { collapseIndex[s] = collapseIndex[t]; } } return(collapseIndex); }
private void UpdateEdgeCollapseRecords(PriorityQueue queue, EdgeRecord[] edgeRec, int index) { Vector3d u = new Vector3d(mesh.VertexPos, index * 3); EdgeRecord uRec = edgeRec[index]; uRec.minError = double.MaxValue; foreach (int j in uRec.adjV) { int adjCount = 0; foreach (int k in edgeRec[j].adjV) { if (uRec.adjV.Contains(k)) { adjCount++; } } if (adjCount != 2) { continue; } Vector3d uv = u - new Vector3d(mesh.VertexPos, j * 3); double err = uRec.area * uv.Dot(uv); if (err < uRec.minError) { uRec.minError = err; uRec.minIndex = j; } } queue.Update(uRec); }
public override bool Equals(object obj) { if (obj is EdgeRecord) { EdgeRecord e = obj as EdgeRecord; return((this.p1 == e.p1 && this.p2 == e.p2) || (this.p1 == e.p2 && this.p2 == e.p1)); } return(false); }
public int CompareTo(object obj) { EdgeRecord rec = obj as EdgeRecord; if (minError < rec.minError) { return(-1); } if (minError > rec.minError) { return(1); } return(0); }
private EdgeRecord[] CreateEdgeCollapseRecords() { int vn = mesh.VertexCount; int fn = mesh.FaceCount; EdgeRecord[] rec = new EdgeRecord[vn]; for (int i = 0; i < vn; i++) { rec[i] = new EdgeRecord(i); } double[] K = new double[10]; for (int i = 0, j = 0; i < fn; i++, j += 3) { int c1 = mesh.FaceIndex[j]; int c2 = mesh.FaceIndex[j + 1]; int c3 = mesh.FaceIndex[j + 2]; Vector3d v1 = new Vector3d(mesh.VertexPos, c1 * 3); Vector3d v2 = new Vector3d(mesh.VertexPos, c2 * 3); Vector3d v3 = new Vector3d(mesh.VertexPos, c3 * 3); double faceArea = ((v2 - v1).Cross(v3 - v1)).Length() / 2.0; rec[c1].area += faceArea; rec[c2].area += faceArea; rec[c3].area += faceArea; } for (int i = 0, j = 0; i < vn; i++, j += 3) { Vector3d u = new Vector3d(mesh.VertexPos, j); EdgeRecord uRec = rec[i]; foreach (int k in mesh.AdjVV[i]) { Vector3d uv = u - new Vector3d(mesh.VertexPos, k * 3); double err = uRec.area * uv.Dot(uv); if (err < uRec.minError) { uRec.minError = err; uRec.minIndex = k; } uRec.adjV.Add(k); } } return(rec); }
public static void PaintPolygon(this Bitmap bitmap, Polygon polygon, Color color) { List <EdgeRecord>[] record = new List <EdgeRecord> [bitmap.y + 1]; for (int i = 0; i < polygon.length; i++) { Point p1 = polygon[i], p2 = polygon[(i + 1 >= polygon.length)?0:(i + 1)]; int y1 = (int)(Math.Ceiling(p1.y)); int y2 = (int)(Math.Ceiling(p2.y)); if (y1 < 0) { y1 = 0; } if (y2 < 0) { y2 = 0; } if (y1 > bitmap.y) { y2 = bitmap.y; } if (y2 > bitmap.y) { y2 = bitmap.y; } if (y1 == y2) { continue; } Point pBegin, pEnd; int yBegin, yEnd; if (y1 > y2) { pBegin = p2; pEnd = p1; yBegin = y2; yEnd = y1; } else { pBegin = p1; pEnd = p2; yBegin = y1; yEnd = y2; } float dx = (pEnd.x - pBegin.x) / (pEnd.y - pBegin.y); float x = (yBegin - pBegin.y) * dx + pBegin.x; if (record[yBegin] == null) { record[yBegin] = new List <EdgeRecord>(); } record[yBegin].Add(new EdgeRecord { x = x, dx = dx, ymax = yEnd }); } List <EdgeRecord> intersect = new List <EdgeRecord>(); for (int line = 0; line < bitmap.y; line++) { if (record[line] != null) { intersect.AddRange(record[line]); } intersect.RemoveAll((edge) => edge.ymax <= line); intersect.Sort((edge1, edge2) => Comparer <float> .Default.Compare(edge1.x, edge2.x)); if (intersect.Count % 2 != 0) { throw new Exception("Odd edges!"); } for (int i = 0; i < intersect.Count / 2; i++) { float left = intersect[2 * i].x; float right = intersect[2 * i + 1].x; int lPoint = (int)(Math.Ceiling(left)); int rPoint = (int)(Math.Floor(right)); if (lPoint < 0) { lPoint = 0; } if (rPoint < 0) { lPoint = 0; } if (lPoint > bitmap.x) { lPoint = bitmap.x; } if (rPoint > bitmap.x) { lPoint = bitmap.x; } for (int point = lPoint; point <= rPoint; point++) { bitmap[point, line] = color; } } for (int i = 0; i < intersect.Count; i++) { intersect[i] = new EdgeRecord { x = intersect[i].x + intersect[i].dx, dx = intersect[i].dx, ymax = intersect[i].ymax }; } } }
private void MainLoop() { int count = 0; while (faceQueue.Count > 0) { count++; HullFace face = faceQueue.Dequeue(); if (face.active == false) { continue; } if (face.furthestIndex != -1) { int p0 = face.furthestIndex; this.hullVertices.Add(p0); // collect visible faces, boundary edges and assoicated vertices List <HullFace> holeFace = new List <HullFace>(); HashSet <EdgeRecord> holeBoundary = new HashSet <EdgeRecord>(); HashSet <int> assoicatedVertex = new HashSet <int>(); foreach (HullFace f in this.surfaceSet) { Vector3d v = this.p[p0] - this.p[f.p1]; if (v.Dot(f.normal) > 0) { holeFace.Add(f); int p1 = f.p1; int p2 = f.p2; int p3 = f.p3; EdgeRecord r1 = new EdgeRecord(p1, p2); EdgeRecord r2 = new EdgeRecord(p2, p3); EdgeRecord r3 = new EdgeRecord(p3, p1); if (holeBoundary.Contains(r1)) { holeBoundary.Remove(r1); } else { holeBoundary.Add(r1); } if (holeBoundary.Contains(r2)) { holeBoundary.Remove(r2); } else { holeBoundary.Add(r2); } if (holeBoundary.Contains(r3)) { holeBoundary.Remove(r3); } else { holeBoundary.Add(r3); } foreach (int index in f.associatedPoints) { assoicatedVertex.Add(index); } } } if (holeFace.Count == 0) { throw new Exception(); } // remove add visible faces foreach (HullFace f in holeFace) { this.surfaceSet.Remove(f); f.active = false; } // add new faces foreach (EdgeRecord edge in holeBoundary) { HullFace newFace = new HullFace(p0, edge.p1, edge.p2); newFace.normal = ((p[edge.p1] - p[p0]).Cross(p[edge.p2] - p[p0])).normalize(); this.surfaceSet.Add(newFace); this.faceQueue.Enqueue(newFace); // add assoicated vertices foreach (int index in assoicatedVertex) { if (index == p0) { continue; } double dis = (p[index] - p[p0]).Dot(newFace.normal); if (dis > 0) { newFace.AddPoint(index, dis); } } } } } computeCenter(); }
private void Simplify() { Program.PrintText("Simplification"); int vn = mesh.VertexCount; // if (vn <= targetVertices) return; int nextLevel = (int)(vn * simplificationRatio); if (nextLevel < targetVertices) { nextLevel = targetVertices; } // copy connectivity // VertexRecord[] vRec = new VertexRecord[vn]; EdgeRecord[] edgeRec = CreateEdgeCollapseRecords(); List <EdgeRecord> collapseRec = new List <EdgeRecord>(); bool[] collapsed = new bool[vn]; PriorityQueue queue = new PriorityQueue(vn); for (int i = 0; i < vn; i++) { queue.Insert(edgeRec[i]); collapsed[i] = false; } { Program.PrintText("output mesh level: " + vn); List <VertexRecord> vRecList = new List <VertexRecord>(); for (int j = 0; j < vn; j++) { if (collapsed[j]) { continue; } VertexRecord r = new VertexRecord(j); foreach (int adj in edgeRec[j].adjV) { r.adjV.Add(adj); } vRecList.Add(r); } simplifiedMeshes.Add(vRecList); collapseRec.Reverse(); collapsedRecords.Add(collapseRec); faceRecords.Add((int[])mesh.FaceIndex.Clone()); collapseRec = new List <EdgeRecord>(); } int count = vn; for (int i = 0; i < vn - targetVertices; i++) { EdgeRecord rec1 = (EdgeRecord)queue.DeleteMin(); EdgeRecord rec2 = edgeRec[rec1.minIndex]; rec2.area += rec1.area; collapseRec.Add(rec1); collapsed[rec1.vIndex] = true; count--; foreach (int j in rec1.adjV) { edgeRec[j].adjV.Remove(rec1.vIndex); if (j != rec2.vIndex) { edgeRec[j].adjV.Add(rec2.vIndex); edgeRec[rec2.vIndex].adjV.Add(j); } } foreach (int j in rec2.adjV) { UpdateEdgeCollapseRecords(queue, edgeRec, j); } UpdateEdgeCollapseRecords(queue, edgeRec, rec2.vIndex); if (count == nextLevel) { Program.PrintText("output mesh level: " + count); List <VertexRecord> vRecList = new List <VertexRecord>(); for (int j = 0; j < vn; j++) { if (collapsed[j]) { continue; } VertexRecord r = new VertexRecord(j); foreach (int adj in edgeRec[j].adjV) { r.adjV.Add(adj); } vRecList.Add(r); } simplifiedMeshes.Add(vRecList); int[] fr = BuildCollapsedFaceIndex(faceRecords[faceRecords.Count - 1], collapseRec); faceRecords.Add(fr); collapseRec.Reverse(); collapsedRecords.Add(collapseRec); collapseRec = new List <EdgeRecord>(); nextLevel = (int)(nextLevel * simplificationRatio); if (nextLevel < targetVertices) { nextLevel = targetVertices; } } } simplifiedMeshes.Reverse(); collapsedRecords.Reverse(); faceRecords.Reverse(); }