Notifications
Clear all

[Closed] How to quickly eliminate elements with lowest face count?

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);
}
1 Reply
(@polytools3d)
Joined: 10 months ago

Posts: 0

If I ever get it to compile I’ll try it.

c# sdk to mxs values casting is much slower than c++ sdk.

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;

2 Replies
(@denist)
Joined: 10 months ago

Posts: 0

it’s true. i’ve fixed that. thanks

(@denist)
Joined: 10 months ago

Posts: 0

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.

scrub that this bloody hopeless

the files without cgsoc whacky formating

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;
Page 6 / 7