Skip to content
Snippets Groups Projects
BuildLattice.h 4.55 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:
	/* Data to build lattice */
	double _cellX, _cellY, _cellZ;
	std::vector<double> _cellRadii;
	std::vector<gp_Pnt> _cellPositions;
samuel.hayden's avatar
samuel.hayden committed

samuel.hayden's avatar
samuel.hayden committed
	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();

samuel.hayden's avatar
samuel.hayden committed
	{
		// 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;
		}
samuel.hayden's avatar
samuel.hayden committed
		_boundingBox = BRepPrimAPI_MakeBox(gp_Pnt(x0, y0, z0), gp_Pnt(x1, y1, z1));
	}

public:
	BuildLattice()
		: _cellX(0.0), _cellY(0.0), _cellZ(0.0)
	{}
samuel.hayden's avatar
samuel.hayden committed

	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()
{
	if (_boundingBox.IsNull())
		determineBoundingBox();

samuel.hayden's avatar
samuel.hayden committed
	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]))
samuel.hayden's avatar
samuel.hayden committed
			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;
}