Last active
August 29, 2015 14:08
-
-
Save Eterea/9db4783a083b1d4d3614 to your computer and use it in GitHub Desktop.
Useful functions to manage coordinates. Some things are for MODO, but others are absolutely common to any app
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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