## PointRotate.py Version 1.02

## Copyright (c) 2006 Bruce Vaughan, BV Detailing & Design, Inc.

## All rights reserved.

## NOT FOR SALE. The software is provided "as is" without any warranty.

#############################################################################

"""

    Return a point rotated about an arbitrary axis in 3D.

    Positive angles are counter-clockwise looking down the axis toward the origin.

    The coordinate system is assumed to be right-hand.

    Arguments: 'axis point 1', 'axis point 2', 'point to be rotated', 'angle of rotation (in radians)' >> 'new point'

    Revision History:

        Version 1.01 (11/11/06) - Revised function code

        Version 1.02 (11/16/06) - Rewrote PointRotate3D function

 

    Reference 'Rotate A Point About An Arbitrary Axis (3D)' - Paul Bourke       

"""

def PointRotate3D(p1, p2, p0, theta):

    from point import Point

    from math import cos, sin, sqrt

 

    # Translate so axis is at origin   

    p = p0 - p1

    # Initialize point q

    q = Point(0.0,0.0,0.0)

    N = (p2-p1)

    Nm = sqrt(N.x**2 + N.y**2 + N.z**2)

   

    # Rotation axis unit vector

    n = Point(N.x/Nm, N.y/Nm, N.z/Nm)

 

    # Matrix common factors    

    c = cos(theta)

    t = (1 - cos(theta))

    s = sin(theta)

    X = n.x

    Y = n.y

    Z = n.z

 

    # 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

 

    #            |p.x|

    # Matrix 'M'*|p.y|

    #            |p.z|

    q.x = d11*p.x + d12*p.y + d13*p.z

    q.y = d21*p.x + d22*p.y + d23*p.z

    q.z = d31*p.x + d32*p.y + d33*p.z

 

    # Translate axis and rotated point back to original location   

    return q + p1

   

## END PointRotate3D() ##########################

def test_PointRotate3D():

    from point import Point, PointLocate

    from member import Member, MemberLocate

    from param import dim_print, Prompt, yes_or_no, Warning, ClearSelection

    from macrolib.angle import dtor

    from macrolib.ExceptWarn import formatExceptionInfo

    from macrolib.PrintPtList import formatPtList

    a1 = 45.0

    while 1:

        ClearSelection()

        try:

            Warning("Rotate a Point About a Member Line - The rotation is REVERSED if the view " +\

                    "along the rotation axis is from the member LEFT end toward the member RIGHT end. " + \

                    "A right hand coordinate system is assumed. Positive angles are counter-clockwise " +\

                    "when looking down the axis toward the origin. The member LEFT end is the origin.")

            mem1 = MemberLocate("Select member to rotate about")

            pt1 = PointLocate("Pick point to rotate")

            a1 = Prompt(a1, "Rotation angle")

            pt2 = PointRotate3D(mem1.left.location, mem1.right.location, pt1, dtor(a1))

            Warning("The selected point is %s, %s, %s \nThe new point is %s, %s, %s" % \

                    (dim_print(pt1.x), dim_print(pt1.y), dim_print(pt1.z), dim_print(pt2.x), dim_print(pt2.y), dim_print(pt2.z)))

            print formatPtList("Rotation Axis End Points:", [mem1.left.location, mem1.right.location])

            print formatPtList("Original Point and Rotated Point Coordinates:", [pt1, pt2])

        except:

            Warning(formatExceptionInfo())

        if not yes_or_no("Continue?"):

                break

## END test_PointRotate3D() #####################

if __name__ == '__main__':

    try:

        test_PointRotate3D()

    finally:

        del test_PointRotate3D

 

# SAMPLE OUTPUT

“””

Rotation Axis End Points:
X attribute         Y attribute         Z attribute         
============================================================
80-0                46-10               120-7               
80-0                52-6                110-5 1/8           

Original Point and Rotated Point Coordinates:
X attribute         Y attribute         Z attribute         
============================================================
80-0                61-3 3/4            115-1 7/8           
87-0 7/8            58-9 1/16           113-8 3/4       

“””