func WrapMesh(m *gomesh.Mesh) *Mesh { m.ReindexVerticesAndFaces() // also wrap vertices; i.e. replaces mesh.Vertex with shapeset.vertex for i := 0; i < m.Vertices.Len(); i++ { if v, ok := m.Vertices.Get(i)[0].(*gomesh.Vertex); ok { m.Vertices.Update(i, &Vertex{Vertex: *v}) } } // also wrap faces and update them to reference outer vertex object for i := 0; i < m.Faces.Len(); i++ { if fx, ok := m.Faces.Get(i)[0].(*gomesh.Face); ok { f := &Face{Face: *fx} f.SetA(m.Vertices.Get(f.GetA().GetLocationInMesh(m))[0]) f.SetB(m.Vertices.Get(f.GetB().GetLocationInMesh(m))[0]) f.SetC(m.Vertices.Get(f.GetC().GetLocationInMesh(m))[0]) m.Faces.Update(i, f) f.GetA().AddFace(f) f.GetB().AddFace(f) f.GetC().AddFace(f) } } // iterate faces, build set of edges vert_pairs := make(map[gomesh.VertexPair]*Edge) m.Faces.EachWithIndex(func(i int, f gomesh.FaceI) { pairs := [3]gomesh.VertexPair{ gomesh.MakeVertexPair(f.GetA(), f.GetB()), gomesh.MakeVertexPair(f.GetB(), f.GetC()), gomesh.MakeVertexPair(f.GetC(), f.GetA()), } for i, pair := range pairs { var e *Edge if e1, exists := vert_pairs[pair]; !exists { e = &Edge{VertexPair: pair} e.V1.(*Vertex).AddEdge(e) e.V2.(*Vertex).AddEdge(e) vert_pairs[pair] = e } else { e = e1 } e.AddFace(f.(*Face)) f.(*Face).Edges[i] = e } }) return &Mesh{ Mesh: *m, Borders: make(map[BorderId]*Border), BoundingBox: m.BoundingBox(), } }
/* Create a new shapeset from a json labels file and a directory of meshes. */ func CreateNew(meshes_dir, labels_path string) (ss *ShapeSet, err error) { // Ensure meshes_dir ends with a slash if meshes_dir[len(meshes_dir)-1] != 47 { meshes_dir += "/" } // Attempt to read given paths var label_data []byte label_data, err = ioutil.ReadFile(labels_path) if err != nil { return } var files []os.FileInfo files, err = ioutil.ReadDir(meshes_dir) if err != nil { return } // Load labels from json file labels := make(map[string]string, 0) var labels_temp interface{} json.Unmarshal(label_data, &labels_temp) for key, val := range labels_temp.(map[string]interface{}) { labels[key] = val.(string) } // Load all meshes with the expected filename pattern (.obj) from the // directory at meshes path. meshes := make([]*Mesh, 0) for _, f := range files { r, _ := regexp.Compile(`^(\d+-\d+).obj$`) if r.MatchString(f.Name()) == true { mesh_file_path := meshes_dir + f.Name() var m *gomesh.Mesh m, err = gomesh.ReadOBJFile(mesh_file_path) if err != nil { return } m.Name = string(r.FindSubmatch([]byte(f.Name()))[1]) meshes = append(meshes, WrapMesh(m)) } } // Compose shapeset ss = New("New ShapeSet", labels, meshes) return }
// Quadric Edge Collapse Decimation // threshold: is the maximum length edge that will be contracted // target_face_count: is interpreted based on the assumption that every // collapsed edge removes two faces. // safer_mode: if true then at most one edge associated with each vertex will be // collapsed, this seems to reduce artifacts for equivalent performance, though // less can be achieved per invokation. func QECD(m *mesh.Mesh, threshold float64, target_face_count int, safer_mode bool) { vertices := make([]*vertex, 0) faces := make([]*face, 0) edges := &edgeHeap{} // build up vertices m.Vertices.Each(func(x, y, z float64) { vertices = append(vertices, &vertex{ Coords: [3]float64{x, y, z}, Faces: make([]*face, 0), Q: &Quadric{}, Edges: make([]*edge, 0), }) }) // Build up faces and update verts // iterate through faces and collect non-border edges // by counting the occurances of every edge, and keeping those with a count of 2 edge_occurances := make(map[[2]int][]*face) m.Faces.Each(func(a, b, c int) { new_face := &face{ Vertices: [3]*vertex{vertices[a], vertices[b], vertices[c]}, } faces = append(faces, new_face) new_face.calculateKp() vertices[a].Faces = append(vertices[a].Faces, new_face) vertices[a].Q.Add(new_face.Kp) vertices[b].Faces = append(vertices[b].Faces, new_face) vertices[b].Q.Add(new_face.Kp) vertices[c].Faces = append(vertices[c].Faces, new_face) vertices[c].Q.Add(new_face.Kp) var edge_description [2]int if a < b { edge_description = [2]int{a, b} } else { edge_description = [2]int{b, a} } edge_occurances[edge_description] = append( edge_occurances[edge_description], new_face, ) if a < c { edge_description = [2]int{a, c} } else { edge_description = [2]int{c, a} } edge_occurances[edge_description] = append( edge_occurances[edge_description], new_face, ) if c < b { edge_description = [2]int{c, b} } else { edge_description = [2]int{b, c} } edge_occurances[edge_description] = append( edge_occurances[edge_description], new_face, ) }) // First iterate through edge_occurances to identify border vertices boundary_vertices := make(map[int]bool) for e, occurances := range edge_occurances { if len(occurances) == 1 { boundary_vertices[e[0]] = true boundary_vertices[e[1]] = true } } // Iterate through edge_occurances again and build up edges for e, occurances := range edge_occurances { // Skip if edge doesn't occur in two faces (boundary or non-manifold) if len(occurances) == 2 { // Skip edge if one of the vertices is on a mesh boundary _, is_boundary1 := boundary_vertices[e[0]] _, is_boundary2 := boundary_vertices[e[1]] if !is_boundary1 && !is_boundary2 { new_edge := &edge{ V1: vertices[e[0]], V2: vertices[e[1]], Faces: occurances, Removed: false, } for _, occurance := range occurances { occurance.Edges = append(occurance.Edges, new_edge) } new_edge.calculateError() vertices[e[0]].Edges = append(vertices[e[0]].Edges, new_edge) vertices[e[1]].Edges = append(vertices[e[1]].Edges, new_edge) edges.Push(new_edge) } } } // Sort edges by error heap.Init(edges) // Iteratively Collapse the lowest error edges, resorting after each collapse // just arbitrarily half the original number of edges for starters edges_collapse_target := (len(faces) - target_face_count) / 2 for len(*edges) > 0 && edges_collapse_target > 0 { lowest_cost_edge := heap.Pop(edges).(*edge) did_collapse := lowest_cost_edge.collapse(threshold) if did_collapse { edges_collapse_target-- } edges.UpdateEdges(lowest_cost_edge.V1.Edges) } // // Update the mesh with the changes made to vertices and faces // m.Vertices = tb.NewVertexBuffer() m.Norms = tb.NewVectorBuffer() m.Faces = tb.NewTriangleBuffer() i := 0 for _, v := range vertices { if !v.Collapsed { v.FinalIndex = i m.Vertices.Buffer = append(m.Vertices.Buffer, v.Coords[:]...) i++ } } for _, f := range faces { if !(f.Collapsed || f.Vertices[0].Collapsed || f.Vertices[1].Collapsed || f.Vertices[2].Collapsed) { a := f.Vertices[0].FinalIndex b := f.Vertices[1].FinalIndex c := f.Vertices[2].FinalIndex m.Faces.Buffer = append(m.Faces.Buffer, a, b, c) } } }