Skip to content
Snippets Groups Projects
BuildLattice.h 4.9 KiB
Newer Older
samuel.hayden's avatar
samuel.hayden committed
#pragma once
#include <vector>
#include <iostream>

samuel.hayden's avatar
samuel.hayden committed
#include "ErrorCodes.h"

samuel.hayden's avatar
samuel.hayden committed
#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
{
samuel.hayden's avatar
samuel.hayden committed
private:
	std::vector<ErrorCodes> _errors;

samuel.hayden's avatar
samuel.hayden committed
protected:
	bool _buildSuccessful;
	double _cx, _cy, _cz;	// Size of each cell
	const std::vector<gp_Pnt>& _cellPositions;	// Position of node1 of unit cell (NOT CENTER)
	const std::vector<double>& _cellRadii;

	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();

public:
	BuildLattice(const std::vector<gp_Pnt>& positions, const std::vector<double>& radii, double cx = 5.0, double cy = 5.0, double cz = 5.0)
		: _cellPositions(positions), _cellRadii(radii), _buildSuccessful(false),
		_cx(cx), _cy(cy), _cz(cz)
	{
		// 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 += _cx;
		y1 += _cy;
		z1 += _cz;
		_boundingBox = BRepPrimAPI_MakeBox(gp_Pnt(x0, y0, z0), gp_Pnt(x1, y1, z1));
	}

	// Setters
	void setCellSize(double cellWidth, double cellDepth, double cellHeight) { _cx = cellWidth, _cy = cellDepth; _cz = cellHeight; }
	void setBoundingBox(const TopoDS_Solid& boundingBox) { _boundingBox = _boundingBox; }

	bool buildLattice();
	TopoDS_Shape getLattice() { return _lattice; }
samuel.hayden's avatar
samuel.hayden committed

	bool hasErrors() { return _errors.size() > 0; }
	void dumpErrors()
	{
		for (const ErrorCodes& code : _errors)
		{
			ERROR_MSG("BuildLattice", code);
		}
	}
samuel.hayden's avatar
samuel.hayden committed
};


// 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);
samuel.hayden's avatar
samuel.hayden committed
		_errors.emplace_back(ErrorCodes::FailedToMergeCells);
samuel.hayden's avatar
samuel.hayden committed
		return false;
	}
samuel.hayden's avatar
samuel.hayden committed
	fuser.SimplifyResult();
samuel.hayden's avatar
samuel.hayden committed
	if (fuser.HasErrors())
	{
		fuser.DumpErrors(std::cout);
		_errors.emplace_back(ErrorCodes::FailedToMergeCells);
		return false;
	}
samuel.hayden's avatar
samuel.hayden committed
	_lattice = fuser.Shape();
	return true;
}

// Trims outside of lattice
template<class UnitCell>
bool BuildLattice<UnitCell>::trimLattice()
{
samuel.hayden's avatar
samuel.hayden committed
	if (_lattice.IsNull())
		_errors.emplace_back(ErrorCodes::LatticeIsNull);
	if (_boundingBox.IsNull())
		_errors.emplace_back(ErrorCodes::BoundingBoxIsNull);
	if (hasErrors())
samuel.hayden's avatar
samuel.hayden committed
		return false;

	// Trim unitcell
samuel.hayden's avatar
samuel.hayden committed
	BRepAlgoAPI_Common trimmer(_lattice, _boundingBox);
	if (trimmer.HasErrors())
	{
		trimmer.DumpErrors(std::cout);
		_errors.emplace_back(ErrorCodes::FailedToTrimLattice);
		return false;
	}
	_lattice = trimmer.Shape();
samuel.hayden's avatar
samuel.hayden committed
	return true;
}

template<class UnitCell>
inline bool BuildLattice<UnitCell>::buildLattice()
{
	size_t nCells = _cellRadii.size();
	std::cout << "[Info](buildLattice) Building " << nCells << " cells" << std::endl;
	for (size_t i = 0; i < nCells; i++)
	{
		if (!buildCell(_cx, _cy, _cz, _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;
}