74static std::map<Type, G4String> Extension = {
75 {Unknown,
"unknown"}, {PLY,
"ply"}, {STL,
"stl"}, {DAE,
"dae"},
76 {OBJ,
"obj"}, {TET,
"tet"}, {OFF,
"off"}};
78static std::map<Type, G4String> TypeString = {
79 {Unknown,
"UNKNOWN"}, {PLY,
"PLY"}, {STL,
"STL"}, {DAE,
"DAE"},
80 {OBJ,
"OBJ"}, {TET,
"TET"}, {OFF,
"OFF"}};
82static std::map<Type, G4String> TypeName = {
83 {Unknown,
"Unknown File Format"}, {PLY,
"Stanford Triangle Format (PLY)"},
84 {STL,
"Stereolithography (STL)"}, {DAE,
"COLLADA (DAE)"},
85 {OBJ,
"Wavefront (OBJ)"}, {TET,
"TetGet (TET)"},
86 {OFF,
"Object File Format (OFF)"}};
88Type TypeFromExtension(G4String extension);
89Type TypeFromName(G4String name);
93#include "G4ThreeVector.hh"
94#include "G4TriangularFacet.hh"
101typedef std::vector<G4ThreeVector> Points;
102typedef std::vector<G4TriangularFacet *> Triangles;
106 Mesh(Points points, Triangles triangles, G4String name =
"");
108 static std::shared_ptr<Mesh> New(Points points, Triangles triangles,
111 static std::shared_ptr<Mesh> New(Triangles triangles, G4String name =
"");
113 static std::shared_ptr<Mesh> New(std::shared_ptr<Mesh> mesh,
119 Triangles GetTriangles();
121 G4bool IsValidForNavigation();
127 Triangles triangles_;
130typedef std::vector<std::shared_ptr<Mesh>> Meshes;
139 Reader(G4String reader_name);
142 virtual G4bool Read(G4String filepath) = 0;
143 virtual G4bool CanRead(Type file_type) = 0;
148 std::shared_ptr<Mesh> GetMesh();
149 std::shared_ptr<Mesh> GetMesh(
size_t index);
150 std::shared_ptr<Mesh> GetMesh(G4String name, G4bool exact =
true);
152 size_t GetNumberOfMeshes();
157 size_t AddMesh(std::shared_ptr<Mesh> mesh);
158 void SetMeshes(Meshes meshs);
178 bool operator==(
Token other) {
return name == other.name; };
179 bool operator!=(
Token other) {
return name != other.name; };
182static Token ErrorToken{
"ErrorToken"};
183static Token EnfOfFileToken{
"EndOfFileToken"};
185static Token ParentToken{
"Parent"};
186static Token WordToken{
"Word"};
187static Token NumberToken{
"Number"};
188static Token ThreeVectorToken{
"ThreeVector"};
189static Token VertexToken{
"Vertex"};
190static Token VerticesToken{
"Vertices"};
191static Token FacetToken{
"Facet"};
192static Token LineToken{
"Line"};
193static Token NormalToken{
"Normal"};
194static Token TextureToken{
"Texture"};
195static Token SolidToken{
"Solid"};
196static Token ObjectToken{
"Object"};
197static Token CommentToken{
"Comment"};
198static Token BlankLineToken{
"BlankLine"};
211 std::vector<Item> children;
214typedef std::vector<Item> Items;
215typedef Items::iterator ItemsIterator;
224 State *operator()(
Lexer *)
const {
return nullptr; }
229 Lexer(std::string filepath,
State *initial_state =
nullptr);
232 std::string String();
234 void Run(
State *initial_state,
size_t lines = 0);
238 void BackupTo(
int position);
245 Item *ThisIsA(
Token token, std::string error =
"");
246 Item *StartOfA(
Token token, std::string error =
"");
247 Item *EndOfA(
Token token, std::string error =
"");
248 Item *MaybeEndOfA(
Token token, std::string error =
"");
250 bool OneOf(std::string possibles);
251 bool ManyOf(std::string possibles);
252 bool Until(std::string match);
253 bool MatchExactly(std::string match);
261 bool ManyCharacters();
267 bool SkipWhiteSpace();
268 bool SkipLineBreak();
269 bool SkipLineBreaks();
272 State *Error(std::string message);
275 bool TestState(
State *state);
279 void PrintMessage(std::string name, std::string message);
280 void PrintItem(
Item item);
287 Item *parent_item_ =
nullptr;
292 size_t position_ = 0;
296 size_t end_line_ = 0;
298 bool dry_run_ =
false;
302 std::string last_error_ =
"";
307#ifdef USE_CADMESH_ASSIMP_READER
309#include "assimp/Importer.hpp"
310#include "assimp/postprocess.h"
311#include "assimp/scene.h"
317class ASSIMPReader :
public File::Reader {
323 G4bool Read(G4String filepath);
324 G4bool CanRead(Type file_type);
327 Assimp::Importer *importer_;
330std::shared_ptr<ASSIMPReader> ASSIMP();
344 G4bool Read(G4String filepath);
345 G4bool CanRead(File::Type file_type);
348std::shared_ptr<BuiltInReader> BuiltIn();
351#ifndef CADMESH_DEFAULT_READER
352#define CADMESH_DEFAULT_READER BuiltIn
355#include "G4AssemblyVolume.hh"
356#include "G4LogicalVolume.hh"
357#include "G4Material.hh"
358#include "G4TessellatedSolid.hh"
360#include "G4UIcommand.hh"
374 CADMeshTemplate(G4String file_name, std::shared_ptr<File::Reader> reader);
377 std::shared_ptr<File::Reader> reader);
379 static std::shared_ptr<T> From(G4String file_name);
381 static std::shared_ptr<T> From(G4String file_name,
382 std::shared_ptr<File::Reader> reader);
384 static std::shared_ptr<T> FromPLY(G4String file_name);
386 static std::shared_ptr<T> FromPLY(G4String file_name,
387 std::shared_ptr<File::Reader> reader);
389 static std::shared_ptr<T> FromSTL(G4String file_name);
391 static std::shared_ptr<T> FromSTL(G4String file_name,
392 std::shared_ptr<File::Reader> reader);
394 static std::shared_ptr<T> FromOBJ(G4String file_name);
396 static std::shared_ptr<T> FromOBJ(G4String file_name,
397 std::shared_ptr<File::Reader> reader);
402 virtual G4VSolid *GetSolid() = 0;
403 virtual G4VSolid *GetSolid(G4int index) = 0;
404 virtual G4VSolid *GetSolid(G4String name, G4bool exact =
true) = 0;
406 virtual std::vector<G4VSolid *> GetSolids() = 0;
408 virtual G4AssemblyVolume *GetAssembly() = 0;
410 bool IsValidForNavigation();
413 G4String GetFileName();
415 File::Type GetFileType();
417 void SetVerbose(G4int verbose);
420 void SetScale(G4double scale);
423 void SetOffset(G4double x, G4double y, G4double z);
424 void SetOffset(G4ThreeVector offset);
425 G4ThreeVector GetOffset();
429 File::Type file_type_;
432 G4ThreeVector offset_;
434 G4AssemblyVolume *assembly_ =
nullptr;
436 std::shared_ptr<File::Reader> reader_ =
nullptr;
444namespace Exceptions {
446void FileNotFound(G4String origin, G4String filepath);
448void LexerError(G4String origin, G4String message);
450void ParserError(G4String origin, G4String message);
452void ReaderCantReadError(G4String origin, File::Type file_type,
455void MeshNotFound(G4String origin,
size_t index);
456void MeshNotFound(G4String origin, G4String name);
463 using CADMeshTemplate::CADMeshTemplate;
466 G4VSolid *GetSolid();
467 G4VSolid *GetSolid(G4int index);
468 G4VSolid *GetSolid(G4String name, G4bool exact =
true);
470 std::vector<G4VSolid *> GetSolids();
472 G4TessellatedSolid *GetTessellatedSolid();
473 G4TessellatedSolid *GetTessellatedSolid(G4int index);
474 G4TessellatedSolid *GetTessellatedSolid(G4String name, G4bool exact =
true);
475 G4TessellatedSolid *GetTessellatedSolid(std::shared_ptr<Mesh> mesh);
477 G4AssemblyVolume *GetAssembly();
480 void SetReverse(G4bool reverse) { this->reverse_ = reverse; };
482 G4bool GetReverse() {
return this->reverse_; };
489#ifdef USE_CADMESH_TETGEN
495class TetrahedralMesh :
public CADMeshTemplate<TetrahedralMesh> {
497 using CADMeshTemplate::CADMeshTemplate;
503 G4VSolid *GetSolid();
504 G4VSolid *GetSolid(G4int index);
505 G4VSolid *GetSolid(G4String name, G4bool exact =
true);
507 std::vector<G4VSolid *> GetSolids();
509 G4AssemblyVolume *GetAssembly();
512 void SetMaterial(G4Material *material) { this->material_ = material; };
514 G4Material *GetMaterial() {
return this->material_; };
516 void SetQuality(G4double quality) { this->quality_ = quality; };
518 G4double GetQuality() {
return this->quality_; };
520 std::shared_ptr<tetgenio> GetTetgenInput() {
return in_; };
522 std::shared_ptr<tetgenio> GetTetgenOutput() {
return out_; };
525 G4ThreeVector GetTetPoint(G4int index_offset);
528 std::shared_ptr<tetgenio> in_ =
nullptr;
529 std::shared_ptr<tetgenio> out_ =
nullptr;
533 G4Material *material_;
542inline Type TypeFromExtension(G4String extension) {
543 std::for_each(extension.begin(), extension.end(),
544 [](
char &e) { e = ::tolower(e); });
546 for (
auto e = Extension.begin(); e != Extension.end(); ++e) {
547 if (e->second == extension) {
555inline Type TypeFromName(G4String name) {
556 auto extension = name.substr(name.find_last_of(
".") + 1);
558 return TypeFromExtension(extension);
565inline Mesh::Mesh(Points points, Triangles triangles, G4String name)
566 : name_(name), points_(points), triangles_(triangles) {}
568inline std::shared_ptr<Mesh> Mesh::New(Points points, Triangles triangles,
570 return std::make_shared<Mesh>(points, triangles, name);
573inline std::shared_ptr<Mesh> Mesh::New(Triangles triangles, G4String name) {
576 return New(points, triangles, name);
579inline std::shared_ptr<Mesh> Mesh::New(std::shared_ptr<Mesh> mesh,
581 return New(mesh->GetPoints(), mesh->GetTriangles(), name);
584inline G4String Mesh::GetName() {
return name_; }
586inline Points Mesh::GetPoints() {
return points_; }
588inline Triangles Mesh::GetTriangles() {
return triangles_; }
590inline G4bool Mesh::IsValidForNavigation() {
591 std::map<G4ThreeVector, size_t> point_index;
594 for (
auto point : points_) {
595 point_index[point] = index;
599 typedef std::pair<size_t, size_t> Edge;
600 std::map<Edge, G4int> edge_use_count;
602 for (
size_t i = 0; i < triangles_.size(); i++) {
603 auto triangle = triangles_[i];
605 size_t a = point_index[triangle->GetVertex(0)];
606 size_t b = point_index[triangle->GetVertex(1)];
607 size_t c = point_index[triangle->GetVertex(2)];
610 edge_use_count[Edge(a, b)] += 1;
614 edge_use_count[Edge(b, a)] += 1;
618 edge_use_count[Edge(b, c)] += 1;
622 edge_use_count[Edge(c, b)] += 1;
626 edge_use_count[Edge(c, a)] += 1;
630 edge_use_count[Edge(a, c)] += 1;
634 for (
auto count : edge_use_count) {
635 if (count.second != 2) {
648inline Reader::Reader(G4String reader_name) : name_(reader_name) {}
650inline Reader::~Reader() {}
652inline G4String Reader::GetName() {
return name_; }
654inline std::shared_ptr<Mesh> Reader::GetMesh() {
655 if (meshes_.size() > 0) {
662inline std::shared_ptr<Mesh> Reader::GetMesh(
size_t index) {
663 if (index < meshes_.size()) {
664 return meshes_[index];
667 Exceptions::MeshNotFound(
"Reader::GetMesh", index);
672inline std::shared_ptr<Mesh> Reader::GetMesh(G4String name, G4bool exact) {
673 for (
auto mesh : meshes_) {
675 if (mesh->GetName() == name)
680 if (mesh->GetName().find(name) != std::string::npos)
685 Exceptions::MeshNotFound(
"Reader::GetMesh", name);
690inline Meshes Reader::GetMeshes() {
return meshes_; }
692inline size_t Reader::GetNumberOfMeshes() {
return meshes_.size(); }
694inline size_t Reader::AddMesh(std::shared_ptr<Mesh> mesh) {
695 meshes_.push_back(mesh);
697 return meshes_.size();
700inline void Reader::SetMeshes(Meshes meshes) { meshes_ = meshes; }
712inline Lexer::Lexer(std::string filepath, State *initial_state) {
713 std::ifstream file(filepath);
714 input_ = std::string((std::istreambuf_iterator<char>(file)),
715 std::istreambuf_iterator<char>());
722inline std::string Lexer::String() {
723 return input_.substr(start_, position_ - start_);
726inline void Lexer::Run(State *initial_state,
size_t lines) {
727 parent_item_ =
new Item{ParentToken, position_, line_,
"",
"",
728 nullptr, std::vector<Item>()};
730 state_ = initial_state;
735 end_line_ = line_ + lines;
738 state_ = (*state_)(
this);
742inline Items Lexer::GetItems() {
return parent_item_->children; }
744inline void Lexer::Backup() {
747 auto next = input_.substr(position_, 1);
754inline void Lexer::BackupTo(
int position) {
755 auto s = input_.substr(position, position_ - position);
756 line_ -= std::count(s.begin(), s.end(),
'\n');
758 position_ = position;
761inline std::string Lexer::Next() {
762 if (position_ >= input_.length()) {
766 auto next = input_.substr(position_, 1);
777inline std::string Lexer::Peek() {
786inline void Lexer::Skip() { start_ = position_; }
788inline Item *Lexer::ThisIsA(Token token, std::string error) {
793 Item{token, position_, line_, String(), error, parent_item_, Items()};
799 parent_item_->children.push_back(item);
800 return &(parent_item_->children.back());
807 items_.push_back(item);
808 return &(items_.back());
812inline Item *Lexer::StartOfA(Token token, std::string error) {
816 parent_item_ = ThisIsA(token, error);
823inline Item *Lexer::EndOfA(Token token, std::string ) {
829 PrintItem(*parent_item_);
831 if (parent_item_->token.name != token.name) {
832 Exceptions::LexerError(
"Lexer::EndOfA",
833 "Trying to end a '" + parent_item_->token.name +
834 "' with a '" + token.name +
"' token.");
838 parent_item_ = parent_item_->parent;
844inline Item *Lexer::MaybeEndOfA(Token token, std::string error) {
845 if (parent_item_->token.name == token.name) {
846 return EndOfA(token, error);
854inline bool Lexer::OneOf(std::string possibles) {
857 size_t position = possibles.find(Peek());
859 if (position != std::string::npos) {
867inline bool Lexer::ManyOf(std::string possibles) {
870 while (OneOf(possibles)) {
877inline bool Lexer::Until(std::string match) {
878 while (!OneOf(match)) {
886inline bool Lexer::MatchExactly(std::string match) {
887 auto start_position = position_;
889 for (
auto m : match) {
890 if (!OneOf(std::string(1, m))) {
891 BackupTo(start_position);
899inline bool Lexer::OneDigit() {
return OneOf(
"0123456789"); }
901inline bool Lexer::ManyDigits() {
return ManyOf(
"0123456789"); }
903inline bool Lexer::OneLetter() {
904 return OneOf(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
907inline bool Lexer::ManyLetters() {
908 return ManyOf(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
911inline bool Lexer::ManyCharacters() {
912 return ManyOf(
"!\"#$%&\\\'()*+,-./"
913 "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[|]^_`"
914 "abcdefghijklmnopqrstuvwxyz{}~");
917inline bool Lexer::Integer() {
918 auto start_position = position_;
923 BackupTo(start_position);
930inline bool Lexer::Float() {
931 auto start_position = position_;
935 bool has_integer = Integer();
938 BackupTo(start_position);
942 bool has_decimal = ManyDigits();
944 if (!has_integer || !has_decimal) {
945 BackupTo(start_position);
952inline bool Lexer::Number() {
959 auto start_position = position_;
964 BackupTo(start_position);
972inline bool Lexer::SkipWhiteSpace() {
973 if (!ManyOf(
" \t\r")) {
982inline bool Lexer::SkipLineBreak() {
991inline bool Lexer::SkipLineBreaks() {
1000inline bool Lexer::SkipLine() {
1009inline State *Lexer::Error(std::string message) {
1011 std::stringstream error;
1012 error <<
"Error around line " << line_ <<
": " << message << std::endl;
1014 last_error_ = error.str();
1019 Item item{ErrorToken, position_, line_,
"",
1020 error.str(), parent_item_, Items()};
1021 items_.push_back(item);
1023 Exceptions::LexerError(
"Lexer", error.str());
1028inline State *Lexer::LastError() {
1029 if (last_error_ ==
"") {
1030 Exceptions::LexerError(
"Lexer",
"Something went wrong.");
1034 Exceptions::LexerError(
"Lexer", last_error_);
1040inline bool Lexer::TestState(State *state) {
1044 if (end_line_ > 0 && line_ > end_line_)
1047 auto start_position = position_;
1051 bool state_transition = ((*state)(
this) !=
nullptr);
1055 BackupTo(start_position);
1057 return state_transition;
1060inline bool Lexer::IsDryRun() {
return dry_run_; }
1062inline size_t Lexer::LineNumber() {
return line_; }
1064#ifdef CADMESH_LEXER_VERBOSE
1065inline void Lexer::PrintMessage(std::string name, std::string message) {
1066 std::cout <<
"Lexer::" << name <<
" : " << message << std::endl;
1069inline void Lexer::PrintMessage(std::string, std::string) {}
1072#ifdef CADMESH_LEXER_VERBOSE
1073inline void Lexer::PrintItem(Item item) {
1074 auto depth = std::max(0, depth_) * 2;
1075 std::cout << std::string(depth,
' ') << item.token.name <<
": " << item.value
1079inline void Lexer::PrintItem(Item) {}
1086template <
typename T>
1087CADMeshTemplate<T>::CADMeshTemplate() : CADMeshTemplate<T>(
"") {}
1089template <
typename T>
1090CADMeshTemplate<T>::CADMeshTemplate(G4String file_name)
1091 : CADMeshTemplate<T>(file_name, File::Unknown) {}
1093template <
typename T>
1094CADMeshTemplate<T>::CADMeshTemplate(G4String file_name, File::Type file_type)
1095 : CADMeshTemplate<T>(file_name, file_type, File::CADMESH_DEFAULT_READER()) {
1098template <
typename T>
1099CADMeshTemplate<T>::CADMeshTemplate(std::shared_ptr<File::Reader> reader)
1100 : CADMeshTemplate<T>(
"", reader) {}
1102template <
typename T>
1103CADMeshTemplate<T>::CADMeshTemplate(G4String file_name,
1104 std::shared_ptr<File::Reader> reader)
1105 : CADMeshTemplate<T>(file_name, File::Unknown, reader) {}
1107template <
typename T>
1108CADMeshTemplate<T>::CADMeshTemplate(G4String file_name, File::Type file_type,
1109 std::shared_ptr<File::Reader> reader) {
1110 if (!reader->CanRead(file_type)) {
1111 Exceptions::ReaderCantReadError(reader->GetName(), file_type, file_name);
1114 file_name_ = file_name;
1115 file_type_ = file_type;
1119 offset_ = G4ThreeVector();
1125 reader_->Read(file_name_);
1128template <
typename T>
1129std::shared_ptr<T> CADMeshTemplate<T>::From(G4String file_name) {
1130 return std::make_shared<T>(file_name);
1133template <
typename T>
1135CADMeshTemplate<T>::From(G4String file_name,
1136 std::shared_ptr<File::Reader> reader) {
1137 return std::make_shared<T>(file_name, reader);
1140template <
typename T>
1141std::shared_ptr<T> CADMeshTemplate<T>::FromPLY(G4String file_name) {
1142 return std::make_shared<T>(file_name, File::PLY);
1145template <
typename T>
1147CADMeshTemplate<T>::FromPLY(G4String file_name,
1148 std::shared_ptr<File::Reader> reader) {
1149 return std::make_shared<T>(file_name, File::PLY, reader);
1152template <
typename T>
1153std::shared_ptr<T> CADMeshTemplate<T>::FromSTL(G4String file_name) {
1154 return std::make_shared<T>(file_name, File::STL);
1157template <
typename T>
1159CADMeshTemplate<T>::FromSTL(G4String file_name,
1160 std::shared_ptr<File::Reader> reader) {
1161 return std::make_shared<T>(file_name, File::STL, reader);
1164template <
typename T>
1165std::shared_ptr<T> CADMeshTemplate<T>::FromOBJ(G4String file_name) {
1166 return std::make_shared<T>(file_name, File::OBJ);
1169template <
typename T>
1171CADMeshTemplate<T>::FromOBJ(G4String file_name,
1172 std::shared_ptr<File::Reader> reader) {
1173 return std::make_shared<T>(file_name, File::OBJ, reader);
1176template <
typename T> CADMeshTemplate<T>::~CADMeshTemplate() {}
1178template <
typename T>
bool CADMeshTemplate<T>::IsValidForNavigation() {
1179 return reader_->GetMesh()->IsValidForNavigation();
1182template <
typename T> G4String CADMeshTemplate<T>::GetFileName() {
1186template <
typename T> File::Type CADMeshTemplate<T>::GetFileType() {
1190template <
typename T>
void CADMeshTemplate<T>::SetVerbose(G4int verbose) {
1194template <
typename T> G4int CADMeshTemplate<T>::GetVerbose() {
1198template <
typename T>
void CADMeshTemplate<T>::SetScale(G4double scale) {
1202template <
typename T> G4double CADMeshTemplate<T>::GetScale() {
return scale_; }
1204template <
typename T>
1205void CADMeshTemplate<T>::SetOffset(G4double x, G4double y, G4double z) {
1206 SetOffset(G4ThreeVector(x, y, z));
1209template <
typename T>
void CADMeshTemplate<T>::SetOffset(G4ThreeVector offset) {
1213template <
typename T> G4ThreeVector CADMeshTemplate<T>::GetOffset() {
1220namespace Exceptions {
1222inline void FileNotFound(G4String origin, G4String filepath) {
1224 (
"CADMesh in " + origin).c_str(),
"FileNotFound", FatalException,
1225 (
"\nThe file: \n\t" + filepath +
"\ncould not be found.").c_str());
1228inline void LexerError(G4String origin, G4String message) {
1230 (
"CADMesh in " + origin).c_str(),
"LexerError", FatalException,
1231 (
"\nThe CAD file appears to contain incorrect syntax:\n\t" + message)
1235inline void ParserError(G4String origin, G4String message) {
1236 G4Exception((
"CADMesh in " + origin).c_str(),
"ParserError", FatalException,
1237 (
"\nThe CAD file appears to contain invalid data:\n\t" + message)
1241inline void ReaderCantReadError(G4String origin, File::Type file_type,
1242 G4String filepath) {
1244 (
"CADMesh in " + origin).c_str(),
"ReaderCantReadError", FatalException,
1245 (G4String(
"\nThe the reader can't read files of type '") +
1246 File::TypeString[file_type] +
1247 ".'\n\tSpecified the incorrect file type (?) for file:\n\t\t" + filepath)
1251inline void MeshNotFound(G4String origin,
size_t index) {
1252 std::stringstream message;
1253 message <<
"\nThe mesh with index '" << index <<
"' could not be found.";
1255 G4Exception((
"CADMesh in " + origin).c_str(),
"MeshNotFound", FatalException,
1256 message.str().c_str());
1259inline void MeshNotFound(G4String origin, G4String name) {
1261 (
"CADMesh in " + origin).c_str(),
"MeshNotFound", FatalException,
1262 (
"\nThe mesh with name '" + name +
"' could not be found.").c_str());
1267#include "Randomize.hh"
1271inline G4VSolid *TessellatedMesh::GetSolid() {
1272 return (G4VSolid *)GetTessellatedSolid();
1275inline G4VSolid *TessellatedMesh::GetSolid(G4int index) {
1276 return (G4VSolid *)GetTessellatedSolid(index);
1279inline G4VSolid *TessellatedMesh::GetSolid(G4String name, G4bool exact) {
1280 return (G4VSolid *)GetTessellatedSolid(name, exact);
1283inline std::vector<G4VSolid *> TessellatedMesh::GetSolids() {
1284 std::vector<G4VSolid *> solids;
1286 for (
auto mesh : reader_->GetMeshes()) {
1287 solids.push_back(GetTessellatedSolid(mesh));
1293inline G4AssemblyVolume *TessellatedMesh::GetAssembly() {
1298 for (
auto mesh : reader_->GetMeshes()) {
1299 auto solid = GetTessellatedSolid(mesh);
1301 G4Material *material =
nullptr;
1304 new G4LogicalVolume(solid, material, mesh->GetName() +
"_logical");
1306 G4ThreeVector position = G4ThreeVector();
1307 G4RotationMatrix *rotation =
new G4RotationMatrix();
1309 assembly_->AddPlacedVolume(logical, position, rotation);
1315inline G4TessellatedSolid *TessellatedMesh::GetTessellatedSolid() {
1316 return GetTessellatedSolid(0);
1319inline G4TessellatedSolid *TessellatedMesh::GetTessellatedSolid(G4int index) {
1320 return GetTessellatedSolid(reader_->GetMesh(index));
1323inline G4TessellatedSolid *TessellatedMesh::GetTessellatedSolid(G4String name,
1325 return GetTessellatedSolid(reader_->GetMesh(name, exact));
1328inline G4TessellatedSolid *
1329TessellatedMesh::GetTessellatedSolid(std::shared_ptr<Mesh> mesh) {
1330 auto volume_solid =
new G4TessellatedSolid(mesh->GetName());
1332 for (
auto triangle : mesh->GetTriangles()) {
1333 auto a = triangle->GetVertex(0) * scale_ + offset_;
1334 auto b = triangle->GetVertex(1) * scale_ + offset_;
1335 auto c = triangle->GetVertex(2) * scale_ + offset_;
1337 auto t =
new G4TriangularFacet(a, b, c, ABSOLUTE);
1340 volume_solid->AddFacet((G4VFacet *)t->GetFlippedFacet());
1344 volume_solid->AddFacet((G4VFacet *)t);
1348 volume_solid->SetSolidClosed(
true);
1349 if (volume_solid->GetNumberOfFacets() == 0) {
1350 G4Exception(
"TessellatedMesh::GetTessellatedSolid",
1351 "The loaded mesh has 0 faces.", FatalException,
1352 "The file may be empty.");
1355 return volume_solid;
1359#ifdef USE_CADMESH_TETGEN
1363inline TetrahedralMesh::TetrahedralMesh() {}
1365inline TetrahedralMesh::~TetrahedralMesh() {}
1367inline G4VSolid *TetrahedralMesh::GetSolid() {
return GetSolid(0); }
1369inline G4VSolid *TetrahedralMesh::GetSolid(G4int ) {
return nullptr; }
1371inline G4VSolid *TetrahedralMesh::GetSolid(G4String ,
1377inline std::vector<G4VSolid *> TetrahedralMesh::GetSolids() {
1379 return std::vector<G4VSolid *>();
1382inline G4AssemblyVolume *TetrahedralMesh::GetAssembly() {
1387 assembly_ =
new G4AssemblyVolume();
1389 in_ = std::make_shared<tetgenio>();
1390 out_ = std::make_shared<tetgenio>();
1392 char *fn = (
char *)file_name_.c_str();
1394 G4bool do_tet =
true;
1396 if (file_type_ == File::STL) {
1400 else if (file_type_ == File::PLY) {
1404 else if (file_type_ == File::TET) {
1405 out_->load_tetmesh(fn, 0);
1409 else if (file_type_ == File::OFF) {
1415 tetgenbehavior *behavior =
new tetgenbehavior();
1416 behavior->nobisect = 1;
1418 behavior->quality = quality_;
1420 tetrahedralize(behavior, in_.get(), out_.get());
1423 G4RotationMatrix *element_rotation =
new G4RotationMatrix();
1424 G4ThreeVector element_position = G4ThreeVector();
1425 G4Transform3D assembly_transform = G4Translate3D();
1427 for (
int i = 0; i < out_->numberoftetrahedra; i++) {
1428 int index_offset = i * 4;
1430 G4ThreeVector p1 = GetTetPoint(index_offset);
1431 G4ThreeVector p2 = GetTetPoint(index_offset + 1);
1432 G4ThreeVector p3 = GetTetPoint(index_offset + 2);
1433 G4ThreeVector p4 = GetTetPoint(index_offset + 3);
1436 file_name_ + G4String(
"_tet_") + G4UIcommand::ConvertToString(i);
1439 new G4Tet(tet_name + G4String(
"_solid"), p1, p2, p3, p4, 0);
1441 auto tet_logical =
new G4LogicalVolume(
1442 tet_solid, material_, tet_name + G4String(
"_logical"), 0, 0, 0);
1444 assembly_->AddPlacedVolume(tet_logical, element_position, element_rotation);
1450inline G4ThreeVector TetrahedralMesh::GetTetPoint(G4int index_offset) {
1451 return G4ThreeVector(
1452 out_->pointlist[out_->tetrahedronlist[index_offset] * 3] * scale_ -
1454 out_->pointlist[out_->tetrahedronlist[index_offset] * 3 + 1] * scale_ -
1456 out_->pointlist[out_->tetrahedronlist[index_offset] * 3 + 2] * scale_ -
1462#define CADMeshLexerToken(name) \
1463 static Token name##Token { #name }
1465#define CADMeshLexerStateDefinition(name) \
1466 struct name##State : public State { \
1467 State *operator()(Lexer *lexer) const; \
1470#define CADMeshLexerState(name) name##State::operator()(Lexer *lexer) const
1472#define ThisIsA(name) lexer->ThisIsA(name##Token)
1473#define StartOfA(name) lexer->StartOfA(name##Token)
1474#define EndOfA(name) lexer->EndOfA(name##Token)
1475#define MaybeEndOfA(name) lexer->MaybeEndOfA(name##Token)
1477#define Skip() lexer->Skip()
1479#define Next() lexer->Peek()
1480#define PrintNext() std::cout << lexer->Peek() << std::endl;
1482#define OneOf(possibles) lexer->OneOf(possibles)
1483#define NotOneOf(possibles) !OneOf(possibles)
1485#define ManyOf(possibles) lexer->ManyOf(possibles)
1486#define NotManyOf(possibles) !ManyOf(possibles)
1488#define Until(match) lexer->Until(match)
1490#define RestOfLine() \
1491 if (Until("\n\r")) \
1494#define MatchExactly(match) lexer->MatchExactly(match)
1495#define DoesNotMatchExactly(match) !MatchExactly(match)
1497#define OneDigit() lexer->OneDigit()
1498#define NotOneDigit() !OneDigit()
1500#define ManyDigits() lexer->ManyDigits()
1501#define NotManyDigits() !ManyDigits()
1503#define OneLetter() lexer->OneLetter()
1504#define NotOneLetter() !OneLetter()
1506#define ManyLetters() lexer->ManyLetters()
1507#define NotManyLetters() !ManyLetters()
1509#define ManyCharacters() lexer->ManyCharacters()
1510#define NotManyCharacters() !ManyCharacters()
1512#define Integer() lexer->Integer()
1513#define NotAnInteger() !Integer()
1515#define Float() lexer->Float()
1516#define NotAFloat() !Float()
1518#define Number() lexer->Number()
1519#define NotANumber() !Number()
1521#define SkipWhiteSpace() lexer->SkipWhiteSpace()
1522#define DidNotSkipWhiteSpace() !SkipWhiteSpace()
1524#define SkipLineBreak() lexer->SkipLineBreak()
1525#define DidNotSkipLineBreak() !SkipLineBreak()
1527#define SkipLineBreaks() lexer->SkipLineBreaks()
1528#define DidNotSkipLineBreaks() !SkipLineBreaks()
1530#define SkipLine() lexer->SkipLine()
1531#define DidNotSkipLine() !SkipLine()
1533#define AtEndOfLine() Next() == "\n" || Next() == "\r"
1535#define Error(message) \
1537 lexer->Error(message); \
1541#define NextState(next) return new next##State()
1542#define TestState(next) lexer->TestState(new next##State())
1543#define TryState(next) \
1544 if (TestState(next)) \
1546#define FinalState() return new __FinalState();
1548#define RunLexer(filepath, start) Lexer(filepath, new start##State).GetItems()
1558 G4bool Read(G4String filepath);
1559 G4bool CanRead(Type file_type);
1562 CADMeshLexerStateDefinition(StartSolid);
1563 CADMeshLexerStateDefinition(EndSolid);
1565 CADMeshLexerStateDefinition(StartFacet);
1566 CADMeshLexerStateDefinition(EndFacet);
1568 CADMeshLexerStateDefinition(StartVertices);
1569 CADMeshLexerStateDefinition(EndVertices);
1571 CADMeshLexerStateDefinition(Vertex);
1573 CADMeshLexerStateDefinition(ThreeVector);
1575 std::shared_ptr<Mesh> ParseMesh(Items items);
1576 G4TriangularFacet *ParseFacet(Items items);
1577 G4TriangularFacet *ParseVertices(Items items);
1578 G4ThreeVector ParseThreeVector(Items items);
1591 G4bool Read(G4String filepath);
1592 G4bool CanRead(Type file_type);
1595 CADMeshLexerStateDefinition(StartSolid);
1596 CADMeshLexerStateDefinition(EndSolid);
1598 CADMeshLexerStateDefinition(Ignore);
1599 CADMeshLexerStateDefinition(Vertex);
1600 CADMeshLexerStateDefinition(Facet);
1601 CADMeshLexerStateDefinition(Object);
1603 std::shared_ptr<Mesh> ParseMesh(Items items);
1604 G4ThreeVector ParseVertex(Items items);
1605 G4TriangularFacet *ParseFacet(Items items, G4bool quad);
1617CADMeshLexerToken(Header);
1618CADMeshLexerToken(Element);
1619CADMeshLexerToken(Property);
1625 G4bool Read(G4String filepath);
1626 G4bool CanRead(Type file_type);
1629 CADMeshLexerStateDefinition(StartHeader);
1630 CADMeshLexerStateDefinition(EndHeader);
1632 CADMeshLexerStateDefinition(Element);
1633 CADMeshLexerStateDefinition(Property);
1634 CADMeshLexerStateDefinition(Ignore);
1636 CADMeshLexerStateDefinition(Vertex);
1637 CADMeshLexerStateDefinition(Facet);
1639 void ParseHeader(Items items);
1641 std::shared_ptr<Mesh> ParseMesh(Items vertex_items, Items face_items);
1642 G4ThreeVector ParseVertex(Items items);
1643 G4TriangularFacet *ParseFacet(Items items, Points vertices);
1645 size_t vertex_count_ = 0;
1646 size_t facet_count_ = 0;
1648 size_t x_index_ = 0;
1649 size_t y_index_ = 0;
1650 size_t z_index_ = 0;
1652 size_t facet_index_ = 0;
1661inline State *STLReader::CADMeshLexerState(StartSolid) {
1662 if (DoesNotMatchExactly(
"solid"))
1663 Error(
"STL files start with 'solid'. Make sure you are using an ASCII STL "
1673 NextState(StartFacet);
1676inline State *STLReader::CADMeshLexerState(EndSolid) {
1681 if (DoesNotMatchExactly(
"endsolid"))
1682 Error(
"STL files end with 'endsolid'.");
1690inline State *STLReader::CADMeshLexerState(StartFacet) {
1695 if (DoesNotMatchExactly(
"facet normal"))
1696 Error(
"Facets are indicated by the tag 'facet normal'.");
1704 NextState(StartVertices);
1707inline State *STLReader::CADMeshLexerState(EndFacet) {
1712 if (DoesNotMatchExactly(
"endfacet"))
1713 Error(
"The end of a facets is indicated by the tag 'endfacet'.");
1720 TryState(StartFacet);
1722 NextState(EndSolid);
1725inline State *STLReader::CADMeshLexerState(StartVertices) {
1730 if (DoesNotMatchExactly(
"outer loop"))
1731 Error(
"The start of the vertices is indicated by the tag 'outer loop'.");
1741inline State *STLReader::CADMeshLexerState(EndVertices) {
1746 if (DoesNotMatchExactly(
"endloop"))
1747 Error(
"The end of the vertices is indicated by the tag 'endloop'.");
1754 NextState(EndFacet);
1757inline State *STLReader::CADMeshLexerState(Vertex) {
1762 if (DoesNotMatchExactly(
"vertex"))
1763 Error(
"A vertex is indicated by the tag 'vertex'.");
1767 NextState(ThreeVector);
1770inline State *STLReader::CADMeshLexerState(ThreeVector) {
1773 StartOfA(ThreeVector);
1776 Error(
"First number in three vector not found.");
1782 Error(
"Second number in three vector not found.");
1788 Error(
"Third number in three vector not found.");
1791 EndOfA(ThreeVector);
1795 if (DidNotSkipLineBreak())
1796 Error(
"Expecting a new line at the end of a three vector.");
1798 TryState(StartVertices);
1802 NextState(EndVertices);
1805inline G4bool STLReader::Read(G4String filepath) {
1806 auto items = RunLexer(filepath, StartSolid);
1808 if (items.size() == 0) {
1809 Exceptions::ParserError(
"STLReader::Read",
1810 "The STL file appears to be empty.");
1813 for (
auto item : items) {
1814 if (item.children.size() == 0) {
1815 std::stringstream error;
1816 error <<
"The mesh appears to be empty."
1817 <<
"Error around line " << item.line <<
".";
1819 Exceptions::ParserError(
"STLReader::Read", error.str());
1822 auto mesh = ParseMesh(item.children);
1824 auto name = G4String(item.value);
1825 AddMesh(Mesh::New(mesh, name));
1831inline G4bool STLReader::CanRead(Type file_type) {
return (file_type == STL); }
1833inline std::shared_ptr<Mesh> STLReader::ParseMesh(Items items) {
1834 Triangles triangles;
1836 for (
auto item : items) {
1837 if (item.children.size() == 0) {
1838 std::stringstream error;
1839 error <<
"The facet appears to be empty."
1840 <<
"Error around line " << item.line <<
".";
1842 Exceptions::ParserError(
"STLReader::Mesh", error.str());
1845 triangles.push_back(ParseFacet(item.children));
1848 return Mesh::New(triangles);
1851inline G4TriangularFacet *STLReader::ParseFacet(Items items) {
1852 Triangles triangles;
1854 for (
auto item : items) {
1855 if (item.children.size() == 0) {
1856 std::stringstream error;
1857 error <<
"The vertex appears to be empty."
1858 <<
"Error around line " << item.line <<
".";
1860 Exceptions::ParserError(
"STLReader::ParseFacet", error.str());
1863 triangles.push_back(ParseVertices(item.children));
1866 if (triangles.size() != 1) {
1867 std::stringstream error;
1868 error <<
"STL files expect exactly 1 triangle per facet.";
1870 if (items.size() != 0) {
1871 error <<
"Error around line " << items[0].line <<
".";
1874 Exceptions::ParserError(
"STLReader::ParseFacet", error.str());
1877 return triangles[0];
1880inline G4TriangularFacet *STLReader::ParseVertices(Items items) {
1881 std::vector<G4ThreeVector> vertices;
1883 for (
auto item : items) {
1884 if (item.children.size() == 0) {
1885 std::stringstream error;
1886 error <<
"The vertex appears to be empty."
1887 <<
"Error around line " << item.line <<
".";
1889 Exceptions::ParserError(
"STLReader::ParseVertices", error.str());
1892 vertices.push_back(ParseThreeVector(item.children));
1895 if (vertices.size() != 3) {
1896 std::stringstream error;
1897 error <<
"STL files expect exactly 3 vertices for a triangular facet. ";
1899 if (items.size() != 0) {
1900 error <<
"Error around line " << items[0].line <<
".";
1903 Exceptions::ParserError(
"STLReader::ParseVertices", error.str());
1906 return new G4TriangularFacet(vertices[0], vertices[1], vertices[2], ABSOLUTE);
1909inline G4ThreeVector STLReader::ParseThreeVector(Items items) {
1910 std::vector<double> numbers;
1912 for (
auto item : items) {
1913 numbers.push_back((
double)atof(item.value.c_str()));
1916 if (numbers.size() != 3) {
1917 std::stringstream error;
1918 error <<
"Three vectors in STL files require exactly 3 numbers";
1920 if (items.size() != 0) {
1921 error <<
"Error around line " << items[0].line <<
".";
1924 Exceptions::ParserError(
"STLReader::ParseThreeVector", error.str());
1927 return G4ThreeVector(numbers[0], numbers[1], numbers[2]);
1936inline State *OBJReader::CADMeshLexerState(StartSolid) {
1943 Error(
"Invalid element tag.");
1946inline State *OBJReader::CADMeshLexerState(EndSolid) {
1954inline State *OBJReader::CADMeshLexerState(Ignore) {
1955 if (DidNotSkipLine())
1956 NextState(EndSolid);
1963 NextState(EndSolid);
1966inline State *OBJReader::CADMeshLexerState(Vertex) {
1969 if (DoesNotMatchExactly(
"v "))
1970 Error(
"A vertex is indicated by the tag 'v'.");
1976 Error(
"First number in three vector not found.");
1982 Error(
"Second number in three vector not found.");
1988 Error(
"Third number in three vector not found.");
2001 NextState(EndSolid);
2004inline State *OBJReader::CADMeshLexerState(Facet) {
2007 if (DoesNotMatchExactly(
"f "))
2008 Error(
"A facet is indicated by the tag 'f'.");
2014 Error(
"First number in three vector not found.");
2025 Error(
"Second number in three vector not found.");
2036 Error(
"Third number in three vector not found.");
2058 NextState(EndSolid);
2061inline State *OBJReader::CADMeshLexerState(Object) {
2064 if (DoesNotMatchExactly(
"o "))
2065 Error(
"An object is indicated by the tag 'o'.");
2081 NextState(EndSolid);
2084inline G4bool OBJReader::Read(G4String filepath) {
2085 auto items = RunLexer(filepath, StartSolid);
2087 if (items.size() == 0) {
2088 Exceptions::ParserError(
"OBJReader::Read",
2089 "The OBJ file appears to be empty.");
2092 for (
auto item : items) {
2093 if (item.children.size() == 0) {
2097 auto mesh = ParseMesh(item.children);
2099 if (mesh->GetTriangles().size() == 0) {
2105 if (item.children[0].token == WordToken) {
2106 name = item.children[0].value;
2109 AddMesh(Mesh::New(mesh, name));
2115inline G4bool OBJReader::CanRead(Type file_type) {
return (file_type == OBJ); }
2117inline std::shared_ptr<Mesh> OBJReader::ParseMesh(Items items) {
2120 for (
auto item : items) {
2121 if (item.token != VertexToken) {
2125 if (item.children.size() == 0) {
2126 std::stringstream error;
2127 error <<
"The vertex appears to be empty."
2128 <<
"Error around line " << item.line <<
".";
2130 Exceptions::ParserError(
"OBJReader::Mesh", error.str());
2133 vertices_.push_back(ParseVertex(item.children));
2136 for (
auto item : items) {
2137 if (item.token != FacetToken) {
2141 if (item.children.size() == 0) {
2142 std::stringstream error;
2143 error <<
"The facet appears to be empty."
2144 <<
"Error around line " << item.line <<
".";
2146 Exceptions::ParserError(
"OBJReader::Mesh", error.str());
2149 facets.push_back(ParseFacet(item.children,
false));
2151 if (item.children.size() == 4) {
2152 facets.push_back(ParseFacet(item.children,
true));
2156 return Mesh::New(facets);
2159inline G4ThreeVector OBJReader::ParseVertex(Items items) {
2160 std::vector<double> numbers;
2162 for (
auto item : items) {
2163 numbers.push_back((
double)atof(item.value.c_str()));
2166 if (numbers.size() != 3) {
2167 std::stringstream error;
2168 error <<
"Three vectors in OBJ files require exactly 3 numbers";
2170 if (items.size() != 0) {
2171 error <<
"Error around line " << items[0].line <<
".";
2174 Exceptions::ParserError(
"OBJReader::ParseThreeVector", error.str());
2177 return G4ThreeVector(numbers[0], numbers[1], numbers[2]);
2180inline G4TriangularFacet *OBJReader::ParseFacet(Items items, G4bool quad) {
2181 std::vector<int> indices;
2183 for (
auto item : items) {
2184 indices.push_back((
int)atoi(item.value.c_str()));
2187 if (indices.size() < 3) {
2188 std::stringstream error;
2189 error <<
"Facets in OBJ files require at least 3 indicies";
2191 if (items.size() != 0) {
2192 error <<
"Error around line " << items[0].line <<
".";
2195 Exceptions::ParserError(
"OBJReader::ParseFacet", error.str());
2198 if (quad && indices.size() != 4) {
2199 std::stringstream error;
2200 error <<
"Trying to triangle-ify a facet that isn't a quad";
2202 if (items.size() != 0) {
2203 error <<
"Error around line " << items[0].line <<
".";
2206 Exceptions::ParserError(
"OBJReader::ParseFacet", error.str());
2210 return new G4TriangularFacet(vertices_[indices[0] - 1],
2211 vertices_[indices[2] - 1],
2212 vertices_[indices[3] - 1], ABSOLUTE);
2216 return new G4TriangularFacet(vertices_[indices[0] - 1],
2217 vertices_[indices[1] - 1],
2218 vertices_[indices[2] - 1], ABSOLUTE);
2228inline State *PLYReader::CADMeshLexerState(StartHeader) {
2229 if (DoesNotMatchExactly(
"ply"))
2230 Error(
"PLY files start with 'ply'.");
2239 Error(
"Invalid header tag.");
2242inline State *PLYReader::CADMeshLexerState(EndHeader) {
2243 if (DoesNotMatchExactly(
"end_header"))
2244 Error(
"PLY file headers end with 'end_header'.");
2246 MaybeEndOfA(Element);
2252inline State *PLYReader::CADMeshLexerState(Element) {
2253 if (DoesNotMatchExactly(
"element "))
2254 Error(
"An element is indicated by the tag 'element'.");
2256 MaybeEndOfA(Element);
2261 if (NotManyCharacters())
2262 Error(
"Element type not found.");
2268 Error(
"Element count not found.");
2276 NextState(EndHeader);
2279inline State *PLYReader::CADMeshLexerState(Property) {
2280 if (DoesNotMatchExactly(
"property "))
2281 Error(
"An property is indicated by the tag 'property'.");
2286 if (NotManyCharacters())
2287 Error(
"Element type not found.");
2301 TryState(EndHeader);
2304 NextState(EndHeader);
2307inline State *PLYReader::CADMeshLexerState(Ignore) {
2308 if (DidNotSkipLine())
2309 NextState(EndHeader);
2313 TryState(EndHeader);
2318inline State *PLYReader::CADMeshLexerState(Vertex) {
2334 Error(
"Expecting only numbers in the vertex specification.");
2351inline State *PLYReader::CADMeshLexerState(Facet) {
2367 Error(
"Expecting only numbers in the facet specification.");
2384inline G4bool PLYReader::Read(G4String filepath) {
2385 auto lexer = Lexer(filepath,
new StartHeaderState);
2386 auto items = lexer.GetItems();
2388 if (items.size() == 0) {
2389 std::stringstream error;
2390 error <<
"The header appears to be empty.";
2392 Exceptions::ParserError(
"PLYReader::Read", error.str());
2397 lexer.Run(
new VertexState, vertex_count_);
2398 auto vertex_items = lexer.GetItems();
2400 if (vertex_items.size() == 0) {
2401 Exceptions::ParserError(
"PLYReader::Read",
2402 "The PLY file appears to have no vertices.");
2405 if (vertex_items.size() != vertex_count_) {
2406 Exceptions::ParserError(
"PLYReader::Read",
2407 "The PLY file appears to be missing vertices.");
2410 lexer.Run(
new FacetState, facet_count_);
2411 auto face_items = lexer.GetItems();
2413 if (face_items.size() == 0) {
2414 Exceptions::ParserError(
"PLYReader::Read",
2415 "The PLY file appears to have no facets.");
2418 if (face_items.size() != facet_count_) {
2419 Exceptions::ParserError(
"PLYReader::Read",
2420 "The PLY file appears to be missing facets");
2423 auto mesh = ParseMesh(vertex_items, face_items);
2424 AddMesh(Mesh::New(mesh));
2429inline G4bool PLYReader::CanRead(Type file_type) {
return (file_type == PLY); }
2431inline void PLYReader::ParseHeader(Items items) {
2432 if (items.size() != 1) {
2433 std::stringstream error;
2434 error <<
"The header appears to be invalid or missing."
2435 <<
"Error around line 1.";
2437 Exceptions::ParserError(
"PLYReader::ParseHeader", error.str());
2440 for (
auto item : items[0].children) {
2441 if (item.token == ElementToken) {
2442 if (item.children.size() < 2) {
2443 std::stringstream error;
2444 error <<
"Invalid element information in header. Expecting 'vertex' or "
2445 "'face' and a number."
2446 <<
"Error around line " << item.line <<
".";
2448 Exceptions::ParserError(
"PLYReader::ParseHeader", error.str());
2451 if (item.children[0].token == WordToken &&
2452 item.children[1].token == NumberToken) {
2453 if (item.children[0].value ==
"vertex") {
2454 vertex_count_ = atoi(item.children[1].value.c_str());
2456 for (
size_t i = 2; i < item.children.size(); i++) {
2457 auto property = item.children[i];
2459 if (property.children.size() > 1) {
2460 if (property.children[1].token == WordToken) {
2461 if (property.children[1].value ==
"x") {
2465 if (property.children[1].value ==
"y") {
2469 if (property.children[1].value ==
"z") {
2477 else if (item.children[0].value ==
"face") {
2478 facet_count_ = atoi(item.children[1].value.c_str());
2480 for (
size_t i = 2; i < item.children.size(); i++) {
2481 auto property = item.children[i];
2483 if (property.children.size() > 1) {
2484 if (property.children[1].token == WordToken) {
2485 if (property.children[1].value ==
"uchar int vertex_indices") {
2486 facet_index_ = i - 2;
2496 if (vertex_count_ == 0) {
2497 std::stringstream error;
2498 error <<
"The number of vertices was not found in the header.";
2500 Exceptions::ParserError(
"PLYReader::ParseHeader", error.str());
2503 if (facet_count_ == 0) {
2504 std::stringstream error;
2505 error <<
"The number of faces was not found in the header.";
2507 Exceptions::ParserError(
"PLYReader::ParseHeader", error.str());
2510 if ((x_index_ == y_index_) || (y_index_ == z_index_) ||
2511 (x_index_ == z_index_)) {
2512 std::stringstream error;
2513 error <<
"The vertex x, y, z indices were not found in the header.";
2515 Exceptions::ParserError(
"PLYReader::ParseHeader", error.str());
2519inline std::shared_ptr<Mesh> PLYReader::ParseMesh(Items vertex_items,
2524 for (
auto item : vertex_items) {
2525 if (item.children.size() == 0) {
2526 std::stringstream error;
2527 error <<
"The vertex appears to be empty."
2528 <<
"Error around line " << item.line <<
".";
2530 Exceptions::ParserError(
"PLYReader::ParseMesh", error.str());
2533 if (item.token == VertexToken) {
2534 vertices.push_back(ParseVertex(item.children));
2538 for (
auto item : face_items) {
2539 if (item.children.size() == 0) {
2540 std::stringstream error;
2541 error <<
"The facet appears to be empty."
2542 <<
"Error around line " << item.line <<
".";
2544 Exceptions::ParserError(
"PLYReader::Mesh", error.str());
2547 if (item.token == FacetToken) {
2548 facets.push_back(ParseFacet(item.children, vertices));
2552 return Mesh::New(facets);
2555inline G4ThreeVector PLYReader::ParseVertex(Items items) {
2556 std::vector<double> numbers;
2558 for (
auto item : items) {
2559 numbers.push_back((
double)atof(item.value.c_str()));
2562 if (numbers.size() < 3) {
2563 std::stringstream error;
2564 error <<
"Vertices in PLY files require atleast 3 numbers. ";
2566 if (items.size() != 0) {
2567 error <<
"Error around line " << items[0].line <<
".";
2570 Exceptions::ParserError(
"PLYReader::ParseVertex", error.str());
2573 return G4ThreeVector(numbers[x_index_], numbers[y_index_], numbers[z_index_]);
2576inline G4TriangularFacet *PLYReader::ParseFacet(Items items, Points vertices) {
2577 std::vector<int> indices;
2579 for (
auto item : items) {
2580 indices.push_back((
int)atoi(item.value.c_str()));
2583 if (indices.size() < 4) {
2584 std::stringstream error;
2585 error <<
"Facets in PLY files require 3 indicies";
2587 if (items.size() != 0) {
2588 error <<
"Error around line " << items[0].line <<
".";
2591 Exceptions::ParserError(
"PLYReader::ParseFacet", error.str());
2594 return new G4TriangularFacet(vertices[indices[1 + facet_index_]],
2595 vertices[indices[2 + facet_index_]],
2596 vertices[indices[3 + facet_index_]], ABSOLUTE);
2601#ifdef USE_CADMESH_ASSIMP_READER
2607inline ASSIMPReader::ASSIMPReader() : Reader(
"ASSIMPReader") {
2608 importer_ =
new Assimp::Importer();
2611inline ASSIMPReader::~ASSIMPReader() {
delete importer_; }
2613inline G4bool ASSIMPReader::Read(G4String filepath) {
2614 auto scene = importer_->ReadFile(filepath.c_str(),
2615 aiProcess_Triangulate |
2616 aiProcess_JoinIdenticalVertices |
2617 aiProcess_CalcTangentSpace);
2620 Exceptions::FileNotFound(
"ASSIMP::Read", filepath);
2624 for (
unsigned int index = 0; index < scene->mNumMeshes; index++) {
2625 aiMesh *mesh = scene->mMeshes[index];
2626 auto name = mesh->mName.C_Str();
2628 Triangles triangles;
2630 for (
unsigned int i = 0; i < mesh->mNumFaces; i++) {
2631 const aiFace &face = mesh->mFaces[i];
2633 G4ThreeVector a(mesh->mVertices[face.mIndices[0]].x,
2634 mesh->mVertices[face.mIndices[0]].y,
2635 mesh->mVertices[face.mIndices[0]].z);
2637 G4ThreeVector b(mesh->mVertices[face.mIndices[1]].x,
2638 mesh->mVertices[face.mIndices[1]].y,
2639 mesh->mVertices[face.mIndices[1]].z);
2641 G4ThreeVector c(mesh->mVertices[face.mIndices[2]].x,
2642 mesh->mVertices[face.mIndices[2]].y,
2643 mesh->mVertices[face.mIndices[2]].z);
2645 triangles.push_back(
new G4TriangularFacet(a, b, c, ABSOLUTE));
2648 AddMesh(Mesh::New(triangles, name));
2654inline G4bool ASSIMPReader::CanRead(Type ) {
return true; }
2656std::shared_ptr<ASSIMPReader> ASSIMP() {
2657 return std::make_shared<ASSIMPReader>();
2667inline G4bool BuiltInReader::Read(G4String filepath) {
2668 File::Reader *reader =
nullptr;
2670 auto type = TypeFromName(filepath);
2673 reader =
new File::STLReader();
2676 else if (type == OBJ) {
2677 reader =
new File::OBJReader();
2680 else if (type == PLY) {
2681 reader =
new File::PLYReader();
2685 Exceptions::ReaderCantReadError(
"BuildInReader::Read", type, filepath);
2688 if (!reader->Read(filepath)) {
2692 SetMeshes(reader->GetMeshes());
2696inline G4bool BuiltInReader::CanRead(Type type) {
2697 return type == STL || type == OBJ || type == PLY;
2700inline std::shared_ptr<BuiltInReader> BuiltIn() {
2701 return std::make_shared<BuiltInReader>();
Definition CADMesh.hh:364
Definition CADMesh.hh:339
Definition CADMesh.hh:227
Definition CADMesh.hh:1587
Definition CADMesh.hh:1621
Definition CADMesh.hh:137
Definition CADMesh.hh:1554
Definition CADMesh.hh:104
Definition CADMesh.hh:462
Definition CADMesh.hh:223
Definition CADMesh.hh:200
Definition CADMesh.hh:219
Definition CADMesh.hh:175