Community
PowerMill Forum
Welcome to Autodesk’s PowerMill Forums. Share your knowledge, ask questions, and explore popular PowerMill topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Macro for iterating selected surfaces

19 REPLIES 19
SOLVED
Reply
Message 1 of 20
edgolovin
3148 Views, 19 Replies

Macro for iterating selected surfaces

Hello everyone!

 

I use PM macro language for a while, mostly picking the commands from command window in echo mode.

 

Currently I'm trying to write a macro for iterating some selected surfaces of the model, but I found that my knowledge isn't sufficient for the task.

 

I need to use FOREACH loop, but I can't obtain a list of selected by user surfaces.

What type should the list be, entity?

 

No matter what to use, list, levels, arrays - I haven't succeed yet to iterate it.

Any suggestions appreciated.

 

//user picks needed surfaces manually, then
CREATE LEVEL 'surfs' MODELCOMPSET
EDIT LEVEL 'surfs' ACQUIRE SELECTED
FOREACH surf IN Level 'surfs' {
	PRINT $surf.Name
	//etc
}
19 REPLIES 19
Message 2 of 20
rob_carri
in reply to: edgolovin

CREATE LEVEL 'surfs' MODELCOMPSET


activate LEVEL 'surfs'



MACRO PAUSE "Seleccione Superficies!"+crlf+""+crlf+""+crlf+""+crlf+" Aprete Reanudar "+crlf+""+crlf+"Cuendo este listo!" // a message to you




EDIT LEVEL "surfs" ACQUIRE SELECTED
EDIT LEVEL "surfs" SELECT SURFACE



message info "Proceso Terminado"

try this

Message 3 of 20
edgolovin
in reply to: rob_carri

Thank you for your answer, rob_carri,

 

but I have no problem with adding surfaces into a set.

 

The problem that I want to solve, is to select all surfaces from the existing set (or from array, or from list, whatever)

one by one automatically

and conduct some actions to them, say print names of all surfaces in the set.

 

As far as I know, I need to use FOREACH loop.

Message 4 of 20
urizenYHS3W
in reply to: edgolovin

There isn't a direct way to FOREACH over selected surfaces.

 

You could try opening a tracefile and then doing PRINT SELSURFACE

 

TRACEFILE OPEN "sel_surfs.txt"
PRINT SELSURFACE
TRACEFILE CLOSE
STRING LIST surfs = {}
FILE OPEN "sel_surs.txt" FOR READ AS "input"
FILE READ $surfs FROM "input"
FILE CLOSE "input"

// Get read of the first element as it is the count
int n = remove_first(surfs)

EDIT MODEL ALL DESELECT ALL
FOREACH surf IN surfs {
  EDIT MODEL ALL SELECT $surf
  //...
  EDIT MODEL ALL DESELECT $surf
}
Message 5 of 20
edgolovin
in reply to: urizenYHS3W

Thank you very much for your respond, I'll try your code.

 

Why is it impossible to iterate surfaces directly?

 

In PM parameters list there is "Model components list", but I don't understand how to use this syntax properly:

 

components.PNG

 

 

Message 6 of 20
LasseFred
in reply to: edgolovin

If you will make a list over your models in pmill, you can use this.

 

STRING $Model_name = ""
$Model_name = INPUT ENTITY MODEL "Choose your model"

______________________
Lasse F.
Message 7 of 20
edgolovin
in reply to: LasseFred

Thanks, your post is useful, but it doesn't solve the problem.

 

Your code helps to select a model, whether I want to select not a model, but certain surfaces in it, and not at once, but one by one.

Message 8 of 20
LasseFred
in reply to: edgolovin

do you make levels to the surfaces you want ?

______________________
Lasse F.
Message 9 of 20
Goffa_
in reply to: edgolovin

Posted edited

did not realise some one alreay posrted this sort of answer already.

Message 10 of 20
edgolovin
in reply to: urizenYHS3W

urizen, your suggestion is almost working,

 

it returns a file containing needed surfaces' names and try to iterate it, but throws out an error:

 

err.PNG

 

 

PM recognizes the name, but can't process it. Why is "Model Component _it's name_ doesn't exist???

On the right side of debugger it can be seen, that the list of surfaces is successfully generated, and iterable surf successfully takes the first instance from the list, too.

It should work, but it doesn't.

Message 11 of 20
LasseFred
in reply to: edgolovin

Try:

 

TRACEFILE OPEN "sel_surfs.txt"
PRINT SELSURFACE
TRACEFILE CLOSE
STRING LIST surfs = {}
FILE OPEN "sel_surs.txt" FOR READ AS "input"
FILE READ $surfs FROM "input"
FILE CLOSE "input"

// Get read of the first element as it is the count
int n = remove_first(surfs)

EDIT MODEL ALL DESELECT ALL
FOREACH surf IN surfs {
  EDIT MODEL ALL SELECT $surfs // edit from $surf to $surfs
  //...
  EDIT MODEL ALL DESELECT $surfs // edit from $surf to $surfs
}
______________________
Lasse F.
Message 12 of 20
edgolovin
in reply to: LasseFred

no, PM returns evaluation error, because $surfs has LIST type and can't be expressed as a string

 

err2.PNG

Message 13 of 20
LasseFred
in reply to: edgolovin

can you use this?

 

// MAKE LEVEL

string name_level = ""
string prompt = "Enter a name for level"
$name_level = input $prompt

 

// SELECT MODEL
STRING $Model_name = ""
$Model_name = INPUT ENTITY MODEL "Choose your model"

 

// MAKE LEVEL AND RENAME
CREATE LEVEL ; LEVEL
RENAME Level # $name_level

 

// PAUSE TO SELECT SURFACES
MACRO PAUSE "SELECT SURFACES"

EDIT LEVEL $name_level ACQUIRE SELECTED
EDIT LEVEL $name_level SELECT ALL
EDIT MODEL $Model_name REVERSE

______________________
Lasse F.
Message 14 of 20
5axes
in reply to: urizenYHS3W

thanks a lot @urizenYHS3W for this solution. I've never thought to use this trick !! Could be usefull.. 

Hereafter the code with some modifications to make it usable :

INT Pos=0
INT Pos2=0
INT Lgth=0
STRING Cmd=''
STRING ActSurf=''

    INT count = 0
    FOREACH m in folder('model') {
    $count = $count + number_selected(m.Components)
    }
   
    // MESSAGE INFO "There are " + $count + " surfaces selected."
    
    if $count > 0 {
		ECHO OFF DCPDEBUG UNTRACE COMMAND ACCEPT //Important to supress useless line in the Tracefile Log	
		TRACEFILE OPEN "c:\Temp\sel_surfs.txt"
		PRINT SELSURFACE
		TRACEFILE CLOSE
		STRING LIST surfs = {}
		FILE OPEN "c:\Temp\sel_surfs.txt" FOR READ AS "input"
		FILE READ $surfs FROM "input"
		FILE CLOSE "input"

		// Get read of the first element as it is the count
		int n = remove_first(surfs)

		FOREACH surf IN surfs {

		$Pos=position($surf,"Process Command")
		$Pos2=position($surf,"There are")
		$Lgth=length($surf)
		  IF $Pos >= 0 OR $Pos2 >= 0 OR $Lgth==1 {
			PRINT "Error command $surf"
		  } ELSE {
			$ActSurf=RTRIM($surf) // Supress the CR at the end of the line from $surf to $surfs
			EDIT MODEL ALL DESELECT ALL
			EDIT MODEL ALL SELECT $ActSurf   // edit from $surf to $surfs
			// Do wath you want
		  }
		}
} ELSE {
	MESSAGE WARN "No Surface selected"
}

 

 

Tags (1)
Message 15 of 20
edgolovin
in reply to: 5axes

Thanks to you and to all people contributed to this topic!

 

The code works perfectly and I've learned a lot.

Message 16 of 20

This MACRO looks very close to the solution I've been looking for! Thanks to everyone so far.

 

I added 

//Do anything
PRINT $ActSurf

and it's printing out a nice list of the selected surfaces names. 

 

Now I'd like to programmatically apply a Surface Finish Path to each surface, with minor edits to each.

 

How do I begin this step?

 

Message 17 of 20
Beta_Librae
in reply to: 5axes

Good Afternoon 5axes,

 

This macro really interests me, probably because I don't understand the function. I ran the macro in 2019 and saw what it did. Why is iterating the surfaces useful?


Kind Regards,
Not cnc, you can call me Peabrain
Message 18 of 20
5axes
in reply to: Beta_Librae

Hello,

This sample code is not really useful. It's just an example to illustrate the use of this tip to get the list of selected surfaces.

Hereafter a sample code where the use of PRINT SELSURFACE have more sens .

FUNCTION main() {
STRING LIST surfs = {}
CALL GetFlatFacesName($surfs)

IF SIZE($surfs) == 0 {
MESSAGE WARN 'Flat surface cannot be found !'
RETURN
}

REAL LIST Zlevel = {}
CALL GetZLevelList($surfs, $Zlevel)

STRING $msg = 'Flat surfaces Z value :' + crlf + JOIN(Zlevel, crlf)
MESSAGE INFO $msg
}

// GET Zhight via block calculation
FUNCTION GetZLevelList(STRING LIST surfs, OUTPUT REAL LIST ZMin) {
$ZMin = {}

UNDRAW BLOCK
EDIT BLOCKTYPE BOX
EDIT BLOCK COORDINATE WORKPLANE

EDIT BLOCK ALL UNLOCK
EDIT BLOCK TOLERANCE '0.01'
EDIT BLOCK RESETLIMIT '0'
EDIT BLOCK LIMITTYPE MODEL

STRING LIST pros = {}
INT Ret = 0
STRING face = ''
GRAPHICS LOCK
FOREACH s IN $surfs {
EDIT MODEL ALL DESELECT ALL
$face = RTRIM($s)
EDIT MODEL ALL SELECT $face

EDIT BLOCK RESET

$Ret = ADD_LAST($ZMin, ROUND($Block.Limits.ZMin,3))
}
GRAPHICS UNLOCK
EDIT MODEL ALL DESELECT ALL

// Remove from the list same value and order in the reverse order the values
$Ret = REMOVE_DUPLICATES($ZMin)
$ZMin = REVERSE(SORT($ZMin))
}

// Gey the name of the flat surfaces
FUNCTION GetFlatFacesName(OUTPUT STRING LIST Surf) {

// Temporary file path
STRING $TraceFilePath = MACRO_PATH(false) + "\Surflist.txt"

$Surf = {}

EDIT MODEL ALL DESELECT ALL
// Select flat surface
EDIT MODEL ALL SELECT FLAT

ECHO OFF DCPDEBUG UNTRACE COMMAND ACCEPT
TRACEFILE OPEN $TraceFilePath
PRINT SELSURFACE
TRACEFILE CLOSE
ECHO ON DCPDEBUG TRACE COMMAND ACCEPT

FILE OPEN $TraceFilePath FOR READ AS Input
FILE READ $Surf FROM Input
FILE CLOSE Input
DELETE FILE $TraceFilePath

INT Ret = REMOVE_FIRST($Surf)
}

In this code the Function GetFlatFacesName get the list of Flat surface of the model.
Then the Z Value of each surface are calculated via a BLOCK calculation as powermill doesn't offer any function to get a surface dimension.

 

 

Message 19 of 20
dan
Participant
in reply to: Beta_Librae

@Beta_Librae My team and I were looking to use the "iterate face" code to essentially 3+2 machine the faces of a large low-polyhedral sculpture. In an ideal world this cuts down on machine time by about 80%-90%. 

In the end we ran into issues with the PowerMill Robot Plugin and the huge number of toolpaths produced by the code. So we had to scrap this approach and just ball nose the whole thing with a 1mm step-over. Takes forever, but looks good. 

 

Below is the code that got close the solution. So many more things we would have liked to do with it. Could potentially be useful in some specific industry of machining generative low-poly designs. 

 

Huge shout out to @5axes, who was extremely helpful getting this code this far. Sorry it never saw glory. 

 

// -- //
// PolyFace_NAPA - METRIC
// Iterates through selected surfaces and automatically generates a surface finish toolpath normal to each.
// -- //
// New American Public Art - Kempelen's Owls [newamericanpublicart.com/kempelens-owls]
// This code is provided under a CC-BY-SA 4.0 licenses [https://creativecommons.org/licenses/by-sa/4.0/]
//// Authors :
//// New American Public Art
//// 5axes [https://forums.autodesk.com/t5/user/viewprofilepage/user-id/3969139)]
//// Autodesk BUILD Space
// -- //


INT ErrorCheck1=0
INT ErrorCheck2=0
INT Lgth=0
STRING ActSurf=''
INT count = 0
REAL iVal = 0
REAL jVal = 0
REAL kVal = 0

FOREACH m in folder('model') {
    $count = $count + number_selected(m.Components)
}
   
MESSAGE INFO "There are " + $count + " surfaces selected."
    
if $count > 0 {
	ECHO OFF DCPDEBUG UNTRACE COMMAND ACCEPT //Important to suppress useless line in the Tracefile Log	
	TRACEFILE OPEN "surfs.txt"
	PRINT SELSURFACE
	TRACEFILE CLOSE
	STRING LIST surfs = {}
	FILE OPEN "surfs.txt" FOR READ AS "input"
	FILE READ $surfs FROM "input"
	FILE CLOSE "input"
	
	// Get rid of the first element as it is the count
	int n = remove_first(surfs)

	FOREACH surf IN surfs {
		$ErrorCheck1=position($surf,"Process Command") // look for error sign
		$ErrorCheck2=position($surf,"There are") // look for error sign
		$Lgth=length($surf)
	    IF $ErrorCheck1 >= 0 OR $ErrorCheck2 >= 0 OR $Lgth==1 {
		    PRINT "Error command $surf"
	    } ELSE {
		    $ActSurf=RTRIM($surf) // Suppress the CR at the end of the line
		    EDIT MODEL ALL DESELECT ALL
		    EDIT MODEL ALL SELECT $ActSurf
			PRINT $ActSurf
				
				//-- run dummy toolpath to get IJK of $ActSurf --//
				EDIT BLOCK RESETLIMIT "1"
				EDIT BLOCK RESET
				ACTIVATE TOOL "tempTool"
				//-- tempTool should be as small and long as your program allows
				
				IMPORT TEMPLATE ENTITY TOOLPATH TMPLTSELECTORGUI "Finishing/Profile-Finishing.ptf"
				EDIT PAR 'StockEngagement.MachineStockOnly' 0
				EDIT PAR 'SurfaceSide' 'outside'
				EDIT PAR 'RadialOffset' "-1.27"
				EDIT PAR 'ProfileBasePosition' 'automatic'
				EDIT PAR 'JoinTolerance' "0.00"
				EDIT FTOLERANCE "0.0508"
				EDIT PAR 'Thickness' "0"
				EDIT TOOLAXIS TYPE LEADLEAN
				EDIT TOOLAXIS LEAD "0"
				EDIT TOOLAXIS LEAN "0"
				EDIT TOOLPATH ; CALCULATE
				FORM ACCEPT SFPatternProf

				INT nb_point=segment_point_count( entity('Toolpath',''),0)
				
				IF $nb_point == 0 {
					MESSAGE ERROR "NO toolpath calculated"
					} ELSE {
					$nb_point=$nb_point/2
					object Analyse= segment_get_point( entity('Toolpath',''), 0, $nb_point)
					REAL i = round($Analyse.ToolAxis[0],5)
					REAL j = round($Analyse.ToolAxis[1],5)
					REAL k = round($Analyse.ToolAxis[2],5)
					//save these for later
					$iVal = $i
					$jVal = $j
					$kVal = $k
					}
				DELETE TOOLPATH ;
				
				//Reset some stuff
				ACTIVATE TOOL "1/2 end mill"
				
				//Run the real toolpath
				FORM STRATEGYSELECTOR
				STRATEGYSELECTOR STRATEGY "Finishing/Surface-Finishing.ptf" NEW
				IMPORT TEMPLATE ENTITY TOOLPATH TMPLTSELECTORGUI "Finishing/Surface-Finishing.ptf"
				
				//-- Workplane
				ACTIVATE WORKPLANE "objectMod"
				
				//-- Block
				//// no changes, should be triangles, Global Transform
				
				//-- Tool
				//// no changes, should be active tool as set above
				
				//-- Machine Tool
				EDIT PAR 'ModelLocation' "ABBLoc"
				
				//-- Limit
				//// no changes
				
				//-- Stock Engagement
				EDIT TPPAGE SWStockEngage
				EDIT PAR 'StockEngagement.MachineStockOnly' 1
				EDIT PAR 'StockEngagement.ThresholdThickness' "0.0508"
				EDIT PAR 'StockEngagement.MinimumLengthRemoved' "4.7625"
				EDIT PAR 'StockModelState.StockModel' "stockMod"
				EDIT STOCKMODEL 'stockMod' ACTIVATE INDEXED_STATE '1'
				
				//-- Surface finishing
				EDIT PAR 'SurfaceSide' 'outside'
				EDIT PAR 'ProjectionSurfaceUnits' 'distance'
				EDIT PAR 'Degouge.Tolerance' "0.254"
				EDIT FTOLERANCE "0.0508"
				
////--- Thickness is the big difference between PolySurf.macs ---/////
////--- this leaves a little stock to be machined in a final pass --//
				EDIT PAR 'Thickness' "1.27"
				
				EDIT PAR 'RadialDepthOfCut.UserDefined' '1' Edit Par 'Stepover' "6.35"
				
				//-- Surface finishing -- Pattern
				EDIT TPPAGE SWProjectPatSurf
				EDIT PAR 'ProjectionPatternDirection' 'v'
				EDIT PAR 'Spiral' 0
				EDIT PAR 'PatternStyle' 'two_way'
				EDIT SURFPROJ STARTCORNER MINU_MINV
				EDIT FINPROJ ORDER NONE
				
				//-- Automatic Verificaiton
				EDIT TPPAGE SWAutoVerifBasic
				EDIT PAR 'Clearance.Head' "609.6"
				EDIT PAR 'CollisionCheck' '1'
				EDIT PAR 'Clearance.Holder' "0.0"
				EDIT PAR 'Clearance.Shank' "0.0"
				
				//-- Point Distribution
				//// no changes
				
				//-- Tool axis
				EDIT TPPAGE SWToolAxis
				EDIT TOOLAXIS TYPE DIRECTION
				EDIT TOOLAXIS DIRI $iVal
				EDIT TOOLAXIS DIRJ $jVal
				EDIT TOOLAXIS DIRK $kVal
				EDIT COLLISIONAVOIDANCE SET ON
				EDIT TOOLAXIS SMOOTHING ON
				
				//-- Tool axis -- Collision Avoidance
				EDIT TPPAGE SWToolAxCAvd	
				EDIT PAR 'CollisionAvoidance.Method' 'lead_then_lean'
				EDIT COLLISIONAVOIDANCE HOLDER_CLEARANCE "1.27"
				EDIT COLLISIONAVOIDANCE SHANK_CLEARANCE "1.27"
				EDIT PAR 'ToolAxisSmoother.Distance' "38.1"
				
				//-- Tool axis -- Smoothing
				EDIT TPPAGE SWToolAxSmth
				EDIT PAR 'ToolAxisSmoother.ElevationSmoothing' 'smoothed'
				EDIT PAR 'ToolAxisSmoother.Angle' "5.0"
				EDIT PAR 'ToolAxisSmoother.AzimuthSmoothing' 'smoothed'
				EDIT PAR 'ToolAxisSmoother.AzimuthAngle' "5.0"
				EDIT PAR 'ToolAxisSmoother.Distance' "38.1"
				
				//-- Machine axis controll
				//// no changes
					
				//-- Rapid Moves
				EDIT TPPAGE SWToolRapidMv
				EDIT TOOLPATH SAFEAREA TYPE PLANE
				EDIT TOOLPATH SAFEAREA WORKPLANE  "objectMod"
				EDIT TOOLPATH SAFEAREA DIRECTION I "0"
				EDIT TOOLPATH SAFEAREA DIRECTION J "0"
				EDIT TOOLPATH SAFEAREA DIRECTION K "1"
				EDIT TOOLPATH SAFEAREA MEASURE_FROM BLOCK
//-- These need to take into consideration the roughing geometery from the last paths				
				EDIT PAR 'Rapid.CalculateDimensions.RapidClearance'  "25.4"
				EDIT PAR 'Rapid.CalculateDimensions.PlungeClearance'  "7.62"
				EDIT TOOLPATH SAFEAREA CALCULATE_DIMENSIONS
				
				// Rapid moves -- Moves and clearances
				EDIT TPPAGE SWToolRapidMVClear
				EDIT TOOLPATH LEADS LINK MOVE_DIR NORMAL
				EDIT TOOLPATH LEADS LINK ARCFIT Y
				EDIT TOOLPATH LEADS LINK ARCFIT_RAD "19.05"
				EDIT TOOLPATH LEADS SKIMDIST "6.35"
				EDIT TOOLPATH LEADS RADIAL_CLEARANCE 6.35
				
				//-- Leads and Links
				EDIT TPPAGE SWLeadsLinks
				EDIT TPPAGE SWLeadIn
				EDIT TOOLPATH LEADS LEADIN RAMP
				FORM PMLLEADINRAMP EDIT TOOLPATH LEADS RAMPPAGE LEADINRAMPOPT1
				EDIT TOOLPATH LEADS LEADIN RAMPOPT FOLLOW CIRCLE
				EDIT TOOLPATH LEADS LEADIN2 POCKET
				LEADINRAMP ACCEPT
				EDIT TPPAGE SWLeadOut
				EDIT TOOLPATH LEADS LEADOUT RAMP
				FORM PMLLEADOUTRAMP EDIT TOOLPATH LEADS RAMPPAGE LEADOUTRAMPOPT1
				EDIT TOOLPATH LEADS LEADOUT RAMPOPT FOLLOW CIRCLE
				EDIT TOOLPATH LEADS LEADIN RAMPOPT DIAMETER ".5" //--TDU
				EDIT TOOLPATH LEADS LEADIN RAMPOPT ZIGANGLE "30.0"
				EDIT TOOLPATH LEADS LEADIN RAMPOPT HEIGHT_TYPE INCR
				EDIT TOOLPATH LEADS LEADIN RAMPOPT HEIGHT_INCREMENT "7.62" //-- increase this if you are getting rapid collisions during retract moves
				LEADINRAMP ACCEPT
				EDIT TOOLPATH LEADS LEADOUT2 POCKET
				EDIT TOOLPATH LEADS LEADOUT COPY
				LEADOUTRAMP ACCEPT
				
				EDIT TPPAGE SWLink
				EDIT PAR 'Connections.Link[0].Type' 'straight'
				EDIT PAR 'Connections.Link[0].ApplyConstraints' '1'
				EDIT PAR 'Toolpath.Connections.Link.First.Constraint[0].Azimuth.Function' 'less_than'
				EDIT PAR 'Toolpath.Connections.Link.First.Constraint[0].Azimuth.Value' "0.254"
				EDIT PAR 'Connections.Link[1].Type' 'circular_arc'
				
				EDIT TPPAGE SWSEPtSPoint
				EDIT TOOLPATH START TYPE POINT_SAFE
				
				EDIT TPPAGE SWSEPtEPoint
				EDIT TOOLPATH END TYPE ABSOLUTE
				EDIT PAR 'EndPoint.Motion' 'reset_machine_tool' //-- this solves many retract and reconfigure errors
				//-- these numbers are the xzy cords of your specific center safe
				EDIT TOOLPATH END POSITION X "154.0"
				EDIT TOOLPATH END POSITION Y "270"
				EDIT TOOLPATH END POSITION Z "20"
				EDIT TOOLPATH ; CALCULATE
				// need some error checking in here
				FORM ACCEPT SFProjectionSurfM
	}
} ELSE {
	
	MESSAGE INFO " DONE! " + $count + " surfaces completed."
	//MESSAGE WARN "No surfaces found"
}


// - follow this up with an "Optimised Constant Z Finising"
// closed offsets, smoothing, centreline
// tool axis = lead/lean
// leads and links = ramp, ramp, straight, safe
Message 20 of 20
Beta_Librae
in reply to: dan

@5axes @dan  Thanks for the insight guys. I was really hoping that this was going to do what I thought it could. Find all of the flat surfaces in the model and apply a workplane to each in the proper orientation. Wishful thinking I guess because really what is the right orientation until we tell it what it is.


Kind Regards,
Not cnc, you can call me Peabrain

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report