void write_texture(std::ofstream& fout, const VectorF& uv) { assert(uv.size() % 2 == 0); const size_t num_uvs = uv.size() / 2; for (size_t i=0; i<num_uvs; i++) { fout << "vt " << uv[i*2] << " " << uv[i*2+1] << std::endl; } }
void InflatorEngine::with_abs_geometry_correction(const VectorF& correction) { if (correction.size() != m_wire_network->get_dim()) { std::stringstream err_msg; err_msg << "Absolute geometry offset dimension mismatch. Expect " << m_wire_network->get_dim() << " but get " << correction.size() << " instead."; throw RuntimeError(err_msg.str()); } m_abs_correction = correction; }
void WireNetwork::translate(const VectorF& offset) { if (offset.size() != m_dim) { std::stringstream err_msg; err_msg << "Offset is of dim (" << offset.size() << "), expecting (" << m_dim << ")"; throw RuntimeError(err_msg.str()); } const size_t num_vertices = get_num_vertices(); for (size_t i=0; i<num_vertices; i++) { m_vertices.row(i) += offset; } update_bbox(); }
VectorF convert_face_attribute_to_vertex_attribute( Mesh& mesh, const VectorF& attribute) { const size_t num_vertices = mesh.get_num_vertices(); const size_t vertex_per_face = mesh.get_vertex_per_face(); const size_t num_faces = mesh.get_num_faces(); const size_t attr_size = attribute.size(); const size_t stride = attr_size / num_faces; const VectorI& faces = mesh.get_faces(); const VectorF& weights = mesh.get_attribute("face_area"); VectorF result = VectorF::Zero(num_vertices * stride); VectorF result_weights = VectorF::Zero(num_vertices); for (size_t i=0; i<num_faces; i++) { const VectorI& face = faces.segment(i*vertex_per_face, vertex_per_face); Float per_vertex_weight = weights[i] / vertex_per_face; for (size_t j=0; j<vertex_per_face; j++) { result_weights[face[j]] += per_vertex_weight; result.segment(face[j]*stride, stride) += per_vertex_weight * attribute.segment(i*stride, stride); } } for (size_t i=0; i<num_vertices; i++) { result.segment(i*stride, stride) /= result_weights[i]; } return result; }
VectorF convert_voxel_attribute_to_vertex_attribute( Mesh& mesh, const VectorF& attribute) { const size_t num_vertices = mesh.get_num_vertices(); const size_t vertex_per_voxel = mesh.get_vertex_per_voxel(); const size_t num_voxels = mesh.get_num_voxels(); const size_t attr_size = attribute.size(); const size_t stride = attr_size / num_voxels; const VectorI& voxels = mesh.get_voxels(); if (!mesh.has_attribute("voxel_volume")) { mesh.add_attribute("voxel_volume"); } const VectorF& weights = mesh.get_attribute("voxel_volume"); VectorF result = VectorF::Zero(num_vertices * stride); VectorF result_weights = VectorF::Zero(num_vertices); for (size_t i=0; i<num_voxels; i++) { const VectorI& voxel = voxels.segment(i*vertex_per_voxel, vertex_per_voxel); Float per_vertex_weight = weights[i] / vertex_per_voxel; for (size_t j=0; j<vertex_per_voxel; j++) { result_weights[voxel[j]] += per_vertex_weight; result.segment(voxel[j]*stride, stride) += per_vertex_weight * attribute.segment(i*stride, stride); } } for (size_t i=0; i<num_vertices; i++) { result.segment(i*stride, stride) /= result_weights[i]; } return result; }
void OBJWriter::write_mesh(Mesh& mesh) { using namespace OBJWriterHelper; std::ofstream fout(m_filename.c_str()); if (!is_anonymous()) { fout << "# Generated with PyMesh" << std::endl; } VectorF texture; VectorI texture_indices; if (mesh.has_attribute("corner_texture")) { texture = mesh.get_attribute("corner_texture"); const size_t num_faces = mesh.get_num_faces(); const size_t vertex_per_face = mesh.get_vertex_per_face(); if (texture.size() != num_faces * vertex_per_face * 2) { // Texture invalid. texture.resize(0); } else { write_texture(fout, texture); texture_indices.resize(num_faces * vertex_per_face); for (size_t i=0; i<num_faces; i++) { for (size_t j=0; j<vertex_per_face; j++) { texture_indices[i*vertex_per_face+j] = i*vertex_per_face+j; } } } } write_vertices(fout, mesh.get_vertices(), mesh.get_dim()); write_faces(fout, mesh.get_faces(), mesh.get_vertex_per_face(), texture_indices); fout.close(); }
void WireNetwork::scale(const VectorF& factors) { if (factors.size() != m_dim) { std::stringstream err_msg; err_msg << "Scaling factors is of dim (" << factors.size() << "), expecting (" << m_dim << ")"; throw RuntimeError(err_msg.str()); } const size_t num_vertices = get_num_vertices(); for (size_t i=0; i<num_vertices; i++) { const VectorF& v = m_vertices.row(i); m_vertices.row(i) = v.cwiseProduct(factors); } update_bbox(); }
void VertexOffsetParameter::apply(VectorF& results, const PatternParameter::Variables& vars) { const VectorF bbox_min = m_wire_network->get_bbox_min(); const VectorF bbox_max = m_wire_network->get_bbox_max(); const VectorF center = 0.5 * (bbox_min + bbox_max); const VectorF half_bbox_size = bbox_max - center; const size_t dim = m_wire_network->get_dim(); const size_t num_vertices = m_wire_network->get_num_vertices(); const size_t roi_size = m_roi.size(); assert(m_axis < dim); assert(results.size() == dim * num_vertices); if (m_formula != "") evaluate_formula(vars); const MatrixFr& vertices = m_wire_network->get_vertices(); for (size_t i=0; i<roi_size; i++) { size_t v_idx = m_roi[i]; assert(v_idx < num_vertices); const VectorF& v = vertices.row(v_idx); assert(fabs(v[m_axis] - center[m_axis]) > 1e-12); Float sign = v[m_axis] - center[m_axis] > 0.0 ? 1.0 : -1.0; results[v_idx * dim + m_axis] = sign * half_bbox_size[m_axis] * m_value; } }
void VertexIsotropicOffsetParameter::apply(VectorF& results, const PatternParameter::Variables& vars) { const size_t dim = m_wire_network->get_dim(); const size_t num_vertices = m_wire_network->get_num_vertices(); const size_t roi_size = m_roi.size(); const VectorF center = m_wire_network->center(); const VectorF bbox_max = m_wire_network->get_bbox_max(); assert(results.size() == dim * num_vertices); assert(roi_size == m_transforms.size()); if (m_formula != "") evaluate_formula(vars); const MatrixFr& vertices = m_wire_network->get_vertices(); size_t seed_vertex_index = m_roi.minCoeff(); VectorF seed_vertex = vertices.row(seed_vertex_index); VectorF seed_offset = VectorF::Zero(dim); seed_offset = (bbox_max - center).cwiseProduct(m_dof_dir) * m_value; for (size_t i=0; i<roi_size; i++) { size_t v_idx = m_roi[i]; assert(v_idx < num_vertices); const MatrixF& trans = m_transforms[i]; results.segment(v_idx*dim, dim) += trans * seed_offset; } }
std::vector<VectorF> IsotropicDofExtractor::extract_dofs(const VectorF& v) { const size_t dim = m_wire_network->get_dim(); assert(v.size() == dim); if (dim == 3) { return extract_3D_dofs(v); } else if (dim == 2) { return extract_2D_dofs(v); } else { std::stringstream err_msg; err_msg << "Unsupported dim: " << dim; throw NotImplementedError(err_msg.str()); } }
void VertexMeanCurvatureAttribute::compute_from_mesh(Mesh& mesh) { const size_t dim = mesh.get_dim(); const size_t num_vertices = mesh.get_num_vertices(); VectorF laplacian = compute_laplacian_vectors(mesh); VectorF normals = compute_vertex_normals(mesh); assert(laplacian.size() == dim*num_vertices); assert(normals.size() == dim*num_vertices); if (!mesh.has_attribute("vertex_voronoi_area")) { mesh.add_attribute("vertex_voronoi_area"); } const auto& area = mesh.get_attribute("vertex_voronoi_area"); VectorF& mean_curvature = m_values; mean_curvature = VectorF::Zero(num_vertices); for (size_t i=0; i<num_vertices; i++) { mean_curvature[i] = laplacian.segment(dim*i,dim).norm() * 0.5; Float sign = laplacian.segment(dim*i, dim).dot(normals.segment(dim*i,dim)); if (sign < 0) { mean_curvature[i] *= -1; } } mean_curvature = mean_curvature.array() / area.array(); }
void Deform::set_soft_ctrs(const VectorF &T, const VectorI &idx_T) { assert(T.size()/3 == idx_T.size()); for (int i = 0, i_end = idx_T.size(); i < i_end; ++ i) { int cid = idx_T[i]; Eigen::Vector3f ctr; ctr << T[3*i], T[3*i+1], T[3*i+2]; soft_ctrs.push_back(Constraint(ctr, cid)); } std::sort(soft_ctrs.begin(), soft_ctrs.end(), ConstraintCompare()); }
void TilerEngine::normalize_unit_wire(const VectorF& cell_size) { if (cell_size.minCoeff() <= 1e-30) { const size_t dim = cell_size.size(); if (dim == 3) throw RuntimeError("It seems the 3D wires are flat."); else if (dim == 2) throw RuntimeError("It seems the 2D wires are degenerated/linear."); else throw NotImplementedError("Unsupported dimension!"); } VectorF factors = cell_size.cwiseQuotient( m_unit_wire_network->get_bbox_max() - m_unit_wire_network->get_bbox_min()); m_unit_wire_network->center_at_origin(); m_unit_wire_network->scale(factors); }
void write_vertices(std::ofstream& fout, const VectorF& vertices, const size_t dim) { if (dim != 2 && dim != 3) { throw IOError("Unsupported mesh dimension: " + std::to_string(dim)); } fout.precision(16); size_t num_vertices = vertices.size() / dim; for (size_t i=0; i<num_vertices; i++) { const auto& v = vertices.segment(i*dim, dim); fout << "v"; for (size_t j=0; j<dim; j++) { fout << " " << v[j]; } fout << std::endl; } }
void EigenSolver::compute_batch_symmetric_2x2(const VectorF& matrices) { const size_t dim = 2; const size_t flatten_size = 3; const size_t num_matrices = matrices.size() / flatten_size; m_eigen_values = VectorF(num_matrices * dim); m_eigen_vectors = MatrixF(num_matrices * dim, dim); for (size_t i=0; i<num_matrices; i++) { const VectorF& entries = matrices.segment(i*flatten_size, flatten_size); MatrixF M(dim, dim); size_t base_idx = i*flatten_size; M << matrices[base_idx ], matrices[base_idx+2], matrices[base_idx+2], matrices[base_idx+1], m_solver.compute(M); m_eigen_values.segment(i*dim, dim) = m_solver.eigenvalues().real(); m_eigen_vectors.block(i*dim, 0, dim, dim) = m_solver.eigenvectors().real(); } }
VectorF AttributeUtils::convert_to_face_attribute(Mesh& mesh, const VectorF& attribute) { const size_t dim = mesh.get_dim(); const size_t num_vertices = mesh.get_num_vertices(); const size_t num_faces = mesh.get_num_faces(); const size_t num_voxels = mesh.get_num_voxels(); size_t attr_size = attribute.size(); if (attr_size == num_vertices || attr_size == dim*num_vertices) { return convert_vertex_attribute_to_face_attribute(mesh, attribute); } else if (attr_size == num_faces || attr_size == dim*num_faces) { std::cerr << "Warning: attribute is already face attribute! " << "This copy is unnecessary!" << std::endl; return attribute; } else if (attr_size == num_voxels || attr_size == dim*num_voxels) { return convert_voxel_attribute_to_face_attribute(mesh, attribute); } else { throw RuntimeError("Unknow attribute type."); } }
VectorF convert_vertex_attribute_to_face_attribute(Mesh& mesh, const VectorF& attribute) { const size_t num_vertices = mesh.get_num_vertices(); const size_t num_faces = mesh.get_num_faces(); const size_t vertex_per_face = mesh.get_vertex_per_face(); const size_t attr_size = attribute.size(); const size_t stride = attr_size / num_vertices; const VectorI& faces = mesh.get_faces(); VectorF result = VectorF::Zero(num_faces * stride); for (size_t i=0; i<num_faces; i++) { const VectorI& face = faces.segment(i*vertex_per_face, vertex_per_face); for (size_t j=0; j<vertex_per_face; j++) { result.segment(i*stride, stride) += attribute.segment(face[j]*stride, stride); } } result /= vertex_per_face; return result; }
VectorF convert_vertex_attribute_to_voxel_attribute(Mesh& mesh, const VectorF& attribute) { const size_t num_vertices = mesh.get_num_vertices(); const size_t num_voxels = mesh.get_num_voxels(); const size_t vertex_per_voxel = mesh.get_vertex_per_voxel(); const size_t attr_size = attribute.size(); const size_t stride = attr_size / num_vertices; const VectorI& voxels = mesh.get_voxels(); VectorF result = VectorF::Zero(num_voxels * stride); for (size_t i=0; i<num_voxels; i++) { const VectorI& voxel = voxels.segment(i*vertex_per_voxel, vertex_per_voxel); for (size_t j=0; j<vertex_per_voxel; j++) { result.segment(i*stride, stride) += attribute.segment(voxel[j]*stride, stride); } } result /= vertex_per_voxel; return result; }
VectorF convert_voxel_attribute_to_face_attribute( Mesh& mesh, const VectorF& attribute) { const size_t num_faces = mesh.get_num_faces(); const size_t num_voxels = mesh.get_num_voxels(); const size_t attr_size = attribute.size(); const size_t stride = attr_size / num_voxels; const size_t vertex_per_voxel = mesh.get_vertex_per_voxel(); const size_t vertex_per_face = mesh.get_vertex_per_face(); if (vertex_per_voxel != 4) throw NotImplementedError("Voxel type is not yet supported"); if (vertex_per_face != 3) throw NotImplementedError("Face type is not yet supported"); const VectorI& faces = mesh.get_faces(); const VectorI& voxels = mesh.get_voxels(); std::map<Triplet, VectorF> per_face_values; for (size_t i=0; i<num_voxels; i++) { const VectorI& voxel = voxels.segment( i*vertex_per_voxel, vertex_per_voxel); const VectorF& value = attribute.segment( i*stride, stride); per_face_values[Triplet(voxel[0], voxel[1], voxel[2])] = value; per_face_values[Triplet(voxel[0], voxel[1], voxel[3])] = value; per_face_values[Triplet(voxel[0], voxel[2], voxel[3])] = value; per_face_values[Triplet(voxel[1], voxel[2], voxel[3])] = value; } VectorF result = VectorF::Zero(num_faces*stride); for (size_t i=0; i<num_faces; i++) { const VectorI& face = faces.segment(i*vertex_per_face, vertex_per_face); result.segment(i*stride, stride) = per_face_values[ Triplet(face[0], face[1], face[2])]; } return result; }
void NodeWriter::write_elem_file(const std::string& filename, Mesh& mesh) { const size_t num_voxels = mesh.get_num_voxels(); const size_t vertex_per_voxel = mesh.get_vertex_per_voxel(); if (num_voxels == 0) return; if (vertex_per_voxel != 4) { throw IOError("Only tet element is supported in .ele file."); } std::ofstream fout(filename.c_str()); fout.precision(16); if (!is_anonymous()) { fout << "# Generated with PyMesh" << std::endl; } VectorF region; if (m_with_region_attribute) { if (!mesh.has_attribute("region")) { throw IOError("Attribute \"region\" does not exist."); } else { region = mesh.get_attribute("region"); assert(num_voxels == region.size()); } } const VectorI& voxels = mesh.get_voxels(); fout << num_voxels << " 4 " << m_with_region_attribute << std::endl; for (size_t i=0; i<num_voxels; i++) { fout << i; for (size_t j=0; j<4; j++) { fout << " " << voxels[i*4+ j]; } if (m_with_region_attribute) { fout << " " << region[i]; } fout << std::endl; } }
void MSHWriter::write_attribute(MshSaver& saver, const std::string& name, VectorF& value, size_t dim, size_t num_vertices, size_t num_elements) { size_t attr_size = value.size(); if (attr_size == num_vertices) { saver.save_scalar_field(name, value); } else if (attr_size == num_vertices * dim) { saver.save_vector_field(name, value); } else if (attr_size == num_vertices * (dim * (dim+1)) / 2) { throw NotImplementedError("Per-vertex tensor field is not supported."); } else if (attr_size == num_elements) { saver.save_elem_scalar_field(name, value); } else if (attr_size == num_elements * dim) { saver.save_elem_vector_field(name, value); } else if (attr_size == num_elements * (dim * (dim + 1)) / 2) { saver.save_elem_tensor_field(name, value); } else { std::stringstream err_msg; err_msg << "Attribute " << name << " has length " << attr_size << std::endl; err_msg << "Unable to interpret the attribute type."; std::cerr << "Warning: "; std::cerr << err_msg.str() << std::endl; } }