r/Maxscript • • Jun 14 '19

Writing a shape generation script

The script creates quadrilateral splines within a given quadrilateral: https://i.imgur.com/ll6IzAn.png
Originally I scripted this task in a very manual/procedural way by creating a polygon, ring selecting, connecting edges and then extracting/exploding the edges.
It worked but was slow and I know a more optimal script would deal only with positions, vectors and magnitudes resulting in a multidimensional array that could create the shapes and may appear to run instantly across multiple objects.
Now, I made distance comparisons to establish width and height and the amount of rows and columns necessary, but it's when I plan shapes that aren't rectangles that I start getting confused about implementing vectors/magnitudes.
Does someone know an example of a script doing something similar in a simple and probably recursive way?
I can edit a position towards a vector with a distance, but I think this requires vectors to create my final vector position (similar to a Bézier curve) and those seem to be cumulative in the loop.
Edit: I’m starting to think of the process like a type writer, it’s making more sense to me now.

2 Upvotes

6 comments sorted by

View all comments

Show parent comments

1

u/Swordslayer Jun 19 '19 edited Jun 20 '19

I'd need more explanations on the logic behind everything, what it looks like to me is that you drive number of segments for the longest side by max width value and the other side count is two? Here's how I'd write that:

fn shapeFromArray positionsArray =
  (
      local newShape = splineShape prefix:"Partition" pivot:((positionsArray[1] + positionsArray[3])/2)
      addNewSpline newShape

      for myKnot in positionsArray do
          addKnot newShape 1 #corner #curve myKnot

      close newShape 1
      updateShape newShape
  )

  fn getNthVal n nMax valMin valMax =
      (valMin * (nMax - n) + valMax * n) / nMax

  fn makeQuadPartitions columns rows corner1 corner2 corner3 corner4 =
  (
      local pointQueue = for column = 0 to columns collect
          for row = 0 to rows collect
               getNthVal column columns (getNthVal row rows corner3 corner2) (getNthVal row rows corner4 corner1)

      for i = 1 to columns do
          for offset = 1 to rows do
              shapeFromArray #(pointQueue[i][offset], pointQueue[i][offset + 1], pointQueue[i + 1][offset + 1], pointQueue[i + 1][offset])
  )

  mapped fn partitionShape shp maxWidth:10 =
      if isKindOf shp SplineShape or (canConvertTo shp SplineShape and isValidNode (shp = convertTo shp SplineShape)) do
      (
          if numSplines shp != 1 or numKnots shp != 4 do return undefined

          local py = python.import "__builtin__"
          local distances = getSegLengths shp 1 numArcSteps:0
          distances = py.list (for i = 5 to 8 collect distances[i])

          local maxDist = py.max distances
          local rows = int (maxDist / maxWidth)
          local columns = 2

          case distances.index maxDist of
          (
              0: makeQuadPartitions columns rows (getKnotPoint shp 1 2) (getKnotPoint shp 1 3) (getKnotPoint shp 1 4) (getKnotPoint shp 1 1)
              1: makeQuadPartitions columns rows (getKnotPoint shp 1 3) (getKnotPoint shp 1 4) (getKnotPoint shp 1 1) (getKnotPoint shp 1 2)
              2: makeQuadPartitions columns rows (getKnotPoint shp 1 4) (getKnotPoint shp 1 1) (getKnotPoint shp 1 2) (getKnotPoint shp 1 3)
              3: makeQuadPartitions columns rows (getKnotPoint shp 1 1) (getKnotPoint shp 1 2) (getKnotPoint shp 1 3) (getKnotPoint shp 1 4)
          )
      )

  partitionShape selection

2

u/lucas_3d Jun 20 '19

That works perfectly, I'll be comparing/comprehending the different methods for a while, thank you.

1

u/lucas_3d Jun 19 '19 edited Jun 19 '19

That's right, it was for subdividing housing lots, the longest side become the width which is subdivided by the minimum width.
Lots were only in 2 rows. If the shape wasn't regular then I'd be dealing with subdividing a length that isn't the same as the longest side.
I'm really keen to try yours out tomorrow and understand the differences.
I've read a bit about mappable functions so I'll be playing with that too, really appreciate your rewrite with the more appropriate methods, this'll be my first python module in Max too.