OMSim
Geant4 for IceCube optical module studies
Loading...
Searching...
No Matches
CADMesh.hh
1// The MIT License (MIT)
2//
3// Copyright (c) 2011-2020 Christopher M. Poole <mail@christopherpoole.net>
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21// THE SOFTWARE.
22
23// CADMESH - Load CAD files into Geant4 quickly and easily.
24//
25// Read all about it at: https://github.com/christopherpoole/CADMesh
26//
27// Basic usage:
28//
29// #include "CADMesh.hh" // This file.
30// ...
31// auto mesh = CADMesh::TessellatedMesh::FromSTL("mesh.stl");
32// G4VSolid* solid = mesh->GetSolid();
33// ...
34//
35
36// !! THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DON'T EDIT IT DIRECTLY. !!
37
38#pragma once
39
40class BuiltInReader;
41class CADMeshTemplate;
42class Mesh;
43class STLReader;
44class ASSIMPReader;
45class PLYReader;
46class FileTypes;
47class OBJReader;
48class Exceptions;
49class TetrahedralMesh;
50class Reader;
51class Lexer;
52class LexerMacros;
53class TessellatedMesh;
54
55#include "G4String.hh"
56
57#include <algorithm>
58#include <map>
59
60namespace CADMesh {
61
62namespace File {
63
64enum Type {
65 Unknown,
66 PLY,
67 STL,
68 DAE,
69 OBJ,
70 TET,
71 OFF,
72};
73
74static std::map<Type, G4String> Extension = {
75 {Unknown, "unknown"}, {PLY, "ply"}, {STL, "stl"}, {DAE, "dae"},
76 {OBJ, "obj"}, {TET, "tet"}, {OFF, "off"}};
77
78static std::map<Type, G4String> TypeString = {
79 {Unknown, "UNKNOWN"}, {PLY, "PLY"}, {STL, "STL"}, {DAE, "DAE"},
80 {OBJ, "OBJ"}, {TET, "TET"}, {OFF, "OFF"}};
81
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)"}};
87
88Type TypeFromExtension(G4String extension);
89Type TypeFromName(G4String name);
90}
91}
92
93#include "G4ThreeVector.hh"
94#include "G4TriangularFacet.hh"
95
96#include <memory>
97#include <vector>
98
99namespace CADMesh {
100
101typedef std::vector<G4ThreeVector> Points;
102typedef std::vector<G4TriangularFacet *> Triangles;
103
104class Mesh {
105public:
106 Mesh(Points points, Triangles triangles, G4String name = "");
107
108 static std::shared_ptr<Mesh> New(Points points, Triangles triangles,
109 G4String name = "");
110
111 static std::shared_ptr<Mesh> New(Triangles triangles, G4String name = "");
112
113 static std::shared_ptr<Mesh> New(std::shared_ptr<Mesh> mesh,
114 G4String name = "");
115
116public:
117 G4String GetName();
118 Points GetPoints();
119 Triangles GetTriangles();
120
121 G4bool IsValidForNavigation();
122
123private:
124 G4String name_ = "";
125
126 Points points_;
127 Triangles triangles_;
128};
129
130typedef std::vector<std::shared_ptr<Mesh>> Meshes;
131}
132
133namespace CADMesh {
134
135namespace File {
136
137class Reader {
138public:
139 Reader(G4String reader_name);
140 ~Reader();
141
142 virtual G4bool Read(G4String filepath) = 0;
143 virtual G4bool CanRead(Type file_type) = 0;
144
145public:
146 G4String GetName();
147
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);
151
152 size_t GetNumberOfMeshes();
153
154 Meshes GetMeshes();
155
156protected:
157 size_t AddMesh(std::shared_ptr<Mesh> mesh);
158 void SetMeshes(Meshes meshs);
159
160private:
161 Meshes meshes_;
162
163 G4String name_ = "";
164};
165}
166}
167
168#include <iostream>
169#include <string>
170
171namespace CADMesh {
172
173namespace File {
174
175struct Token {
176 std::string name;
177
178 bool operator==(Token other) { return name == other.name; };
179 bool operator!=(Token other) { return name != other.name; };
180};
181
182static Token ErrorToken{"ErrorToken"};
183static Token EnfOfFileToken{"EndOfFileToken"};
184
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"};
199
200struct Item {
201 Token token;
202
203 size_t position;
204 size_t line;
205
206 std::string value;
207 std::string error;
208
209 Item *parent;
210
211 std::vector<Item> children;
212};
213
214typedef std::vector<Item> Items;
215typedef Items::iterator ItemsIterator;
216
217class Lexer;
218
219struct State {
220 virtual State *operator()(Lexer *) const = 0;
221};
222
223struct __FinalState : public State {
224 State *operator()(Lexer *) const { return nullptr; }
225};
226
227class Lexer {
228public:
229 Lexer(std::string filepath, State *initial_state = nullptr);
230
231public:
232 std::string String();
233
234 void Run(State *initial_state, size_t lines = 0);
235 Items GetItems();
236
237 void Backup();
238 void BackupTo(int position);
239
240 std::string Next();
241 std::string Peek();
242
243 void Skip();
244
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 = "");
249
250 bool OneOf(std::string possibles);
251 bool ManyOf(std::string possibles);
252 bool Until(std::string match);
253 bool MatchExactly(std::string match);
254
255 bool OneDigit();
256 bool ManyDigits();
257
258 bool OneLetter();
259 bool ManyLetters();
260
261 bool ManyCharacters();
262
263 bool Integer();
264 bool Float();
265 bool Number();
266
267 bool SkipWhiteSpace();
268 bool SkipLineBreak();
269 bool SkipLineBreaks();
270 bool SkipLine();
271
272 State *Error(std::string message);
273 State *LastError();
274
275 bool TestState(State *state);
276
277 bool IsDryRun();
278
279 void PrintMessage(std::string name, std::string message);
280 void PrintItem(Item item);
281
282 size_t LineNumber();
283
284private:
285 State *state_;
286
287 Item *parent_item_ = nullptr;
288 Items items_;
289
290 std::string input_;
291
292 size_t position_ = 0;
293 size_t start_ = 0;
294 size_t width_ = 1;
295 size_t line_ = 1;
296 size_t end_line_ = 0;
297
298 bool dry_run_ = false;
299
300 int depth_ = 0;
301
302 std::string last_error_ = "";
303};
304}
305}
306
307#ifdef USE_CADMESH_ASSIMP_READER
308
309#include "assimp/Importer.hpp"
310#include "assimp/postprocess.h"
311#include "assimp/scene.h"
312
313namespace CADMesh {
314
315namespace File {
316
317class ASSIMPReader : public File::Reader {
318public:
319 ASSIMPReader();
320 ~ASSIMPReader();
321
322public:
323 G4bool Read(G4String filepath);
324 G4bool CanRead(Type file_type);
325
326private:
327 Assimp::Importer *importer_;
328};
329
330std::shared_ptr<ASSIMPReader> ASSIMP();
331}
332}
333#endif
334
335namespace CADMesh {
336
337namespace File {
338
339class BuiltInReader : public Reader {
340public:
341 BuiltInReader() : Reader("BuiltInReader"){};
342
343public:
344 G4bool Read(G4String filepath);
345 G4bool CanRead(File::Type file_type);
346};
347
348std::shared_ptr<BuiltInReader> BuiltIn();
349}
350}
351#ifndef CADMESH_DEFAULT_READER
352#define CADMESH_DEFAULT_READER BuiltIn
353#endif
354
355#include "G4AssemblyVolume.hh"
356#include "G4LogicalVolume.hh"
357#include "G4Material.hh"
358#include "G4TessellatedSolid.hh"
359#include "G4Tet.hh"
360#include "G4UIcommand.hh"
361
362namespace CADMesh {
363
364template <typename T> class CADMeshTemplate {
365public:
367
368 CADMeshTemplate(G4String file_name);
369
370 CADMeshTemplate(G4String file_name, File::Type file_type);
371
372 CADMeshTemplate(std::shared_ptr<File::Reader> reader);
373
374 CADMeshTemplate(G4String file_name, std::shared_ptr<File::Reader> reader);
375
376 CADMeshTemplate(G4String file_name, File::Type file_type,
377 std::shared_ptr<File::Reader> reader);
378
379 static std::shared_ptr<T> From(G4String file_name);
380
381 static std::shared_ptr<T> From(G4String file_name,
382 std::shared_ptr<File::Reader> reader);
383
384 static std::shared_ptr<T> FromPLY(G4String file_name);
385
386 static std::shared_ptr<T> FromPLY(G4String file_name,
387 std::shared_ptr<File::Reader> reader);
388
389 static std::shared_ptr<T> FromSTL(G4String file_name);
390
391 static std::shared_ptr<T> FromSTL(G4String file_name,
392 std::shared_ptr<File::Reader> reader);
393
394 static std::shared_ptr<T> FromOBJ(G4String file_name);
395
396 static std::shared_ptr<T> FromOBJ(G4String file_name,
397 std::shared_ptr<File::Reader> reader);
398
400
401public:
402 virtual G4VSolid *GetSolid() = 0;
403 virtual G4VSolid *GetSolid(G4int index) = 0;
404 virtual G4VSolid *GetSolid(G4String name, G4bool exact = true) = 0;
405
406 virtual std::vector<G4VSolid *> GetSolids() = 0;
407
408 virtual G4AssemblyVolume *GetAssembly() = 0;
409
410 bool IsValidForNavigation();
411
412public:
413 G4String GetFileName();
414
415 File::Type GetFileType();
416
417 void SetVerbose(G4int verbose);
418 G4int GetVerbose();
419
420 void SetScale(G4double scale);
421 G4double GetScale();
422
423 void SetOffset(G4double x, G4double y, G4double z);
424 void SetOffset(G4ThreeVector offset);
425 G4ThreeVector GetOffset();
426
427protected:
428 G4String file_name_;
429 File::Type file_type_;
430 G4int verbose_;
431 G4double scale_;
432 G4ThreeVector offset_;
433
434 G4AssemblyVolume *assembly_ = nullptr;
435
436 std::shared_ptr<File::Reader> reader_ = nullptr;
437};
438}
439
440#include "globals.hh"
441
442namespace CADMesh {
443
444namespace Exceptions {
445
446void FileNotFound(G4String origin, G4String filepath);
447
448void LexerError(G4String origin, G4String message);
449
450void ParserError(G4String origin, G4String message);
451
452void ReaderCantReadError(G4String origin, File::Type file_type,
453 G4String filepath);
454
455void MeshNotFound(G4String origin, size_t index);
456void MeshNotFound(G4String origin, G4String name);
457}
458}
459
460namespace CADMesh {
461
462class TessellatedMesh : public CADMeshTemplate<TessellatedMesh> {
463 using CADMeshTemplate::CADMeshTemplate;
464
465public:
466 G4VSolid *GetSolid();
467 G4VSolid *GetSolid(G4int index);
468 G4VSolid *GetSolid(G4String name, G4bool exact = true);
469
470 std::vector<G4VSolid *> GetSolids();
471
472 G4TessellatedSolid *GetTessellatedSolid();
473 G4TessellatedSolid *GetTessellatedSolid(G4int index);
474 G4TessellatedSolid *GetTessellatedSolid(G4String name, G4bool exact = true);
475 G4TessellatedSolid *GetTessellatedSolid(std::shared_ptr<Mesh> mesh);
476
477 G4AssemblyVolume *GetAssembly();
478
479public:
480 void SetReverse(G4bool reverse) { this->reverse_ = reverse; };
481
482 G4bool GetReverse() { return this->reverse_; };
483
484private:
485 G4bool reverse_;
486};
487}
488
489#ifdef USE_CADMESH_TETGEN
490
491#include "tetgen.h"
492
493namespace CADMesh {
494
495class TetrahedralMesh : public CADMeshTemplate<TetrahedralMesh> {
496public:
497 using CADMeshTemplate::CADMeshTemplate;
498
499 TetrahedralMesh();
500 ~TetrahedralMesh();
501
502public:
503 G4VSolid *GetSolid();
504 G4VSolid *GetSolid(G4int index);
505 G4VSolid *GetSolid(G4String name, G4bool exact = true);
506
507 std::vector<G4VSolid *> GetSolids();
508
509 G4AssemblyVolume *GetAssembly();
510
511public:
512 void SetMaterial(G4Material *material) { this->material_ = material; };
513
514 G4Material *GetMaterial() { return this->material_; };
515
516 void SetQuality(G4double quality) { this->quality_ = quality; };
517
518 G4double GetQuality() { return this->quality_; };
519
520 std::shared_ptr<tetgenio> GetTetgenInput() { return in_; };
521
522 std::shared_ptr<tetgenio> GetTetgenOutput() { return out_; };
523
524private:
525 G4ThreeVector GetTetPoint(G4int index_offset);
526
527private:
528 std::shared_ptr<tetgenio> in_ = nullptr;
529 std::shared_ptr<tetgenio> out_ = nullptr;
530
531 G4double quality_;
532
533 G4Material *material_;
534};
535}
536#endif
537
538namespace CADMesh {
539
540namespace File {
541
542inline Type TypeFromExtension(G4String extension) {
543 std::for_each(extension.begin(), extension.end(),
544 [](char &e) { e = ::tolower(e); });
545
546 for (auto e = Extension.begin(); e != Extension.end(); ++e) {
547 if (e->second == extension) {
548 return e->first;
549 }
550 }
551
552 return Unknown;
553}
554
555inline Type TypeFromName(G4String name) {
556 auto extension = name.substr(name.find_last_of(".") + 1);
557
558 return TypeFromExtension(extension);
559}
560}
561}
562
563namespace CADMesh {
564
565inline Mesh::Mesh(Points points, Triangles triangles, G4String name)
566 : name_(name), points_(points), triangles_(triangles) {}
567
568inline std::shared_ptr<Mesh> Mesh::New(Points points, Triangles triangles,
569 G4String name) {
570 return std::make_shared<Mesh>(points, triangles, name);
571}
572
573inline std::shared_ptr<Mesh> Mesh::New(Triangles triangles, G4String name) {
574 Points points;
575
576 return New(points, triangles, name);
577}
578
579inline std::shared_ptr<Mesh> Mesh::New(std::shared_ptr<Mesh> mesh,
580 G4String name) {
581 return New(mesh->GetPoints(), mesh->GetTriangles(), name);
582}
583
584inline G4String Mesh::GetName() { return name_; }
585
586inline Points Mesh::GetPoints() { return points_; }
587
588inline Triangles Mesh::GetTriangles() { return triangles_; }
589
590inline G4bool Mesh::IsValidForNavigation() {
591 std::map<G4ThreeVector, size_t> point_index;
592
593 size_t index = 0;
594 for (auto point : points_) {
595 point_index[point] = index;
596 index++;
597 }
598
599 typedef std::pair<size_t, size_t> Edge;
600 std::map<Edge, G4int> edge_use_count;
601
602 for (size_t i = 0; i < triangles_.size(); i++) {
603 auto triangle = triangles_[i];
604
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)];
608
609 if (a < b) {
610 edge_use_count[Edge(a, b)] += 1;
611 }
612
613 else if (a > b) {
614 edge_use_count[Edge(b, a)] += 1;
615 }
616
617 if (b < c) {
618 edge_use_count[Edge(b, c)] += 1;
619 }
620
621 else if (b > c) {
622 edge_use_count[Edge(c, b)] += 1;
623 }
624
625 if (c < a) {
626 edge_use_count[Edge(c, a)] += 1;
627 }
628
629 else if (c > a) {
630 edge_use_count[Edge(a, c)] += 1;
631 }
632 }
633
634 for (auto count : edge_use_count) {
635 if (count.second != 2) {
636 return false;
637 }
638 }
639
640 return true;
641}
642}
643
644namespace CADMesh {
645
646namespace File {
647
648inline Reader::Reader(G4String reader_name) : name_(reader_name) {}
649
650inline Reader::~Reader() {}
651
652inline G4String Reader::GetName() { return name_; }
653
654inline std::shared_ptr<Mesh> Reader::GetMesh() {
655 if (meshes_.size() > 0) {
656 return meshes_[0];
657 }
658
659 return nullptr;
660}
661
662inline std::shared_ptr<Mesh> Reader::GetMesh(size_t index) {
663 if (index < meshes_.size()) {
664 return meshes_[index];
665 }
666
667 Exceptions::MeshNotFound("Reader::GetMesh", index);
668
669 return nullptr;
670}
671
672inline std::shared_ptr<Mesh> Reader::GetMesh(G4String name, G4bool exact) {
673 for (auto mesh : meshes_) {
674 if (exact) {
675 if (mesh->GetName() == name)
676 return mesh;
677 }
678
679 else {
680 if (mesh->GetName().find(name) != std::string::npos)
681 return mesh;
682 }
683 }
684
685 Exceptions::MeshNotFound("Reader::GetMesh", name);
686
687 return nullptr;
688}
689
690inline Meshes Reader::GetMeshes() { return meshes_; }
691
692inline size_t Reader::GetNumberOfMeshes() { return meshes_.size(); }
693
694inline size_t Reader::AddMesh(std::shared_ptr<Mesh> mesh) {
695 meshes_.push_back(mesh);
696
697 return meshes_.size();
698}
699
700inline void Reader::SetMeshes(Meshes meshes) { meshes_ = meshes; }
701}
702}
703
704#include <fstream>
705#include <sstream>
706#include <streambuf>
707
708namespace CADMesh {
709
710namespace File {
711
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>());
716
717 if (initial_state) {
718 Run(initial_state);
719 }
720}
721
722inline std::string Lexer::String() {
723 return input_.substr(start_, position_ - start_);
724}
725
726inline void Lexer::Run(State *initial_state, size_t lines) {
727 parent_item_ = new Item{ParentToken, position_, line_, "", "",
728 nullptr, std::vector<Item>()};
729
730 state_ = initial_state;
731
732 end_line_ = 0;
733
734 if (lines > 0)
735 end_line_ = line_ + lines;
736
737 while (state_) {
738 state_ = (*state_)(this);
739 }
740}
741
742inline Items Lexer::GetItems() { return parent_item_->children; }
743
744inline void Lexer::Backup() {
745 position_ -= width_;
746
747 auto next = input_.substr(position_, 1);
748
749 if (next == "\n") {
750 line_--;
751 }
752}
753
754inline void Lexer::BackupTo(int position) {
755 auto s = input_.substr(position, position_ - position);
756 line_ -= std::count(s.begin(), s.end(), '\n');
757
758 position_ = position;
759}
760
761inline std::string Lexer::Next() {
762 if (position_ >= input_.length()) {
763 return "";
764 }
765
766 auto next = input_.substr(position_, 1);
767
768 width_ = 1;
769 position_ += width_;
770
771 if (next == "\n")
772 line_++;
773
774 return next;
775}
776
777inline std::string Lexer::Peek() {
778 auto next = Next();
779
780 if (next != "")
781 Backup();
782
783 return next;
784}
785
786inline void Lexer::Skip() { start_ = position_; }
787
788inline Item *Lexer::ThisIsA(Token token, std::string error) {
789 if (dry_run_)
790 return nullptr;
791
792 auto item =
793 Item{token, position_, line_, String(), error, parent_item_, Items()};
794 Skip();
795
796 if (parent_item_) {
797 PrintItem(item);
798
799 parent_item_->children.push_back(item);
800 return &(parent_item_->children.back());
801 }
802
803 else {
804 depth_++;
805 PrintItem(item);
806
807 items_.push_back(item);
808 return &(items_.back());
809 }
810}
811
812inline Item *Lexer::StartOfA(Token token, std::string error) {
813 if (dry_run_)
814 return nullptr;
815
816 parent_item_ = ThisIsA(token, error);
817
818 depth_++;
819
820 return parent_item_;
821}
822
823inline Item *Lexer::EndOfA(Token token, std::string /*error*/) {
824 if (dry_run_)
825 return nullptr;
826
827 depth_--;
828
829 PrintItem(*parent_item_);
830
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.");
835 }
836
837 if (parent_item_) {
838 parent_item_ = parent_item_->parent;
839 }
840
841 return nullptr;
842}
843
844inline Item *Lexer::MaybeEndOfA(Token token, std::string error) {
845 if (parent_item_->token.name == token.name) {
846 return EndOfA(token, error);
847 }
848
849 else {
850 return nullptr;
851 }
852}
853
854inline bool Lexer::OneOf(std::string possibles) {
855 auto peek = Peek();
856
857 size_t position = possibles.find(Peek());
858
859 if (position != std::string::npos) {
860 auto next = Next();
861 return next != "";
862 }
863
864 return false;
865}
866
867inline bool Lexer::ManyOf(std::string possibles) {
868 bool has = false;
869
870 while (OneOf(possibles)) {
871 has = true;
872 }
873
874 return has;
875}
876
877inline bool Lexer::Until(std::string match) {
878 while (!OneOf(match)) {
879 if (Next() == "")
880 return false;
881 }
882
883 return true;
884}
885
886inline bool Lexer::MatchExactly(std::string match) {
887 auto start_position = position_;
888
889 for (auto m : match) {
890 if (!OneOf(std::string(1, m))) {
891 BackupTo(start_position);
892 return false;
893 }
894 }
895
896 return true;
897}
898
899inline bool Lexer::OneDigit() { return OneOf("0123456789"); }
900
901inline bool Lexer::ManyDigits() { return ManyOf("0123456789"); }
902
903inline bool Lexer::OneLetter() {
904 return OneOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
905}
906
907inline bool Lexer::ManyLetters() {
908 return ManyOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
909}
910
911inline bool Lexer::ManyCharacters() {
912 return ManyOf("!\"#$%&\\\'()*+,-./"
913 "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[|]^_`"
914 "abcdefghijklmnopqrstuvwxyz{}~");
915}
916
917inline bool Lexer::Integer() {
918 auto start_position = position_;
919
920 OneOf("+-");
921
922 if (!ManyDigits()) {
923 BackupTo(start_position);
924 return false;
925 }
926
927 return true;
928}
929
930inline bool Lexer::Float() {
931 auto start_position = position_;
932
933 OneOf("+-");
934
935 bool has_integer = Integer();
936
937 if (!OneOf(".")) {
938 BackupTo(start_position);
939 return false;
940 }
941
942 bool has_decimal = ManyDigits();
943
944 if (!has_integer || !has_decimal) {
945 BackupTo(start_position);
946 return false;
947 }
948
949 return true;
950}
951
952inline bool Lexer::Number() {
953 if (!Float()) {
954 if (!Integer()) {
955 return false;
956 }
957 }
958
959 auto start_position = position_;
960
961 if (OneOf("eE")) {
962 if (!Float()) {
963 if (!Integer()) {
964 BackupTo(start_position);
965 }
966 }
967 }
968
969 return true;
970}
971
972inline bool Lexer::SkipWhiteSpace() {
973 if (!ManyOf(" \t\r")) {
974 Skip();
975 return false;
976 }
977
978 Skip();
979 return true;
980}
981
982inline bool Lexer::SkipLineBreak() {
983 if (!OneOf("\n")) {
984 return false;
985 }
986
987 Skip();
988 return true;
989}
990
991inline bool Lexer::SkipLineBreaks() {
992 if (!ManyOf("\n")) {
993 return false;
994 }
995
996 Skip();
997 return true;
998}
999
1000inline bool Lexer::SkipLine() {
1001 if (!Until("\n")) {
1002 return false;
1003 }
1004
1005 Skip();
1006 return true;
1007}
1008
1009inline State *Lexer::Error(std::string message) {
1010
1011 std::stringstream error;
1012 error << "Error around line " << line_ << ": " << message << std::endl;
1013
1014 last_error_ = error.str();
1015
1016 if (dry_run_)
1017 return nullptr;
1018
1019 Item item{ErrorToken, position_, line_, "",
1020 error.str(), parent_item_, Items()};
1021 items_.push_back(item);
1022
1023 Exceptions::LexerError("Lexer", error.str());
1024
1025 return nullptr;
1026}
1027
1028inline State *Lexer::LastError() {
1029 if (last_error_ == "") {
1030 Exceptions::LexerError("Lexer", "Something went wrong.");
1031 }
1032
1033 else {
1034 Exceptions::LexerError("Lexer", last_error_);
1035 }
1036
1037 return nullptr;
1038}
1039
1040inline bool Lexer::TestState(State *state) {
1041 if (dry_run_)
1042 return false;
1043
1044 if (end_line_ > 0 && line_ > end_line_)
1045 return false;
1046
1047 auto start_position = position_;
1048
1049 dry_run_ = true;
1050
1051 bool state_transition = ((*state)(this) != nullptr);
1052
1053 dry_run_ = false;
1054
1055 BackupTo(start_position);
1056
1057 return state_transition;
1058}
1059
1060inline bool Lexer::IsDryRun() { return dry_run_; }
1061
1062inline size_t Lexer::LineNumber() { return line_; }
1063
1064#ifdef CADMESH_LEXER_VERBOSE
1065inline void Lexer::PrintMessage(std::string name, std::string message) {
1066 std::cout << "Lexer::" << name << " : " << message << std::endl;
1067}
1068#else
1069inline void Lexer::PrintMessage(std::string, std::string) {}
1070#endif
1071
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
1076 << std::endl;
1077}
1078#else
1079inline void Lexer::PrintItem(Item) {}
1080#endif
1081}
1082}
1083
1084namespace CADMesh {
1085
1086template <typename T>
1087CADMeshTemplate<T>::CADMeshTemplate() : CADMeshTemplate<T>("") {}
1088
1089template <typename T>
1090CADMeshTemplate<T>::CADMeshTemplate(G4String file_name)
1091 : CADMeshTemplate<T>(file_name, File::Unknown) {}
1092
1093template <typename T>
1094CADMeshTemplate<T>::CADMeshTemplate(G4String file_name, File::Type file_type)
1095 : CADMeshTemplate<T>(file_name, file_type, File::CADMESH_DEFAULT_READER()) {
1096}
1097
1098template <typename T>
1099CADMeshTemplate<T>::CADMeshTemplate(std::shared_ptr<File::Reader> reader)
1100 : CADMeshTemplate<T>("", reader) {}
1101
1102template <typename T>
1103CADMeshTemplate<T>::CADMeshTemplate(G4String file_name,
1104 std::shared_ptr<File::Reader> reader)
1105 : CADMeshTemplate<T>(file_name, File::Unknown, reader) {}
1106
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);
1112 }
1113
1114 file_name_ = file_name;
1115 file_type_ = file_type;
1116
1117 scale_ = 1.0;
1118
1119 offset_ = G4ThreeVector();
1120
1121 verbose_ = 0;
1122
1123 reader_ = reader;
1124
1125 reader_->Read(file_name_);
1126}
1127
1128template <typename T>
1129std::shared_ptr<T> CADMeshTemplate<T>::From(G4String file_name) {
1130 return std::make_shared<T>(file_name);
1131}
1132
1133template <typename T>
1134std::shared_ptr<T>
1135CADMeshTemplate<T>::From(G4String file_name,
1136 std::shared_ptr<File::Reader> reader) {
1137 return std::make_shared<T>(file_name, reader);
1138}
1139
1140template <typename T>
1141std::shared_ptr<T> CADMeshTemplate<T>::FromPLY(G4String file_name) {
1142 return std::make_shared<T>(file_name, File::PLY);
1143}
1144
1145template <typename T>
1146std::shared_ptr<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);
1150}
1151
1152template <typename T>
1153std::shared_ptr<T> CADMeshTemplate<T>::FromSTL(G4String file_name) {
1154 return std::make_shared<T>(file_name, File::STL);
1155}
1156
1157template <typename T>
1158std::shared_ptr<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);
1162}
1163
1164template <typename T>
1165std::shared_ptr<T> CADMeshTemplate<T>::FromOBJ(G4String file_name) {
1166 return std::make_shared<T>(file_name, File::OBJ);
1167}
1168
1169template <typename T>
1170std::shared_ptr<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);
1174}
1175
1176template <typename T> CADMeshTemplate<T>::~CADMeshTemplate() {}
1177
1178template <typename T> bool CADMeshTemplate<T>::IsValidForNavigation() {
1179 return reader_->GetMesh()->IsValidForNavigation();
1180}
1181
1182template <typename T> G4String CADMeshTemplate<T>::GetFileName() {
1183 return file_name_;
1184}
1185
1186template <typename T> File::Type CADMeshTemplate<T>::GetFileType() {
1187 return file_type_;
1188}
1189
1190template <typename T> void CADMeshTemplate<T>::SetVerbose(G4int verbose) {
1191 verbose_ = verbose;
1192}
1193
1194template <typename T> G4int CADMeshTemplate<T>::GetVerbose() {
1195 return verbose_;
1196}
1197
1198template <typename T> void CADMeshTemplate<T>::SetScale(G4double scale) {
1199 scale_ = scale;
1200}
1201
1202template <typename T> G4double CADMeshTemplate<T>::GetScale() { return scale_; }
1203
1204template <typename T>
1205void CADMeshTemplate<T>::SetOffset(G4double x, G4double y, G4double z) {
1206 SetOffset(G4ThreeVector(x, y, z));
1207}
1208
1209template <typename T> void CADMeshTemplate<T>::SetOffset(G4ThreeVector offset) {
1210 offset_ = offset;
1211}
1212
1213template <typename T> G4ThreeVector CADMeshTemplate<T>::GetOffset() {
1214 return offset_;
1215}
1216}
1217
1218namespace CADMesh {
1219
1220namespace Exceptions {
1221
1222inline void FileNotFound(G4String origin, G4String filepath) {
1223 G4Exception(
1224 ("CADMesh in " + origin).c_str(), "FileNotFound", FatalException,
1225 ("\nThe file: \n\t" + filepath + "\ncould not be found.").c_str());
1226}
1227
1228inline void LexerError(G4String origin, G4String message) {
1229 G4Exception(
1230 ("CADMesh in " + origin).c_str(), "LexerError", FatalException,
1231 ("\nThe CAD file appears to contain incorrect syntax:\n\t" + message)
1232 .c_str());
1233}
1234
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)
1238 .c_str());
1239}
1240
1241inline void ReaderCantReadError(G4String origin, File::Type file_type,
1242 G4String filepath) {
1243 G4Exception(
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)
1248 .c_str());
1249}
1250
1251inline void MeshNotFound(G4String origin, size_t index) {
1252 std::stringstream message;
1253 message << "\nThe mesh with index '" << index << "' could not be found.";
1254
1255 G4Exception(("CADMesh in " + origin).c_str(), "MeshNotFound", FatalException,
1256 message.str().c_str());
1257}
1258
1259inline void MeshNotFound(G4String origin, G4String name) {
1260 G4Exception(
1261 ("CADMesh in " + origin).c_str(), "MeshNotFound", FatalException,
1262 ("\nThe mesh with name '" + name + "' could not be found.").c_str());
1263}
1264}
1265}
1266
1267#include "Randomize.hh"
1268
1269namespace CADMesh {
1270
1271inline G4VSolid *TessellatedMesh::GetSolid() {
1272 return (G4VSolid *)GetTessellatedSolid();
1273}
1274
1275inline G4VSolid *TessellatedMesh::GetSolid(G4int index) {
1276 return (G4VSolid *)GetTessellatedSolid(index);
1277}
1278
1279inline G4VSolid *TessellatedMesh::GetSolid(G4String name, G4bool exact) {
1280 return (G4VSolid *)GetTessellatedSolid(name, exact);
1281}
1282
1283inline std::vector<G4VSolid *> TessellatedMesh::GetSolids() {
1284 std::vector<G4VSolid *> solids;
1285
1286 for (auto mesh : reader_->GetMeshes()) {
1287 solids.push_back(GetTessellatedSolid(mesh));
1288 }
1289
1290 return solids;
1291}
1292
1293inline G4AssemblyVolume *TessellatedMesh::GetAssembly() {
1294 if (assembly_) {
1295 return assembly_;
1296 }
1297
1298 for (auto mesh : reader_->GetMeshes()) {
1299 auto solid = GetTessellatedSolid(mesh);
1300
1301 G4Material *material = nullptr;
1302
1303 auto logical =
1304 new G4LogicalVolume(solid, material, mesh->GetName() + "_logical");
1305
1306 G4ThreeVector position = G4ThreeVector();
1307 G4RotationMatrix *rotation = new G4RotationMatrix();
1308
1309 assembly_->AddPlacedVolume(logical, position, rotation);
1310 }
1311
1312 return assembly_;
1313}
1314
1315inline G4TessellatedSolid *TessellatedMesh::GetTessellatedSolid() {
1316 return GetTessellatedSolid(0);
1317}
1318
1319inline G4TessellatedSolid *TessellatedMesh::GetTessellatedSolid(G4int index) {
1320 return GetTessellatedSolid(reader_->GetMesh(index));
1321}
1322
1323inline G4TessellatedSolid *TessellatedMesh::GetTessellatedSolid(G4String name,
1324 G4bool exact) {
1325 return GetTessellatedSolid(reader_->GetMesh(name, exact));
1326}
1327
1328inline G4TessellatedSolid *
1329TessellatedMesh::GetTessellatedSolid(std::shared_ptr<Mesh> mesh) {
1330 auto volume_solid = new G4TessellatedSolid(mesh->GetName());
1331
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_;
1336
1337 auto t = new G4TriangularFacet(a, b, c, ABSOLUTE);
1338
1339 if (reverse_) {
1340 volume_solid->AddFacet((G4VFacet *)t->GetFlippedFacet());
1341 }
1342
1343 else {
1344 volume_solid->AddFacet((G4VFacet *)t);
1345 }
1346 }
1347
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.");
1353 return nullptr;
1354 }
1355 return volume_solid;
1356}
1357}
1358
1359#ifdef USE_CADMESH_TETGEN
1360
1361namespace CADMesh {
1362
1363inline TetrahedralMesh::TetrahedralMesh() {}
1364
1365inline TetrahedralMesh::~TetrahedralMesh() {}
1366
1367inline G4VSolid *TetrahedralMesh::GetSolid() { return GetSolid(0); }
1368
1369inline G4VSolid *TetrahedralMesh::GetSolid(G4int /*index*/) { return nullptr; }
1370
1371inline G4VSolid *TetrahedralMesh::GetSolid(G4String /*name*/,
1372 G4bool /*exact*/) {
1373
1374 return nullptr;
1375}
1376
1377inline std::vector<G4VSolid *> TetrahedralMesh::GetSolids() {
1378
1379 return std::vector<G4VSolid *>();
1380}
1381
1382inline G4AssemblyVolume *TetrahedralMesh::GetAssembly() {
1383 if (assembly_) {
1384 return assembly_;
1385 }
1386
1387 assembly_ = new G4AssemblyVolume();
1388
1389 in_ = std::make_shared<tetgenio>();
1390 out_ = std::make_shared<tetgenio>();
1391
1392 char *fn = (char *)file_name_.c_str();
1393
1394 G4bool do_tet = true;
1395
1396 if (file_type_ == File::STL) {
1397 in_->load_stl(fn);
1398 }
1399
1400 else if (file_type_ == File::PLY) {
1401 in_->load_ply(fn);
1402 }
1403
1404 else if (file_type_ == File::TET) {
1405 out_->load_tetmesh(fn, 0);
1406 do_tet = false;
1407 }
1408
1409 else if (file_type_ == File::OFF) {
1410 out_->load_off(fn);
1411 do_tet = false;
1412 }
1413
1414 if (do_tet) {
1415 tetgenbehavior *behavior = new tetgenbehavior();
1416 behavior->nobisect = 1;
1417 behavior->plc = 1;
1418 behavior->quality = quality_;
1419
1420 tetrahedralize(behavior, in_.get(), out_.get());
1421 }
1422
1423 G4RotationMatrix *element_rotation = new G4RotationMatrix();
1424 G4ThreeVector element_position = G4ThreeVector();
1425 G4Transform3D assembly_transform = G4Translate3D();
1426
1427 for (int i = 0; i < out_->numberoftetrahedra; i++) {
1428 int index_offset = i * 4;
1429
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);
1434
1435 G4String tet_name =
1436 file_name_ + G4String("_tet_") + G4UIcommand::ConvertToString(i);
1437
1438 auto tet_solid =
1439 new G4Tet(tet_name + G4String("_solid"), p1, p2, p3, p4, 0);
1440
1441 auto tet_logical = new G4LogicalVolume(
1442 tet_solid, material_, tet_name + G4String("_logical"), 0, 0, 0);
1443
1444 assembly_->AddPlacedVolume(tet_logical, element_position, element_rotation);
1445 }
1446
1447 return assembly_;
1448}
1449
1450inline G4ThreeVector TetrahedralMesh::GetTetPoint(G4int index_offset) {
1451 return G4ThreeVector(
1452 out_->pointlist[out_->tetrahedronlist[index_offset] * 3] * scale_ -
1453 offset_.x(),
1454 out_->pointlist[out_->tetrahedronlist[index_offset] * 3 + 1] * scale_ -
1455 offset_.y(),
1456 out_->pointlist[out_->tetrahedronlist[index_offset] * 3 + 2] * scale_ -
1457 offset_.z());
1458}
1459}
1460#endif
1461
1462#define CADMeshLexerToken(name) \
1463 static Token name##Token { #name }
1464
1465#define CADMeshLexerStateDefinition(name) \
1466 struct name##State : public State { \
1467 State *operator()(Lexer *lexer) const; \
1468 }
1469
1470#define CADMeshLexerState(name) name##State::operator()(Lexer *lexer) const
1471
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)
1476
1477#define Skip() lexer->Skip()
1478
1479#define Next() lexer->Peek()
1480#define PrintNext() std::cout << lexer->Peek() << std::endl;
1481
1482#define OneOf(possibles) lexer->OneOf(possibles)
1483#define NotOneOf(possibles) !OneOf(possibles)
1484
1485#define ManyOf(possibles) lexer->ManyOf(possibles)
1486#define NotManyOf(possibles) !ManyOf(possibles)
1487
1488#define Until(match) lexer->Until(match)
1489
1490#define RestOfLine() \
1491 if (Until("\n\r")) \
1492 lexer->Backup()
1493
1494#define MatchExactly(match) lexer->MatchExactly(match)
1495#define DoesNotMatchExactly(match) !MatchExactly(match)
1496
1497#define OneDigit() lexer->OneDigit()
1498#define NotOneDigit() !OneDigit()
1499
1500#define ManyDigits() lexer->ManyDigits()
1501#define NotManyDigits() !ManyDigits()
1502
1503#define OneLetter() lexer->OneLetter()
1504#define NotOneLetter() !OneLetter()
1505
1506#define ManyLetters() lexer->ManyLetters()
1507#define NotManyLetters() !ManyLetters()
1508
1509#define ManyCharacters() lexer->ManyCharacters()
1510#define NotManyCharacters() !ManyCharacters()
1511
1512#define Integer() lexer->Integer()
1513#define NotAnInteger() !Integer()
1514
1515#define Float() lexer->Float()
1516#define NotAFloat() !Float()
1517
1518#define Number() lexer->Number()
1519#define NotANumber() !Number()
1520
1521#define SkipWhiteSpace() lexer->SkipWhiteSpace()
1522#define DidNotSkipWhiteSpace() !SkipWhiteSpace()
1523
1524#define SkipLineBreak() lexer->SkipLineBreak()
1525#define DidNotSkipLineBreak() !SkipLineBreak()
1526
1527#define SkipLineBreaks() lexer->SkipLineBreaks()
1528#define DidNotSkipLineBreaks() !SkipLineBreaks()
1529
1530#define SkipLine() lexer->SkipLine()
1531#define DidNotSkipLine() !SkipLine()
1532
1533#define AtEndOfLine() Next() == "\n" || Next() == "\r"
1534
1535#define Error(message) \
1536 { \
1537 lexer->Error(message); \
1538 return nullptr; \
1539 }
1540
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)) \
1545 NextState(next)
1546#define FinalState() return new __FinalState();
1547
1548#define RunLexer(filepath, start) Lexer(filepath, new start##State).GetItems()
1549
1550namespace CADMesh {
1551
1552namespace File {
1553
1554class STLReader : public Reader {
1555public:
1556 STLReader() : Reader("STLReader"){};
1557
1558 G4bool Read(G4String filepath);
1559 G4bool CanRead(Type file_type);
1560
1561protected:
1562 CADMeshLexerStateDefinition(StartSolid);
1563 CADMeshLexerStateDefinition(EndSolid);
1564
1565 CADMeshLexerStateDefinition(StartFacet);
1566 CADMeshLexerStateDefinition(EndFacet);
1567
1568 CADMeshLexerStateDefinition(StartVertices);
1569 CADMeshLexerStateDefinition(EndVertices);
1570
1571 CADMeshLexerStateDefinition(Vertex);
1572
1573 CADMeshLexerStateDefinition(ThreeVector);
1574
1575 std::shared_ptr<Mesh> ParseMesh(Items items);
1576 G4TriangularFacet *ParseFacet(Items items);
1577 G4TriangularFacet *ParseVertices(Items items);
1578 G4ThreeVector ParseThreeVector(Items items);
1579};
1580}
1581}
1582
1583namespace CADMesh {
1584
1585namespace File {
1586
1587class OBJReader : public Reader {
1588public:
1589 OBJReader() : Reader("OBJReader"){};
1590
1591 G4bool Read(G4String filepath);
1592 G4bool CanRead(Type file_type);
1593
1594protected:
1595 CADMeshLexerStateDefinition(StartSolid);
1596 CADMeshLexerStateDefinition(EndSolid);
1597
1598 CADMeshLexerStateDefinition(Ignore);
1599 CADMeshLexerStateDefinition(Vertex);
1600 CADMeshLexerStateDefinition(Facet);
1601 CADMeshLexerStateDefinition(Object);
1602
1603 std::shared_ptr<Mesh> ParseMesh(Items items);
1604 G4ThreeVector ParseVertex(Items items);
1605 G4TriangularFacet *ParseFacet(Items items, G4bool quad);
1606
1607private:
1608 Points vertices_;
1609};
1610}
1611}
1612
1613namespace CADMesh {
1614
1615namespace File {
1616
1617CADMeshLexerToken(Header);
1618CADMeshLexerToken(Element);
1619CADMeshLexerToken(Property);
1620
1621class PLYReader : public Reader {
1622public:
1623 PLYReader() : Reader("PLYReader"){};
1624
1625 G4bool Read(G4String filepath);
1626 G4bool CanRead(Type file_type);
1627
1628protected:
1629 CADMeshLexerStateDefinition(StartHeader);
1630 CADMeshLexerStateDefinition(EndHeader);
1631
1632 CADMeshLexerStateDefinition(Element);
1633 CADMeshLexerStateDefinition(Property);
1634 CADMeshLexerStateDefinition(Ignore);
1635
1636 CADMeshLexerStateDefinition(Vertex);
1637 CADMeshLexerStateDefinition(Facet);
1638
1639 void ParseHeader(Items items);
1640
1641 std::shared_ptr<Mesh> ParseMesh(Items vertex_items, Items face_items);
1642 G4ThreeVector ParseVertex(Items items);
1643 G4TriangularFacet *ParseFacet(Items items, Points vertices);
1644
1645 size_t vertex_count_ = 0;
1646 size_t facet_count_ = 0;
1647
1648 size_t x_index_ = 0;
1649 size_t y_index_ = 0;
1650 size_t z_index_ = 0;
1651
1652 size_t facet_index_ = 0;
1653};
1654}
1655}
1656
1657namespace CADMesh {
1658
1659namespace File {
1660
1661inline State *STLReader::CADMeshLexerState(StartSolid) {
1662 if (DoesNotMatchExactly("solid"))
1663 Error("STL files start with 'solid'. Make sure you are using an ASCII STL "
1664 "file.");
1665
1666 SkipWhiteSpace();
1667
1668 RestOfLine();
1669
1670 StartOfA(Solid);
1671
1672 SkipLineBreak();
1673 NextState(StartFacet);
1674}
1675
1676inline State *STLReader::CADMeshLexerState(EndSolid) {
1677 SkipWhiteSpace();
1678 SkipLineBreaks();
1679 SkipWhiteSpace();
1680
1681 if (DoesNotMatchExactly("endsolid"))
1682 Error("STL files end with 'endsolid'.");
1683
1684 Skip();
1685 EndOfA(Solid);
1686
1687 FinalState();
1688}
1689
1690inline State *STLReader::CADMeshLexerState(StartFacet) {
1691 SkipWhiteSpace();
1692 SkipLineBreaks();
1693 SkipWhiteSpace();
1694
1695 if (DoesNotMatchExactly("facet normal"))
1696 Error("Facets are indicated by the tag 'facet normal'.");
1697
1698 SkipWhiteSpace();
1699
1700 StartOfA(Facet);
1701
1702 SkipLine();
1703
1704 NextState(StartVertices);
1705}
1706
1707inline State *STLReader::CADMeshLexerState(EndFacet) {
1708 SkipWhiteSpace();
1709 SkipLineBreaks();
1710 SkipWhiteSpace();
1711
1712 if (DoesNotMatchExactly("endfacet"))
1713 Error("The end of a facets is indicated by the tag 'endfacet'.");
1714
1715 SkipWhiteSpace();
1716 SkipLineBreak();
1717
1718 EndOfA(Facet);
1719
1720 TryState(StartFacet);
1721
1722 NextState(EndSolid);
1723}
1724
1725inline State *STLReader::CADMeshLexerState(StartVertices) {
1726 SkipWhiteSpace();
1727 SkipLineBreaks();
1728 SkipWhiteSpace();
1729
1730 if (DoesNotMatchExactly("outer loop"))
1731 Error("The start of the vertices is indicated by the tag 'outer loop'.");
1732
1733 SkipWhiteSpace();
1734 SkipLineBreak();
1735
1736 StartOfA(Vertices);
1737
1738 NextState(Vertex);
1739}
1740
1741inline State *STLReader::CADMeshLexerState(EndVertices) {
1742 SkipWhiteSpace();
1743 SkipLineBreaks();
1744 SkipWhiteSpace();
1745
1746 if (DoesNotMatchExactly("endloop"))
1747 Error("The end of the vertices is indicated by the tag 'endloop'.");
1748
1749 SkipWhiteSpace();
1750 SkipLineBreak();
1751
1752 EndOfA(Vertices);
1753
1754 NextState(EndFacet);
1755}
1756
1757inline State *STLReader::CADMeshLexerState(Vertex) {
1758 SkipWhiteSpace();
1759 SkipLineBreaks();
1760 SkipWhiteSpace();
1761
1762 if (DoesNotMatchExactly("vertex"))
1763 Error("A vertex is indicated by the tag 'vertex'.");
1764
1765 SkipWhiteSpace();
1766
1767 NextState(ThreeVector);
1768}
1769
1770inline State *STLReader::CADMeshLexerState(ThreeVector) {
1771 SkipWhiteSpace();
1772
1773 StartOfA(ThreeVector);
1774
1775 if (NotANumber())
1776 Error("First number in three vector not found.");
1777
1778 ThisIsA(Number);
1779 SkipWhiteSpace();
1780
1781 if (NotANumber())
1782 Error("Second number in three vector not found.");
1783
1784 ThisIsA(Number);
1785 SkipWhiteSpace();
1786
1787 if (NotANumber())
1788 Error("Third number in three vector not found.");
1789
1790 ThisIsA(Number);
1791 EndOfA(ThreeVector);
1792
1793 SkipWhiteSpace();
1794
1795 if (DidNotSkipLineBreak())
1796 Error("Expecting a new line at the end of a three vector.");
1797
1798 TryState(StartVertices);
1799
1800 TryState(Vertex);
1801
1802 NextState(EndVertices);
1803}
1804
1805inline G4bool STLReader::Read(G4String filepath) {
1806 auto items = RunLexer(filepath, StartSolid);
1807
1808 if (items.size() == 0) {
1809 Exceptions::ParserError("STLReader::Read",
1810 "The STL file appears to be empty.");
1811 }
1812
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 << ".";
1818
1819 Exceptions::ParserError("STLReader::Read", error.str());
1820 }
1821
1822 auto mesh = ParseMesh(item.children);
1823
1824 auto name = G4String(item.value);
1825 AddMesh(Mesh::New(mesh, name));
1826 }
1827
1828 return true;
1829}
1830
1831inline G4bool STLReader::CanRead(Type file_type) { return (file_type == STL); }
1832
1833inline std::shared_ptr<Mesh> STLReader::ParseMesh(Items items) {
1834 Triangles triangles;
1835
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 << ".";
1841
1842 Exceptions::ParserError("STLReader::Mesh", error.str());
1843 }
1844
1845 triangles.push_back(ParseFacet(item.children));
1846 }
1847
1848 return Mesh::New(triangles);
1849}
1850
1851inline G4TriangularFacet *STLReader::ParseFacet(Items items) {
1852 Triangles triangles;
1853
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 << ".";
1859
1860 Exceptions::ParserError("STLReader::ParseFacet", error.str());
1861 }
1862
1863 triangles.push_back(ParseVertices(item.children));
1864 }
1865
1866 if (triangles.size() != 1) {
1867 std::stringstream error;
1868 error << "STL files expect exactly 1 triangle per facet.";
1869
1870 if (items.size() != 0) {
1871 error << "Error around line " << items[0].line << ".";
1872 }
1873
1874 Exceptions::ParserError("STLReader::ParseFacet", error.str());
1875 }
1876
1877 return triangles[0];
1878}
1879
1880inline G4TriangularFacet *STLReader::ParseVertices(Items items) {
1881 std::vector<G4ThreeVector> vertices;
1882
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 << ".";
1888
1889 Exceptions::ParserError("STLReader::ParseVertices", error.str());
1890 }
1891
1892 vertices.push_back(ParseThreeVector(item.children));
1893 }
1894
1895 if (vertices.size() != 3) {
1896 std::stringstream error;
1897 error << "STL files expect exactly 3 vertices for a triangular facet. ";
1898
1899 if (items.size() != 0) {
1900 error << "Error around line " << items[0].line << ".";
1901 }
1902
1903 Exceptions::ParserError("STLReader::ParseVertices", error.str());
1904 }
1905
1906 return new G4TriangularFacet(vertices[0], vertices[1], vertices[2], ABSOLUTE);
1907}
1908
1909inline G4ThreeVector STLReader::ParseThreeVector(Items items) {
1910 std::vector<double> numbers;
1911
1912 for (auto item : items) {
1913 numbers.push_back((double)atof(item.value.c_str()));
1914 }
1915
1916 if (numbers.size() != 3) {
1917 std::stringstream error;
1918 error << "Three vectors in STL files require exactly 3 numbers";
1919
1920 if (items.size() != 0) {
1921 error << "Error around line " << items[0].line << ".";
1922 }
1923
1924 Exceptions::ParserError("STLReader::ParseThreeVector", error.str());
1925 }
1926
1927 return G4ThreeVector(numbers[0], numbers[1], numbers[2]);
1928}
1929}
1930}
1931
1932namespace CADMesh {
1933
1934namespace File {
1935
1936inline State *OBJReader::CADMeshLexerState(StartSolid) {
1937 StartOfA(Solid);
1938
1939 TryState(Object);
1940 TryState(Vertex);
1941 TryState(Ignore);
1942
1943 Error("Invalid element tag.");
1944}
1945
1946inline State *OBJReader::CADMeshLexerState(EndSolid) {
1947 if (Next() != "")
1948 lexer->LastError();
1949
1950 EndOfA(Solid);
1951 FinalState();
1952}
1953
1954inline State *OBJReader::CADMeshLexerState(Ignore) {
1955 if (DidNotSkipLine())
1956 NextState(EndSolid);
1957
1958 TryState(Object);
1959 TryState(Vertex);
1960 TryState(Facet);
1961 TryState(Ignore);
1962
1963 NextState(EndSolid);
1964}
1965
1966inline State *OBJReader::CADMeshLexerState(Vertex) {
1967 SkipLineBreaks();
1968
1969 if (DoesNotMatchExactly("v "))
1970 Error("A vertex is indicated by the tag 'v'.");
1971
1972 SkipWhiteSpace();
1973 StartOfA(Vertex);
1974
1975 if (NotANumber())
1976 Error("First number in three vector not found.");
1977
1978 ThisIsA(Number);
1979 SkipWhiteSpace();
1980
1981 if (NotANumber())
1982 Error("Second number in three vector not found.");
1983
1984 ThisIsA(Number);
1985 SkipWhiteSpace();
1986
1987 if (NotANumber())
1988 Error("Third number in three vector not found.");
1989
1990 ThisIsA(Number);
1991
1992 EndOfA(Vertex);
1993
1994 SkipLine();
1995
1996 TryState(Vertex);
1997 TryState(Object);
1998 TryState(Facet);
1999 TryState(Ignore);
2000
2001 NextState(EndSolid);
2002}
2003
2004inline State *OBJReader::CADMeshLexerState(Facet) {
2005 SkipLineBreaks();
2006
2007 if (DoesNotMatchExactly("f "))
2008 Error("A facet is indicated by the tag 'f'.");
2009
2010 SkipWhiteSpace();
2011 StartOfA(Facet);
2012
2013 if (NotANumber())
2014 Error("First number in three vector not found.");
2015
2016 ThisIsA(Number);
2017
2018 OneOf("/");
2019 Number();
2020 OneOf("/");
2021 Number();
2022 SkipWhiteSpace();
2023
2024 if (NotANumber())
2025 Error("Second number in three vector not found.");
2026
2027 ThisIsA(Number);
2028
2029 OneOf("/");
2030 Number();
2031 OneOf("/");
2032 Number();
2033 SkipWhiteSpace();
2034
2035 if (NotANumber())
2036 Error("Third number in three vector not found.");
2037
2038 ThisIsA(Number);
2039
2040 OneOf("/");
2041 Number();
2042 OneOf("/");
2043 Number();
2044 SkipWhiteSpace();
2045
2046 if (Number())
2047 ThisIsA(Number);
2048
2049 EndOfA(Facet);
2050
2051 SkipLine();
2052
2053 TryState(Facet);
2054 TryState(Vertex);
2055 TryState(Object);
2056 TryState(Ignore);
2057
2058 NextState(EndSolid);
2059}
2060
2061inline State *OBJReader::CADMeshLexerState(Object) {
2062 SkipLineBreaks();
2063
2064 if (DoesNotMatchExactly("o "))
2065 Error("An object is indicated by the tag 'o'.");
2066
2067 EndOfA(Solid);
2068
2069 SkipWhiteSpace();
2070 StartOfA(Solid);
2071
2072 ManyCharacters();
2073 ThisIsA(Word);
2074 SkipWhiteSpace();
2075
2076 TryState(Vertex);
2077 TryState(Facet);
2078 TryState(Object);
2079 TryState(Ignore);
2080
2081 NextState(EndSolid);
2082}
2083
2084inline G4bool OBJReader::Read(G4String filepath) {
2085 auto items = RunLexer(filepath, StartSolid);
2086
2087 if (items.size() == 0) {
2088 Exceptions::ParserError("OBJReader::Read",
2089 "The OBJ file appears to be empty.");
2090 }
2091
2092 for (auto item : items) {
2093 if (item.children.size() == 0) {
2094 continue;
2095 }
2096
2097 auto mesh = ParseMesh(item.children);
2098
2099 if (mesh->GetTriangles().size() == 0) {
2100 continue;
2101 }
2102
2103 G4String name;
2104
2105 if (item.children[0].token == WordToken) {
2106 name = item.children[0].value;
2107 }
2108
2109 AddMesh(Mesh::New(mesh, name));
2110 }
2111
2112 return true;
2113}
2114
2115inline G4bool OBJReader::CanRead(Type file_type) { return (file_type == OBJ); }
2116
2117inline std::shared_ptr<Mesh> OBJReader::ParseMesh(Items items) {
2118 Triangles facets;
2119
2120 for (auto item : items) {
2121 if (item.token != VertexToken) {
2122 continue;
2123 }
2124
2125 if (item.children.size() == 0) {
2126 std::stringstream error;
2127 error << "The vertex appears to be empty."
2128 << "Error around line " << item.line << ".";
2129
2130 Exceptions::ParserError("OBJReader::Mesh", error.str());
2131 }
2132
2133 vertices_.push_back(ParseVertex(item.children));
2134 }
2135
2136 for (auto item : items) {
2137 if (item.token != FacetToken) {
2138 continue;
2139 }
2140
2141 if (item.children.size() == 0) {
2142 std::stringstream error;
2143 error << "The facet appears to be empty."
2144 << "Error around line " << item.line << ".";
2145
2146 Exceptions::ParserError("OBJReader::Mesh", error.str());
2147 }
2148
2149 facets.push_back(ParseFacet(item.children, false));
2150
2151 if (item.children.size() == 4) {
2152 facets.push_back(ParseFacet(item.children, true));
2153 }
2154 }
2155
2156 return Mesh::New(facets);
2157}
2158
2159inline G4ThreeVector OBJReader::ParseVertex(Items items) {
2160 std::vector<double> numbers;
2161
2162 for (auto item : items) {
2163 numbers.push_back((double)atof(item.value.c_str()));
2164 }
2165
2166 if (numbers.size() != 3) {
2167 std::stringstream error;
2168 error << "Three vectors in OBJ files require exactly 3 numbers";
2169
2170 if (items.size() != 0) {
2171 error << "Error around line " << items[0].line << ".";
2172 }
2173
2174 Exceptions::ParserError("OBJReader::ParseThreeVector", error.str());
2175 }
2176
2177 return G4ThreeVector(numbers[0], numbers[1], numbers[2]);
2178}
2179
2180inline G4TriangularFacet *OBJReader::ParseFacet(Items items, G4bool quad) {
2181 std::vector<int> indices;
2182
2183 for (auto item : items) {
2184 indices.push_back((int)atoi(item.value.c_str()));
2185 }
2186
2187 if (indices.size() < 3) {
2188 std::stringstream error;
2189 error << "Facets in OBJ files require at least 3 indicies";
2190
2191 if (items.size() != 0) {
2192 error << "Error around line " << items[0].line << ".";
2193 }
2194
2195 Exceptions::ParserError("OBJReader::ParseFacet", error.str());
2196 }
2197
2198 if (quad && indices.size() != 4) {
2199 std::stringstream error;
2200 error << "Trying to triangle-ify a facet that isn't a quad";
2201
2202 if (items.size() != 0) {
2203 error << "Error around line " << items[0].line << ".";
2204 }
2205
2206 Exceptions::ParserError("OBJReader::ParseFacet", error.str());
2207 }
2208
2209 if (quad) {
2210 return new G4TriangularFacet(vertices_[indices[0] - 1],
2211 vertices_[indices[2] - 1],
2212 vertices_[indices[3] - 1], ABSOLUTE);
2213 }
2214
2215 else {
2216 return new G4TriangularFacet(vertices_[indices[0] - 1],
2217 vertices_[indices[1] - 1],
2218 vertices_[indices[2] - 1], ABSOLUTE);
2219 }
2220}
2221}
2222}
2223
2224namespace CADMesh {
2225
2226namespace File {
2227
2228inline State *PLYReader::CADMeshLexerState(StartHeader) {
2229 if (DoesNotMatchExactly("ply"))
2230 Error("PLY files start with 'ply'.");
2231
2232 StartOfA(Header);
2233
2234 SkipLine();
2235
2236 TryState(Element);
2237 TryState(Ignore);
2238
2239 Error("Invalid header tag.");
2240}
2241
2242inline State *PLYReader::CADMeshLexerState(EndHeader) {
2243 if (DoesNotMatchExactly("end_header"))
2244 Error("PLY file headers end with 'end_header'.");
2245
2246 MaybeEndOfA(Element);
2247
2248 EndOfA(Header);
2249 FinalState();
2250}
2251
2252inline State *PLYReader::CADMeshLexerState(Element) {
2253 if (DoesNotMatchExactly("element "))
2254 Error("An element is indicated by the tag 'element'.");
2255
2256 MaybeEndOfA(Element);
2257
2258 SkipWhiteSpace();
2259 StartOfA(Element);
2260
2261 if (NotManyCharacters())
2262 Error("Element type not found.");
2263
2264 ThisIsA(Word);
2265 SkipWhiteSpace();
2266
2267 if (NotANumber())
2268 Error("Element count not found.");
2269
2270 ThisIsA(Number);
2271 SkipLine();
2272
2273 TryState(Property);
2274 TryState(Ignore);
2275
2276 NextState(EndHeader);
2277}
2278
2279inline State *PLYReader::CADMeshLexerState(Property) {
2280 if (DoesNotMatchExactly("property "))
2281 Error("An property is indicated by the tag 'property'.");
2282
2283 SkipWhiteSpace();
2284 StartOfA(Property);
2285
2286 if (NotManyCharacters())
2287 Error("Element type not found.");
2288
2289 ThisIsA(Word);
2290 SkipWhiteSpace();
2291
2292 RestOfLine();
2293 ThisIsA(Word);
2294
2295 EndOfA(Property);
2296
2297 SkipLineBreak();
2298
2299 TryState(Property);
2300 TryState(Element);
2301 TryState(EndHeader);
2302 TryState(Ignore);
2303
2304 NextState(EndHeader);
2305}
2306
2307inline State *PLYReader::CADMeshLexerState(Ignore) {
2308 if (DidNotSkipLine())
2309 NextState(EndHeader);
2310
2311 TryState(Element);
2312 TryState(Property);
2313 TryState(EndHeader);
2314
2315 NextState(Ignore);
2316}
2317
2318inline State *PLYReader::CADMeshLexerState(Vertex) {
2319 SkipLineBreaks();
2320 SkipWhiteSpace();
2321 SkipLineBreaks();
2322
2323 StartOfA(Vertex);
2324
2325 size_t i = 0;
2326
2327 while (i < 32) {
2328 if (AtEndOfLine())
2329 break;
2330
2331 SkipWhiteSpace();
2332
2333 if (NotANumber())
2334 Error("Expecting only numbers in the vertex specification.");
2335
2336 ThisIsA(Number);
2337 SkipWhiteSpace();
2338
2339 i++;
2340 }
2341
2342 EndOfA(Vertex);
2343
2344 SkipLine();
2345
2346 TryState(Vertex);
2347
2348 FinalState();
2349}
2350
2351inline State *PLYReader::CADMeshLexerState(Facet) {
2352 SkipLineBreaks();
2353 SkipWhiteSpace();
2354 SkipLineBreaks();
2355
2356 StartOfA(Facet);
2357
2358 size_t i = 0;
2359
2360 while (i < 32) {
2361 if (AtEndOfLine())
2362 break;
2363
2364 SkipWhiteSpace();
2365
2366 if (NotANumber())
2367 Error("Expecting only numbers in the facet specification.");
2368
2369 ThisIsA(Number);
2370 SkipWhiteSpace();
2371
2372 i++;
2373 }
2374
2375 EndOfA(Facet);
2376
2377 SkipLine();
2378
2379 TryState(Facet);
2380
2381 FinalState();
2382}
2383
2384inline G4bool PLYReader::Read(G4String filepath) {
2385 auto lexer = Lexer(filepath, new StartHeaderState);
2386 auto items = lexer.GetItems();
2387
2388 if (items.size() == 0) {
2389 std::stringstream error;
2390 error << "The header appears to be empty.";
2391
2392 Exceptions::ParserError("PLYReader::Read", error.str());
2393 }
2394
2395 ParseHeader(items);
2396
2397 lexer.Run(new VertexState, vertex_count_);
2398 auto vertex_items = lexer.GetItems();
2399
2400 if (vertex_items.size() == 0) {
2401 Exceptions::ParserError("PLYReader::Read",
2402 "The PLY file appears to have no vertices.");
2403 }
2404
2405 if (vertex_items.size() != vertex_count_) {
2406 Exceptions::ParserError("PLYReader::Read",
2407 "The PLY file appears to be missing vertices.");
2408 }
2409
2410 lexer.Run(new FacetState, facet_count_);
2411 auto face_items = lexer.GetItems();
2412
2413 if (face_items.size() == 0) {
2414 Exceptions::ParserError("PLYReader::Read",
2415 "The PLY file appears to have no facets.");
2416 }
2417
2418 if (face_items.size() != facet_count_) {
2419 Exceptions::ParserError("PLYReader::Read",
2420 "The PLY file appears to be missing facets");
2421 }
2422
2423 auto mesh = ParseMesh(vertex_items, face_items);
2424 AddMesh(Mesh::New(mesh));
2425
2426 return true;
2427}
2428
2429inline G4bool PLYReader::CanRead(Type file_type) { return (file_type == PLY); }
2430
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.";
2436
2437 Exceptions::ParserError("PLYReader::ParseHeader", error.str());
2438 }
2439
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 << ".";
2447
2448 Exceptions::ParserError("PLYReader::ParseHeader", error.str());
2449 }
2450
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());
2455
2456 for (size_t i = 2; i < item.children.size(); i++) {
2457 auto property = item.children[i];
2458
2459 if (property.children.size() > 1) {
2460 if (property.children[1].token == WordToken) {
2461 if (property.children[1].value == "x") {
2462 x_index_ = i - 2;
2463 }
2464
2465 if (property.children[1].value == "y") {
2466 y_index_ = i - 2;
2467 }
2468
2469 if (property.children[1].value == "z") {
2470 z_index_ = i - 2;
2471 }
2472 }
2473 }
2474 }
2475 }
2476
2477 else if (item.children[0].value == "face") {
2478 facet_count_ = atoi(item.children[1].value.c_str());
2479
2480 for (size_t i = 2; i < item.children.size(); i++) {
2481 auto property = item.children[i];
2482
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;
2487 }
2488 }
2489 }
2490 }
2491 }
2492 }
2493 }
2494 }
2495
2496 if (vertex_count_ == 0) {
2497 std::stringstream error;
2498 error << "The number of vertices was not found in the header.";
2499
2500 Exceptions::ParserError("PLYReader::ParseHeader", error.str());
2501 }
2502
2503 if (facet_count_ == 0) {
2504 std::stringstream error;
2505 error << "The number of faces was not found in the header.";
2506
2507 Exceptions::ParserError("PLYReader::ParseHeader", error.str());
2508 }
2509
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.";
2514
2515 Exceptions::ParserError("PLYReader::ParseHeader", error.str());
2516 }
2517}
2518
2519inline std::shared_ptr<Mesh> PLYReader::ParseMesh(Items vertex_items,
2520 Items face_items) {
2521 Points vertices;
2522 Triangles facets;
2523
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 << ".";
2529
2530 Exceptions::ParserError("PLYReader::ParseMesh", error.str());
2531 }
2532
2533 if (item.token == VertexToken) {
2534 vertices.push_back(ParseVertex(item.children));
2535 }
2536 }
2537
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 << ".";
2543
2544 Exceptions::ParserError("PLYReader::Mesh", error.str());
2545 }
2546
2547 if (item.token == FacetToken) {
2548 facets.push_back(ParseFacet(item.children, vertices));
2549 }
2550 }
2551
2552 return Mesh::New(facets);
2553}
2554
2555inline G4ThreeVector PLYReader::ParseVertex(Items items) {
2556 std::vector<double> numbers;
2557
2558 for (auto item : items) {
2559 numbers.push_back((double)atof(item.value.c_str()));
2560 }
2561
2562 if (numbers.size() < 3) {
2563 std::stringstream error;
2564 error << "Vertices in PLY files require atleast 3 numbers. ";
2565
2566 if (items.size() != 0) {
2567 error << "Error around line " << items[0].line << ".";
2568 }
2569
2570 Exceptions::ParserError("PLYReader::ParseVertex", error.str());
2571 }
2572
2573 return G4ThreeVector(numbers[x_index_], numbers[y_index_], numbers[z_index_]);
2574}
2575
2576inline G4TriangularFacet *PLYReader::ParseFacet(Items items, Points vertices) {
2577 std::vector<int> indices;
2578
2579 for (auto item : items) {
2580 indices.push_back((int)atoi(item.value.c_str()));
2581 }
2582
2583 if (indices.size() < 4) {
2584 std::stringstream error;
2585 error << "Facets in PLY files require 3 indicies";
2586
2587 if (items.size() != 0) {
2588 error << "Error around line " << items[0].line << ".";
2589 }
2590
2591 Exceptions::ParserError("PLYReader::ParseFacet", error.str());
2592 }
2593
2594 return new G4TriangularFacet(vertices[indices[1 + facet_index_]],
2595 vertices[indices[2 + facet_index_]],
2596 vertices[indices[3 + facet_index_]], ABSOLUTE);
2597}
2598}
2599}
2600
2601#ifdef USE_CADMESH_ASSIMP_READER
2602
2603namespace CADMesh {
2604
2605namespace File {
2606
2607inline ASSIMPReader::ASSIMPReader() : Reader("ASSIMPReader") {
2608 importer_ = new Assimp::Importer();
2609}
2610
2611inline ASSIMPReader::~ASSIMPReader() { delete importer_; }
2612
2613inline G4bool ASSIMPReader::Read(G4String filepath) {
2614 auto scene = importer_->ReadFile(filepath.c_str(),
2615 aiProcess_Triangulate |
2616 aiProcess_JoinIdenticalVertices |
2617 aiProcess_CalcTangentSpace);
2618
2619 if (!scene) {
2620 Exceptions::FileNotFound("ASSIMP::Read", filepath);
2621 return false;
2622 }
2623
2624 for (unsigned int index = 0; index < scene->mNumMeshes; index++) {
2625 aiMesh *mesh = scene->mMeshes[index];
2626 auto name = mesh->mName.C_Str();
2627
2628 Triangles triangles;
2629
2630 for (unsigned int i = 0; i < mesh->mNumFaces; i++) {
2631 const aiFace &face = mesh->mFaces[i];
2632
2633 G4ThreeVector a(mesh->mVertices[face.mIndices[0]].x,
2634 mesh->mVertices[face.mIndices[0]].y,
2635 mesh->mVertices[face.mIndices[0]].z);
2636
2637 G4ThreeVector b(mesh->mVertices[face.mIndices[1]].x,
2638 mesh->mVertices[face.mIndices[1]].y,
2639 mesh->mVertices[face.mIndices[1]].z);
2640
2641 G4ThreeVector c(mesh->mVertices[face.mIndices[2]].x,
2642 mesh->mVertices[face.mIndices[2]].y,
2643 mesh->mVertices[face.mIndices[2]].z);
2644
2645 triangles.push_back(new G4TriangularFacet(a, b, c, ABSOLUTE));
2646 }
2647
2648 AddMesh(Mesh::New(triangles, name));
2649 }
2650
2651 return true;
2652}
2653
2654inline G4bool ASSIMPReader::CanRead(Type /*file_type*/) { return true; }
2655
2656std::shared_ptr<ASSIMPReader> ASSIMP() {
2657 return std::make_shared<ASSIMPReader>();
2658}
2659}
2660}
2661#endif
2662
2663namespace CADMesh {
2664
2665namespace File {
2666
2667inline G4bool BuiltInReader::Read(G4String filepath) {
2668 File::Reader *reader = nullptr;
2669
2670 auto type = TypeFromName(filepath);
2671
2672 if (type == STL) {
2673 reader = new File::STLReader();
2674 }
2675
2676 else if (type == OBJ) {
2677 reader = new File::OBJReader();
2678 }
2679
2680 else if (type == PLY) {
2681 reader = new File::PLYReader();
2682 }
2683
2684 else {
2685 Exceptions::ReaderCantReadError("BuildInReader::Read", type, filepath);
2686 }
2687
2688 if (!reader->Read(filepath)) {
2689 return false;
2690 }
2691
2692 SetMeshes(reader->GetMeshes());
2693 return true;
2694}
2695
2696inline G4bool BuiltInReader::CanRead(Type type) {
2697 return type == STL || type == OBJ || type == PLY;
2698}
2699
2700inline std::shared_ptr<BuiltInReader> BuiltIn() {
2701 return std::make_shared<BuiltInReader>();
2702}
2703}
2704}
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