Monday, May 25, 2009

01B-Alice-Questions

Thanks a lot Daniel for all the comments. I am happy to know the script is working in the right direction. :) Sorry for sending you back my questions again...late...

Refer to your comments

1) I understand what you said and why the value of the points should be generated inside the function. However, if I change my function to

def pointBoundary(iterations, ptA, ptB, ptC):

do I still need to, at least for once, use the random function to generate 3 points before I can call my function?
when I call the recursion, can I just say, for instance:

pointBoundary(10, ptA, ptB, ptC) or pointBoundary(10)

2) I am not clear what do you mean:
"it should be idented under the else statement, so that it is executed only if iterations are not equal to 0"
because I have already idented...what should I change?

3)I successfully created random points and store them in a list.

pts=["ptA","ptB","ptC"]
for i in range (len(pt)):
from random import *

x = uniform(-squareSideLength/2, squareSideLength/2)
y = uniform(-squareSideLength/2, squareSideLength/2)
pts[i] =(x,y)

Is that alright?

** I have extra questions -
any differences if I write "pts[%d]%i" but not "pt[i]" ??

4) How to make sure I offset the line outward but not inward, in relation to the centre of the square??

5) Would using "classes" will help to shortening the script? because I always need to repeat the each steps for A, B, C...but I can't simply use loop...

6) Other questions you haven't answered:

a) Can you run the Serpentine Pavilion Script? I have syntax error with the line "iterations-=i"
b) What does argument type -"boolean" and "linear" mean?
c) What does "break" mean?
d) I can check cmds.command on the python help list, but how about others like "random" commands, those kinds of none cmds. commands?

Thanks.

Sunday, May 24, 2009

01B - Alexandra+Micea - Recursion squares - ScreenShots







01B - Mircea+Alexandra - Recursion squares-Script


#assignment o1B_A+M

#create an initial square
#get the coordinates of the points on each line, depending on the percentage ( in this case the percenatege is a subdivison)
#create a new square with the center in each point we get in the previous step
#rotate the squares with an angle
#scale the initial square
#recursion (by each iteration a new square is created, and along the lines other squares are created and rotated in the same time)


import maya.cmds as cmds

#create one initial square
x=10
y=10
mySquare = cmds.nurbsSquare(sl1=x, sl2=y)


def recursion( iterations , amt , percentage):
it=iterations
pp=percentage

#select the square
cmds.select( mySquare, r=1 )
isSides = cmds.filterExpand( sm=9 )
print isSides

#go through all the lines of the square
for i in range(0, len(isSides), 1):
print i
line = isSides[i]
#get the coordinates on the lines depending on the percentages
for j in range(1, pp+1, 1):
procent = j/float(pp)
poc = cmds.pointOnCurve(line,pr=procent,top=True,p=True)
#create a new square with the center in each point;
#the side of the squares created either can have decreasing values or the same length
#newSquare = cmds.nurbsSquare(c=poc, sl1=1/float(x/pp), sl2=1/float(y/pp))
newSquare = cmds.nurbsSquare(c=poc, sl1=2, sl2=2)
#rotate squares with an angle
cmds.rotate(0,0,it*amt*2, newSquare, pivot=poc)

if iterations == 0:
return "Done."
else:
iterations -= 1
percentage -= 1
#scale the initial square
cmds.scale( 1/float( x/pp),1/float( x/pp), 1/float( x/pp) , mySquare, pivot=(0, 0, 0), absolute=True )
recursion(iterations, amt, percentage)


recursion(4,10,4)



Assignment 01B



Question:
How to get the intersection coordinate in this case?

Assignment 01B

import maya.cmds as cmds

#Step1:Define the biggest and smallest circles
BigRadius=30
SmallRadius=2
Minus= BigRadius-SmallRadius

#Step2:Create these two circles
cmds.circle(c=(0,0,0),r=30)
cmds.circle(c=(0,-28,0),r=2)

#Step3:Generate two circles which follow the tangent princples
#1)r1+r2=D
NextRadius=SmallRadius+1
D= NextRadius+SmallRadius
cmds.circle(c=(0,-28,0),r=D)

#2)offset the outmost circle based on the radius of next circle
cmds.circle(c=(0,0,0), r=BigRadius-NextRadius)
#3)Get the intersection point at the right side and as the center point of the new circle
# which is tangent with previous two circles
#Question:
# How to find out the coordinate of the intersection point in this case??????????????????????

'''
#Loop through it based on previous steps
for i in range(2,BigRadius,1):
cmds.circle(c=(0,0,0),r=Minus-i)
radius=3
r1= radius
r2= radius+i
radius+=1
D=r1+r2
cmds.circle(c=(the center coordinate from the intersection point),r=D)
'''

Saturday, May 23, 2009

MY SCRIPT "RECURSION STUFF" - pic



MY SCRIPT "RECURSION STUFF" - it works)

 def PLAN():
   1)Create primitive (6 angle for ex-le)
   2)Use this primitive as a path (curve)
   3)Define the random amount of primitives(within Fibonacci numbers 1,1,3,5,8,13,21,44,65...)
   4)Dulicate them
   5)Pick a random point within pritive length 
   6)Move them on it 
   7)Scale primitives random
   8)enjoy)
PLAN()
###RECURSION STUFF#####
##
def primitives(numSides, radius):
#create a circle
myCircle = cmds.circle(radius = 30)
#get param steps, I will take 6 for ex-le
paramSteps = 1./6
#loop and get points coordinates
points = []
for i in range(0, 8, 1):
points.append(  cmds.pointOnCurve(myCircle[0], p=1, pr=paramSteps*i, top=1)  )
#create a curve connecting points
myPrimitive = cmds.curve(ep=points, d=1)
#close the curve
cmds.closeCurve(n="p_"+str(numSides)+"_sides", rpo=1)
#delete the circle 
cmds.delete(myCircle)
#return the name of the primitive
return myPrimitive
primitives(6, 30)

from random import *

def Whatamess():
#define the random amount of primitives
randomAmount = randint(21,44) # fibonachi number 1,1,3,5,8,13,21,44,65... and so on
for i in range (0,randomAmount,1):
#duplicate my primitiv
myDupObj2 = cmds.duplicate( 'curve1' ) 
# get the center of the duplicated object
myCenter = cmds.xform(myDupObj2, q=1, t=1, ws=1)
# get the maximun "length" of the curve, so we can pick a random point within this length
#I wanna use my Primitive as a curve. Why not?)
myCurveParam = cmds.getAttr("curve1.maxValue")
# select a random point on the curve
myPoint = cmds.pointOnCurve( 'curve1', pr = uniform(0,myCurveParam), p=True)
# select the previously duplicated object
cmds.select(myDupObj2)
# move it to the new location
cmds.move(myPoint[0],myPoint[1],myPoint[2])
#scales it
cmds.scale(uniform(1,1.5),uniform(1,1.5),uniform(1,1.5),a=1)

Whatamess()

### As You can see, I changed my consept a bit,
### from controlled variant to random, because I dont know how to put 
### mathematical formulas (Fibonacci x3 = x2+x1) But I included one of your "helpful" scripts and I like the result) after all

 
 def PLAN1():
   1)Create primitive (6 angle for ex-le)
   2)Use this primitive as a path (curve)
   3)Define the random amount of primitives(within Fibonacci numbers 1,1,3,5,8,13,21,44,65...)
   4)Dulicate them
   5)Pick a  point within pritive length ( I dont know how to pick different 
          points with Fibonacci proporsion-divide curve propotionally [1,1,3,5...])
   6)Move them on it  (I dont know how to put them, so they will not intersect)
   7)Scale primitives  (but I dont know how to scale them proportionally)
   8)enjoy more)
PLAN1()

It does not work and giving mistake:
UnboundLocalError: local variable 'Squares' referenced before assignment #


import maya.cmds as cmds
x=10
y=10
#Make a Square
initialSqare = cmds.nurbsSquare(sl1=x, sl2=y)
#get outline
isSides = cmds.filterExpand (sm=9)
print isSides
#make an empty list
Squares = []
Squares.append (1)

def squareINsquare (number):
#scale
x=10/(1.5*len(Squares)+1)
y=10/(1.5*len(Squares)+1)
#loop
for j in range (0,len(Squares),1):
cmds.select (Squares[j], r=True)
#get outline
isSides = cmds.filterExpand (sm=9)
#looping in outline
for i in range (0,2,1):
perc1 = 0
perc2 = 1
line1=isSides[1]
line2 = isSides[2]
if i == 0:
poc1 = cmds.pointOnCurve(line1, pr=perc1, top=True, p=True)
print poc1
#change the center of the new square
poc1[0]=poc1[0]-x/2
poc1[1]=poc1[1]+y/2
print poc1
#make a new square
initialSqare1 = cmds.nurbsSquare(c = poc1, sl1=x, sl2=y)
#the same for the oposit corner of the squre
else:
poc2 = cmds.pointOnCurve(line2, pr=perc2, top=True, p=True)
print poc2
poc2[0]=poc2[0]+x/2
poc2[1]=poc2[1]-y/2
print poc2
initialSqare2 = cmds.nurbsSquare(c = poc2, sl1=x, sl2=y)

Squares.append (initialSqare1)
Squares.append (initialSqare2)
Squares=Squares1
Squares1=[]
if number == 0 :
#stop
return "Done."
else:
#did not finish yet
#remove one unit (count down)
number -= 1

squareINsquare (number)

squareINsquare (3)

01B - alec' - Real recursion, soft code, optimized, updated, improved & commented new script...

In this script I mainly correct my mistakes! I changed the loop in a real recursive function, I used "soft code" instead of "hard code" and I tried to optimized my codes.

I also added a recursion "J" which makes vary the result every time we call the function once again. This new "j" parameter (called "recursions" with a "s") increase the rotation angle and the scale of the squares. (= the first 4th screenshots)

In this example, I used a loop at the end of the script to call the function 5times!
and I configured this script to show only the z-axis projection. (= the last screenshot)

I didn't managed to simplify the "projection part" ... from the line 53 to 65.



import maya.cmds as cmds

##########################
### INITIAL PARAMETERS ###
##########################
### drawx = project square on x axis, drawy = project square on y axis, drawz = project square on z axis
### delete3Dsquare = delete the original iterated squares
### deletelocator = delete locator related to the rotationpoint
### deleteSquareSurface = delete the nurbsSquare used for the pointPosition + offset function
drawx = 0 # 0 = Fasle /// 1 = True
drawy = 0 # 0 = Fasle /// 1 = True
drawz = 1 # 0 = Fasle /// 1 = True
delete3Dsquare = 1 # 0 = Fasle /// 1 = True
deletelocator = 1 # 0 = Fasle /// 1 = True
deleteSquareSurface = 1 # 0 = Fasle /// 1 = True
iterationgroup = cmds.group(em=True)
if cmds.objExists('j'):
print "rien"
else:
cmds.spaceLocator(n='j')
iterations = 1
j = []



############################
### DEF RECURSIVE SQUARE ###
############################
### Def the function according to 3 parameters; number of iterations, angle of rotation between each square, offset of the point of rotation
### rotationpoint [0,0,0] is the initial rotation point position /// these position are used only for the first iteration

def recursivesquares(j,iteration, angle, offset, rotationpoint=[0,0,0]):
group = cmds.group(em=True)

### Create the square, and rotate it according to the angle and rotationpoint parameters
nurbsSquare = cmds.nurbsSquare(sl1=iterations*5, sl2=iterations*5, c=rotationpoint, nry=1, nrz=0)
cmds.parent(nurbsSquare[0], group)
cmds.rotate(iterations*iteration*angle, iterations*iteration*angle, iterations*iteration*angle, [nurbsSquare[0]], pivot=(rotationpoint))

### Determining the position of each corner of this square
topposition = cmds.pointPosition('top'+nurbsSquare[0]+'.cv[0]', world=True)
leftposition = cmds.pointPosition('left'+nurbsSquare[0]+'.cv[0]', world=True)
rightposition = cmds.pointPosition('right'+nurbsSquare[0]+'.cv[0]', world=True)
bottomposition = cmds.pointPosition('bottom'+nurbsSquare[0]+'.cv[0]', world=True)

### Create a nurbs surface to use the pointOnSurface command with the offset parameter
### Create a locator in the position of this new rotationpoint
nurbsSquareSurface = cmds.squareSurface('top'+nurbsSquare[0], 'right'+nurbsSquare[0], 'bottom'+nurbsSquare[0], 'left'+nurbsSquare[0], ct1=1, ct2=1, ct3=1, ct4=1, po=0)
rotationpoint = cmds.pointOnSurface(nurbsSquareSurface[0], u=offset/(iteration+1), v=offset/(iteration+1), position=True)
locator = cmds.spaceLocator(p=rotationpoint)
cmds.parent(locator[0], nurbsSquareSurface[0], group)

### Project the squares on the x, y or/and z axis
if drawx == 1:
squaresonx = cmds.curve(d=1, p=[(topposition[0], topposition[1], 0),(leftposition[0], leftposition[1], 0),(bottomposition[0], bottomposition[1], 0),(rightposition[0], rightposition[1], 0), (topposition[0], topposition[1], 0)] )
cmds.parent(squaresonx, group)

if drawy == 1:
squaresony = cmds.curve(d=1, p=[(topposition[0], 0, topposition[2]),(leftposition[0], 0, leftposition[2]),(bottomposition[0], 0, bottomposition[2]),(rightposition[0], 0, rightposition[2]), (topposition[0], 0, topposition[2])] )
cmds.parent(squaresony, group)

if drawz == 1:
squaresonz = cmds.curve(d=1, p=[(0, topposition[1], topposition[2]),(0, leftposition[1], leftposition[2]),(0, bottomposition[1], bottomposition[2]),(0, rightposition[1], rightposition[2]), (0, topposition[1], topposition[2])] )
cmds.parent(squaresonz, group)

else:
print "project nothing"

### Clean the Scene
cmds.parent(group, iterationgroup)

if delete3Dsquare == 1:
cmds.delete(nurbsSquare[0])

if deletelocator == 1:
cmds.delete(locator[0])

if deleteSquareSurface == 1:
cmds.delete(nurbsSquareSurface[0])



### Iterate the function
if iteration == 0:
j.append(1)
return j

else:
iteration -= 1
recursivesquares(j,iteration, angle, offset, rotationpoint)


#############################
### CALL RECURSIVE SQUARE ###
#############################


for i in range (0, 5, 1):
recursivesquares(j,10,15,.9, [0,0,0])
iterations = len(j)+1
print iterations


Wednesday, May 20, 2009

Week 03 – code (part 2) - classes

Classes are the workhorses of object-oriented programming languages (OOP) like Python. As we saw, everything in Python is an object. Strings, lists, functions and even modules are objects and, as objects, they all have attributes and functions (which in the case of objects are called methods) associated with them. Let’s take the example of a list:

myList = [1 ,3.4, 5, 66, 298] 
myList.append(243)
myList.sort( )

In the above examples, append() and sort() are methods of the object list, and can be called by using the construction objectName.method(arguments).

Lists, integers, strings, etc, are built-in objects in Python. But you can create your own objects by using classes. Classes are object definitions created by the user, and work as a place to collect functions and attributes related to the object you want to create.

When you put functions and variables into a class, they have a way to “talk” to each other and keep information together. Here is an better explanation and example taken from a tutorial on the web:

For example, imagine you have a golf club. It has information about it (i.e. variables) like the length of the shaft, the material of the grip, and the material of the head. It also has functions associated with it, like the function of swinging your golf club, or the function of breaking it in pure frustration. For those functions, you need to know the variables of the shaft length, head material, etc. (…)

What happens if each time you use your golf club, the shaft gets weaker, the grip on the handle wears away a little, you get that little more frustrated, and a new scratch is formed on the head of the club? A function cannot [handle] that. A function only makes one output, not four or five, or five hundred. What is needed is a way to group functions and variables that are closely related into one place so that they can interact with each other.

Chances are that you also have more than one golf club. Without classes, you need to write a whole heap of code for each different golf club. This is a pain, seeing that all clubs share common features, it is just that some have changed properties - like what the shaft is made of, and it's weight. The ideal situation would be to have a design of your basic golf club. Each time you create a new club, simply specify its attributes - the length of its shaft, its weight, etc. (…)

These problems that a thing called object-oriented-programming solves. It puts functions and variables together in a way that they can see each other and work together, be replicated, and altered as needed, and not when unneeded. And we use a thing called a 'class' to do this.

To use classes, the same way when you create functions, you have first to define them (class definition), and then call them by creating instances of this class. Like what we did in class:

#### CLASSES
#defining a class
class Student:
#first define the class constructor
#which is the function that is executed
#every time you create an instance of this class
def __init__(self, name, attendance):
#in this function, we pass three arguments:
#self should ALWAYS be passed as the first argument
#in every function inside of a class definition
#the following arguments are defined by you
#depending on what you want to pass for the instance
#when you are creating it
self.name = name
self.attendance = attendance
self.marks = []
#in the lines above we declare a series of variables
#inhrent to the class, which will later work as
#attributes of each instance of the class you create
#as use of the "self.nameOfVariable" syntax indicates
numberOfAssignments = 0
#above we created a local variable which will exist only
#inside the class, and cannot be accessed as attributes
#of the instances you create (note we don't use "self"
print "New student was created"
print "this student did", numberOfAssignments, " assignments"
#the lines above are simple print statements which will
#show when you create an instance of the class,
#because they are located on the __init__ function

#now we leave the __init__ function and we can than create
#as many internal functions as we want
#(which are called "methods" of this class
#note that all of them MUST take as a first argument
#the variable self, so that they always refer to the
#instance itself

def addMark(self, mark):
#this is a simple function which
#appends whatever value we pass as an argument
#to the internal list "marks", which was
#created in the __init__ function
self.marks.append(mark)

def addAttendance(self):
#the same with this method, which doesn't take
#any additional arguments, but still makes modifications
#(by adding one unit) to the attendance attribute of the class
self.attendance += 1

Now that we have our class define, we can create instances of it and call its attributes and functions easily:

## creating an instance of the class		
myStudent = Student("Liu", 10)
#as you see, we create instances of a class
#by simply assigning it to a variable and
#passing the necessary intial arguments
#required by the __init__ function
#Note that we don't ever need to pass "self" as an argument
#on the instance creation, as Python automatically
#does it internally

#now we can access the attribute of these functions, also
#defined on the __init__ function, by using a simple construction:
print myStudent.name
print myStudent.attendance

#Here lies one of the powers of classes: I can create
#as many instances of that class as I need,
#and all of them inherit the methods and attributes of the class
myStudent2 = Student("Grisha", 20)
print myStudent2.name
print myStudent2.marks

#the same way as I accessed attributes aobve, I can
#call the class's methods:
myStudent2.addMark(10)
print myStudent2.marks

This was a short and small example of classes. You can do many powerful things with it as we will see next class. So keep in mind that the class definition works as a blueprint, from which as many instances as you want can be generated.

Tuesday, May 19, 2009

Week 03 – code (part 1)

We started by creating a function which would create an object on stage by recursion:

import maya.cmds as cmds

def fakeRecursion( iterations ):
for i in range(iterations): #range(0, iterations, 1)
#create the objects
cmds.circle( n="myCircle_%d" % i )
cmds.nurbsSquare( n="mySquare_%d" % i )
#rotate objs
cmds.rotate(i*10, i*10, i*10, "myCircle_%d"%i)
cmds.rotate(-i*10,- i*10,- i*10, "mySquare_%d"%i)
#move objs
cmds.move(0,0,i/10, "myCircle_%d"%i)
cmds.move(0,0,i/10, "mySquare_%d"%i)
#collect points for polyFacet
pos1 = cmds.pointPosition("topmySquare_%d.cv[0]" %i)
pos2 = cmds.pointPosition("myCircle_%d.cv[0]" % i)
pos3 = cmds.pointPosition("rightmySquare_%d.cv[0]" %i)
pos4 = cmds.pointPosition("myCircle_%d.cv[1]" % i)
pos5 = cmds.pointPosition("bottommySquare_%d.cv[0]" %i)
pos6 = cmds.pointPosition("myCircle_%d.cv[2]" % i)
pos7 = cmds.pointPosition("leftmySquare_%d.cv[0]" %i)
pos8 = cmds.pointPosition("myCircle_%d.cv[3]" % i)

cmds.polyCreateFacet(n="myFacet_%d" % i,
p=[pos1, pos2, pos3, pos4, pos5, pos6, pos7, pos8]
)
cmds.group("myCircle_%d" % i,
"mySquare_%d" % i,
"myFacet_%d" % i )

fakeRecursion(30)


As we saw, the code above works, but has a series of coding problem which makes it non-flexible and difficult to read and modify. The first modification we did was to convert the recursion, which in this case was made by using a for loop, to what we could call “real” recursion, when the function calls itself:



def realRecursion( iterations ):
i = iterations
#create the objects
cmds.circle( n="myCircle_%d" % i )
cmds.nurbsSquare( n="mySquare_%d" % i )
#rotate objs
cmds.rotate(i*10, i*10, i*10, "myCircle_%d"%i)
cmds.rotate(-i*10,- i*10,- i*10, "mySquare_%d"%i)
#move objs
cmds.move(0,0,i/10, "myCircle_%d"%i)
cmds.move(0,0,i/10, "mySquare_%d"%i)
#collect points for polyFacet
pos1 = cmds.pointPosition("topmySquare_%d.cv[0]" %i)
pos2 = cmds.pointPosition("myCircle_%d.cv[0]" % i)
pos3 = cmds.pointPosition("rightmySquare_%d.cv[0]" %i)
pos4 = cmds.pointPosition("myCircle_%d.cv[1]" % i)
pos5 = cmds.pointPosition("bottommySquare_%d.cv[0]" %i)
pos6 = cmds.pointPosition("myCircle_%d.cv[2]" % i)
pos7 = cmds.pointPosition("leftmySquare_%d.cv[0]" %i)
pos8 = cmds.pointPosition("myCircle_%d.cv[3]" % i)

cmds.polyCreateFacet(n="myFacet_%d" % i,
p=[pos1, pos2, pos3, pos4, pos5, pos6, pos7, pos8]
)
cmds.group("myCircle_%d" % i,
"mySquare_%d" % i,
"myFacet_%d" % i )

#recursion part
if iterations == 0:
return "Done."
else:
iterations -= 1
realRecursion(iterations)

realRecursion( 30 )


As we see it keeps producing the same result as the function before. Also, in terms of speed and memory, the difference is not noticeable. But as we saw, when you start to use complex and long functions, the use of “real” recursion is regarded as much more efficient.



The second step on the optimization of the function was to remove all the hard-coded bits. This allows for greater flexibility, as we don’t really need to care about the names of the created objects, simply by using variables to store them and to refer to them later:



def realRecursionOpt1( iterations ):
i = iterations
#create the objects
myCircle = cmds.circle( )
mySquare = cmds.nurbsSquare( )
#rotate objs
cmds.rotate(i*10, i*10, i*10, myCircle )
cmds.rotate(-i*10,- i*10,- i*10, mySquare)
#move objs
cmds.move(0,0,i/10, myCircle )
cmds.move(0,0,i/10, mySquare )

#collect points for polyFacet
#select mySquare
cmds.select( mySquare, r=1 )
sides = cmds.filterExpand( sm=9 )
pos1 = cmds.pointPosition( sides[0]+".cv[0]" )
pos2 = cmds.pointPosition( myCircle[0] + ".cv[0]" )
pos3 = cmds.pointPosition( sides[1]+".cv[0]" )
pos4 = cmds.pointPosition( myCircle[0] + ".cv[1]")
pos5 = cmds.pointPosition( sides[2]+".cv[0]" )
pos6 = cmds.pointPosition( myCircle[0] + ".cv[2]")
pos7 = cmds.pointPosition( sides[3]+".cv[0]" )
pos8 = cmds.pointPosition( myCircle[0] + ".cv[3]")

myFacet = cmds.polyCreateFacet(
p=[pos1, pos2, pos3, pos4, pos5, pos6, pos7, pos8]
)
cmds.group( myCircle, mySquare, myFacet )

#recursion part
if iterations == 0:
return "Done."
else:
iterations -= 1
realRecursionOpt1(iterations)

realRecursionOpt1( 30 )


As you can see, we do not have to know any names of objects if we store them in variables and use them to refer to them later.



As a last step on the optmization process, we saw how when you repeat a command too many times, it almost always means you can convert it into a loop. The same is valid for numbers or strings which are being repeated too many times: you should always recur to variables or arguments to define values which are used several times:



def realRecursionOpt2( iterations , amt=10  ):
i = iterations
#create the objects
myCircle = cmds.circle( )
mySquare = cmds.nurbsSquare( )
#rotate objs
cmds.rotate(i*amt, i*amt, i*amt, myCircle )
cmds.rotate(-i*amt,- i*amt,- i*amt, mySquare)
#move objs
cmds.move(0,0,i/amt, myCircle )
cmds.move(0,0,i/amt, mySquare )

#collect points for polyFacet
#select mySquare
cmds.select( mySquare, r=1 )
sides = cmds.filterExpand( sm=9 )

#create a list to store the positions
positions = []
for i in range( len(sides) ):
pos1 = cmds.pointPosition( sides[i] +".cv[0]" )
pos2 = cmds.pointPosition( myCircle[0] + ".cv[%d]" % i )
positions.append(pos1)
positions.append(pos2)


myFacet = cmds.polyCreateFacet(
p=positions
)
cmds.group( myCircle, mySquare, myFacet )

#recursion part
if iterations == 0:
return "Done."
else:
iterations -= 1
realRecursionOpt2(iterations, iterations )

realRecursionOpt2( 30 )


Another thing we saw on the example above is the creation and usage of optional function arguments, in this case, amt=10. In this case, as we already assign a value to amt in the function definition,  it means that if you don’t pass this argument in the function call, Maya will assume its value as 10. In case you do supply an argument, Maya will use this value instead.

Week 03 – recap

Yesterday in our third class we started by taking a look on how to optimize your code. In the example, we saw how to avoid common mistakes on scripting, such as hard-coding and repetition instead of loops. Also, we saw again how to convert a loop recursion into a “real” recursion.

In the end we had a initial and quick introduction to classes in Python, which will be our main topic next class. We will then start to look into voronoi diagrams, delaunay tessellations, and convex hulls.

Assignment 01B


import maya.cmds as cmds
import math
import maya.mel as mm



def getDistance(start, end):
#start and end must be lists xyz
v = [start[0]-end[0], start[1]-end[1], start[2]-end[2]] #list format x,y,z
vector = "<<" + str(v[0]) + "," + str(v[1]) + "," + str(v[2]) + ">>"
mag = mm.eval("mag " + vector + ";")

return mag


#########THIS IS THE NON_RECURSIVE PART ------ JUST SKIP#######################
'''
mySquare = cmds.nurbsSquare(sl1=10, sl2=15)

isSides = cmds.filterExpand (sm=9)

pos = []

for i in range (len(isSides)):
posa = cmds.pointPosition(isSides[i]+".cv[0]")
pos.append (posa)



diag = getDistance(pos[0],pos[2])
a = getDistance(pos[2],pos[3])
b = getDistance(pos[3],pos[0])

h = math.sqrt(a*a - ((a*diag)/(b+a)) * ((a*diag)/(b+a)))


mySquare2 = cmds.nurbsSquare(sl1=h, sl2=diag)
isSides2 = cmds.filterExpand (sm=9)
pos2 = []

for i in range (len(isSides2)):
posb = cmds.pointPosition(isSides2[i]+".cv[0]")
pos2.append (posb)

#get diference between actual location and move
dist = getDistance(pos[2],pos2[2])
p1 = pos[2]
p2 = pos2[2]
x=p2[0] - p1[0]
print x
y=p2[0] - p1[0]
cmds.move(x,-y,0,mySquare)



#get angle of rotation
sinF = getDistance(pos[0],pos[1])
alpha = math.asin(sinF/diag)
Ld= math.degrees (alpha)

cmds.rotate(0,0,Ld,mySquare2, pivot = pos2[2])
'''



#create initial rectangle
mySquare = cmds.nurbsSquare(sl1=a, sl2=b)


#define recursive function
def MyRecursive(iterations,a,b):

isSides = cmds.filterExpand (sm=9)

pos = []
for i in range (len(isSides)):
posa = cmds.pointPosition(isSides[i]+".cv[0]")
pos.append (posa)


#define length of diagonal in order to use it for next rectangle
diag = getDistance(pos[0],pos[2])
#define length of 2 sides to get height
a = getDistance(pos[2],pos[3])
b = getDistance(pos[3],pos[0])
#get height of triangle (diagonal and the two sides)
h = math.sqrt(a*a - ((a*diag)/(b+a)) * ((a*diag)/(b+a)))

#create new rectangle with l2=diagonal length and l1= height of triangle
mySquare2 = cmds.nurbsSquare(sl1=h, sl2=diag)
isSides2 = cmds.filterExpand (sm=9)

pos2 = []

for i in range (len(isSides2)):
posb = cmds.pointPosition(isSides2[i]+".cv[0]")
pos2.append (posb)

#get diference between actual location and move to future pivot point
dist = getDistance(pos[2],pos2[2])
p1 = pos[2]
p2 = pos2[2]
x=p2[0] - p1[0]
y=p2[0] - p1[0]
cmds.move(x,-y,0,mySquare)



#get angle of rotation from diagonal
sinF = getDistance(pos[0],pos[1])
alpha = math.asin(sinF/diag)
Ld= math.degrees (alpha)

#rotate on diagonal
cmds.rotate(0,0,Ld,mySquare2, pivot = pos2[2])

#recursion part
#if else conditions
if iterations == 0:
return "Done"
else:
iterations -= 1
MyRecursive(iterations, a,b)

#call function
MyRecursive(10,10,15)



The problems i have are first of all that the height of the triangle i am calculating is not corresponding to the actual height.

Second would be that the recursion is not working as it should.

What it should do is first create a rectangle, create another one(with length=diagonal, and width=height of the triangle formed by diagonal and two sides). Rotate the last created rectangle on the diagonal, so that one of the sides "becomes" the diagonal. And then repeat everything for the next one.

Irina_Algorithm Sketches






Alice_Assignment 01B script trial


import maya.cmds as cmds

#create an initial square
initialSquare = cmds.nurbsSquare (sl1=10, sl2=10)
isSides = cmds.filterExpand(sm=9)

#create 3 random points inside the square** (I don't know how to find this random command)
ptA =
ptB =
ptC =

def pointBoundary(iterations)
i=iterations

#Create 3 curves
lineA = cmds.curve(ep=(ptC,ptB),d=1)
lineB = cmds.curve(ep=(ptA,ptC),d=1)
lineC = cmds.curve(ep=(ptB,ptA),d=1)

#Get the distance between 3 points
lenA = cmds.distanceDimension(ptC,ptB)
lenB = cmds.distanceDimension(ptA,ptC)
lenC = cmds.distanceDimension(ptB,ptA)

#Radius of the 3 circles:riA,riB,riC
riA = (lenB + lenC - lenA)/2
riB = (lenA + lenC - lenB)/2
riC = (lenA + lenB - lenC)/2

#Create 3 circles
cirleA = cmds.circle(c=ptA,r=riA)
cirleB = cmds.circle(c=ptB,r=riB)
CirleC = cmds.circle(c=ptC,r=riC)

#Tangent points among the 3 circles
tanA = cmds.curveIntersect(lineA,circleB)
tanB = cmds.curveIntersect(lineB,circleC)
tanC = cmds.curveIntersect(lineC,circleA)

#Offset lenA, lenB, lenC to a long distance and create new lines offA, offB, offC
#(I am not sure if it offset to the right direction!!!)

offA = cmds.offsetCurve(lenA,1000)
offB = cmds.offsetCurve(lenB,1000)
offC = cmds.offsetCurve(lenC,1000)

nodeA = cmds.closestPointOnCurve(offA,tanA)
nodeB = cmds.closestPointOnCurve(offB,tanB)
nodeC = cmds.closestPointOnCurve(offC,tanC)

#Draw perpendicular lines
perA = cmds.curve(ep=(tanA,nodeA), d=1)
perB = cmds.curve(ep=(tanB,nodeB), d=1)
perC = cmds.curve(ep=(tanC,nodeC), d=1)


#Test if perpendicular lines intersect with which sides of the square
#Get coordinates of the 3 intersection points on the square and
#replace the existing values of ptA, ptB, ptC

for i in range(len(isSides)):
isIntA = cmds.curveIntersect(perA,isSides[i])
isIntB = cmds.curveIntersect(perB,isSides[i])
isIntC = cmds.curveIntersect(perC,isSides[i])
if isIntA != None:
ptA = isIntA
if isIntB != None:
ptB = isIntB
if isIntC != None:
ptC =isIntC


#Resize the initial Square
cmds.rotate(0,0,30,initialSquare)
cmds.scale(1.5,1.5,1,initialSquare)

#Recursion
if iterations ==0:
return "Done"
else:
iterations -=1

def pointBoundary(10)

Monday, May 18, 2009


import maya.cmds as cmds
x=10
y=10
#Make a Square
initialSqare = cmds.nurbsSquare(sl1=x, sl2=y)
#get outline
isSides = cmds.filterExpand (sm=9)
print isSides
#make an empty list
Squares = []
Squares.append (1)

def squareINsquare (number):
#scale
x=10/(1.5*len(Squares)+1)
y=10/(1.5*len(Squares)+1)
#loop
for j in range (0,len(Squares),1):
cmds.select (Squares[j], r=True)
#get outline
isSides = cmds.filterExpand (sm=9)
#looping in outline
for i in range (0,2,1):
perc1 = 0
perc2 = 1
line1=isSides[1]
line2 = isSides[2]
if i == 0:
poc1 = cmds.pointOnCurve(line1, pr=perc1, top=True, p=True)
print poc1
#change the center of the new square
poc1[0]=poc1[0]-x/2
poc1[1]=poc1[1]+y/2
print poc1
#make a new square
initialSqare1 = cmds.nurbsSquare(c = poc1, sl1=x, sl2=y)
#the same for the oposit corner of the squre
else:
poc2 = cmds.pointOnCurve(line2, pr=perc2, top=True, p=True)
print poc2
poc2[0]=poc2[0]+x/2
poc2[1]=poc2[1]-y/2
print poc2
initialSqare2 = cmds.nurbsSquare(c = poc2, sl1=x, sl2=y)

Squares.append (initialSqare1)
Squares.append (initialSqare2)
Squares=Squares1
Squares1=[]
if number == 0 :
#stop
return "Done."
else:
#did not finish yet
#remove one unit (count down)
number -= 1

squareINsquare (number)

squareINsquare (3)

Andreea Assignment01B


Alice_Assignment 01B

I started by writing a simple algorithm and tried to search for suitable commands in Maya to execute the task, according to my idea. But soon enough, I already feel like I don't know much commands -.-.....

Besides, to answer your comments for my last post, mathematically speaking, there should be only 1 possibility to draw 3 circles touching each of the others. Therefore, given any 3 points, there should be only 1 result. 

I haven't get to the point to solve how to avoid concentrations result of the circles after many iterations. However, if it doesn't make the script much more complicated, I would like to try out if the square(the boundary) is rotated/extended according to a certain rule each time after making 3 new points and in a way to create an intricate network.... : )  


Assignment 01B

assignment 01b-1

Sunday, May 17, 2009

homework

Assignment 01B

Question:
How to find out the point which is tangent to the other circle in this case?

First Assignement ::: Relationship between 2D & 3D

Recurcive square ($iteration=10, $angle=15, $offset=2)
Recurcive square ($iteration=10, $angle=15, $offset=2)

Recurcive square ($iteration=10, $angle=15, $offset=0.2)

Recurcive square ($iteration=15, $angle=33, $offset=0.2)
Recurcive square ($iteration=8, $angle=75, $offset=0.2)



import maya.cmds as cmds

cmds.select(all=True)
cmds.delete()


def recursivesquares(iteration, angle, offset):
rotationpoint = [0,0,0]
for i in range (0, iteration, 1):

cmds.nurbsSquare(n="nurbsSquare%d" %i, sl1=10, sl2=10, c=rotationpoint, nry=1, nrz=0)
cmds.select("topnurbsSquare%d" %i)

cmds.select("nurbsSquare%d" %i)
cmds.rotate(i*angle, i*angle, i*angle, pivot=(rotationpoint))

top = 'topnurbsSquare%d' %i
topposition = cmds.pointPosition('topnurbsSquare%d.cv[0]' %i, world=True)
left = 'leftnurbsSquare%d' %i
leftposition = cmds.pointPosition('leftnurbsSquare%d.cv[0]' %i, world=True)
bottom = 'bottomnurbsSquare%d' %i
bottomposition = cmds.pointPosition('bottomnurbsSquare%d.cv[0]' %i, world=True)
right = 'rightnurbsSquare%d' %i
rightposition = cmds.pointPosition('rightnurbsSquare%d.cv[0]' %i, world=True)

cmds.squareSurface(top, right, bottom, left, n='nurbsSurface%d'%i, ct1=1, ct2=1, ct3=1, ct4=1, po=0)
rotationpoint = cmds.pointOnSurface('nurbsSurface%d'%i, u=offset, v=offset, position=True)
cmds.spaceLocator(p=rotationpoint, n="locator%d" %i)
cmds.delete('nurbsSurface%d'%i)

cmds.delete('nurbsSquare%d' %i)
cmds.curve(n='topviewnurbsSquare%d' %i, d=1, p=[(topposition[0], topposition[1], 0),(leftposition[0], leftposition[1], 0),(bottomposition[0], bottomposition[1], 0),(rightposition[0], rightposition[1], 0), (topposition[0], topposition[1], 0)] )
cmds.curve(n='frontviewnurbsSquare%d' %i, d=1, p=[(topposition[0], 0, topposition[2]),(leftposition[0], 0, leftposition[2]),(bottomposition[0], 0, bottomposition[2]),(rightposition[0], 0, rightposition[2]), (topposition[0], 0, topposition[2])] )
cmds.curve(n='sideviewnurbsSquare%d' %i, d=1, p=[(0, topposition[1], topposition[2]),(0, leftposition[1], leftposition[2]),(0, bottomposition[1], bottomposition[2]),(0, rightposition[1], rightposition[2]), (0, topposition[1], topposition[2])] )

group = cmds.group('topviewnurbsSquare%d' %i, 'frontviewnurbsSquare%d' %i, 'sideviewnurbsSquare%d' %i, 'locator%d' %i, n='Squares%d' %i)

recursivesquares(10,15,0.9)

Thursday, May 14, 2009

Assignment 01B

Now it is time to start scripting your idea. Don’t worry about making it perfect, just start simple and small and go step-by-step. Simplification is the key. Here some guidelines:

  • Make your diagrams and logic (Assignment 01A) very clear. Divide the script into smaller tasks to check which tasks you know and which you don’t know how to perform
  • Define initial condition for your function to work. If it is very clear, you know that after you reach the initial condition again, you can run your function one more time. That’s where the recursion is.
  • Define a clear final condition
  • Make one iteration of your function work and only then make it recursive
  • If you reach a point where you can’t proceed, either look for help on the web, or post your progress on the blog, so I can make some comments

Please, post your progress by Sunday (17.05) morning on the blog, as I need time to take a look at it and prepare for the class on Monday, to be able to help you.

Don’t forget to post and updated diagram and logic if you changed it or developed further. We need to understand what you want to achieve!

If you manage the whole script by Sunday, great. If not, please make sure you tried really hard!

Assignment 01B – Help Functions

For the completion of Assignment 01, I prepared some small help functions and procedures to help you out in the process of scripting. They are based on things I observed on most submissions. They are not intended to provide ready solutions, but to offer some hints. Therefore they might seem a bit random and out of context. Any help you need to use them, please post on the comments.

gsii_A01_helpFunctions.py

The serpentine() function

We started the script by defining the main logic behind it, according to the diagrams posted last week.

# Basic logic
# 1) create an initial square (4 sides)
# 2) loop thorugh the sides:
# 2.1) get current line (line1)
# 2.2) get next line (line2)
# 2.3) define the percentages
# 2.4) find the point on curve
# 2.5) connect these points
# 3) After finished, select all 4 new lines and run again


As we see by this logic, what we need to run the loop each time is 4 curves through which we will loop and generate a new set of 4 lines. You can notice that as soon as we reach the initial condition, we can run the whole loop again (3): this is where recursion comes in handy.



#creating initial square
initialSquare = cmds.nurbsSquare( sl1=10, sl2=10 )
isSides = cmds.filterExpand(sm=9)
print isSides


This is how we start everything. With this command we have the 4 initial curve which make our connection loop work. Most important is that, by the way Maya created a nurbsSquare, all curves are selected in the right order on which they compose the square.



#lets connect line after line in a loop
for i in range(0, len(isSides), 1):
print i
#get the name of the current line
line1 = isSides[i]
#get the name of the following line
#but first check if we are already on the last line
#because then we have to pick back the first line
if i == len(isSides)-1:
#this means it is in the last element
#so we have to get the first curve
line2 = isSides[0]
else:
#otherwise, get next curve
line2 = isSides[i+1]

print line1, line2 #to check the line pair
#define the percentages on which to connect the lines
#this could be defined before the loop, because it is fixed
#but in case we wanted to make it variable, we need to
#define them here
perc1 = 1./2
perc2 = 1./3
#get the coordinates on the lines on the percentages
poc1 = cmds.pointOnCurve( line1, pr=perc1, top=True, p=True )
poc2 = cmds.pointOnCurve( line2, pr=perc2, top=True, p=True )
#create the curve to connect both lines
cmds.curve(ep=(poc1, poc2), d=1)


This is the basic main loop we need. Having a set of four consecutive curves selected, it works by going through each one of them and connecting them with a straight line from certain points in each line (define by percentages). By the end of this loop, we have 4 new curves, which we can use to feed the next iteration of the function.



To convert this basic part into a recursive function, we just need some small adjustments. The most important is the if/else statement after the loop which checks for the final condition. This ensures us the loop will not be infinite, and that the function will call itself again in case the end condition is still not met, creating the recursive effect we need.



#turning this into a recursive function
def serpentine(iterations):
#we assume that 4 lines are selected on stage
#and that these lines are in correct order
#this is the initial condition for the loop to work
isSides = cmds.filterExpand(sm=9)
#create a group to store the new lines
#in the end all we need is to select the group
#and we'll have the condition to run the function again
group = cmds.group( n="newCurves", em=True )
#loop through the curves in isSides
for i in range(0, len(isSides),1):
#get first curve name
line1 = isSides[i]
#get second curve name
if i == len(isSides)-1:
#this means it is in the last element
#so I have to get the first
line2 = isSides[0]
else:
#otherwise, get next element
line2 = isSides[i+1]
#print to check the pair
print line1, line2
#define the percentages
perc1 = 1./2
perc2 = 1./3
#get the coordinates on the lines
poc1 = cmds.pointOnCurve( line1, pr=perc1, top=True, p=True )
poc2 = cmds.pointOnCurve( line2, pr=perc2, top=True, p=True )
#create the curve
crv = cmds.curve( ep=(poc1, poc2), d=1 )
#put the curve in the group
cmds.parent( crv, group )

## now the recursive part
#check for the final condition
if iterations == 0:
#finished stop!
return "Done."
else:
#did not finish yet...
#remove one unit form iterations
#(coutdown)
iterations –= 1
#select the group
cmds.select( group, r=True )
#call the function again
serpentine( iterations )

Now, all you need is to create an initial square on stage, select it, and run the function, passing as a parameter the number of iterations you want it to perform.

Week 02 - recap

Last Monday we translated the rules from the Serpentine Pavilion to a full working script. In it, you saw how to find points in a curve, how to turn an initial loop into a recursive function, and how to create workaround for the lack of full 2D drafting support in Maya.

Also, we reviewed your submissions for assignment 01A (all comments are on the blog, under each post).

As a continuation of the assignment, you should give the first go at scripting your idea, keeping in mind the comments made, and what you should improve. Some of you should post new diagrams showing the improved logic of your script, according to the comments.