Notifications
Clear all

[Closed] Faces <-> vertices + angles between faces

I want to figure out

  1. Which faces of the selected object are being formed by which vertices
  2. What are the angles between faces of the selected object

Please share a maxscript snippet.

16 Replies

– I want to figure out:
1. Which faces of the selected object are being formed by which vertices
2. What are the angles between faces of the selected object
Verstanden?

  • Jawohl, mein lieber Freund!
    1. See GetFace or GetVertsUsingFace to get a set of verts making the face;
    2. It’s a arc-cosine of dot product of two face normals. See GetFaceNormal and dot
      Capiche?
  1. See GetFace or GetVertsUsingFace to get a set of verts making the face;
  2. It’s a arc-cosine of dot product of two face normals. See GetFaceNormal and Dot…

Nice.

Capiche?
No ;(

Verstanden? Jawohl!
Are you nazi?

 lo1

If you’re the same guy that asked this:
http://stackoverflow.com/questions/8784168/which-points-in-3d-space-form-which-face-angle-between-faces

Then I’ve answered your question there.

IIRC one issue with the normal method it won’t tell you if the angle between faces is obtuse or reflex

my methodology is therefore

convert to or create a copy as a trimesh
create a list of all internal edges
remove all the duplicate reverse edges from the list
for all edges in the list
get the 2 faces that share this edge
create a coordinate system based on face1
transform the spare vert in face2 into this system
if the spare vert z is +ve the angle is obtuse else its reflex
compute the angle as above

1 Reply
(@jormasoranen)
Joined: 10 months ago

Posts: 0

Unfortunately I am not as experienced in coding as you are. Can you share this as code I could use, please? All I know is that I am using an editable poly right now.

heres a script i wrote a long time ago that uses the method I described above, it renders edges to a bitmap dependent on edge angles, though you should try and work it out for yourself you will learn more that way.

macroScript Edge_O_Sketch
 			category: 	"Claudes_Utils"
 			buttontext:	"EdgeOSketch"
 			Icon:		#("Surface_tools",1)
 (
 	local bitmapX = bitmapY = 1024
 	local bitmapx_1 = bitmapx-1
 	local bitmapy_1 = bitmapy-1
 	local temp_bitmap_filename = (getDir #image + "/Edge_0_Sketch_temp.bmp")
 	local currentPos = lastPos = [0,0]
 	local theChannel = 1
 	local minAngle = 0.0
 	local lineWidth = 1
 	local lineColour = white
 	local lineType = 1
 	local renderPeaks = true
 	local renderAllOpenEdges = false
 	local SettingsRollout 
 
 	local theWindow
 	local noise = false
 	local noiseValue = 1.0
 	local constrainToMatID = false
 	local matID = 1
 	local theObjToRender = undefined
 	local x_sel = 7
 	local y_sel = 7
 	local bmapSizeList = #("32","64","128","256","512","768","1024","2048")
 	local bmapSizes = #(32,64,128,256,512,768,1024,2048)
 	local renderTypeList = #("Hollows","Hills","Borders","All")
 	local render_Sel = 1
 		
 --*************************************************************
 -- returns the position in a face of a particular vert or zero
 	
 	fn GetVertFaceIndex theMesh theFace theVert =
 	(
 		faceVerts = getface theMesh theFace
 		if faceVerts.x == theVert then return 1
 		if faceVerts.y == theVert then return 2
 		 if faceVerts.z == theVert then return 3
 		return 0
 	)
 	
 --**********************************************************
 	
 	fn GetTVertFromFaceIndex theMesh theFace FaceIndex =
 	(
 		tfaceVerts = getTVFace theMesh theFace 
 		if FaceIndex == 1 then return GetTVert theMesh tfaceVerts.x
 		if FaceIndex == 2 then return GetTVert theMesh tfaceVerts.y
 		if FaceIndex == 3 then return GetTVert theMesh tfaceVerts.z
 	)
 	
 --**********************************************************
 	
 	fn paintBrush theBitMap pos col = (setPixels theBitMap pos #(col))
 	
 --**********************************************************
 	
 	fn drawStroke theBitMap lastPos pos BrushSize col=
 	(
 		currentPos = lastPos
 		deltaX = pos.x - lastPos.x
 		deltaY = pos.y - lastPos.y
 	
 		maxSteps = amax #(abs(deltaX),abs(deltaY))
 	
 		deltaStepX = deltaX / maxSteps 
 		deltaStepY = deltaY / maxSteps 
 	
 		for i = 0 to maxSteps do
 		(
 			if noise then
 			(
 				for b = 1 to (BrushSize / noiseValue) do
 				(
 					paintBrush theBitMap (currentPos + (random [-BrushSize/2,-BrushSize/2] [BrushSize/2,BrushSize/2] )) col
 				)
 			)
 			else
 			(
 				for b = -BrushSize/2 to BrushSize/2 do
 				(
 					for c = -BrushSize/2 to BrushSize/2 do
 					(
 						paintBrush theBitMap (currentPos + [c,b]) col
 					)
 				)
 			)
 			currentPos += [deltaStepX, deltaStepY]
 		)  
 	)
 	
 --**********************************************************
 -- returns only those edges that have 2 faces
 	
 	fn GetInternalEdges theMesh =
 	(
 		theMesh.edges as bitarray - meshop.getOpenEdges theMesh
 	)
 	
 --*************************************************************
 	
 	fn IsEdgeVisible theMesh theEdge =
 	(
 		local theFace = ((theEdge-1)/3)+1 
 		local edgeIndex = theEdge - (theFace-1)*3
 		
 		getEdgeVis theMesh theFace edgeIndex
 	)
 	
 --*************************************************************
 -- returns the 2 faces sharing an edge
 	
 	fn GetEdgedFaces theMesh theEdge =
 	(
 		meshop.getFacesUsingEdge theMesh (#(theEdge) + meshop.getEdgesReverseEdge theMesh theEdge) as array
 	)
 	
 --**********************************************************
 -- returns the vert not used by an edge of a face
 	
 	fn GetSpareFaceVert theMesh theFace theEdge =
 	(
 		getvert themesh ((meshop.getVertsUsingFace theMesh  theFace - meshop.getVertsUsingEdge theMesh theEdge) as array)[1] 
 	)
 	
 --*************************************************************
 	
 	fn GetEdgeCreasing theMesh theEdge =
 	(
 -- get the two faces adjoining the edge
 		
 		theFaces = GetEdgedFaces theMesh theEdge
 			
 -- create a coordinate transform matrix based on the first		
 			
 		faceNormal = getFaceNormal theMesh theFaces[1]
 		faceMat = matrixFromNormal faceNormal
 	
 -- offset it to the center of the first face
 	
 		faceCenter = meshop.getFaceCenter theMesh theFaces[1]
 		faceMat.translation = faceCenter
 		
 -- get the vert from face 2 not used on the edge	
 		
 		spare = GetSpareFaceVert theMesh theFaces[2] theEdge
 	
 -- transform it into the coordinate system of the first face
 	
 		spare =  spare * (inverse faceMat)
 			
 -- we only need the z value		
 			
 		if spare.z >= 0 then return true else return false
 	)
 	
 --*************************************************************
 	
 	fn GetEdgeAngle theMesh theEdge =
 	(
 	-- get the two faces adjoining the edge
 		
 		theFaces = GetEdgedFaces theMesh theEdge
 			
 	-- get our face normals		
 			
 		v1 = getFaceNormal theMesh theFaces[1]
 		v2 = getFaceNormal theMesh theFaces[2]
 		
 	-- calculate the angle	
 	
 		theAngle = acos(dot (normalize v1) (normalize v2))
 	)
 	
 --**********************************************************
 	
 	fn GetEdgeSmG theMesh theEdge =
 	(
 	-- get the two faces adjoining the edge
 		
 		theFaces = GetEdgedFaces theMesh theEdge
 			
 		sg1=getFaceSmoothGroup theMesh theFaces[1]
 		sg2=getFaceSmoothGroup theMesh theFaces[2]	
 		
 		if sg1+sg2 == 0 then return false
 		
 		return sg1 == sg2 
 	)
 	
 --**********************************************************
 -- removes the partnered edge from a list of edges, useful because i know
 -- all my edges are shared :]
 
 	fn RemoveReverseEdges theMesh edgeList=
 	(
 		theEdges = edgeList as array
 		reqEdges = #()
 	
 		for i in theEdges do
 		(
 			if i != 0  then
 			(
 				reverseEdge = (meshop.getEdgesReverseEdge theMesh i as array)[1]
 				if (index = finditem theEdges reverseEdge) != 0 then
 				(
 					theEdges[index] = 0
 				)
 			)
 		)
 		j=1
 		for i in theEdges do
 		(
 			if i != 0 then
 			(
 				reqEdges[j] = i
 				j=j+1
 			)
 		)
 		return reqEdges 
 	)
 	
 --*************************************************************
 	
 	fn RenderEdges theObj BrushSize col =
 	(
 		local theBitmap = bitmap bitmapX bitmapY color:backgroundColor filename:temp_bitmap_filename
 
 -- clear our bitmap
 
 		--copy theBackgroundBitmap theCanvasBitmap
 	
 -- get a snapshot of the mesh	
 	
 		theMesh = snapshotAsMesh theObj
 		
 		meshop.deleteIsoMapVertsAll theMesh
 	
 		internalEdges = GetInternalEdges theMesh
 		internalEdges = RemoveReverseEdges theMesh internalEdges 
 	
 		for i in internalEdges do
 		(
 			if IsEdgeVisible theMesh i  then
 			(
 				if GetEdgeCreasing theMesh i == renderPeaks then
 				(
 					if GetEdgeAngle theMesh i > minAngle  and not GetEdgeSmG theMesh i	then
 					(
 						
 		-- get edge verts and faces				
 		
 						theVerts = meshop.getVertsUsingEdge theMesh i as array
 						theFaces = GetEdgedFaces theMesh i
 						
 						if	constrainToMatID == false then
 						(		
 	
 		-- get the UV verts
 		
 							vindex1 = GetVertFaceIndex theMesh theFaces[1] theVerts[1]
 							uvVert1 = GetTVertFromFaceIndex theMesh theFaces[1] vindex1
 							
 							
 							vindex2 = GetVertFaceIndex theMesh theFaces[1] theVerts[2]	
 							uvVert2 = GetTVertFromFaceIndex theMesh theFaces[1] vindex2
 			
 		-- draw on the bitmap
 				
 							drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
 									[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
 						
 								
 		-- get the UV verts
 		
 							vindex1 = GetVertFaceIndex theMesh theFaces[2] theVerts[1]
 							uvVert1 = GetTVertFromFaceIndex theMesh theFaces[2] vindex1
 							
 							
 							vindex2 = GetVertFaceIndex theMesh theFaces[2] theVerts[2]	
 							uvVert2 = GetTVertFromFaceIndex theMesh theFaces[2] vindex2
 			
 		-- draw on the bitmap
 				
 							drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
 									[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
 						)			
 						else
 						(
 							if getFaceMatID theMesh  theFaces[1] == matID then
 							(
 								-- get the UV verts
 			
 								vindex1 = GetVertFaceIndex theMesh theFaces[1] theVerts[1]
 								uvVert1 = GetTVertFromFaceIndex theMesh theFaces[1] vindex1
 								
 								
 								vindex2 = GetVertFaceIndex theMesh theFaces[1] theVerts[2]	
 								uvVert2 = GetTVertFromFaceIndex theMesh theFaces[1] vindex2
 				
 			-- draw on the bitmap
 					
 								drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
 										[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
 
 							
 							)
 							if getFaceMatID theMesh  theFaces[2] == matID then
 							(
 			
 			-- get the UV verts
 		
 								vindex1 = GetVertFaceIndex theMesh theFaces[2] theVerts[1]
 								uvVert1 = GetTVertFromFaceIndex theMesh theFaces[2] vindex1
 								
 								
 								vindex2 = GetVertFaceIndex theMesh theFaces[2] theVerts[2]	
 								uvVert2 = GetTVertFromFaceIndex theMesh theFaces[2] vindex2
 				
 			-- draw on the bitmap
 					
 								drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
 										[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
 							)
 						)			
 					)
 				)
 			)
 		)
 
 -- save the bitmap in temp bmp		
 		
 		save theBitmap
 		
 -- dispay our bitmap		
 		
 		display theBitmap
 		
 -- delete our snapshot		
 		
 		delete theMesh
 	)
 	
 --****************************************************************	
 
 	fn RenderOpenEdges theObj BrushSize col =
 	(
 		local theBitmap = bitmap bitmapX bitmapY color:backgroundColor filename:temp_bitmap_filename
 
 	
 -- get a snapshot of the mesh	
 	
 		theMesh = snapshotAsMesh theObj
 		
 		theEdges = (meshop.getOpenEdges theMesh) as array
 	
 		for i in theEdges do
 		(
 			if IsEdgeVisible theMesh i  then
 			(
 				-- get edge verts and faces				
 		
 				theVerts = meshop.getVertsUsingEdge theMesh i as array
 				theFaces = GetEdgedFaces theMesh i
 		
 				if	constrainToMatID == false then
 				(		
 
 		-- get the UV verts
 		
 						vindex1 = GetVertFaceIndex theMesh theFaces[1] theVerts[1]
 						uvVert1 = GetTVertFromFaceIndex theMesh theFaces[1] vindex1
 						
 						
 						vindex2 = GetVertFaceIndex theMesh theFaces[1] theVerts[2]	
 						uvVert2 = GetTVertFromFaceIndex theMesh theFaces[1] vindex2
 		
 		-- draw on the bitmap
 				
 						drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
 								[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
 				)				
 				else
 				(
 					if getFaceMatID theMesh  theFaces[1] == matID then 
 					(
 
 		-- get the UV verts
 		
 						vindex1 = GetVertFaceIndex theMesh theFaces[1] theVerts[1]
 						uvVert1 = GetTVertFromFaceIndex theMesh theFaces[1] vindex1
 						
 						
 						vindex2 = GetVertFaceIndex theMesh theFaces[1] theVerts[2]	
 						uvVert2 = GetTVertFromFaceIndex theMesh theFaces[1] vindex2
 		
 		-- draw on the bitmap
 				
 						drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
 								[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
 
 					)
 				)			
 			)
 		)
 
 -- save the bitmap in temp bmp		
 		
 		save theBitmap
 		
 -- dispay our bitmap		
 		
 		display theBitmap
 		
 -- delete our snapshot		
 		
 		delete theMesh
 	)
 	
 --****************************************************************	
 
 	fn RenderAll theObj BrushSize col =
 	(
 		local theBitmap = bitmap bitmapX bitmapY color:backgroundColor filename:temp_bitmap_filename
 
 	
 -- get a snapshot of the mesh	
 	
 		theMesh = snapshotAsMesh theObj
 		
 		theEdges = theMesh.Edges
 	
 		for i in theEdges do
 		(
 			if IsEdgeVisible theMesh i  then
 			(
 										
 		-- get edge verts and faces				
 		
 						theVerts = meshop.getVertsUsingEdge theMesh i as array
 						theFaces = GetEdgedFaces theMesh i
 						
 						
 		-- get the UV verts
 		
 						vindex1 = GetVertFaceIndex theMesh theFaces[1] theVerts[1]
 						uvVert1 = GetTVertFromFaceIndex theMesh theFaces[1] vindex1
 						
 						
 						vindex2 = GetVertFaceIndex theMesh theFaces[1] theVerts[2]	
 						uvVert2 = GetTVertFromFaceIndex theMesh theFaces[1] vindex2
 		
 		-- draw on the bitmap
 				
 						drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
 								[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
 					
 								
 			)
 		)
 
 -- save the bitmap in temp bmp		
 		
 		save theBitmap
 		
 -- dispay our bitmap		
 		
 		display theBitmap
 		
 -- delete our snapshot		
 		
 		delete theMesh
 	)
 	
 --*************************************************************	
 	
 	fn pbMeshFilterFunc theObj = 
 	(
 		classof theObj == Editable_Mesh or classof theObj == Editable_Poly
 	)
 	
 --*************************************************************
 
 	rollout SettingsRollout "Settings"
 	(
 	
 -- render size
 	
 		label lab1 "Render Size" align:#left offset:[0,4]	
 		dropdownlist bmXSizeddlist items:bmapSizeList selection:x_sel width:52 offset:[64,-22]	
 		label lab2 "x" offset:[16,-23]	
 		dropdownlist bmYSizeddlist items:bmapSizeList selection:y_sel width:52 offset:[130,-22]	
 
 -- render type and cutoff angle
 
 		label lab3 "Render..." align:#left offset:[0,4]
 		dropdownlist renderTypeddlist items:renderTypeList selection:render_Sel width:72 offset:[64,-22]	
 		spinner cutoffangleSpn "Angle:" range:[0,90.0,minAngle ] type:#float fieldWidth:32 align:#left offset:[140,-24]
 
 -- line width and colour
 		
 		spinner lineWidthSpn "Line Width:  " range:[1,100,lineWidth] type:#integer fieldWidth:32 align:#left offset:[0,4]
 		colorpicker lineColourCP "Line Colour:" color:lineColour fieldWidth:32 height:16 offset:[114,-22]
 
 -- noise setup	
 		
 		checkbox usenoiseCbx "Noise   " checked:noise offset:[0,4]
 		spinner noiseAmountSpn "Noise Level:   " range:[0,10,noiseValue] type:#float fieldWidth:32 align:#left offset:[78,-19]
 		
 -- matID setup	
 		
 		checkbox constrainMatIDCbx "Constrain Mat ID" checked:constrainToMatID offset:[0,4]
 		spinner MatIDSpn "Mat ID:" range:[1,999,matID] type:#integer fieldWidth:32 align:#left offset:[110,-19]
 		
 	
 -- object picker	
 	
 		pickbutton pRenderObj "Render Obj" filter:pbMeshFilterFunc align:#center offset:[0,4] 
 		
 -- event handlers		
 		
 
 		on bmXSizeddlist selected item do
 		(
 			bitmapX = bmapSizes[item]
 			bitmapx_1 = bitmapX-1
 			x_sel = item
 		)
 		
 		on bmYSizeddlist selected item do
 		(
 			bitmapY = bmapSizes[item]
 			bitmapy_1 = bitmapY-1
 			y_sel = item
 		)
 		
 		on renderTypeddlist selected item do
 		(
 			if item == 1 then
 				renderPeaks = true
 			if item == 2 then
 				renderPeaks = false
 				
 			render_Sel = item	
 		)
 		
 		on cutoffangleSpn  changed val do (minAngle = val)	
 
 		on lineWidthSpn changed val do (lineWidth = val)
 
 		on lineColourCP changed colour do (lineColour  = colour)
 
 		on usenoiseCbx  changed state do (noise = state)
 		
 		on noiseAmountSpn changed val do (noiseValue= val)
 		
 		on constrainMatIDCbx changed state do (constrainToMatID = state)
 		
 		on noiseAmountSpn changed val do (matID = val)
 
 		on pRenderObj picked item do
 		(
 			theObjToRender = item
 			pRenderObj.text = item.name
 			
 			case render_Sel of
 			(
 				1:
 				(
 					RenderEdges theObjToRender lineWidth lineColour
 				)
 				2:
 				(
 					RenderEdges theObjToRender lineWidth lineColour
 				)
 				3:
 				(
 					RenderOpenEdges theObjToRender lineWidth lineColour
 				)
 				4:
 				(
 					RenderAll theObjToRender lineWidth lineColour
 				)
 			)
 		)
 
 	)
 	
 	on execute do
 	(
 		try(CloseRolloutFloater theWindow) catch()
 		
 		theWindow = newRolloutFloater "Edge '0' Sketch" 250 195 8 100
 	
 		Addrollout SettingsRollout 	theWindow 
 
 	)
 
 )

So acos(dot (normalize face1) (normalize face2)) seems to be the line here.

Unfortunately normalize is not recognized by max and you did not define it.

Also I need to know the difference between those two cases A & B as attached.

that line is correct but face1 & face2 are nothing to do with me

Normalize Vector

[left]normalize <point3>
[/left]
[left]Returns the point3 value normalized such that the vector length equals 1.
[/left]
[left]For example:
[/left]
[left]b = [100,30.5,41.3] – take some Point3 value
[/left]
[left][100,30.5,41.3]
[/left]
[left]normalB1 =normalize b – get the normalized vector
[/left]
[left][0.889603,0.271329,0.367406]
[/left]
[left]length normalB1 – check the length, should be 1.0
[/left]
[left]1.0 – It is!
[/left]
[left]normalB2 = b / (length b) – Do-It-Yourself Normalize…
[/left]
[left][0.889603,0.271329,0.367406] – same value
[/left]
[left]length normalB2 – of course, the length is also 1.0
[/left]
[left]1.0
[/left]

[left]
[/left]

last post updated

read the posts

1 Reply
(@jormasoranen)
Joined: 10 months ago

Posts: 0

don’t be a smartass and contribute some useful answer instead.

Page 1 / 2