Notifications
Clear all

[Closed] Need help finishing / debugging script

only two? how is about no one?
i repeat my question… what does make a face area zero?

Seems I was editing the post at the same time. The sentence should have been: “This code does not deal with 3 inline vertices.”

Calculating the area T of a triangle is an elementary problem encountered often in many different situations. The best known and simplest formula is:

T = 1/2bh

where b is the length of the base of the triangle, and h is the height or altitude of the triangle.

which means that if any angle of triangle is Zero the Area is Zero.

2 Replies
(@polytools3d)
Joined: 11 months ago

Posts: 0

Which means that the 3 vertices are inline?

(@denist)
Joined: 11 months ago

Posts: 0

all three vertices might be in the same point, or two of them, or no one. but for sure two angles of this triangle must be zero, and one 180.

now you have to clear understand that a welding of zero-area triangle vertices is not a trivial task.

ps. a face deleting method we can discuss for isolated faces only

1 Reply
(@polytools3d)
Joined: 11 months ago

Posts: 0

Sure, and in many cases it won’t be even possible, so you would need to build new faces.

Well, as I mentioned earlier, vertices might not always need to be welded. It all depends on what you need so I wouldn’t adventure to claim that face deleting must be only for isolated faces.
Think about this, perhaps there is a chance that you do want those holes after all, even if it doesn’t make sense in most cases.

what is the most problem of ‘welding’?

we might move vertices in some cases

we can distort uvs

what is the most problem of ‘deleting’?

we might make new open edges

we can break ‘smoothing’

In my case all 0A faces are garbage, byproduct of software that imported the geometry from non-native format.
They all need to be deleted. Their removal does not effect ‘useful’ geometry.
The question is how to do it efficiently.

Kameleon
Sent you a pm.

1 Reply
(@polytools3d)
Joined: 11 months ago

Posts: 0

So what you are saying is that your code is already producing the results you need, meaning you don’t need any vertex welding?
If this is correct then this code should be pretty efficient.

#we might need to add new faces if can’t move a vertex

Here is an adapted version of your script that should perform very well, though I would restructure the whole script.
PS: if you are on Max 2010 or below, you will need to comment out the “processPostedMessages” line.

(
  
  try(destroydialog ::Myroll) catch()
  
  total_f	 = 0
  processed_f = 0
  
  lp_count  = 0
  lp_thresh = 5000
  
  df_count  = 0
  df_thresh = 5000
  df_total  = 0
  
  lp_fdelta = 0
  lp_flast  = 0
  
  for o in (selection as array) do total_f += o.numfaces
  
  format "Total faces selected: %
" (formattedPrint total_f format:"8.0u")
  
  rollout Myroll "Del 0 area faces"
  (
  	
  	button bt_start "Start" width:100
  	
  	
  	on bt_start pressed do
  	(
  		st = lp_tlast = lp_tdelta = timestamp()
  
  		exit_bool = 0
  		
  		_getFaceArea = meshop.getFaceArea
  		_deleteFaces = meshop.deleteFaces
  		
  		for o in (selection as array) while exit_bool != 1 do 
  		(
  			faceSel = #{}
  			obj_tot_f = o.numfaces
  			
  			for f = 1 to o.numfaces while exit_bool != 1 do
  			(
  				if keyboard.escpressed then exit_bool = 1
  					
  				if (_getFaceArea o f) == 0 do
  				(
  					append faceSel f
  					df_total += 1
  				)
  				
  				if lp_count == lp_thresh then
  				(
  					
  					lp_tdelta = timestamp() - lp_tlast
  					lp_tlast = timestamp()
  					
  					lp_fdelta = processed_f - lp_flast
  					lp_flast = processed_f
  					
  					clearlistener()
  					eta1 = (lp_tdelta ) * (total_f - processed_f) / (lp_thresh * 1000) --seconds
  					
  					fps_o = (1000.0*processed_f/(lp_tlast - st))
  					fps_l = (1000.0*lp_fdelta/lp_tdelta)
  					
  					format "
"
  					format "Obj Total F: [ % ]   Name:   [ % ] 
" (formattedPrint obj_tot_f format:"8.0u") o.name
  					format "
"
  					format "F Sel buffr: [ % ]   Last loop:   [ % ]   FPS loop:   [ % ]   FPS overall:   [ % ] 
" (formattedPrint faceSel.numberset format:"8.0u") (formattedPrint lp_tdelta format:"6.0u") (formattedPrint fps_l format:"10.0f") (formattedPrint fps_o format:"10.0f")
  					format "
"
  					format " [ % ]  [ % ] / [ % ]   Removed: [ % ]   Percent: [ % ] 
" (formattedPrint (100.0*processed_f/total_f) format:"6.2f") (formattedPrint processed_f format:"8.0u") (formattedPrint total_f format:"8.0u") (formattedPrint df_total format:"8.0u") (formattedPrint (100.0*df_total/processed_f) format:"6.2f")
  					format "
"
  					format "ETA 1: % secs / % mins   Elapsed: % secs / % mins 
" (formattedPrint eta1 format:"7.0f") (formattedPrint (eta1/60) format:"7.2f") (formattedPrint ((lp_tlast - st)/1000) format:"7.0u") (formattedPrint (1.0*(lp_tlast - st)/60000) format:"7.2f")
  					
  					lp_count = 1
  					
  				)
  				else
  				(
  					lp_count += 1
  				)
  				
  				processed_f += 1
  				
  			)
  			
  			_deleteFaces o faceSel
  			windows.processPostedMessages()
  			
  		)
  		
  		lp_tlast = timestamp()
  		fps_o = (1000.0*processed_f/(lp_tlast - st))
  		
  		format "
"
  		format "----------------------------------------------------------------------------------------------
"
  		format " [ % ]  [ % ] / [ % ]   Removed: [ % ]   Percent: [ % ] 
" (formattedPrint (100.0*processed_f/total_f) format:"6.2f") (formattedPrint processed_f format:"8.0u") (formattedPrint total_f format:"8.0u") (formattedPrint df_total format:"8.0u") (formattedPrint (100.0*df_total/processed_f) format:"6.2f")
  		format "Elapsed: % secs / % mins   FPS:   [ % ]
" (formattedPrint ((lp_tlast - st)/1000) format:"7.0u") (formattedPrint ((1.0*lp_tlast - st)/60000) format:"7.2f") (formattedPrint fps_o format:"10.0f")
  		
  	)
  )
  
  createDialog Myroll width:300 height:200
  
  )

Thank you for your effort…
However, I don’t see any meaningful difference from the code I wrote. As far as I can see, the problem is in selection gathering and your code is using append same as mine.
Why do you think it will be more efficient?
That being said, I will try it when I have the chance, ofc…

1 Reply
(@polytools3d)
Joined: 11 months ago

Posts: 0

One of the big slowdown in your code was because of the Modify panel and the selection of faces, even if you turn off redraw and undo.

   This process if highly optimized if you just use “meshop.deleteFaces” instead, and avoid working with modifiers and selecting/deselecting faces.
   
The other mayor slowdown (which I just found), was caused by the “meshop.getFaceArea” function as I’ve described in my previous post.
  
 This is at least what I’ve found. Perhaps it is working different on your end, but on my end I get these results:
  
  Here is a brief comparison between the original code and the later optimizations:

Optimization 1: avoid the use of Modify Panel and face selection
Optimization 2: avoid the use of meshop.getFaceArea

The code can be further optimized, but the latest one runs around 20/30 times faster and uses half the memory, which is not bad.


nodes = 50
faces = 41600

time:6261 ram:10340720L ORIGINAL
time: 350 ram: 4876232L OPTIMIZATION 1
time: 286 ram: 4873024L OPTIMIZATION 2

nodes = 1
faces = 41600

time:8395 ram:10327144L ORIGINAL
time:5859 ram: 4870776L OPTIMIZATION 1
time: 278 ram: 4870592L OPTIMIZATION 2

Actually one of the things causing a big slowdown was “meshop.getFaceArea”, which seems to get exponentially slower the higher the number of the mesh faces is.

 So for 100 objects with 1000 faces each, it is pretty fast, but for 1 object with 100000 faces it is unbelievable slow.

 Also, depending on how the feedback is working for you, you may want to move the “windows.processPostedMessages()” inside the face loop and trigger it every 1.5/2.0 seconds.

 I just have it on the nodes loop, as it works well on my tests.

 Ok, here is a new version with a custom code for the face area. Hope it works well for you. 
(
     
     try(destroydialog ::Myroll) catch()
     
     total_f	 = 0
     processed_f = 0
     
     lp_count  = 0
     lp_thresh = 5000
     
     df_count  = 0
     df_thresh = 5000
     df_total  = 0
     
     lp_fdelta = 0
     lp_flast  = 0
     
     for o in (selection as array) do total_f += o.numfaces
     
     format "Total faces selected: %
" (formattedPrint total_f format:"8.0u")
     
     rollout Myroll "Del 0 area faces"
     (
   	  
   	  button bt_start "Start" width:100
   	  
   	  
   	  on bt_start pressed do
   	  (
   		
   		  st = lp_tlast = lp_tdelta = timestamp()
     
   		  exit_bool = 0
   		  
   		  _deleteFaces = meshop.deleteFaces
   		  
   		  for o in (selection as array) while exit_bool != 1 do 
   		  (
   			  faceSel = #{}
   			  obj_tot_f = o.numfaces
   			  
   			  for f = 1 to o.numfaces while exit_bool != 1 do
   			  (
   				  if keyboard.escpressed then exit_bool = 1
   				
   				face = getface o f
   				v1 = getvert o face[1]
   				v2 = getvert o face[2]
   				v3 = getvert o face[3]
   				area = length (cross (v1-v2) (v1-v3))/2.0
   				
   				  if area == 0 do
   				  (
   					  append faceSel f
   					  df_total += 1
   				  )
   				  
   				  if lp_count == lp_thresh then
   				  (
   					  
   					  lp_tdelta = timestamp() - lp_tlast
   					  lp_tlast = timestamp()
   					  
   					  lp_fdelta = processed_f - lp_flast
   					  lp_flast = processed_f
   					  
   					  clearlistener()
   					  eta1 = (lp_tdelta ) * (total_f - processed_f) / (lp_thresh * 1000) --seconds
   					  
   					  fps_o = (1000.0*processed_f/(lp_tlast - st))
   					  fps_l = (1000.0*lp_fdelta/lp_tdelta)
   					  
   					  format "
"
   					  format "Obj Total F: [ % ]   Name:   [ % ] 
" (formattedPrint obj_tot_f format:"8.0u") o.name
   					  format "
"
   					  format "F Sel buffr: [ % ]   Last loop:   [ % ]   FPS loop:   [ % ]   FPS overall:   [ % ] 
" (formattedPrint faceSel.numberset format:"8.0u") (formattedPrint lp_tdelta format:"6.0u") (formattedPrint fps_l format:"10.0f") (formattedPrint fps_o format:"10.0f")
   					  format "
"
   					  format " [ % ]  [ % ] / [ % ]   Removed: [ % ]   Percent: [ % ] 
" (formattedPrint (100.0*processed_f/total_f) format:"6.2f") (formattedPrint processed_f format:"8.0u") (formattedPrint total_f format:"8.0u") (formattedPrint df_total format:"8.0u") (formattedPrint (100.0*df_total/processed_f) format:"6.2f")
   					  format "
"
   					  format "ETA 1: % secs / % mins   Elapsed: % secs / % mins 
" (formattedPrint eta1 format:"7.0f") (formattedPrint (eta1/60) format:"7.2f") (formattedPrint ((lp_tlast - st)/1000) format:"7.0u") (formattedPrint (1.0*(lp_tlast - st)/60000) format:"7.2f")
   					  
   					  lp_count = 1
   					  
   				  )
   				  else
   				  (
   					  lp_count += 1
   				  )
   				  
   				  processed_f += 1
   				  
   			  )
   			  
   			  _deleteFaces o faceSel
   			  windows.processPostedMessages()
   			  
   		  )
   		  
   		  lp_tlast = timestamp()
   		  fps_o = (1000.0*processed_f/(lp_tlast - st))
   		  
   		  format "
"
   		  format "----------------------------------------------------------------------------------------------
"
   		  format " [ % ]  [ % ] / [ % ]   Removed: [ % ]   Percent: [ % ] 
" (formattedPrint (100.0*processed_f/total_f) format:"6.2f") (formattedPrint processed_f format:"8.0u") (formattedPrint total_f format:"8.0u") (formattedPrint df_total format:"8.0u") (formattedPrint (100.0*df_total/processed_f) format:"6.2f")
   		  format "Elapsed: % secs / % mins   FPS:   [ % ]
" (formattedPrint ((lp_tlast - st)/1000) format:"7.0u") (formattedPrint ((1.0*lp_tlast - st)/60000) format:"7.2f") (formattedPrint fps_o format:"10.0f")
   		  
   	  )
   	
     )
     
     createDialog Myroll width:300 height:200
     
   )
1 Reply
(@denist)
Joined: 11 months ago

Posts: 0
 the time of computation of mesh face area doesn't depend on number faces in the mesh. in your case the slowing down caused by printing the info in the listener. longer listener - slower code execution.
 
 to make everything works more or less right we have to check that our nodes in list are kinda meshes or OK to be converted to mesh. because we want to delete zero faces it's ok to collapse a stack. so 
 here is a possible realization:

     try(destroydialog zeroFaceHunter) catch()
rollout zeroFaceHunter "ZeroFace Hunter" width:200
(
	button hunt_bt "Start Hunting" width:192 pos:[4,4]
	
	local min_area = 0.0
	on hunt_bt pressed do 
	(
		local ready_for_clean = #()

		local getfacearea = meshop.getfacearea		
		local canceled = off, meshes = 0, zerofaces = 0, allfaces = 0
		t1 = timestamp()
		m1 = heapfree
		for node in selection while not (canceled = keyboard.escpressed) where canconvertto node editable_mesh do
		(
			meshes += 1
			mesh = snapshotasmesh node
			allfaces += (num = mesh.numfaces) 
			faces = #{}
			for f=1 to num while not (canceled = keyboard.escpressed) where (getfacearea mesh f) <= min_area do append faces f
			if not faces.isempty do 
			(
				append ready_for_clean #(node, faces)
				zerofaces += faces.numberset
			)
		)
		t2 = timestamp()
		m2 = heapfree
		if not canceled then
		(
			if zerofaces > 0 then 
			(
				if 
				(
					querybox (ready_for_clean.count as string + " node(s) and " + zerofaces as string + " faces are waiting.
 Do you want to clean them up?") title:"ZeroFace Hunter:"
				)
				do undo "Delete ZERO faces" on
				(
					suspendEditing()
					deletefaces = meshop.deletefaces
					
					t3 = timestamp()
					m3 = heapfree
					for node in ready_for_clean do
					(
						converttomesh node[1]
						deletefaces node[1] node[2]  
					)
					t4 = timestamp()
					m4 = heapfree
					
					format "pocessed:
	nodes:% faces:%
" meshes allfaces  
					format "searched:
	time:% memory:%
" (t2-t1) (m1-m2) 
					format "deleted:
	time:% memory:%
" (t4-t3) (m3-m4)
					
					resumeEditing() 
				)
			)
			else messagebox "There is no nodes to clean." title:"ZeroFace Hunter:"
		)
		else messagebox "The hunting was canceled. See you next time." title:"ZeroFace Hunter:"
		gc light:on 
		format
	)
)
createdialog zeroFaceHunter

     

edited… some info added… made undoable

Page 2 / 4