00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 __title__="FreeCAD Draft Workbench - Vector library"
00025 __author__ = "Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline"
00026 __url__ = ["http://free-cad.sourceforge.net"]
00027
00028 "a vector math library for FreeCAD"
00029
00030 import math,FreeCAD
00031 from FreeCAD import Vector, Matrix
00032
00033 params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
00034 def precision():
00035 return params.GetInt("precision")
00036
00037 def typecheck (args_and_types, name="?"):
00038 for v,t in args_and_types:
00039 if not isinstance (v,t):
00040 FreeCAD.Console.PrintWarning("typecheck[" + str(name) + "]: " + str(v) + " is not " + str(t) + "\n")
00041 raise TypeError("fcvec." + str(name))
00042
00043 def tup(u,array=False):
00044 "returns a tuple (x,y,z) with the vector coords, or an array if array=true"
00045 typecheck ([(u,Vector)], "tup");
00046 if array:
00047 return [u.x,u.y,u.z]
00048 else:
00049 return (u.x,u.y,u.z)
00050
00051 def neg(u):
00052 "neg(Vector) - returns an opposite (negative) vector"
00053 typecheck ([(u,Vector)],"neg")
00054 return Vector(-u.x, -u.y, -u.z)
00055
00056 def equals(u,v):
00057 "returns True if vectors differ by less than precision (from ParamGet), elementwise "
00058 typecheck ([(u,Vector), (v,Vector)], "equals")
00059 return isNull (u.sub(v))
00060
00061 def scale(u,scalar):
00062 "scale(Vector,Float) - scales (multiplies) a vector by a factor"
00063 typecheck ([(u,Vector), (scalar,(int,long,float))], "scale")
00064 return Vector(u.x*scalar, u.y*scalar, u.z*scalar)
00065
00066 def scaleTo(u,l):
00067 "scaleTo(Vector,length) - scales a vector to a given length"
00068 typecheck ([(u,Vector),(l,(int,long,float))], "scaleTo")
00069 if u.Length == 0:
00070 return Vector(u)
00071 else:
00072 a = l/u.Length
00073 return Vector(u.x*a, u.y*a, u.z*a)
00074
00075 def dist(u, v):
00076 "dist(Vector,Vector) - returns the distance between both points/vectors"
00077 typecheck ([(u,Vector), (v,Vector)], "dist")
00078 x=u.sub(v).Length
00079 return u.sub(v).Length
00080
00081 def angle(u,v=Vector(1,0,0),normal=Vector(0,0,1)):
00082 '''
00083 angle(Vector,[Vector],[Vector]) - returns the angle
00084 in radians between the two vectors. If only one is given,
00085 angle is between the vector and the horizontal East direction.
00086 If a third vector is given, it is the normal used to determine
00087 the sign of the angle.
00088 '''
00089 typecheck ([(u,Vector), (v,Vector)], "angle")
00090 ll = u.Length*v.Length
00091 if ll==0: return 0
00092 dp=u.dot(v)/ll
00093 if (dp < -1): dp = -1
00094 elif (dp > 1): dp = 1
00095 ang = math.acos(dp)
00096 normal1 = u.cross(v)
00097 coeff = normal.dot(normal1)
00098 if coeff >= 0:
00099 return ang
00100 else:
00101 return -ang
00102
00103 def project(u,v):
00104 "project(Vector,Vector): projects the first vector onto the second one"
00105 typecheck([(u,Vector), (v,Vector)], "project")
00106 dp = v.dot(v)
00107 if dp == 0: return Vector(0,0,0)
00108 if dp != 15: return scale(v, u.dot(v)/dp)
00109 return Vector(0,0,0)
00110
00111 def rotate2D(u,angle):
00112 "rotate2D(Vector,angle): rotates the given vector around the Z axis"
00113 return Vector(math.cos(-angle)*u.x-math.sin(-angle)*u.y,
00114 math.sin(-angle)*u.x+math.cos(-angle)*u.y,u.z)
00115
00116 def rotate(u,angle,axis=Vector(0,0,1)):
00117 '''rotate(Vector,Float,axis=Vector): rotates the first Vector
00118 around the given axis, at the given angle.
00119 If axis is omitted, the rotation is made on the xy plane.'''
00120 typecheck ([(u,Vector), (angle,(int,long,float)), (axis,Vector)], "rotate")
00121
00122 if angle == 0: return u
00123
00124 l=axis.Length
00125 x=axis.x/l
00126 y=axis.y/l
00127 z=axis.z/l
00128 c = math.cos(angle)
00129 s = math.sin(angle)
00130 t = 1 - c;
00131
00132 xyt = x*y*t
00133 xzt = x*z*t
00134 yzt = y*z*t
00135 xs = x*s
00136 ys = y*s
00137 zs = z*s
00138
00139 m = Matrix(c + x*x*t, xyt - zs, xzt + ys, 0,
00140 xyt + zs, c + y*y*t, yzt - xs, 0,
00141 xzt - ys, yzt + xs, c + z*z*t, 0)
00142
00143 return m.multiply(u)
00144
00145 def isNull(vector):
00146 '''isNull(vector): Tests if a vector is nul vector'''
00147 p = precision()
00148 return (round(vector.x,p)==0 and round(vector.y,p)==0 and round(vector.z,p)==0)
00149
00150 def find(vector,vlist):
00151 '''find(vector,vlist): finds a vector in a list of vectors. returns
00152 the index of the matching vector, or None if none is found.
00153 '''
00154 typecheck ([(vector,Vector), (vlist,list)], "find")
00155 for i,v in enumerate(vlist):
00156 if equals(vector,v):
00157 return i
00158 return None
00159
00160 def isColinear(vlist):
00161 '''isColinear(list_of_vectors): checks if vectors in given list are colinear'''
00162 typecheck ([(vlist,list)], "isColinear");
00163 if len(vlist) < 3: return True
00164 first = vlist[1].sub(vlist[0])
00165 for i in range(2,len(vlist)):
00166 if angle(vlist[i].sub(vlist[0]),first) != 0:
00167 return False
00168 return True
00169
00170 def rounded(v):
00171 "returns a rounded vector"
00172 p = precision()
00173 return Vector(round(v.x,p),round(v.y,p),round(v.z,p))
00174
00175 def getPlaneRotation(u,v,w=None):
00176 "returns a rotation matrix defining the (u,v,w) coordinates system"
00177 if not w: w = u.cross(v)
00178 typecheck([(u,Vector), (v,Vector), (w,Vector)], "getPlaneRotation")
00179 m = FreeCAD.Matrix(
00180 u.x,v.x,w.x,0,
00181 u.y,v.y,w.y,0,
00182 u.z,v.z,w.z,0,
00183 0.0,0.0,0.0,1.0)
00184 return m
00185
00186 def removeDoubles(vlist):
00187 "removes consecutive doubles from a list of vectors"
00188 typecheck ([(vlist,list)], "removeDoubles");
00189 nlist = []
00190 if len(vlist) < 2: return vlist
00191 for i in range(len(vlist)-1):
00192 if not equals(vlist[i],vlist[i+1]):
00193 nlist.append(vlist[i])
00194 nlist.append(vlist[-1])
00195 return nlist