Notifications
Clear all

[Closed] Structs with functions

I was wondering if someone could explain or show and example to me on what is the benefit of putting a function in a struct?

I understand how to use structs but I do not see the immediate benefit of putting a function inside of one. I’m not sure if my example is one that really displays the benefits of functions in structs.

example:


struct person (
  name, 
  height, 
  age, 
  sex,

  fnWirecolor obj = (
    obj.wirecolor = random black white
  )
)

21 Replies

I think of it as like Methods… I’ve changed your example to be more the way a function inside a struct would work instead of referencing outer variables.

struct person (
  name, 
  height, 
  age, 
  sex,

  fn CalculateWeight = (
       (height * 10) + (0.2 * age)
  )
)

Then for every instance of the struct you can call this function and it will reference everything inside the struct.

bob = person "Bob" 174 21 "Male"

bob.CalculateWeight()

That’s my interpretation anyway, I know other people use them differently.

encapsulation…

and stuff like this…

struct AnInterface
 (
 private
 
 	version = 1.1, 
 	sourcefile = "D:/Development/3dsMax/MaxScript/interfaces/AnInterface.ms",	
 	
 public	
 	
 -- Get this version		
 		
 	fn getVersion = version,
 	fn getSourceFile = sourcefile,	
 
 -- Installs this script into "stdplugs/stdscripts/"	
 	
 	fn Install =
 	(	
 		file = getSourceFile();
 		sourcefileModdate = getFileModDate file;
 		
 		filename = filenameFromPath file;
 		stdscriptsdir = (getdir #maxroot) + "stdplugs/stdscripts/";
 		destfile = stdscriptsdir + filename;
 
 		need_to_update = false
 		if doesFileExist destfile then
 		(
 			destfileModdate = getFileModDate destfile;
 			if sourcefileModdate != destfileModdate then
 				need_to_update = true;
 		)
 		else
 			need_to_update = true;
 		
 		if need_to_update then
 		(	
 			deleteFile (stdscriptsdir + filename);
 			copyFile file  (stdscriptsdir +  filename);
 		)
 	),
 	
 	
 	fn GetFacesFromVerts obj verts =
 	(
 		faces = polyop.getFacesUsingVert obj verts[1]
 		for v = 2 to verts.count do	faces *= polyop.getFacesUsingVert obj verts[v];
 		faces
 	),	
 	
 -- more functions here	
 	
 	on create do install()
 )	
 
 -- create an instance of our interface
 
 global library = AnInterface();

then you call your functions with

library.GetFacesFromVerts obj verts

Very cool.
I appreciate booth of your examples they make a lot of sense and have surely opened my eyes to more ways to use structs. These are great. They can make things much simpler.

Thank you both.

Yep I use structs as a library of functions all the time I have a Math struct that I can call when doing math operations.

math.mirror cross:x flip:y
math.getOffset $[1] $[2]

this way I do not need to rewrite it every time I need it or nor do I need to keep various scripts open. One of the tools I give to clients also contains a library of functions that are used by a variety of characters, I do not need to give them a new script every time because once they have placed that main script in their system I know I can call upon select functions doesn’t matter the character

PePeTD
That is a very good idea. It seems like that is a good way to build a foundation of scripts, and like you said eliminate the rewriting of scripts.

another example showing encapsulation…

-- 2D binary tree packing demo

fn compare v1 v2 =
(	
	v1min = amin v1.width v1.height;
	v2min = amin v2.width v2.height;
	d =  v2min - v1min;
	if d == 0 then
	(
		v1max = amax v1.width v1.height;
		v2max = amax v2.width v2.height;
		d = v2max - v1max;
	)	
	d;
)

fn RandomColorGen src_color = (	0.5 * ((random (color 0 0 0) (color 255 255 255)) + src_color))

struct leafnode
(
	pos,
	width,
	height,
	down,
	right,
	used,
	
	fn init xy w h d:undefined r:undefined u:false =
	(
		pos = xy; width = w; height = h; down = d;  right = r; used = u;
	)
)

struct rect
( 	
	pos,
	width,
	height,
	flip = false,
	
	fn printf = (format "x:% y:% w:% h:%
" pos.x pos.y width height; ),
	fn makeshape =
	(
		if pos != undefined then
		(	
			rct = rectangle length:height width:width cornerRadius:0 pos:[width * 0.5,height * 0.5,0] 
			rct.wirecolor = random (color 0 0 0) (color 255 255 255);
			rct.pivot = [0,0,0];
			rct.pos = [pos.x,pos.y,0];
		)	
	),
	fn toBitmap dest_bm =
	(
		if pos != undefined then
		(	
			source_bm = bitmap width height color:(RandomColorGen (color 232 232 255))
			pasteBitmap source_bm dest_bm (box2 0 0 width height) pos;
			close source_bm;
		)
	)		
)	

struct packer 
(
	width,
	height,
	rectangles,
	root = leafnode(),
	
	fn onCreate = ( root.init [0.0,0.0] width height; ),
	fn addrect r = ( append rectangles r),
	fn findleafnode leaf w h = 
	(
		result = undefined;
		if leaf != undefined and leaf.used then
		(
			newleaf = findleafnode 	leaf.right w h;
			if newleaf != undefined then
				result = newleaf;
			else
				result = findleafnode leaf.down w h;
		)
		else if leaf != undefined and w <= leaf.width and h <= leaf.height then
			result = leaf;
		result;
	),
	fn splitleafnode leaf w h =
	(
		leaf.used = true;
		leaf.down = leafnode [leaf.pos.x,(leaf.pos.y + h)] leaf.width (leaf.height - h) undefined undefined false;
		leaf.right = leafnode [(leaf.pos.x + w), leaf.pos.y] (leaf.width - w) h undefined undefined false;
		leaf.pos;
	),
	fn sortit compfn = (qsort rectangles compfn),
	fn pack  =
	(
		for r in rectangles do
		(
			if (leaf = findleafnode root r.width r.height) != undefined then
				r.pos = splitleafnode leaf r.width r.height;
			else
				r.pos = undefined;
		)	
	),	
	fn show =
	(
		bm = bitmap width height color:white
		for r in rectangles do r.toBitmap bm;
		display bm;		
	),	
	on create do onCreate()
)	


thePacker = packer 200 200 #();

thePacker.addrect (rect [0,0] 50 50)
thePacker.addrect (rect [0,0] 100 100)
thePacker.addrect (rect [0,0] 100 50)
thePacker.addrect (rect [0,0] 50 50)
thePacker.addrect (rect [0,0] 50 100)
thePacker.addrect (rect [0,0] 50 50)
thePacker.addrect (rect [0,0] 50 50)
thePacker.addrect (rect [0,0] 100 100)

thePacker.sortit compare; 
thePacker.pack()
thePacker.show()

       

 fn MaxVal a b = (res = a; if a < b then res = b; res) 
    fn MinVal a b = (res = a; if a > b then res = b; res) 
 

is it more than just a sample? …
hmm… amax. hmm… amin.

no idea why I wrote my own functions and does it matter ? really, in a demo snippet.

fixed it as not to offend Denis

 eek

Member order counts unless you do some instantiation, for example:

struct my_struct
(
 fn b =
 (
  a()
 ),

 fn a =
 (
  print "working"
 ),
 EndOfStruct
)

test = my_struct()
test.b()



This would break but you can get around it with this:

struct my_struct
(
 self,
 fn b =
 (
  self = my_struct()
  self.a()
 ),

 fn a =
 (
  print "working"
 ),
 EndOfStruct
)

test = my_struct()
test.b()


2 Replies
(@denist)
Joined: 10 months ago

Posts: 0

you can. but don’t do it because it’s wrong.

(@spacefrog)
Joined: 10 months ago

Posts: 0

A better solution for that problem is using forward declarations:

struct my_struct
(
    -- forward declaration
    function a=(),	
    function b =
    (
        a()
    ),
    function a =
    (
        print "working"
    )
)

a problem regarding member variable declaration order that remains is discussed here:
http://forums.cgsociety.org/showthread.php?p=7444135#post7444135

As posted in that thread’s last post, it has been confirmed to be a bug in maxscript, lets hope for some fix in upcoming Max releases…

Page 1 / 2