Community
3ds Max Programming
Welcome to Autodesk’s 3ds Max Forums. Share your knowledge, ask questions, and explore popular 3ds Max SDK, Maxscript and Python topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Create NGON by specifying edge length.

33 REPLIES 33
SOLVED
Reply
Message 1 of 34
aslantamjidi
3727 Views, 33 Replies

Create NGON by specifying edge length.

a little Script to aid exact creating Polygon shapes with specifying edge length.

 

nGon.PNG

 

the Mathematics behind this script can be found on HERE.

33 REPLIES 33
Message 2 of 34
Anonymous
in reply to: aslantamjidi

I've not tested this yet, but if it works then it appears to be exactly what autodesk needs to include in Max natively - maybe via a small update/patch for all versions and spare us the need to wait for a new release to get it.  Well done!

Message 3 of 34
Swordslayer
in reply to: aslantamjidi

Nice one! I've taken the liberty to convert it to scripted shape primitive so that it appears in the same category that the original NGon does and you can create it with autogrid anywhere in the scene just like other primitives. Hope you don't mind:

 

--	visit My webSite at: www.aslan3d.com
--	contact with my by: aslan.tamjidi@gmail.com

plugin shape NGonExt
	name:"NGonExt" category:"Splines" replaceUI:on
	extends:NGon classID:#(0x117e72e, 0x5ba1ec54)
	usePBValidity:on
(
	fn updateRadius = this.radius =
		 0.5d0 * this.edgeLength / (if this.type == 1 then tan else sin) (180d0 / this.sides)
	
	fn updateEdgeLength =
	(
		disableRefMsgs()
		this.params.spnEdgeLength.value =
			2 * this.radius * (if this.type == 1 then tan else sin) (180d0 / this.sides)
		enableRefMsgs()
	)

	parameters main rollout:params
	(
		radius type:#worldUnits default:5 ui:spnRadius
		type type:#integer default:2 ui:rbType
		sides type:#integer default:6 ui:spnSides
		edgeLength type:#worldunits ui:spnEdgeLength
		cornerRad type:#worldunits default:0 ui:spnCornerRadius
		circular type:#boolean default:off ui:chxCircular

		on edgeLength set val do updateRadius()
		on sides set val do (delegate.nSides = val; updateRadius())
		on type set index do (delegate.scribe = index - 1; updateRadius())
		on radius set val do (delegate.radius = val; updateEdgeLength())
		on cornerRad set val do delegate.cornerRadius = val
		on circular set state do delegate.circular = state
	)

	rollout params "NGon by Aslan3D.com" width:150
	(
		spinner spnRadius "Radius: " range:[0,1e6,10] type:#worldunits fieldWidth:70
		radioButtons rbType labels:#("Inscribed", "Circumscribed") columns:2 default:2
		spinner spnSides "Sides: " range:[3,100,6] type:#integer fieldWidth:70
		spinner spnEdgeLength "Edge Length: " range:[0,1e6,10] type:#worldunits fieldWidth:70
		spinner spnCornerRadius "Corner radius: " range:[0,1e6,0] type:#worldunits fieldWidth:70
		checkBox chxCircular "Circular" checked:off align:#center
	)

	tool create numPoints:2
	(
		on mousePoint click do if click == 1 do
			nodeTM.translation = worldPoint

		on mouseMove click do if click == 2 do
			radius = (gridDist.x^2 + gridDist.y^2)^.5
	)
)

Since it extends the built-in NGon, you will also get the original params at creation time - those could be hidden but not that easily so I didn't bother. In the modify panel, only the new params will be shown.

 

@Anonymous: if you put it inside the scripts\startup folder, it'll be always at your disposal.

Message 4 of 34
Anonymous
in reply to: Swordslayer

@Anonymous This is great!  The only problem I have is that I can't define where or how one of the edges is oriented.  eg:  I want to create a pentagon off of an already created edge, or based on the distance between 2 verts.  As it is, it creates the NGon just fine, but I don't know how to orient it so as to make one of the edges position as mentioned - along a given edge or between 2 verts.  Ideally, the creation process would go something like this:

 

Pick start point,

then pick a 2nd point to define the direction that one of the edges will run,

then (optional) define an exact length of the side. 

 

This would allow us to create NGons with precise edge placement and/or edge length.  If you're familiar with how Rhino does it, that's what I'd love to see in Max.

 

Any idea how to add this functionality or how to achieve it after the NGon is created?

 

I have a screencast of what I want, but it's not showing in the drop down atm.  Will try to get it working and post a link so you can see what I'm on about.

Message 5 of 34
Anonymous
in reply to: Anonymous

 

Screen cast showing how Rhino does NGons from edge.

 

 

Message 6 of 34
Swordslayer
in reply to: Anonymous

Yes, I think this should do the trick:

 

ngonSnap.gif 

 

Not as smooth as Rhino, though, it will jump around a bit when snapping. Set the number of sides before you start drag-creating it, it will only respect the picked direction on creation, not when changing the params later on.

 

--	visit My webSite at: www.aslan3d.com
--	contact with my by: aslan.tamjidi@gmail.com

plugin shape NGonExt
	name:"NGonExt" category:"Splines" replaceUI:on
	extends:NGon classID:#(0x117e72e, 0x5ba1ec54)
	usePBValidity:on
(
	fn getRot vec =
	(
		local rot = atan2 vec.x vec.y
		if rot > 0 then rot else 360d0 + rot
	)

	fn updateRadius = this.radius =
		 0.5d0 * this.edgeLength / (if this.type == 1 then tan else sin) (180d0 / this.sides)
	
	fn updateEdgeLength =
	(
		disableRefMsgs()
		this.params.spnEdgeLength.value =
			2 * this.radius * (if this.type == 1 then tan else sin) (180d0 / this.sides)
		enableRefMsgs()
	)

	parameters main rollout:params
	(
		radius type:#worldUnits default:0 ui:spnRadius
		type type:#integer default:2 ui:rbType
		sides type:#integer default:5 ui:spnSides
		edgeLength type:#worldunits ui:spnEdgeLength
		cornerRad type:#worldunits default:0 ui:spnCornerRadius
		circular type:#boolean default:off ui:chxCircular

		on edgeLength set val do updateRadius()
		on sides set val do (delegate.nSides = val; updateRadius())
		on type set index do (delegate.scribe = index - 1; updateRadius())
		on radius set val do (delegate.radius = val; updateEdgeLength())
		on cornerRad set val do delegate.cornerRadius = val
		on circular set state do delegate.circular = state
	)

	rollout params "NGon by Aslan3D.com" width:150
	(
		spinner spnRadius "Radius: " range:[0,1e6,10] type:#worldunits fieldWidth:70
		radioButtons rbType labels:#("Inscribed", "Circumscribed") columns:2 offsets:#([2, 0], [-10, 0]) default:2
		spinner spnSides "Sides: " range:[3,100,6] type:#integer fieldWidth:70
		spinner spnEdgeLength "Edge Length: " range:[0,1e6,10] type:#worldunits fieldWidth:70
		spinner spnCornerRadius "Corner radius: " range:[0,1e6,0] type:#worldunits fieldWidth:70
		checkBox chxCircular "Circular" checked:off align:#center
	)

	tool create numPoints:2
	(
		local startPos, invTM, zDir, angle, vec
		local targetPos, dist, roet

		on mousePoint click do if click == 1 do
		(
			zDir = nodeTM.row3
			angle = 90 - 180d0 / sides
			invTM = inverseHighPrecision nodeTM
			startPos = nodeTM.translation = worldPoint
		)

		on mouseMove click do if click == 2 do
		(
			vec = worldPoint - startPos
			dist = .5 * length vec * tan angle
			edgeLength = (gridDist.x^2 + gridDist.y^2)^.5
			targetPos = startPos + vec / 2 + dist * cross zDir (normalize vec)
			rot = getRot (normalize (targetPos * invTM - startPos * invTM)) + 90

			nodeTM = angleAxis rot zDir as matrix3 * transMatrix targetPos
		)
	)
)
Message 7 of 34
aslantamjidi
in reply to: Swordslayer

wow thank you Vojtěch Čada.

it's completely new script, from ground. your do it great always. I couldn't imagine as compact script as you write. Heart

this should be on ScriptSpot.com too...

Message 8 of 34
Swordslayer
in reply to: aslantamjidi

My pleasure. Anyway, the last one I posted is wrong, the nodeTM seems to be set in grid space, not world space as I thought, so the mousetool should be instead:

 

tool create numPoints:2
(
	local startPos, angle, vec
	local targetPos, dist, roet

	on mousePoint click do if click == 1 do
	(
		startPos = gridPoint
		angle = 90 - 180d0 / sides
		nodeTM.translation = worldPoint
	)

	on mouseMove click do if click == 2 do
	(
		vec = gridPoint - startPos
		dist = .5 * length vec * tan angle
		edgeLength = (gridDist.x^2 + gridDist.y^2)^.5
		targetPos = startPos + vec / 2 + dist * cross z_axis (normalize vec)
		rot = getRot (normalize (targetPos - startPos)) + 90

		nodeTM = angleAxis rot z_axis as matrix3 * transMatrix targetPos
	)
)

I've attached the fixed script, there might be other mistakes...

Message 9 of 34
aslantamjidi
in reply to: Swordslayer

I think attached script is my old one...

Message 11 of 34
Anonymous
in reply to: Swordslayer

@Anonymous  I replaced the old script with your latest version nut now it no longer appears in the shapes tab but as a floating dialog whenever max starts up.  Did I do something wrong or is the script behaving different?

 

I'm also not sure how to use it.  With the floating dialog up, i set the params and click Create, but it just creates a ngon at the origin with no drag functionality.

 

EDIT:

I was a bit hasty - the new post works great.  A little jerky but totally functional.  Many thanks.  I also agree that this should be posted on ScriptSpot - I'm sure many others will find this script of value.  Great job!

Message 12 of 34
Swordslayer
in reply to: Anonymous
Message 13 of 34
Anonymous
in reply to: Swordslayer

All we need now is to convince AutoDesk to add this as a update/patch to Max as a native operation and it'd be perfect.

Message 14 of 34
Swordslayer
in reply to: Anonymous

It kept bugging me that this is basically a creation-time hack, so I made a proper ngon by edge spline primitive. Doesn't have corner radius or circularize option, both would be possible but don't seem that useful when you're snapping to some existing edge. Holding shift when creating it constraints the axis to x/y.

Message 15 of 34
Anonymous
in reply to: Swordslayer

I'm not sure what a "creation-time hack" is, but this script is cool!  And the constrain with shift is a bonus as well.  I do have one issue though, If i create say a pentagon, then want to create another ngon off one of the edges, it seems that the orientation of the new ngon is dependant on which point you choose as the starting point of the edge.  This can get confusing because if you choose the wrong starting point, the new ngon would overlap the existing one as opposed to picking the opposite point and the orientation is away from the original ngon (if that makes any sense). 

 

I'd like to suggest that IF you add the option to say hold down CTRL or ALT while dragging, the orientation of the new ngon would flip/mirror so you don't have to cancel the creation and start over with the opposite point to get the orientation right.

 

I hope that makes sense, but if you play with it you'll see what I mean - if not I'll try explaining it better.

Message 16 of 34
Swordslayer
in reply to: Anonymous
Message 17 of 34
Anonymous
in reply to: Swordslayer

Autodesk really should consider offering you some contact work. It never ceases to amaze me how potent max scripting is - I wish I had the discipline and patience to learn it.
Message 18 of 34
aslantamjidi
in reply to: Swordslayer

an other Idea...
you can separate creation mouse event to two click instead of one click&drag so then you have mouse wheel rotation to increase or decrease sides count on the go.
you are brilliant.

Message 19 of 34
Swordslayer
in reply to: aslantamjidi

I agree that users should be able to manipulate anything that has segments in that way. At the same time, I'm keeping mousewheel manipulation strictly to the KeyHydra toolset - if you're using it, you can add ngonEdge to the config manually (the entry would look almost the same as the ngon example shown on the gif).

Message 20 of 34

unfortunately the code for solution is not right and can't be used as plugin in general...

 

it's very easy to see -  just try to animate both Radius and Edge Length...

Radius and Edge Length are cross-dependent values. So the code needs to be reviewed.

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

Post to forums  

Autodesk Design & Make Report