File indexing completed on 2025-01-18 09:11:33
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Visualization/ObjVisualization3D.hpp"
0010
0011 #include <algorithm>
0012 #include <fstream>
0013 #include <stdexcept>
0014
0015 namespace Acts {
0016
0017 void ObjVisualization3D::vertex(const Vector3& vtx, Color color) {
0018 auto& o = object();
0019 o.vertexColors[o.vertices.size()] = color;
0020 o.vertices.push_back(vtx.template cast<ValueType>());
0021 }
0022
0023 void ObjVisualization3D::line(const Vector3& a, const Vector3& b, Color color) {
0024 auto& o = object();
0025 if (color != Color{0, 0, 0}) {
0026 o.lineColors[o.lines.size()] = color;
0027 }
0028
0029 vertex(a, color);
0030 vertex(b, color);
0031 o.lines.push_back({o.vertices.size() - 2, o.vertices.size() - 1});
0032 }
0033
0034 void ObjVisualization3D::face(const std::vector<Vector3>& vtxs, Color color) {
0035 auto& o = object();
0036 if (color != Color{0, 0, 0}) {
0037 o.faceColors[o.faces.size()] = color;
0038 }
0039 FaceType idxs;
0040 idxs.reserve(vtxs.size());
0041 for (const auto& vtx : vtxs) {
0042 vertex(vtx, color);
0043 idxs.push_back(o.vertices.size() - 1);
0044 }
0045 o.faces.push_back(std::move(idxs));
0046 }
0047
0048 void ObjVisualization3D::faces(const std::vector<Vector3>& vtxs,
0049 const std::vector<FaceType>& faces,
0050 Color color) {
0051 auto& o = object();
0052
0053 if (faces.empty()) {
0054 face(vtxs, color);
0055 } else {
0056 if (color != Color{0, 0, 0}) {
0057 o.faceColors[o.faces.size()] = color;
0058 }
0059 auto vtxoffs = o.vertices.size();
0060 if (color != Color{0, 0, 0}) {
0061 o.vertexColors[o.vertices.size()] = color;
0062 }
0063 o.vertices.insert(o.vertices.end(), vtxs.begin(), vtxs.end());
0064 for (const auto& face : faces) {
0065 if (face.size() == 2) {
0066 o.lines.push_back({face[0] + vtxoffs, face[1] + vtxoffs});
0067 } else {
0068 FaceType rawFace;
0069 std::ranges::transform(
0070 face, std::back_inserter(rawFace),
0071 [&](unsigned long iv) { return (iv + vtxoffs); });
0072 o.faces.push_back(rawFace);
0073 }
0074 }
0075 }
0076 }
0077
0078 void ObjVisualization3D::write(const std::filesystem::path& path) const {
0079 std::ofstream os;
0080 std::filesystem::path objectpath = path;
0081 if (!objectpath.has_extension()) {
0082 objectpath.replace_extension(std::filesystem::path("obj"));
0083 }
0084 os.open(std::filesystem::absolute(objectpath).string());
0085 std::filesystem::path mtlpath = objectpath;
0086 mtlpath.replace_extension(std::filesystem::path("mtl"));
0087
0088 const std::string mtlpathString = std::filesystem::absolute(mtlpath).string();
0089 os << "mtllib " << mtlpathString << "\n";
0090 std::ofstream mtlos;
0091 mtlos.open(mtlpathString);
0092
0093 write(os, mtlos);
0094 os.close();
0095 mtlos.close();
0096 }
0097
0098 void ObjVisualization3D::write(std::ostream& os) const {
0099 std::stringstream sterile;
0100 write(os, sterile);
0101 }
0102
0103 void ObjVisualization3D::write(std::ostream& os, std::ostream& mos) const {
0104 std::map<std::string, bool, std::less<>> materials;
0105
0106 auto mixColor = [&](const Color& color) {
0107 std::string materialName;
0108 materialName = "material_";
0109 materialName += std::to_string(color[0]) + std::string("_");
0110 materialName += std::to_string(color[1]) + std::string("_");
0111 materialName += std::to_string(color[2]);
0112
0113 if (!materials.contains(materialName)) {
0114 mos << "newmtl " << materialName << "\n";
0115 std::vector<std::string> shadings = {"Ka", "Kd", "Ks"};
0116 for (const auto& shd : shadings) {
0117 mos << shd << " " << std::to_string(color[0] / 256.) << " ";
0118 mos << std::to_string(color[1] / 256.) << " ";
0119 mos << std::to_string(color[2] / 256.) << " " << "\n";
0120 }
0121 mos << "\n";
0122 }
0123 return std::string("usemtl ") + materialName;
0124 };
0125
0126 std::size_t vertexOffset = 0;
0127 for (const auto& o : m_objects) {
0128 if (!o.name.empty()) {
0129 os << "o " << o.name << "\n";
0130 }
0131
0132 std::size_t iv = 0;
0133 Color lastVertexColor = {0, 0, 0};
0134 for (const VertexType& vtx : o.vertices) {
0135 if (o.vertexColors.contains(iv)) {
0136 auto color = o.vertexColors.find(iv)->second;
0137 if (color != lastVertexColor) {
0138 os << mixColor(color) << "\n";
0139 lastVertexColor = color;
0140 }
0141 }
0142
0143 os << "v " << std::setprecision(m_outputPrecision)
0144 << m_outputScalor * vtx.x() << " " << m_outputScalor * vtx.y() << " "
0145 << m_outputScalor * vtx.z() << "\n";
0146 ++iv;
0147 }
0148 std::size_t il = 0;
0149 Color lastLineColor = {0, 0, 0};
0150 for (const auto& [start, end] : o.lines) {
0151 if (o.lineColors.contains(il)) {
0152 auto color = o.lineColors.find(il)->second;
0153 if (color != lastLineColor) {
0154 os << mixColor(color) << "\n";
0155 lastLineColor = color;
0156 }
0157 }
0158 os << "l " << vertexOffset + start + 1 << " " << vertexOffset + end + 1
0159 << "\n";
0160 ++il;
0161 }
0162 std::size_t is = 0;
0163 Color lastFaceColor = {0, 0, 0};
0164 for (const FaceType& fc : o.faces) {
0165 if (o.faceColors.contains(is)) {
0166 auto color = o.faceColors.find(is)->second;
0167 if (color != lastFaceColor) {
0168 os << mixColor(color) << "\n";
0169 lastFaceColor = color;
0170 }
0171 }
0172 os << "f";
0173 for (std::size_t fi : fc) {
0174 os << " " << vertexOffset + fi + 1;
0175 }
0176 os << "\n";
0177 ++is;
0178 }
0179
0180 vertexOffset += iv;
0181 }
0182 }
0183
0184 void ObjVisualization3D::clear() {
0185 m_objects.clear();
0186 }
0187
0188 void ObjVisualization3D::object(const std::string& name) {
0189 if (name.empty()) {
0190 throw std::invalid_argument{"Object name can not be empty"};
0191 }
0192 m_objects.push_back(Object{.name = name});
0193 }
0194
0195 ObjVisualization3D::Object& ObjVisualization3D::object() {
0196 if (m_objects.empty()) {
0197 m_objects.push_back(Object{.name = ""});
0198 }
0199
0200 return m_objects.back();
0201 }
0202
0203 const ObjVisualization3D::Object& ObjVisualization3D::object() const {
0204 if (m_objects.empty()) {
0205 throw std::runtime_error{"No objects present"};
0206 }
0207
0208 return m_objects.back();
0209 }
0210
0211 }