void PLYDataWriter::write_header(p_ply oply) { ply_add_element ( oply, "vertex", mesh->vertex_count() ); ply_add_scalar_property(oply, "x", PLY_FLOAT ); ply_add_scalar_property(oply, "y", PLY_FLOAT ); ply_add_scalar_property(oply, "z", PLY_FLOAT ); ply_add_element ( oply, "face", mesh->face_count() ); ply_add_list_property ( oply, "vertex_index", PLY_UCHAR, PLY_INT ); ply_write_header ( oply ); }
bool WritePlyFile(const std::string &filename, int nTriangles, const int *vertexIndices, int nVertices, const Point3f *P, const Vector3f *S, const Normal3f *N, const Point2f *UV) { p_ply plyFile = ply_create(filename.c_str(), PLY_DEFAULT, PlyErrorCallback, 0, nullptr); if (plyFile != nullptr) { ply_add_element(plyFile, "vertex", nVertices); ply_add_scalar_property(plyFile, "x", PLY_FLOAT); ply_add_scalar_property(plyFile, "y", PLY_FLOAT); ply_add_scalar_property(plyFile, "z", PLY_FLOAT); if (N != nullptr) { ply_add_scalar_property(plyFile, "nx", PLY_FLOAT); ply_add_scalar_property(plyFile, "ny", PLY_FLOAT); ply_add_scalar_property(plyFile, "nz", PLY_FLOAT); } if (UV != nullptr) { ply_add_scalar_property(plyFile, "u", PLY_FLOAT); ply_add_scalar_property(plyFile, "v", PLY_FLOAT); } if (S != nullptr) Warning("PLY mesh in \"%s\" will be missing tangent vectors \"S\".", filename.c_str()); ply_add_element(plyFile, "face", nTriangles); ply_add_list_property(plyFile, "vertex_indices", PLY_UINT8, PLY_INT); ply_write_header(plyFile); for (int i = 0; i < nVertices; ++i) { ply_write(plyFile, P[i].x); ply_write(plyFile, P[i].y); ply_write(plyFile, P[i].z); if (N) { ply_write(plyFile, N[i].x); ply_write(plyFile, N[i].y); ply_write(plyFile, N[i].z); } if (UV) { ply_write(plyFile, UV[i].x); ply_write(plyFile, UV[i].y); } } for (int i = 0; i < nTriangles; ++i) { ply_write(plyFile, 3); ply_write(plyFile, vertexIndices[3 * i]); ply_write(plyFile, vertexIndices[3 * i + 1]); ply_write(plyFile, vertexIndices[3 * i + 2]); } ply_close(plyFile); return true; } return false; }
void PlyWriter::done(PointTableRef table) { if (!ply_add_element(m_ply, "vertex", m_pointCollector->size())) { std::stringstream ss; ss << "Could not add vertex element"; throw pdal_error(ss.str()); } auto dimensions = table.layout()->dims(); for (auto dim : dimensions) { std::string name = Dimension::name(dim); e_ply_type plyType = getPlyType(Dimension::defaultType(dim)); if (!ply_add_scalar_property(m_ply, name.c_str(), plyType)) { std::stringstream ss; ss << "Could not add scalar property '" << name << "'"; throw pdal_error(ss.str()); } } if (!ply_add_comment(m_ply, "Generated by PDAL")) { std::stringstream ss; ss << "Could not add comment"; throw pdal_error(ss.str()); } if (!ply_write_header(m_ply)) { std::stringstream ss; ss << "Could not write ply header"; throw pdal_error(ss.str()); } for (PointId index = 0; index < m_pointCollector->size(); ++index) { for (auto dim : dimensions) { double value = m_pointCollector->getFieldAs<double>(dim, index); if (!ply_write(m_ply, value)) { std::stringstream ss; ss << "Error writing dimension '" << Dimension::name(dim) << "' of point number " << index; throw pdal_error(ss.str()); } } } if (!ply_close(m_ply)) { throw pdal_error("Error closing ply file"); } }
void write_ply(const std::string &filename, const MatrixXu &F, const MatrixXf &V, const MatrixXf &N, const MatrixXf &Nf, const MatrixXf &UV, const MatrixXf &C, const ProgressCallback &progress) { auto message_cb = [](p_ply ply, const char *msg) { cerr << "rply: " << msg << endl; }; Timer<> timer; cout << "Writing \"" << filename << "\" (V=" << V.cols() << ", F=" << F.cols() << ") .. "; cout.flush(); if (N.size() > 0 && Nf.size() > 0) throw std::runtime_error("Please specify either face or vertex normals but not both!"); p_ply ply = ply_create(filename.c_str(), PLY_DEFAULT, message_cb, 0, nullptr); if (!ply) throw std::runtime_error("Unable to write PLY file!"); ply_add_comment(ply, "Generated by Instant Meshes"); ply_add_element(ply, "vertex", V.cols()); ply_add_scalar_property(ply, "x", PLY_FLOAT); ply_add_scalar_property(ply, "y", PLY_FLOAT); ply_add_scalar_property(ply, "z", PLY_FLOAT); if (N.size() > 0) { ply_add_scalar_property(ply, "nx", PLY_FLOAT); ply_add_scalar_property(ply, "ny", PLY_FLOAT); ply_add_scalar_property(ply, "nz", PLY_FLOAT); if (N.cols() != V.cols() || N.rows() != 3) throw std::runtime_error("Vertex normal matrix has incorrect size"); } if (UV.size() > 0) { ply_add_scalar_property(ply, "u", PLY_FLOAT); ply_add_scalar_property(ply, "v", PLY_FLOAT); if (UV.cols() != V.cols() || UV.rows() != 2) throw std::runtime_error("Texture coordinate matrix has incorrect size"); } if (C.size() > 0) { ply_add_scalar_property(ply, "red", PLY_FLOAT); ply_add_scalar_property(ply, "green", PLY_FLOAT); ply_add_scalar_property(ply, "blue", PLY_FLOAT); if (C.cols() != V.cols() || (C.rows() != 3 && C.rows() != 4)) throw std::runtime_error("Color matrix has incorrect size"); } /* Check for irregular faces */ std::map<uint32_t, std::pair<uint32_t, std::map<uint32_t, uint32_t>>> irregular; size_t nIrregular = 0; if (F.rows() == 4) { for (uint32_t f=0; f<F.cols(); ++f) { if (F(2, f) == F(3, f)) { nIrregular++; auto &value = irregular[F(2, f)]; value.first = f; value.second[F(0, f)] = F(1, f); } } } ply_add_element(ply, "face", F.cols() - nIrregular + irregular.size()); ply_add_list_property(ply, "vertex_indices", PLY_UINT8, PLY_INT); if (Nf.size() > 0) { ply_add_scalar_property(ply, "nx", PLY_FLOAT); ply_add_scalar_property(ply, "ny", PLY_FLOAT); ply_add_scalar_property(ply, "nz", PLY_FLOAT); if (Nf.cols() != F.cols() || Nf.rows() != 3) throw std::runtime_error("Face normal matrix has incorrect size"); } ply_write_header(ply); for (uint32_t j=0; j<V.cols(); ++j) { for (uint32_t i=0; i<V.rows(); ++i) ply_write(ply, V(i, j)); if (N.size() > 0) { for (uint32_t i=0; i<N.rows(); ++i) ply_write(ply, N(i, j)); } if (UV.size() > 0) { for (uint32_t i=0; i<UV.rows(); ++i) ply_write(ply, UV(i, j)); } if (C.size() > 0) { for (uint32_t i=0; i<std::min(3u, (uint32_t) C.rows()); ++i) ply_write(ply, C(i, j)); } if (progress && j % 500000 == 0) progress("Writing vertex data", j / (Float) V.cols()); } for (uint32_t f=0; f<F.cols(); ++f) { if (F.rows() == 4 && F(2, f) == F(3, f)) continue; ply_write(ply, F.rows()); for (uint32_t i=0; i<F.rows(); ++i) ply_write(ply, F(i, f)); if (Nf.size() > 0) { for (uint32_t i=0; i<Nf.rows(); ++i) ply_write(ply, Nf(i, f)); } if (progress && f % 500000 == 0) progress("Writing face data", f / (Float) F.cols()); } for (auto item : irregular) { auto face = item.second; uint32_t v = face.second.begin()->first, first = v; ply_write(ply, face.second.size()); while (true) { ply_write(ply, v); v = face.second[v]; if (v == first) break; } if (Nf.size() > 0) { for (uint32_t i=0; i<Nf.rows(); ++i) ply_write(ply, Nf(i, face.first)); } } ply_close(ply); cout << "done. ("; if (irregular.size() > 0) cout << irregular.size() << " irregular faces, "; cout << "took " << timeString(timer.value()) << ")" << endl; }