Extract shape from selected polygon (script request)


#1

I have a bunch of volumes (see sample max-file) from which I need to extract a shape of the polygon facing to top (facing z up) and a shape of the polygon at the bottom (facing z down) of each individual object.
If I have 10 volumes, I would end up with 20 shapes,.
For clarity, it would be beneficial if the “top-splines” were added into a separate layer and the “bottom-splines” where added into another layer.

House Volumes.max (1.0 MB)


#2

This code not check the orientation of the polygons. It will find top and bottom polygon and will extract is edges as a shape.

(
	local poGetFaceCenter = polyop.getFaceCenter
	local poGetEdgesUsingFace = polyop.getEdgesUsingFace
	local poCreateShape = polyop.createShape
	
	topSplineLayer = layermanager.newlayerfromname "Top Splines"
	bottomSplineLayer = layermanager.newlayerfromname "Bottom Splines"
	
	selObjsArr = selection as array
	convertToPoly selObjsArr
	
	for o in selObjsArr do
	(
		minVal = -1e9
		maxVal = 1e9
		topFace = undefined
		bottomFace = undefined
		for f = 1 to o.numfaces do
		(
			fcp = (poGetFaceCenter o f).z
			if fcp > minVal do
			(
				minVal = fcp
				topFace = f
			)
			if fcp < maxVal do
			(
				maxVal = fcp
				bottomFace = f
			)
		)
		
		if topFace != undefined and bottomFace != undefined do
		(			
			poCreateShape o (poGetEdgesUsingFace o topFace) smooth:false name:(o.name+"_topShape") node:o
			topSplineLayer.addNode (objects[objects.count])
			
			poCreateShape o (poGetEdgesUsingFace o bottomFace) smooth:false name:(o.name+"_bottomShape") node:o
			bottomSplineLayer.addNode (objects[objects.count])			
		)
		
	)
	messagebox "Done" title:""
)

#3

Thank you for your swift reply!

What are the conditions for the script? Do I need to convert them all to one single mesh, poly etc? Because I can’t make it work for me.


#4

I used the scene you provided.

  1. Select all objects from which you want to extract the shapes
  2. run the script

If you have object with more than one “top face” the script will extract the edges of only one of those top faces. In the scene you provided all objects have only one top and one bottom polygon.


#5

Selecting first, running script then - thats the way it works.

However, this is what happened if I run the script without selecting anything.
It creates the two layers, and it pops up “Done.”
No splines were created.

If I select the meshes, and run the script again, this happens:

    -- Error occurred in o loop
    --  Frame:
    --   minVal: 3.8555
    --   o: $3dSolid
    --   topFace: 1
    --   bottomFace: 3
    --   maxVal: 3.4583
    --   called in anonymous codeblock
    --  Frame:
    --   poGetEdgesUsingFace: polyop.getEdgesUsingFace()
    --   poCreateShape: polyop.createShape()
    --   topSplineLayer: undefined
    --   bottomSplineLayer: undefined
    --   selObjsArr: #($3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, $3dSolid, ...)
    --   poGetFaceCenter: polyop.getFaceCenter()
    -- Unknown property: "addnode" in undefined

I would suggest

  1. check if anything is selected before script is executed
  2. accept layers to exist if I would run the script a second time.

What did you mean by this?


#6
(
	local poGetFaceCenter = polyop.getFaceCenter
	local poGetEdgesUsingFace = polyop.getEdgesUsingFace
	local poCreateShape = polyop.createShape
	
	topLayerName = "Top Splines"
	bottomLayerName = "Bottom Splines"
	
	topSplineLayer = if (layer = layerManager.getLayerFromName topLayerName) == undefined then
		layermanager.newlayerfromname topLayerName
	else
		layer
	
	bottomSplineLayer = if (layer = layerManager.getLayerFromName bottomLayerName) == undefined then
		layermanager.newlayerfromname bottomLayerName
	else
		layer
	
	
	selObjsArr = selection as array
	convertToPoly selObjsArr
	
	for o in selObjsArr do
	(
		minVal = -1e9
		maxVal = 1e9
		topFace = undefined
		bottomFace = undefined
		for f = 1 to o.numfaces do
		(
			fcp = (poGetFaceCenter o f).z
			if fcp > minVal do
			(
				minVal = fcp
				topFace = f
			)
			if fcp < maxVal do
			(
				maxVal = fcp
				bottomFace = f
			)
		)
		
		if topFace != undefined and bottomFace != undefined do
		(			
			poCreateShape o (poGetEdgesUsingFace o topFace) smooth:false name:(o.name+"_topShape") node:o
			topSplineLayer.addNode (objects[objects.count])
			
			poCreateShape o (poGetEdgesUsingFace o bottomFace) smooth:false name:(o.name+"_bottomShape") node:o
			bottomSplineLayer.addNode (objects[objects.count])			
		)
		
	)
	messagebox "Done" title:""
)

This code not check the orientation of the polygons

What did you mean by this?

Pick one object, select top polygon and flip it. Its normal now points to negative Z axis, but the script will “consider it” as a top polygon.


#7

Works outstanding! Thank you very much Miauu!

The purpose of this script is to model building volumes in 3dsMax and then export the shapes into Infraworks as native infraworks buildings.

Small issue left: You could add a filter to ignore splines. Currently, I can select splines and the effect is that it turns splines into polys.

question: the minVal and maxVal, are they for determining the angle of the face, ie whether its flat or not?


#8

Those values are used to find the top and bottom polygon using the polygon’s center. No angles are involved.

This have to skip splines, only editable mesh and editable poly objects will be processed by the sctipy:

(
	local poGetFaceCenter = polyop.getFaceCenter
	local poGetEdgesUsingFace = polyop.getEdgesUsingFace
	local poCreateShape = polyop.createShape
	
	topLayerName = "Top Splines"
	bottomLayerName = "Bottom Splines"
	
	topSplineLayer = if (layer = layerManager.getLayerFromName topLayerName) == undefined then
		layermanager.newlayerfromname topLayerName
	else
		layer
	
	bottomSplineLayer = if (layer = layerManager.getLayerFromName bottomLayerName) == undefined then
		layermanager.newlayerfromname bottomLayerName
	else
		layer
	
	
	selObjsArr = selection as array
	convertToPoly selObjsArr
	
	for o in selObjsArr where classOf o == Editable_Mesh or classOf o == Editable_Poly do
	(
		minVal = -1e9
		maxVal = 1e9
		topFace = undefined
		bottomFace = undefined
		for f = 1 to o.numfaces do
		(
			fcp = (poGetFaceCenter o f).z
			if fcp > minVal do
			(
				minVal = fcp
				topFace = f
			)
			if fcp < maxVal do
			(
				maxVal = fcp
				bottomFace = f
			)
		)
		
		if topFace != undefined and bottomFace != undefined do
		(			
			poCreateShape o (poGetEdgesUsingFace o topFace) smooth:false name:(o.name+"_topShape") node:o
			topSplineLayer.addNode (objects[objects.count])
			
			poCreateShape o (poGetEdgesUsingFace o bottomFace) smooth:false name:(o.name+"_bottomShape") node:o
			bottomSplineLayer.addNode (objects[objects.count])			
		)
		
	)
	messagebox "Done" title:""
)

#9

:thinking: hmm, it seems still to affect splines.
It turns them into polys and then I get the popup “Done”


#10
(
	local poGetFaceCenter = polyop.getFaceCenter
	local poGetEdgesUsingFace = polyop.getEdgesUsingFace
	local poCreateShape = polyop.createShape
	
	topLayerName = "Top Splines"
	bottomLayerName = "Bottom Splines"
	
	topSplineLayer = if (layer = layerManager.getLayerFromName topLayerName) == undefined then
		layermanager.newlayerfromname topLayerName
	else
		layer
	
	bottomSplineLayer = if (layer = layerManager.getLayerFromName bottomLayerName) == undefined then
		layermanager.newlayerfromname bottomLayerName
	else
		layer
	
	
	selObjsArr = selection as array
	
	for o in selObjsArr where classOf o == Editable_Mesh or classOf o == Editable_Poly do
	(
		convertToPoly o
		minVal = -1e9
		maxVal = 1e9
		topFace = undefined
		bottomFace = undefined
		for f = 1 to o.numfaces do
		(
			fcp = (poGetFaceCenter o f).z
			if fcp > minVal do
			(
				minVal = fcp
				topFace = f
			)
			if fcp < maxVal do
			(
				maxVal = fcp
				bottomFace = f
			)
		)
		
		if topFace != undefined and bottomFace != undefined do
		(			
			poCreateShape o (poGetEdgesUsingFace o topFace) smooth:false name:(o.name+"_topShape") node:o
			topSplineLayer.addNode (objects[objects.count])
			
			poCreateShape o (poGetEdgesUsingFace o bottomFace) smooth:false name:(o.name+"_bottomShape") node:o
			bottomSplineLayer.addNode (objects[objects.count])			
		)
		
	)
	messagebox "Done" title:""
)

Select top or bottom face of an amount of volumes
#11

Thank you very much Miauu! :+1: