Notifications
Clear all

[Closed] remaking geometry theory c++

Remaking a copy of an object but fixing all it’s problems. problem geometry could be something you might have extracted from google earth. So just wanted to get your thoughts on how other people might attack this problem.

bad geometry might have…

[ol]
[li]- double faces[/li][li]- holes in the mesh[/li][li]- unwelded verts[/li][li]- flipped normals[/li][li]- isolated verts or faces[/li][/ol]

The goal would be to remake this geometry or just repair it. But where to start?

[ol]
[li]- You could get a facelist and find what verts belong to that face and see if any other verts are in the same POS[/li][li]- You would want to find verts between 2 other verts[/li][li]- fill holes in the mesh[/li][/ol]

any thoughts?

17 Replies

i think you have to start from loading the data anyhow and convert it to MNMesh. because poly methods look more advanced than mesh’s

Ok, lets look at repairing our Geo. So Node ->to Obj ->to MNMesh.

I guess the first thing would be…

1 – weld all our Verts with 0.01 threshhold.
2 – I would do is remove any verts that have no faces.
3 – find any verts with only 2 edges and get the two vector of the edge and see if they match. If they do we could remove them or flag them

first step after conversion has to be “delete isolated verts” and “delete dead structures”

if you need to do a lot of spacial nearest vert stuff (esoecially if faces are not connected) then the first thing you would do is build a kdtree or similar to speed it up.

1 Reply
(@denist)
Joined: 1 year ago

Posts: 0

i was always been intrigued with your kdtree approach. i have my own. i don’t ask about a code or details of implementation, but will be very interesting to compare our result.

let say a task:

prepare a data for 100K verts mesh (time and memory use)

find closest vert to a specified point (time)

find 100 closest verts to a specified point, and return them in nearest order (time)

So remember still new to the SDK.

Got a start on this, but can’t find a get face from vert to see if a vert has no face it must be an isolated vert.


void RepairGeo(INode* Node){
	Object *Obj = Node->EvalWorldState(TimeValue(0)).obj;
	if (Obj->CanConvertToType(Class_ID(POLYOBJ_CLASS_ID, 0))) {
		PolyObject *PolyObj = (PolyObject *)Obj->ConvertToType(TimeValue(0), Class_ID(POLYOBJ_CLASS_ID, 0));
		if (PolyObj){
			MNMesh *pMesh = &PolyObj->mm;

			/// find Isolated verts
			for (int i=0; i < pMesh->VNum(); i++){
				int FaceCount;
				FaceCount = 0; // get face from vert --- pMesh->VFaceIndex(i, ?, ?);
				if(FaceCount == 0){
					pMesh->RemoveVertex(i);
				}
			}
			pMesh->CollapseDeadStructs();
			pMesh->EliminateCollinearVerts();
			pMesh->EliminateCoincidentVerts(0.01);
		}
	}
}

Also thing I should be using
Object* objectRef=Node->GetObjectRef();

1 Reply
(@denist)
Joined: 1 year ago

Posts: 0

check EPoly methods as well (EpfnDeleteIsoVerts ())

memory approx is 28 bytes per vert, as for timing not really done any tests but the overhead is building the tree, as it’s usually a one time thing and once built where the mesh is static the look up is trivial.

average look up is 0(log n)

1 Reply
(@denist)
Joined: 1 year ago

Posts: 0

found this link http://rosettacode.org/wiki/K-d_tree
it looks like everything there, doesn’t it?

for my algorithm it takes a time to build a data. for 100K points it’s about 0.2-0.4s
after that everything is very fast… something like find closest point for every stored point is about 0.1s

pretty much, it’s all out in the public domain, for what it’s worth this is what I use, we can simplify as were only ever interested in point3, it also helps to index into the original mesh and or use faces centers not verts when you want to constrain ray tracing

#include <max.h>
  #include <vector>
  #include <float.h>
  
  #define SAFE_DELETE(a) if( (a) != NULL ) delete (a); (a) = NULL;
  #define SQ(x) ((x)*(x))
  
  inline float dsqu(const Point3& a,const Point3& b) 
  { 
  	Point3 c(a.x - b.x, a.y - b.y, a.z - b.z);
  	return c.LengthSquared();
  }
  
  struct kd3node : public MaxHeapOperators
  {
  	Point3	pos;	// point position
  	int		dir;	// direction of the slice
  	int		index;	// vert or face index in the mesh
  	kd3node	*left; 
  	kd3node	*right; 
  
  	kd3node(const Point3& p, const int d, const int i) : pos(p), dir(d), index(i), left(NULL), right(NULL) {}
  	~kd3node() { SAFE_DELETE(left); SAFE_DELETE(right); }
  	float slice() const { return pos[dir]; }
  	int nextdir() const { return (dir + 1) % 3; }
  	float delta(const Point3& p) const { return p[dir] - pos[dir]; }
  	float dsqu(const Point3& p) const { return ::dsqu(pos,p); }
  };
  
  class kd3tree : public MaxHeapOperators
  {
  	enum buildtype { verts, faces };
  
  	int	size;
  	kd3node *root;
  
  public:
  
  	kd3tree() : root(NULL) {}
  	kd3tree(Mesh& mesh, bool useverts = true) : root(NULL) { useverts ? buildfromverts(mesh) : buildfromfaces(mesh); }
  	~kd3tree() { clear(); }
  	void clear() { SAFE_DELETE(root); size = 0; }
  	kd3node* findnearest(const Point3 &pos)
  	{
  		kd3node* result = root;  
  		float dist_sq = result->dsqu(pos);
  		traverse(root, pos, &result, dist_sq); 
  		return result;
  	}
  	int findnearest(const Point3 &pos, float range, BitArray& result)
  	{
  		result.SetSize(size);
  		return traverse(root, pos, range, result);
  	}
  	void buildfromverts(Mesh& mesh);
  	void buildfromfaces(Mesh& mesh);
  	int getSize() { return size; }
  
  protected:
  
  	kd3node* insert(kd3node **nptr, const Point3 &pos, int i, int dir);
  	int insert(const Point3 &pos, int i) { return insert(&root, pos, i, 0) ? 0 : -1; }
  	void traverse(kd3node *node, const Point3 &pos, kd3node **result, float& result_dist_sq);
  	int traverse(kd3node *node, const Point3 &pos, float range, BitArray& result);
  };
  
  kd3node* kd3tree::insert(kd3node **nptr, const Point3 &pos, int i, int dir)
  {
  	if(!*nptr) 
  	{
  		*nptr = new kd3node(pos,dir,i);
  		size++;
  		return *nptr;
  	}
  	kd3node* n = *nptr;
  	return pos[n->dir] < n->slice() ? insert(&n->left,pos,i,n->nextdir()) : insert(&n->right,pos,i,n->nextdir());
  }
  
  // nearest traverse
  
  void kd3tree::traverse(kd3node *node, const Point3 &pos, kd3node **result, float& result_dist_sq)
  {
  	if(!node) return;
  
  	kd3node* near_node = node->right; 
  	kd3node* far_node = node->left;
  	if(node->delta(pos) <= 0)  // reverse the tree ?
  	{
  		near_node = node->left;
  		far_node = node->right;
  	} 
  	
  	if(near_node) 
  		traverse(near_node, pos, result, result_dist_sq);
  	if(far_node) 
  		traverse(far_node, pos, result, result_dist_sq); 
  
  // Check the distance of the point at the current node, compare it with our best so far
  
  	float dist_sq = node->dsqu(pos);
  	if (dist_sq < result_dist_sq)  
  	{
  		*result = node;
  		result_dist_sq = dist_sq;
  	}
  }
  
  // range traverse
  
  int kd3tree::traverse(kd3node *node, const  Point3 &pos, float range, BitArray& result)
  {
  	if(!node) return 0;
  
  	float  dist_sq = node->dsqu(pos);
  	int ret, added_res = 0;
  
  	if(dist_sq <= SQ(range)) 
  	{
  		result.Set(node->index);
  		added_res = 1;
  	}
  
  	float dx = node->delta(pos);
  	ret = traverse(dx <= 0.0 ? node->left : node->right, pos, range, result);
  	if(ret >= 0 && fabs(dx) < range) 
  	{
  		added_res += ret;
  		ret = traverse(dx <= 0.0 ? node->right : node->left, pos, range, result);
  	}
  	if(ret == -1)
  		return -1;
  
  	added_res += ret;
  	return added_res;
  }
  
  void kd3tree::buildfromverts(Mesh& mesh)
  {
  	int numverts = mesh.numVerts;
  	Point3* verts = mesh.verts;
  	for(int v = 0; v < numverts; ++v)
  		insert(verts[v],v);
  }
  void kd3tree::buildfromfaces(Mesh& mesh)
  {
  	int numfaces = mesh.numFaces;
  	for(int f = 0; f < numfaces; ++f)
  		insert(mesh.FaceCenter(f),f);
  }
  

in reality it’s pretty simple stuff and should be part of the max core mesh interface reducing 100000 compares to 5 is not to be sniffed at

thank you very much for the code… it looks very safe for memory use…

the only thing that i’m not sure that is safe to get closest by face center. it doesn’t automatically mean that all close enough verts belongs a face with closest center. it’s probably safer to re-calc bary to world point and search by verts.

(tomorrow i will try to implement you code. thanks again)

Page 1 / 2