Useful functions to manage coordinates. Some things are for MODO, but others are absolutely common to any app
#python | |
# ---------------------------------------------------------------------------------------------------------------------- | |
# NAME: etr_usefulCoordsFunctions.py | |
# VERS: Version 1.1 | |
# DATE: October 29, 2014 | |
# | |
# MADE: Cristobal Vila, etereaestudios.com | |
# | |
# USES: Useful functions to manage coordinates. Some things are for MODO, but others are absolutely common to any app | |
# ---------------------------------------------------------------------------------------------------------------------- | |
# Query the Absolute World Position for a given vert | |
def fn_abs(vert): | |
return lx.evalN('query layerservice vert.wpos ? %s' % vert) | |
# Detect the sign of a number, returning -1 or +1 | |
def fn_sign(number): | |
return cmp(number, 0) | |
# Convert Degrees to Radians | |
def fn_deg2rad(deg): | |
return deg/57.2957795131 | |
# Convert Radians to Degrees | |
def fn_rad2deg(rad): | |
return rad*57.2957795131 | |
# Substract two coordinates pos1-pos2 (useful to calculate Relative Position from 1 to 2) | |
def fn_subtract(pos1, pos2): | |
return [i-j for i, j in zip(pos1, pos2)] | |
# Add two coordinates pos1+pos2 (useful to revert 1 to Absolute Position from Relative in respect to 2) | |
def fn_add(pos1, pos2): | |
return [i+j for i, j in zip(pos1, pos2)] | |
# Multiply our position coordinates by a given value | |
def fn_multiply(value, pos): | |
return [i*value for i in pos] | |
# Calculate Distance for a Vector (or Point to origin) using Pythagoras Theorem | |
def fn_vectorDist(vect): | |
return math.sqrt(vect[0]**2 + vect[1]**2 + vect[2]**2) | |
# Calculate Distance between two points positions using Pythagoras Theorem | |
def fn_distance(pos1, pos2): | |
distX = pos1[0] - pos2[0] | |
distY = pos1[1] - pos2[1] | |
distZ = pos1[2] - pos2[2] | |
return math.sqrt(distX**2 + distY**2 + distZ**2) | |
# Calculate the Unit Vector between 2 points, using absolute coordinates | |
def fn_unitVect(pos1, pos2): | |
subt = fn_subtract(pos2, pos1) | |
dist = fn_distance(pos2, pos1) | |
return [i/dist for i in subt] | |
# Normalize a Vector | |
def fn_normalize(vect): | |
dist = math.sqrt(vect[0]**2 + vect[1]**2 + vect[2]**2) | |
return [i/dist for i in vect] | |
# Calculate the Normal Vector to a triangle formed by 3 verts, using absolute coordinates | |
# Big thanks to Luis Randez for helping to improve this one | |
def fn_normVect(pos1, pos2, pos3): | |
vA = fn_unitVect(pos1, pos2) | |
vB = fn_unitVect(pos2, pos3) | |
signo = cmp(vA[0]*vB[1] - vA[1]*vB[0], 0) | |
return fn_multiply(signo, [vA[1]*vB[2] - vA[2]*vB[1], vA[2]*vB[0] - vA[0]*vB[2], vA[0]*vB[1] - vA[1]*vB[0]]) | |
# Average two vectors, and normalize result | |
def fn_average(vect1, vect2): | |
sumVects = fn_add(vect1, vect2) | |
return fn_normalize(sumVects) | |
# Calculate Dot Product (Scalar Product) between two vectors | |
def fn_dotProduct(vect1, vect2): | |
return sum(i*j for i, j in zip(vect1, vect2)) | |
# Change position for a selected vert using new pos coordinates ('false true' is for Absolute Position) | |
def fn_vertSetPosition(vert, pos): | |
lx.eval('select.element %s vertex set %s' % (currentLayer, vert)) | |
lx.eval('vert.set x %s false true' % pos[0]) | |
lx.eval('vert.set y %s false true' % pos[1]) | |
lx.eval('vert.set z %s false true' % pos[2]) | |
# ---------------------------------------------------------------------------------------------------------------------- | |
# Calculate position for a D point to form an planar Isosceles Trapezoid with 3 given ABC points | |
# Big thanks to my friend Albert Alomar for his great help with this | |
# ---------------------------------------------------------------------------------------------------------------------- | |
def fn_isoTrapezoid_align(vertA, vertB, vertC, vertD): | |
absA = fn_abs(vertA) | |
absB = fn_abs(vertB) | |
absC = fn_abs(vertC) | |
vectorBA = fn_subtract(absA, absB) | |
vectorBC = fn_subtract(absC, absB) | |
lenBC = fn_vectorDist(vectorBC) | |
normVectBA = fn_normalize(vectorBA) | |
normVectBC = fn_normalize(vectorBC) | |
angleB = math.acos(fn_dotProduct(normVectBA, normVectBC)) | |
modBCproy = lenBC * math.cos(angleB) | |
# We finally need to calculate: D = A + C - B - (2 * modBCproy * normVectBA) | |
# Lets do this in two steps | |
# 1. First we will calculate: M = 2 * modBCproy * normVectBA | |
M = [i*modBCproy*2 for i in normVectBA] | |
# 2. Now we can calculate: A + C - B - M | |
absD = [h+i-j-k for h, i, j, k in zip(absA, absC, absB, M)] | |
fn_vertSetPosition(vertD, absD) | |
# ---------------------------------------------------------------------------------------------------------------------- | |
# Calculate position for a D point to be aligned with AC and at 1/3 distance from A | |
# ---------------------------------------------------------------------------------------------------------------------- | |
def fn_triangle_align(vertA, vertC, vertD): | |
absA = fn_abs(vertA) | |
absC = fn_abs(vertC) | |
relCA = fn_subtract(absC, absA) | |
relCAmul = fn_multiply(0.333333333333, relCA) | |
absD = fn_add(relCAmul, absA) | |
fn_vertSetPosition(vertD, absD) | |
# ---------------------------------------------------------------------------------------------------------------------- | |
# Calculate the Unit Vector Direction for each X, Y, Z axis on a Rotated Workplane | |
# Thanks to Dongju for this: http://community.thefoundry.co.uk/discussion/topic.aspx?f=119&t=93337 | |
# ---------------------------------------------------------------------------------------------------------------------- | |
def fn_wplaneAxis_toVect(axis): | |
# Determine X,Y,Z angles for your workplane | |
wpRX = lx.eval('workPlane.edit rotX:?') | |
wpRY = lx.eval('workPlane.edit rotY:?') | |
wpRZ = lx.eval('workPlane.edit rotZ:?') | |
# Store both Sin and Cos for each value | |
cx = math.cos(wpRX) | |
sx = math.sin(wpRX) | |
cy = math.cos(wpRY) | |
sy = math.sin(wpRY) | |
cz = math.cos(wpRZ) | |
sz = math.sin(wpRZ) | |
# Apply the magical rotation matrix | |
if axis == 'x': | |
return [-sy*sx*sz + cy*cz, sy*sx*cz + cy*sz, -sy*cx] | |
elif axis == 'y': | |
return [-cx*sz, cx*cz, sx] | |
elif axis == 'z': | |
return [cy*sx*sz + sy*cz, sy*sz - cy*sx*cz, cy*cx] | |
# ---------------------------------------------------------------------------------------------------------------------- | |
# Rotate vert P a predefined angle around vert C, using a vector normal as axis direction | |
# Based on "Rotate a point about an arbitrary axis (3 dimensions)" by Paul Burke and Bruce Vaughan | |
# http://paulbourke.net/geometry/rotate/ | |
# ---------------------------------------------------------------------------------------------------------------------- | |
def fn_pointRotate3D(absP, absC, axis, angle): | |
# Calculate coordinates of P relatives to C | |
PR = fn_subtract(absP, absC) | |
# Factors for matrix operations | |
c = cos(angle) | |
t = (1-c) | |
s = sin(angle) | |
x = axis[0] | |
y = axis[1] | |
z = axis[2] | |
# Define matrix 'M' | |
D11 = t*x**2 + c | |
D12 = t*x*y - s*z | |
D13 = t*x*z + s*y | |
D21 = t*x*y + s*z | |
D22 = t*y**2 + c | |
D23 = t*y*z - s*x | |
D31 = t*x*z - s*y | |
D32 = t*y*z + s*x | |
D33 = t*z**2 + c | |
# |PR[0]| | |
# Calculate 'M'*|PR[1]| | |
# |PR[2]| | |
R0 = D11*PR[0] + D12*PR[1] + D13*PR[2] | |
R1 = D21*PR[0] + D22*PR[1] + D23*PR[2] | |
R2 = D31*PR[0] + D32*PR[1] + D33*PR[2] | |
# Determine the new relative coordinates for P --> R | |
R = [R0, R1, R2] | |
# Convert relative coords to absolute ones | |
return fn_add(R, absC) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment