Home Technical Talk
The BRAWL² Tournament Challenge has been announced!

It starts May 12, and ends Sept 12. Let's see what you got!

https://polycount.com/discussion/237047/the-brawl²-tournament

[MAXScript] Begining and End of Selected Edge Loop

interpolator
Offline / Send Message
Revel interpolator
Quick question for you guys that do maxscript; is there a way to identified which edges are there on the begining and end of a selected edges loop (of course when a non full loop selected)?

By simply extracting the edgeLoop[1] and edgeLoop[edgeLoop.count] wont do the trick...(in this example case; edgeLoop = (polyOp.getEdgeSelection $) as array)

Replies

  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    Sure, they are the edges where one of the verts isn't shared with any of the other selected edges.
  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    Basically
    1. (
    2. local getEdgesByVerts = polyOp.getEdgesUsingVert
    3. local getVertsByEdges = polyOp.getVertsUsingEdge
    4.  
    5. fn getEdges obj loopEdges =
    6. for edge in loopEdges where
    7. (getEdgesByVerts obj (getVertsByEdges obj edge) * loopEdges).numberSet != 3
    8. collect edge
    9.  
    10. getEdges $ (polyOp.getEdgeSelection $)
    11. )
  • Revel
    Offline / Send Message
    Revel interpolator
    Thanks fo much Swordslayer, it works but I still don't get it about the [...].numberSet != 3 part though...

    I'm inspired to do my own version of Angle Loop because I don't really like how he implemented the rollout into the edit poly rollout (and causes flash everytime) so I decided to practice write my own version.

    Here is what I've got so far;
    1. (
    2. -- veriables
    3. local
    4. selEdges = #(),
    5. getVertsByEdges = polyOp.getVertsUsingEdge,
    6. getEdgesByVerts = polyOp.getEdgesUsingVert
    7. for edge in (polyOp.getEdgeSelection $) do
    8. append selEdges edge
    9. -- functions
    10. fn getEdges obj loopEdges =
    11. for edge in loopEdges
    12. where (getEdgesByVerts obj (getVertsByEdges obj edge) * loopEdges).numberSet != 3
    13. collect edge
    14. fn getVerts obj loopVerts =
    15. for vert in loopVerts
    16. where (getVertsByEdges obj (getEdgesByVerts obj vert) * loopVerts).numberSet != 3
    17. collect vert
    18. fn angleLoop obj vOp eOp =
    19. (
    20. eTest = getEdgesByVerts obj vOp
    21. for edgeOp in eOp do
    22. (
    23. for edgeTest in eTest do
    24. (
    25. edge1verts = (polyop.getVertsUsingEdge $ edgeTest) as array
    26. vector1 = (polyop.getVert $ edge1verts[1]) - (polyop.getVert $ edge1verts[2])
    27. edge2verts = (polyop.getVertsUsingEdge $ edgeOp) as array
    28. vector2 = (polyop.getVert $ edge2verts[1]) - (polyop.getVert $ edge2verts[2])
    29. vAngle = acos (dot (normalize vector1) (normalize vector2))
    30. if vAngle < 20 or
    31. vAngle > 160 do
    32. append selEdges edgeTest
    33. )
    34. )
    35. )
    36. -- operation
    37. vOp = getVerts $ (polyop.getVertsUsingEdge $ (polyOp.getEdgeSelection $))
    38. eOp = getEdges $ (polyOp.getEdgeSelection $)
    39. angleLoop $ vOp eOp
    40. polyop.setEdgeSelection $ selEdges
    41. redrawViews()
    42. )
    .. but with this it's only select the next possible edges instead of select the whole possible edges like the version on Scriptspot and also somehow it ignored the last edge, still looking into what's causing this. If you have any suggestion on how to improve this, as always please post it here! :)
  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    Quite a few suggestions, actually the post was getting out of hands :) In the end, I've opted to upload the thing to scriptspot instead, no encryption, of course: heuristic edge select. Hope it gives you the results you were after; feel free to adapt it to your needs eitherway.

    The [...].numberSet != 3 part basically checks if there are three selected edges sharing the two verts of the middle one. If it is so, it means the edge has another selected edge on both its sides; if not, that edge has to be at the end of the loop and it's the edge we were looking for.
  • Revel
    Offline / Send Message
    Revel interpolator
    Yeah! nice one Swordslayer! I did however slightly alter the behavior of how user execute your script. There is a double click functions that Mark posted a while ago here on the forum so I assigned a single click for normal execute and double clicks for opening a dialog box setting, a similar setup for my chamfer/ inset/ extrude/ etc.

    And no way I can wrote a script that complex myself at the moment..haha!
  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    Glad to hear that, could you post a link to the double click functions? I'm more or less a random visitor here and it sounds like I missed that one, sounds interesting.
  • Revel
    Offline / Send Message
    Revel interpolator
    Here you go LINK. As always I like to modified people's script, so here is my little modified version;
    1. lastClicked = 0
    2. fn multiClicks singleCmd doubleCmd =
    3. (
    4. thisClicked = timeStamp()
    5. if (thisClicked - lastClicked) > 500 then singleClick = 1 else singleClick = 0
    6. if (thisClicked - lastClicked) < 500 then doubleClick = 1 else doubleClick = 0
    7. lastClicked = thisClicked
    8. case of
    9. (
    10. (singleClick == 1): singleCmd()
    11. (doubleClick == 1): doubleCmd()
    12. )
    13. )
    Well I wanted to make it so the command call either singleCmd OR doubleCmd, cus on it's current form it run the singleCmd and then run the doubleCmd. Some action like extrude/ chamfer works well this this setup but something like connect, it's just didn't work cus the singleCmd call the connect and then when we double click it to call the doubleCmd (in this case; connect dialog box), the previous selected edges has been connected thus calling the dialog box after that become useless.
  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    That's a nice idea, you can do that, too ;) Proof of concept:
    1. macroscript DoubleTap
    2. category:"Advanced"
    3. toolTip:"Double Tap"
    4. (
    5. local lastTapped = 0
    6. local delay = 500
    7. local waiting = false
    8. local timer = dotNetObject "Timer"
    9. fn singleFn = print "single"
    10. fn doubleFn = print "double"
    11.  
    12. fn onTick sender evnt =
    13. (
    14. if waiting do singleFn()
    15. sender.Stop()
    16. waiting = false
    17. )
    18.  
    19. fn multiClicks =
    20. (
    21. local tapped = timeStamp()
    22. waiting = tapped - lastTapped > delay
    23. if waiting then timer.Start()
    24. else doubleFn()
    25. lastTapped = tapped
    26. )
    27.  
    28. timer.Interval = delay
    29. dotnet.addEventHandler timer "Tick" onTick
    30.  
    31. on execute do multiClicks()
    32. )
  • Revel
    Offline / Send Message
    Revel interpolator
    Yeah, I does work like I planned at first! but, hmmm...at the current state of the script we cant really make it as a global function and use it across many other scripts locally, right?
  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    Okay, this one was a bit tricky, for details refer to the thread at cgtalk. Place this in your ..\stdplugs\stdscripts\ folder (will work for max 9+):
    1. struct tapWatcherDef
    2. (
    3. singleFn, doubleFn,
    4.  
    5. delay = 250,
    6. timer = dotNetObject "Timer",
    7. lastTapped = timeStamp() - 2*delay,
    8. waiting = false,
    9.  
    10. fn onTick sender evnt =
    11. (
    12. sender.Stop()
    13. if sender.Tag.Value.waiting do
    14. sender.Tag.Value.singleFn()
    15. sender.Tag.Value.waiting = false
    16. ),
    17.  
    18. fn init self =
    19. (
    20. dotNet.addEventHandler timer "Tick" onTick
    21. timer.Interval = delay
    22. timer.Tag = dotNetMXSValue self
    23. ),
    24.  
    25. fn multiClick =
    26. (
    27. local tapped = timeStamp()
    28. waiting = tapped - lastTapped > delay
    29.  
    30. if waiting then timer.Start()
    31. else doubleFn()
    32.  
    33. lastTapped = tapped
    34. )
    35. )

    and call it from the macroscript like this:
    1. macroScript DoubleTap
    2. category:"Advanced"
    3. toolTip:"Double Tap"
    4. (
    5. fn singleFn = print "single tap"
    6. fn doubleFn = print "double tap"
    7.  
    8. local tapFn = if globalVars.isGlobal #tapWatcherDef AND isStructDef ::tapWatcherDef then
    9. (
    10. local tapWatcher = tapWatcherDef singleFn:singleFn doubleFn:doubleFn
    11. tapWatcher.init tapWatcher
    12. tapWatcher.multiClick
    13. )
    14. else singleFn
    15.  
    16. on execute do tapFn()
    17. )
  • Revel
    Offline / Send Message
    Revel interpolator
    Hey Swordslayer thanks for the solution, couldn't figured that out on my own for sure when it touch dotnet stuff..anyway, I've play around with your script for a while but something still doesn't feel quite right so I go ahead and read your thread on CGTalk..and to be honest I don't quite understand, heh!

    I did tried the Polytools' solution and it seems like by combining only using one global instance work more similar to my previous script. But one thing that still question in my head is; what are the ids (senderMcr)? it seems like a random number, so I removed it from the script and it still works like normal..hmm..
  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    Yes, random numbers, could be anything; but it is needed - it will work as expected most of the time yet when you press two such single keyboard shortcuts in a short time, it will get detected as one shortcut pressed twice.
Sign In or Register to comment.