Skip to content

Instantly share code, notes, and snippets.

@Eterea
Last active August 29, 2015 14:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Eterea/9db4783a083b1d4d3614 to your computer and use it in GitHub Desktop.
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
#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