add OccupancyGrid class
This commit is contained in:
parent
8c2703db4a
commit
02c4e32a1f
|
@ -72,6 +72,7 @@ set(VCG_HEADERS
|
|||
vcg/complex/algorithms/polygonal_algorithms.h
|
||||
vcg/complex/algorithms/inertia.h
|
||||
vcg/complex/algorithms/mesh_assert.h
|
||||
vcg/complex/algorithms/occupancy_grid.h
|
||||
vcg/complex/algorithms/cut_tree.h
|
||||
vcg/complex/algorithms/nring.h
|
||||
vcg/complex/algorithms/tetra/tetfuse_collapse.h
|
||||
|
|
|
@ -0,0 +1,435 @@
|
|||
#include <bitset>
|
||||
|
||||
#include <vcg/complex/algorithms/align_pair.h>
|
||||
#include <vcg/space/index/grid_static_obj.h>
|
||||
|
||||
#ifndef VCGLIB_OCCUPANCY_GRID_H
|
||||
#define VCGLIB_OCCUPANCY_GRID_H
|
||||
|
||||
#define OG_MAX_MCB_SIZE 2048
|
||||
#define OG_MESH_INFO_MAX_STAT 64
|
||||
|
||||
namespace vcg {
|
||||
namespace tri {
|
||||
|
||||
template<class MeshType>
|
||||
class OccupancyGrid {
|
||||
|
||||
private:
|
||||
|
||||
GridStaticObj<MeshCounter, float> G;
|
||||
|
||||
int mn;
|
||||
int TotalArea;
|
||||
/**
|
||||
* Maximum number of meshes that cross a cell
|
||||
*/
|
||||
int MaxCount;
|
||||
|
||||
/**
|
||||
* SortedVisual Arcs
|
||||
*/
|
||||
std::vector<OGArcInfo> SVA; // SortedVirtual Arcs;
|
||||
/**
|
||||
* High level information for each mesh. Mapped by mesh id
|
||||
*/
|
||||
std::map<int, OGMeshInfo> VM;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Class to keep for each voxel the id of the mesh passing through it.
|
||||
* based on bitset
|
||||
*/
|
||||
class MeshCounter {
|
||||
|
||||
private:
|
||||
std::bitset<OG_MAX_MCB_SIZE> cnt;
|
||||
|
||||
public:
|
||||
|
||||
static constexpr int MaxVal() {
|
||||
return OG_MAX_MCB_SIZE;
|
||||
}
|
||||
|
||||
bool Empty() const {
|
||||
return cnt.none();
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
cnt.reset();
|
||||
}
|
||||
|
||||
bool IsSet(size_t i) const {
|
||||
return cnt.test(i);
|
||||
}
|
||||
|
||||
void Set(size_t i) {
|
||||
cnt.set(i);
|
||||
}
|
||||
|
||||
void UnSet(size_t i) {
|
||||
cnt.reset(i);
|
||||
}
|
||||
|
||||
size_t Count() const {
|
||||
return cnt.count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a vector with all the id of the meshes
|
||||
*/
|
||||
void Pack(std::vector<int> &v) const {
|
||||
|
||||
v.clear();
|
||||
|
||||
for (size_t i = 0; i < MeshCounter::MaxVal(); ++i) {
|
||||
if (cnt.test(i) {
|
||||
v.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool operator < (const MeshCounter &c) const {
|
||||
|
||||
if (cnt==c.cnt) return false;
|
||||
|
||||
size_t ii = 0;
|
||||
|
||||
while (ii < MeshCounter::MaxVal()){
|
||||
if (cnt[ii]!=c.cnt[ii]) {
|
||||
return cnt[ii] < c.cnt[ii];
|
||||
}
|
||||
++ii;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for collecting cumulative information about each mesh in the OG.
|
||||
* This info are collected in the Compute() by scanning the OG after we filled it with all the meshes.
|
||||
*/
|
||||
class OGMeshInfo {
|
||||
|
||||
public:
|
||||
|
||||
int id; // the id of the mesh
|
||||
int area; // number of voxels in the OG touched by this mesh
|
||||
int coverage; // quanto e' ricoperta da altre mesh eccetto se stessa (eg: se ho due mesh di 1000 con overlap al 30% la covrg e' 300)
|
||||
|
||||
bool used = false;
|
||||
|
||||
std::vector<int> densityDistribution; // Distribution of the of the density of the voxels touched by this mesh:
|
||||
// densityDistribution[i] says how many voxel (among the ones coverd by this mesh)
|
||||
// are covered by <i> othermeshes. Sum(densityDistribution) == area;
|
||||
// if densityDistribution[1] > 0 means that this mesh is the unique to cover some portion of the space.
|
||||
|
||||
OGMeshInfo() {
|
||||
Init(-1);
|
||||
}
|
||||
|
||||
void Init(int _id) {
|
||||
coverage=0;area=0; id=_id;
|
||||
}
|
||||
|
||||
bool operator < (OGMeshInfo &o) const {
|
||||
return area < o.area;
|
||||
}
|
||||
|
||||
static constexpr int MaxStat() {
|
||||
return OG_MESH_INFO_MAX_STAT;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Classe con informazioni su un arco plausibile
|
||||
*/
|
||||
class OGArcInfo {
|
||||
public:
|
||||
|
||||
enum sort {
|
||||
AREA,
|
||||
NORM_AREA,
|
||||
DEGREE
|
||||
};
|
||||
|
||||
int s,t; // source and target (come indici nel gruppo corrente)
|
||||
int area; //
|
||||
float norm_area;
|
||||
|
||||
OGArcInfo(int _s, int _t, int _area, float _n) : s{_s}, t{_t}, area{_area}, norm_area{_n} {}
|
||||
OGArcInfo(int _s, int _t, int _area) s{_s}, t{_t}, area{_area} {}
|
||||
|
||||
bool operator < (const OGArcInfo &p) const {
|
||||
return norm_area < p.norm_area;
|
||||
}
|
||||
};
|
||||
|
||||
bool Init(int _mn, Box3d bb, int size) {
|
||||
|
||||
// the number of meshes (including all the unused ones; eg it is the range of the possible id)
|
||||
mn = _mn;
|
||||
if (mn > MeshCounter::MaxVal()) return false;
|
||||
|
||||
MeshCounter MC;
|
||||
|
||||
MC.Clear();
|
||||
G.Create(bb,size,MC);
|
||||
VM.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Add(const char *MeshName, Matrix44d &Tr, int id) {
|
||||
|
||||
AlignPair::A2Mesh M;
|
||||
|
||||
vcg::tri::io::Importer<A2Mesh>::Open(M,MeshName);
|
||||
vcg::tri::Clean<A2Mesh>::RemoveUnreferencedVertex(M);
|
||||
|
||||
AddMesh(M,Tr,id);
|
||||
}
|
||||
|
||||
void AddMeshes(std::vector<std::string> &names, std::vector<Matrix44d> &trv,int size) {
|
||||
|
||||
Box3d bb, totalbb;
|
||||
|
||||
bb.SetNull();
|
||||
totalbb.SetNull();
|
||||
|
||||
std::fprintf(stdout, "OG::AddMesh:Scanning BBoxex\n");
|
||||
|
||||
for (std::size_t i = 0; i < names.size(); ++i) {
|
||||
ply::ScanBBox(names[i].c_str(),bb);
|
||||
totalbb.Add(trv[i], bb);
|
||||
}
|
||||
|
||||
Init(names.size(),totalbb,size);
|
||||
|
||||
for (std::size_t i = 0; i < names.size(); ++i) {
|
||||
std::fprintf(stdout, "OG::AddMesh:Adding Mesh %i '%s'\n", i, names[i].c_str());
|
||||
Add(names[i].c_str(),trv[i],i);
|
||||
}
|
||||
}
|
||||
|
||||
void AddMesh(MeshType &mesh, const Matrix44d &Tr, int ind) {
|
||||
|
||||
Matrix44f Trf;
|
||||
Trf.Import(Tr);
|
||||
|
||||
for (auto vi = std::begin(M.vert); vi != std::end(M.vert); ++vi) {
|
||||
|
||||
if (!(*vi).IsD()) {
|
||||
G.Grid( Trf * Point3f::Construct((*vi).P()) ).Set(ind);
|
||||
}
|
||||
}
|
||||
|
||||
VM[ind].Init(ind);
|
||||
VM[ind].used = true;
|
||||
}
|
||||
|
||||
void RemoveMesh(int id) {
|
||||
|
||||
MeshCounter *GridEnd = G.grid+G.size();
|
||||
|
||||
for (MeshCounter* ig = G.grid; ig != GridEnd; ++ig) {
|
||||
ig->UnSet(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called after we have <added> all the mesh to the OG
|
||||
* to collect the information about the interferences between the various meshes.
|
||||
*/
|
||||
void Compute() {
|
||||
|
||||
// Analisi della griglia
|
||||
// Si deve trovare l'insieme degli archi piu'plausibili
|
||||
// un arco ha "senso" in una cella se entrambe le mesh compaiono in quell'arco
|
||||
// Si considera tutti gli archi possibili e si conta in quante celle ha senso un arco
|
||||
|
||||
std::vector<int> VA; // virtual arcs
|
||||
VA.resize(mn * mn, 0);
|
||||
|
||||
std::map<std::pair<int,int>, int> VAMap;
|
||||
|
||||
// First Loop:
|
||||
// Scan the grid and update possible arc count
|
||||
for (int i = 0; i < G.siz[0]; ++i) {
|
||||
|
||||
for (int j = 0; j < G.siz[1]; ++j) {
|
||||
|
||||
for (int k = 0; k < G.siz[2]; ++k) {
|
||||
|
||||
std::vector<int> vv;
|
||||
G.Grid(i, j, k).Pack(vv);
|
||||
std::size_t meshInCell = vv.size();
|
||||
|
||||
for (std::size_t ii = 0; ii < vv.size(); ++ii) {
|
||||
|
||||
OccupancyGrid::OGMeshInfo &omi_ii = VM[vv[ii]];
|
||||
|
||||
++omi_ii.area; // compute mesh area
|
||||
if (meshInCell > omi_ii.densityDistribution.size()) {
|
||||
omi_ii.densityDistribution.resize(meshInCell);
|
||||
}
|
||||
|
||||
++(omi_ii.densityDistribution[meshInCell - 1]);
|
||||
}
|
||||
|
||||
for (std::size_t ii = 0; ii < vv.size(); ++ii) {
|
||||
for (std::size_t jj = ii + 1; jj < vv.size(); ++jj) {
|
||||
// count intersections of all mesh pairs
|
||||
++VAMap[std::make_pair(vv[ii], vv[jj])];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find all the arcs, e.g. all the pair of meshes
|
||||
SVA.clear();
|
||||
for (auto vi = std::begin(VAMap); vi != std::end(VAMap); ++vi) {
|
||||
if (vi->second > 0) {
|
||||
int m_s = vi->first.first;
|
||||
int m_t = vi->first.second;
|
||||
int area = vi->second;
|
||||
SVA.push_back( OGArcInfo (m_s,m_t,area,float(area)/float(min(VM[m_s].area,VM[m_t].area)) ));
|
||||
}
|
||||
}
|
||||
|
||||
// Compute Mesh Coverage
|
||||
for (std::size_t i = 0; i < SVA.size(); ++i) {
|
||||
VM[SVA[i].s].coverage += SVA[i].area;
|
||||
VM[SVA[i].t].coverage += SVA[i].area;
|
||||
}
|
||||
|
||||
std::sort(std::begin(SVA), std::end(SVA));
|
||||
std::reverse(std::begin(SVA), std::end(SVA));
|
||||
}
|
||||
|
||||
void ComputeUsefulMesh(FILE *elfp) {
|
||||
|
||||
int mcnt = 0;
|
||||
std::vector<int> UpdArea(mn);
|
||||
std::vector<int> UpdCovg(mn);
|
||||
|
||||
for (std::size_t m = 0; m < mn; ++m) {
|
||||
|
||||
if (VM[m].used && VM[m].area > 0) {
|
||||
mcnt++;
|
||||
UpdCovg[m]=VM[m].coverage;
|
||||
UpdArea[m]=VM[m].area;
|
||||
}
|
||||
}
|
||||
|
||||
int sz = G.size();
|
||||
if (elfp) {
|
||||
std::fprintf(elfp, "\n\nComputing Usefulness of Meshes of %i(on %i) meshes\n Og with %i / %i fill ratio %i max mesh per cell\n\n", mcnt, mn, TotalArea, sz, MaxCount);
|
||||
std::fprintf(elfp, "\n");
|
||||
}
|
||||
|
||||
int CumArea = 0;
|
||||
|
||||
for (std::size_t m = 0; m < mn-1; ++m) {
|
||||
|
||||
int best = max_element(std::begin(UpdArea), std::end(UpdArea)) - std::begin(UpdArea);
|
||||
|
||||
CumArea += UpdArea[best];
|
||||
if (UpdCovg[best] < 0) break;
|
||||
|
||||
// se era una mesh fuori del working group si salta tutto.
|
||||
if (VM[best].area == 0) continue;
|
||||
|
||||
if (elfp) {
|
||||
fprintf(elfp, "%3i %3i %7i (%7i) %7i %5.2f %7i(%7i)\n",
|
||||
m, best, UpdArea[best], VM[best].area, TotalArea - CumArea,
|
||||
100.0 - 100 * float(CumArea) / TotalArea, UpdCovg[best], VM[best].coverage);
|
||||
}
|
||||
|
||||
UpdArea[best] = -1;
|
||||
UpdCovg[best] = -1;
|
||||
|
||||
for (std::size_t i = 0; i < sz; ++i) {
|
||||
|
||||
MeshCounter &mc = G.grid[i];
|
||||
|
||||
if (mc.IsSet(best)) {
|
||||
|
||||
mc.UnSet(best);
|
||||
|
||||
for (std::size_t j = 0; j < mn; ++j) {
|
||||
if (mc.IsSet(j)) {
|
||||
--UpdArea[j];
|
||||
UpdCovg[j]-=mc.Count();
|
||||
}
|
||||
}
|
||||
|
||||
mc.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dump(FILE *fp) {
|
||||
|
||||
std::fprintf(fp, "Occupancy Grid\n");
|
||||
std::fprintf(fp, "grid of ~%i kcells: %d x %d x %d\n", G.size(), G.siz[0], G.siz[1], G.siz[2]);
|
||||
std::fprintf(fp, "grid voxel size of %f %f %f\n", G.voxel[0], G.voxel[1], G.voxel[2]);
|
||||
|
||||
std::fprintf(fp,"Computed %lu arcs for %i meshes\n", SVA.size(), mn);
|
||||
|
||||
for (std::size_t i=0;i<VM.size();++i) {
|
||||
|
||||
if (VM[i].used) {
|
||||
|
||||
std::fprintf(fp, "mesh %3lu area %6i covg %7i (%5.2f%%) DensDistr:", i, VM[i].area, VM[i].coverage, float(VM[i].coverage)/float(VM[i].area));
|
||||
|
||||
for (std::size_t j = 0; j < std::min(static_cast<std::size_t>(8), VM[i].densityDistribution.size()); ++j) {
|
||||
std::fprintf(fp," %3i ", VM[i].densityDistribution[j]);
|
||||
}
|
||||
|
||||
std::fprintf(fp,"\n");
|
||||
}
|
||||
else {
|
||||
std::fprintf(fp, "mesh %3lu ---- UNUSED\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
std::fprintf(fp, "Computed %lu Arcs :\n", SVA.size());
|
||||
|
||||
for (std::size_t i = 0; i <SVA.size() && SVA[i].norm_area > .1; ++i) {
|
||||
std::fprintf(fp, "%4i -> %4i Area:%5i NormArea:%5.3f\n", SVA[i].s, SVA[i].t, SVA[i].area, SVA[i].norm_area);
|
||||
}
|
||||
|
||||
std::fprintf(fp, "End OG Dump\n");
|
||||
}
|
||||
|
||||
void ComputeTotalArea() {
|
||||
|
||||
using uint = unsigned int;
|
||||
|
||||
int ccnt = 0;
|
||||
MaxCount = 0;
|
||||
|
||||
int sz=G.size();
|
||||
|
||||
for (int i = 0; i < sz; ++i)
|
||||
|
||||
if (!G.grid[i].Empty()) {
|
||||
|
||||
ccnt++;
|
||||
if (G.grid[i].Count() > static_cast<uint>(MaxCount)) {
|
||||
MaxCount = G.grid[i].Count();
|
||||
}
|
||||
}
|
||||
|
||||
TotalArea = ccnt;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif //VCGLIB_OCCUPANCY_GRID_H
|
Loading…
Reference in New Issue