コード例 #1
0
ファイル: simplify.go プロジェクト: nat-n/gomesh
// 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)
		}
	}

}