Source code for fcfun

# ----------------------------------------------------------------------------
# -- FreeCad Functions
# -- comps library
# -- Python functions for FreeCAD
# ----------------------------------------------------------------------------
# -- (c) Felipe Machado
# -- Area of Electronics. Rey Juan Carlos University (urjc.es)
# -- October-2016
# ----------------------------------------------------------------------------
# --- LGPL Licence
# ----------------------------------------------------------------------------

import FreeCAD
import Part
import math
import logging
import DraftVecUtils

#from FreeCAD import Base

# ---------------------- can be taken away after debugging
import os
import sys
# directory this file is
filepath = os.getcwd()
import sys
# to get the components
# In FreeCAD can be added: Preferences->General->Macro->Macro path
sys.path.append(filepath)
# ---------------------- can be taken away after debugging


import kcomp

from kcomp import LAYER3D_H


logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

# vector constants
V0 = FreeCAD.Vector(0,0,0)
VX = FreeCAD.Vector(1,0,0)
VY = FreeCAD.Vector(0,1,0)
VZ = FreeCAD.Vector(0,0,1)
VXN = FreeCAD.Vector(-1,0,0)
VYN = FreeCAD.Vector(0,-1,0)
VZN = FreeCAD.Vector(0,0,-1)

# color constants
WHITE  = (1.0, 1.0, 1.0)
BLACK  = (0.0, 0.0, 0.0)

RED    = (1.0, 0.0, 0.0)
GREEN  = (0.0, 1.0, 0.0)
BLUE   = (0.0, 0.0, 1.0)

YELLOW = (1.0, 1.0, 0.0)
MAGENT = (1.0, 0.0, 1.0)
CIAN   = (0.0, 1.0, 1.0)

ORANGE = (1.0, 0.5, 0.0)
ORANGE_08 = (1.0, 0.8, 0.0)

RED_05    = (1.0, 0.5, 0.5)
GREEN_05  = (0.5, 1.0, 0.5)
BLUE_05   = (0.5, 0.5, 1.0)

RED_07    = (1.0, 0.7, 0.7)
GREEN_07  = (0.7, 1.0, 0.7)
BLUE_07   = (0.7, 0.7, 1.0)

RED_D07    = (0.7, 0.0, 0.0)
GREEN_D07  = (0.0, 0.7, 0.0)
BLUE_D07   = (0.0, 0.0, 0.7)

YELLOW_05 = (1.0, 1.0, 0.5)
MAGENT_05 = (1.0, 0.5, 1.0)
CIAN_05   = (0.5, 1.0, 1.0)

YELLOW_08 = (1.0, 1.0, 0.8)
MAGENT_08 = (1.0, 0.8, 1.0)
CIAN_08   = (0.8, 1.0, 1.0)

DSKYBLUE   = (0.0, 0.7, 1.0)
LSKYBLUE   = (0.5, 0.7, 1.0)

GRAY_08  = (0.8, 0.8, 0.8)

GRAY_09  = (0.9, 0.9, 0.9)
YELLOW_095 = (1.0, 1.0, 0.95)

# no rotation vector
V0ROT = FreeCAD.Rotation(VZ,0)

EQUAL_TOL = 0.001 # less than a micron is the same


COS30 = 0.86603   
COS45 = 0.707   



[docs]def rotateview(axisX=1.0,axisY=0.0,axisZ=0.0,angle=45.0): """Rotate the camara""" import math from pivy import coin try: cam = Gui.ActiveDocument.ActiveView.getCameraNode() rot = coin.SbRotation() rot.setValue(coin.SbVec3f(axisX,axisY,axisZ),math.radians(angle)) nrot = cam.orientation.getValue() * rot cam.orientation = nrot print(axisX," ",axisY," ",axisZ," ",angle) except Exception: print("Not ActiveView ")
# to compare numbers that they are almost the same, but because of # floating point calculations they are not exactly the same
[docs]def equ (x,y): """Compare numbers that are the same but not exactly the same""" p = DraftVecUtils.precision() if round(x,p) == round(y,p): return True else: return False
[docs]def fc_isperp (fc1, fc2): """ Return 1 if fc1 and fc2 are perpendicular, 0 if they are not Parameters ---------- fc1 : FreeCAD.Vector Firs vector fc2 : FreeCAD.Vector Second vector Returns ------- * 1 if fc1 and fc2 are perpendicular * 0 if they are not """ if DraftVecUtils.isNull(fc1) == 1 or DraftVecUtils.isNull(fc2) == 1: # if any of them are null, they are not perpendicular return 0 else: nperp = fc1.dot(fc2) nperp_round = round(nperp,DraftVecUtils.precision()) if nperp_round == 0: return 1 else: return 0
[docs]def fc_isparal (fc1, fc2): """ Return 1 if fc1 and fc2 are paralell (colinear), 0 if they are not Parameters ---------- fc1 : FreeCAD.Vector Firs vector fc2 : FreeCAD.Vector Second vector Returns ------- * 1 if fc1 and fc2 are parallel * 0 if they are not """ if DraftVecUtils.isNull(fc1) == 1 or DraftVecUtils.isNull(fc2) == 1: # if any of them are null, they are not parallel return 0 else: # scale both to 1, normalize n1 = DraftVecUtils.scaleTo(fc1,1) n2 = DraftVecUtils.scaleTo(fc2,1) n1neg = n1.negative() if (DraftVecUtils.equals(n1,n2) or DraftVecUtils.equals(n1neg,n2)): return 1 else: return 0
[docs]def fc_isparal_nrm (fc1, fc2): """ Very similar to fc_isparal, but in this case the arguments are normalized so, less operations to do. return 1 if fc1 and fc2 are paralell (colinear), 0 if they are not Parameters ---------- fc1 : FreeCAD.Vector Firs vector fc2 : FreeCAD.Vector Second vector Returns ------- * 1 if fc1 and fc2 are parallel * 0 if they are not """ if DraftVecUtils.isNull(fc1) == 1 or DraftVecUtils.isNull(fc2) == 1: # if any of them are null, they are not parallel return 0 else: fc1neg = fc1.negative() if (DraftVecUtils.equals(fc1,fc2) or DraftVecUtils.equals(fc1neg,fc2)): return 1 else: return 0
[docs]def fc_isonbase (fcv): """ Just tells if a vector has 2 of the coordinates zero so it is on just a base vector """ if fcv.x == 0: if fcv.y == 0: # (0,0, ) if fcv.z == 0: # null vector return 0 # (0,0,0) else: return 1 # (0,0,Z) else: # (0,Y, ) if fcv.z == 0: return 1 # (0,Y,0) else: return 0 # (0,Y,Z) else: #(X, , ) if fcv.y == 0: # (X,0, ) if fcv.z == 0: return 1 # (X,0,0) else: return 0 # (X,0,Z) else: # (X,Y, ) return 0
[docs]def get_fc_perpend1(fcv): """ gets a 'random' perpendicular FreeCAD.Vector Parameters ---------- fcv : FreeCAD.Vector Vector from which to get perpendicular vector Returns ------- FreeCAD.Vector Random perpendicular vector """ if DraftVecUtils.isNull(fcv): logger.error('null vector') if fc_isonbase(fcv) == 1: # 2 of the bases are 0 # just move them fcp = FreeCAD.Vector(fcv.z, fcv.x, fcv.y) elif fcv.x == 0: fcp = FreeCAD.Vector(0, fcv.z, -fcv.y) elif fcv.y == 0: fcp = FreeCAD.Vector(-fcv.z, 0, fcv.x) elif fcv.z == 0: fcp = FreeCAD.Vector(fcv.y, -fcv.x, 0) else: # none of them are zero (same as before) fcp = FreeCAD.Vector(fcv.y, -fcv.x, 0) return fcp
# get_tangent_circle_pt
[docs]def get_tangent_circle_pt (ext_pt, center_pt, rad, axis_n, axis_side = None): """ Get the point of the tangent to the circle :: (difficult to draw in using ASCII text) external point : tangent point 1 *--- _ \ / \ \( ) circle tangent \ _ / point 2 The 3 points: center(C), ext_pt(E) and tangent_pt(T) form a rectangle triangle axis_p : axis_side : / : <90 / T / . *. / . 90 . rad . . . alpha beta . *-----------------------* ---- axis_c (axis going thru centers) E : C : : : :.................: : : + : : axis_c_ET_d : : : :.......................: + EC_d (hypotenuse) Parameters ---------- ext_pt : FreeCAD.Vector External point center_pt : FreeCAD.Vector Center of the circle rad : float Radius of the circle axis_n : FreeCAD.Vector Direction of the normal of the circle axis_side : FreeCAD.Vector Direction to the side of the tangent point, if not given, it will return both points The 2 tangent points will be at each side of axis_c. The smaller than 90 degree angle between axis_side and the 2 possible axis_p Returns ------- If axis_side is not given: returns a list with the 2 points that each point forms a line tangent to the circle. The 2 lines are defined by one of each point and the external point. If axis_side is given: Only returns a point (FreeCAD.Vector) with the tangent point defined by the direction of axis_side If there is an error it will return 0 Notes ----- **Interesting Parameters** axis_p (FreeCAD.Vector) Vector of the circle plane, perpendicular to axis_d. It can have to possible directions. If paremeter axis_side is defined, it will have the direction that has less than 90 degress related to axis_side """ # normalize axis_n vector (just in case) axis_n = DraftVecUtils.scaleTo(axis_n,1) E_pt = ext_pt C_pt = center_pt # vector from the external point to the center: EC = C_pt - E_pt # normalized vector: axis_c = DraftVecUtils.scaleTo(EC,1) if fc_isperp(axis_c, axis_n) == 0: logger.error('axis_n is not perpendicular to the line formed by the') logger.error('external point and the circle center') return 0 #calculation of axis_p vector, and its negative axis_p = axis_n.cross(axis_c) axis_pn = axis_p.negative() if axis_side is not None: axis_side = DraftVecUtils.scaleTo(axis_side, 1) if axis_side.dot(axis_p) < 0 : # axis_p in the other direction axis_p = axis_pn axis_pn = V0 # not using the negative direction, just one point # length (hypotenuse: distance from the circle center to the external point) EC_d = EC.Length if rad >= EC_d : logger.error('The external point has to be out of the circle') return 0 # calculation of the length of the other cathetus (ET) ET_d = math.sqrt(EC_d*EC_d - rad*rad) # calculation of the sine and cosine of alpha angle cos_alpha = ET_d / EC_d sin_alpha = rad / EC_d # projection distance of the cathetus onto (axis_c: EC): axis_c_ET_d = ET_d * cos_alpha # projection vector axis_c_ET = DraftVecUtils.scale(axis_c, axis_c_ET_d) # projection distance of the cathetus onto (axis_p): axis_p_ET_d = ET_d * sin_alpha # projection vector along axis_p axis_p_ET = DraftVecUtils.scale(axis_p , axis_p_ET_d) T_1 = E_pt + axis_c_ET + axis_p_ET if axis_pn == V0: return T_1 else: tg_list = [] tg_list.append(T_1) # projection vector along axis_pn axis_pn_ET = DraftVecUtils.scale(axis_pn, axis_p_ET_d) T_2 = E_pt + axis_c_ET + axis_pn_ET tg_list.append(T_2) return tg_list
#T = get_tangent_point (ext_pt = V0, # center_pt = FreeCAD.Vector(5,0,0), # rad = 2, # axis_n = VZ) # #axis_p = VY) #cir = Part.makeCircle(2,FreeCAD.Vector(5,0,0)) #Part.show(cir) #line_E_T1 = Part.LineSegment(V0, T[0]).toShape() #Part.show(line_E_T1) #line_E_T2 = Part.LineSegment(V0, T[1]).toShape() #Part.show(line_E_T2) # get_tangent_2circles
[docs]def get_tangent_2circles (center1_pt, center2_pt, rad1, rad2, axis_n, axis_side = None): """ Returns a list of lists (matrix) with the 2 tangent points for each of the 2 tangent lines :: (difficult to draw in using ASCII text) axis_p : T2 : axis_side . * r1 / ------------ . . / : . . . / : T1 . . . r2-r1 (r_diff) + r2*sin(beta) * . . : r1 . alpha beta : *----------------------* ---- axis_c (axis going thru centers) C1 : C2 :: : : :: :.....: :: + : :: r2*cos(beta): :: : ::......................: :: + :: C1_C2_d (hypotenuse) :: :: r1*cos(beta) alpha = atan(r_diff/C1_C2_d) beta = 90 - alpha tangent points along axis_c and axis_p T2_c = C2_c - r2 * cos(beta) T2_p = C2_p - r2 * sin(beta) T1_c = C1_c - r1 * cos(beta) T1_p = C1_p - r1 * sin(beta) Parameters ---------- center1_pt : FreeCAD.Vector Center of the circle 1 center2_pt : FreeCAD.Vector Center of the circle 2 rad1 : float Radius of the circle 1 rad2 : float Radius of the circle 2 axis_n : FreeCAD.Vector Direction of the normal of the circle axis_side : FreeCAD.Vector Direction to the side of the tangent line, if not given, it will return the 2 points of both lines The 2 tangent lines will be at each side of axis_c. The smaller than 90 degree angle between axis_side and the 2 possible axis_p Returns ------- * If axis_side is given: - Returns a list of lists (matrix) * Element [0][0] is the point tangent to circle 1 at side axis_side * Element [0][1] is the point tangent to circle 2 at side axis_side * Element [1][0] is the point tangent to circle 1 at opposite side of direction of axis_side * Element [1][1] is the point tangent to circle 2 at opposite side of direction of axis_side * If axis_side is not given, the order of the list of the lines is arbitrary * If there is an error it will return 0 Notes ----- **Interesting variables** axis_p (FreeCAD.Vecrtor) Vector of the circle plane, perpendicular to axis_d. It can have to possible directions. If paremeter axis_side is defined, it will have the direction that has less than 90 degress related to axis_side """ # normalize axis_n vector (just in case) axis_n = DraftVecUtils.scaleTo(axis_n,1) # choosing r1 the smaller radius, and r2 the larger if rad1 < rad2: C1_pt = center1_pt C2_pt = center2_pt r1 = rad1 r2 = rad2 else: #changing circle names C1_pt = center2_pt C2_pt = center1_pt r1 = rad2 r2 = rad1 r_diff = r2 - r1 # vector from center1 to center2: C1_C2 = C2_pt - C1_pt # normalized vector: axis_c = DraftVecUtils.scaleTo(C1_C2,1) if fc_isperp(axis_c, axis_n) == 0: logger.error('axis_n is not perpendicular to the line formed by the') logger.error('external point and the circle center') return 0 #calculation of axis_p vector, and its negative axis_p = axis_n.cross(axis_c) axis_pn = axis_p.negative() if axis_side is not None: if axis_side.dot(axis_p) < 0 : # axis_p in the other direction axis_p = axis_pn axis_pn = axis_p.negative() # if axis_side is not defined, the order is random # length (hypotenuse: distance from the circle center to the external point) C1_C2_d = C1_C2.Length if r_diff >= C1_C2_d : logger.error('smaller circle is inside the larger') return 0 # calculation of the length of the other cathetus (T1_T2) T1_T2_d = math.sqrt(C1_C2_d * C1_C2_d - r_diff * r_diff) # calculation of the sine and cosine of beta angle cos_beta = r_diff / C1_C2_d sin_beta = T1_T2_d / C1_C2_d # projection distance of the radius onto axis_d axis_c_r1_d = r1 * cos_beta axis_c_r2_d = r2 * cos_beta # projection vector, negative, opposite direction to axis_c axis_c_r1 = DraftVecUtils.scale(axis_c, -axis_c_r1_d) axis_c_r2 = DraftVecUtils.scale(axis_c, -axis_c_r2_d) # projection distance of the radius onto axis_p axis_p_r1_d = r1 * sin_beta axis_p_r2_d = r2 * sin_beta # projection vector, negative, opposite direction to axis_c axis_p_r1 = DraftVecUtils.scale(axis_p, axis_p_r1_d) axis_p_r2 = DraftVecUtils.scale(axis_p, axis_p_r2_d) axis_pn_r1 = DraftVecUtils.scale(axis_pn, axis_p_r1_d) axis_pn_r2 = DraftVecUtils.scale(axis_pn, axis_p_r2_d) # tangent line on side axis_p L1_T1 = C1_pt + axis_c_r1 + axis_p_r1 L1_T2 = C2_pt + axis_c_r2 + axis_p_r2 L2_T1 = C1_pt + axis_c_r1 + axis_pn_r1 L2_T2 = C2_pt + axis_c_r2 + axis_pn_r2 if rad1 < rad2: L1 = [L1_T1, L1_T2] L2 = [L2_T1, L2_T2] else: # the order was changed L1 = [L1_T2, L1_T1] L2 = [L2_T2, L2_T1] L = [L1, L2] return L
#L = get_tangent_2circles ( # center1_pt = V0, # center2_pt = FreeCAD.Vector(20,0,0), # rad1 = 2, # rad2 = 10, # axis_n = VZ, # axis_side = VY) #cir1 = Part.makeCircle(2,FreeCAD.Vector(0,0,0)) #cir2 = Part.makeCircle(10,FreeCAD.Vector(20,0,0)) #Part.show(cir1) #Part.show(cir2) #line_1 = Part.LineSegment(L[0][0], L[0][1]).toShape() #Part.show(line_1) #line_2 = Part.LineSegment(L[1][0], L[1][1]).toShape() #Part.show(line_2)
[docs]def fuseshplist (shp_list): """ Since multifuse methods needs to be done by a shape and a list, and usually I have a list that I want to fuse, I make this function to save the inconvenience of doing everytime what I will do here Fuse multiFuse """ if len(shp_list) > 0: shp1 = shp_list.pop() #remove and get the first element if len(shp_list) > 0: shpfuse = shp1.multiFuse(shp_list) else: #only one element, no fuse: logger.debug('only one element to fuse') shpfuse = shp1 else: logger.debug('empty list to fuse') return return (shpfuse)
[docs]def add_fcobj(shp, name, doc = None): """ Just creates a freeCAD object of the shape, just to save one line""" if doc is None: doc = FreeCAD.ActiveDocument fcobj = doc.addObject("Part::Feature", name) fcobj.Shape = shp return fcobj
[docs]def addBox(x, y, z, name, cx= False, cy=False): """ Adds a box, centered on the specified axis x and/or y, with its Placement and Rotation at zero. So it can be referenced absolutely from its given position Parameters ---------- x : float Length y : float Width z : float Height name : str Object Name cx : Boolean Centered in axis x cy : Boolean Centered in axis y Returns ------- FreeCAD.Object FreeCAD.Object with the shape of a box """ # we have to bring the active document doc = FreeCAD.ActiveDocument box = doc.addObject("Part::Box",name) box.Length = x box.Width = y box.Height = z xpos = 0 ypos = 0 # centered if cx == True: xpos = -x/2 if cy == True: ypos = -y/2 box.Placement.Base =FreeCAD.Vector(xpos,ypos,0) return box
# adds a box, centered on the specified axis, with its # Placement and Rotation at zero. So it can be referenced absolutely from # its given position
[docs]def addBox_cen(x, y, z, name, cx= False, cy=False, cz=False): """ Adds a box, centered on the specified axis, with its Placement and Rotation at zero. So it can be referenced absolutely from its given position Parameters ---------- x : float Length y : float Width z : float Height name : str Object Name cx : Boolean Centered in the X axis cy : Boolean Centered in the Y axis cz : Boolean Centered in the Z axis Returns ------- FreeCAD.Object FreeCAD.Object with the shape of a box """ # we have to bring the active document doc = FreeCAD.ActiveDocument if cx == True: x0 = -x/2.0 x1 = x/2.0 else: x0 = 0 x1 = x if cy == True: y0 = -y/2.0 y1 = y/2.0 else: y0 = 0 y1 = y if cz == True: z0 = - z/2.0 else: z0 = 0 p00 = FreeCAD.Vector (x0,y0,z0) p10 = FreeCAD.Vector (x1,y0,z0) p11 = FreeCAD.Vector (x1,y1,z0) p01 = FreeCAD.Vector (x0,y1,z0) sq_list = [p00, p10, p11, p01] square = doc.addObject("Part::Polygon",name + "_sq") square.Nodes =sq_list square.Close = True square.ViewObject.Visibility = False box = doc.addObject ("Part::Extrusion", name) box.Base = square box.Dir = (0,0, z) box.Solid = True # we need to recompute if we want to do operations on this object doc.recompute() return box
# adds a shape of box, referenced on the specified axis, with its # Placement and Rotation at zero. So it can be referenced absolutely from # its given position
[docs]def shp_boxcen(x, y, z, cx= False, cy=False, cz=False, pos=V0): """ Adds a shape of box, referenced on the specified axis, with its Placement and Rotation at zero. So it can be referenced absolutely from its given position Parameters ---------- x : float Length y : float Width z : float Height name : str Object Name cx : boolean Center in the length or not cy : boolean Center in the or width not cz : boolean Center in the height or not pos : FreeCAD.Vector Placement Returns -------- TopoShape Shape of a box """ # we have to bring the active document doc = FreeCAD.ActiveDocument if cx == True: x0 = -x/2.0 x1 = x/2.0 else: x0 = 0 x1 = x if cy == True: y0 = -y/2.0 y1 = y/2.0 else: y0 = 0 y1 = y if cz == True: z0 = - z/2.0 else: z0 = 0 p00 = FreeCAD.Vector (x0,y0,z0) + pos p10 = FreeCAD.Vector (x1,y0,z0) + pos p11 = FreeCAD.Vector (x1,y1,z0) + pos p01 = FreeCAD.Vector (x0,y1,z0) + pos # the square shp_wire_sq = Part.makePolygon([p00, p10, p11, p01, p00]) # the face shp_face_sq = Part.Face(shp_wire_sq) shp_box = shp_face_sq.extrude(FreeCAD.Vector(0,0,z)) doc.recompute() return shp_box
# The same as shp_boxcen, but when it is used to cut. So sometimes it is # useful to leave an extra 1mm on some sides to avoid making cuts sharing # faces. The extra part is added but not influences on the reference # Arguments: # x, y , z: the size of the edges of the box # cx, cy , cz: if the box will be centered on any of these axis # cx, cy , cz: if the box will be centered on any of these axis # xtr_x, xtr_nx, xtr_y, xtr_ny, xtr_z , xtr_nz: # if an extra mm will be added, the number will determine the size # # # # | Y cy=1, xtr_ny=1 # | # 1 | # _________ # | | | # | | | # | | | # | | | # |_|_______|
[docs]def shp_boxcenxtr(x, y, z, cx= False, cy=False, cz=False, xtr_nx = 0, xtr_x = 0, xtr_ny = 0, xtr_y = 0, xtr_nz = 0, xtr_z = 0, pos=V0): """ The same as shp_boxcen, but when it is used to cut. So sometimes it is useful to leave an extra 1mm on some sides to avoid making cuts sharing faces. The extra part is added but not influences on the reference :: | Y cy=1, xtr_ny=1 | 1 | _________ | | | | | | | | | | | | |_|_______| Parameters ---------- x : float Length y : float Width z : float Height cx : int Center in the length or not cy : int Center in the or width not cz : int Center in the height or not xtr_x : float Extra mm to add in positive axis of length xtr_nx : float Extra mm to add in negative axis of length xtr_y : float Extra mm to add in positive axis of width xtr_ny : float Extra mm to add in negative axis of width xtr_z : float Extra mm to add in positive axis of height xtr_nz : float Extra mm to add in negative axis of height pos : FreeCAD.Vector Placement Returns -------- TopoShape Shape of a box """ # we have to bring the active document doc = FreeCAD.ActiveDocument if cx == True: x0 = -x/2.0 - xtr_nx x1 = x/2.0 + xtr_x else: x0 = 0 - xtr_nx x1 = x + xtr_x if cy == True: y0 = -y/2.0 - xtr_ny y1 = y/2.0 + xtr_y else: y0 = 0 - xtr_ny y1 = y + xtr_y if cz == True: z0 = -z/2.0 - xtr_nz else: z0 = 0 - xtr_nz p00 = FreeCAD.Vector (x0,y0,z0) + pos p10 = FreeCAD.Vector (x1,y0,z0) + pos p11 = FreeCAD.Vector (x1,y1,z0) + pos p01 = FreeCAD.Vector (x0,y1,z0) + pos # the square shp_wire_sq = Part.makePolygon([p00, p10, p11, p01, p00]) # the face shp_face_sq = Part.Face(shp_wire_sq) shp_box = shp_face_sq.extrude(FreeCAD.Vector(0,0, z+xtr_z+xtr_nz)) doc.recompute() return shp_box
# same as shp_boxcen but with a filleted dimension
[docs]def shp_boxcenfill (x, y, z, fillrad, fx=False, fy=False, fz=True, cx= False, cy=False, cz=False, pos=V0): """ Same as shp_boxcen but with a filleted dimension Parameters ---------- x : float Length y : float Width z : float Height fillrad : float Fillet size fx : boolean Fillet in x dimension fy : boolean Fillet in y dimension fz : boolean Fillet in z dimension cx : boolean Center in the length or not cy : boolean Center in the or width not cz : boolean Center in the height or not pos : FreeCAD.Vector Placement Returns -------- TopoShape Shape of a box """ shp_box = shp_boxcen (x=x, y=y, z=z, cx=cx, cy=cy, cz=cz, pos=pos) edg_list = [] for ind, edge in enumerate(shp_box.Edges): vertex0 = edge.Vertexes[0] vertex1 = edge.Vertexes[1] p0 = vertex0.Point p1 = vertex1.Point vdif = p1 - p0 if vdif.x != 0 and fx==True: edg_list.append(edge) elif vdif.y != 0 and fy==True: edg_list.append(edge) elif vdif.z != 0 and fz==True: edg_list.append(edge) shp_boxfill = shp_box.makeFillet(fillrad, edg_list) return (shp_boxfill)
# same as shp_boxcen but with a chamfered dimension
[docs]def shp_boxcenchmf (x, y, z, chmfrad, fx=False, fy=False, fz=True, cx= False, cy=False, cz=False, pos=V0): """ Same as shp_boxcen but with a chamfered dimension Parameters ---------- x : float Length y : float Width z : float Height fillrad : float Fillet size fx : boolean Fillet in x dimension fy : boolean Fillet in y dimension fz : boolean Fillet in z dimension cx : boolean Center in the length or not cy : boolean Center in the or width not cz : boolean Center in the height or not pos : FreeCAD.Vector Placement Returns -------- TopoShape Shape of a box """ shp_box = shp_boxcen (x=x, y=y, z=z, cx=cx, cy=cy, cz=cz, pos=pos) edg_list = [] for ind, edge in enumerate(shp_box.Edges): vertex0 = edge.Vertexes[0] vertex1 = edge.Vertexes[1] p0 = vertex0.Point p1 = vertex1.Point vdif = p1 - p0 if vdif.x != 0 and fx==True: edg_list.append(edge) elif vdif.y != 0 and fy==True: edg_list.append(edge) elif vdif.z != 0 and fz==True: edg_list.append(edge) shp_boxchmf = shp_box.makeChamfer(chmfrad, edg_list) return (shp_boxchmf)
# Makes a box with width, depth, heigth. # Originally: # box_w: The width is X # box_d: The depth is Y # box_h: The Height is Z # and then rotation will be referred to axis_w = (1,0,0) and # axis_nh = (0,0,-1) # centered on any of the dimensions: # cw, cd, ch # check if it makes sense to have this small function
[docs]def shp_box_rot (box_w, box_d, box_h, axis_w = 'x', axis_nh = '-z', cw=1, cd=1, ch=1 ): """ Makes a box with width, depth, heigth and then rotation will be referred to *axis_w = (1,0,0)* and *axis_nh = (0,0,-1)*. Can be centered on any of the dimensions. Parameters ---------- box_w : float The width is X box_d : float The depth is Y box_h : float The height is Z cw : int If *1* is centered cd : int If *1* is centered ch : int If *1* is centered axis_w : str Can be: *x, -x, y, -y, z, -z* axis_nh : str Can be: *x, -x, y, -y, z, -z* Notes ----- Check if it makes sense to have this small function """ shp_box = shp_boxcen(x=box_w, y=box_d, z=box_h, cx= cw, cy=cd, cz=ch, pos=V0) vrot = calc_rot(getvecofname(axis_w), getvecofname(axis_nh)) shp_box.Placement.Rotation = vrot return shp_box
[docs]def shp_box_dir (box_w, box_d, box_h, fc_axis_w = V0, fc_axis_h = VZ, fc_axis_d =VY, cw=1, cd=1, ch=1, pos=V0): """ Makes a shape of a box given its 3 dimensions: width, depth and height and the direction of the height and depth dimensions. The position of the box is given and also if the position is given by a corner or its center :: ________ |\ \ | \ \ | \_______\ \ | | \|_______| Example of not centered on origin Z=fc_axis_h . Y = fc_axis_d : . : __________ : /: . / | : / : . / | h :/________/ | | :.....|...|3 | / 4 | / | / | / d |/________|/.....................X 1 2 w Example of centered on origin Z=fc_axis_h Y = fc_axis_d : . __________ . /: : / |. / : : / .| h /__:_____/. | | :.....|...|3 | / 4 :..|../........................X | / | / d |/________|/ 1 2 w Parameters ---------- box_w : float Width of the box box_d : float Depth of the box box_h : float Height of the box fc_axis_w : FreeCAD.Vector Direction of the width fc_axis_d : FreeCAD.Vector Direction of the depth fc_axis_h : FreeCAD.Vector Direction of the height cw : int * 1: the width dimension is centered * 0: it is not centered cd : int * 1: the depth dimension is centered * 0: it is not centered ch : int * 1: the height dimension is centered * 0: it is not centered pos : FreeCAD.Vector Position of the box, it can be the center one corner, or a point centered in the dimensions given by cw, cd, ch Returns -------- TopoShape Shape of a box """ # box_w: width of the box # box_d: depth of the box # box_h: heiht of the box # fc_axis_h: FreeCAD vector that has the direction of the height # fc_axis_d: FreeCAD vector that has the direction of the depth # fc_axis_w: FreeCAD vector that has the direction of the width # Not necessary, unless cw=0, then it indicates the # direction of w, it has to be perpendicular to the previous # if = V0, the perpendicular will be calculated # cw: 1 the width dimension is centered, 0 it is not # cd: 1 the depth is centered, 0 it is not # ch: 1 the height dimension is centered, 0 it is not # pos: FreeCAD.Vector of the position of the box, it can be the center # one corner, or a point centered in the dimensions given by # cw, cd, ch # normalize the axis, just in case: axis_h = DraftVecUtils.scaleTo(fc_axis_h,1) axis_d = DraftVecUtils.scaleTo(fc_axis_d,1) if fc_axis_w == V0: axis_w = axis_d.cross(axis_h) else: axis_w = DraftVecUtils.scaleTo(fc_axis_w,1) #get the points of the base: width x depth # if not centered, the first vertex of the base is on V0 if cw == 1: # just scale and not scaleTo because they are unit vectors w_neg = DraftVecUtils.scale(axis_w, -box_w/2.) w_pos = DraftVecUtils.scale(axis_w, box_w/2.) else: w_neg = V0 w_pos = DraftVecUtils.scale(axis_w, box_w) if cd == 1: d_neg = DraftVecUtils.scale(axis_d, -box_d/2.) d_pos = DraftVecUtils.scale(axis_d, box_d/2.) else: d_neg = V0 d_pos = DraftVecUtils.scale(axis_d, box_d) if ch == 1: h_neg = DraftVecUtils.scale(axis_h, -box_h/2.) else: h_neg = V0 v1 = pos + w_neg + d_neg + h_neg v2 = pos + w_pos + d_neg + h_neg v3 = pos + w_pos + d_pos + h_neg v4 = pos + w_neg + d_pos + h_neg # make a wire with the points wire_base = Part.makePolygon([v1,v2,v3,v4,v1]) # make the face of the wire shp_facebase = Part.Face(wire_base) # length of the extrusion v_extr = DraftVecUtils.scale(axis_h, box_h) shp_box = shp_facebase.extrude(v_extr) return(shp_box)
[docs]def shp_box_dir_xtr (box_w, box_d, box_h, fc_axis_h =VZ, fc_axis_d = VY, fc_axis_w = V0, cw=1, cd=1, ch=1, xtr_h = 0, xtr_nh = 0, xtr_d = 0, xtr_nd = 0, xtr_w = 0, xtr_nw = 0, pos=V0): """ Makes a shape of a box given its 3 dimensions: width, depth and height and the direction of the height and depth dimensions. The position of the box is given and also if the position is given by a corner or its center. Extra mm to make cuts :: ________ |\ \ | \ \ | \_______\ \ | | \|_______| Example of not centered on origin Z=fc_axis_h . Y = fc_axis_d : . : __________ : /: . / | : / : . / | h :/________/ | | :.....|...|3 | / 4 | / | / | / d |/________|/.....................X 1 2 w Example of centered on origin Z=fc_axis_h Y = fc_axis_d : . __________ . /: : / |. / : : / .| h /__:_____/. | | :.....|...|3 | / 4 :..|../........................X | / | / d |/________|/ 1 2 w Parameters ---------- box_w : float Width of the box box_d : float Depth of the box box_h : float Heiht of the box fc_axis_h : FreeCAD.Vector Direction of the height fc_axis_d : FreeCAD.Vector Direction of the depth fc_axis_w : FreeCAD.Vector Direction of the width cw : int * 1 the width dimension is centered * 0 it is not centered cd : int * 1 the depth dimension is centered * 0 it is not centered ch : int * 1 the height dimension is centered * 0 it is not centered xtr_w : float If an extra mm will be added, the number will determine the size useful to make cuts xtr_nw : float If an extra mm will be added, the number will determine the size useful to make cuts xtr_d : float If an extra mm will be added, the number will determine the size useful to make cuts xtr_nd : float If an extra mm will be added, the number will determine the size useful to make cuts xtr_h : float If an extra mm will be added, the number will determine the size useful to make cuts xtr_nh : float If an extra mm will be added, the number will determine the size useful to make cuts pos : FreeCAD.Vector Position of the box, it can be the center one corner, or a point centered in the dimensions given by cw, cd, ch Returns -------- TopoShape FreeCAD.Object with a shape of a box Notes ----- **fc_axis_w** not necessary, unless cw=0, then it indicates the direction of w, it has to be perpendicular to the previous """ # normalize the axis, just in case: axis_h = DraftVecUtils.scaleTo(fc_axis_h,1) axis_d = DraftVecUtils.scaleTo(fc_axis_d,1) if fc_axis_w == V0: axis_w = axis_d.cross(axis_h) else: axis_w = DraftVecUtils.scaleTo(fc_axis_w,1) #get the points of the base: width x depth # if not centered, the first vertex of the base is on V0 if cw == 1: w_neg = DraftVecUtils.scale(axis_w, -box_w/2. - xtr_nw) w_pos = DraftVecUtils.scale(axis_w, box_w/2. + xtr_w) else: w_neg = DraftVecUtils.scale(axis_w, - xtr_nw) w_pos = DraftVecUtils.scale(axis_w, box_w + xtr_w) if cd == 1: d_neg = DraftVecUtils.scale(axis_d, -box_d/2. - xtr_nd) d_pos = DraftVecUtils.scale(axis_d, box_d/2. + xtr_d) else: d_neg = DraftVecUtils.scale(axis_d, - xtr_nd) d_pos = DraftVecUtils.scale(axis_d, box_d + xtr_d) if ch == 1: h_neg = DraftVecUtils.scale(axis_h, -box_h/2. - xtr_nh) else: h_neg = DraftVecUtils.scale(axis_h, - xtr_nh) v1 = pos + w_neg + d_neg + h_neg v2 = pos + w_pos + d_neg + h_neg v3 = pos + w_pos + d_pos + h_neg v4 = pos + w_neg + d_pos + h_neg # make a wire with the points wire_base = Part.makePolygon([v1,v2,v3,v4,v1]) # make the face of the wire shp_facebase = Part.Face(wire_base) # length of the extrusion v_extr = DraftVecUtils.scale(axis_h, box_h + xtr_h + xtr_nh) shp_box = shp_facebase.extrude(v_extr) return(shp_box)
[docs]def shp_boxdir_fillchmfplane ( box_w, box_d, box_h, axis_d = VY, axis_w = V0, axis_h = VZ, cw=1, cd=1, ch=1, xtr_d = 0, xtr_nd = 0, xtr_w = 0, xtr_nw = 0, xtr_h = 0, xtr_nh = 0, fillet = 1, radius = 1., plane_fill = VZ, both_planes = 1, edge_dir = V0, pos=V0): """ Creates a box shape (cuboid) along 3 axis. The shape will be filleted or chamfered on the edges of the plane defined by the plane_fill vector. If both_planes == 1, both faces will be filleted/chamfered if both_planes == 0, only the face that plane_fill is normal and goes outwards if edge_dir has an edge direction, only those edges in that direction will be filleted/chamfered :: Example of not centered on origin: cd=0, cw=0, ch=0 axis_h . axis_d : . : __________.... : /: . / | : : / : . / | :h :/________/ | : | :.....|...|..:.. | / | / . | / | / . d |/________|/.................> axis_w : : :....w....: Example of centered on origin: cd=1, cw=1, ch=1 axis_h axis_d : . __________ . /: : / |. / : : / .| h /__:_____/. | | :.....|...| | / :..|../..............> axis_w | / | / |/________|/ w Example of parameter both_planes and edge_dir if both_planes == 1: if edge_dir == V0: edges_to_chamfer = [1,2,3,4,5,6,7,8] elif edge_dir == axis_w: edges_to_chamfer = [2,4,6,8] elif edge_dir == axis_d: edges_to_chamfer = [1,3,5,7] elif both_planes == 0: if edge_dir == V0: edges_to_chamfer = [1,2,3,4] elif edge_dir == axis_w: edges_to_chamfer = [2,4] elif edge_dir == axis_d: edges_to_chamfer = [1,3] axis_h=plane_fill : : ____2_____ : /: / | : 1 : 3 | :/_____4__/ | | :...6.|...| | / | / | 5 | 7 |/___8____|/.................> axis_w Another example of parameter both_planes if both_planes == 1: edges_to_chamfer = [1,2,3,4,5,6,7,8] elif both_planes == 0: edges_to_chamfer = [5,6,7,8] axis_h : : ____2_____ : /: / | : 1 : 3 | :/_____4__/ | | :...6.|...| | / | / | 5 | 7 |/___8____|/.................> axis_w : : : V plane_fill = axis_h.negative() Parameters ---------- box_d : positive float Depth of the box box_w : positive float Width of the box box_h : positive float Height of the box axis_d : FreeCAD.Vector Depth vector of the coordinate system axis_w : FreeCAD.Vector Width vector of the coordinate system, can be V0 if centered and will be perpendicular to axis_d and axis_w axis_h : FreeCAD.Vector Height vector of the coordinate system cw : int 1: centered along axis_w cd : int 1: centered along axis_d ch : int 1: centered along axis_h xtr_d : float, >= 0 Extra depth, if there is an extra depth along axis_d xtr_nd : float, >= 0 Extra depth, if there is an extra depth along axis_d.negative xtr_w : float, >= 0 Extra width, if there is an extra width along axis_w xtr_nw : float, >= 0 Extra width, if there is an extra width along axis_w.negative xtr_h : float, >= 0 Extra height, if there is an extra height along axis_h xtr_nh : float, >= 0 Extra height, if there is an extra height along axis_h.negative fillet : int * 1: to fillet the edges * 0: to chamfer the edges radius : float >= 0 radius of the fillet/chamfer plane_fill : FreeCAD.Vector Vector perpendicular to the face that is going to be filleted/chamfered both_planes : int * 0: fillet/chamfer only the edges on the face perpendicular to plane_fill and on the face that plane_fill goes outwards. See drawing * 1: fillet/chamfer the edges on both faces perpendicular to plane_fill edge_dir : FreeCAD.Vector * V0: fillet/chamfer all the edges of that/those faces * Axis: fillet/chamfer only the edges of that/those faces that are paralell to this axis pos : FreeCAD.Vector Position of the box Returns -------- TopoShape Shape of the filleted/chamfered box """ doc = FreeCAD.ActiveDocument # normalize axes: # axis_l.normalize() could be used, but would change the vector # used as parameter axis_d = DraftVecUtils.scaleTo(axis_d,1) axis_h = DraftVecUtils.scaleTo(axis_h,1) if axis_w == V0: axis_w = axis_d.cross(axis_h) else: axis_w = DraftVecUtils.scaleTo(axis_w,1) plane_fill = DraftVecUtils.scaleTo(plane_fill,1) edge_dir = DraftVecUtils.scaleTo(edge_dir,1) n_plane_fill = plane_fill.negative() shp_box = shp_box_dir_xtr ( box_w = box_w, box_d = box_d, box_h = box_h, fc_axis_h = axis_h, fc_axis_d = axis_d, fc_axis_w = axis_w, cw=cw, cd=cd, ch=ch, xtr_d = xtr_d, xtr_nd = xtr_nd, xtr_w = xtr_h, xtr_nw = xtr_nw, xtr_h = xtr_h, xtr_nh = xtr_nh, pos=pos) edg_list = [] if both_planes == 0: # need to sort the edges in two planes edg_list_plane1 = [] edg_list_plane2 = [] ind_edg_plane1 = 0 ind_edg_plane2 = 0 for ind, edge in enumerate(shp_box.Edges): vertex0 = edge.Vertexes[0] vertex1 = edge.Vertexes[1] p0 = vertex0.Point p1 = vertex1.Point vdif = p1 - p0 vdif.normalize() # check that they are not parallel to the normal: if not fc_isparal_nrm(vdif, plane_fill) : # all the edges or check if they are parallel to edge_dir if edge_dir == V0 or fc_isparal_nrm(vdif,edge_dir): if both_planes == 1: edg_list.append(edge) else: #only take one face scalar_proy = p0.dot(plane_fill) #logger.debug ('%i', scalar_proy) # see if this value is in either list if ind_edg_plane1 > 0: # check if they are equal, but with a precision if equ(scalarproy_edg_plane1, scalar_proy) : ind_edg_plane1 += 1 edg_list_plane1.append(edge) else: # not in the same plane. Plane 2 list if ind_edg_plane2 > 0: if equ(scalarproy_edg_plane2, scalar_proy) : ind_edg_plane2 += 1 edg_list_plane2.append(edge) else: logger.error('error in plane to fillet') else: # first edge on list 2 ind_edg_plane2 = 1 edg_list_plane2.append(edge) scalarproy_edg_plane2 = scalar_proy else: # first edge on plane 1 ind_edg_plane1 = 1 edg_list_plane1.append(edge) scalarproy_edg_plane1 = scalar_proy if both_planes == 0: if ind_edg_plane1 > 0: if scalarproy_edg_plane1 > scalarproy_edg_plane2: edg_list = edg_list_plane1 else: edg_list = edg_list_plane2 elif edge_dir == V0: logger.debug('No axis edge to fillet or chamfer') else: logger.debug('Probably wrong edge_dir') if len(edg_list) != 0: if fillet == 1: #logger.debug('%s', str(edg_list)) shp_fillchmf = shp_box.makeFillet(radius, edg_list) else: #logger.debug('%s', str(edg_list)) shp_fillchmf = shp_box.makeChamfer(radius, edg_list) doc.recompute() return shp_fillchmf else: logger.debug('No edge to fillet or chamfer') return
# Test shp_boxdir_fillchmfplane #doc = FreeCAD.newDocument() #shp=shp_boxdir_fillchmfplane(10,3,4, # xtr_d = 1, xtr_nd = 3, # xtr_w = 2, xtr_nw = 2, # xtr_h = 3, xtr_nh = 1, # ch=0, # fillet=0,plane_fill=VYN, both_planes=0, # edge_dir = VZ, # pos=FreeCAD.Vector(1,2,4)) #Part.show(shp) # def shp_face_lgrail # adds a shape of the profile (face) of a linear guide rail, the dent is just # rough, to be able to see that it is a profile # Arguments: # rail_w : width of the rail # rail_h : height of the rail # axis_l : the axis where the lenght of the rail is: 'x', 'y', 'z' # axis_b : the axis where the base of the rail is poingint: # 'x', 'y', 'z', '-x', '-y', '-z', # It will be centered on the width axis, and zero on the length and height # Z # | # _________________ 5 # | | 4 # \ 3 / A little dent to see that it is a rail # / \ 2 # | | # | | # |_________________| _____________ Y # 1
[docs]def shp_face_lgrail (rail_w, rail_h, axis_l = 'x', axis_b = '-z'): """ Adds a shape of the profile (face) of a linear guide rail, the dent is just rough, to be able to see that it is a profile :: It will be centered on the width axis, and zero on the length and height Z | _________________ 5 | | 4 \ 3 / A little dent to see that it is a rail / \ 2 | | | | |_________________| _____________ Y 1 Parameters ---------- rail_w : float Width of the rail rail_h : float Height of the rail axis_l : str Axis where the lenght of the rail is: 'x', 'y', 'z' axis_b : str Axis where the base of the rail is poingint: 'x', 'y', 'z', '-x', '-y', '-z', Returns -------- Shape FreeCAD Shape Face of a rail """ #First we do it on like it is axis_l = 'x' and axis_h = 'z' #so we draw width on Y and height on Z v1 = FreeCAD.Vector(0, rail_w/2., 0) v1n = FreeCAD.Vector(0, -rail_w/2., 0) v2 = FreeCAD.Vector(0, rail_w/2., rail_h/2.) v2n = FreeCAD.Vector(0, -rail_w/2., rail_h/2.) v3 = FreeCAD.Vector(0, rail_w/2.-rail_h/8.,rail_h/2. + rail_h/8.) v3n = FreeCAD.Vector(0, -rail_w/2.+rail_h/8.,rail_h/2. + rail_h/8.) v4 = FreeCAD.Vector(0, rail_w/2., rail_h/2. + rail_h/4.) v4n = FreeCAD.Vector(0, -rail_w/2., rail_h/2. + rail_h/4.) v5 = FreeCAD.Vector(0, rail_w/2., rail_h) v5n = FreeCAD.Vector(0, -rail_w/2., rail_h) # the square shp_wire_rail = Part.makePolygon([v1, v2, v3, v4, v5, v5n, v4n, v3n, v2n, v1n, v1]) vrot = calc_rot(getvecofname(axis_l), getvecofname(axis_b)) # the face #shp_wire_rail.rotate(vrot) # It doesn't work shp_wire_rail.Placement.Rotation = vrot shp_face_rail = Part.Face(shp_wire_rail) return (shp_face_rail)
[docs]def wire_lgrail (rail_w, rail_h, axis_w = VX, axis_h = VY, pos_w = 0, pos_h = 0, pos = V0): """ Creates a wire of a linear guide rail, the dent is just rough, to be able to see that it is a profile :: axis_h : ne ________2________ e | | nd| | d \ nc c / A little dent to see that it is a rail nb / 1 \ b | | | | | | na|________o________|a ...... axis_w 0 1 rail_h/8 : : : ne ________2______:_:.... | | :+ rail_h/4 nd| |................. \ nc c / .... rail_h/8 + rail_h/4 nb / 1 \ .... rail_h/8...: | | : | | + rail_h/2 | | : na|________o________|a ..:............ axis_w 0 1 pos_o (origin) is at pos_w = 0, pos_h = 0 Parameters ---------- rail_w : float Width of the rail rail_h : float Height of the rail axis_w : FreeCAD.Vector The axis where the width of the rail is axis_h : FreeCAD.Vector The axis where the height of the rail is pos_w : int Location of pos along axis_w * 0 : center of symmetry * 1 : end of the rail pos_h : int Location of pos along axis_h * 0 : bottom * 1 : middle point (this is kind of non-sense) * 2 : top point pos : FreeCAD.Vector Position, at the point defined by pos_w and pos_h Returns ------- FreeCAD Wire Wire of a rail """ # normalize the axis axis_w = DraftVecUtils.scaleTo(axis_w,1) axis_h = DraftVecUtils.scaleTo(axis_h,1) # distances from the origin (pos_o) to pos_h along axis_h h_o = {} h_o[0] = V0 h_o[1] = DraftVecUtils.scale(axis_h,rail_h/2.) h_o[2] = DraftVecUtils.scale(axis_h,rail_h) # distances from the origin (pos_o) to pos_w along axis_w # this is symmetric w_o = {} w_o[0] = V0 w_o[1] = DraftVecUtils.scale(axis_w,rail_w/2.) # usually not necessary, just change the direction of axis_w: w_o[-1] = DraftVecUtils.scale(axis_w,-rail_w/2.) #not necessary, just change # origin reference position: pos_o = pos + h_o[pos_h].negative() + w_o[pos_w].negative() pt_a = pos_o + w_o[1] pt_na = pos_o + w_o[-1] pt_b = pt_a + h_o[1] pt_nb = pt_na + h_o[1] pt_c = (pt_b + DraftVecUtils.scale(axis_h, rail_h/8.) + DraftVecUtils.scale(axis_w, -rail_h/8.)) pt_nc = (pt_nb + DraftVecUtils.scale(axis_h, rail_h/8.) + DraftVecUtils.scale(axis_w, rail_h/8.)) pt_d = pt_b + DraftVecUtils.scale(axis_h, rail_h/4.) pt_nd = pt_nb + DraftVecUtils.scale(axis_h, rail_h/4.) pt_e = pt_a + h_o[2] pt_ne = pt_na + h_o[2] wire_rail = Part.makePolygon([pt_a, pt_b, pt_c, pt_d, pt_e, pt_ne, pt_nd, pt_nc, pt_nb, pt_na, pt_a]) return wire_rail
# ------------------------ def shp_face_rail # adds a shape of the profile (face) of a rail # Arguments: # rail_w : width of the rail # rail_ws : small width of the rail # rail_h : height of the rail # rail_h_plus : above the rail can be some height to attach, o whatever # it is not inluded on rail_h # offs_w : offset on the width, to make the hole # offs_h : offset on the heigth, to make the hole # axis_l : the axis where the lenght of the rail is: 'x', 'y', 'z' # axis_b : the axis where the base of the rail is poingint: # 'x', 'y', 'z', '-x', '-y', '-z', # It will be centered on the width axis, and zero on the length and height # hole_d : diameter of a hole inside the rail. To have a leadscrew # hole_relpos_z: relative position of the center of the hole, relative # to the height (the rail_h, not the total height (rail_h+rail_h_plus) # Z # | # ___________ 4 ___________ # | | ____________ rail_h_plus # | | | # | | 3 + rail_h # / ___ \ | # / / \ \ 2 | _______ hole_relpos_z*rail_h # | \___/ | | # |_________________| _____________ Y # 1 # |--rail_ws-| # |---- rail_w ----|
[docs]def shp_face_rail (rail_w, rail_ws, rail_h, rail_h_plus = 0, offs_w = 0, offs_h = 0, axis_l = 'x', axis_b = '-z', hole_d = 0, hole_relpos_z=0.4): """ Adds a shape of the profile (face) of a rail :: Z | ___________ 4 ___________ | | ____________ rail_h_plus | | | | | 3 + rail_h / ___ \ | / / \ \ 2 | _______ hole_relpos_z*rail_h | \___/ | | |_________________| _____________ Y 1 |--rail_ws-| |---- rail_w ----| Parameters ---------- rail_w : float Width of the rail rail_ws : float Small width of the rail rail_h : float Height of the rail rail_h_plus : float Above the rail can be some height to attach, o whatever it is not inluded on rail_h offs_w : float Offset on the width, to make the hole offs_h : float Offset on the heigth, to make the hole axis_l : str The axis where the lenght of the rail is: 'x', 'y', 'z' axis_b : str The axis where the base of the rail is poingint: 'x', 'y', 'z', '-x', '-y', '-z', It will be centered on the width axis, and zero on the length and height hole_d : float Diameter of a hole inside the rail. To have a leadscrew hole_relpos_z : float Relative position of the center of the hole, relative to the height (the rail_h, not the total height (rail_h+rail_h_plus) Returns -------- Shape FreeCAD Shape Face of a rail """ # hole_relpos_z is the relative position referenced to rail_h #First we do it on like it is axis_l = 'x' and axis_h = 'z' #so we draw width on Y and height on Z #dent = rail_h / 3. dent = (rail_w - rail_ws)/2. y1 = rail_w/2 + offs_w y3 = rail_w/2 -dent + offs_w z0 = - offs_h #z2 = dent + offs_h z2 = (rail_h - dent)/2. + offs_h z3 = (rail_h - dent)/2. + dent + offs_h z4 = rail_h + rail_h_plus + 2*offs_h v1 = FreeCAD.Vector(0, y1, z0) v1n = FreeCAD.Vector(0, -y1, z0) v2 = FreeCAD.Vector(0, y1, z2) v2n = FreeCAD.Vector(0, -y1, z2) v3 = FreeCAD.Vector(0, y3, z3) v3n = FreeCAD.Vector(0, -y3, z3) v4 = FreeCAD.Vector(0, y3, z4) v4n = FreeCAD.Vector(0, -y3, z4) # the square shp_wire_rail = Part.makePolygon([v1, v2, v3, v4, v4n, v3n, v2n, v1n, v1]) vrot = calc_rot(getvecofname(axis_l), getvecofname(axis_b)) # the face #shp_wire_rail.rotate(vrot) # It doesn't work shp_wire_rail.Placement.Rotation = vrot shp_face_rail = Part.Face(shp_wire_rail) #Part.show(shp_face_rail) if hole_d > 0: cir = Part.makeCircle (hole_d/2., FreeCAD.Vector(0, 0, hole_relpos_z*rail_h), VX) cir.Placement.Rotation = vrot wire_cir = Part.Wire(cir) face_cir = Part.Face(wire_cir) #Part.show(shp_thruhole) shp_face_rail = shp_face_rail.cut(face_cir) #return shp_face_hole return shp_face_rail
# Add cylinder r: radius, h: height
[docs]def addCyl (r, h, name): """ Add cylinder Parameters ---------- r : float Radius h : float Height Returns -------- FreeCAD Object Cylinder """ # we have to bring the active document doc = FreeCAD.ActiveDocument cyl = doc.addObject("Part::Cylinder",name) cyl.Radius = r cyl.Height = h return cyl
# Add cylinder in a position. So it is in a certain position, with its # Placement and Rotation at zero. So it can be referenced absolutely from # its given position # r: radius, # h: height # name # axis: 'x', 'y' or 'z' # 'x' will along the x axis # 'y' will along the y axis # 'z' will be vertical # h_disp: displacement on the height. # if 0, the base of the cylinder will be on the plane # if -h/2: the plane will be cutting h/2
[docs]def addCyl_pos (r, h, name, axis = 'z', h_disp = 0): """ Add cylinder in a position. So it is in a certain position, with its Placement and Rotation at zero. So it can be referenced absolutely from its given position Parameters ---------- r : float Radius h : float Height name : str Name axis : str 'x', 'y' or 'z' * 'x' will along the x axis * 'y' will along the y axis * 'z' will be vertical h_disp : int Displacement on the height. * if 0, the base of the cylinder will be on the plane * if -h/2: the plane will be cutting h/2 Returns -------- FreeCAD Object Cylinder """ # we have to bring the active document doc = FreeCAD.ActiveDocument cir = doc.addObject("Part::Circle", name + "_circ") cir.Radius = r if axis == 'x': rot = FreeCAD.Rotation (VY, 90) cir.Placement.Base = (h_disp, 0, 0) extdir = (h,0,0) # direction for the extrusion elif axis == 'y': rot = FreeCAD.Rotation (VX, -90) cir.Placement.Base = (0, h_disp, 0) extdir = (0,h,0) else: # 'z' or any other rot = FreeCAD.Rotation (VZ, 0) cir.Placement.Base = (0, 0, h_disp) extdir = (0,0,h) cir.Placement.Rotation = rot # to hide the circle if cir.ViewObject != None: cir.ViewObject.Visibility=False cyl = doc.addObject ("Part::Extrusion", name) cyl.Base = cir cyl.Dir = extdir cyl.Solid = True return cyl
# same as addCyl_pos, but avoiding the creation of many FreeCAD objects # Add cylinder # r: radius, # h: height # name # normal: FreeCAD.Vector pointing to the normal (if its module is not one, # the height will be larger than h # pos: position of the cylinder
[docs]def addCylPos (r, h, name, normal = VZ, pos = V0): """ Same as addCyl_pos, but avoiding the creation of many FreeCAD objects Parameters ---------- r : float Radius, h : float Height name : str Objet name normal : FreeCAD.Vector FreeCAD.Vector pointing to the normal (if its module is not one, the height will be larger than h pos : FreeCAD.Vector Position of the cylinder Returns -------- FreeCAD Object Cylinder """ # we have to bring the active document doc = FreeCAD.ActiveDocument cir = Part.makeCircle (r, # Radius pos, # Position normal) # direction #print "circle: %", cir_out.Curve wire_cir = Part.Wire(cir) face_cir = Part.Face(wire_cir) dir_extrus = DraftVecUtils.scaleTo(normal, h) shp_cyl = face_cir.extrude(dir_extrus) cyl = doc.addObject("Part::Feature", name) cyl.Shape = shp_cyl return cyl
# same as addCylPos, but just creates the shape # Add cylinder # r: radius, # h: height # normal: FreeCAD.Vector pointing to the normal (if its module is not one, # the height will be larger than h # pos: position of the cylinder
[docs]def shp_cyl (r, h, normal = VZ, pos = V0): """ Same as addCylPos, but just creates the shape Parameters ---------- r : float Radius, h : float Height normal : FreeCAD.Vectot FreeCAD.Vector pointing to the normal (if its module is not one, the height will be larger than h pos : FreeCAD.Vector Position of the cylinder Returns -------- Shape FreeCAD Shape of a cylinder """ cir = Part.makeCircle (r, # Radius pos, # Position normal) # direction #print "circle: %", cir_out.Curve wire_cir = Part.Wire(cir) face_cir = Part.Face(wire_cir) dir_extrus = DraftVecUtils.scaleTo(normal, h) shpcyl = face_cir.extrude(dir_extrus) return shpcyl
# Add cylinder, can be centered on the position, and also can have an extra # mm on top and bottom to make cuts # r: radius, # h: height # normal: FreeCAD.Vector pointing to the normal # ch : centered on the middle, of the height # xtr_top : extra on top (but does not influence the centering) # xtr_bot : extra on bottom (but does not influence the centering) # pos: position of the cylinder #
[docs]def shp_cylcenxtr (r, h, normal = VZ, ch = 1, xtr_top=0, xtr_bot=0, pos = V0): """ Add cylinder, can be centered on the position, and also can have an extra mm on top and bottom to make cuts Parameters ---------- r : float Radius h : float Height normal : FreeCAD.Vector FreeCAD.Vector pointing to the normal ch : int Centered on the middle, of the height xtr_top : float Extra on top (but does not influence the centering) xtr_bot : float Extra on bottom (but does not influence the centering) pos : FreeCAD.Vector Position of the cylinder Returns -------- Shape FreeCAD Shape of a cylinder """ # Normalize the normal, in case it is not one: nnormal = DraftVecUtils.scaleTo(normal, 1) if ch == 1: # we have to move the circle half the height down + xtr_bot basepos = pos - DraftVecUtils.scaleTo(nnormal, h/2. + xtr_bot) else: basepos = pos - DraftVecUtils.scaleTo(nnormal, xtr_bot) cir = Part.makeCircle (r, # Radius basepos, # Position nnormal) # direction #print "circle: %", cir.Curve wire_cir = Part.Wire(cir) face_cir = Part.Face(wire_cir) dir_extrus = DraftVecUtils.scaleTo(normal, h+xtr_bot+xtr_top) shpcyl = face_cir.extrude(dir_extrus) return shpcyl
[docs]def shp_cyl_gen (r, h, axis_h = VZ, axis_ra = None, axis_rb = None, pos_h = 0, pos_ra = 0, pos_rb = 0, xtr_top=0, xtr_bot=0, xtr_r=0, pos = V0): """ This is a generalization of shp_cylcenxtr. Makes a cylinder in any position and direction, with optional extra heights and radius, and various locations in the cylinder :: pos_h = 1, pos_ra = 0, pos_rb = 0 pos at 1: axis_rb : : . . . . ( o ) ---- axis_ra This o will be pos_o (origin) . . . . axis_h : : ............... :____:____:....: xtr_top | | | | | | | | | | | | |____1____|...............> axis_ra :....o....:....: xtr_bot This o will be pos_o pos_h = 0, pos_ra = 1, pos_rb = 0 pos at x: axis_rb : : : . . : . . x ) ----> axis_ra . . . . axis_h : : ............... :____:____:....: xtr_top | | | | | | x |....>axis_ra | | | | |_________|..... :....o....:....: xtr_bot This o will be pos_o pos_h = 0, pos_ra = 1, pos_rb = 1 pos at x: axis_rb : : : . . : . . ( ) . . x . . ....> axis_ra axis_h : : ............... :____:____:....: xtr_top || | || | || | |x |....>axis_ra || | || | ||_________|..... ::....o....:....: xtr_bot :; xtr_r Parameters ---------- r : float Radius of the cylinder h : float Height of the cylinder axis_h : FreeCAD.Vector Vector along the cylinder height axis_ra : FreeCAD.Vector Vector along the cylinder radius, a direction perpendicular to axis_h only make sense if pos_ra = 1. It can be None. axis_rb : FreeCAD.Vector Vector along the cylinder radius, a direction perpendicular to axis_h and axis_rb only make sense if pos_rb = 1 It can be None pos_h : int Location of pos along axis_h (0, 1) * 0: the cylinder pos is centered along its height * 1: the cylinder pos is at its base (not considering xtr_h) pos_ra : int Location of pos along axis_ra (0, 1) * 0: pos is at the circunference center * 1: pos is at the circunsference, on axis_ra, at r from the circle center (not at r + xtr_r) pos_rb : int Location of pos along axis_rb (0, 1) * 0: pos is at the circunference center * 1: pos is at the circunsference, on axis_rb, at r from the circle center (not at r + xtr_r) xtr_top : float Extra height on top, it is not taken under consideration when calculating the cylinder center along the height xtr_bot : float Extra height at the bottom, it is not taken under consideration when calculating the cylinder center along the height or the position of the base xtr_r : float Extra length of the radius, it is not taken under consideration when calculating pos_ra or pos_rb pos : FreeCAD.Vector Position of the cylinder, taking into account where the center is Returns -------- Shape FreeCAD Shape of a cylinder """ # calculate pos_o, which is at the center of the circle and at the base # counting xtr_bot if is is > 0 axis_h = DraftVecUtils.scaleTo(axis_h, 1) if pos_ra == 0: ra_to_o = V0 else: if axis_ra is not None: axis_ra = DraftVecUtils.scaleTo(axis_ra, 1) ra_to_o = DraftVecUtils.scale(axis_ra, r) else : logger.error('axis_ra not defined while pos_ra ==1') if pos_rb == 0: rb_to_o = V0 else: if axis_rb is not None: axis_rb = DraftVecUtils.scaleTo(axis_rb, 1) rb_to_o = DraftVecUtils.scale(axis_rb, r) else : logger.error('axis_rb not defined while pos_rb ==1') if pos_h == 0: # we have to move the circle half the height down + xtr_bot h_to_o = DraftVecUtils.scale(axis_h, -(h/2. + xtr_bot)) else: h_to_o = DraftVecUtils.scale(axis_h, - xtr_bot) pos_o = pos + h_to_o + ra_to_o + rb_to_o cir = Part.makeCircle (r + xtr_r, # Radius pos_o, # Position axis_h) # direction wire_cir = Part.Wire(cir) face_cir = Part.Face(wire_cir) extrude_dir = DraftVecUtils.scale(axis_h, h+xtr_bot+xtr_top) shpcyl = face_cir.extrude(extrude_dir) return shpcyl
#cyl = shp_cyl_gen (r=2, h=2, axis_h = VZ, # axis_ra = VX, axis_rb = VY, # pos_h = 1, pos_ra = 1, pos_rb = 0, # xtr_top=0, xtr_bot=1, xtr_r=2, # pos = V0) # #pos = FreeCAD.Vector(1,2,0)) #Part.show(cyl) # Add cylinder, with inner hole: # r_ext: external radius, # r_int: internal radius, # h: height # name # axis: 'x', 'y' or 'z' # 'x' will along the x axis # 'y' will along the y axis # 'z' will be vertical # h_disp: displacement on the height. # if 0, the base of the cylinder will be on the plane # if -h/2: the plane will be cutting h/2
[docs]def addCylHole (r_ext, r_int, h, name, axis = 'z', h_disp = 0): """ Add cylinder, with inner hole: Parameters ---------- r_ext : float External radius, r_int : float Internal radius, h : float Height name : str Object name axis : str 'x', 'y' or 'z' * 'x' will along the x axis * 'y' will along the y axis * 'z' will be vertical h_disp : int Displacement on the height. * if 0, the base of the cylinder will be on the plane * if -h/2: the plane will be cutting h/2 Returns -------- FreeCAD.Object Cylinder with hole """ # we have to bring the active document doc = FreeCAD.ActiveDocument cyl_ext = addCyl (r_ext, h, name + "_ext") cyl_int = addCyl (r_int, h + 2, name + "_int") if axis == 'x': rot = FreeCAD.Rotation (VY, 90) cyl_ext.Placement.Base = (h_disp, 0, 0) cyl_int.Placement.Base = (h_disp-1, 0, 0) elif axis == 'y': rot = FreeCAD.Rotation (VX, -90) cyl_ext.Placement.Base = (0, h_disp, 0) cyl_int.Placement.Base = (0, h_disp-1, 0) else: # 'z' or any other rot = FreeCAD.Rotation (VZ, 0) cyl_ext.Placement.Base = (0, 0, h_disp) cyl_int.Placement.Base = (0, 0, h_disp-1) cyl_ext.Placement.Rotation = rot cyl_int.Placement.Rotation = rot cylHole = doc.addObject("Part::Cut", name) cylHole.Base = cyl_ext cylHole.Tool = cyl_int return cylHole
# Same as addCylHole, but just a shape # Add cylinder, with inner hole: # r_ext: external radius, # r_int: internal radius, # h: height # axis: 'x', 'y' or 'z' # 'x' will along the x axis # 'y' will along the y axis # 'z' will be vertical # h_disp: displacement on the height. # if 0, the base of the cylinder will be on the plane # if -h/2: the plane will be cutting h/2
[docs]def shp_cylhole (r_ext, r_int, h, axis = 'z', h_disp = 0.): """ Same as addCylHole, but just a shape Add cylinder, with inner hole: Parameters ---------- r_ext : float External radius, r_int : float Internal radius, h : float Height axis : str 'x', 'y' or 'z' * 'x' will along the x axis * 'y' will along the y axis * 'z' will be vertical h_disp : int Displacement on the height. * if 0, the base of the cylinder will be on the plane * if -h/2: the plane will be cutting h/2 Returns ------- Shape FreeCAD Shape of a cylinder with hole """ normal = getfcvecofname(axis) pos_ext = DraftVecUtils.scaleTo(normal, h_disp) pos_int = DraftVecUtils.scaleTo(normal, h_disp-1) shp_cyl_ext = shp_cyl (r_ext, h, normal = normal, pos=pos_ext) shp_cyl_int = shp_cyl (r_int, h+2, normal = normal, pos=pos_int) shp_cyl_hole = shp_cyl_ext.cut(shp_cyl_int) return shp_cyl_hole
# same as addCylHole, but avoiding the creation of many FreeCAD objects # Add cylinder, with inner hole: # r_out: outside radius, # r_in : inside radius, # h: height # name # normal: FreeCAD.Vector pointing to the normal (if its module is not one, # the height will be larger than h # pos: position of the cylinder
[docs]def addCylHolePos (r_out, r_in, h, name, normal = VZ, pos = V0): """ Same as addCylHole, but avoiding the creation of many FreeCAD objects Add cylinder, with inner hole Parameters ---------- r_out : float Outside radius r_in : float Inside radius h : float Height name : str Object name normal : FreeCAD.Vector FreeCAD.Vector pointing to the normal (if its module is not one, the height will be larger than h pos : FreeCAD.Vector Position of the cylinder Returns -------- Shape FreeCAD Shape of a cylinder with hole """ # we have to bring the active document doc = FreeCAD.ActiveDocument cir_out = Part.makeCircle (r_out, # Radius pos, # Position normal) # direction cir_in = Part.makeCircle (r_in, # Radius pos, # Position normal) # direction #print "in: %", cir_in.Curve #print "out: %", cir_out.Curve wire_cir_out = Part.Wire(cir_out) wire_cir_in = Part.Wire(cir_in) face_cir_out = Part.Face(wire_cir_out) face_cir_in = Part.Face(wire_cir_in) face_cir_hole = face_cir_out.cut(face_cir_in) dir_extrus = DraftVecUtils.scaleTo(normal, h) shp_cyl_hole = face_cir_hole.extrude(dir_extrus) cyl_hole = doc.addObject("Part::Feature", name) cyl_hole.Shape = shp_cyl_hole return cyl_hole
[docs]def shp_cylholedir (r_out, r_in, h, normal = VZ, pos = V0): """ Same as addCylHolePos, but just a shape Same as shp_cylhole, but this one accepts any normal Parameters ---------- r_out : float Outside radius r_in : float Inside radius h : float Height normal : FreeCAD.Vector FreeCAD.Vector pointing to the normal (if its module is not one, the height will be larger than h pos : FreeCAD.Vector Position of the cylinder Returns -------- Shape FreeCAD Shape of a cylinder with hole """ cir_out = Part.makeCircle (r_out, # Radius pos, # Position normal) # direction cir_in = Part.makeCircle (r_in, # Radius pos, # Position normal) # direction wire_cir_out = Part.Wire(cir_out) wire_cir_in = Part.Wire(cir_in) face_cir_out = Part.Face(wire_cir_out) face_cir_in = Part.Face(wire_cir_in) face_cir_hole = face_cir_out.cut(face_cir_in) dir_extrus = DraftVecUtils.scaleTo(normal, h) shp_cyl_hole = face_cir_hole.extrude(dir_extrus) return shp_cyl_hole
[docs]def shp_cylhole_gen (r_out, r_in, h, axis_h = VZ, axis_ra = None, axis_rb = None, pos_h = 0, pos_ra = 0, pos_rb = 0, xtr_top=0, xtr_bot=0, xtr_r_out=0, xtr_r_in=0, pos = V0): """ This is a generalization of shp_cylholedir. Makes a hollow cylinder in any position and direction, with optional extra heights, and inner and outer radius, and various locations in the cylinder :: pos_h = 1, pos_ra = 0, pos_rb = 0 pos at 1: axis_rb : : . . . . . . ( ( 0 ) ) ---- axis_ra . . . . . . axis_h : : ............... :____:____:....: xtr_top | : : | | : : | | : : | | : 0 : | 0: pos would be at 0, if pos_h == 0 | : : | | : : | |_:__1__:_|....>axis_ra :.:..o..:.:....: xtr_bot This o will be pos_o (orig) : : : : :..: : + : :r_in: : : :....: + r_out Values for pos_ra (similar to pos_rb along it axis) axis_h : : ............... :____:____:....: xtr_top | : : | | : : | | : : | 2 1 0 : |....>axis_ra (if pos_h == 0) | : : | | : : | |_:_____:_|..... :.:..o..:.:....: xtr_bot This o will be pos_o (orig) : : : : :..: : + : :r_in: : : :....: + r_out Parameters ---------- r_out : float Radius of the outside cylinder r_in : float Radius of the inner hole of the cylinder h : float Height of the cylinder axis_h : FreeCAD.Vector Vector along the cylinder height axis_ra : FreeCAD.Vector Vector along the cylinder radius, a direction perpendicular to axis_h it is not necessary if pos_ra == 0 It can be None, but if None, axis_rb has to be None axis_rb : FreeCAD.Vector Vector along the cylinder radius, a direction perpendicular to axis_h and axis_ra it is not necessary if pos_ra == 0 It can be None pos_h : int Location of pos along axis_h (0, 1) * 0: the cylinder pos is centered along its height, not considering xtr_top, xtr_bot * 1: the cylinder pos is at its base (not considering xtr_h) pos_ra : int Location of pos along axis_ra (0, 1) * 0: pos is at the circunference center * 1: pos is at the inner circunsference, on axis_ra, at r_in from the circle center (not at r_in + xtr_r_in) * 2: pos is at the outer circunsference, on axis_ra, at r_out from the circle center (not at r_out + xtr_r_out) pos_rb : int Location of pos along axis_ra (0, 1) * 0: pos is at the circunference center * 1: pos is at the inner circunsference, on axis_rb, at r_in from the circle center (not at r_in + xtr_r_in) * 2: pos is at the outer circunsference, on axis_rb, at r_out from the circle center (not at r_out + xtr_r_out) xtr_top : float Extra height on top, it is not taken under consideration when calculating the cylinder center along the height xtr_bot : float Extra height at the bottom, it is not taken under consideration when calculating the cylinder center along the height or the position of the base xtr_r_in : float Extra length of the inner radius (hollow cylinder), it is not taken under consideration when calculating pos_ra or pos_rb. It can be negative, so this inner radius would be smaller xtr_r_out : float Extra length of the outer radius it is not taken under consideration when calculating pos_ra or pos_rb. It can be negative, so this outer radius would be smaller pos: FreeCAD.Vector Position of the cylinder, taking into account where the center is Returns -------- Shape FreeCAD Shape of a cylinder with hole """ # calculate pos_o, which is at the center of the circle and at the base # counting xtr_bot it is is > 0 axis_h = DraftVecUtils.scaleTo(axis_h, 1) # vectors from o (orig) along axis_h, to the pos_h points h_o = {} h_o[0] = DraftVecUtils.scale(axis_h, h/2. + xtr_bot) h_o[1] = DraftVecUtils.scale(axis_h, xtr_bot) # vectors from o (orig) along axis_ra, to the pos_ra points ra_o = {} ra_o[0] = V0 if pos_ra != 0: if axis_ra is not None: axis_ra = DraftVecUtils.scaleTo(axis_ra, 1) ra_o[1] = DraftVecUtils.scale(axis_ra, - r_in) ra_o[2] = DraftVecUtils.scale(axis_ra, - r_out) else : logger.error('axis_ra not defined while pos_ra ==1') # vectors from o (orig) along axis_rb, to the pos_rb points rb_o = {} rb_o[0] = V0 if pos_rb != 0: if axis_rb is not None: axis_rb = DraftVecUtils.scaleTo(axis_rb, 1) rb_o[1] = DraftVecUtils.scale(axis_rb, - r_in) rb_o[2] = DraftVecUtils.scale(axis_rb, - r_out) else : logger.error('axis_rb not defined while pos_rb ==1') pos_o = pos + (h_o[pos_h] + ra_o[pos_ra] + rb_o[pos_rb]).negative() shp_hollowcyl = shp_cylholedir (r_out = r_out + xtr_r_out, r_in = r_in + xtr_r_in, h = h+xtr_bot+xtr_top, normal = axis_h, pos = pos_o) return shp_hollowcyl
#cyl = shp_cylhole_gen (r_in=2, r_out=5, h=4, # #axis_h = FreeCAD.Vector(1,1,0), # axis_h = VZ, # axis_ra = VX, axis_rb = VYN, # pos_h = 0, pos_ra = 1, pos_rb = 2, # xtr_top=0, xtr_bot=1, # xtr_r_in=0, xtr_r_out=-1, # pos = V0) # #pos = FreeCAD.Vector(1,2,3)) #Part.show(cyl)
[docs]def shp_cylhole_arc (r_out, r_in, h, axis_h = VZ, axis_ra = None, axis_rb = None, end_angle = 360, pos_h = 0, pos_ra = 0, pos_rb = 0, xtr_top=0, xtr_bot=0, xtr_r_out=0, xtr_r_in=0, pos = V0): """ This is similar to make shp_cylhole_gen but not for a whole, just an arc. I don't know how where makeCircle starts its startangle and end angle That is why I use this way Makes a hollow cylinder in any position and direction, with optional extra heights, and inner and outer radius, and various locations in the cylinder :: pos_h = 1, pos_ra = 0, pos_rb = 0 pos at 1: axis_rb : : . . . . . . ( ( 0 ) ) ---- axis_ra . . . . . . axis_h : : ............... :____:____:....: xtr_top | : : | | : : | | : : | | : 0 : | 0: pos would be at 0, if pos_h == 0 | : : | | : : | |_:__1__:_|....>axis_ra :.:..o..:.:....: xtr_bot This o will be pos_o (orig) : : : : :..: : + : :r_in: : : :....: + r_out Values for pos_ra (similar to pos_rb along it axis) axis_h : : ............... :____:____:....: xtr_top | : : | | : : | | : : | 2 1 0 : |....>axis_ra (if pos_h == 0) | : : | | : : | |_:_____:_|..... :.:..o..:.:....: xtr_bot This o will be pos_o (orig) : : : : :..: : + : :r_in: : : :....: + r_out Parameters ---------- r_out : float Radius of the outside cylinder r_in : float Radius of the inner hole of the cylinder h : float Height of the cylinder axis_h : FreeCAD.Vector Vector along the cylinder height axis_ra : FreeCAD.Vector Vector along the cylinder radius, a direction perpendicular to axis_h it is not necessary if pos_ra == 0 It can be None, but if None, axis_rb has to be None Defines the starting angle axis_rb : FreeCAD.Vector Vector along the cylinder radius, a direction perpendicular to axis_h and axis_ra it is not necessary if pos_ra == 0 It can be None end_angle : float (in degrees) Rotating from axis_ra in the direction determined by axis_h pos_h : int Location of pos along axis_h (0, 1) * 0: the cylinder pos is centered along its height, not considering xtr_top, xtr_bot * 1: the cylinder pos is at its base (not considering xtr_h) pos_ra : int Location of pos along axis_ra (0, 1) * 0: pos is at the circunference center * 1: pos is at the inner circunsference, on axis_ra, at r_in from the circle center (not at r_in + xtr_r_in) * 2: pos is at the outer circunsference, on axis_ra, at r_out from the circle center (not at r_out + xtr_r_out) pos_rb : int Location of pos along axis_ra (0, 1) * 0: pos is at the circunference center * 1: pos is at the inner circunsference, on axis_rb, at r_in from the circle center (not at r_in + xtr_r_in) * 2: pos is at the outer circunsference, on axis_rb, at r_out from the circle center (not at r_out + xtr_r_out) xtr_top : float Extra height on top, it is not taken under consideration when calculating the cylinder center along the height xtr_bot : float Extra height at the bottom, it is not taken under consideration when calculating the cylinder center along the height or the position of the base xtr_r_in : float Extra length of the inner radius (hollow cylinder), it is not taken under consideration when calculating pos_ra or pos_rb. It can be negative, so this inner radius would be smaller xtr_r_out : float Extra length of the outer radius it is not taken under consideration when calculating pos_ra or pos_rb. It can be negative, so this outer radius would be smaller pos : FreeCAD.Vector Position of the cylinder, taking into account where the center is Returns -------- Shape FreeCAD Shape of a arc of the cylinder """ # calculate pos_o, which is at the center of the circle and at the base # counting xtr_bot it is is > 0 axis_h = DraftVecUtils.scaleTo(axis_h, 1) # vectors from o (orig) along axis_h, to the pos_h points h_o = {} h_o[0] = DraftVecUtils.scale(axis_h, h/2. + xtr_bot) h_o[1] = DraftVecUtils.scale(axis_h, xtr_bot) # vectors from o (orig) along axis_ra, to the pos_ra points ra_o = {} ra_o[0] = V0 if pos_ra != 0 or end_angle < 360: if axis_ra is not None: axis_ra = DraftVecUtils.scaleTo(axis_ra, 1) ra_o[1] = DraftVecUtils.scale(axis_ra, - r_in) ra_o[2] = DraftVecUtils.scale(axis_ra, - r_out) else : logger.warning('axis_ra not defined while pos_ra ==1') logger.warning('getting any perpendicular') axis_ra = get_fc_perpend1(axis_h) # vectors from o (orig) along axis_rb, to the pos_rb points rb_o = {} rb_o[0] = V0 if pos_rb != 0: if axis_rb is not None: axis_rb = DraftVecUtils.scaleTo(axis_rb, 1) rb_o[1] = DraftVecUtils.scale(axis_rb, - r_in) rb_o[2] = DraftVecUtils.scale(axis_rb, - r_out) else : logger.error('axis_rb not defined while pos_rb ==1') pos_o = pos + (h_o[pos_h] + ra_o[pos_ra] + rb_o[pos_rb]).negative() shp_hollowcyl = shp_cylholedir (r_out = r_out + xtr_r_out, r_in = r_in + xtr_r_in, h = h+xtr_bot+xtr_top, normal = axis_h, pos = pos_o) if end_angle < 360: # # axis_h towards you # # # 2quart(<180) 1quart (<90) # ______ > axis_ra # \ # 3quart(>180) \ 4quart(>270) # \ # : # v # axis_d_neg # pos_o_cut = pos_o + DraftVecUtils.scale(axis_h, -1) axis_d = DraftVecUtils.rotate(axis_ra, 0.5*math.pi, axis_h) # 90 axis_d_neg = DraftVecUtils.scale(axis_d, -1) # 270 axis_ra_neg = DraftVecUtils.scale(axis_ra, -1) # to radians rad_angle = end_angle * math.pi /180 # Unit vector in the angle of the cut pos_cut_dir = DraftVecUtils.rotate(axis_ra, rad_angle, axis_h) # position at the cylinder to cut (extra to cut) pos_cut = pos_o_cut + DraftVecUtils.scale(pos_cut_dir, 2* (r_out + xtr_r_out + 1)) cut_h = h+xtr_bot+xtr_top + 2 cut_r = r_out + xtr_r_out + 1 cut_l = [] if end_angle <= 180: # take away the axis_d_neg part shp_cuthalf = shp_box_dir (box_w = 2*cut_r, box_d = cut_r, box_h = cut_h, fc_axis_w = axis_ra, fc_axis_h = axis_h, fc_axis_d = axis_d_neg, cw =1, cd=0, ch=0, pos= pos_o_cut) cut_l.append(shp_cuthalf) if end_angle < 180: if end_angle <= 90: # take away the axis_ra_neg part shp_cut2quart = shp_box_dir ( box_w = cut_r, box_d = cut_r, box_h = cut_h, fc_axis_w = axis_ra_neg, fc_axis_h = axis_h, fc_axis_d = axis_d, cw =0, cd=0, ch=0, pos= pos_o_cut) cut_l.append(shp_cut2quart) if end_angle < 90: pos_cut2 = pos_o_cut + DraftVecUtils.scale(axis_d, 2* cut_r) wire_cut = Part.makePolygon([pos_o_cut, pos_cut, pos_cut2, pos_o_cut]) face_cut = Part.Face(wire_cut) dir_extrud = DraftVecUtils.scaleTo(axis_h, cut_h) shp_cutangle = face_cut.extrude(dir_extrud) cut_l.append(shp_cutangle) else : # 90<angle<180 pos_cut2 = pos_o_cut + DraftVecUtils.scale(axis_ra_neg, 2* cut_r) wire_cut = Part.makePolygon([pos_o_cut, pos_cut, pos_cut2, pos_o_cut]) face_cut = Part.Face(wire_cut) dir_extrud = DraftVecUtils.scaleTo(axis_h, cut_h) shp_cutangle = face_cut.extrude(dir_extrud) cut_l.append(shp_cutangle) else : # > 180 if end_angle <= 270: shp_cut3quart = shp_box_dir ( box_w = r_out + xtr_r_out + 1, box_d = r_out + xtr_r_out + 1, box_h = h+xtr_bot+xtr_top + 2, fc_axis_w = axis_ra, fc_axis_h = axis_h, fc_axis_d = axis_d_neg, cw =0, cd=0, ch=0, pos=pos_o_cut) cut_l.append(shp_cut3quart) if end_angle < 270: pos_cut2 = pos_o_cut + DraftVecUtils.scale(axis_d_neg, 2* cut_r) wire_cut = Part.makePolygon([pos_o_cut, pos_cut, pos_cut2, pos_o_cut]) face_cut = Part.Face(wire_cut) dir_extrud = DraftVecUtils.scaleTo(axis_h, cut_h) shp_cutangle = face_cut.extrude(dir_extrud) cut_l.append(shp_cutangle) else : #>270 pos_cut2 = pos_o_cut + DraftVecUtils.scale(axis_ra, 2* cut_r) wire_cut = Part.makePolygon([pos_o_cut, pos_cut, pos_cut2, pos_o_cut]) face_cut = Part.Face(wire_cut) dir_extrud = DraftVecUtils.scaleTo(axis_h, cut_h) shp_cutangle = face_cut.extrude(dir_extrud) cut_l.append(shp_cutangle) shp_cutangle = fuseshplist(cut_l) shp_hollowcyl = shp_hollowcyl.cut(shp_cutangle) return shp_hollowcyl
#cyl = shp_cylhole_arc (r_in=2, r_out=5, h=4, # #axis_h = FreeCAD.Vector(1,1,0), # axis_h = VZ, # axis_ra = VX, axis_rb = VYN, # end_angle = 60, # pos_h = 0, pos_ra = 1, pos_rb = 2, # xtr_top=0, xtr_bot=1, # xtr_r_in=0, xtr_r_out=-1, # pos = V0) #pos = FreeCAD.Vector(1,2,3)) #Part.show(cyl)
[docs]def add2CylsHole (r1, h1, r2, h2, thick, normal = VZ, pos = V0): """ Creates a piece formed by 2 hollow cylinders :: :.. h1 .....+..h2..: : : : ...:___________: : thick...|.......... | : | : |______:..... | :........| : | : | + r2 | : |....: | :........| : | : ______| + r1 |.........: | : |___________|...........: Parameters ---------- r1 : float Radius of the 1st cylinder. The first cylinder relative to the position pos h1 : float Height of the 1st cylinder (seen from outside) r2 : float Radius of the 2nd cylinder h2 : float Height of the 2nd cylinder (seen from outside) normal : FreeCAD.Vector Direction of the height pos : FreeCAD.Vector Position of the center Returns -------- Shape FreeCAD Shape of a two cylinders """ # normalize de axis just in case: nnormal = DraftVecUtils.scaleTo(normal,1) # the smaller radius cylinder will be larger, add thick if r1 < r2: h1_real = h1 + thick h2_real = h2 pos_cyl2 = pos + DraftVecUtils.scaleTo(nnormal, h1) rs = r1 # small radius rl = r2 # large radius pos_innercyl_large = pos + DraftVecUtils.scaleTo(nnormal, h1+thick) # inner height of the large cylinder innercyl_h_l = h2 - thick # extra for the cut, depending which side it is inncercyl_larg_xtrbot = 0 inncercyl_larg_xtrtop = 1 elif r1 > r2: h1_real = h1 h2_real = h2 + thick pos_cyl2 = pos + DraftVecUtils.scaleTo(nnormal, h1-thick) rs = r2 # small radius rl = r1 # large radius pos_innercyl_large = pos # inner height of the large cylinder innercyl_h_l = h1 - thick # extra for the cut, depending which side it is inncercyl_larg_xtrbot = 1 inncercyl_larg_xtrtop = 0 else: logger.debug('Cylinders have the same radius') shp_cyl1 = shp_cyl(r1, h1_real, nnormal, pos) shp_cyl2 = shp_cyl(r2, h2_real, nnormal, pos_cyl2) shp_ext = shp_cyl1.fuse(shp_cyl2) # thruhole of the smaller radius shp_innercyl_s = shp_cylcenxtr (rs-thick, h = h1+h2, normal = nnormal, ch = 0, xtr_top=1, xtr_bot=1, pos = pos) # thruhole of the larger radius shp_innercyl_l = shp_cylcenxtr (rl-thick, h = innercyl_h_l, normal = nnormal, ch = 0, xtr_top=inncercyl_larg_xtrtop, xtr_bot=inncercyl_larg_xtrbot, pos = pos_innercyl_large) shp_innercyl = shp_innercyl_s.fuse(shp_innercyl_l) shp_2cyls = shp_ext.cut(shp_innercyl) return (shp_2cyls)
[docs]def add3CylsHole (r1, h1, r2, h2, rring, hring, thick, normal = VZ, pos = V0): """ Creates a piece formed by 2 hollow cylinders, and a ring on the side of the larger cylinder :: ref _:.. h1 .....+..h2..: | | : : ...| |___________: : thick...|.|.......... | : | | : |______:..... | | :........| : | | : | + r2 * | : |....:....... | | :........| : : | | : ______| + r1 : |.|.........: | : : | |___________|...........: + rring | | : |_|..............................: : : + hring Parameters ---------- r1 : float Radius of the 1st cylinder. The first cylinder relative to the position pos (if this is larger than r2, the ring will go first) h1 : float Height of the 1st cylinder (seen from outside) r2 : float Radius of the 2nd cylinder h2 : float Height of the 2nd cylinder (seen from outside) rring : float Radius of the ring, it has to be larger than r1, and r2 hring : float Height of the ring, it has to be larger than r1, and r2 thick : float Thickness of the walls, excluding the ring normal : FreeCAD.Vector Direction of the height pos : FreeCAD.Vector Position of the center Returns -------- Shape FreeCAD Shape of a three cylinders """ # normalize de axis just in case: nnormal = DraftVecUtils.scaleTo(normal,1) if r1 > rring or r2 > rring: logger.error('r ring has to be larger the the other radius' ) # the smaller radius cylinder will be larger, add thick if r1 < r2: # the smaller radius cylinder first shp_cyl1 = shp_cyl(r1, h1 + 1, nnormal, pos) pos_cyl2 = pos + DraftVecUtils.scaleTo(nnormal, h1) shp_cyl2 = shp_cyl(r2, h2 + hring/2., nnormal, pos_cyl2) pos_ring = pos + DraftVecUtils.scaleTo(nnormal, h1+ h2) shp_ring = shp_cyl(rring, hring, nnormal, pos_ring) # thruhole of the smaller radius shp_innercyl_s = shp_cylcenxtr (r1-thick, h = h1+h2+hring, normal = nnormal, ch = 0, xtr_top=1, xtr_bot=1, pos = pos) # thruhole of the larger radius pos_innercyl_l = pos + DraftVecUtils.scaleTo(nnormal, h1+thick) shp_innercyl_l = shp_cylcenxtr (r2-thick, h = h2 + hring - thick, normal = nnormal, ch = 0, xtr_top=1, xtr_bot=0, pos = pos_innercyl_l) elif r1 > r2: # the ring first, then the larger radius, and then the smaller shp_ring = shp_cyl(rring, hring, nnormal, pos) pos_cyl1 = pos + DraftVecUtils.scaleTo(nnormal, hring) shp_cyl1 = shp_cylcenxtr(r1, h1, nnormal, ch=0, xtr_top = 0, xtr_bot = hring/2., pos = pos_cyl1) pos_cyl2 = pos_cyl1 + DraftVecUtils.scaleTo(nnormal, h1-thick) shp_cyl2 = shp_cyl(r2,h2+thick, nnormal, pos_cyl2) # thruhole of the smaller radius shp_innercyl_s = shp_cylcenxtr (r2-thick, h = h1+h2+hring, normal = nnormal, ch = 0, xtr_top=1, xtr_bot=1, pos = pos) # thruhole of the larger radius pos_innercyl_l = pos + DraftVecUtils.scaleTo(nnormal, h1+thick) shp_innercyl_l = shp_cylcenxtr (r1-thick, h = h1 + hring - thick, normal = nnormal, ch = 0, xtr_top=0, xtr_bot=1, pos = pos) else: logger.debug('Cylinders have the same radius') shp_ext = shp_cyl1.multiFuse([shp_cyl2, shp_ring]) shp_innercyl = shp_innercyl_s.fuse(shp_innercyl_l) shp_2cyls_ring = shp_ext.cut(shp_innercyl) return (shp_2cyls_ring)
# ------------------- def shp_stadium_wire # Creates a wire (shape), that is a rectangle with semicircles at a pair of # opposite sides. Also called discorectangle # it will be centered on XY # Y # _____ .. r |_X # (_____)-- # : : # :.l.: # # l: length of the parallels (from center to center) # r: Radius of the semicircles # axis_rect: 'x' the parallels are on axis X (as in the drawing) # 'y' the parallels are on axis Y # pos_z: position on the Z axis
[docs]def shp_stadium_wire (l, r, axis_rect='x', pos_z=0): """ Creates a wire (shape), that is a rectangle with semicircles at a pair of opposite sides. Also called discorectangle it will be centered on XY :: Y _____ .. r |_X (_____)-- : : :.l.: Parameters ---------- l : float Length of the parallels (from center to center) r : float Radius of the semicircles axis_rect : str 'x' the parallels are on axis X (as in the drawing) 'y' the parallels are on axis Y pos_z : float Position on the Z axis Returns -------- Shape Wire FreeCAD Wire of a stadium """ # considering axis_rect == 'x', if not, later it is rotated # center points of the semicircles: cen = FreeCAD.Vector (l/2., 0, pos_z) cen_n = FreeCAD.Vector (-l/2., 0, pos_z) arch = Part.makeCircle (r, cen, VZ, 270, 90) arch_n = Part.makeCircle (r, cen_n, VZ, 90, 270) # points of the lines p_x_y = FreeCAD.Vector(l/2.,r, pos_z) p_nx_y = FreeCAD.Vector(-l/2.,r, pos_z) p_x_ny = FreeCAD.Vector(l/2.,-r, pos_z) p_nx_ny = FreeCAD.Vector(-l/2.,-r, pos_z) # In Freecad 0.17 Line is an infinite Line, change to LineSegment lin_y = Part.LineSegment(p_x_y, p_nx_y).toShape() lin_ny = Part.LineSegment(p_nx_ny, p_x_ny).toShape() list_elem = [arch, lin_y, arch_n, lin_ny] if axis_rect == 'y': for elem in list_elem: # arguments of rotate: rotation center, rotation axis, angle elem.rotate(V0,VZ,90) wire_stadium = Part.Wire (list_elem) #Part.show(wire_stadium) return (wire_stadium)
# same as shp_stadium_wire, but returns a face
[docs]def shp_stadium_face (l, r, axis_rect='x', pos_z=0): """ Same as shp_stadium_wire, but returns a face Parameters ---------- l : float Length of the parallels (from center to center) r : float Radius of the semicircles axis_rect : str 'x' the parallels are on axis X (as in the drawing) 'y' the parallels are on axis Y pos_z : float Position on the Z axis Returns -------- Shape Face FreeCAD Face of a stadium """ shpStadiumWire = shp_stadium_wire (l, r, axis_rect, pos_z) shpStadiumFace = Part.Face (shpStadiumWire) return shpStadiumFace
# ------------------- def shp_stadium_wire_dir
[docs]def shp_stadium_wire_dir (length, radius, fc_axis_l = VX, fc_axis_s = VY, ref_l = 1, ref_s = 1, pos=V0): """ Same as shp_stadium_wire but in any direction Also called discorectangle :: fc_axis_s | _____ .. radius |--> fc_axis_l (_____)-- : : :.l.: length fc_axis_s in this drawing, : p_edge the zero is on point 2 :_________ ref_l = 2, ref_s = 1 / \ 3 2 1 ) -------> fc_axis_l 5\_____4____/ n_edge n_edge n circle p circle Parameters ---------- length : float Length of the parallels (distance between semcircle centers) radius : float Radius of the semicircles fc_axis_l : FreeCAD.Vector Vector on the direction of the paralles fc_axis_s : FreeCAD.Vector Vector on the direction perpendicular to the paralles ref_l : int Reference (zero) of the fc_axis_l * 1 reference on the center (makes axis_s symmetrical) * 2 reference at one of the semicircle centers (point 2) the other circle center will be on the direction of fc_axis_l * 3 reference at the end (point 3) the other end will be on the direction of fc_axis_l ref_s : int Reference (zero) of the fc_axis_s * 1 reference at the center (makes axis_l symmetrical): p 1,2,3 * 2 reference at the parallels lines: p: 4, 5 the other parallel will be on the direction of fc_axis_s pos : FreeCAD.Vector FreeCAD vector of the position of the reference Returns -------- Shape Wire FreeCAD Wire of a stadium """ # normalize the axis axis_l = DraftVecUtils.scaleTo(fc_axis_l,1) axis_s = DraftVecUtils.scaleTo(fc_axis_s,1) # axis_s: 1, 2, 3 are the points in s # ____:_____ # / 3 \ # 3 2 1 4 5 --> axis_l: 3, 2, 1, are the points in l # \____2_____/ # # # ----- Distance vectors on axis_l # distance from 1 to 2 in axis_l fc_1_2_l = DraftVecUtils.scale(axis_l, -length/2.) fc_2_3_l = DraftVecUtils.scale(axis_l, -radius) fc_1_3_l = fc_1_2_l + fc_2_3_l fc_1_4_l = fc_1_2_l.negative() fc_1_5_l = fc_1_3_l.negative() # ----- reference to 1 on axis_l #d vector to go from the reference point to point 1 in l if ref_l == 1: # ref on stadium center refto_1_l = V0 elif ref_l == 2: # ref on circle center (left) refto_1_l = fc_1_4_l # or fc_1_2_l.negative() elif ref_l == 3: # ref at the left end refto_1_l = fc_1_5_l # or fc_1_3_l.negative else: logger.error('wrong ref_l in shp_stadium_wire_dir') # ----- Distance vectors on axis_s # distance from 1 to 2 in axis_s fc_1_2_s = DraftVecUtils.scale(axis_s, -radius) fc_1_3_s = fc_1_2_s.negative() #fc_2_3_s = DraftVecUtils.scale(axis_s, 2*radius) # ----- reference to 1 on axis_s #d vector to go from the reference point to point 1 in s if ref_s == 1: # ref on stadium center refto_1_s = V0 elif ref_s == 2: # ref at the bottom refto_1_s = fc_1_3_s # or fc_1_2_s.negative() else: logger.error('wrong ref_l in shp_stadium_wire_dir') # Now define the center point of the stadium. This is an absolute position, # and everything will be defined from this point # ln: L axis Negative side # lp: L axis Positive side # sn: S axis Negative side # sp: S axis Positive side # s0: S axis at zero # # axis_s # ln_sp : # ____:____lp_sp # / \ # ln_s0 cs ) lp_s0 -------> axis_l # \__________/ # ln_sn lp_sn # # axis_s: 1, 2, 3 are the points in s # ____:_____ # / 3 \ # 3 2 1 4 5 --> axis_l: 3, 2, 1, are the points in l # \____2_____/ # # # Define these 6 points from cs_pos (Center Stadium pos) cs_pos = pos + refto_1_l + refto_1_s ln_s0_pos = cs_pos + fc_1_3_l lp_s0_pos = cs_pos + fc_1_5_l ln_sp_pos = cs_pos + fc_1_2_l + fc_1_3_s lp_sp_pos = cs_pos + fc_1_4_l + fc_1_3_s ln_sn_pos = cs_pos + fc_1_2_l + fc_1_2_s lp_sn_pos = cs_pos + fc_1_4_l + fc_1_2_s # In Freecad 0.17 Line is an infinite Line, change to LineSegment lin_p = Part.LineSegment(ln_sp_pos, lp_sp_pos).toShape() arch_p = Part.Arc(lp_sp_pos, lp_s0_pos, lp_sn_pos).toShape() lin_n = Part.LineSegment(lp_sn_pos, ln_sn_pos).toShape() arch_n = Part.Arc(ln_sn_pos, ln_s0_pos, ln_sp_pos).toShape() wire_stadium = Part.Wire ([lin_p, arch_p, lin_n, arch_n]) #Part.show(wire_stadium) return (wire_stadium)
[docs]def shp_stadium_dir ( length, radius, height, fc_axis_h = VZ, fc_axis_l = VX, fc_axis_s = V0, ref_l = 1, ref_s = 1, ref_h = 1, xtr_h = 0, xtr_nh = 0, pos=V0): """ Makes a stadium shape in any direction :: fc_axis_s : :_________ ref_l = 2, ref_s = 1 / \ 3 2 1 ) -------> fc_axis_l 5\_____4____/ fc_axis_h _:___________ ............................ | | : | | : | 1 | ref_h=1 + h | | : |______2______|.......> fc_axis_l .........: ref_h=2 Parameters ---------- length : float Length of the parallels (distance between semcircle centers) height : float Height the stadium fc_axis_s : FreeCAD.Vector Direction on the short axis, not necessary if ref_s == 1 it will be the perpendicular of the other 2 vectors fc_axis_h : FreeCAD.Vector Vector on the height direction ref_l : int Reference (zero) of the fc_axis_l * 1: reference on the center (makes axis_s symmetrical) * 2: reference at one of the semicircle centers (point 2) the other circle center will be on the direction of fc_axis_l * 3: reference at the end (point 3) the other end will be on the direction of fc_axis_l ref_s : int Reference (zero) of the fc_axis_s * 1: reference at the center (makes axis_l symmetrical): p 1,2,3 * 2: reference at the parallels lines: p: 4, 5 the other parallel will be on the direction of fc_axis_s ref_h : int * 1: reference is at the center of the height * 2: reference is at the bottom xtr_h : float If >0 it will be that extra height on the direction of fc_axis_h xtr_nh : float If >0 it will be that extra height on the opositve direction of fc_axis_h pos : FreeCAD.Vector Placement Returns -------- Shape FreeCAD Shape of a stadium """ # normalize the axis axis_l = DraftVecUtils.scaleTo(fc_axis_l,1) axis_h = DraftVecUtils.scaleTo(fc_axis_h,1) axis_h_n = axis_h.negative() if fc_axis_s == V0: axis_s = axis_l.cross(axis_h) else: axis_s = DraftVecUtils.scaleTo(fc_axis_s,1) if ref_h == 1: # we have to move the stadium half the height down + xtr_nh basepos = pos + DraftVecUtils.scale(axis_h_n, height/2. + xtr_nh) else: basepos = pos + DraftVecUtils.scale(axis_h_n, xtr_nh) shp_stadium_wire = shp_stadium_wire_dir (length=length, radius=radius, fc_axis_l = axis_l, fc_axis_s = axis_s, ref_l = ref_l, ref_s = ref_s, pos = basepos) # make a face of the wire shp_stadium_face = Part.Face (shp_stadium_wire) # extrude it dir_extrud = DraftVecUtils.scaleTo(axis_h, height + xtr_nh + xtr_h) shp_stadium = shp_stadium_face.extrude(dir_extrud) return (shp_stadium)
#shp_std = shp_stadium_dir ( # length=20, radius=5, height=40, # fc_axis_l = VX, # #fc_axis_s = VY, # fc_axis_h = VZ, # ref_l = 2, # ref_s = 1, # ref_h = 2, # #xtr_h = 0, # xtr_nh = 1, # pos=FreeCAD.Vector(0,0,-1))
[docs]def shp_2stadium_dir ( length, r_s, r_l, h_tot, h_rl, fc_axis_h = VZ, fc_axis_l = VX, ref_l = 1, rl_h0 = 1, xtr_h = 0, xtr_nh = 0, pos=V0): """ Makes to concentric stadiums, useful for making rails for bolts the length is the same for both. Changes the radius and the height The smaller radius will have the largest length :: rl_h0 = 1: the large stadium is at h=0 fc_axis_h ________:________...................... | : : | : | : : | : ___| : : |___ ........ + h_tot | : : | : h_rl : |_______:____*____:_______|........:.......: ......> fc_axis_l : : : : :...:.+.:.........: : r_s: lenght : : : : :.r_l...: rl_h0 = 0 : the large stadium is at the end of h fc_axis_h ____________:____________.............. | : : | : h_rl : |___ : : ___|....: : | : : | :+ h_tot : | : : | : : |___:____*____:___|................: ......> fc_axis_l : : : : :...:.+.:.........: : r_s: length : : : : :.r_l...: on the axis_h, the h_rl stadium can be at the reference, or at the end of the reference (rl_h0 =0):: ref_l points: fc_axis_s : :_________ / \ ( 2 1 ) -------> fc_axis_l \__________/ Parameters ---------- length : float Length of the parallels, from one semicircle center to the other r_s : float Smaller radius of the semicircles r_l : float Larger radius of the semicircles h_tot : float Total height h_rl : float Height of the larger radius stadium fc_axis_h : FreeCAD.Vector Vector on the direction of the height fc_axis_l : FreeCAD.Vector Vector on the direction of the parallels, ref_l : int Reference (zero) of the fc_axis_l * 1: reference on the center (makes axis_s symmetrical) * 2: reference at one of the semicircle centers (point 2) the other circle center will be on the direction of fc_axis_l rl_h0 : int * 1: if the larger radius stadium is at the beginning of the axis_h * 0: at the end of axis_h xtr_h : float If >0 it will be that extra height on the direction of fc_axis_h xtr_nh : float If >0 it will be that extra height on the opositve direction of fc_axis_h xtr_nh : float pos : FreeCAD.Vector Position of the reference Returns -------- Shape FreeCAD Shape of a two stadiums """ # normalize the axis_h axis_h = DraftVecUtils.scaleTo(fc_axis_h,1) # the r_s (smaller radius ) stadium goes all over the height if not (ref_l == 1 or ref_l == 2): logger.error('wrong value for ref_l') if rl_h0 == 1: # the larger stadium is at the beginning: pos_rl = pos axis_h_rl = axis_h # no extra for the shorter stadium, so the surfaces are not in the # same plane xtr_nh_rs = 0 xtr_h_rs = xtr_h xtr_nh_rl = xtr_nh xtr_h_rl = 0 # no extra on positive side, because it is inside else: pos_rl = pos + DraftVecUtils.scale(axis_h, h_tot) axis_h_rl = axis_h.negative() xtr_nh_rs = xtr_nh xtr_h_rs = 0 xtr_nh_rl = xtr_h xtr_h_rl = 0 # no extra on positive side because is inside shp_stadium_rs = shp_stadium_dir(length = length, radius = r_s, height = h_tot, fc_axis_l = fc_axis_l, fc_axis_h = axis_h, ref_l = ref_l, ref_s = 1, ref_h = 2, #ref at the end xtr_h = xtr_h_rs, xtr_nh = xtr_nh_rs, pos = pos) shp_stadium_rl = shp_stadium_dir(length = length, radius = r_l, height = h_rl, fc_axis_l = fc_axis_l, fc_axis_h = axis_h_rl, ref_l = ref_l, ref_s = 1, ref_h = 2, #ref at the end xtr_h = xtr_h_rl, xtr_nh = xtr_nh_rl, pos = pos_rl) shp_2stadium = shp_stadium_rs.fuse(shp_stadium_rl) shp_2stadium = shp_2stadium.removeSplitter() return (shp_2stadium)
#shp_2std = shp_2stadium_dir ( # length = 20, r_s = 10, r_l = 15, # h_tot = 30, h_rl = 10, # fc_axis_h = VZ, # fc_axis_l = VX, # ref_l = 2, # rl_h0 = 2, # xtr_h = 0, # xtr_nh = 3, # pos=V0) # ------------------- def shp_belt_wire_dir
[docs]def shp_belt_wire_dir (center_sep, rad1, rad2, fc_axis_l = VX, fc_axis_s = VY, ref_l = 1, ref_s = 1, pos=V0): """ Makes a shape of a wire with 2 circles and exterior tangent lines check `here <https://en.wikipedia.org/wiki/Tangent_lines_to_circles>`_ It is not easy to draw it well rad1 and rad2 can be exchanged, rad1 doesnt have to be larger:: .... fc_axis_s : ( \ tangent | rad1 : ( \ .. rad2 |--> fc_axis_l, on the direction of rad2 .--( + +)-- ( /: ( / : : : :...: + center_sep .... fc_axis_s : ( \ tangent | rad1 : ( \ .. rad2 | --( + +)-- |--> fc_axis_l, on the direction of rad2 ( /: centered on this axis ( / : : : :...: ref_l: 3 2 1 Parameters ---------- center_sep : float Separation of the circle centers rad1 : float Radius of the firs circle, on the opposite direction of fc_axis_l fc_axis_l : FreeCAD.Vector Vector on the direction circle centers, pointing to rad2 fc_axis_s : FreeCAD.Vector Vector on the direction perpendicular to fc_axis_l, on the plane of the wire ref_l : int Reference (zero) of the fc_axis_l * 1: reference on the center * 2: reference at one of the semicircle centers (point 2) the other circle center will be on the direction of fc_axis_l * 3: reference at the end of rad1 circle the other end will be on the direction of fc_axis_l pos : FreeCAD.Vector Position of the reference Returns -------- Shape Wire FreeCAD Wire of a belt """ # normalize the axis axis_l = DraftVecUtils.scaleTo(fc_axis_l,1) axis_s = DraftVecUtils.scaleTo(fc_axis_s,1) # .... fc_axis_s # : ( \ tangent | # rad1 : ( \ .. rad2 | # --3 2 1 45-- |--> fc_axis_l, on the direction of rad2 # ( /: centered on this axis # ( / : # : : # :...: # + center_sep # ----- Distance vectors on axis_l # distance from 1 to 2 in axis_l fc_1_2_l = DraftVecUtils.scale(axis_l, -center_sep/2.) fc_2_3_l = DraftVecUtils.scale(axis_l, -rad1) fc_2_4_l = DraftVecUtils.scale(axis_l, center_sep) fc_4_5_l = DraftVecUtils.scale(axis_l, rad2) fc_2_5_l = fc_2_4_l + fc_4_5_l # ----- reference is point 2 on axis_l # vector to go from the reference point to point 2 in l if ref_l == 1: # ref on circle center sep refto_2_l = fc_1_2_l elif ref_l == 2: # ref on circle center (rad1) refto_2_l = V0 elif ref_l == 3: # ref at the left end refto_2_l = fc_2_3_l.negative() else: logger.error('wrong ref_l in shp_belt_wire_dir') # Now define the center of the rad1 circle # and everything will be defined from this point # ln: L axis Negative side # lp: L axis Positive side # sn: S axis Negative side # sp: S axis Positive side # s0: S axis at zero # # .... ln_sp fc_axis_s # : ( \ tangent | # rad1 : ( \ lp_sp | # ln_s0 2 4lp_s0 |--> fc_axis_l, on the direction of rad2 # ( / lp_sn centered on this axis # ( / # lp_sp # # cs_rad1 is point 2 (center of circle 1) cs_rad1 = pos + refto_2_l # cs_rad2 is point 4 (center of circle 2) cs_rad2 = cs_rad1 + fc_2_4_l # ln_s0 is point 3 ln_s0_pos = cs_rad1 + fc_2_3_l # lp_s0 is point 5 lp_s0_pos = cs_rad2 + fc_4_5_l dif_rad = float(abs(rad1 - rad2)) # Since we take our reference on axis_l, they are aligned, like if they were # on axis X, and axis Y would be zero. # therefore, angle gamma is zero (se wikipedia) # check: https://en.wikipedia.org/wiki/Tangent_lines_to_circles # the angle beta of the tanget is calculate from pythagoras: # the length (separation between centers) and dif_rad beta = math.atan (dif_rad/center_sep) print('beta %f', 180*beta/math.pi) print('beta %f', beta*math.pi/2) # depending on who is larger rad1 or rad2, the negative angle will be either # on top or down of axis_s # # ( \ # ( /alfa beta\ which is 90-beta # ( ) # ( / # ( / # cos_beta = math.cos(beta) sin_beta = math.sin(beta) tan_axis_s_rad1add = DraftVecUtils.scale(axis_s, rad1 * cos_beta) tan_axis_s_rad2add = DraftVecUtils.scale(axis_s, rad2 * cos_beta) if rad1 > rad2: # then it will be positive on axis_l on rad1 and rad2 tan_axis_l_rad1add = DraftVecUtils.scale(axis_l, rad1 * sin_beta) tan_axis_l_rad2add = DraftVecUtils.scale(axis_l, rad2 * sin_beta) else: tan_axis_l_rad1add = DraftVecUtils.scale(axis_l, - rad1 * sin_beta) tan_axis_l_rad2add = DraftVecUtils.scale(axis_l, - rad2 * sin_beta) ln_sp_pos = cs_rad1 + tan_axis_l_rad1add + tan_axis_s_rad1add ln_sn_pos = cs_rad1 + tan_axis_l_rad1add + tan_axis_s_rad1add.negative() lp_sp_pos = cs_rad2 + tan_axis_l_rad2add + tan_axis_s_rad2add lp_sn_pos = cs_rad2 + tan_axis_l_rad2add + tan_axis_s_rad2add.negative() # In Freecad 0.17 Line is an infinite Line, change to LineSegment lin_p = Part.LineSegment(ln_sp_pos, lp_sp_pos).toShape() arch_p = Part.Arc(lp_sp_pos, lp_s0_pos, lp_sn_pos).toShape() lin_n = Part.LineSegment(lp_sn_pos, ln_sn_pos).toShape() arch_n = Part.Arc(ln_sn_pos, ln_s0_pos, ln_sp_pos).toShape() wire_belt = Part.Wire ([lin_p, arch_p, lin_n, arch_n]) #Part.show(wire_belt) return (wire_belt)
#belt_wire = shp_belt_wire_dir (center_sep = 70, rad1= 20, rad2=30, # fc_axis_l = VX, # fc_axis_s = VY, # ref_l = 1, # pos=FreeCAD.Vector(1,2,3))
[docs]def shp_belt_dir (center_sep, rad1, rad2, height, fc_axis_h = VZ, fc_axis_l = VX, ref_l = 1, ref_h = 1, xtr_h = 0, xtr_nh = 0, pos=V0): """ Makes a shape of 2 tangent circles (like a belt joining 2 circles). check shp_belt_wire_dir Parameters ---------- center_sep : float Separation of the circle centers rad1 : float Radius of the first circle, on the opposite direction of fc_axis_l rad2 : float Radius of the second circle, on the direction of fc_axis_l height : float Height of the shape fc_axis_l : FreeCAD.Vector Vector on the direction circle centers, pointing to rad2 fc_axis_h : FreeCAD.Vector Vector on the hieght direction ref_l : int Reference (zero) of the fc_axis_l * 1: reference on the center * 2: reference at rad1 semicircle centers (point 2) the other circle center will be on the direction of fc_axis_l * 3: reference at the end of rad1 circle the other end will be on the direction of fc_axis_l ref_h : int * 1: reference is at the center of the height * 2: reference is at the bottom xtr_h : float If >0 it will be that extra height on the direction of fc_axis_h xtr_nh : float If >0 it will be that extra height on the opositve direction of fc_axis_h pos : FreeCAD.Vector Position of the reference Returns -------- Shape FreeCAD Shape of a belt """ # normalize the axis axis_l = DraftVecUtils.scaleTo(fc_axis_l,1) axis_h = DraftVecUtils.scaleTo(fc_axis_h,1) axis_h_n = axis_h.negative() axis_s = axis_l.cross(axis_h) if ref_h == 1: # we have to move the stadium half the height down + xtr_nh basepos = pos + DraftVecUtils.scale(axis_h_n, height/2. + xtr_nh) else: basepos = pos + DraftVecUtils.scale(axis_h_n, xtr_nh) shp_belt_wire = shp_belt_wire_dir (center_sep = center_sep, rad1 = rad1, rad2 = rad2, fc_axis_l = axis_l, fc_axis_s = axis_s, ref_l = ref_l, pos=basepos) # make a face of the wire shp_belt_face = Part.Face (shp_belt_wire) # extrude it dir_extrud = DraftVecUtils.scaleTo(axis_h, height + xtr_nh + xtr_h) shp_belt = shp_belt_face.extrude(dir_extrud) return (shp_belt)
#belt_shp = shp_belt_dir (center_sep = 70, rad1= 20, rad2=30, height = 10, # fc_axis_l = VX, # fc_axis_h = VZ, # ref_l = 1, # ref_h = 1, # xtr_h = 0, # xtr_nh = 0, # pos=V0); #Part.show(belt_shp)
[docs]def shp_hollowbelt_dir (center_sep, rad1, rad2, rad_thick, height, fc_axis_h = VZ, fc_axis_l = VX, ref_l = 1, ref_h = 1, xtr_h = 0, xtr_nh = 0, pos=V0): """ Makes a shape of 2 tangent circles (like a belt joining 2 circles). check shp_belt_wire_dir Parameters ---------- center_sep : float Separation of the circle centers rad1 : float Internal radius of the first circle, on the opposite direction of fc_axis_l rad2 : float Internal radius of the second circle, on the direction of fc_axis_l rad_thick : float Increment to rad1 and rad2 to make the thickness. height : float Height of the shape fc_axis_l : FreeCAD.Vector Vector on the direction circle centers, pointing to rad2 fc_axis_h : FreeCAD.Vector Vector on the hieght direction ref_l : int Reference (zero) of the fc_axis_l * 1: reference on the center * 2: reference at one of the semicircle centers (point 2) the other circle center will be on the direction of fc_axis_l * 3: reference at the end of rad1 circle the other end will be on the direction of fc_axis_l ref_h : int * 1: reference is at the center of the height * 2: reference is at the bottom xtr_h : float If >0 it will be that extra height on the direction of fc_axis_h xtr_nh : float If >0 it will be that extra height on the opositve direction of fc_axis_h pos : FreeCAD.Vector Position of the reference Returns -------- Shape FreeCAD Shape """ belt_shp = shp_belt_dir (center_sep = center_sep, rad1=rad1+rad_thick, rad2=rad2+rad_thick, height =height, fc_axis_l = fc_axis_l, fc_axis_h = fc_axis_h, ref_l = ref_l, ref_h = ref_h, xtr_h = xtr_h, xtr_nh = xtr_nh, pos=pos); belt_shp_hole = shp_belt_dir (center_sep = center_sep, rad1=rad1, rad2=rad2, height =height, fc_axis_l = fc_axis_l, fc_axis_h = fc_axis_h, ref_l = ref_l, ref_h = ref_h, xtr_h = xtr_h+1, xtr_nh = xtr_nh+1, pos=pos); shp_belthole = belt_shp.cut(belt_shp_hole) shp_belthole = shp_belthole.removeSplitter() #Part.show(shp_belthole) return(shp_belthole)
#shp_belthollow = shp_hollowbelt_dir ( # center_sep = 70, rad1= 50, rad2=30, # rad_thick = 4, # height = 10, # fc_axis_l = VX, # fc_axis_h = VZ, # ref_l = 2, # ref_h = 1, # xtr_h = 0, # xtr_nh = 0, # pos=V0); # ------------------- def shpRndRectWire # Creates a wire (shape), that is a rectangle with rounded edges. # if r== 0, it will be a rectangle # x: dimension of the base, on the X axis # y: dimension of the height, on the Y axis # r: radius of the rouned edge. # The wire will be centered # # Y # |_ X # # ______ ___ y # / \ r # | | # | | z=0 # | | # \______/ ___ # # |_______| x
[docs]def shpRndRectWire (x=1, y=1, r= 0.5, zpos = 0): """ Creates a wire (shape), that is a rectangle with rounded edges. if r== 0, it will be a rectangle The wire will be centered :: Y |_ X ______ ___ y / \ r | | | | z=0 | | \______/ ___ |_______| x Parameters ---------- x : float Dimension of the base, on the X axis y : float Dimension of the height, on the Y axis r : float Radius of the rouned edge. zpos : float Position on the Z axis Returns -------- Shape Wire FreeCAD Wire of a rounded edges rectangle """ #doc = FreeCAD.ActiveDocument if 2*r >= x or 2*r >= y: print("Radius too large: addRoundRectan") if x > y: r = y/2.0 - 0.1 # otherwise there will be a problem else: r = x/2.0 - 0.1 # points as if they were on X - Y # lyy # r_y rx_y # ______ # 0_ry / \ x_ry # | | # lx0 | | lxx # 0_r | | x_r # \______/ # r_0 rx_0 # ly0 x_0 = - x/2.0 x_r = r - x/2.0 x_rx = x/2.0 - r x_x = x/2.0 y_0 = - y/2.0 y_r = r - y/2.0 y_ry = y/2.0 - r y_y = y/2.0 # Lines: p_r_0 = FreeCAD.Vector(x_r, y_0, zpos) p_rx_0 = FreeCAD.Vector(x_rx, y_0, zpos) # toShape, because otherwise we couldn't make the wire. # by doing this we are creating an edge # an alternative would be to use makeLine # In Freecad 0.17 Line is an infinite Line, change to LineSegment ly0 = Part.LineSegment(p_r_0, p_rx_0).toShape() # Horizontal lower line p_x_r = FreeCAD.Vector(x_x ,y_r, zpos) p_x_ry = FreeCAD.Vector(x_x ,y_ry, zpos) lxx = Part.LineSegment(p_x_r, p_x_ry).toShape() # vertical on the right p_r_y = FreeCAD.Vector(x_r, y_y, zpos) p_rx_y = FreeCAD.Vector(x_rx, y_y, zpos) lyy = Part.LineSegment(p_r_y, p_rx_y).toShape() # Horizontal top line p_0_r = FreeCAD.Vector(x_0, y_r, zpos) p_0_ry = FreeCAD.Vector(x_0, y_ry, zpos) lx0 = Part.LineSegment(p_0_r, p_0_ry).toShape() # vertical on the left # if I wanted to see these shapes #fc_ly0 = doc.addObject("Part::Feature", "ly0") #fc_ly0.Shape = ly0 #fc_lxx = doc.addObject("Part::Feature", "lxx") #fc_lxx.Shape = lxx #fc_lyy = doc.addObject("Part::Feature", "lyy") #fc_lyy.Shape = lyy #fc_lx0 = doc.addObject("Part::Feature", "lx0") #fc_lx0.Shape = lx0 if r > 0: # center points of the 4 archs: pcarch_00 = FreeCAD.Vector (x_r, y_r,zpos) pcarch_x0 = FreeCAD.Vector (x_rx, y_r,zpos) pcarch_0y = FreeCAD.Vector (x_r, y_ry,zpos) pcarch_xy = FreeCAD.Vector (x_rx, y_ry,zpos) dircir = FreeCAD.Vector (0,0,1) # ALTERNATIVE 1: Making the OpenCascade shape, # and adding it to a Freecad Object arch_00 = Part.makeCircle (r, pcarch_00, dircir, 180, 270) arch_x0 = Part.makeCircle (r, pcarch_x0, dircir, 270, 0) arch_0y = Part.makeCircle (r, pcarch_0y, dircir, 90, 180) arch_xy = Part.makeCircle (r, pcarch_xy, dircir, 0, 90) # freecad object #fc_arch_00 = doc.addObject("Part::Feature", "arch_00") #fc_arch_00.Shape = arch_00 #fc_arch_x0 = doc.addObject("Part::Feature", "arch_x0") #fc_arch_x0.Shape = arch_x0 #fc_arch_0y = doc.addObject("Part::Feature", "arch_0y") #fc_arch_0y.Shape = arch_0y #fc_arch_xy = doc.addObject("Part::Feature", "arch_xy") #fc_arch_xy.Shape = arch_xy # ALTERNATIVE 2: using the Part::Circle # you have to place it with Placement #cir_00 = doc.addObject("Part::Circle","cir_00") #cir_00.Angle0 = 180 #cir_00.Angle1 = 270 #cir_00.Radius = r #cir_00.Placement.Base = pcarch_00 # Make a wire # it seems that it matters the order # for this example, it doesnt work if I do Part.Shape as in the # example: # http://freecadweb.org/wiki/index.php?title=Topological_data_scripting wire_rndrect = Part.Wire ([ lx0, arch_00, ly0, arch_x0, lxx, arch_xy, lyy, arch_0y ]) else: # just a rectangle wire_rndrect = Part.Wire ([ lx0, ly0, lxx, lyy, ]) return wire_rndrect
# same as shpRndRectWire, but returns a face
[docs]def shp_rndrect_face (x, y, r=0.5, pos_z=0): """ Same as shpRndRectWire Parameters ---------- x : float Dimension of the base, on the X axis y : float Dimension of the height, on the Y axis r : float Radius of the rouned edge. zpos : float Position on the Z axis Returns -------- Shape Face FreeCAD Face of a rounded edges rectangle """ shp_RndRectWire = shpRndRectWire (x, y, r=r, zpos= pos_z) shpRndRectFace = Part.Face (shp_RndRectWire) return shpRndRectFace
#doc = FreeCAD.newDocument() #wire1 = shp_stadium_wire (4, 2, axis_rect='y', pos_z=2) #wire1 = shpRndRectWire (x=10, y=12, r=0) #wire2 = shpaddRndRectWire (x=10-2, y=12-2, r= 0 ) #rndrect_1 = doc.addObject("Part::Feature", "rndrect_1") #rndrect_1.Shape = wire1 #rndrect_2 = doc.addObject("Part::Feature", "rndrect_2") #rndrect_2.Shape = wire2 #face1 = Part.Face(wire1) #face2 = Part.Face(wire2) #cut = face1.cut(face2) #extr = cut.extrude(Base.Vector(0,0,5)) #Part.show(extr) #extr_rndrect = doc.addObject("Part::Extrusion", name) #extr_rndrect.Base = rndrect #extr_rndrect.Dir = (0,0,2) #extr_rndrect.Solid = True #shp_rndrect = Part.Shape #fc_rndrect = doc.addObject("Part::Feature", "fc_rndrect") #fc_rndrect.Shape = shp_rndrect #doc.recompute() # ------------------- def wire_sim_xy # Creates a wire (shape), from a list of points on the positive quadrant of XY # the wire is simmetrical to both X and Y # vecList: list of FreeCAD Vectors, the have to be in order clockwise # if the first or the last points are not on the axis, a new point will be # created # # Y # |_ X # # __|__ # / | \ We receive these points # | | | # | |-------- z=0 # | | # \_____/ #
[docs]def wire_sim_xy (vecList): """ Creates a wire (shape), from a list of points on the positive quadrant of XY the wire is simmetrical to both X and Y :: Y |_ X __|__ / | \ We receive these points | | | | |-------- z=0 | | \_____/ Parameters ---------- vecList : list List of FreeCAD Vectors, the have to be in order clockwise if the first or the last points are not on the axis, a new point will be created """ edgList = [] if vecList[0].x != 0: # the first element is not on the Y axis,so we create a first point vec = FreeCAD.Vector (0, vecList[0].y, vecList[0].z) # In Freecad 0.17 Line is an infinite Line, change to LineSegment seg = Part.LineSegment(vec, vecList[0]) # segment edg = seg.toShape() # edge edgList.append(edg) # append to the edge list listlen = len(vecList) for index, vec in enumerate(vecList): if vec.x < 0 or vec.y < 0: logger.error('WireSimXY with negative points') if index < listlen-1: # it is not the last element seg = Part.LineSegment(vec, vecList[index+1]) edg = seg.toShape() edgList.append(edg) index += 1 if vecList[-1].y != 0: # the last element is not on the X axis vec = FreeCAD.Vector (vecList[-1].x, 0, vecList[-1].z) seg = Part.LineSegment(vecList[-1], vec) edg = seg.toShape() edgList.append(edg) # the wire for the first cuadrant, quarter quwire = Part.Wire(edgList) # mirror on Y axis MirY = FreeCAD.Matrix() MirY.scale(FreeCAD.Vector(-1,1,1)) mir_quwire = quwire.transformGeometry(MirY) # another option # mir_quwire = quwire.mirror(FreeCAD.Vector(0,0,0), FreeCAD.Vector(1,0,0)) #halfwire = Part.Wire([quwire, mir_quwire]) # get the half wire halfwire = Part.Wire([mir_quwire, quwire]) # get the half wire # otherwise it doesnt work because the edges are not aligned halfwire.fixWire() # mirror on X axis MirX = FreeCAD.Matrix() MirX.scale(FreeCAD.Vector(1,-1,1)) mir_halfwire = halfwire.transformGeometry(MirX) totwire = Part.Wire([mir_halfwire, halfwire]) # get the total wire totwire.fixWire() return totwire
# ------------------- end def wire_sim_xy # ------------------- def wire_cableturn
[docs]def wire_cableturn (d, w, corner_r, conn_d, conn_sep, xtr_conn_d = 0, closed = 0, axis_d = VY, axis_w = VX, pos_d = 0, pos_w = 0, pos=V0): """ Creates a electrical wire turn, in any direction But it is a wire in FreeCAD, has no volumen :: axis_d : : .....:w ..... : : : pos_d ____________ ...... .. 3 / \ :..corner_r | | : | | : | | + d 2 | | : | | : | | : \___ o ____/ ......: 1 \ / : | | + conn_d | | : | |............:...........axis_w 0 : : conn_sep 1 0 pos_w pos_o (orig) is at pos_d=0, pos_w=0, marked with o Parameters ---------- d : float Depth/length of the turn w : float Width of the turn corner_r : float Radius of the corners conn_d : float Depth/length of the connector part * 0: there is no connecting wire xtr_conn_d : float If conn_d > 0, there can be and extra length of connector to make unions, it will not be counted as pos_d = 0 It will not work well if it is closed conn_sep : float Separation of the connectors closed : boolean * 0 : the ends are not closed * 1 : the ends are closed axis_d : FreeCAD.Vector Coordinate System Vector along the depth axis_w : FreeCAD.Vector Coordinate System Vector along the width pos_d : int Location of pos along the axis_d (0,1,2,3), see drawing * 0: reference at the beginning of the connector * 1: reference at the beginning of the turn, at the side of the connector * 2: reference at the middle of the turn * 3: reference at the end of the turn pos_w : int Location of pos along the axis_w (0,1), see drawing * 0: reference at the center of simmetry * 1: reference at the end of the turn pos : FreeCAD.Vector Position of the reference Returns -------- Shape Wire FreeCAD Wire of a electrical wire """ # normalize the axis axis_d = DraftVecUtils.scaleTo(axis_d,1) axis_w = DraftVecUtils.scaleTo(axis_w,1) d_o = {} # distances from the pos_o to pos_d d_o[0] = DraftVecUtils.scale(axis_d, -conn_d) d_o[1] = V0 d_o[2] = DraftVecUtils.scale(axis_d, d/2.) d_o[3] = DraftVecUtils.scale(axis_d, d) xtr_conn_d_vec = DraftVecUtils.scale(axis_d, -xtr_conn_d) w_o = {} # distances from the pos_o to pos_w w_o[0] = V0 w_o[1] = DraftVecUtils.scale(axis_w, -w/2.) # reference position pos_o = pos + d_o[pos_d].negative() + w_o[pos_w].negative() if (2 * corner_r + conn_sep >= w ) or (2 * corner_r >= d): corner_r = min(d/2.1,(w-conn_sep)/4.1) logger.warning('radius too large, taking:' + str(corner_r)) # w_t # ____________ ..... .. 3 # /B C\ :..corner_r # | | : # | | : # w_l | | w_r + d 2 # | | : # | | : # | A D| : # \___ ____/ ......: 1 # \ / : # | | + conn_d # | | : # \_/............:...........axis_w 0 # # Define the 4 corners 0, 1, 2, 3, that are at the center of the radius # of the corners # vector with length of the radius along axis_w d_rad = DraftVecUtils.scale(axis_d, corner_r) d_rad_n = d_rad.negative() w_rad = DraftVecUtils.scale(axis_w, corner_r) w_rad_n = w_rad.negative() # vector with half the length of the separation of connectors along axis_w w_hsep = DraftVecUtils.scale(axis_w, conn_sep/2.) w_hsep_n = w_hsep.negative() pt_A = pos_o + d_o[1] + w_o[1] + d_rad + w_rad pt_B = pos_o + d_o[3] + w_o[1] + d_rad_n + w_rad pt_C = pos_o + d_o[3] + w_o[1].negative() + d_rad_n + w_rad_n pt_D = pos_o + d_o[1] + w_o[1].negative() + d_rad + w_rad_n if corner_r > 0 : corner_r45 = corner_r/math.sqrt(2) d_rad45 = DraftVecUtils.scale(axis_d, corner_r45) d_rad45_n = d_rad45.negative() w_rad45 = DraftVecUtils.scale(axis_w, corner_r45) w_rad45_n = w_rad45.negative() pt_A1 = pt_A + d_rad_n pt_A2 = pt_A + d_rad45_n + w_rad45_n pt_A3 = pt_A + w_rad_n corner_A = Part.Arc(pt_A1, pt_A2, pt_A3).toShape() pt_B1 = pt_B + w_rad_n pt_B2 = pt_B + d_rad45 + w_rad45_n pt_B3 = pt_B + d_rad corner_B = Part.Arc(pt_B1, pt_B2, pt_B3).toShape() pt_C1 = pt_C + d_rad pt_C2 = pt_C + d_rad45 + w_rad45 pt_C3 = pt_C + w_rad corner_C = Part.Arc(pt_C1, pt_C2, pt_C3).toShape() pt_D1 = pt_D + w_rad pt_D2 = pt_D + d_rad45_n + w_rad45 pt_D3 = pt_D + d_rad_n corner_D = Part.Arc(pt_D1, pt_D2, pt_D3).toShape() # In Freecad 0.17 Line is an infinite Line, change to LineSegment line_AB = Part.LineSegment(pt_A3, pt_B1).toShape() line_BC = Part.LineSegment(pt_B3, pt_C1).toShape() line_CD = Part.LineSegment(pt_C3, pt_D1).toShape() top_wire = Part.Wire([corner_A, line_AB, corner_B, line_BC, corner_C, line_CD, corner_D]) top_wire_firstpt = pt_A1 top_wire_lastpt = pt_D3 if conn_d == 0: # the turn ends here: if closed == 1: line_bot = Part.LineSegment(pt_D3, pt_A1).toShape() cable_wire = Part.Wire([line_bot,top_wire,]) else: # # | A D| # \___E F___/ # pt_E = pos_o + w_hsep_n pt_F = pos_o + w_hsep line_EA = Part.LineSegment(pt_E, pt_A1).toShape() line_DF = Part.LineSegment(pt_D3, pt_F).toShape() cable_wire = Part.Wire([line_EA,top_wire, line_DF]) else : if conn_d < corner_r : conn_d = corner_r * 1.1 logger.warning('radius larger than connector length') logger.warning('making it: ' + str(conn_d)) logger.warning('Distances mabe be WRONG') # Points E1, E2, E3, F1, F2, F3: pt_E = pos_o + w_hsep_n + d_rad_n + w_rad_n # radius center pt_F = pos_o + w_hsep + d_rad_n + w_rad # radius center # E3 is the closest to A pt_E3 = pt_E + d_rad pt_E2 = pt_E + d_rad45 + w_rad45 pt_E1 = pt_E + w_rad # F1 is the closest to D pt_F3 = pt_F + w_rad_n pt_F2 = pt_F + d_rad45 + w_rad45_n pt_F1 = pt_F + d_rad corner_E = Part.Arc(pt_E1, pt_E2, pt_E3).toShape() corner_F = Part.Arc(pt_F1, pt_F2, pt_F3).toShape() line_EA = Part.LineSegment(pt_E3, pt_A1).toShape() line_DF = Part.LineSegment(pt_D3, pt_F1).toShape() pt_G = pos_o + w_hsep_n + d_o[0] + xtr_conn_d_vec pt_H = pos_o + w_hsep + d_o[0] + xtr_conn_d_vec line_GE = Part.LineSegment(pt_G, pt_E1).toShape() line_FH = Part.LineSegment(pt_F3, pt_H).toShape() cable_wire = Part.Wire([line_GE, corner_E, line_EA,top_wire, line_DF, corner_F, line_FH]) if closed == 1: line_HG = Part.LineSegment(pt_H, pt_G).toShape() cable_wire = Part.Wire([cable_wire, line_HG]) else : # no corners line_AB = Part.LineSegment(pt_A, pt_B).toShape() line_BC = Part.LineSegment(pt_B, pt_C).toShape() line_CD = Part.LineSegment(pt_C, pt_D).toShape() top_wire = Part.Wire([line_AB, line_BC,line_CD]) top_wire_firstpt = pt_A top_wire_lastpt = pt_D # points E - F # | | # |____E F___| # if conn_d == 0: # the turn ends here: if closed == 1: line_bot = Part.LineSegment(pt_D, pt_A).toShape() cable_wire = Part.Wire([line_bot,top_wire,]) else : pt_E = pos_o + w_hsep_n pt_F = pos_o + w_hsep line_EA = Part.LineSegment(pt_E, pt_A).toShape() line_DF = Part.LineSegment(pt_D, pt_F).toShape() cable_wire = Part.Wire([line_EA,top_wire, line_DF]) else: pt_E = pos_o + w_hsep_n pt_F = pos_o + w_hsep line_EA = Part.LineSegment(pt_E, pt_A).toShape() line_DF = Part.LineSegment(pt_D, pt_F).toShape() # points E - F # | | # |____E F___| # | | # | | # G H pt_G = pt_E + d_o[0] + xtr_conn_d_vec pt_H = pt_F + d_o[0] + xtr_conn_d_vec line_GE = Part.LineSegment(pt_G, pt_E).toShape() line_FH = Part.LineSegment(pt_F, pt_H).toShape() cable_wire = Part.Wire([line_GE, line_EA,top_wire, line_DF, line_FH]) if closed == 1 : line_HG = Part.LineSegment(pt_H, pt_G).toShape() cable_wire = Part.Wire([cable_wire, line_HG]) #Part.show(cable_wire) return (cable_wire)
#cablewire= wire_cableturn (d=20, w=30, corner_r=1, # conn_d=4, conn_sep=3, # closed = 0, # axis_d = VY, # axis_w = VX, # pos_d = 0, # pos_w = 0, # pos=V0) # ------------------- def shp_cableturn
[docs]def shp_cableturn (d, w, thick_d, corner_r, conn_d, conn_sep, xtr_conn_d = 0, closed = 0, axis_d = VY, axis_w = VX, pos_d = 0, pos_w = 0, pos=V0): """ Creates a shape of an electrical cable turn, in any direction But it is a shape in FreeCAD See function wire_cableturn :: axis_d : : .....:w ..... : : : pos_d ____________ ...... .. 3 / \ :..corner_r | | : | | : | | + d 2 | | : | | : | | : \___ o ____/ ......: 1 \ / : | | + conn_d | | : | |............:...........axis_w 0 : : conn_sep 1 0 pos_w pos_o (orig) is at pos_d=0, pos_w=0, marked with o Parameters ---------- d : float Depth/length of the turn w : float Width of the turn thick_d : float Diameter of the wire corner_r : float Radius of the corners conn_d : float Depth/length of the connector part * 0: there is no connecting wire xtr_conn_d : float If conn_d > 0, there can be and extra length of connector to make unions, it will not be counted as pos_d = 0 It will not work well if it is closed conn_sep : float Separation of the connectors closed : boolean * 0 : the ends are not closed * 1 : the ends are closed axis_d : FreeCAD.Vector Coordinate System Vector along the depth axis_w : FreeCAD.Vector Coordinate System Vector along the width pos_d : int Location of pos along the axis_d (0,1,2,3), see drawing * 0: reference at the beginning of the connector * 1: reference at the beginning of the turn, at the side of the connector * 2: reference at the middle of the turn * 3: reference at the end of the turn pos_w : int Location of pos along the axis_w (0,1), see drawing * 0: reference at the center of simmetry * 1: reference at the end of the turn pos : FreeCAD.Vector Position of the reference Returns -------- Shape FreeCAD Shape of a electrical wire """ # normalize the axis axis_d = DraftVecUtils.scaleTo(axis_d,1) axis_w = DraftVecUtils.scaleTo(axis_w,1) cablewire = wire_cableturn (d=d, w=w, corner_r=corner_r, conn_d=conn_d, conn_sep=conn_sep, xtr_conn_d = xtr_conn_d, closed = closed, axis_d = axis_d, axis_w = axis_w, pos_d = pos_d, pos_w = pos_w, pos=pos) d_o = {} # distances from the pos_o to pos_d d_o[0] = DraftVecUtils.scale(axis_d, -conn_d) d_o[1] = V0 d_o[2] = DraftVecUtils.scale(axis_d, d/2.) d_o[3] = DraftVecUtils.scale(axis_d, d) w_o = {} # distances from the pos_o to pos_w w_o[0] = V0 w_o[1] = DraftVecUtils.scale(axis_w, -w/2.) # reference position pos_o = pos + d_o[pos_d].negative() + w_o[pos_w].negative() # the section of the wire at the end pos_d = 3 pos_section = pos_o + d_o[3] circle = Part.makeCircle (thick_d/2., pos_section, axis_w) wire_circle = Part.Wire(circle) face_circle = Part.Face(wire_circle) #shp_cable = cablewire.makePipe(wire_circle) # hollow tube #shp_cable = cablewire.makePipe(face_circle) # filled tube # filled tube # Is solid, Frenet, 0: defaul, 1: right corners, 2: rounded corners shp_cable = cablewire.makePipeShell([wire_circle], True, False, 2) #Part.show(shp_cable) return (shp_cable)
#shp_cable = shp_cableturn (d = 20, w=30, thick_d=1, # corner_r=1, # conn_d=4, conn_sep=3, # xtr_conn_d = 10, # closed = 0, # axis_d = VY, # axis_w = VX, # pos_d = 0, # pos_w = 0, # pos=V0) # ------------------- def wire_beltclamp
[docs]def wire_beltclamp (d, w, corner_r, conn_d, conn_sep, xtr_conn_d = 0, closed = 0, axis_d = VY, axis_w = VX, pos_d = 0, pos_w = 0, pos=V0): """ Creates a wire following 2 pulleys and ending in a belt clamp But it is a wire in FreeCAD, has no volumen :: axis_w : : pulley1 pulley2 ----------------------------------- ( ) ( )--------> axis_d ---------=== ( ) ( ) ===-------- clamp1 clamp2 1 0 2 3 45 67 8 9 10 11 pos_d : : : : : : : : : :............: : : + : : clamp_sep : : : :.................................: + pull_sep_d pos_w points: axis_w : pull2 : clamp1 clamp2 2_ 3- ( 1 ) - - pull_sep_w (positive) ( 0 ) - - - - - - - - - - - - - - - 5- - - 6 ___ ...................___.............:+ clamp_pull1_w (neg) 4- 7 < ) ( > :+ clamp_w 8 ___ ...................___.............: axis_w : pull2 : clamp1 clamp2 _ - ( ) - - pull_sep_w (positive) ( ) - - - - - - - - - - - - - - - - - - ___ ...................___.............:+ clamp_pull1_w (neg) - < ) ( > :+ clamp_w ___ ...................___.............: : : : :: : : : : : : : :cyl_r : : : : : : :...: :...: :.......: : : : + + : : + : : : clamp_cyl_sep : : + : : : : : clamp_pull2_d : : : :...: : : : : + : : :..................: clamp_d : : : + : : : clamp_sep : :...: : : + : : clamp_d : : :......: + clamp_pull1_d Parameters ---------- pull1_d : float Diameter of pulley 1 pull2_d : float Diameter of pulley 2 pull_sep_d : float Separation between the 2 pulleys centers along axis_d if positive, pulley 2 is further away in the direction of axis_d if negative, pulley 2 is further away opposite to the direction of axis_d pull_sep_w : float Separation between the 2 pulleys centers along axis_w if positive, pulley 2 is further away in the direction of axis_w if negative, pulley 2 is further away opposite to the direction of axis_w clamp_pull1_d : float Separation between the clamp (side closer to the center) and the center of the pulley1 clamp_pull1_w : float Separation between the center of the clamp and the center of the pulley1 if positive, the clamp is further away in the direction of axis_w if negative, the clamp is further away opposite to the direction of axis_w clamp_d : float Length of the clamp (same for each clamp) clamp_w : float Width of inner space (same for each clamp) clamp_sep : float Separation between clamps, the closest ends clamp_cyl_sep : float Separation between clamp and the center of the cylinder (or the center) of the larger cylinder (when is a belt shape) cyl_r : float Radius of the cylinder for the belt, if it is not a cylinder but a shape of 2 cylinders: < ) , then the raidius of the larger one axis_d : FreeCAD.Vector Coordinate System Vector along the depth axis_w : FreeCAD.Vector Coordinate System Vector along the width pos_d : int Location of pos along the axis_d, see drawing * 0: center of the pulley 1 * 1: end of pulley 1 * 2: end of clamp 1, closest end to pulley 1 * 3: other end of clamp 1, closest to cylinder * 4: center of cylinder (or shape < ) 1 * 5: external radius of cylinder 1 * 6: external radius of cylinder 2 * 7: center of cylinder (or shape ( > 2 * 8: end of clamp 2, closest to cylinder * 9: other end of clamp 2, closest end to pulley 2 * 10: center of pulley 2 * 11: end of pulley 2 pos_w : int Location of pos along the axis_w, see drawing * 0: center of pulley 1 * 1: center of pulley 2 * 2: end (radius) of pulley 1 along axis_w * 3: end (radius) of pulley 2 along axis_w * 4: other end (radius) of pulley 1 opposite to axis_w * 5: other end (radius) of pulley 2 opposite to axis_w * 6: clamp space, closest to the pulley * 7: center of clamp space * 8: clamp space, far away from the pulley pos : FreeCAD.Vector Position of the reference Returns -------- Shape Wire FreeCAD Wire of a belt clamped """ """ # normalize the axis axis_d = DraftVecUtils.scaleTo(axis_d,1) axis_w = DraftVecUtils.scaleTo(axis_w,1) d_o = {} # distances from the pos_o to pos_d d_o[0] = V0 d_o[1] = DraftVecUtils.scale(axis_d, -conn_d) d_o[2] = DraftVecUtils.scale(axis_d, d/2.) d_o[3] = DraftVecUtils.scale(axis_d, d) xtr_conn_d_vec = DraftVecUtils.scale(axis_d, -xtr_conn_d) w_o = {} # distances from the pos_o to pos_w w_o[0] = V0 w_o[1] = DraftVecUtils.scale(axis_w, -w/2.) # reference position pos_o = pos + d_o[pos_d].negative() + w_o[pos_w].negative() if (2 * corner_r + conn_sep >= w ) or (2 * corner_r >= d): corner_r = min(d/2.1,(w-conn_sep)/4.1) logger.warning('radius too large, taking:' + str(corner_r)) # w_t # ____________ ..... .. 3 # /B C\ :..corner_r # | | : # | | : # w_l | | w_r + d 2 # | | : # | | : # | A D| : # \___ ____/ ......: 1 # \ / : # | | + conn_d # | | : # \_/............:...........axis_w 0 # # Define the 4 corners 0, 1, 2, 3, that are at the center of the radius # of the corners # vector with length of the radius along axis_w d_rad = DraftVecUtils.scale(axis_d, corner_r) d_rad_n = d_rad.negative() w_rad = DraftVecUtils.scale(axis_w, corner_r) w_rad_n = w_rad.negative() # vector with half the length of the separation of connectors along axis_w w_hsep = DraftVecUtils.scale(axis_w, conn_sep/2.) w_hsep_n = w_hsep.negative() pt_A = pos_o + d_o[1] + w_o[1] + d_rad + w_rad pt_B = pos_o + d_o[3] + w_o[1] + d_rad_n + w_rad pt_C = pos_o + d_o[3] + w_o[1].negative() + d_rad_n + w_rad_n pt_D = pos_o + d_o[1] + w_o[1].negative() + d_rad + w_rad_n if corner_r > 0 : corner_r45 = corner_r/math.sqrt(2) d_rad45 = DraftVecUtils.scale(axis_d, corner_r45) d_rad45_n = d_rad45.negative() w_rad45 = DraftVecUtils.scale(axis_w, corner_r45) w_rad45_n = w_rad45.negative() pt_A1 = pt_A + d_rad_n pt_A2 = pt_A + d_rad45_n + w_rad45_n pt_A3 = pt_A + w_rad_n corner_A = Part.Arc(pt_A1, pt_A2, pt_A3).toShape() pt_B1 = pt_B + w_rad_n pt_B2 = pt_B + d_rad45 + w_rad45_n pt_B3 = pt_B + d_rad corner_B = Part.Arc(pt_B1, pt_B2, pt_B3).toShape() pt_C1 = pt_C + d_rad pt_C2 = pt_C + d_rad45 + w_rad45 pt_C3 = pt_C + w_rad corner_C = Part.Arc(pt_C1, pt_C2, pt_C3).toShape() pt_D1 = pt_D + w_rad pt_D2 = pt_D + d_rad45_n + w_rad45 pt_D3 = pt_D + d_rad_n corner_D = Part.Arc(pt_D1, pt_D2, pt_D3).toShape() # In Freecad 0.17 Line is an infinite Line, change to LineSegment line_AB = Part.LineSegment(pt_A3, pt_B1).toShape() line_BC = Part.LineSegment(pt_B3, pt_C1).toShape() line_CD = Part.LineSegment(pt_C3, pt_D1).toShape() top_wire = Part.Wire([corner_A, line_AB, corner_B, line_BC, corner_C, line_CD, corner_D]) top_wire_firstpt = pt_A1 top_wire_lastpt = pt_D3 if conn_d == 0: # the turn ends here: if closed == 1: line_bot = Part.LineSegment(pt_D3, pt_A1).toShape() cable_wire = Part.Wire([line_bot,top_wire,]) else: # # | A D| # \___E F___/ # pt_E = pos_o + w_hsep_n pt_F = pos_o + w_hsep line_EA = Part.LineSegment(pt_E, pt_A1).toShape() line_DF = Part.LineSegment(pt_D3, pt_F).toShape() cable_wire = Part.Wire([line_EA,top_wire, line_DF]) else : if conn_d < corner_r : conn_d = corner_r * 1.1 logger.warning('radius larger than connector length') logger.warning('making it: ' + str(conn_d)) logger.warning('Distances mabe be WRONG') # Points E1, E2, E3, F1, F2, F3: pt_E = pos_o + w_hsep_n + d_rad_n + w_rad_n # radius center pt_F = pos_o + w_hsep + d_rad_n + w_rad # radius center # E3 is the closest to A pt_E3 = pt_E + d_rad pt_E2 = pt_E + d_rad45 + w_rad45 pt_E1 = pt_E + w_rad # F1 is the closest to D pt_F3 = pt_F + w_rad_n pt_F2 = pt_F + d_rad45 + w_rad45_n pt_F1 = pt_F + d_rad corner_E = Part.Arc(pt_E1, pt_E2, pt_E3).toShape() corner_F = Part.Arc(pt_F1, pt_F2, pt_F3).toShape() line_EA = Part.LineSegment(pt_E3, pt_A1).toShape() line_DF = Part.LineSegment(pt_D3, pt_F1).toShape() pt_G = pos_o + w_hsep_n + d_o[0] + xtr_conn_d_vec pt_H = pos_o + w_hsep + d_o[0] + xtr_conn_d_vec line_GE = Part.LineSegment(pt_G, pt_E1).toShape() line_FH = Part.LineSegment(pt_F3, pt_H).toShape() cable_wire = Part.Wire([line_GE, corner_E, line_EA,top_wire, line_DF, corner_F, line_FH]) if closed == 1: line_HG = Part.LineSegment(pt_H, pt_G).toShape() cable_wire = Part.Wire([cable_wire, line_HG]) else : # no corners line_AB = Part.LineSegment(pt_A, pt_B).toShape() line_BC = Part.LineSegment(pt_B, pt_C).toShape() line_CD = Part.LineSegment(pt_C, pt_D).toShape() top_wire = Part.Wire([line_AB, line_BC,line_CD]) top_wire_firstpt = pt_A top_wire_lastpt = pt_D # points E - F # | | # |____E F___| # if conn_d == 0: # the turn ends here: if closed == 1: line_bot = Part.LineSegment(pt_D, pt_A).toShape() cable_wire = Part.Wire([line_bot,top_wire,]) else : pt_E = pos_o + w_hsep_n pt_F = pos_o + w_hsep line_EA = Part.LineSegment(pt_E, pt_A).toShape() line_DF = Part.LineSegment(pt_D, pt_F).toShape() cable_wire = Part.Wire([line_EA,top_wire, line_DF]) else: pt_E = pos_o + w_hsep_n pt_F = pos_o + w_hsep line_EA = Part.LineSegment(pt_E, pt_A).toShape() line_DF = Part.LineSegment(pt_D, pt_F).toShape() # points E - F # | | # |____E F___| # | | # | | # G H pt_G = pt_E + d_o[0] + xtr_conn_d_vec pt_H = pt_F + d_o[0] + xtr_conn_d_vec line_GE = Part.LineSegment(pt_G, pt_E).toShape() line_FH = Part.LineSegment(pt_F, pt_H).toShape() cable_wire = Part.Wire([line_GE, line_EA,top_wire, line_DF, line_FH]) if closed == 1 : line_HG = Part.LineSegment(pt_H, pt_G).toShape() cable_wire = Part.Wire([cable_wire, line_HG]) #Part.show(cable_wire) return (cable_wire) """
[docs]def regpolygon_vecl (n_sides, radius, x_angle=0): """ Calculates the vertexes of a regular polygon. Returns a list of FreeCAD vectors with the vertexes. The first vertex will be repeated at the end, this is needed to close the wire to make the shape The polygon will be on axis XY (z=0). Parameters ---------- n_sides : int Number of sides of the polygon radius : float Circumradius of the polygon x_angle : float If zero, the first vertex will be on axis x (y=0) if x_angle != 0, it will rotated some angle Returns -------- List List of FreeCAD.Vector of the vertexes """ v = FreeCAD.Vector(radius, 0, 0) if x_angle != 0: # rotate the polygon x_angle_rad = math.radians(x_angle) # uses radians, rotates around Z axis # It seems that the angle of the function is wrong, changing the sign v = DraftVecUtils.rotate2D(v,-x_angle_rad) vec_vertex_list = [v] # divide the 360 degrees by the number of sides polygon_angle = 2*math.pi / n_sides for i in xrange(n_sides): v = DraftVecUtils.rotate2D(v,polygon_angle) # the first vertex will be also the last one vec_vertex_list.append(v) return (vec_vertex_list)
[docs]def regpolygon_dir_vecl (n_sides, radius, fc_normal, fc_verx1, pos): """ Similar to regpolygon_vecl but in any place and direction of the space calculates the vertexes of a regular polygon. Returns a list of FreeCAD vectors with the vertexes. The first vertex will be repeated at the end, this is needed to close the wire to make the shape The polygon will have the center in pos. The normal on fc_normal The direction of the first vertex on fc_verx_1 Parameters ---------- n_sides : int Number of sides of the polygon radius : float Circumradius of the polygon fc_normal : FreeCAD.Vector Direction of the normal fc_verx1 : FreeCAD.Vector Direction of the first vertex pos : FreeCAD.Vector Position of the center Returns -------- List List of FreeCAD.Vector of the vertexes """ # normalize the normal direction nnormal = DraftVecUtils.scaleTo(fc_normal,1) # check if the vectors are perpendicular if not fc_isperp(nnormal, fc_verx1): logger.error('Vectors are Not perpendicular') #direction of the first vertex scaled to the radius n1dir_rad = DraftVecUtils.scaleTo(fc_verx1,radius) vertex_list = [] # divide the 360 degrees by the number of sides polygon_angle = 2*math.pi / n_sides for i in range(n_sides): rot_angle = i*polygon_angle # Rotate n1dir, and then add to pos vertex = pos + DraftVecUtils.rotate(n1dir_rad,rot_angle,nnormal) vertex_list.append(vertex) # the first vertex will be also the last one vertex_list.append(vertex_list[0]) return (vertex_list)
[docs]def shp_regpolygon_face (n_sides, radius, n_axis='z', v_axis='x', edge_rot=0, pos=V0): """ Makes the shape of a face of a regular polygon Parameters ---------- n_sides : int Number of sides of the polygon radius : float Circumradius of the polygon n_axis : str Axis of the normal: 'x', '-x', 'y', '-y', 'z', '-z' v_axis : str Perpendicular to n_axis, pointing to the first vertex, unless, x_angle is != 0. the vertex will be rotated x_angle degrees for v_axis x_angle : float If zero, the first vertex will be on axis v_axis if x_angle != 0, it will rotated some angle pos : FreeCAD.Vector Position of the center. Default (0,0,0) Returns ------- Shape Face FreeCAD Face of a regular polygon """ rpolygon_vlist = regpolygon_vecl (n_sides, radius, x_angle=edge_rot) rpolygon_wire = Part.makePolygon(rpolygon_vlist) vrot = calc_rot_z(getvecofname(n_axis), getvecofname(v_axis)) rpolygon_wire.Placement.Rotation = vrot rpolygon_wire.Placement.Base = pos shp_rpolygon_face = Part.Face(rpolygon_wire) return shp_rpolygon_face
[docs]def shp_regpolygon_dir_face (n_sides, radius, fc_normal=VZ, fc_verx1=VX, pos=V0): """ Similar to shp_regpolygon_face, but in any direction of the space makes the shape of a face of a regular polygon Parameters ---------- n_sides : int Number of sides of the polygon radius : float Circumradius of the polygon fc_normal : FreeCAD.Vector Direction of the normal fc_verx1 : FreeCAD.Vector Direction of the first vertex pos : FreeCAD.Vector Position of the center. Default (0,0,0) Returns -------- Shape Face FreeCAD Face of a regular polygon """ rpolygon_vlist = regpolygon_dir_vecl (n_sides, radius, fc_normal, fc_verx1, pos) rpolygon_wire = Part.makePolygon(rpolygon_vlist) shp_rpolygon_face = Part.Face(rpolygon_wire) return shp_rpolygon_face
[docs]def shp_regprism (n_sides, radius, length, n_axis='z', v_axis='x', centered = 0, edge_rot=0, pos=V0): """ Makes a shape of a face of a regular polygon Parameters ---------- n_sides : int Number of sides of the polygon radius : float Circumradius of the polygon length : float Length of the polygon n_axis : str Axis of the normal: 'x', '-x', 'y', '-y', 'z', '-z' v_axis : str Perpendicular to n_axis, pointing to the first vertex, unless, x_angle is != 0. the vertex will be rotated x_angle degrees for v_axis centered : int 1 if the extrusion is centered on pos (symmetrical) x_angle : float if zero, the first vertex will be on axis v_axis if x_angle != 0, it will rotated some angle pos : FreeCAD.Vector Position of the center. Default (0,0,0) Returns -------- Shape FreeCAD Shape of a regular prism """ shp_rpolygon_face = shp_regpolygon_face (n_sides, radius, n_axis = n_axis, v_axis = v_axis, edge_rot=edge_rot, pos = pos) vec_n_axis = getfcvecofname(n_axis) shp_rprism = shp_extrud_face(shp_rpolygon_face, length, vec_n_axis,centered) return shp_rprism
[docs]def shp_regprism_xtr (n_sides, radius, length, n_axis='z', v_axis='x', centered = 0, xtr_top = 0, xtr_bot = 0, edge_rot=0, pos=V0): """ makes a shape of a face of a regular polygon. Includes the posibility to add extra length on top and bottom. On top is easy, but at the bottom, the reference will be no counting that extra lenght added. This is useful to make boolean difference Parameters ---------- n_sides : int Number of sides of the polygon radius : float Circumradius of the polygon length : float Length of the polygon n_axis : str Axis of the normal: 'x', '-x', 'y', '-y', 'z', '-z' v_axis : str Perpendicular to n_axis, pointing to the first vertex, unless, x_angle is != 0. the vertex will be rotated x_angle degrees for v_axis centered : int 1 if the extrusion is centered on pos (symmetrical) xtr_top : float Add an extra lenght on top. If 0, nothing added xtr_bot : float Add an extra lenght at the bottom. If 0, nothing added x_angle : float If zero, the first vertex will be on axis v_axis if x_angle != 0, it will rotated some angle pos : FreeCAD.Vector Position of the center. Default (0,0,0) Returns -------- Shape FreeCAD Shape of a regular prism """ vec_n_axis = getfcvecofname(n_axis) if centered == 0: if xtr_bot > 0: # bring back the extra distance pos = pos - DraftVecUtils.scaleTo(vec_n_axis,xtr_bot) else: #centered, find the new center, related to how much is increased # on top and bottom pos = pos + (xtr_top - xtr_bot)/2. shp_rpolygon_face = shp_regpolygon_face (n_sides, radius, n_axis = n_axis, v_axis = v_axis, edge_rot=edge_rot, pos = pos) totlen = length + xtr_bot + xtr_top shp_rprism = shp_extrud_face(shp_rpolygon_face, totlen, vec_n_axis,centered) return shp_rprism
[docs]def shp_regprism_dirxtr (n_sides, radius, length, fc_normal=VZ, fc_verx1=VX, centered = 0, xtr_top = 0, xtr_bot = 0, pos=V0): """ Similar to shp_regprism_xtr, but in any direction makes a shape of a face of a regular polygon. Includes the posibility to add extra length on top and bottom. On top is easy, but at the bottom, the reference will be no counting that extra lenght added. This is useful to make boolean difference Parameters ---------- n_sides : int Number of sides of the polygon radius : float Circumradius of the polygon length : float Length of the polygon fc_normal : FreeCAD.Vector Direction of the normal fc_verx1 : FreeCAD.Vector Direction of the first vertex centered : int 1 if the extrusion is centered on pos (symmetrical) xtr_top : float Add an extra lenght on top. If 0, nothing added xtr_bot : float Add an extra lenght at the bottom. If 0, nothing added pos : FreeCAD.Vector Position of the center. Default (0,0,0) Returns -------- Shape FreeCAD Shape of a regular prism """ # normalize the normal: nnorm = DraftVecUtils.scaleTo(fc_normal, 1) totlen = length + xtr_bot + xtr_top if centered == 0: if xtr_bot > 0: # bring back the extra distance pos = pos - DraftVecUtils.scaleTo(nnorm,xtr_bot) else: #centered, find the new center movcenter = (xtr_top - xtr_bot)/2. pos = pos + DraftVecUtils.scaleTo(nnorm,movcenter) shp_rpolygon_face = shp_regpolygon_dir_face (n_sides, radius, nnorm, fc_verx1, pos) shp_rprism = shp_extrud_face(shp_rpolygon_face, totlen, nnorm,centered) return shp_rprism
[docs]def shp_cylhole_bolthole (r_out, r_in, h, n_bolt = 4, d_bolt = 0, r_bolt2cen = 0, axis_h = VZ, axis_ra = VY, axis_rb = None, bolt_axis_ra = 1, pos_h = 0, pos_ra = 0, pos_rb = 0, xtr_top=0, xtr_bot=0, xtr_r_out=0, xtr_r_in=0, pos = V0): """ This is a generalization of shp_cylholedir and shp_cylhole Makes a hollow cylinder in any position and direction, with optional extra heights, and inner and outer radius, and various locations in the cylinder Also has a number of nbolt holes along a radius r_bolt2cen the bolts a equi spaced depending on the number :: pos_h = 1, pos_ra = 0, pos_rb = 0 pos at 1: axis_rb : : . . o: are n_bolt(4) holes .o. .o. ( ( 0 ) ) ---- axis_ra .o. .o. . . axis_h : : ............... :____:____:....: xtr_top | : : | | : : | | : : | | : 0 : | 0: pos would be at 0, if pos_h == 0 | : : | | : : | |_:__1__:_|....>axis_ra :.:..o..:.:....: xtr_bot This o will be pos_o (orig) : : : : :..: : + : :r_in: : : :....: + r_out Values for pos_ra (similar to pos_rb along it axis) axis_h : d_bolt : :.:............ :_:_:__:__:_:....: xtr_top | : : : : | | : : : : | | : : : : | 3 2 1 0 : : |....>axis_ra (if pos_h == 0) | : : : : | | : : : : | |_:_:_____:_:_|..... :.: :..o..:.:....: xtr_bot This o will be pos_o (orig) : : : : : : :..: : : + : : : r_in : :....: : + : r_bolt2cen: : : :....: + r_out Parameters ---------- r_out : float Radius of the outside cylinder r_in : float Radius of the inner hole of the cylinder h : float Height of the cylinder n_bolt : int Number of bolt holes, if zero no bolt holes d_bolt : float Diameter of the bolt holes r_bolt2cen : float Distance (radius) from the cylinder center to the bolt hole centers bolt_axis_ra : int * 1: the first bolt will be on axis ra * 0: the first bolt will be rotated half of the angle between to bolt holes -> centered on the side axis_h : FreeCAD.Vector Vector along the cylinder height axis_ra : FreeCAD.Vector Vector along the cylinder radius, a direction perpendicular to axis_h it is not necessary if pos_ra == 0 It can be None, but if None, axis_rb has to be None axis_rb : FreeCAD.Vector Vector along the cylinder radius, a direction perpendicular to axis_h and axis_ra it is not necessary if pos_ra == 0 It can be None pos_h : int Location of pos along axis_h (0, 1) * 0: the cylinder pos is centered along its height, not considering xtr_top, xtr_bot * 1: the cylinder pos is at its base (not considering xtr_h) pos_ra : int Location of pos along axis_ra (0, 1) * 0: pos is at the circunference center * 1: pos is at the inner circunsference, on axis_ra, at r_in from the circle center (not at r_in + xtr_r_in) * 2: pos is at the center of the bolt hole (one of them) * 3: pos is at the outer circunsference, on axis_ra, at r_out from the circle center (not at r_out + xtr_r_out) pos_rb : int Location of pos along axis_ra (0, 1) * 0: pos is at the circunference center * 1: pos is at the inner circunsference, on axis_rb, at r_in from the circle center (not at r_in + xtr_r_in) * 2: pos is at the center of the bolt hole (one of them) * 3: pos is at the outer circunsference, on axis_rb, at r_out from the circle center (not at r_out + xtr_r_out) xtr_top : float Extra height on top, it is not taken under consideration when calculating the cylinder center along the height xtr_bot : float Extra height at the bottom, it is not taken under consideration when calculating the cylinder center along the height or the position of the base xtr_r_in : float Extra length of the inner radius (hollow cylinder), it is not taken under consideration when calculating pos_ra or pos_rb. It can be negative, so this inner radius would be smaller xtr_r_out : float Extra length of the outer radius it is not taken under consideration when calculating pos_ra or pos_rb. It can be negative, so this outer radius would be smaller pos : FreeCAD.Vector Position of the cylinder, taking into account where the center is Returns -------- Shape FreeCAD Shape of a cylinder with hole """ # calculate pos_o, which is at the center of the circle and at the base # counting xtr_bot it is is > 0 axis_h = DraftVecUtils.scaleTo(axis_h, 1) # vectors from o (orig) along axis_h, to the pos_h points h_o = {} h_o[0] = DraftVecUtils.scale(axis_h, h/2. + xtr_bot) h_o[1] = DraftVecUtils.scale(axis_h, xtr_bot) # vectors from o (orig) along axis_ra, to the pos_ra points ra_o = {} ra_o[0] = V0 if pos_ra != 0: if axis_ra is not None: axis_ra = DraftVecUtils.scaleTo(axis_ra, 1) ra_o[1] = DraftVecUtils.scale(axis_ra, - r_in) ra_o[2] = DraftVecUtils.scale(axis_ra, - r_bolt2cen) ra_o[3] = DraftVecUtils.scale(axis_ra, - r_out) else : logger.error('axis_ra not defined while pos_ra ==1') # vectors from o (orig) along axis_rb, to the pos_rb points rb_o = {} rb_o[0] = V0 if pos_rb != 0: if axis_rb is not None: axis_rb = DraftVecUtils.scaleTo(axis_rb, 1) rb_o[1] = DraftVecUtils.scale(axis_rb, - r_in) rb_o[2] = DraftVecUtils.scale(axis_rb, - r_bolt2cen) rb_o[3] = DraftVecUtils.scale(axis_rb, - r_out) else : logger.error('axis_rb not defined while pos_rb ==1') pos_o = pos + (h_o[pos_h] + ra_o[pos_ra] + rb_o[pos_rb]).negative() if r_in > 0: shp_holecyl = shp_cylholedir (r_out = r_out + xtr_r_out, r_in = r_in + xtr_r_in, h = h+xtr_bot+xtr_top, normal = axis_h, pos = pos_o) else: # without central hole shp_holecyl = shp_cyl (r= r_out + xtr_r_out, h = h+xtr_bot+xtr_top, normal = axis_h, pos = pos_o) # bolt holes: if (n_bolt > 0 and d_bolt > 0 and r_bolt2cen > 0) : if bolt_axis_ra == 0: axis_x = DraftVecUtils.rotate(axis_ra, math.pi/n_bolt, axis_h) else: axis_x = axis_ra boltcen_l = regpolygon_dir_vecl (n_bolt, r_bolt2cen, fc_normal= axis_h, fc_verx1 =axis_x, pos = pos_o) bolt_cyl_l = [] for boltcen in boltcen_l: shp_bolt_cyl = shp_cylcenxtr (r = d_bolt/2., h = h, normal = axis_h, ch = 0, xtr_top=1, xtr_bot=1, pos = boltcen) bolt_cyl_l.append(shp_bolt_cyl) boltfuse_shp = fuseshplist(bolt_cyl_l) shp_holecyl = shp_holecyl.cut(boltfuse_shp) return shp_holecyl
#shp_holecyl = shp_cylhole_bolthole (r_out = 20. , r_in = 0, h=10., # n_bolt = 4, d_bolt = 5+0.5, r_bolt2cen = 31.5/2., # axis_h = VXN, axis_ra = VZ, axis_rb = None, # bolt_axis_ra = 0, # pos_h = 1, pos_ra = 3, pos_rb = 0, # xtr_top=0, xtr_bot=0, # xtr_r_out=0, xtr_r_in=0, # pos = V0) # ------------------ shp_extrud_face # extrudes a face on any plane # returns a shape # # Arguments: # face: face to be extruded. # length: extrusion length # centered: 1 if the extrusion is centered (simetrical) 0 if it is not # vec_extr_axis: Typically, it will be the same as vec_facenormal. # by default, if it is 0, it will be equal to vec_facenormal # It doesn't have to be on an axis, it can be diagonally
[docs]def shp_extrud_face (face, length, vec_extr_axis, centered=0): """ Extrudes a face on any plane Parameters ---------- face : FreeCAD.Face Face to be extruded. length : float Extrusion length centered : int 1 if the extrusion is centered (simetrical) 0 if it is not vec_extr_axis : FreeCAD.Vector Typically, it will be the same as vec_facenormal. by default, if it is 0, it will be equal to vec_facenormal It doesn't have to be on an axis, it can be diagonally Returns -------- Shape FreeCAD Shape of the Face """ # Normalize the extrusion vector vec_extr = DraftVecUtils.scaleTo(vec_extr_axis,length) if centered == 1: #we have to move it back half the lenght of the extrusion # either this or DraftVecUtils.neg( ) pos = V0 - DraftVecUtils.scaleTo(vec_extr_axis,length/2.) face.Placement.Base = pos shp_extrusion = face.extrude(vec_extr) return (shp_extrusion)
# ------------------ shp_extrud_face_rot # extrudes a face that is on plane XY, includes a rotation # returns a shape # # Y # : # ____:___ # \ : | # \ :...|...... X # \ | # \____| # # # # face: face to be extruded. On plane XY # # vec_facenormal: FreeCAD vector that indicates where the normal of the # face will point. The normal of the original face is VZ, but this # function may rotate it depending on this argument # It has to be on an axis: 'x', 'y', .. # vec_edgx: FreeCAD vector that indicates where the edge X will be after # the rotation # It has to be on an axis: 'x', 'y', .. # length: extrusion length # centered: 1 if the extrusion is centered (simetrical) 0 if it is not # vec_extr_axis: Typically, it will be the same as vec_facenormal. # by default, if it is 0, it will be equal to vec_facenormal # It doesn't have to be on an axis, it can be diagonally
[docs]def shp_extrud_face_rot (face, vec_facenormal, vec_edgx, length, centered=0, vec_extr_axis = 0): """ Extrudes a face that is on plane XY, includes a rotation :: Y : ____:___ \ : | \ :...|...... X \ | \____| Parameters ---------- face : FreeCAD.Face Face to be extruded. On plane XY vec_facenormal : FreeCAD.Vector Indicates where the normal of the face will point. The normal of the original face is VZ, but this function may rotate it depending on this argument It has to be on an axis: 'x', 'y', .. vec_edgx : FreeCAD.Vector Indicates where the edge X will be after the rotation It has to be on an axis: 'x', 'y', .. length : float Extrusion length centered : int 1 if the extrusion is centered (simetrical) 0 if it is not vec_extr_axis : FreeCAD.Vector Typically, it will be the same as vec_facenormal. by default, if it is 0, it will be equal to vec_facenormal It doesn't have to be on an axis, it can be diagonally Returns -------- Shape FreeCAD Shape of a face """ # since vec2 of calc_rot is referenced to VNZ, vec_facenomal is negated vec_nfacenormal = DraftVecUtils.neg(vec_facenormal) vrot = fc_calc_rot(vec_edgx, vec_nfacenormal) face.Placement.Rotation = vrot if vec_extr_axis == 0: # default case vec_extr_axis = vec_facenormal # Normalize the extrusion vector vec_extr = DraftVecUtils.scaleTo(vec_extr_axis,length) if centered == 1: #we have to move it back half the lenght of the extrusion # either this or DraftVecUtils.neg( ) pos = V0 - DraftVecUtils.scaleTo(vec_extr_axis,length/2.) face.Placement.Base = pos shp_extrusion = face.extrude(vec_extr) # Reset the rotation of the original face # I am not sure, but I think it is necessary if I want to use it again # outside of the function face.Placement.Rotation = V0ROT face.Placement.Base = V0 return (shp_extrusion)
[docs]def addBolt (r_shank, l_bolt, r_head, l_head, hex_head = 0, extra=1, support=1, headdown = 1, name="bolt"): """ Creates the hole for the bolt shank and the head or the nut Tolerances have to be included Parameters ---------- r_shank : float Radius of the shank (tolerance included) l_bolt : float Total length of the bolt: head & shank r_head : float Radius of the head (tolerance included) l_head : float Length of the head hex_head : int Inidicates if the head is hexagonal or rounded * 1: hexagonal * 0: rounded h_layer3d : float Height of the layer for printing, if 0, means that the support is not needed extra : int 1 if you want 1 mm on top and botton to avoid cutting on the same plane pieces after making cuts (boolean difference) support : int 1 if you want to include a triangle between the shank and the head to support the shank and not building the head on the air using kcomp.LAYER3D_H headdown : int * 1 if the head is down. * 0 if it is up Returns -------- FreeCAD Object FreeCAD Object of a bolt """ # we have to bring the active document doc = FreeCAD.ActiveDocument elements = [] # shank shank = doc.addObject("Part::Cylinder", name + "_shank") shank.Radius = r_shank shank.Height = l_bolt + 2*extra pos = FreeCAD.Vector(0,0,-extra) shank.Placement = FreeCAD.Placement(pos, V0ROT, V0) elements.append (shank) # head: if hex_head == 0: head = doc.addObject("Part::Cylinder", name + "_head") head.Radius = r_head else: head = doc.addObject("Part::Prism", name + "_head") head.Polygon = 6 head.Circumradius = r_head head.Height = l_head + extra if headdown == 1: zposhead = -extra else: zposhead = l_bolt - l_head poshead = FreeCAD.Vector(0,0,zposhead) head.Placement.Base = poshead elements.append (head) # support for the shank: if support==1 and kcomp.LAYER3D_H > 0: sup1 = doc.addObject("Part::Prism", name + "_sup1") sup1.Polygon = 3 sup1.Circumradius = r_shank * 2 # we could put it just on top of the head, but since we are going to # make an union, we put it from the bottom (no need to include extra) # sup1.Height = kcomp.LAYER3D_H # pos1 = FreeCAD.Vector(0,0,l_head) # rot30z = FreeCAD.Rotation(VZ,30) # sup1.Placement = FreeCAD.Placement(pos1, rot30z, V0) sup1.Height = l_head + kcomp.LAYER3D_H # rotation make only make sense for hexagonal head, but it doesn't # matter for rounded head rot30z = FreeCAD.Rotation(VZ,30) if headdown == 1: zposheadsup1 = 0 else: zposheadsup1 = l_bolt - l_head - kcomp.LAYER3D_H sup1.Placement.Base = FreeCAD.Vector(0,0,zposheadsup1) sup1.Placement.Rotation = rot30z # take vertex away: if hex_head == 0: sup1away = doc.addObject("Part::Cylinder", name + "_sup1away") sup1away.Radius = r_head else: sup1away = doc.addObject("Part::Prism", name + "_sup1away") sup1away.Polygon = 6 sup1away.Circumradius = r_head # again, we take all the height sup1away.Height = l_head + kcomp.LAYER3D_H sup1away.Placement.Base = sup1.Placement.Base sup1cut = doc.addObject("Part::Common", "sup1cut") sup1cut.Base = sup1 sup1cut.Tool = sup1away elements.append (sup1cut) # another support # 1.15 is the relationship between the Radius and the Apothem # of the hexagon: sqrt(3)/2 . I make it slightly smaller sup2 = doc.addObject("Part::Prism", name + "_sup2") sup2.Polygon = 6 sup2.Circumradius = r_shank * 1.15 sup2.Height = l_head + 2* kcomp.LAYER3D_H if headdown == 1: zposheadsup2 = 0 else: zposheadsup2 = l_bolt - l_head - 2* kcomp.LAYER3D_H sup2.Placement.Base = FreeCAD.Vector(0,0,zposheadsup2) elements.append (sup2) # union of elements bolt = doc.addObject("Part::MultiFuse", name) bolt.Shapes = elements return bolt
# bolt = doc.addObject("Part::Fuse", name) # bolt.Base = shank # bolt.Tool = head
[docs]def shp_bolt (r_shank, l_bolt, r_head, l_head, hex_head = 0, xtr_head=1, xtr_shank=1, support=1, axis = 'z', hex_ref = 'x', hex_rot_angle = 0, pos = V0): """ Similar to addBolt, but creates a shape instead of a FreeCAD Object Creates a shape of the bolt shank and head or the nut Tolerances have to be included if you want it for making a hole It is referenced at the end of the head Parameters ---------- r_shank : float Radius of the shank (tolerance included) l_bolt : float Total length of the bolt: head & shank r_head : float Radius of the head (tolerance included) l_head : float Length of the head hex_head : int Inidicates if the head is hexagonal or rounded * 1: hexagonal * 0: rounded h_layer3d : float Height of the layer for printing, if 0, means that the support is not needed xtr_head : int 1 if you want 1 mm on the head to avoid cutting on the same plane pieces after making cuts (boolean difference) xtr_shank : int 1 if you want 1 mm at the opposite side of the head to avoid cutting on the same plane pieces after making cuts (boolean difference) support : int 1 if you want to include a triangle between the shank and the head to support the shank and not building the head on the air using kcomp.LAYER3D_H axis : str 'x', '-x', 'y', '-y', 'z', '-z': Defines the orientation. For example: :: axis = '-z': Z : ....... ____:____ xtr_head=1 .......| :....|...... X | | |__ __| | | | | | | |___| axis = 'z': Z : : _:_ | : | | : | | : | __| : |__ | : | xtr_head=1 .......| :....|...... X .......|____:____| hex_ref : str In case of a hexagonal head, this will indicate the axis that the first vertex of the nut will point hex_ref has to be perpendicular to axis, if not, it will be changed hex_rot_angle : float Angle in degrees. In case of a hexagonal head, it will indicate the angle of rotation of the hexagon referenced to hex_ref. pos : FreeCAD.Vector Position of the center of the head of the bolt Returns -------- Shape FreeCAD Shape of a bolt """ elements = [] v_axis = getfcvecofname(axis) # It is built as its orientation is 'z', it will be rotated at the end # shank # In shp_cylcenxtr, xtr_bot is where pos is (0). The head # and xtr_bot is the other end (-z) if axis '-z'. The end of the shank shp_shank = shp_cylcenxtr (r_shank, l_bolt, v_axis, ch=0, # the shank end is top xtr_top = xtr_shank, # the head end is bottom # No need to add extra, the head will do xtr_bot = 0, pos = pos) elements.append (shp_shank) # head: if hex_head == 0: shp_head = shp_cylcenxtr (r_head, l_head, v_axis, ch=0, # no extra on top, the shank will be there xtr_top = 0, xtr_bot = xtr_head, pos = pos) else: # check if axis and hex_ref are the same vector (wrong) if vecname_paral (axis, hex_ref): hex_ref = get_vecname_perpend(axis) shp_head = shp_regprism_xtr (n_sides=6, radius = r_head, length = l_head, n_axis=axis, v_axis=hex_ref, centered = 0, # no extra on top, the shank will be there xtr_top = 0, xtr_bot = xtr_head, edge_rot = hex_rot_angle, pos=pos) # Dont append the head, because multifuse requieres one outside #elements.append (shp_head) # support for the shank: if support==1 and kcomp.LAYER3D_H > 0: # we could put it just on top of the head, but since we are going to # make an union, we put it from the bottom (no need to include extra) shp_sup1 = shp_regprism (n_sides=3, radius = 2*r_shank, length = l_head + kcomp.LAYER3D_H, n_axis=axis, v_axis=hex_ref, centered = 0, edge_rot = hex_rot_angle + 30, pos=pos) # take vertexes away: sup1away_l = l_head + kcomp.LAYER3D_H if hex_head == 0: shp_sup1away = shp_cyl(r_head, sup1away_l, v_axis, pos) else: shp_sup1away = shp_regprism(n_sides=6, radius= r_head, length= sup1away_l, n_axis = axis, v_axis = hex_ref, centered = 0, edge_rot = hex_rot_angle, pos = pos) shp_sup1cut = shp_sup1.common(shp_sup1away) elements.append (shp_sup1cut) # another support # 1.15 is the relationship between the Radius and the Apothem # of the hexagon: sqrt(3)/2 . I make it slightly smaller shp_sup2 = shp_regprism (n_sides=6, radius = 1.15*r_shank, length = l_head + 2* kcomp.LAYER3D_H, n_axis=axis, v_axis=hex_ref, centered = 0, edge_rot = hex_rot_angle, pos=pos) elements.append (shp_sup2) # union of elements shp_bolt = shp_head.multiFuse(elements) shp_bolt = shp_bolt.removeSplitter() return shp_bolt
[docs]def shp_bolt_dir (r_shank, l_bolt, r_head, l_head, hex_head = 0, xtr_head=1, xtr_shank=1, support=1, fc_normal = VZ, fc_verx1 = VX, #default value has to be 0 for backward compatibility #because it didnt exist before pos_n = 0, pos = V0): """ Similar to shp_bolt, but it can be done in any direction Creates a shape, not a of a FreeCAD Object Creates a shape of the bolt shank and head or the nut Tolerances have to be included if you want it for making a hole It is referenced at the end of the head Parameters ---------- r_shank : float Radius of the shank (tolerance included) l_bolt : float Total length of the bolt: head & shank r_head : float Radius of the head (tolerance included) l_head : float Length of the head hex_head : int Inidicates if the head is hexagonal or rounded * 1: hexagonal * 0: rounded h_layer3d : float Height of the layer for printing, if 0, means that the support is not needed xtr_head : int 1 if you want 1 mm on the head to avoid cutting on the same plane pieces after making cuts (boolean difference) xtr_shank : int 1 if you want 1 mm at the opposite side of the head to avoid cutting on the same plane pieces after making cuts (boolean difference) support : int 1 if you want to include a triangle between the shank and the head to support the shank and not building the head on the air using kcomp.LAYER3D_H fc_normal : FreeCAD.Vector Defines the orientation. For example: :: fc_normal = (0,0,-1): Z : ....... ____:____ ..xtr_head=1 .......| :....|...... X pos_n = 0 : l_head+: | | : :......|__ __| pos_n = 1 :+ l_bolt | | : | | :.......................| |.............pos_n = 2 |___|....xtr_shank : : fc_normal fc_normal = (0,0,1): Z : : _:_ | : | | : | | : | __| : |__ | : | xtr_head=1 .......| :....|...... X .......|____:____| fc_verx1 : FreeCAD.Vector In case of a hexagonal head, this will indicate the axis that the first vertex of the nut will point it has to be perpendicular to fc_normal, pos_n : int Location of pos along the normal, at the cylinder center * 0: at the top of the head (excluding xtr_head) * 1: at the union of the head and the shank * 2: at the end of the shank (excluding xtr_shank) pos : FreeCAD.Vector Position of the center of the head of the bolt Returns ------- Shape FreeCAD Shape of a bolt """ elements = [] nnormal = DraftVecUtils.scaleTo(fc_normal,1) # vectors to pos_n = 0 (to the end of the head) n0to = {} n0to[0] = V0 n0to[1] = DraftVecUtils.scale(nnormal, l_head) # xtr_head not included n0to[2] = DraftVecUtils.scale(nnormal, l_bolt) # xtr_head/shank not included pos0 = pos + (n0to[pos_n]).negative() shp_shank = shp_cylcenxtr (r_shank, l_bolt, nnormal, ch=0, # the shank end is top xtr_top = xtr_shank, # the head end is bottom # No need to add extra, the head will do xtr_bot = 0, pos = pos0) elements.append (shp_shank) # head: if hex_head == 0: shp_head = shp_cylcenxtr (r_head, l_head, nnormal, ch=0, # no extra on top, the shank will be there xtr_top = 0, xtr_bot = xtr_head, pos = pos0) if not fc_isperp(nnormal, fc_verx1): # get any perpendicular vector: fc_verx1 = get_fc_perpend1(nnormal) else: # check if fc_normal and fc_verx1 are perpendicular if not fc_isperp(nnormal, fc_verx1): logger.debug('Vectors are not perpendicular') # get any perpendicular vector: fc_verx1 = get_fc_perpend1(nnormal) shp_head = shp_regprism_dirxtr ( n_sides=6, radius = r_head, length = l_head, fc_normal=nnormal, fc_verx1=fc_verx1, centered = 0, # no extra on top, the shank will be there xtr_top = 0, xtr_bot = xtr_head, pos=pos0) # Dont append the head, because multifuse requires one outside of the list # elements.append (shp_head) # support for the shank: if support==1 and kcomp.LAYER3D_H > 0: # we could put it just on top of the head, but since we are going to # make an union, we put it from the bottom (no need to include extra) # have to rotate 30 degrees the vertex for this triangle fc_verx1_triangle = DraftVecUtils.rotate(fc_verx1, math.pi/6., nnormal) shp_sup1 = shp_regprism_dirxtr (n_sides=3, radius = 2*r_shank, length = l_head + kcomp.LAYER3D_H, fc_normal=nnormal, fc_verx1=fc_verx1_triangle, centered = 0, pos=pos0) # take vertexes away: sup1away_l = l_head + kcomp.LAYER3D_H if hex_head == 0: shp_sup1away = shp_cyl(r_head, sup1away_l, nnormal, pos0) else: shp_sup1away = shp_regprism_dirxtr ( n_sides=6, radius= r_head, length= sup1away_l, fc_normal=nnormal, fc_verx1=fc_verx1, centered = 0, pos = pos0) shp_sup1cut = shp_sup1.common(shp_sup1away) elements.append (shp_sup1cut) # another support # 1.15 is the relationship between the Radius and the Apothem # of the hexagon: sqrt(3)/2 . I make it slightly smaller shp_sup2 = shp_regprism_dirxtr ( n_sides=6, radius = 1.15*r_shank, length = l_head + 2* kcomp.LAYER3D_H, fc_normal=nnormal, fc_verx1=fc_verx1, centered = 0, pos=pos0) elements.append (shp_sup2) # union of elements shp_bolt = shp_head.multiFuse(elements) shp_bolt = shp_bolt.removeSplitter() return shp_bolt
#doc = FreeCAD.newDocument() #shp = shp_bolt_dir (r_shank = 5, l_bolt=50, r_head=10, l_head=12, # hex_head = 1, # xtr_head=1, # xtr_shank=1, # support=0, # fc_normal = FreeCAD.Vector(1,1,1), # fc_verx1 = VX, # pos_n = 1, # pos = V0) #Part.show(shp)
[docs]def addBoltNut_hole (r_shank, l_bolt, r_head, l_head, r_nut, l_nut, hex_head = 0, extra=1, supp_head=1, supp_nut=1, headdown=1, name="bolt"): """ Creates the hole for the bolt shank, the head and the nut. The bolt head will be at the botton, and the nut will be on top Tolerances have to be already included in the argments values Parameters ---------- r_shank : float Radius of the shank (tolerance included) l_bolt : float Total length of the bolt: head & shank r_head : float Radius of the head (tolerance included) l_head : float Length of the head r_nut : float Radius of the nut (tolerance included) l_nut : float Length of the nut. It doesn't have to be the length of the nut but how long you want the nut to be inserted hex_head : int Inidicates if the head is hexagonal or rounded * 1: hexagonal * 0: rounded zpos_nut : float Inidicates the height position of the nut, the lower part h_layer3d : float Height of the layer for printing, if 0, means that the support is not needed extra : int 1 if you want 1 mm on top and botton to avoid cutting on the same plane pieces after makeing differences support : int 1 if you want to include a triangle between the shank and the head to support the shank and not building the head on the air using kcomp.LAYER3D_H Returns -------- FreeCAD Object FreeCAD Object of a Nut Hole """ # we have to bring the active document doc = FreeCAD.ActiveDocument elements = [] bolt = addBolt (r_shank = r_shank, l_bolt = l_bolt, r_head = r_head, l_head = l_head, hex_head = hex_head, extra = extra, support = supp_head, headdown = headdown, name = name + "_bolt") nut = doc.addObject("Part::Prism", name + "_nut") nut.Polygon = 6 nut.Circumradius = r_nut nut.Height = l_nut + extra if headdown == 1: pos = FreeCAD.Vector (0, 0, l_bolt - l_nut) else: pos = FreeCAD.Vector (0, 0, -extra) nut.Placement = FreeCAD.Placement(pos, V0ROT, V0) elements.append (bolt) elements.append (nut) # support for the nut if supp_nut == 1 and kcomp.LAYER3D_H > 0: supnut1 = doc.addObject("Part::Prism", name + "_nutsup1") supnut1.Polygon = 3 supnut1.Circumradius = r_shank * 2 supnut1.Height = l_nut + kcomp.LAYER3D_H if headdown == 1: pos_supnut1 = FreeCAD.Vector (0, 0, l_bolt - l_nut - kcomp.LAYER3D_H) else: pos_supnut1 = V0 rot30z = FreeCAD.Rotation(VZ,30) supnut1.Placement = FreeCAD.Placement(pos_supnut1, rot30z, V0) # take vertex away: supnut1away = doc.addObject("Part::Prism", name + "_supnut1away") supnut1away.Polygon = 6 supnut1away.Circumradius = r_nut supnut1away.Height = supnut1.Height supnut1away.Placement = FreeCAD.Placement(pos_supnut1, V0ROT, V0) supnut1cut = doc.addObject("Part::Common", "supnut1_cut") supnut1cut.Base = supnut1 supnut1cut.Tool = supnut1away elements.append (supnut1cut) # the other support # 1.15 is the relationship between the Radius and the Apothem # of the hexagon: sqrt(3)/2 . I make it slightly smaller supnut2 = doc.addObject("Part::Prism", name + "_supnut2") supnut2.Polygon = 6 supnut2.Circumradius = r_shank * 1.15 supnut2.Height = l_nut + 2* kcomp.LAYER3D_H if headdown == 1: pos_supnut2 = FreeCAD.Vector(0,0, l_bolt - l_nut - 2*kcomp.LAYER3D_H) else: pos_supnut2 = V0 supnut2.Placement = FreeCAD.Placement(pos_supnut2, V0ROT, V0) elements.append (supnut2) boltnut = doc.addObject("Part::MultiFuse", "boltnut") boltnut.Shapes = elements return boltnut
[docs]def shp_boltnut_dir_hole (r_shank, l_bolt, r_head, l_head, r_nut, l_nut, hex_head=0, xtr_head=1, xtr_nut=1, supp_head=1, supp_nut=1, headstart=1, fc_normal = VZ, fc_verx1=V0, pos = V0): """ Similar to addBoltNut_hole, but in any direction and creates shapes, not FreeCAD Objects Creates the hole for the bolt shank, the head and the nut. The bolt head will be at the botton, and the nut will be on top Tolerances have to be already included in the argments values Parameters ---------- r_shank : float Radius of the shank (tolerance included) l_bolt : float Total length of the bolt: head & shank r_head : float Radius of the head (tolerance included) l_head : float Length of the head r_nut : float Radius of the nut (tolerance included) l_nut : float Length of the nut. It doesn't have to be the length of the nut but how long you want the nut to be inserted hex_head : int Inidicates if the head is hexagonal or rounded * 1: hexagonal * 0: rounded xtr_head : int 1 if you want an extra size on the side of the head to avoid cutting on the same plane pieces after making differences xtr_nut : int 1 if you want an extra size on the side of the nut to avoid cutting on the same plane pieces after making differences supp_head : int 1 if you want to include a triangle between the shank and the head to support the shank and not building the head on the air using kcomp.LAYER3D_H supp_nut : int 1 if you want to include a triangle between the shank and the nut to support the shank and not building the nut on the air using kcomp.LAYER3D_H headstart : int If on pos you have the head, or if you have it on the other end fc_normal : FreeCAD.Vector Direction of the bolt fc_verx1 : FreeCAD.Vector Direction of the first vertex of the hexagonal nut. Perpendicular to fc_normal. If not perpendicular or zero, means that it doesn't matter which direction and the function will obtain one perpendicular direction pos : FreeCAD.Vector Position of the head (if headstart) or of the nut Returns -------- FreeCAD Object FreeCAD Object of a Nut Hole """ # we have to bring the active document doc = FreeCAD.ActiveDocument # normalize nnormal = DraftVecUtils.scaleTo(fc_normal,1) if not fc_isperp(nnormal, fc_verx1): # if they are not perpendicular (or if fc_verx1 is null) # get a perpendicular vector nverx1 = get_fc_perpend1(nnormal) else: nverx1 = DraftVecUtils.scaleTo(fc_verx1,1) # vector from the origin position (pos) to the end pos2end = DraftVecUtils.scaleTo(nnormal, l_bolt) # nnormal negated nnormal_neg = DraftVecUtils.scaleTo(nnormal,-1) if headstart == 1: #the head will be on pos and the nut on pos + l_bolt pos_head = pos pos_nut = pos + pos2end nnormal_head = nnormal nnormal_nut = nnormal_neg else: #the nut will be on pos and the head on pos + l_bolt pos_head = pos + pos2end pos_nut = pos nnormal_head = nnormal_neg nnormal_nut = nnormal # bolt with the head: shp_bolt = shp_bolt_dir (r_shank = r_shank, l_bolt = l_bolt, r_head = r_head, l_head = l_head, hex_head = hex_head, xtr_head = xtr_head, xtr_shank = 0, # no need, the nut will go extra support = supp_head, fc_normal = nnormal_head, fc_verx1 = nverx1, pos_n = 0, pos = pos_head) # Nut: shp_nut = shp_regprism_dirxtr ( n_sides = 6, radius = r_nut, length = l_nut, fc_normal = nnormal_nut, fc_verx1 = nverx1, centered = 0, # no extra on top, the shank will be there xtr_top = 0, xtr_bot = xtr_nut, pos = pos_nut) nut_elements = [shp_nut] # support for the nut if supp_nut == 1 and kcomp.LAYER3D_H > 0: # rotate 30 degrees nverx1_triangle = DraftVecUtils.rotate(nverx1, -math.pi/6., nnormal_nut) shp_sup1 = shp_regprism_dirxtr (n_sides=3, radius = 2*r_shank, length = l_nut + kcomp.LAYER3D_H, fc_normal=nnormal_nut, fc_verx1=nverx1_triangle, centered = 0, pos=pos_nut) # take vertexes away: sup1away_l = l_nut + kcomp.LAYER3D_H shp_sup1away = shp_regprism_dirxtr ( n_sides=6, radius= r_nut, length= sup1away_l, fc_normal=nnormal_nut, fc_verx1=nverx1, centered = 0, pos = pos_nut) shp_sup1cut = shp_sup1.common(shp_sup1away) nut_elements.append (shp_sup1cut) # another support # 1.15 is the relationship between the Radius and the Apothem # of the hexagon: sqrt(3)/2 . I make it slightly smaller shp_sup2 = shp_regprism_dirxtr ( n_sides=6, radius = 1.15*r_shank, length = l_nut + 2* kcomp.LAYER3D_H, fc_normal=nnormal_nut, fc_verx1=nverx1, centered = 0, pos=pos_nut) nut_elements.append (shp_sup2) # union of elements shp_boltnut = shp_bolt.multiFuse(nut_elements) shp_boltnut = shp_boltnut.removeSplitter() return shp_boltnut
# ------------------- def aluprof_vec # Creates a wire (shape), that is an approximation of a generic alum # profile extrusion # width: the total width of the profile, it is a square # thick: the thickness of the side # slot: the width of the rail # insquare: the width of the inner square # indiam: the diameter of the inner hole # # Y # |_ X # :----- width ----: # : slot : # : :--: : # :______: :______: # | __| |__ | # | |\ \ / /| | # |_| \ \____/ / |_| ........... # | | ...... insquare # | ( ) | ......indiam : # _ | ____ | ..............: # | | / / \ \ | | # | |/ /_ _\ \| | .... # |______| |______| ....thick # Y values: # : 3 _____ 4 # : |_1 7| ................... 1,2: width/2 - thick # : 2 / /|_| ....................7: width/2- (thick+thick*cos45) # :___/ / 6 5 ..................... 5,6: slot/2. # : 0 |8 :8:insquare/2-thick*cos45 0:insquare/2 : # :.....|......:..........................:.............: # obtains the points of the aluminum profile positive quadrant
[docs]def aluprof_vec (width, thick, slot, insquare): """ Creates a wire (shape), that is an approximation of a generic alum profile extrusion :: Y |_ X :----- width ----: : slot : : :--: : :______: :______: | __| |__ | | |\ \ / /| | |_| \ \____/ / |_| ........... | | ...... insquare | ( ) | ......indiam : _ | ____ | ..............: | | / / \ \ | | | |/ /_ _\ \| | .... |______| |______| ....thick Y values: : 3 _____ 4 : |_1 7| ................... 1,2: width/2 - thick : 2 / /|_| ....................7: width/2- (thick+thick*cos45) :___/ / 6 5 ..................... 5,6: slot/2. : 0 |8 :8:insquare/2-thick*cos45 0:insquare/2 : :.....|......:..........................:.............: Parameters ---------- width : float The total width of the profile, it is a square thick : float The thickness of the side slot : float The width of the rail insquare : float The width of the inner square indiam : float The diameter of the inner hole Returns -------- Vector The points of the aluminum profile positive quadrant """ y = [] y.append(insquare/2) # y0, x8 y.append(width/2. - thick) # y1, x7 y.append(y[-1]) # y2, x6, y2==y1 y.append(width/2.) # y3, x5 y.append(y[-1]) # y4, x4, y4==y3 y.append(slot/2.) # y5, x3 y.append(y[-1]) # y6, x2 y6==y5 y.append(width/2.-thick*(1+COS45)) # y7, x1 y.append(insquare/2.-thick*COS45) # y8, x0 n = len(y)-1 vec = [] for ind in range(len(y)): vec.append(FreeCAD.Vector(y[n-ind], y[ind], 0)) return (vec)
""" y1 = insquare/2 # x9 y2 = width/2. - thick # x8 y3 = y2 # x7 y4 = width/2. # x6 y5 = y4 # x5 y6 = width/2. - slot/2. # x4 y7 = y6 # x3 y8 = width/2.-2*thick # x2 y9 = insquare/2.-thick # x1 """ # ------------------- def shp_aluwire_dir
[docs]def shp_aluwire_dir (width, thick, slot, insquare, fc_axis_x=VX, fc_axis_y=VY, ref_x = 1, ref_y = 1, pos=V0): """ Creates a wire (shape), that is an approximation of a generic alum profile extrusion. Creates it in any position an any direction :: Y |_ X :----- width ----: : slot : : :--: : :______: :______: | __| |__ | | |\ \ / /| | |_| \ \____/ / |_| ........... | | ...... insquare | ( ) | ......indiam : _ | ____ | ..............: | | / / \ \ | | | |/ /_ _\ \| | .... |______| |______| ....thick Y values: : 3 _____ 4 : |_1 7| ................... 1,2: width/2 - thick : 2 / /|_| ....................7: width/2- (thick+thick*cos45) :___/ / 6 5 ..................... 5,6: slot/2. : 0 |8 :8:insquare/2-thick*cos45 0:insquare/2 : :.....|......:..........................:.............: ref_x= 1 ; ref_y = 1 fc_axis_w : : _ : _ |_|_:_|_| ........|.:.|........ fc_axis_p _|_:_|_ |_| : |_| : : : ref_x= 2 ; ref_y = 1 (the zero of axis_y is at the center) (the zero of axis_x is at one side) fc_axis_y : : : :_ _ |_|___|_| ..........:.|...|........ fc_axis_x :_|___|_ |_| |_| : : : Parameters ---------- width : float Total width of the profile, it is a square thick : float Thickness of the side slot : float Width of the rail insquare : float Width of the inner square indiam : float Diameter of the inner hole fc_axis_x : int Is a generic X axis, can be any * 1: reference (zero) at the center * 2: reference (zero) at the side, the other end side will be on the direction of fc_axis_x fc_axis_y : int Is a generic Y axis, can be any perpendicular to fc_axis_y * 1: reference (zero) at the center * 2: reference (zero) at the side, the other end side will be on the direction of fc_axis_y ref_x : float Reference (zero) on the fc_axis_x ref_y : float Reference (zero) on the fc_axis_1 pos : FreeCAD.Vector Position of the center Returns -------- Shape Wire FreeCAD Shape Wire of a aluminium profile """ axis_x = DraftVecUtils.scaleTo(fc_axis_x, 1) axis_y = DraftVecUtils.scaleTo(fc_axis_y, 1) # Get the center position if ref_x == 2: ref2center_x = DraftVecUtils.scale(axis_x, width/2.) else: ref2center_x = V0 if ref_y == 2: ref2center_y = DraftVecUtils.scale(axis_y, width/2.) else: ref2center_y = V0 center_pos = pos + ref2center_x + ref2center_y y = [] y.append(insquare/2) # y0, x8 y.append(width/2. - thick) # y1, x7 y.append(y[-1]) # y2, x6, y2==y1 y.append(width/2.) # y3, x5 y.append(y[-1]) # y4, x4, y4==y3 y.append(slot/2.) # y5, x3 y.append(y[-1]) # y6, x2 y6==y5 y.append(width/2.-thick*(1+COS45)) # y7, x1 y.append(insquare/2.-thick*COS45) # y8, x0 n = len(y)-1 # # 1st point # | go clockwise # 2 | 1 # ----|---- # 3 | 4 # | # # vec = [] # First quadrant for ind in range(len(y)): point = (center_pos + DraftVecUtils.scale(axis_x, y[n-ind]) + DraftVecUtils.scale(axis_y, y[ind])) vec.append(point) # 4 quadrant for ind in range(len(y)): point = (center_pos + DraftVecUtils.scale(axis_x, y[ind]) + DraftVecUtils.scale(axis_y, -y[n-ind])) vec.append(point) # 3 quadrant for ind in range(len(y)): point = (center_pos + DraftVecUtils.scale(axis_x, -y[n-ind]) + DraftVecUtils.scale(axis_y, -y[ind])) vec.append(point) # 2 quadrant for ind in range(len(y)): point = (center_pos + DraftVecUtils.scale(axis_x, -y[ind]) + DraftVecUtils.scale(axis_y, y[n-ind])) vec.append(point) # The first point has to be the last to close the wire vec.append(vec[0]) shp_aluwire = Part.makePolygon(vec) return (shp_aluwire)
# -------------------- NutHole ----------------------------- # adding a Nut hole (hexagonal) with a prism attached to introduce the nut # tolerances are included # nut_r : circumradius of the hexagon # nut_h : height of the nut, usually larger than the actual nut height, to be # able to introduce it # hole_h: the hole height, from the center of the hexagon to the side it will # see light # name: name of the object (string) # extra: 1 if you want 1 mm out of the hole, to cut # nuthole_x: 1 if you want that the nut height to be along the X axis # and the 2*apotheme on the Y axis # ie. Nut hole facing X # 0 if you want that the nut height to be along the Y axis # ie. Nut hole facing Y # cx: 1 if you want the coordinates referenced to the x center of the piece # it can be done because it is a new shape formed from the union # cy: 1 if you want the coordinates referenced to the y center of the piece # holedown: I THINK IS THE OTHER WAY; CHECK # 0: the z0 is the bottom of the square (hole) # 1: the z0 is the center of the hexagon (nut) # it can be done because it is a new shape formed from the union # # 0 1 # /\ __ # | | | | # | | | | # |__|__ z = 0 | | -- z = 0 # \/
[docs]class NutHole (object): """ Adding a Nut hole (hexagonal) with a prism attached to introduce the nut. Tolerances are included :: 0 1 /\ __ | | | | | | | | |__|__ z = 0 | | -- z = 0 \/ Parameters ---------- nut_r : float Circumradius of the hexagon nut_h : float Height of the nut, usually larger than the actual nut height, to be able to introduce it hole_h : float The hole height, from the center of the hexagon to the side it will see light name : str Name of the object (string) extra : int * 1 if you want 1 mm out of the hole, to cut nuthole_x : int * 1 : if you want that the nut height to be along the X axis and the 2*apotheme on the Y axis ie. Nut hole facing X * 0 : if you want that the nut height to be along the Y axis ie. Nut hole facing Y cx : int * 1 : if you want the coordinates referenced to the x center of the piece it can be done because it is a new shape formed from the union cy : int * 1 : if you want the coordinates referenced to the y center of the piece holedown : int I THINK IS THE OTHER WAY; CHECK * 0: the z0 is the bottom of the square (hole) * 1: the z0 is the center of the hexagon (nut) it can be done because it is a new shape formed from the union Returns -------- FreeCAD Object FreeCAD object of a nut hole """ def __init__(self, nut_r, nut_h, hole_h, name, extra = 1, nuthole_x = 1, cx=0, cy=0, holedown = 0): self.nut_r = nut_r self.nut_h = nut_h self.nut_2ap = 2 * nut_r * COS30 #Apotheme = R * cos (30) self.hole_h = hole_h self.name = name self.extra = extra self.nuthole_x = nuthole_x self.cx = cx self.cy = cy self.holedown = holedown doc = FreeCAD.ActiveDocument self.doc = doc # the nut nut = doc.addObject("Part::Prism", name + "_nut") nut.Polygon = 6 nut.Circumradius = nut_r nut.Height = nut_h self.nutObj = nut if nuthole_x == 1: x_hole = nut_h y_hole = self.nut_2ap nutrot = FreeCAD.Rotation(VY,90) if cx == 1: #centered on X, xpos_nut = - nut_h / 2.0 else: xpos_nut = 0 if cy == 1: #centered on Y, already is ypos_nut = 0 else: # already starting on y=0 ypos_nut = self.nut_2ap/2.0 else : # nut h is on Y x_hole = self.nut_2ap y_hole = nut_h # the rotation of the nut will be on X # this is a rotation of Yaw and Pitch, because we want to have the # vertex on top, not the face of the hexagonal prism nutrot = FreeCAD.Rotation(90,90,0) if cx == 1: #centered on X, already is xpos_nut = 0 else: # move to the half of the apotheme xpos_nut = self.nut_2ap/2.0 if cy == 1: #centered on Y, ypos_nut = - nut_h / 2.0 else: # already starting on y=0 ypos_nut = 0 hole = addBox (x_hole, y_hole, hole_h + extra, name + "_hole", cx = cx, cy = cy) self.holeObj = hole if holedown== 1: # the nut will be top zpos_nut = hole_h if extra > 0: # then we will have to bring down the z of the hole hole.Placement.Base = hole.Placement.Base \ + FreeCAD.Vector(0,0,-extra) else: zpos_nut = 0 nut.Placement.Base = FreeCAD.Vector (xpos_nut, ypos_nut, zpos_nut) nut.Placement.Rotation = nutrot nuthole = doc.addObject("Part::Fuse", name) nuthole.Base = nut nuthole.Tool = hole self.fco = nuthole # the FreeCad Object
# -------------------- shp_nuthole -----------------------------
[docs]def shp_nuthole (nut_r, nut_h, hole_h, xtr_nut = 1, xtr_hole = 1, fc_axis_nut = VX, fc_axis_hole = VZ, ref_nut_ax = 1, ref_hole_ax = 1, pos = V0): """ Similar to NutHole, but creates a shape, in any direction. Add a Nut hole (hexagonal) with a prism attached to introduce the nut tolerances are included :: fc_axis_hole fc_axis_hole : : _:_ _:_ .. | | | | : | | | | + hole_h |___|----fc_axis_nut | |--: | | \ / + nut_r |___| V....: : : :...: + nut_h ref_nut: fc_axis_hole fc_axis_hole : : _:_ _:_ | | | | | | | | 2_1_|----fc_axis_nut | | | | \ / |___| V ref_hole: fc_axis_hole fc_axis_hole : : _2_ _2_ | | | | | | | | |_1_|----fc_axis_nut | 1 | | | \ / |___| V fc_axis_hole : _:_ ... |.2.|...xtr_hole (but pos is not referenced on the xtr) | | | | |_1_|----fc_axis_nut | | ___ but pos is still referenced on the axis of |___|..... | | the shank xtr_nut....|___| Parameters ---------- nut_r : float Circumradius of the hexagon nut_h : float Height of the nut, usually larger than the actual nut height, to be able to introduce it hole_h : float The hole height, from the center of the hexagon to the side it will see light xtr_nut : int 1 if you want 1 mm out of the hole, to cut xtr_hole : int 1 if you want 1 mm out of the hole, to cut fc_axis_nut : FreeCAD.Vector Axis of the shank of the nut fc_axis_hole : FreeCAD.Vector Axis of the shank of the nut ref_nut_ax : int If it is referenced to the center, symmetrical point on the on the fc_axis_nut ref_hole_ax : int If it is referenced at the center of the shank, or at the end of the hole, not counting extra pos : FreeCAD.Vector Position Returns -------- Shape FreeCAD Shape of a nut hole """ doc = FreeCAD.ActiveDocument # normalize axis: axis_nut = DraftVecUtils.scaleTo(fc_axis_nut,1) axis_hole = DraftVecUtils.scaleTo(fc_axis_hole,1) nut_2ap = 2 * nut_r * COS30 #Apotheme = R * cos (30) # --- Reference to point *: hole=1 , nut=2 # fc_axis_hole fc_axis_hole # : : # _2_ _2_ # | | | | # | | | | # *___|----fc_axis_nut | * | # | | \ / # |___| V fc_1_2_nut = DraftVecUtils.scale(axis_nut, -nut_h/2.) fc_2_1_hole = DraftVecUtils.scale(axis_hole, -hole_h) # ref to point nut=2 (*) # _:_ _:_ # | | | | # | | | | # *_1_|----fc_axis_nut | * | # | | :\ /: # |___| : V : # : : : : # :...: :...: # + nut_h + nut_2ap if ref_nut_ax == 1: refto_2_nut = fc_1_2_nut else: refto_2_nut = V0 # ref to point axis_hole=1 (*) # 2___ _2_... # | | | | + hole_h # | | | | : # 1___|----fc_axis_nut | 1 |-- # | | \ / # |___| V # : : # :...: # + nut_h if ref_hole_ax == 1: refto_1_hole = V0 else: refto_1_hole = fc_2_1_hole # absolute position of point *: axis_nut = 2 , axis_hole = 1 nut2_hole1_pos = pos + refto_2_nut + refto_1_hole # position of the nut, including the extra nut_pos = nut2_hole1_pos + DraftVecUtils.scale(axis_hole, -xtr_nut) shp_nut = shp_regprism_dirxtr ( n_sides = 6, radius = nut_r, length = nut_h, fc_normal = axis_nut, fc_verx1 = axis_hole, centered = 0, # no extra, tolerances included xtr_top = 0, xtr_bot = 0, pos = nut_pos) # position is in nut2_hole1_pos, and then xtr are considered in both # directions shp_hole = shp_box_dir_xtr(box_w = nut_2ap, box_d = nut_h, box_h = hole_h, fc_axis_h = axis_hole, fc_axis_d = axis_nut, cw=1, cd=0, ch=0, xtr_h = xtr_hole, xtr_nh = xtr_nut, pos= nut2_hole1_pos) shp_nuthole = shp_nut.fuse(shp_hole) shp_nuthole = shp_nuthole.removeSplitter() doc.recompute() return shp_nuthole
#doc = FreeCAD.newDocument() #shpNuthole = shp_nuthole (nut_r = 5, nut_h = 4, hole_h = 10, # xtr_nut = 1, xtr_hole = 1, # fc_axis_nut = VY, # fc_axis_hole = VX, # ref_nut_ax = 1, # ref_hole_ax = 1, # pos = FreeCAD.Vector(1,1,2)) #Part.show(shpNuthole) # ---------------- Fillet on edges of a certain length # box: is the original shape we want to fillet # e_len: the length of the edges that we want to fillet # radius: the radius of the fillet # name: the name of the shape we want to create
[docs]def fillet_len (box, e_len, radius, name): """ Make a new object with fillet Parameters ---------- box : TopoShape Original shape we want to fillet e_len : float Length of the edges that we want to fillet radius : float Radius of the fillet name : str Name of the shape we want to create Returns -------- FreeCAD Object FreeCAD Object with fillet made """ # we have to bring the active document doc = FreeCAD.ActiveDocument fllts_v = [] edge_ind = 1 #logger.debug('fillet_len: box %s - %s' % # ( str(box), str(box.Shape))) for edge_i in box.Shape.Edges: #logging.debug('fillet_len: edge Length: %s' % str(edge_i.Length)) if edge_i.Length == e_len: # same length # the index is appeneded (edge_ind),not the edge itself (edge_i) # radius is twice, because it can be variable #logging.debug('fillet_len: append edge. Length: %s ' , # str(edge_i.Length)) fllts_v.append((edge_ind, radius, radius)) edge_ind += 1 box_fllt = doc.addObject ("Part::Fillet", name) box_fllt.Base = box box_fllt.Edges = fllts_v # to hide the objects in freecad gui if box.ViewObject != None: box.ViewObject.Visibility=False return box_fllt
# Calculate Bolt separation # We want to know how much separation is needed for a bolt # The bolt (din912) head diameter is usually smaller than the nut (din934) # The nut max value is give by its 2*apotheme (S) (wrench size) # so its max diameter is 2A x cos(30) # # din912 din938 # D S(max) D(max) # M3: 5.5 5.5 6,35 # M4: 7.0 7.0 8,08 # M5: 8.5 8.0 9,24 # M6: 10.0 10.0 11,55 # # So it will the nut what gives the separation # # _____ : _______ # | |_ : _| # | | : | # | | : | # | _| : |_ # |_____| : |______ # : : : # :..,..:.,.: # : sep rad: # : : # :....,....: # bolt_sep # # Arguments: # bolt_d: diameter of the bolt: 3, 4, ... for M3, M4,... # hasnut: 1: if there is a nut # 0: if there is not a nut, so just the bolt head (smaller) # sep: separation from the outside of the nut to the end, if empty, # default value 2mm
[docs]def get_bolt_end_sep (bolt_d, hasnut, sep=2.): """ Calculate Bolt separation Calculates know how much separation is needed for a bolt The bolt (din912) head diameter is usually smaller than the nut (din934) The nut max value is given by its 2*apotheme (S) (wrench size) so its max diameter is 2A x cos(30) Example of nut and bolt head sizes: +--------+--------+--------+--------+ | | din912 | din938 | | +========+========+========+========+ | | D | S(max) | D(max) | +--------+--------+--------+--------+ | **M3** | 5.5 | 5.5 | 6,35 | +--------+--------+--------+--------+ | **M4** | 7.0 | 7.0 | 8,08 | +--------+--------+--------+--------+ | **M5** | 8.5 | 8.0 | 9,24 | +--------+--------+--------+--------+ | **M6** | 10.0 | 10.0 | 11,55 | +--------+--------+--------+--------+ Therefore, if there is a nut, the nut will be used to calculate the separation :: _____ : _______ | |_ : _| | | : | | | : | | _| : |_ |_____| : |______ : : : :..,..:.,.: : sep rad: : : :....,....: bolt_sep Parameters ---------- bolt_d : int Diameter of the bolt: 3, 4, ... for M3, M4,... hasnut : int * 1: if there is a nut * 0: if there is not a nut, so just the bolt head (smaller) sep : float Separation from the outside of the nut to the end, if empty, default value 2mm Returns -------- float Minimum separation between the center of the bolt and the end """ if hasnut == 1: diam = kcomp.NUT_D934_2A[bolt_d] / COS30 else: # no nut, calculate with bolt head diam = kcomp.D912_HEAD_D[bolt_d] rad = diam/2. bolt_sep = rad + sep return bolt_sep
# ------------------- get_bolt_bearing_sep ------------------------- # same as get_bolt_end_sep, but when there is a bearing. # If there is a bearing, there will be more space because the nut is at # the bottom or top, and the widest side is on the middle # # lbearing_r # rad ..+... # ..+.. : : # ______ : :__:______:_ # | |_ : _| .* : # | | : | .* : this is the bearing section (circunference) # | | : | ( : # | _| : |_ : *. : # |______| : |__:____*_: # : : : : # : :.bsep : # : : # :.bolt_b_sep..: # # Arguments: # bolt_d: diameter of the bolt: 3, 4, ... for M3, M4,... # hasnut: 1: if there is a nut # 0: if there is not a nut, so just the bolt head (smaller) # lbearing_r: radius of the linear bearing # bsep: separation from the outside of the nut to the end of bearing # default value 0mm
[docs]def get_bolt_bearing_sep (bolt_d, hasnut, lbearing_r, bsep=0): """ same as get_bolt_end_sep, but when there is a bearing. If there is a bearing, there will be more space because the nut is at the bottom or top, and the widest side is on the middle :: lbearing_r rad ..+... ..+.. : : ______ : :__:______:_ | |_ : _| .* : | | : | .* : this is the bearing section (circunference) | | : | ( : | _| : |_ : *. : |______| : |__:____*_: : : : : : :.bsep : : : :.bolt_b_sep..: Parameters ---------- bolt_d : int Diameter of the bolt: 3, 4, ... for M3, M4,... hasnut : int * 1: if there is a nut * 0: if there is not a nut, so just the bolt head (smaller) lbearing_r : float Radius of the linear bearing bsep : float Separation from the outside of the nut to the end of bearing default value 0mm Returns -------- float Minimum separation between the center of the bolt and the bearing """ if hasnut == 1: diam = kcomp.NUT_D934_2A[bolt_d] / COS30 else: # no nut, calculate with bolt head diam = kcomp.D912_HEAD_D[bolt_d] rad = diam/2. bolt_b_sep = rad + bsep + lbearing_r return bolt_b_sep
# ---------------- edgeonaxis # It tells if an edge is on an axis # Arguments: # edge: an FreeCAD edge, with its vertexes # axis: a text, being 'x', '-x', 'y', '-y', 'z', '-z'
[docs]def edgeonaxis (edge, axis): """ It tells if an edge is on an axis Parameters ---------- edge : Edge A FreeCAD edge, with its vertexes axis : str 'x', '-x', 'y', '-y', 'z', '-z' Returns ------- boolean True: edge on an axis False: edge not on an axis """ vex0 = edge.Vertexes[0] vex1 = edge.Vertexes[1] #logger.debug( "vex0.X: %s", vex0.X) #logger.debug( "vex1.X: %s", vex1.X) #logger.debug( "vex0.Y: %s", vex0.Y) #logger.debug( "vex1.Y: %s", vex1.Y) #logger.debug( "vex0.Z: %s", vex0.Z) #logger.debug( "vex1.Z: %s", vex1.Z) #logger.debug( "axis: %s", axis) #v0x = vex0.X #v1x = vex1.X #v0y = vex0.Y #v1y = vex1.Y #v0z = vex0.Z #v1z = vex1.Z if (equ(vex0.X, vex1.X) and equ(vex0.Y, vex1.Y) and equ(vex0.Z, vex1.Z)): logger.debug('edgeonaxis: error, same point') return False elif equ(vex0.X, vex1.X) and equ(vex0.Y, vex1.Y): if axis == 'z' or axis == '-z': return True else: return False elif equ(vex0.X, vex1.X) and equ(vex0.Z, vex1.Z): if axis == 'y' or axis == '-y': return True else: return False elif equ(vex0.Y, vex1.Y) and equ(vex0.Z, vex1.Z): if axis == 'x' or axis == '-x': return True else: return False else: return False
[docs]def shp_filletchamfer_dir (shp, fc_axis = VZ, fillet = 1, radius=1): """ Fillet or chamfer edges on a certain axis Parameters ---------- shp : Shape Original shape we want to fillet or chamfer fillet : int * 1 if we are doing a fillet * 0 if it is a chamfer radius : float The radius of the fillet or chamfer fc_axis : FreeCAD.Vector Axis where the fillet will be Returns -------- Shape FreeCAD Shape with fillet/chamfer made """ # we have to bring the active document doc = FreeCAD.ActiveDocument doc.recompute() # you may hav problems if you dont do it edgelist = [] # normalize the axis: nnorm = DraftVecUtils.scaleTo(fc_axis,1) # get the negative of the normalized vector nnorm_neg = nnorm.negative() for edge in shp.Edges: #logger.debug('filletchamfer: edge Length: %s', edge.Length) # get the FreeCAD.Vector with the point if len(edge.Vertexes) == 2: p0 = edge.Vertexes[0].Point p1 = edge.Vertexes[1].Point v_vertex = p1.sub(p0) #substraction # I could calculate the angle, but I think it will take more # time than normalizing and checking if they are the same v_vertex.normalize() # check if they are the same vector (they are parallel): if ( DraftVecUtils.equals(v_vertex, nnorm) or DraftVecUtils.equals(v_vertex, nnorm_neg)): edgelist.append(edge) #logger.debug('append edge Length: %s', edge.Length) #logger.debug(str(p0) + ' - ' + str(p1)) if len(edgelist) != 0: if fillet == 1: #logger.debug('%s', str(edgelist)) shp_fillcham = shp.makeFillet(radius, edgelist) else: shp_fillcham = shp.makeChamfer(radius, edgelist) doc.recompute() return shp_fillcham else: logger.debug('No edge to fillet or chamfer') return
[docs]def shp_filletchamfer_dirs (shp, fc_axis_l, fillet = 1, radius=1): """ Same as shp_filletchamfer_dir, but with a list of directions Parameters ---------- shp : Shape Original shape we want to fillet or chamfer fc_axis_l : list List of FreeCAD.Vector. Each vector indicates the axis where the fillet/chamfer will be fillet : int * 1 if we are doing a fillet * 0 if it is a chamfer radius : float Radius of the fillet or chamfer Returns -------- Shape FreeCAD Shape with fillet/chamfer made """ # we have to bring the active document doc = FreeCAD.ActiveDocument doc.recompute() # you may hav problems if you dont do it edgelist = [] n_axis_list = [] for axis in fc_axis_l: # normalize the axis: nnorm = DraftVecUtils.scaleTo(axis,1) n_axis_list.append(nnorm) # get the negative of the normalized vector nnorm_neg = nnorm.negative() n_axis_list.append(nnorm_neg) #logger.debug('filletchamfer: elen: %s', e_len) for edge in shp.Edges: #logger.debug('filletchamfer: edge Length: %s ind %s', # edge.Length, edge_ind) # get the FreeCAD.Vector with the point if len(edge.Vertexes) == 2: p0 = edge.Vertexes[0].Point p1 = edge.Vertexes[1].Point v_vertex = p1.sub(p0) #substraction # I could calculate the angle, but I think it will take more # time than normalizing and checking if they are the same v_vertex.normalize() # check if they are the same vector (they are parallel): for naxis in n_axis_list: if ( DraftVecUtils.equals(v_vertex, naxis)): edgelist.append(edge) break # breaks inside this for, but not the outer if len(edgelist) != 0: if fillet == 1: #logger.debug('%', str(edgelist)) shp_fillcham = shp.makeFillet(radius, edgelist) else: shp_fillcham = shp.makeChamfer(radius, edgelist) doc.recompute() return shp_fillcham else: logger.debug('No edge to fillet or chamfer') return
[docs]def shp_filletchamfer_dirpt (shp, fc_axis = VZ, fc_pt = V0, fillet = 1, radius=1): """ Fillet or chamfer edges on a certain axis and a point contained in that axis Parameters ---------- shp : Shape Original shape we want to fillet or chamfer fc_axis : FreeCAD.Vector Axis where the fillet will be fc_pt : FreeCAD.Vector Placement of the point fillet : int * 1 if we are doing a fillet * 0 if it is a chamfer radius : float Radius of the fillet or chamfer Returns -------- Shape FreeCAD Shape with fillet/chamfer made """ # we have to bring the active document doc = FreeCAD.ActiveDocument doc.recompute() # you may hav problems if you dont do it edgelist = [] # normalize the axis: nnorm = DraftVecUtils.scaleTo(fc_axis,1) # get the negative of the normalized vector nnorm_neg = nnorm.negative() #logger.debug('filletchamfer: elen: %s', e_len) for edge in shp.Edges: #logger.debug('filletchamfer: edge Length: %s ind %s', # edge.Length, edge_ind) # get the FreeCAD.Vector with the point if len(edge.Vertexes) == 2: p0 = edge.Vertexes[0].Point p1 = edge.Vertexes[1].Point v_vertex = p1.sub(p0) #substraction # I could calculate the angle, but I think it will take more # time than normalizing and checking if they are the same v_vertex.normalize() # check if they are the same vector (they are parallel): if ( DraftVecUtils.equals(v_vertex, nnorm) or DraftVecUtils.equals(v_vertex, nnorm_neg)): # Now check if this vertex goes through the point # get the vector from a vertex to the point if DraftVecUtils.equals(p1, fc_pt): # same point edgelist.append(edge) break # vertex found else: v_vertex_pt = p1.sub(fc_pt) v_vertex_pt.normalize() if ( DraftVecUtils.equals(v_vertex_pt, nnorm) or DraftVecUtils.equals(v_vertex_pt, nnorm_neg)): edgelist.append(edge) break #only one if len(edgelist) != 0: if fillet == 1: #logger.debug('%', str(edgelist)) shp_fillcham = shp.makeFillet(radius, edgelist) else: shp_fillcham = shp.makeChamfer(radius, edgelist) doc.recompute() return shp_fillcham else: logger.debug('No edge to fillet or chamfer') return
[docs]def shp_filletchamfer_dirpts (shp, fc_axis, fc_pts, fillet = 1, radius=1): """ Fillet or chamfer edges on a certain axis and a list of point contained in that axis Parameters ---------- shp : Shape Original shape we want to fillet or chamfer fc_axis : FreeCAD.Vector Axis where the fillet will be fc_pts : FreeCAD.Vector Vector list of the points fillet : int * 1 if we are doing a fillet * 0 if it is a chamfer radius : float Radius of the fillet or chamfer Returns -------- Shape FreeCAD Shape with fillet/chamfer made """ # we have to bring the active document doc = FreeCAD.ActiveDocument doc.recompute() # you may hav problems if you dont do it edgelist = [] # normalize the axis: nnorm = DraftVecUtils.scaleTo(fc_axis,1) # get the negative of the normalized vector nnorm_neg = nnorm.negative() #logger.debug('filletchamfer: elen: %s', e_len) for edge in shp.Edges: #logger.debug('filletchamfer: edge Length: %s ind %s', # edge.Length, edge_ind) # get the FreeCAD.Vector with the point if len(edge.Vertexes) == 2: p0 = edge.Vertexes[0].Point p1 = edge.Vertexes[1].Point v_vertex = p1.sub(p0) #substraction # I could calculate the angle, but I think it will take more # time than normalizing and checking if they are the same v_vertex.normalize() # check if they are the same vector (they are parallel): if ( DraftVecUtils.equals(v_vertex, nnorm) or DraftVecUtils.equals(v_vertex, nnorm_neg)): # Now check if this vertex goes through the point # get the vector from a vertex to the point for pti in fc_pts: if DraftVecUtils.equals(p1, pti): # same point edgelist.append(edge) break # vertex found else: v_vertex_pt = p1.sub(pti) v_vertex_pt.normalize() if ( DraftVecUtils.equals(v_vertex_pt, nnorm) or DraftVecUtils.equals(v_vertex_pt, nnorm_neg)): edgelist.append(edge) break # vertex found if len(edgelist) != 0: if fillet == 1: #logger.debug('%', str(edgelist)) shp_fillcham = shp.makeFillet(radius, edgelist) else: shp_fillcham = shp.makeChamfer(radius, edgelist) doc.recompute() return shp_fillcham else: logger.debug('No edge to fillet or chamfer') return shp
[docs]def shp_cir_fillchmf (shp, circen_pos = V0, fillet = 1, radius=1): """ Fillet or chamfer edges that is a circle, the shape has to be a cylinder Parameters ---------- shp : Shape Original cylinder shape we want to fillet or chamfer circen_pos : FreeCAD.Vector Center of the circle fillet : int * 1 if we are doing a fillet * 0 if it is a chamfer radius : float Radius of the fillet or chamfer Returns -------- Shape FreeCAD Shape with fillet/chamfer made """ # we have to bring the active document doc = FreeCAD.ActiveDocument doc.recompute() # you may hav problems if you dont do it edgelist = [] for edge in shp.Edges: # get the edges, if it is a cylinder, 2 edges will have just one # point and one will have to (the height) # check if they are closed: if edge.Closed == True: # only one point # Get the center of Mass, which will be the center cen = edge.CenterOfMass # check if they are the same vector if ( DraftVecUtils.equals(circen_pos, cen)): edgelist.append(edge) break if len(edgelist) != 0: if fillet == 1: shp_fillcham = shp.makeFillet(radius, edgelist) else: shp_fillcham = shp.makeChamfer(radius, edgelist) doc.recompute() return shp_fillcham else: logger.debug('No edge to fillet or chamfer') return
[docs]def shp_cylfilletchamfer (shp, fillet = 1, radius=1): """ Fillet or chamfer all edges of a cylinder Parameters ---------- shp : Shape Original cylinder shape we want to fillet or chamfer fillet : int * 1 if we are doing a fillet * 0 if it is a chamfer radius : float Radius of the fillet or chamfer Returns -------- Shape FreeCAD Shape with fillet/chamfer made """ # we have to bring the active document doc = FreeCAD.ActiveDocument doc.recompute() # you may hav problems if you dont do it edgelist = [] for edge in shp.Edges: # get the edges, if it is a cylinder, 2 edges will have just one # point and one will have to (the height) # check if they are closed: if edge.Closed == True: # only one point edgelist.append(edge) if len(edgelist) != 0: if fillet == 1: shp_fillcham = shp.makeFillet(radius, edgelist) else: shp_fillcham = shp.makeChamfer(radius, edgelist) doc.recompute() return shp_fillcham else: logger.debug('No edge to fillet or chamfer') return
# --- Fillet or chamfer edges of a certain length, on a certain axis # --- and a certain coordinate # For a shape # shp: is the original shape we want to fillet or chamfer # fillet: 1 if we are doing a fillet, 0 if it is a chamfer # e_len: the length of the edges that we want to fillet or chamfer # if e_len == 0, chamfer/fillet any length # radius: the radius of the fillet or chamfer # axis : the axis where the fillet will be # xpos_chk,ypos_chk,zpos_chk : if the position will be checked # if axis = 'x', x_pos_check will not make sense # xpos,ypos,zpos : the position
[docs]def shp_filletchamfer (shp, e_len, fillet = 1, radius=1, axis='x', xpos_chk = 0, ypos_chk = 0, zpos_chk=0, xpos = 0, ypos = 0, zpos = 0 ): """ Fillet or chamfer edges of a certain length, on a certain axis and a certain coordinate Parameters ---------- shp : Shape Original shape we want to fillet or chamfer fillet : int * 1 if we are doing a fillet * 0 if it is a chamfer e_len : float Length of the edges that we want to fillet or chamfer if e_len == 0, chamfer/fillet any length radius : float Radius of the fillet or chamfer axis : str Axis where the fillet will be xpos_chk : int If the position will be checked. ypos_chk : int If the position will be checked. zpos_chk : int If the position will be checked. xpos : float The X position ypos : float The Y position zpos : float The Z position Notes ----- If axis = 'x', x_pos_check will not make sense Returns -------- Shape FreeCAD Shape with fillet/chamfer made """ # we have to bring the active document doc = FreeCAD.ActiveDocument doc.recompute() # you may hav problems if you dont do it edgelist = [] #logger.debug('filletchamfer: elen: %s', e_len) for edge_ind, edge in enumerate(shp.Edges): #logger.debug('filletchamfer: edge Length: %s ind %s', # edge.Length, edge_ind) # using equ because float number can be not exactly the same if (e_len == 0 or equ(edge.Length, e_len)): # same length if edgeonaxis (edge, axis) == True: #logger.debug('edgeonaxis: Length: %s' % str(edge.Length)) v0 = edge.Vertexes[0] v1 = edge.Vertexes[1] if axis == 'x' or axis == '-x': if ypos_chk == True and zpos_chk == True: # its on the axis, so just checking one edge if equ(v0.Y, ypos) and equ(v0.Z, zpos): edgelist.append(edge) elif ypos_chk == True: if equ(v0.Y, ypos): edgelist.append(edge) elif zpos_chk == True: if equ(v0.Z, zpos): edgelist.append(edge) else: # all the edges on axis x with e_len are appended edgelist.append(edge) elif axis == 'y' or axis == '-y': if xpos_chk == True and zpos_chk == True: if equ(v0.X, xpos) and equ(v0.Z, zpos): edgelist.append(edge) elif xpos_chk == True: if equ(v0.X, xpos): edgelist.append(edge) elif zpos_chk == True: if equ(v0.Z, zpos): edgelist.append(edge) else: edgelist.append(edge) elif axis == 'z' or axis == '-z': if xpos_chk == True and ypos_chk == True: if equ(v0.X, ypos) and equ(v0.Y, ypos): edgelist.append(edge) elif xpos_chk == True: if equ(v0.X, xpos): edgelist.append(edge) elif ypos_chk == True: if equ(v0.Y, ypos): edgelist.append(edge) else: edgelist.append(edge) if len(edgelist) != 0: if fillet == 1: logger.debug('%', str(edgelist)) shp_fillcham = shp.makeFillet(radius, edgelist) else: shp_fillcham = shp.makeChamfer(radius, edgelist) doc.recompute() return shp_fillcham else: logger.debug('No edge to fillet or chamfer') return
# --- Fillet or chamfer edges of a certain length, on a certain axis # --- and a certain coordinate # fco: is the original FreeCAD object we want to fillet or chamfer # fillet: 1 if we are doing a fillet, 0 if it is a chamfer # e_len: the length of the edges that we want to fillet or chamfer # if e_len == 0, chamfer/fillet any length # radius: the radius of the fillet or chamfer # axis : the axis where the fillet will be # xpos_chk,ypos_chk,zpos_chk : if the position will be checked # if axis = 'x', x_pos_check will not make sense # xpos,ypos,zpos : the position # name: the name of the fco we want to create
[docs]def filletchamfer (fco, e_len, name, fillet = 1, radius=1, axis='x', xpos_chk = 0, ypos_chk = 0, zpos_chk=0, xpos = 0, ypos = 0, zpos = 0, ): """ Fillet or chamfer edges of a certain length, on a certain axis and a certain coordinate Parameters ---------- fco : FreeCAD Object Original FreeCAD object we want to fillet or chamfer fillet : int * 1 if we are doing a fillet * 0 if it is a chamfer e_len : float Length of the edges that we want to fillet or chamfer if e_len == 0, chamfer/fillet any length radius : float Radius of the fillet or chamfer axis : str Axis where the fillet will be xpos_chk : int If the X position will be checked ypos_chk : int If the Y position will be checked zpos_chk : int If the Z position will be checked xpos : float The X position ypos : float The Y position zpos : float The Z position name : str Name of the fco we want to create Notes ----- If axis = 'x', x_pos_check will not make sense Returns -------- FreeCAD Object FreeCAD Object with fillet/chamfer made """ # we have to bring the active document doc = FreeCAD.ActiveDocument doc.recompute() # you may hav problems if you dont do it edgelist = [] #logger.debug('filletchamfer: elen: %s', e_len) for edge_ind, edge in enumerate(fco.Shape.Edges): #logger.debug('filletchamfer: edge Length: %s ind %s', # edge.Length, edge_ind) # using equ because float number can be not exactly the same if (e_len == 0 or equ(edge.Length, e_len)): # same length if edgeonaxis (edge, axis) == True: #logger.debug('edgeonaxis: Length: %s' % str(edge.Length)) v0 = edge.Vertexes[0] v1 = edge.Vertexes[1] if axis == 'x' or axis == '-x': if ypos_chk == True and zpos_chk == True: # its on the axis, so just checking one edge if equ(v0.Y, ypos) and equ(v0.Z, zpos): edgelist.append((edge_ind+1,radius,radius)) elif ypos_chk == True: if equ(v0.Y, ypos): edgelist.append((edge_ind +1,radius,radius)) elif zpos_chk == True: if equ(v0.Z, zpos): edgelist.append((edge_ind+1,radius,radius)) else: # all the edges on axis x with e_len are appended edgelist.append((edge_ind+1,radius,radius)) elif axis == 'y' or axis == '-y': if xpos_chk == True and zpos_chk == True: if equ(v0.X, xpos) and equ(v0.Z, zpos): edgelist.append((edge_ind+1,radius,radius)) elif xpos_chk == True: if equ(v0.X, xpos): edgelist.append((edge_ind+1,radius,radius)) elif zpos_chk == True: if equ(v0.Z, zpos): edgelist.append((edge_ind+1,radius,radius)) else: edgelist.append((edge_ind+1,radius,radius)) elif axis == 'z' or axis == '-z': if xpos_chk == True and ypos_chk == True: if equ(v0.X, ypos) and equ(v0.Y, ypos): edgelist.append((edge_ind+1,radius,radius)) elif xpos_chk == True: if equ(v0.X, xpos): edgelist.append((edge_ind+1,radius,radius)) elif ypos_chk == True: if equ(v0.Y, ypos): edgelist.append((edge_ind+1,radius,radius)) else: edgelist.append((edge_ind+1,radius,radius)) if len(edgelist) != 0: if fillet == 1: fco_fillcham = doc.addObject ("Part::Fillet", name) else: fco_fillcham = doc.addObject ("Part::Chamfer", name) fco_fillcham.Base = fco fco_fillcham.Edges = edgelist if fco.ViewObject != None: fco.ViewObject.Visibility=False doc.recompute() return fco_fillcham else: logger.debug('No edge to fillet or chamfer') return
# ---------------- calc_rot ----------------------------- # ---------------- Yaw, Pitch and Roll transfor # Having an object with an orientation defined by 2 vectors # the vectors a tuples, nor FreeCAD.Vectors # use the wrapper fc_calc_rot to have FreeCAD.Vector arguments # First vector original direction (x,y,z) is (1,0,0) # Second vector original direction (x,y,z) is (0,0,-1) # we want to rotate the object in an ortoghonal direction. The vectors # will be in -90, 180, or 90 degrees. # this function returns the Rotation given by yaw, pitch and roll # In case vec1 is (0,0,0), means that it doesn't matter that vector. # Yaw is the rotation of Z axis. Positive Yaw is like screwing up # # Y Y Y # |_X : yaw=0 : yaw=60 # / : : / # Z : : / # : : / # :________.... X :/............ X # # # Z Y Z Z # |/_ X : pitch=0 : pitch=-60 # : : / # : : / # : : / # :________.... X :/............ X # # # Z Z # Z : roll=0 : roll=-60 # |_Y : : / # / : : / # X : : / # :________.... Y :/............ Y # #
[docs]def calc_rot (vec1, vec2): """ Having an object with an orientation defined by 2 vectors the vectors a tuples, nor FreeCAD.Vectors use the wrapper fc_calc_rot to have FreeCAD.Vector arguments First vector original direction (x,y,z) is (1,0,0) Second vector original direction (x,y,z) is (0,0,-1) we want to rotate the object in an ortoghonal direction. The vectors will be in -90, 180, or 90 degrees. this function returns the Rotation given by yaw, pitch and roll In case vec1 is (0,0,0), means that it doesn't matter that vector. Yaw is the rotation of Z axis. Positive Yaw is like screwing up :: Y Y Y |_X : yaw=0 : yaw=60 / : : / Z : : / : : / :________.... X :/............ X Z Y Z Z |/_ X : pitch=0 : pitch=-60 : : / : : / : : / :________.... X :/............ X Z Z Z : roll=0 : roll=-60 |_Y : : / / : : / X : : / :________.... Y :/............ Y Parameters ---------- vec1 : tuples Direction vec2 : tuples Direction Returns -------- FreeCAD.Rotation """ # rotation calculation if vec1 == (1,0,0): yaw = 0 pitch = 0 if vec2 == (0,1,0): roll = 90 elif vec2 == (0,-1,0): roll = -90 elif vec2 == (0,0,1): roll = 180 elif vec2 == (0,0,-1): roll = 0 else: print("error 1 in yaw-pitch-roll") elif vec1 == (-1,0,0): yaw = 180 pitch = 0 if vec2 == (0,1,0): roll = -90 #negative because of the yaw elif vec2 == (0,-1,0): roll = 90 # positive because of the yaw = 180 elif vec2 == (0,0,1): roll = 180 elif vec2 == (0,0,-1): roll = 0 else: print("error 2 in yaw-pitch-roll") elif vec1 == (0,1,0): yaw = 90 pitch = 0 if vec2 == (1,0,0): roll = -90 elif vec2 == (-1,0,0): roll = 90 elif vec2 == (0,0,1): roll = 180 elif vec2 == (0,0,-1): roll = 0 else: print("error 3 in yaw-pitch-roll") elif vec1 == (0,-1,0): yaw = -90 pitch = 0 if vec2 == (1,0,0): roll = 90 elif vec2 == (-1,0,0): roll = -90 elif vec2 == (0,0,1): roll = 180 elif vec2 == (0,0,-1): roll = 0 else: print("error 4 in yaw-pitch-roll") elif vec1 == (0,0,1): pitch = -90 yaw = 0 if vec2 == (1,0,0): roll = 0 elif vec2 == (-1,0,0): roll = 180 elif vec2 == (0,1,0): roll = 90 elif vec2 == (0,-1,0): roll = -90 else: print("error 5 in yaw-pitch-roll") elif vec1 == (0,0,-1): pitch = 90 yaw = 0 if vec2 == (1,0,0): roll = 180 elif vec2 == (-1,0,0): roll = 0 elif vec2 == (0,1,0): roll = 90 elif vec2 == (0,-1,0): roll = -90 else: print("error 6 in yaw-pitch-roll") elif vec1 == (0,0,0): # it doesn't matter the direction of vec1 yaw = 0 if vec2 == (1,0,0): pitch = -90 roll = 0 elif vec2 == (-1,0,0): pitch = 90 roll = 0 elif vec2 == (0,1,0): pitch = 0 roll = 90 elif vec2 == (0,-1,0): pitch = 0 roll = -90 elif vec2 == (0,0,1): pitch = 0 roll = 180 elif vec2 == (0,0,-1): pitch = 0 roll = 0 # the same position else: print("error 7 in yaw-pitch-roll") vrot = FreeCAD.Rotation(yaw,pitch,roll) return vrot
[docs]def get_fcvectup (tup): """ Gets the FreeCAD.Vector of a tuple Parameters ---------- tup : tuple Tuple of 3 elements Returns -------- FreeCAD.Vector FreeCAD.Vector of a tuple """ fcvec = FreeCAD.Vector(tup[0], tup[1], tup[2]) return (fcvec)
# ---------------- fc_calc_rot ----------------------------- # same as calc_rot but using FreeCAD.Vectors arguments
[docs]def fc_calc_rot (fc_vec1, fc_vec2): """ Same as calc_rot but using FreeCAD.Vectors arguments """ ##vec1 = (fc_vec1.X, fc_vec1.Y, fc_vec1.Z) ##vec2 = (fc_vec2.X, fc_vec2.Y, fc_vec2.Z) vrot = calc_rot(DraftVecUtils.tup(fc_vec1),DraftVecUtils.tup(fc_vec2)) return vrot
[docs]def calc_rot_z (v_refz, v_refx): """ Calculates de rotation like calc_rot. However uses a different origin axis. calc_rot uses: vec1 original direction (x,y,z) is (0,0,1) vec2 original direction (x,y,z) is (1,0,0) So it makes a change of axis before calling calc_rot Parameters ---------- v_refz : tuple or FreeCAD.Vector Vector indicating the rotation from (0,0,1) to v_refz v_refx : tuple or FreeCAD.Vector Vector indicating the rotation from (1,0,0) to v_refx Returns -------- FreeCAD.Rotation """ if type(v_refz) is tuple: v_refz = get_fcvectup(v_refz) v_refx = get_fcvectup(v_refx) # since arg2 of calc_rot is referenced to VNZ, v_refz is negated # so v_refnz becomes referenced to VZ v_refnz = DraftVecUtils.neg(v_refz) vrot = fc_calc_rot(v_refx, v_refnz) return vrot
[docs]def get_rot (v1, v2): """ Calculate the rotation from v1 to v2 the difference with previous verions, such fc_calc_rot, calc_rot, calc_rot is that it is for any vector direction. The difference with DraftVecUtils.getRotation is that getRotation doesnt work for vectors with 180 degrees. Notes ----- MAYBE IT IS NOT NECESSARY, just use FreeCAD.Rotation rotation.Axis, math.degrees(rotation.Angle) Parameters ---------- v1 : FreeCAD.Vector Vector to calculate the rotation v2 : FreeCAD.Vector Vector to calculate the rotation Returns -------- FreeCAD.Rotation Tuple representing a quaternion rotation between v2 and v1 """ #normalize vectors nv1 = DraftVecUtils.scaleTo(v1,1.) nv2 = DraftVecUtils.scaleTo(v2,1.) if DraftVecUtils.equals(nv1,nv2.negative()): # we have to flip, but DraftVecUtils.getRotation doesnt get it done # for this case return FreeCAD.Rotation(VX,180) else: return DraftVecUtils.getRotation(nv1,nv2)
# ---------------- calc_desp_ncen ------------------------ # similar to calc_rot, but calculates de displacement, when we don't want # to have all of the dimensions centered # First vector original direction (x,y,z) is (1,0,0) # Second vector original direction (x,y,z) is (0,0,-1) # The arguments vec1, vec2 are tuples (x,y,z) but they may be also # FreeCAD.Vectors # vec1, vec2 have to be on the axis: x, -x, y, -y, z, -z # vec1 can be (0,0,0): it means that it doesn't matter how it is rotated # Length: original dimension on X # Width: original dimension on Y # Height: original dimension on Z # # the picture is wrong, because originally it is centered, that's # why the position is moved only half of the dimension. But the concept # is valid # # Z . Y length (x) = 1 # : _ . width (y) = 2 # : / /| heigth (z) = 3 # :/_ / | # | | | vec1 original (before rotation) = VX # | | / vec2 original (before rotation) = -VZ # |__|/..............X # # # Example after rotation and change position # # Z . Y length (x) = 3 # : ____. width (y) = 2 # : / /| heigth (z) = 1 # :/___ // vec1 = VZ # |____|/..............X vec2 = VX # # So we have to move X its original heith (3), otherwise it would # be on the negative side, like this # # Z # : . Y length (x) = 3 # _:__. width (y) = 2 # / : /| heigth (z) = 1 # /___:// vec1 = VZ # |____|/..............X vec2 = VX
[docs]def calc_desp_ncen (Length, Width, Height, vec1, vec2, cx=False, cy=False, cz=False, H_extr = False): """ Similar to calc_rot, but calculates de displacement, when we don't want to have all of the dimensions centered First vector original direction (x,y,z) is (1,0,0) Second vector original direction (x,y,z) is (0,0,-1) The arguments vec1, vec2 are tuples (x,y,z) but they may be also FreeCAD.Vectors :: Z . Y length (x) = 1 : _ . width (y) = 2 : / /| heigth (z) = 3 :/_ / | | | | vec1 original (before rotation) = VX | | / vec2 original (before rotation) = -VZ |__|/..............X Example after rotation and change position Z . Y length (x) = 3 : ____. width (y) = 2 : / /| heigth (z) = 1 :/___ // vec1 = VZ |____|/..............X vec2 = VX So we have to move X its original heith (3), otherwise it would be on the negative side, like this Z : . Y length (x) = 3 _:__. width (y) = 2 / : /| heigth (z) = 1 /___:// vec1 = VZ |____|/..............X vec2 = VX the picture is wrong, because originally it is centered, that's why the position is moved only half of the dimension. But the concept is valid Parameters ---------- vec1 : tuples Have to be on the axis: x, -x, y, -y, z, -z :: vec1 can be (0,0,0): it means that it doesnt matter how it is rotated vec2 : tuples Have to be on the axis: x, -x, y, -y, z, -z Length : float Original dimension on X Width : float Original dimension on Y Height : float Original dimension on Z cx : boolean Position centered or not cy : boolean Position centered or not cz : boolean Position centered or not Returns -------- FreeCAD.Vector Vector of the displacement """ # rotation calculation x = 0 y = 0 z = 0 if abs(vec1[0]) == 1: # X axis: vec1 == (1,0,0) or vec1 == (-1,0,0): if abs(vec2[1]) == 1: # Y if cx == False: x = Length / 2.0 if cy == False: y = Height / 2.0 if cz == False: z = Width / 2.0 elif abs(vec2[2]) == 1: # Z if cx == False: x = Length / 2.0 if cy == False: y = Width / 2.0 if cz == False: z = Height / 2.0 else: print("error 1 in calc_desp_ncen") elif abs(vec1[1]) == 1: # Y axis if abs(vec2[0]) == 1: # X if cx == False: x = Height / 2.0 if cy == False: y = Length / 2.0 if cz == False: z = Width / 2.0 elif abs(vec2[2]) == 1: # Z if cx == False: x = Width / 2.0 if cy == False: y = Length / 2.0 if cz == False: z = Height / 2.0 else: print("error 2 in calc_desp_ncen") elif abs(vec1[2]) == 1: # Z axis if abs(vec2[0]) == 1: # X if cx == False: x = Height / 2.0 if cy == False: y = Width / 2.0 if cz == False: z = Length / 2.0 elif abs(vec2[1]) == 1: # Y if cx == False: x = Width / 2.0 if cy == False: y = Height / 2.0 if cz == False: z = Length / 2.0 else: print("error 3 in calc_desp_ncen") elif (vec1[0]==0 and vec1[1]==0 and vec1[2]==0): #It doesnt matter vec1. Probably it is symetrical on plane XY. # So Length and Width are the same if Width != Length: logger.error('Check rotation vec1=(0,0,0), and Length!=Width') if abs(vec2[0]) == 1: # X. Pitch = -90. in calc_rot if cx == False: x = Height / 2.0 if cy == False: y = Width / 2.0 if cz == False: z = Length / 2.0 elif abs(vec2[1]) == 1: # Y. Roll = +-90. in calc_rot if cx == False: x = Length / 2.0 if cy == False: y = Height / 2.0 if cz == False: z = Width / 2.0 elif abs(vec2[2]) == 1: # Z. Nothing. Roll 0 or 180 if cx == False: x = Width / 2.0 if cy == False: y = Length / 2.0 if cz == False: z = Height / 2.0 else: print("error 4 in calc_desp_ncen") else: print("error 5 in calc_desp_ncen") vdesp = FreeCAD.Vector(x,y,z) return vdesp
# ---------------- fc_calc_desp_ncen ----------------------------- # same as calc_desp_ncen but using FreeCAD.Vectors arguments
[docs]def fc_calc_desp_ncen (Length, Width, Height, fc_vec1, fc_vec2, cx=False, cy=False, cz=False, H_extr = False ): """ Same as calc_desp_ncen but using FreeCAD.Vectors arguments """ vec1 = DraftVecUtils.tup(fc_vec1) vec2 = DraftVecUtils.tup(fc_vec2) vdesp = calc_desp_ncen(Length, Width, Height, vec1, vec2, cx, cy, cz, H_extr) return vdesp
[docs]def getvecofname(axis): """ Get axis name renunrs the vector """ if axis == 'x': vec = (1,0,0) elif axis == '-x': vec = (-1,0,0) elif axis == 'y': vec = (0,1,0) elif axis == '-y': vec = (0,-1,0) elif axis == 'z': vec = (0,0,1) elif axis == '-z': vec = (0,0,-1) return vec
#VX, VY, VZ,...
[docs]def getfcvecofname(axis): """ Returns the FreeCAD.Vecor of the vector name given """ fc_vec = FreeCAD.Vector(getvecofname(axis)) return fc_vec
[docs]def vecname_paral (vec1, vec2): """ Given to vectors by name 'x', '-x', ... indicates if they are parallel or not """ paral = -1 if vec1 == 'x' or vec1 == '-x': if vec2 == 'x' or vec2 == '-x': paral = 1 else: paral = 0 elif vec1 == 'y' or vec1 == '-y': if vec2 == 'y' or vec2 == '-y': paral = 1 else: paral = 0 elif vec1 == 'z' or vec1 == '-z': if vec2 == 'z' or vec2 == '-z': paral = 1 else: paral = 0 return paral
[docs]def get_vecname_perpend1(vecname): """ Gets a perpendicular vecname Parameters ---------- vec : str 'x', '-x', 'y', '-y', 'z', '-z' Returns -------- str Perpendicular vector name """ if vecname == 'x': return 'y' elif vecname == 'y': return 'z' elif vecname == 'z': return 'x' elif vecname == '-x': return '-y' elif vecname == '-y': return '-z' elif vecname == '-z': return '-x'
[docs]def get_vecname_perpend2(vecname): """ Gets the other perpendicular vecname (see get_vecname_perpend) Parameters ---------- vec : str 'x', '-x', 'y', '-y', 'z', '-z' Returns ------- str Perpendicular vector name """ if vecname == 'x': return 'z' elif vecname == 'y': return 'x' elif vecname == 'z': return 'y' elif vecname == '-x': return '-z' elif vecname == '-y': return '-x' elif vecname == '-z': return '-y'
[docs]def get_nameofbasevec (fcvec): """ From a base vector either: (1,0,0), (0,1,0), (0,0,1), (-1,0,0), (0,-1,0), (0,0,-1) Gets its name: 'x', 'y',.... Returns ------- str Vector name """ if fcvec.x==1 and fcvec.y==0 and fcvec.z==0: return 'x' elif fcvec.x==0 and fcvec.y==1 and fcvec.z==0: return 'y' elif fcvec.x==0 and fcvec.y==0 and fcvec.z==1: return 'z' elif fcvec.x==-1 and fcvec.y==0 and fcvec.z==0: return '-x' elif fcvec.x==0 and fcvec.y==-1 and fcvec.z==0: return '-y' elif fcvec.x==0 and fcvec.y==0 and fcvec.z==-1: return '-z' else: print("Not a base vector")
[docs]def get_fclist_4perp_vecname (vecname): """ Gets a list of 4 FreCAD.Vector perpendicular to one vecname for example: :: from 'x' -> (0,1,0), (0,0,1), (0,-1,0), (0,0,-1) Parameters ---------- vecname : str 'x', '-x', 'y', '-y', 'z', '-z' Returns ------- list List of FreeCAD.Vector """ fc_p1 = getfcvecofname(get_vecname_perpend1(vecname)) fc_p2 = getfcvecofname(get_vecname_perpend2(vecname)) fc_list = [fc_p1, fc_p2, DraftVecUtils.neg(fc_p1), DraftVecUtils.neg(fc_p2)] return fc_list
[docs]def get_fclist_4perp_fcvec (fcvec): """ Gets a list of 4 FreeCAD.Vector perpendicular to one base vector fcvec can only be: * (1,0,0) * (0,1,0) * (0,0,1) * (-1,0,0) * (0,-1,0) * (0,0,-1) For example: :: from (1,0,0) -> (0,1,0), (0,0,1), (0,-1,0), (0,0,-1) Parameters ---------- fcvec : vector (1,0,0), (0,1,0), (0,0,1), (-1,0,0), (0,-1,0), (0,0,-1) Returns ------- list List of FreeCAD.Vector """ return (get_fclist_4perp_vecname(get_nameofbasevec(fcvec)))
[docs]def get_fclist_4perp2_vecname (vecname): """ Gets a list of 4 FreCAD.Vector perpendicular to one vecname different from get_fclist_4perp_vecname For example: :: from 'x' -> (0,1,1), (0,-1,1), (0,-1,-1), (0,1,-1) Parameters ---------- vecname : str 'x', '-x', 'y', '-y', 'z', '-z' Returns ------- list List of FreeCAD.Vector """ fc_p1 = getfcvecofname(get_vecname_perpend1(vecname)) fc_p1_neg = DraftVecUtils.neg(fc_p1) fc_p2 = getfcvecofname(get_vecname_perpend2(vecname)) fc_p2_neg = DraftVecUtils.neg(fc_p2) fc_list = [(fc_p1 + fc_p2), (fc_p1 + fc_p2_neg), (fc_p1_neg + fc_p2_neg), (fc_p1_neg + fc_p2)] return fc_list
[docs]def get_fclist_4perp2_fcvec (fcvec): """ Gets a list of 4 FreCAD.Vector perpendicular to one base vector fcvec can only be: * (1,0,0) * (0,1,0) * (0,0,1) * (-1,0,0) * (0,-1,0) * (0,0,-1) For example: :: from (1,0,0) -> (0,1,0), (0,0,1), (0,-1,0), (0,0,-1) Parameters ---------- fcvec : vector (1,0,0), (0,1,0), (0,0,1), (-1,0,0), (0,-1,0), (0,0,-1) Returns ------- list List of FreeCAD.Vector """ return (get_fclist_4perp2_vecname(get_nameofbasevec(fcvec)))
[docs]def get_positive_vecname (vecname): """ It just get 'x' when vecname is 'x' or '-x', and the same for the others, because some functions receive only positive base vector Parameters ---------- vecname : str 'x', '-x', 'y', '-y', 'z', '-z' Returns ------- str Vector name """ if vecname == 'x' or vecname == '-x': return 'x' elif vecname == 'y' or vecname == '-y': return 'y' elif vecname == 'z' or vecname == '-z': return 'z' else: logger.error('Not a valid base vector name')