a little Script to aid exact creating Polygon shapes with specifying edge length.
the Mathematics behind this script can be found on HERE.
Solved! Go to Solution.
Solved by Swordslayer. Go to Solution.
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!
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.
@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.
Yes, I think this should do the trick:
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 ) ) )
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.
this should be on ScriptSpot.com too...
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...
Ooops, sorry, edited.
@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!
See the edit above, I've goofed up and attached aslantamjidi's original script instead at first.
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.
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.
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.
I like the way you think 🙂 Holding ctrl now flips the shape (plus there's a UI parametr for that now).
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.
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).
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.