Announcements

Between mid-October and November, the content on AREA will be relocated to the Autodesk Community M&E Hub and the Autodesk Community Gallery. Learn more HERE.

CAN SPLINES' LENGTH OR SEGMENTS BE ACCURATELY MEASURED THROUGH MAXSCRIPT?

CAN SPLINES' LENGTH OR SEGMENTS BE ACCURATELY MEASURED THROUGH MAXSCRIPT?

StanleyNguyen2023
Participant Participant
1,617 Views
7 Replies
Message 1 of 8

CAN SPLINES' LENGTH OR SEGMENTS BE ACCURATELY MEASURED THROUGH MAXSCRIPT?

StanleyNguyen2023
Participant
Participant

During my modeling work, I consistently use the built-in measure tool to monitor my assets' dimensions and lengths. Its ability to refresh information in real-time, without the need to repeatedly run the code or press the button, makes it an excellent tool. So, having a real-time updating feature in a shape length measure script can certainly enhance efficiency. As for me, I'm currently working on crafting a simple script that includes shape length information and other object parameters that I usually work with to replace the built-in measure tool and to accelerate my workflow. 

 

However, I've encountered a roadblock. Certain spline codes, including getSplineSelection and numSpline are incompatible with standard shape primitives even with the edit spline modifier added on top. Moreover,  curvelength/ getseglengths may yield incorrect values when the object undergoes scaling or has deform modifiers applied.

 

So my approach is using clone method to create temporary objects from the current selection, resetting their scaling, converting it to editable spline to collapse all modifier stacks and avoid standard shape primitives, then measuring and deleting these objects. 

 

There is, however, a significant issue with the code I've made (detailed in the code below). The original object perpetually refreshes, impeding select any of its modifiers. Selecting sub-object levels also results in substantial errors.

 

I suspect the root of the problem lies in a conflict between line 21, line23 and the node callback event. This callback refreshes the modify panel and all information within it whenever I select spline objects or sub-object levels of the object.

 

Questions : 

 

Is there an alternative method that consumes less system performance than object cloning?

 

If not, what modifications can I apply to the original code to prevent the constant refreshing caused by the conflict between line 21, line23 and the node callback event?

 

(
fn ShapesLength =
(
	local ShapeArr = selection as Array -- to simplify, my current selection only includes Line, Editable_Spline and Edit_Spline object

	local ShapeCopyArr = #()
	
	with redraw off 
	(	
		ShapeCopyArr = for i in ShapeArr collect (copy i)
		
		for i in ShapeCopyArr do -- try to reset Xform without selecting the dupplicated object
		(
			i.isHidden = true
			i.parent = undefined
			local ObjPos = i.position; local ObjRot = i.rotation
			i.rotation = (quat 0 0 0 1); i.position = ObjPos
			local ObjTm = i.transform; i.transform = transMatrix i.pos
			local piv = i.objecttransform * inverse i.transform
			i.objectoffsetPos = [0,0,0]; i.objectoffsetRot = (quat 0 0 0 1); i.objectoffsetScale = [1,1,1]; ObjTm.translation = [0,0,0]; ObjTm = piv * ObjTm
			local xformMod = XForm(); addmodifier i xformMod; xformMod.gizmo.transform = ObjTm -- ISSUE 
			i.rotation = ObjRot; i.position = ObjPos
			convertToSplineShape i -- ISSUE 
		)		
	)
)

fn ShapesLength_Callback ev nd = (ShapesLength())

fn Measure_Callback_On =
(
	ShapesLength_Event = undefined
	gc()
	
	ShapesLength()
	ShapesLength_Event = NodeEventCallback mouseUp:true delay:1000 selectionChanged:ShapesLength_Callback deleted:ShapesLength_Callback \
		groupChanged:ShapesLength_Callback geometryChanged:ShapesLength_Callback 
)

Measure_Callback_On()
)
0 Likes
Accepted solutions (1)
1,618 Views
7 Replies
Replies (7)
Message 2 of 8

denisT.MaxDoctor
Advisor
Advisor

The idea is almost right... But it's all very slow and eats up a lot of memory.

The only solution that can help is to do the same thing, but at the level of objects instead of nodes.

We can do it with the SDK, and if we need to stay with MXS, we can use the .NET MAX SDK.

I am not a master at using .NET MAX SDK, and my hastily written code can certainly be optimized by experts like Serejah or Swordslayer...

 

well, let's give it a try:

global __g = (dotnetclass "Autodesk.Max.GlobalInterface").Instance


fn spline3DLength node g: = 
(
	--g = (dotnetclass "Autodesk.Max.GlobalInterface").Instance

	inode = g.COREInterface7.GetINodeByHandle node.inode.handle
	ob_state = inode.EvalWorldState g.COREInterface.Time true --asdotnetobject:true
	obj = ob_state.obj
	sp = obj.ConvertToType g.COREInterface.Time g.SplineShapeClassID
	bz = sp.Shape	

	temp_s3d = g.Spline3D.Create bz.Splines
	tm = inode.GetObjectTM g.COREInterface.Time (g.Interval.Create())

	temp_s3d.Transform tm
	len = temp_s3d.SplineLength
		
	temp_s3d.Dispose()
		
	len
)
/*
spline3DLength $ g:__g
*/

 

 

0 Likes
Message 3 of 8

denisT.MaxDoctor
Advisor
Advisor

I forgot to mention... since we are working at the object level, we don't need to use methods such as modifiers collapse, conversion to splines, xform reset.

0 Likes
Message 4 of 8

denisT.MaxDoctor
Advisor
Advisor
Accepted solution

I can already see some potential problems, but I won't point out them or how to solve them just yet in order to keep the intrigue of the task alive.

 

continuing the fun, let's organize "real time" length monitoring:

fn spline3DLength node g: = 
(
	if g == unsupplied do g = (dotnetclass "Autodesk.Max.GlobalInterface").Instance

	inode = g.COREInterface7.GetINodeByHandle node.inode.handle
	ob_state = inode.EvalWorldState g.COREInterface.Time true --asdotnetobject:true
	obj = ob_state.obj
	sp = obj.ConvertToType g.COREInterface.Time g.SplineShapeClassID
	bz = sp.Shape	

	temp_s3d = g.Spline3D.Create bz.Splines
	--temp_s3d = bz.Splines
	tm = inode.GetObjectTM g.COREInterface.Time (g.Interval.Create())

	temp_s3d.Transform tm
	len = temp_s3d.SplineLength
		
	temp_s3d.Dispose()
		
	len
)
fn promptShapeLength node = if iskindof node Shape do
(
	len = spline3DLength node
	pushprompt (formattedprint len format:".3f")
)

deleteallchangehandlers id:#shape_length_monitor
_h = when geometry shapes changes id:#shape_length_monitor node do
(
        promptShapeLength node
)

 

Message 5 of 8

StanleyNguyen2023
Participant
Participant
Well, .NET and SDK represent a whole new realm for me, and it's a tad overwhelming - especially considering I've just started exploring MaxScript a bit over two weeks ago.

Returning to the main topic, based on the end of your code snippet, I understand that the change handle id:#shape_length_monitor has been registered to run the functions promptShapeLength and spline3DLength. However, when I execute the script and try changing my selection from one shape to another, nothing gets printed in the listener. The only log generated by the script is when I execute it, yielding: "ChangeHandler:0x00004aa4." Is there something I'm doing wrong, or is there an additional step required to initialize the script?

Apart from this, I'm delving back into the 3dsMax help doc to grasp the meaning of your code, genuinely excited about it
0 Likes
Message 6 of 8

denisT.MaxDoctor
Advisor
Advisor

change handler registered to notify you of a change in #geometry. If you need to track a change in #selection, just add this event type. (See MXS help for details)

 

 

Message 7 of 8

denisT.MaxDoctor
Advisor
Advisor

@StanleyNguyen2023 wrote:
Well, .NET and SDK represent a whole new realm for me, and it's a tad overwhelming - especially considering I've just started exploring MaxScript a bit over two weeks ago.


How was I supposed to know how familiar you were with MaxScript? Judging by the nature of your questions and the quality of your code, things look a lot more mature than two weeks. 
😉

Message 8 of 8

StanleyNguyen2023
Participant
Participant

I took some time to thoroughly review the code as it didn't appear to print the numbers in my listener dialog. After I added a line "format "% \n" len" at the end of the promptShapeLength function, it turned out the shape length parameters were successfully printed. The code operated remarkably well. I compared the code's output with the built-in measurement tool in 3dsmax and they matched perfectly. This is arguably the highlight of my day, I'm truly thrilled. Thank you, Denis!

However, I stumbled upon some minor issues:

  • I recorded a video where the code works smoothly in most cases (in the attachment, please check). However, peculiarly, it flagged an error with the Line class: "Unknown property: "shape" in dotNetObject: Autodesk.Max.Wrappers.ShapeObject". This is strange as other shape primitives, such as Circle, didn't encounter any problems. Is this the potential problem you were referring to earlier?

  • I also experienced issues with the "pushprompt (formattedprint len format:".3f")" . For some reason, it doesn't display the length parameter in my listener. Apart from this, there were instances where the code printed zero length.

  • Lastly, is there a way to get the length of selected segments or selected splines in a shape object while I'm editing the object at sub-object levels 2 and 3?

 

0 Likes