#pragma once #include <vector> #include <iostream> #include "ErrorCodes.h" #include "unitcells/UnitCellBuilder.h" #include "unitcells/UnitCellBCC.h" #include "BRepAlgoAPI_Fuse.hxx" #include "BRepAlgoAPI_Common.hxx" #include "BRepBuilderAPI_Transform.hxx" #include "BRepPrimAPI_MakeBox.hxx" template<class UnitCell> class BuildLattice { private: std::vector<ErrorCodes> _errors; protected: /* Data to build lattice */ double _cellX, _cellY, _cellZ; std::vector<double> _cellRadii; std::vector<gp_Pnt> _cellPositions; /* Built objects */ TopoDS_ListOfShape _unitCells; TopoDS_Shape _tmpUnitCell; TopoDS_Shape _lattice; TopoDS_Solid _boundingBox; protected: bool buildCell(double w, double d, double h, double r); bool translateCell(double dx, double dy, double dz); bool mergeCells(); bool trimLattice(); void determineBoundingBox() { // Compute Basic Bounding Box double x0 = DBL_MAX, y0 = DBL_MAX, z0 = DBL_MAX; double x1 = -DBL_MAX, y1 = -DBL_MAX, z1 = -DBL_MAX; for (const gp_Pnt& point : _cellPositions) { x0 = point.X() < x0 ? point.X() : x0; y0 = point.Y() < y0 ? point.Y() : y0; z0 = point.Z() < z0 ? point.Z() : z0; x1 = point.X() > x1 ? point.X() : x1; y1 = point.Y() > y1 ? point.Y() : y1; z1 = point.Z() > z1 ? point.Z() : z1; } x1 += _cellX; y1 += _cellY; z1 += _cellZ; _boundingBox = BRepPrimAPI_MakeBox(gp_Pnt(x0, y0, z0), gp_Pnt(x1, y1, z1)); } public: BuildLattice() : _cellX(0.0), _cellY(0.0), _cellZ(0.0) {} bool buildLattice(); TopoDS_Shape getLattice() { return _lattice; } bool hasErrors() { return _errors.size() > 0; } void dumpErrors() { for (const ErrorCodes& code : _errors) { ERROR_MSG("BuildLattice", code); } } }; // Builds a cell of type UnitCell template<class UnitCell> bool BuildLattice<UnitCell>::buildCell(double w, double d, double h, double r) { UnitCell cellBuilder(w, d, h, r); cellBuilder.buildUnitCell(); if (!cellBuilder.status()) { std::cout << "[Error](buildCell) Error building unit cell" << std::endl; return false; } _tmpUnitCell = cellBuilder.getUnitCell(); return true; } // Translates cell to position dx, dy, dz template<class UnitCell> bool BuildLattice<UnitCell>::translateCell(double dx, double dy, double dz) { gp_Trsf translationVector; translationVector.SetTranslation(gp_Vec(dx, dy, dz)); _unitCells.Append(BRepBuilderAPI_Transform(_tmpUnitCell, translationVector)); return true; } // Merges all unit cells template<class UnitCell> bool BuildLattice<UnitCell>::mergeCells() { BRepAlgoAPI_Fuse fuser; TopoDS_ListOfShape arg; arg.Append(_unitCells.First()); _unitCells.RemoveFirst(); fuser.SetArguments(arg); fuser.SetTools(_unitCells); fuser.SetRunParallel(true); fuser.SetFuzzyValue(1e-4); fuser.Build(); if (fuser.HasErrors()) { fuser.DumpErrors(std::cout); _errors.emplace_back(ErrorCodes::FailedToMergeCells); return false; } fuser.SimplifyResult(); if (fuser.HasErrors()) { fuser.DumpErrors(std::cout); _errors.emplace_back(ErrorCodes::FailedToMergeCells); return false; } _lattice = fuser.Shape(); return true; } // Trims outside of lattice template<class UnitCell> bool BuildLattice<UnitCell>::trimLattice() { if (_lattice.IsNull()) _errors.emplace_back(ErrorCodes::LatticeIsNull); if (_boundingBox.IsNull()) _errors.emplace_back(ErrorCodes::BoundingBoxIsNull); if (hasErrors()) return false; // Trim unitcell BRepAlgoAPI_Common trimmer(_lattice, _boundingBox); if (trimmer.HasErrors()) { trimmer.DumpErrors(std::cout); _errors.emplace_back(ErrorCodes::FailedToTrimLattice); return false; } _lattice = trimmer.Shape(); return true; } template<class UnitCell> inline bool BuildLattice<UnitCell>::buildLattice() { if (_boundingBox.IsNull()) determineBoundingBox(); size_t nCells = _cellRadii.size(); std::cout << "[Info](buildLattice) Building " << nCells << " cells" << std::endl; for (size_t i = 0; i < nCells; i++) { if (!buildCell(_cellX, _cellY, _cellZ, _cellRadii[i])) return false; const gp_Pnt& pos = _cellPositions[i]; if (!translateCell(pos.X(), pos.Y(), pos.Z())) return false; if (i % 10 == 0) std::cout << "[Info](bulidLattice) (" << i << "/" << nCells << ") built" << std::endl; } std::cout << "[Info](bulidLattice) (" << nCells << "/" << nCells << ") built" << std::endl; std::cout << "[Info](buildLattice) All cells built" << std::endl; std::cout << "[Info](buildLattice) Merging cells (this step takes some time)" << std::endl; if (!mergeCells()) return false; std::cout << "[Info](buildLattice) Trimming lattice" << std::endl; if (!trimLattice()) return false; return true; }