Jorge is that for my STL version using reserve(16) on the vert arrays ? or the “traditional” using AdjFaceList & ElementFromFace ? never mind i’ve noticed the links Try the STL version
here the maxalloc.h file
#ifndef __MAXMALLOC_H__
#define __MAXMALLOC_H__
#include "maxheapdirect.h"
#include <memory>
#include <limits>
#include "..\resource\resource.h"
//********************************************************************************************
// stl allocator using max_new
template <typename T> class MaxAlloc
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template <typename U> struct rebind { typedef MaxAlloc[u] other; };
MaxAlloc() throw() {}
MaxAlloc(const MaxAlloc&) throw() {}
template <typename U> MaxAlloc(const MaxAlloc[u]&) throw() {}
~MaxAlloc() throw() {}
MaxAlloc& operator=( const MaxAlloc& ) { return *this; }
pointer address(reference r) const { return &r; }
const_pointer address(const_reference c) const { return &c; }
size_type max_size() const { return (std::numeric_limits<size_t>::max)() / sizeof(T); }
void construct( pointer p, const_reference c ) { new( reinterpret_cast<void*>(p) ) T(c); }
void destroy( pointer p ) { (p)->~T(); }
pointer allocate(size_type n, const void* = NULL)
{
void* p = MAX_new(n * sizeof(T));
if(p == NULL) throw RuntimeError(GetString(IDS_STL_MEMORY_ALLOCATION_FAILED)); // throw std::bad_alloc();
return pointer(p);
}
void deallocate(void* p, size_type )
{
if(p == NULL) return;
MAX_delete(p);
}
};
template <typename T1, typename T2>
bool operator==( const MaxAlloc<T1>&, const MaxAlloc& ) throw() { return true; }
template <typename T1, typename T2>
bool operator!=( const MaxAlloc<T1>&, const MaxAlloc& ) throw() { return false; }
//********************************************************************************************
// stl allocator using max_mallox
template <typename T> class MaxMallocAlloc
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template <typename U> struct rebind { typedef MaxMallocAlloc[u] other; };
MaxMallocAlloc() throw() {}
MaxMallocAlloc( const MaxMallocAlloc& ) throw() {}
template <typename U> MaxMallocAlloc( const MaxMallocAlloc[u]& ) throw() { }
~MaxMallocAlloc() throw() {}
MaxMallocAlloc& operator=( const MaxMallocAlloc& ) { return *this; }
pointer address( reference r ) const { return &r; }
const_pointer address( const_reference c ) const { return &c; }
size_type max_size() const { return (std::numeric_limits<size_t>::max)()/sizeof(T); }
void construct( pointer p, const_reference c ) { new( reinterpret_cast<void*>(p) ) T(c); }
void destroy( pointer p ) { (p)->~T(); }
pointer allocate( size_type n, const void* = NULL )
{
void* p = MAX_malloc(n * sizeof(T));
if(p == NULL) throw RuntimeError(GetString(IDS_STL_MEMORY_ALLOCATION_FAILED)); //throw std::bad_alloc();
return pointer(p);
}
void deallocate( void* p, size_type )
{
if( p == NULL ) return;
MAX_free(p);
}
};
template <typename T1, typename T2>
bool operator==( const MaxMallocAlloc<T1>&, const MaxMallocAlloc& ) throw(){ return true; }
template <typename T1, typename T2>
bool operator!=( const MaxMallocAlloc<T1>&, const MaxMallocAlloc& ) throw() { return false; }
#endif
[/u][/u][/u][/u]
A C# version of the algorithm isn’t too bad, but passing the array back to Max takes too long unfortunately and it uses a lot of memory from the Heap.
it’s much the same for the SDK 25% is taken up by append
just about my final version
typedef std::vector < int, MaxAlloc < int > > ivector;
def_struct_primitive(meshop_getAllElements, meshop, "getAllElements");
Value* meshop_getAllElements_cf(Value** arg_list, int count)
{
check_arg_count(getAllElements, 1, count);
Mesh* mesh = get_meshForValue(arg_list[0], MESH_READ_ACCESS, NULL, getAllElements);
int numv = mesh->numVerts;
int numf = mesh->numFaces;
BitArray faces(numf);
std::vector < ivector, MaxAlloc < ivector > > verts(numv);
for(std::vector < ivector, MaxAlloc < ivector > >::iterator it = verts.begin(); it != verts.end(); ++it) it->reserve(16);
one_typed_value_local(Array* result);
vl.result = new Array(0);
Face* faceptr = mesh->faces;
for(int i = 0; i < numf; ++i, ++faceptr)
{
verts[faceptr->v[0]].push_back(i);
verts[faceptr->v[1]].push_back(i);
verts[faceptr->v[2]].push_back(i);
}
faceptr = mesh->faces;
for(int i = 0; i < numf; ++i)
{
if(faces[i]) continue;
ivector element;
element.reserve(4096);
element.push_back(i);
for(unsigned int j = 0; j < element.size(); ++j)
{
int fi = element[j];
if(faces[fi]) continue;
Face& f = faceptr[fi];
for(int k = 0; k < 3; ++k)
{
int v = f.v[k];
if(verts[v].empty()) continue;
element.insert(element.end(), verts[v].begin(), verts[v].end()); // cannot use iterators with this here
verts[v].clear();
}
faces.Set(fi);
}
BitArray fbits(numf);
for(ivector::iterator it = element.begin(); it != element.end(); ++it) fbits.Set(*it);
vl.result->append(new BitArrayValue(fbits));
}
return_value(vl.result);
}
this is fastest version for me:
{
int numf = mesh->numFaces;
int numv = mesh->numVerts;
Tab<Tab verts;
verts.SetCount(numv);
Tab<BitArray> elements;
for (int i = 0; i < numf; i++) if (faces[i])
{
Face& f = mesh->faces[i];
for (int k = 0; k < 3; k++)
{
if (!verts[f.v[k]]) verts[f.v[k]] = new Tab<int>();
verts[f.v[k]]->Append(1, &i);
}
}
for (int i = 0; i < numf; i++) if (faces[i])
{
Tab<int> element;
element.Append(1, &i);
BitArray fbits(numf);
for (int j = 0; j < element.Count(); j++)
{
int fi = element[j];
if (!fbits[fi])
{
Face& f = mesh->faces[fi];
for (int k = 0; k < 3; k++)
{
int v = f.v[k];
if (!verts[v]) continue;
element.Append(verts[v]->Count(), verts[v]->Addr(0));
delete verts[v];
verts[v] = NULL;
}
fbits.Set(fi);
faces.Clear(fi);
}
}
elements.Append(1, &fbits);
}
return elements;
}
where faces is all faces.
i’ve excluded return to mxs from computation it this snippet.
verts[v] = NULL;
should be replaced with
delete verts[v];
verts[v] = NULL;
should be… but it crashes the function for big meshes with ** system exception **
i’ve reverted everything back to Tab<Tab<int>>…
also i’ve understood that AdjFaceList method doesn’t work for me in many cases. if ‘elements’ share a vert they are one elements in my algorithms.
Thank you Klunk! This one compiled without issues and it’s pretty fast. I’ve updated the tests post.
PD: @Admin will someone ever update/fix/improve the formatting options of this forum (among other things)?
yeah, you could quite easily create meshes to slow it back down, models with lots of 32 face fans for example (though you could add a maximum faces per vert hint to the function argument list) but for genearal quad meshes you could even drop it to say 12 to decrease the memory foot print a tad.
should be… but it crashes the function for big meshes with ** system exception **
have you tried a “safe” delete Denis? (though I don’t think it’s causing the crash)
if(verts[v]) delete verts[v];
verts[v] = NULL;