コード例 #1
0
ファイル: borders_index.go プロジェクト: nat-n/shapeset
func (ss *ShapeSet) IndexBorders() (err error) {
	// Clear existing borders
	ss.ResetBorders()

	// Compose a map with the boundaries with bounding boxes for each mesh
	var wg sync.WaitGroup
	new_boundaries := make(chan *boundarySet, 16)
	for _, m := range ss.Meshes {
		wg.Add(1)
		go func(mesh1 *Mesh) {
			// Ensure vertices and faces know their places
			mesh1.ReindexVerticesAndFaces()

			m_boundaries, err := mesh1.IdentifyBoundaries()
			if err != nil {
				return
			}
			mesh1_boundaries := make([]*boundaryDetails, len(m_boundaries))
			for i, boundary := range m_boundaries {
				wrapped_boundary := make([]gomesh.VertexI, len(boundary))
				for j, bv := range boundary {
					wrapped_boundary[j] = bv
				}
				mesh1_boundaries[i] = &boundaryDetails{
					wrapped_boundary,
					*mesh1.SubsetBoundingBox(boundary),
				}
			}
			new_boundaries <- &boundarySet{mesh1_boundaries, MeshIdFromString(mesh1.Name)}
		}(m)
	}

	// Recieve new_boundaries until they're all done
	go func() {
		wg.Wait()
		close(new_boundaries)
	}()
	boundaries := make(map[MeshId][]*boundaryDetails)
	for new_boundary_set := range new_boundaries {
		boundaries[new_boundary_set.MeshId] = new_boundary_set.Boundaries
		wg.Done()
	}

	// The following block compares all borders to build up the vertexOccurances
	//  map of a location onto a number of vertices from different meshes
	vertexOccurances := make(map[geom.Vec3][]gomesh.VertexI)
	new_vertex_occurances := make(chan map[geom.Vec3][]gomesh.VertexI, 16)
	for mesh_id1, m1 := range ss.Meshes {
		for mesh_id2, m2 := range ss.Meshes {
			if mesh_id2.LessThan(mesh_id1) ||
				!m1.BoundingBox.Expanded(0.01).Intersects(
					m2.BoundingBox.Expanded(0.01)) {
				// Make sure we only deal with each pair of meshes once,
				//  and ignore pairs of meshes whose bounding boxes dont intersect
				continue
			}
			wg.Add(1)
			go func(mesh_id1, mesh_id2 MeshId, boundaries1, boundaries2 []*boundaryDetails) {
				newVertexOccurances := make(map[geom.Vec3][]gomesh.VertexI)
				for _, boundary1 := range boundaries1 {
					for _, boundary2 := range boundaries2 {
						if !boundary1.BoundingBox.Expanded(0.01).Intersects(
							boundary2.BoundingBox.Expanded(0.01)) {
							continue
						}
						// Identify any matching vertices between boundary1 and boundary2
						// by using a sort wrapper to order the verts so that potentially
						// colocated vertices occur consequtively.
						verts := make([]gomesh.VertexI, 0)

						// Loop over the vertices in both borders to fill in verts
						for _, vert := range boundary1.Verts {
							verts = append(verts, vert)
						}
						for _, vert := range boundary2.Verts {
							verts = append(verts, vert)
						}

						// Sort verts so that any border vertex from m2 that is potentially
						// collocated with a border vertex from m1 follows it directly in
						// the array.
						sort.Sort(gomesh.VerticesByPosition{verts})

						// iterate over the sorted verts and identify pairs of verts from
						// different meshes at the same location
						prev_vert := verts[0]
						for _, vert := range verts[1:] {
							// This assumes that these vertices both appear in only one mesh already!!
							// ... which will be true in the main use case.
							cm, _ := vert.GetMeshLocation()
							pm, _ := prev_vert.GetMeshLocation()
							if pm != cm &&
								prev_vert.GetX() == vert.GetX() &&
								prev_vert.GetY() == vert.GetY() &&
								prev_vert.GetZ() == vert.GetZ() {
								// Found a matching vertex `vert`, which is shared between
								//  boundary1 and boundary2.
								// Record the mesh and index of both occurances of a vertex at
								//  this location.
								vec := geom.Vec3{vert.GetX(), vert.GetY(), vert.GetZ()}
								newVertexOccurances[vec] = append(
									newVertexOccurances[vec],
									prev_vert,
									vert,
								)
							}
							prev_vert = vert
						}
					}
				}

				// Send newly discovered vertex occurances to the reciever to be added
				// into the VertexOccurances map.
				new_vertex_occurances <- newVertexOccurances

			}(mesh_id1, mesh_id2, boundaries[mesh_id1], boundaries[mesh_id2])
		}
	}

	// Recieve new_boundaries until they're all done
	go func() {
		wg.Wait()
		close(new_vertex_occurances)
	}()
	for recieved_vertex_occurances := range new_vertex_occurances {
		// this channel recieves once for each overlapping pair of boundaries
		for vec, occurances := range recieved_vertex_occurances {
			vertexOccurances[vec] = append(vertexOccurances[vec], occurances...)
		}
		wg.Done()
	}

	// Finally, unpack vertexOccurances to populate ss.BordersIndex and the
	//  Borders object of each MeshWrapper.
	new_mesh_border_verts := make(chan map[MeshId]map[BorderDescription][]gomesh.VertexI, 16)
	for _, occurances := range vertexOccurances {
		wg.Add(1)
		go func(occurances []gomesh.VertexI) {
			border_participants := make([]MeshId, 0)
			mesh_border_verts := make(map[MeshId]map[BorderDescription][]gomesh.VertexI)

			// uniqueify occurances of this vertex by mesh
			sort.Sort(gomesh.VerticesByMesh{occurances})
			unique_occurances := make([]gomesh.VertexI, 0, len(occurances))
			var found bool
			for _, occurance := range occurances {
				found = false
				for _, uo := range unique_occurances {
					uo_m, _ := uo.GetMeshLocation()
					occurance_m, _ := occurance.GetMeshLocation()
					if occurance_m == uo_m {
						found = true
						break
					}
				}
				if !found {
					unique_occurances = append(unique_occurances, occurance)
				}
			}

			// Derive the canonical description for the border this vertex belongs to
			for _, occurance := range unique_occurances {
				occurance_m, _ := occurance.GetMeshLocation()
				border_participants = append(border_participants,
					MeshIdFromString(occurance_m.GetName()))
			}
			sort.Sort(ByMeshIdPrecedence(border_participants))
			border_desc := BorderDescriptionFromMeshIds(border_participants)

			// Register this vertex as being the next item in the determined border
			//  for each of the participating meshes.
			for _, vert := range unique_occurances {
				occurance_m, _ := vert.GetMeshLocation()
				occurance_mid := MeshIdFromString(occurance_m.GetName())
				if _, exists := mesh_border_verts[occurance_mid]; !exists {
					mesh_border_verts[occurance_mid] = make(map[BorderDescription][]gomesh.VertexI)
				}
				mesh_border_verts[occurance_mid][border_desc] = append(
					mesh_border_verts[occurance_mid][border_desc],
					vert,
				)
			}

			new_mesh_border_verts <- mesh_border_verts
		}(occurances)
	}

	// Recieve new_mesh_border_verts until they're all done
	go func() {
		wg.Wait()
		close(new_mesh_border_verts)
	}()

	// A slice of all border descriptions as strings for the sake of sorting
	border_desc_strings := make([]string, 0)
	encountered_border_descs := make(map[BorderDescription]map[MeshId][]gomesh.VertexI)

	for recieved_mesh_border_verts := range new_mesh_border_verts {
		for mesh_id, border_verts := range recieved_mesh_border_verts {
			for border_desc, verts := range border_verts {
				// Lookup/Create am int-string border id for a border of this description
				_, border_seen := encountered_border_descs[border_desc]
				if !border_seen {
					border_desc_strings = append(border_desc_strings, border_desc.ToString())
					encountered_border_descs[border_desc] = make(map[MeshId][]gomesh.VertexI)
				}
				encountered_border_descs[border_desc][mesh_id] = append(
					encountered_border_descs[border_desc][mesh_id],
					verts...,
				)
			}
		}
		wg.Done()
	}

	// Create borders in string sorted order
	sort.Strings(border_desc_strings)
	for _, border_desc_str := range border_desc_strings {
		ss.BordersIndex.NewBorder(BorderDescriptionFromString(border_desc_str))
	}

	for border_desc, bmap := range encountered_border_descs {
		border := ss.BordersIndex.BorderFor(border_desc)

		// single out border vertices of first mesh to be the border vertices
		var first_mesh_verts []gomesh.VertexI
		for first_mesh_id, border_verts := range bmap {
			first_mesh_verts = border_verts
			delete(bmap, first_mesh_id)
			break
		}
		for _, v1I := range first_mesh_verts {
			v1 := v1I.(*Vertex)
			v1.Border = border
			border.Vertices = append(border.Vertices, v1)
		}

		// merge border vertices from other meshes into those of the first mesh
		for _, border_verts := range bmap {
			for vi, v1I := range first_mesh_verts {
				v2I := border_verts[vi]
				v1 := v1I.(*Vertex)
				v2 := v2I.(*Vertex)
				// move v2.Faces over to v1.Faces
				err := gomesh.MergeSharedVertices(v1I, v2I)
				if err != nil {
					panic(err)
				}
				// move v2.Edges over to v1.Edges
				for _, e := range v2.Edges {
					e.ReplaceVertex(v2, v1)
					v1.AddEdge(e)
				}
				v2.Edges = v2.Edges[:0]
				v2_mesh, v2_i := v2.GetMeshLocation()
				v2_mesh.GetVertices().Update(v2_i, v1I)
				v1.SetLocationInMesh(&v2_mesh, v2_i)
			}
		}
	}

	// Now that border vertices are registered, infer border edges
	ss.BordersIndex.indexBorderEdges()

	return
}
コード例 #2
0
ファイル: io.go プロジェクト: nat-n/shapeset
func Load(ss_reader *io.Reader) (ss *ShapeSet, err error) {
	// Parse json from reader and load with temporary types
	parsed_data := new(shapeSetParseSchema)
	err = json.NewDecoder(*ss_reader).Decode(parsed_data)
	if err != nil {
		err = errors.New("Could not parse json from ss_reader")
		return
	}

	// for building up partial border info from meshes
	border_tracker := make(map[BorderId]map[MeshId][]*Vertex)

	meshesBuffer := make([]*Mesh, 0)
	for _, mesh_data := range parsed_data.Meshes {
		var verts, norms []float64
		var faces []int
		mesh_name := mesh_data.Name
		m := NewMesh(mesh_name)

		// load vertices from parsed data
		verts, err = parseCSFloats(mesh_data.Verts)
		vertexBuffer := make([]gomesh.VertexI, 0, len(verts)/3)
		if err != nil {
			err = errors.New("Could not parse vertices for: " + mesh_name)
			return
		}
		for i := 0; i < len(verts); i += 3 {
			vertexBuffer = append(vertexBuffer, &Vertex{Vertex: gomesh.Vertex{
				Vec3:   geom.Vec3{verts[i], verts[i+1], verts[i+2]},
				Meshes: make(map[gomesh.Mesh]int),
			}})
		}

		// Vertex normals are optional
		if len(mesh_data.Norms) > 0 {
			norms, err = parseCSFloats(mesh_data.Norms)
			if err != nil {
				err = errors.New("Could not parse normals for: " + mesh_name)
				return
			}
			if len(norms) != 0 && len(norms) != len(verts) {
				err = errors.New("Malformed Mesh (vertices/normals mismatch): " + mesh_name)
				return
			}
			for i := 0; i < len(norms); i += 3 {
				vertexBuffer[i/3].SetNormal(&geom.Vec3{norms[i], norms[i+1], norms[i+2]})
			}
		}

		edges := make(map[gomesh.VertexPair]*Edge)

		// load faces from parsed data
		faces, err = parseCSInts(mesh_data.Faces)
		faceBuffer := make([]gomesh.FaceI, 0, len(faces)/3)
		if err != nil {
			err = errors.New("Could not parse faces for: " + mesh_name)
			return
		}
		for i := 0; i < len(faces); i += 3 {
			// create new face from vertex triple
			vA := vertexBuffer[faces[i]]
			vB := vertexBuffer[faces[i+1]]
			vC := vertexBuffer[faces[i+2]]
			new_face := &Face{Face: gomesh.Face{Vertices: [3]gomesh.VertexI{vA, vB, vC}}}

			// reference face from vertices
			vA.AddFace(new_face)
			vB.AddFace(new_face)
			vC.AddFace(new_face)
			faceBuffer = append(faceBuffer, new_face)

			// find/create edges of new_face
			e0 := gomesh.MakeVertexPair(vA, vB)
			e1 := gomesh.MakeVertexPair(vB, vC)
			e2 := gomesh.MakeVertexPair(vC, vA)
			newPairs := [3]gomesh.VertexPair{e0, e1, e2}
			for i, vp := range newPairs {
				var f_edge *Edge
				if e, exists := edges[vp]; exists {
					f_edge = e
				} else {
					f_edge = &Edge{VertexPair: vp}
					f_edge.Vertex1().AddEdge(f_edge)
					f_edge.Vertex2().AddEdge(f_edge)
					edges[vp] = f_edge
				}
				f_edge.AddFace(new_face)
				new_face.Edges[i] = f_edge
			}
		}

		for border_id, border_indices := range mesh_data.Borders {
			var vert_indices []int
			vert_indices, err = parseCSInts(border_indices)
			if err != nil {
				err = errors.New(
					"Could not parse border for mesh " + m.GetName() +
						" indices for border " + border_id + ", in mesh " + mesh_name)
				return
			}

			bverts := make([]*Vertex, 0)
			for _, vi := range vert_indices {
				bverts = append(bverts, vertexBuffer[vi].(*Vertex))
			}
			bid, err := BorderIdFromString(border_id)
			if err != nil {
				panic(err.Error())
			}
			mid := MeshIdFromString(mesh_name)
			if _, exists := border_tracker[bid]; !exists {
				border_tracker[bid] = make(map[MeshId][]*Vertex)
			}
			border_tracker[bid][mid] = bverts
		}

		m.Vertices.Append(vertexBuffer...)
		m.Faces.Append(faceBuffer...)
		m.ReindexVerticesAndFaces()
		m.BoundingBox = m.Mesh.BoundingBox()
		meshesBuffer = append(meshesBuffer, m)
	}

	// Create ShapeSet
	ss = New(parsed_data.Name, parsed_data.Shapes, meshesBuffer)

	// merge border vertices
	for border_id, mesh_borders := range border_tracker {
		mesh_ids := ByMeshIdPrecedence{}
		for mesh_id, _ := range mesh_borders {
			mesh_ids = append(mesh_ids, mesh_id)
		}
		sort.Sort(mesh_ids)

		first_mesh_vertices := mesh_borders[mesh_ids[0]]
		for _, mesh_id := range mesh_ids[1:] {
			secondary_mesh_vertices := mesh_borders[mesh_id]
			for i := 0; i < len(first_mesh_vertices); i++ {
				gomesh.MergeSharedVertices(
					first_mesh_vertices[i],
					secondary_mesh_vertices[i])
			}
		}

		_, err = ss.BordersIndex.LoadBorder(
			border_id,
			[]MeshId(mesh_ids),
			first_mesh_vertices,
		)
		if err != nil {
			return
		}
	}

	ss.BordersIndex.indexBorderEdges()

	return
}