469,898 Members | 1,613 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,898 developers. It's quick & easy.

Translate in 3D

bvdet
2,851 Expert Mod 2GB
I have done some more work on a simple class I wrote to calculate a global coordinate in 3D given a local coordinate:
Expand|Select|Wrap|Line Numbers
  1. ##  Basis3D.py Version 1.02 (module macrolib.Basis3D)
  2. ##  Copyright (c) 2006 Bruce Vaughan, BV Detailing & Design, Inc.
  3. ##  All rights reserved.
  4. ##  NOT FOR SALE. The software is provided "as is" without any warranty.
  5. ############################################################################
  6. """
  7.     Class BasisTransToGlobal
  8.     Given 3 counter-clockwise non-collinear points, define an orthonormal basis in 3D space (the local basis).
  9.     Calculate the global point, a vector in the standard basis set, given a displacement vector in the local basis.
  10.     The object type of the displacement vector 'vR' is 'point'.
  11.     An instance translate method can be called:
  12.         ref_pt + instance.translate(x, y, z) --> global coordinate point object
  13.     Method 'translate' example usage:
  14.         pt = global point origin of translation to be calculated (example: mem.left.location)
  15.         a = class instance
  16.         x, y, and z are offsets from pt in the local basis
  17.         pt + a.translate(x, y, z)
  18. """
  19.  
  20. from macrolib.ExceptWarn import formatExceptionInfo
  21. from macrolib.P3D import Plane3D
  22. from param import Warning
  23. from point import Point
  24.  
  25. def chk_type(p_list):
  26.     for p in p_list:
  27.         if not isinstance(p, type(Point(0,0,0))):
  28.             return False
  29.     return True
  30.  
  31. class BasisTransToGlobal(object):
  32.     def __init__(self, vN, vA, vB, vR=Point(0,0,0)):
  33.         self.vN = vN
  34.         if chk_type([vN, vA, vB, vR]):
  35.  
  36.             # local basis aligned with instance 'a', define the plane
  37.             a = Plane3D(vN, vA, vB)
  38.  
  39.             if a.N_len > 0.0:
  40.  
  41.                 # Unit vector normal to defined plane, local basis 'Z'
  42.                 self.N = a.N_uv
  43.  
  44.                 # Unit vector between vN and vA, local basis 'X'
  45.                 self.A = a.d0
  46.  
  47.                 # Unit cross product vector, local basis 'Y'
  48.                 self.B = a.cross_product(self.N, self.A)
  49.  
  50.                 # global coordinate vector
  51.                 self.R = self.translate(vR.x, vR.y, vR.z) + vN
  52.  
  53.             else:
  54.                 Warning("The points are collinear ***INVALID***")
  55.                 self.R = None
  56.         else:
  57.             Warning("Argument type must be 'point'")
  58.             self.R = None
  59.  
  60.     def translate(self, X, Y, Z):
  61.         A, B, N = self.A, self.B, self.N
  62.         M = (X*X + Y*Y + Z*Z)**0.5
  63.         # vR normalized
  64.         if M > 0:
  65.             X1, Y1, Z1 = X/M, Y/M, Z/M
  66.         else:
  67.             X1, Y1, Z1 = 0.0, 0.0, 0.0
  68.  
  69.         D = self.determinant3(A.x, A.y, A.z, N.x, N.y, N.z, B.x, B.y, B.z)
  70.         Dx = self.determinant3(X1, A.y, A.z, Z1, N.y, N.z, Y1, B.y, B.z)
  71.         Dy = self.determinant3(A.x, X1, A.z, N.x, Z1, N.z, B.x, Y1, B.z)
  72.         Dz = self.determinant3(A.x, A.y, X1, N.x, N.y, Z1, B.x, B.y, Y1)
  73.  
  74.         # resultant unit vector R1
  75.         R1 = Point(Dx/D, Dy/D, Dz/D)
  76.  
  77.         # global coordinate vector with respect to local basis origin
  78.         return Point(R1.x*M, R1.y*M, R1.z*M)
  79.  
  80.     def determinant3(self, a,b,c,m,n,k,u,v,w):
  81.         return a*n*w + b*k*u + m*v*c - c*n*u - b*m*w - a*k*v
  82.  
  83.     def version(self):
  84.         "Basis3D.BasisTransToGlobal Version 1.02"
Here' s the test script:
Expand|Select|Wrap|Line Numbers
  1. from macrolib.Basis3D import BasisTransToGlobal
  2. def test_BasisTransToGlobal():
  3.     from macrolib.ExceptWarn import formatExceptionInfo
  4.     from macrolib.PrintPtList import formatPtList
  5.     from macrolib.PrintDict import formatDict
  6.     from param import Dialog, dim_print, Warning, ResponseNotOK, Units
  7.     from point import Point, PointLocate
  8.     import os
  9.     Units("feet")
  10.     try:
  11.         dlg1 = Dialog("Translate to Global in an Orthogonal Basis")
  12.         dlg1.group_title("Orthonormal Basis and Resultant Unit Vector")
  13.         image_path = os.path.join(os.getcwd(), "macro", "Images")
  14.         image_name = os.path.join(image_path, "Basis3D_XYZ.gif")
  15.         dlg1.image(image_name)
  16.         dlg1.group_title("Translation Vector")
  17.         dlg1.entry('distX', dim_print(60.0), "Enter translate 'X' direction")
  18.         dlg1.entry('distY', dim_print(30.0), "Enter translate 'Y' direction")
  19.         dlg1.entry('distZ', dim_print(0.0), "Enter translate 'Z' direction")
  20.         try:
  21.             dlg1.done()
  22.         except ResponseNotOK:
  23.             raise StandardError, "User Cancelled"
  24.         pt1 = PointLocate("Pick point 1 (Basis 0,0,0)")
  25.         pt2 = PointLocate("Pick point 2 (Basis 'X')")
  26.         pt3 = PointLocate("Pick point 3 to define plane")
  27.         pt4 = Point(dlg1.distX, dlg1.distY, dlg1.distZ)
  28.     except:
  29.         Warning(formatExceptionInfo())
  30.     else:
  31.         if pt1 and pt2 and pt3 and pt4:
  32.             a = BasisTransToGlobal(pt1, pt2, pt3, pt4)
  33.             if a.R:
  34.                 print formatPtList("Local Basis Origin:", [pt1, ])
  35.                 print formatPtList("Local Basis Translate Vector:", [pt4, ])
  36.                 print formatPtList("Resultant Global Point:", [a.R, ])
  37.                 print formatDict("BasisTransToGlobal Instance Dictionary:", a.__dict__)
  38.                 # print formatDict("Local Dictionary:", locals())
  39.                 print formatPtList("Resultant Global Points Calculated With Method 'translate':",
  40.                                    [pt1+a.translate(12, 12, 0), pt1+a.translate(13, 13, 0), \
  41.                                     pt1+a.translate(14, 14, -3)])
  42.  
  43. if __name__ == '__main__':
  44.     test_BasisTransToGlobal()
Test script output:
Expand|Select|Wrap|Line Numbers
  1. Local Basis Origin:
  2. X attribute         Y attribute         Z attribute         
  3. ==================================================
  4. 2-7 3/8            -2-3 1/2            1-9 15/16           
  5.  
  6. Local Basis Translate Vector:
  7. X attribute         Y attribute         Z attribute         
  8. ==================================================
  9. 5-0                 2-6                 10                  
  10.  
  11. Resultant Global Points:
  12. X attribute         Y attribute         Z attribute         
  13. ==================================================
  14. -1-3 5/8            -7-2 3/8            -7 7/8              
  15.  
  16. BasisTransToGlobal Instance Dictionary:
  17. Key = A     Value = 0, -0.623718, -0.78165
  18. Key = B     Value = 0.746515, -0.520085, 0.415003
  19. Key = N     Value = -0.665369, -0.583513, 0.465615
  20. Key = R     Value = -15.620537, -86.364783, -7.845922
  21. Key = vN    Value = -31.362292, -27.504023, 21.946829
  22.  
  23. Resultant Global Points Calculated With Method 'translate':
  24. X attribute         Y attribute         Z attribute         
  25. ==================================================
  26. -1-10 3/8           -3-5 1/4            1-5 9/16            
  27. -1-9 11/16          -3-6 3/8            1-5 3/16            
  28. -1-6 15/16          -3-5 3/4            1-3 7/16
Any comments or suggestions for improvement will be appreciated. I am planning to use this class in some of my production scripts. Thank you.

BV
Dec 19 '06 #1
9 2821
bartonc
6,596 Expert 4TB
Looks like good encapsulation of the problem space to me. Admittedly, vector math is not my strong suit, but I see a clean style here.
Dec 20 '06 #2
bvdet
2,851 Expert Mod 2GB
Looks like good encapsulation of the problem space to me. Admittedly, vector math is not my strong suit, but I see a clean style here.
Thanks Barton. I have been working on this on and off for over two months and been unable to find anything else to improve on my own. Is there a reason to derive BasisTransToGlobal from Plane3D instead of creating a Plane3D instance?

BV
Dec 20 '06 #3
bartonc
6,596 Expert 4TB
Thanks Barton. I have been working on this on and off for over two months and been unable to find anything else to improve on my own. Is there a reason to derive BasisTransToGlobal from Plane3D instead of creating a Plane3D instance?

BV
Sinse your instance (a) doesn't seem to live outside of __init__, I don't see much advantage. But let's see what it would look like and discuss it.

Expand|Select|Wrap|Line Numbers
  1. class BasisTransToGlobal(Plane3D):
  2.     def __init__(self, vN, vA, vB, vR=Point(0,0,0)):
  3.         Plane3D.__init__(self, vN, vA, vB)
  4.         self.vN = vN
  5.         if chk_type([vN, vA, vB, vR]):
  6.  
  7.             # local basis aligned with instance 'a', define the plane
  8.             # now all references to a. become self.
If Plane3D exposes vN then either self.vN collides with it or is not needed. I'd really need to know more about a Plane3D object. You probably got it right in your implementation, though. Something to think about, anyway.
Dec 20 '06 #4
bartonc
6,596 Expert 4TB
Sinse your instance (a) doesn't seem to live outside of __init__, I don't see much advantage. But let's see what it would look like and discuss it.

Expand|Select|Wrap|Line Numbers
  1. class BasisTransToGlobal(Plane3D):
  2.     def __init__(self, vN, vA, vB, vR=Point(0,0,0)):
  3.         Plane3D.__init__(self, vN, vA, vB)
  4.         self.vN = vN
  5.         if chk_type([vN, vA, vB, vR]):
  6.  
  7.             # local basis aligned with instance 'a', define the plane
  8.             # now all references to a. become self.
If Plane3D exposes vN then either self.vN collides with it or is not needed. I'd really need to know more about a Plane3D object. You probably got it right in your implementation, though. Something to think about, anyway.
Oh! I see why not to do this! instantiation takes place if chk_typ passes. I'm guessing that Plane3D doesn't do that for you.
Dec 20 '06 #5
bartonc
6,596 Expert 4TB
Oh! I see why not to do this! instantiation takes place if chk_typ passes. I'm guessing that Plane3D doesn't do that for you.
Of course, you could do this:

Expand|Select|Wrap|Line Numbers
  1. class BasisTransToGlobal(Plane3D):
  2.     def __init__(self, vN, vA, vB, vR=Point(0,0,0)):
  3.         self.vN = vN
  4.         if chk_type([vN, vA, vB, vR]):
  5.  
  6.             # local basis aligned with instance 'a', define the plane
  7.             Plane3D.__init__(self, vN, vA, vB)
  8.             # now all references to a. become self.
But I still don't see much, if any, advantage.
Dec 20 '06 #6
kudos
127 Expert 100+
its been ages since I have done any 3d computer graphics programming, but isn't it easier to use homogenous coordinates. Then you also can dig out somekind of matrix package (pynum?) and use it for all the operations.

-kudos
Dec 20 '06 #7
bvdet
2,851 Expert Mod 2GB
its been ages since I have done any 3d computer graphics programming, but isn't it easier to use homogenous coordinates. Then you also can dig out somekind of matrix package (pynum?) and use it for all the operations.

-kudos
Hi kudos,

Many SDS/2 Python scripts are designed to add to or modify objects in 3D space. These objects are beams, columns, and other members that form the structural skeleton of a building. Each of these objects has its own coordinate system, and we can translate in member coordinates with the built-in member translate method. Occasionally there will be a situation where a series of points need to be calculated with respect to a local basis and there is no member. That's why I wrote this class and its sister class that calculates the local point given a global coodinate.

It's likely that SciPy, Numpy or CoordSys would do what I need, but there may be installation issues with the average SDS/2 user. Beside that, I wanted to know how to perform these translations.

Have a great day,
BV
Dec 20 '06 #8
bvdet
2,851 Expert Mod 2GB
Of course, you could do this:

Expand|Select|Wrap|Line Numbers
  1. class BasisTransToGlobal(Plane3D):
  2.     def __init__(self, vN, vA, vB, vR=Point(0,0,0)):
  3.         self.vN = vN
  4.         if chk_type([vN, vA, vB, vR]):
  5.  
  6.             # local basis aligned with instance 'a', define the plane
  7.             Plane3D.__init__(self, vN, vA, vB)
  8.             # now all references to a. become self.
But I still don't see much, if any, advantage.
Barton,

It gives me some additional methods, but I may not need them. Plane3D also does a type check, but raises a TypeError. It would look like this:
Expand|Select|Wrap|Line Numbers
  1. class BasisTransToGlobal(Plane3D):
  2.     def __init__(self, vN, vA, vB, vR=Point(0,0,0)):
  3.         self.vN = vN
  4.         # local basis aligned with plane defined
  5.         Plane3D.__init__(self, vN, vA, vB)
  6.         if chk_type([vR, ]):
  7.  
  8.             if self.N_len > 0.0:
  9.  
  10.                 # Unit vector normal to defined plane, local basis 'Z'
  11.                 self.N = self.N_uv
  12.  
  13.                 # Unit vector between vN and vA, local basis 'X'
  14.                 self.A = self.d0
  15.  
  16.                 # Unit cross product vector, local basis 'Y'
  17.                 self.B = self.cross_product(self.N, self.A)
  18.  
  19.                 # global coordinate vector
  20.                 self.R = self.translate(vR.x, vR.y, vR.z) + vN
  21.  
  22.             else:
  23.                 Warning("The points are collinear ***INVALID***")
  24.                 self.R = None
  25.         else:
  26.             raise TypeError, "Arguments must be <type 'point'>"
This would be consistent with Plane3D.
Dec 20 '06 #9
bartonc
6,596 Expert 4TB
Barton,

It gives me some additional methods, but I may not need them. Plane3D also does a type check, but raises a TypeError. It would look like this:
Expand|Select|Wrap|Line Numbers
  1. class BasisTransToGlobal(Plane3D):
  2.     def __init__(self, vN, vA, vB, vR=Point(0,0,0)):
  3.         self.vN = vN
  4.         # local basis aligned with plane defined
  5.         Plane3D.__init__(self, vN, vA, vB)
  6.         if chk_type([vR, ]):
  7.  
  8.             if self.N_len > 0.0:
  9.  
  10.                 # Unit vector normal to defined plane, local basis 'Z'
  11.                 self.N = self.N_uv
  12.  
  13.                 # Unit vector between vN and vA, local basis 'X'
  14.                 self.A = self.d0
  15.  
  16.                 # Unit cross product vector, local basis 'Y'
  17.                 self.B = self.cross_product(self.N, self.A)
  18.  
  19.                 # global coordinate vector
  20.                 self.R = self.translate(vR.x, vR.y, vR.z) + vN
  21.  
  22.             else:
  23.                 Warning("The points are collinear ***INVALID***")
  24.                 self.R = None
  25.         else:
  26.             raise TypeError, "Arguments must be <type 'point'>"
This would be consistent with Plane3D.
That sure look very clean to me. You never know when the extra methods may come in handy... It's a little more work to document, though.
Dec 21 '06 #10

Post your reply

Sign in to post your reply or Sign up for a free account.

Similar topics

1 post views Thread by shank | last post: by
4 posts views Thread by Gadrin77 | last post: by
6 posts views Thread by bobueland | last post: by
6 posts views Thread by Anders K. Olsen | last post: by
1 post views Thread by peterbe | last post: by
1 post views Thread by =?Utf-8?B?R2F1cmF2?= | last post: by
4 posts views Thread by kovariadam | last post: by
1 post views Thread by Waqarahmed | last post: by
reply views Thread by Salome Sato | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.