Maya Variable Concatenation - python

Having a few problems basically inserting a bunch of flags generated by a loop:
def drawHelix(radius, length, coils):
numPoints = int(8)
degrees = float((360 / numPoints))
centerX = float(0)
centerZ = float(0)
xLoc = float(0)
zLoc = float(0)
yLoc = float(0)
yOffset = float(((length / coils) / numPoints))
vectorIndex = int(0)
pointStr = ""
knotStr = ""
for i in range(1, (360 * coils), 20):
t = i + degrees
xLoc = centerX + (math.cos(t) * radius)
zLoc = centerZ - (math.sin(t) * radius)
pointStr = (pointStr + " p=(" + str(xLoc) + "," + str(yLoc) + "," + str(zLoc) + "),")
knotStr = (knotStr + "k=(" + str(vectorIndex) + ")")
vectorIndex = i + 1
yLoc = yLoc + yOffset
print pointStr
spiral = cmds.curve(d=float(1.0), pointStr, knotStr)
cmds.rebuildCurve (spiral, ch=1, rpo=1, rt=0, end=1, kr=1, kcp=0, kep=0, kt=0, s=0, d=3, tol=0.001)
return spiral
Which I then run with: drawHelix (2.00, 3.00, 5.00)
The problem is that Maya doesn't recognise the "pointStr" as a flag for the curve command, when I print pointStr it does give me exactly what I want, but struggling on how to actually make this work!

The Python interpreter will not expand your strings before calling the function (you could achieve this using eval but this is generally considered bad practice -- see this post on SO).
It should work when passing the arguments as a dict of keywords.
Look it up here:
Section 4.7 More on Defining Functions in the Official Python Tutorial
PEP 3102 Keyword-Only Arguments
Section 5.3.4 Calls in the Python Reference Manual
So instead of:
pointStr = (pointStr + " p=(" + str(xLoc) + "," + str(yLoc) + "," + str(zLoc) + "),")
knotStr = (knotStr + "k=(" + str(vectorIndex) + ")")
You should do
kwargs['d'] = 1.0
kwargs['p'] = []
for i in range(1, (360 * coils), 20):
...
kwargs['p'].append((xloc, yloc, zloc))
kwargs['k'].append(vectorIndex)
spiral = cmds.curve(**kwargs)
Apart from that there are a few other issues in your code:
float((360 / numPoints)) will evaluate differently in Python2.x and Python3.x. This is what happens in 2.x:
In [5]: float(7 / 6)
Out[5]: 1.0
In [6]: 7. / 6
Out[6]: 1.1666666666666667
In If you wanted to ensure that floating point division is performed in your case use degrees = 360. / numPoints.
The potential implications are worse in this line of your code: yOffset = float(((length / coils) / numPoints)).
You declare float and int constants just by writing them either with or without a decimal point. No need to wrap them in a call to float() or int()

I assume this is what you had in mind:
from maya import cmds
import math
def drawHelix(radius, length, coils):
numPoints = int(8)
degrees = float((360 / numPoints))
centerX = float(0)
centerZ = float(0)
xLoc = float(0)
zLoc = float(0)
yLoc = float(0)
yOffset = float(((length / float(coils)) / float(numPoints)))
vectorIndex = int(0)
pointStr = []
knotStr = []
yLoc = 0
for i in range(1, (360 * coils), 20):
t = i + degrees
xLoc = centerX + (math.cos(t) * radius)
zLoc = centerZ - (math.sin(t) * radius)
pointStr.append((xLoc, yLoc,zLoc))
knotStr.append(vectorIndex)
vectorIndex = i + 1
yLoc = yLoc + yOffset
print pointStr
spiral = cmds.curve(p= pointStr, k=knotStr,d=float(1.0))
cmds.rebuildCurve (spiral, ch=1, rpo=1,
rt=0, end=1, kr=1, kcp=0, kep=0,
kt=0, s=0, d=3, tol=0.001)
return spiral
There is just a way much better way to do this. This is how your supposed to use Maya, use nodes to build your stuff. So here goes, a unnecessarily commented and verbose version:
from maya import cmds
def getHistoryShape(name):
history = cmds.listHistory(name)
filteredShape = cmds.ls(history, shapes=1)[0]
return filteredShape
def drawHelix(radius, length, coils):
cyl = cmds.cylinder( ch=True, radius=radius, ax=(0,1,0),
hr=float(length)/float(radius) )
# build a curve on the cylinders surface
crv = cmds.curveOnSurface(cyl[0], d=1,
uv=[(0,0),(length, coils*4)],
k=[0,1])
# make a duplicate that is visible
crv = cmds.duplicateCurve(ch=1, rn=0, local=1)
# tell maya to ignore the cylinder as a piece of geometry
shape = getHistoryShape(cyl[0])
cmds.setAttr(shape+'.intermediateObject', 1)
cmds.rename(cyl[0],'helix1')
return crv
Now you can change the helixes parameters later, live. You could expose the parameters radius, length and coils for the user, so they can be animated. See Maya factory scripts for example.

Related

OpenScad - How to find Robotic Arm Nodes Coordinates after Rotations - 5 axis

I found the coordinates of 2 nodes out of 3. I need to find the last coordinate, that of the aqua colored sphere. Here is my code. Can someone help me?
Thanks
Enable Animation to view it in moviment - FPS:30 STEPS:300
Modules
module spalla(){
translate([0,-50,0])
rotate([0,90,0]){
rotate([-90,0,0]){
cylinder(50,50,40,true,$fn=6);
difference(){
union(){
translate([0,-20,50])cube([50,10,50],true);
translate([0,20,50])cube([50,10,50],true);
}
translate([0,0,50])rotate([90,0,0])cylinder(100,10,10,true);
}
}
translate([0,50,0])rotate([0,0,A1ROT])braccio();
}
}
module braccio(){
translate([A1LEN/2,0,0])cube([A1LEN,30,30],true);
translate([A1LEN,0,0])rotate([360-A21ROT,0,0])rotate([0,0,A22ROT])avambraccio();
}
module avambraccio(){
translate([A2LEN/2,0,0])color("red")cube([A2LEN,30,30],true);
translate([A2LEN,0,0])color("aqua")sphere(30);
}
Function to rotate point
Note: depending of your Openscad coordinate system it may be necessary to permute the parameters of the function.
function rotate3d(pitch, roll, yaw,point) = let(
function rotate3d(roll, pitch, yaw,point) = let(
function rotate3d(pitch, roll, yaw,point) = let(
cosa = cos(yaw),
sina = sin(yaw),
cosb = cos(pitch),
sinb = sin(pitch),
cosc = cos(roll),
sinc = sin(roll),
Axx = cosa*cosb,
Axy = cosa*sinb*sinc - sina*cosc,
Axz = cosa*sinb*cosc + sina*sinc,
Ayx = sina*cosb,
Ayy = sina*sinb*sinc + cosa*cosc,
Ayz = sina*sinb*cosc - cosa*sinc,
Azx = -sinb,
Azy = cosb*sinc,
Azz = cosb*cosc,
px = point[0],
py = point[1],
pz = point[2],
rx = Axx*px + Axy*py + Axz*pz,
ry = Ayx*px + Ayy*py + Ayz*pz,
rz = Azx*px + Azy*py + Azz*pz
)[rx,ry,rz];
Functions to get positions coordinates of the arm nodes
RSGetPos Get position of Right Shoulder
LSGetPos Get position of Left Shoulder
RA1GetPos Get position of Right Arm part 1 (green color)
LA1GetPos Get position of Left Arm part 1 (green color)
*** The features I miss ***
RA2GetPos Get position of Right Arm part 2 (red color) i need coords of aqua color sphere
LA2GetPos Get position of Left Arm part 2 (red color) i need coords of aqua color sphere
function RSGetPos() = [cos(SROTZ)*SWIDE/2,sin(SROTZ)*SWIDE/2,0];
function LSGetPos() = [cos(SROTZ+180)*SWIDE/2,sin(SROTZ+180)*SWIDE/2,0];
function RA1GetPos() = rotate3d( 0, SROT, SROTZ, rotate3d(-A1ROT,0,0,[0,0,-A1LEN])+[SWIDE/2,0,0]);
function LA1GetPos() = rotate3d( 0, SROT, SROTZ, rotate3d(A1ROT,0,0,[0,0,-A1LEN])+[-SWIDE/2,0,0]);
Calling functions to get coordinaets of nodes and draw the nodes
color("red",0.5)translate(LSGetPos()){
sphere(50);
translate([-100,0,0])rotate($vpr) text(str(LSGetPos()),50);
}
color("blue",0.5)translate(LA1GetPos()){
sphere(50);
translate([-100,0,0])rotate($vpr) text(str(LA1GetPos()),50);
}
//color("red",0.5)translate(RSGetPos()){sphere(50);rotate($vpr)text(str(RSGetPos()),130);}
//color("blue",0.5)translate(RA1GetPos()){sphere(50);rotate($vpr)text(str(RA1GetPos()),130);}
Dimensions of the Arm parts
A1LEN=300; //The length of A1 green part of the arm.
A2LEN=200; //The length of A2 red part of the arm.
SWIDE=400; //Width of Shoulders
5 input rotations - look at the Drawing i have posted as refer
SROTZ = sin($t*360*2)*45;
SROT = sin($t*360*4)*45+45;
A1ROT = sin($t*360*2)*45+45;
A21ROT = sin($t*360*2)*45+45;
A22ROT = sin($t*360*2)*45+45;
/*
SROTZ =0;
SROT =0;
A1ROT =0;
A21ROT=0;
A22ROT=0;
*/
Calling the main module
rotate([0,0,SROTZ]){
translate([SWIDE/2,0,0])rotate([0,0,-90])rotate([0,SROT,0])spalla();
translate([-SWIDE/2,0,0])mirror([0,1,0])rotate([0,0,90])rotate([0,SROT,0])spalla();
}
This is my answers to my question, with some simplification.
function rotate3d(rot,point) = let(
roll = rot[0] ,
pitch= rot[1] ,
yaw = rot[2],
cosa = cos(yaw),
sina = sin(yaw),
cosb = cos(pitch),
sinb = sin(pitch),
cosc = cos(roll),
sinc = sin(roll),
Axx = cosa*cosb,
Axy = cosa*sinb*sinc - sina*cosc,
Axz = cosa*sinb*cosc + sina*sinc,
Ayx = sina*cosb,
Ayy = sina*sinb*sinc + cosa*cosc,
Ayz = sina*sinb*cosc - cosa*sinc,
Azx = -sinb,
Azy = cosb*sinc,
Azz = cosb*cosc,
px = point[0],
py = point[1],
pz = point[2],
rx = Axx*px + Axy*py + Axz*pz,
ry = Ayx*px + Ayy*py + Ayz*pz,
rz = Azx*px + Azy*py + Azz*pz
)[rx,ry,rz];
module draw(p,r=10){
translate(p) sphere(r);
color( "blue" ,1)translate(p) rotate($vpr)text(str(p),40);
}
len1=75;
len2=150;
len3=180;
/*
rot1=[0,-45,10];
rot2=[0,-90,0];
rot3=[0,145,0];
*/
rot1=[0,sin($t*360*2)*100,sin($t*360)*100];
rot2=[0,sin($t*360)*100,0];
rot3=[0,sin($t*360*2)*100,0];
size1=[len1,30,30];
size2=[len2,30,30];
size3=[len3,30,30];
module m1(){ translate([len1/2,0,0])color("red")cube(size1 ,true);translate([len1,0,0])rotate(rot2)m2();}
module m2(){ translate([len2/2,0,0])color("green")cube(size2,true);translate([len2,0,0])rotate(rot3)m3();}
module m3(){ translate([len3/2,0,0])color("pink")cube(size3,true);translate([len3,0,0]); }
init1=[len1,0,0];
init2=[len2,0,0];
init3=[len3,0,0];
rp1=rotate3d(rot1,init1);
rp2=rotate3d(rot1+rot2,init2)+rp1;
rp3=rotate3d(rot1+rot2+rot3,init3)+rp2;
tr=[100,0,0];
rx=[sin($t*360)*100,0,sin($t*360)*100];
xrp1=rotate3d(rx,rp1)+tr;
xrp2=rotate3d(rx,rp2)+tr;
xrp3=rotate3d(rx,rp3)+tr;
draw(xrp1,20);
draw(xrp2,20);
draw(xrp3,20);
translate(tr)rotate(rx)rotate(rot1)m1();

Cubic Equations in Python

Using the formula from https://engineersfield.com/cubic-equation-formula/:
class CubicEquation():
def __init__(self,a,b,c,d):
'''initialize constants and formula'''
q = (3*c - b**2) / 9
r = -27*d + b*(9*c - 2*b**2)
discriminant = q**3 + r**2
s = r + sqrt(discriminant)
t = r - sqrt(discriminant)
term1 = sqrt(3 * ((-t + s) / 2))
r13 = 2 * sqrt(q)
self.cubic_equation = [\
'-term1 + r13*cos(q**3 / 3)',\
'-term1 + r13*cos(q**3 + (2 * pi)/3)',\
'-term1 + r13*cos(q**3 + (4 * pi)/3)'\
]
def solve(self):
*--snip--*
and then later calling it with answer = eval(self.cubic_equation[index])
when calling this formula with args (1,1,1,1), I receive the solution:
-6.803217085397121, -8.226355957420402, -8.208435953185608
and yes I have triple-checked my formulas with those on the site.
What is the correct code for this function, and what went wrong with my current program?

FontForge Python extension: Can't get gsub_multiple lookup to work

I'm experimenting with the fontforge Python library/wrapper thing and I don't seem to get multiple character substitution to work.
Maybe you gals and guys could help to point me at what I'm doing wrong?
Basically, I'm trying to replace "ABC" with the character representation of "a", but I'm going to extend that with proper subsitutions once this is working.
from random import randint
from datetime import datetime
def add_pixel(pen, x, y, scale = 100):
pen.moveTo(((x + 0) * scale, (y + 0) * scale))
pen.lineTo(((x + 0) * scale, (y + 1) * scale))
pen.lineTo(((x + 1) * scale, (y + 1) * scale))
pen.lineTo(((x + 1) * scale, (y + 0) * scale))
pen.closePath()
def add_character(font, code, name):
if not name in list(font):
font.createChar(code, name)
pen = font[code].glyphPen()
for i in range(1, 15):
add_pixel(pen, randint(0, 15), randint(0, 15), 100 * 10 / 15)
try:
import fontforge
except Exception, e:
raise
else:
font = fontforge.font()
font.familyname = "font"
font.fontname = "font x15"
font.fullname = "font x15"
font.version = datetime.now().strftime("%Y-%m-%d %H:%M")
# lower
for c in range(0x61, 0x61 + 26):
add_character(font, c, unichr(c))
# upper
for c in range(0x41, 0x41 + 26):
add_character(font, c, unichr(c))
font.addLookup("gsub", "gsub_multiple", (), (("dlig",(("latn",("dflt")),)),))
font.addLookupSubtable("gsub", "gsub_n")
glyph = font["a"]
glyph.addPosSub("gsub_n", ("A", "B", "C"))
# font.save("font.x15.sfd")
font.generate("font.x15.otf", flags=("PfEd-lookups", "opentype"))
finally:
pass
I think your lookup type doens't match the feature.
# Try "gsub_ligature" as type.
font.addLookup("gsub", "gsub_ligature", (), (("dlig",(("latn",("dflt")),)),))
Tip: You can inspect your features by generating a feature file:
font.generateFeatureFile("features.fea")

Perspective projection and rotation in python

I've tried searching but none of the other questions seem to be like mine. I'm more or less experimenting with perspective projection and rotation in python, and have run into a snag. I'm sure my projection equations are accurate, as well as my rotation equations; however, when I run it, the rotation starts normal, but begins to swirl inwards until the vector is in the same position as the Z axis (the axis I am rotating over).
''' Imports '''
from tkinter import Tk, Canvas, TclError
from threading import Thread
from math import cos, sin, radians, ceil
from time import sleep
''' Points class '''
class pPoint:
def __init__(self, fPoint, wWC, wHC):
self.X = 0
self.Y = 0
self.Z = 0
self.xP = 0
self.yP = 0
self.fPoint = fPoint
self.wWC = wWC
self.wHC = wHC
def pProject(self):
self.xP = (self.fPoint * (self.X + self.wWC)) / (self.fPoint + self.Z)
self.yP = (self.fPoint * (self.Y + self.wHC)) / (self.fPoint + self.Z)
''' Main class '''
class Main:
def __init__(self):
''' Declarations '''
self.wWidth = 640
self.wHeight = 480
self.fPoint = 256
''' Generated declarations '''
self.wWC = self.wWidth / 2
self.wHC = self.wHeight / 2
''' Misc declarations '''
self.gWin = Tk()
self.vPoint = pPoint(self.fPoint, self.wWC, self.wHC)
self.vPoint.X = 50
self.vPoint.Y = 60
self.vPoint.Z = -25
self.vPoint.pProject()
self.ang = 0
def initWindow(self):
self.gWin.minsize(self.wWidth, self.wHeight)
self.gWin.maxsize(self.wWidth, self.wHeight)
''' Create canvas '''
self.gCan = Canvas(self.gWin, width = self.wWidth, height = self.wHeight, background = "black")
self.gCan.pack()
def setAxis(self):
''' Create axis points '''
self.pXax = pPoint(self.fPoint, self.wWC, self.wHC)
self.pXbx = pPoint(self.fPoint, self.wWC, self.wHC)
self.pYax = pPoint(self.fPoint, self.wWC, self.wHC)
self.pYbx = pPoint(self.fPoint, self.wWC, self.wHC)
self.pZax = pPoint(self.fPoint, self.wWC, self.wHC)
self.pZbx = pPoint(self.fPoint, self.wWC, self.wHC)
''' Set axis points '''
self.pXax.X = -(self.wWC)
self.pXax.Y = 0
self.pXax.Z = 1
self.pXbx.X = self.wWC
self.pXbx.Y = 0
self.pXbx.Z = 1
self.pYax.X = 0
self.pYax.Y = -(self.wHC)
self.pYax.Z = 1
self.pYbx.X = 0
self.pYbx.Y = self.wHC
self.pYbx.Z = 1
self.pZax.X = 0
self.pZax.Y = 0
self.pZax.Z = -(self.fPoint) / 2
self.pZbx.X = 0
self.pZbx.Y = 0
self.pZbx.Z = (self.fPoint * self.wWC) - self.fPoint
def projAxis(self):
''' Project the axis '''
self.pXax.pProject()
self.pXbx.pProject()
self.pYax.pProject()
self.pYbx.pProject()
self.pZax.pProject()
self.pZbx.pProject()
def drawAxis(self):
''' Draw the axis '''
self.gCan.create_line(self.pXax.xP, self.pXax.yP, self.pXbx.xP, self.pXbx.yP, fill = "white")
self.gCan.create_line(self.pYax.xP, self.pYax.yP, self.pYbx.xP, self.pYbx.yP, fill = "white")
self.gCan.create_line(self.pZax.xP, self.pZax.yP, self.pZbx.xP, self.pZbx.yP, fill = "white")
def prePaint(self):
self.vA = self.gCan.create_line(self.wWC, self.wHC, self.vPoint.xP, self.vPoint.yP, fill = "red")
def paintCanvas(self):
try:
while True:
self.ang += 1
if self.ang >= 361:
self.ang = 0
self.vPoint.X = (self.vPoint.X * cos(radians(self.ang))) - (self.vPoint.Y * sin(radians(self.ang)))
self.vPoint.Y = (self.vPoint.X * sin(radians(self.ang))) + (self.vPoint.Y * cos(radians(self.ang)))
self.vPoint.pProject()
self.gCan.coords(self.vA, self.wWC, self.wHC, self.vPoint.xP, self.vPoint.yP)
self.gWin.update_idletasks()
self.gWin.update()
sleep(0.1)
except TclError:
pass
mMain = Main()
mMain.initWindow()
mMain.setAxis()
mMain.projAxis()
mMain.drawAxis()
mMain.prePaint()
mMain.paintCanvas()
Thank you for any input :)
EDIT: Sorry, I just realized I forgot to put my question. I just want to know why it is gravitating inward, and not just rotating "normally"?
This section is wrong:
self.ang += 1
if self.ang >= 361:
self.ang = 0
self.vPoint.X = (self.vPoint.X * cos(radians(self.ang))
- self.vPoint.Y * sin(radians(self.ang)))
self.vPoint.Y = (self.vPoint.X * sin(radians(self.ang))
+ self.vPoint.Y * cos(radians(self.ang)))
self.vPoint.pProject()
For two reasons:
self.ang will take integers in the open range [0 - 360], which means the angle 360 (== 0) is repeated.
In each iteration, you rotate the point from the previous iteration by the angle. As a result, your first frame is at 1 degree, your second at 1+2 = 3, the third at 1 + 2 + 3... You should either be:
rotating the point from the previous iteration by a constant angle each time (1°). This suffers from the problem mentioned in my comment
rotating the initial point by the current angle of rotation each time
Not actualy related to your problem, but I strongly suggest you to use Numpy to perform geometric transformations, specially if it involves 3D points.
Below, I post a sample snippet, I hope it helps:
import numpy
from math import radians, cos, sin
## suppose you have a Nx3 cloudpoint (it might even be a single row of x,y,z coordinates)
cloudpoint = give_me_a_cloudpoint()
## this will be a rotation around Y azis:
yrot = radians(some_angle_in_degrees)
## let's create a rotation matrix using a numpy array
yrotmatrix = numpy.array([[cos(yrot), 0, -sin(yrot)],
[0, 1, 0],
[sin(yrot), 0, cos(yrot)]], dtype=float)
## apply the rotation via dot multiplication
rotatedcloud = numpy.dot(yrotmatrix, pointcloud.T).T # .T means transposition

Help with Windows Geometry in Python

Why are the commands to change the window position before and after sleep(3.00) being ignored?
if self.selectedM.get() == 'Bump':
W1 = GetSystemMetrics(1) + 200
print W1
w1.wm_geometry("+100+" + str(W1))
w2.wm_geometry("+100+" + str(W1))
w3.wm_geometry("+100+" + str(W1))
w4.wm_geometry("+100+" + str(W1))
self.rvar.set(0)
self.rvar2.set(0)
self.rvar3.set(0)
self.rvar4.set(0)
s = self.wm_geometry()
geomPatt = re.compile(r"(\d+)?x?(\d+)?([+-])(\d+)([+-])(\d+)")
m = geomPatt.search(s)
X3 = m.group(4)
Y3 = m.group(6)
M = int(Y3) - 150
P = M + 150
MH = W1
MUH = Y3
while Y3 > M:
sleep(0.0009)
Y3 = int(Y3) - 1
self.update_idletasks()
self.wm_geometry("+" + str(X3) + "+" + str(Y3))
print 1
Alpha = 1.0
#while 0.0 < Alpha :
# Alpha = Alpha - 0.01
# self.attributes("-alpha", Alpha)
# sleep(0.005)
self.wm_geometry("+" + str(X3) + "+" + str(MH))
sleep(3.00)
self.wm_geometry("+" + str(X3) + "+" + str(MUH))
#while 1.0 > Alpha :
# Alpha = Alpha + 0.01
# self.attributes("-alpha", Alpha)
# sleep(0.005)
while Y3 < P:
sleep(0.0009)
Y3 = int(Y3) + 1
self.update_idletasks()
self.wm_geometry("+" + str(X3) + "+" + str(Y3))
The answer to your question is that you don't give the system a chance to update the display. The display is updated by the event loop but you don't enter the event loop after either of the wm_geometry calls surrounding the sleep(3.00) call. They aren't being ignored, it's just that you're changing the geometry again before the system has a chance to update the display.
Does the answer to the question Having Trouble with Tkinter Transparency help you solve this problem too?

Categories